second commit
This commit is contained in:
456
node_modules/sucrase/dist/esm/CJSImportProcessor.js
generated
vendored
Normal file
456
node_modules/sucrase/dist/esm/CJSImportProcessor.js
generated
vendored
Normal file
@ -0,0 +1,456 @@
|
||||
|
||||
|
||||
|
||||
import {isDeclaration} from "./parser/tokenizer";
|
||||
import {ContextualKeyword} from "./parser/tokenizer/keywords";
|
||||
import {TokenType as tt} from "./parser/tokenizer/types";
|
||||
|
||||
import getImportExportSpecifierInfo from "./util/getImportExportSpecifierInfo";
|
||||
import {getNonTypeIdentifiers} from "./util/getNonTypeIdentifiers";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class responsible for preprocessing and bookkeeping import and export declarations within the
|
||||
* file.
|
||||
*
|
||||
* TypeScript uses a simpler mechanism that does not use functions like interopRequireDefault and
|
||||
* interopRequireWildcard, so we also allow that mode for compatibility.
|
||||
*/
|
||||
export default class CJSImportProcessor {
|
||||
__init() {this.nonTypeIdentifiers = new Set()}
|
||||
__init2() {this.importInfoByPath = new Map()}
|
||||
__init3() {this.importsToReplace = new Map()}
|
||||
__init4() {this.identifierReplacements = new Map()}
|
||||
__init5() {this.exportBindingsByLocalName = new Map()}
|
||||
|
||||
constructor(
|
||||
nameManager,
|
||||
tokens,
|
||||
enableLegacyTypeScriptModuleInterop,
|
||||
options,
|
||||
isTypeScriptTransformEnabled,
|
||||
keepUnusedImports,
|
||||
helperManager,
|
||||
) {;this.nameManager = nameManager;this.tokens = tokens;this.enableLegacyTypeScriptModuleInterop = enableLegacyTypeScriptModuleInterop;this.options = options;this.isTypeScriptTransformEnabled = isTypeScriptTransformEnabled;this.keepUnusedImports = keepUnusedImports;this.helperManager = helperManager;CJSImportProcessor.prototype.__init.call(this);CJSImportProcessor.prototype.__init2.call(this);CJSImportProcessor.prototype.__init3.call(this);CJSImportProcessor.prototype.__init4.call(this);CJSImportProcessor.prototype.__init5.call(this);}
|
||||
|
||||
preprocessTokens() {
|
||||
for (let i = 0; i < this.tokens.tokens.length; i++) {
|
||||
if (
|
||||
this.tokens.matches1AtIndex(i, tt._import) &&
|
||||
!this.tokens.matches3AtIndex(i, tt._import, tt.name, tt.eq)
|
||||
) {
|
||||
this.preprocessImportAtIndex(i);
|
||||
}
|
||||
if (
|
||||
this.tokens.matches1AtIndex(i, tt._export) &&
|
||||
!this.tokens.matches2AtIndex(i, tt._export, tt.eq)
|
||||
) {
|
||||
this.preprocessExportAtIndex(i);
|
||||
}
|
||||
}
|
||||
this.generateImportReplacements();
|
||||
}
|
||||
|
||||
/**
|
||||
* In TypeScript, import statements that only import types should be removed.
|
||||
* This includes `import {} from 'foo';`, but not `import 'foo';`.
|
||||
*/
|
||||
pruneTypeOnlyImports() {
|
||||
this.nonTypeIdentifiers = getNonTypeIdentifiers(this.tokens, this.options);
|
||||
for (const [path, importInfo] of this.importInfoByPath.entries()) {
|
||||
if (
|
||||
importInfo.hasBareImport ||
|
||||
importInfo.hasStarExport ||
|
||||
importInfo.exportStarNames.length > 0 ||
|
||||
importInfo.namedExports.length > 0
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
const names = [
|
||||
...importInfo.defaultNames,
|
||||
...importInfo.wildcardNames,
|
||||
...importInfo.namedImports.map(({localName}) => localName),
|
||||
];
|
||||
if (names.every((name) => this.shouldAutomaticallyElideImportedName(name))) {
|
||||
this.importsToReplace.set(path, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shouldAutomaticallyElideImportedName(name) {
|
||||
return (
|
||||
this.isTypeScriptTransformEnabled &&
|
||||
!this.keepUnusedImports &&
|
||||
!this.nonTypeIdentifiers.has(name)
|
||||
);
|
||||
}
|
||||
|
||||
generateImportReplacements() {
|
||||
for (const [path, importInfo] of this.importInfoByPath.entries()) {
|
||||
const {
|
||||
defaultNames,
|
||||
wildcardNames,
|
||||
namedImports,
|
||||
namedExports,
|
||||
exportStarNames,
|
||||
hasStarExport,
|
||||
} = importInfo;
|
||||
|
||||
if (
|
||||
defaultNames.length === 0 &&
|
||||
wildcardNames.length === 0 &&
|
||||
namedImports.length === 0 &&
|
||||
namedExports.length === 0 &&
|
||||
exportStarNames.length === 0 &&
|
||||
!hasStarExport
|
||||
) {
|
||||
// Import is never used, so don't even assign a name.
|
||||
this.importsToReplace.set(path, `require('${path}');`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const primaryImportName = this.getFreeIdentifierForPath(path);
|
||||
let secondaryImportName;
|
||||
if (this.enableLegacyTypeScriptModuleInterop) {
|
||||
secondaryImportName = primaryImportName;
|
||||
} else {
|
||||
secondaryImportName =
|
||||
wildcardNames.length > 0 ? wildcardNames[0] : this.getFreeIdentifierForPath(path);
|
||||
}
|
||||
let requireCode = `var ${primaryImportName} = require('${path}');`;
|
||||
if (wildcardNames.length > 0) {
|
||||
for (const wildcardName of wildcardNames) {
|
||||
const moduleExpr = this.enableLegacyTypeScriptModuleInterop
|
||||
? primaryImportName
|
||||
: `${this.helperManager.getHelperName("interopRequireWildcard")}(${primaryImportName})`;
|
||||
requireCode += ` var ${wildcardName} = ${moduleExpr};`;
|
||||
}
|
||||
} else if (exportStarNames.length > 0 && secondaryImportName !== primaryImportName) {
|
||||
requireCode += ` var ${secondaryImportName} = ${this.helperManager.getHelperName(
|
||||
"interopRequireWildcard",
|
||||
)}(${primaryImportName});`;
|
||||
} else if (defaultNames.length > 0 && secondaryImportName !== primaryImportName) {
|
||||
requireCode += ` var ${secondaryImportName} = ${this.helperManager.getHelperName(
|
||||
"interopRequireDefault",
|
||||
)}(${primaryImportName});`;
|
||||
}
|
||||
|
||||
for (const {importedName, localName} of namedExports) {
|
||||
requireCode += ` ${this.helperManager.getHelperName(
|
||||
"createNamedExportFrom",
|
||||
)}(${primaryImportName}, '${localName}', '${importedName}');`;
|
||||
}
|
||||
for (const exportStarName of exportStarNames) {
|
||||
requireCode += ` exports.${exportStarName} = ${secondaryImportName};`;
|
||||
}
|
||||
if (hasStarExport) {
|
||||
requireCode += ` ${this.helperManager.getHelperName(
|
||||
"createStarExport",
|
||||
)}(${primaryImportName});`;
|
||||
}
|
||||
|
||||
this.importsToReplace.set(path, requireCode);
|
||||
|
||||
for (const defaultName of defaultNames) {
|
||||
this.identifierReplacements.set(defaultName, `${secondaryImportName}.default`);
|
||||
}
|
||||
for (const {importedName, localName} of namedImports) {
|
||||
this.identifierReplacements.set(localName, `${primaryImportName}.${importedName}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getFreeIdentifierForPath(path) {
|
||||
const components = path.split("/");
|
||||
const lastComponent = components[components.length - 1];
|
||||
const baseName = lastComponent.replace(/\W/g, "");
|
||||
return this.nameManager.claimFreeName(`_${baseName}`);
|
||||
}
|
||||
|
||||
preprocessImportAtIndex(index) {
|
||||
const defaultNames = [];
|
||||
const wildcardNames = [];
|
||||
const namedImports = [];
|
||||
|
||||
index++;
|
||||
if (
|
||||
(this.tokens.matchesContextualAtIndex(index, ContextualKeyword._type) ||
|
||||
this.tokens.matches1AtIndex(index, tt._typeof)) &&
|
||||
!this.tokens.matches1AtIndex(index + 1, tt.comma) &&
|
||||
!this.tokens.matchesContextualAtIndex(index + 1, ContextualKeyword._from)
|
||||
) {
|
||||
// import type declaration, so no need to process anything.
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.tokens.matches1AtIndex(index, tt.parenL)) {
|
||||
// Dynamic import, so nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.tokens.matches1AtIndex(index, tt.name)) {
|
||||
defaultNames.push(this.tokens.identifierNameAtIndex(index));
|
||||
index++;
|
||||
if (this.tokens.matches1AtIndex(index, tt.comma)) {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.tokens.matches1AtIndex(index, tt.star)) {
|
||||
// * as
|
||||
index += 2;
|
||||
wildcardNames.push(this.tokens.identifierNameAtIndex(index));
|
||||
index++;
|
||||
}
|
||||
|
||||
if (this.tokens.matches1AtIndex(index, tt.braceL)) {
|
||||
const result = this.getNamedImports(index + 1);
|
||||
index = result.newIndex;
|
||||
|
||||
for (const namedImport of result.namedImports) {
|
||||
// Treat {default as X} as a default import to ensure usage of require interop helper
|
||||
if (namedImport.importedName === "default") {
|
||||
defaultNames.push(namedImport.localName);
|
||||
} else {
|
||||
namedImports.push(namedImport);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.tokens.matchesContextualAtIndex(index, ContextualKeyword._from)) {
|
||||
index++;
|
||||
}
|
||||
|
||||
if (!this.tokens.matches1AtIndex(index, tt.string)) {
|
||||
throw new Error("Expected string token at the end of import statement.");
|
||||
}
|
||||
const path = this.tokens.stringValueAtIndex(index);
|
||||
const importInfo = this.getImportInfo(path);
|
||||
importInfo.defaultNames.push(...defaultNames);
|
||||
importInfo.wildcardNames.push(...wildcardNames);
|
||||
importInfo.namedImports.push(...namedImports);
|
||||
if (defaultNames.length === 0 && wildcardNames.length === 0 && namedImports.length === 0) {
|
||||
importInfo.hasBareImport = true;
|
||||
}
|
||||
}
|
||||
|
||||
preprocessExportAtIndex(index) {
|
||||
if (
|
||||
this.tokens.matches2AtIndex(index, tt._export, tt._var) ||
|
||||
this.tokens.matches2AtIndex(index, tt._export, tt._let) ||
|
||||
this.tokens.matches2AtIndex(index, tt._export, tt._const)
|
||||
) {
|
||||
this.preprocessVarExportAtIndex(index);
|
||||
} else if (
|
||||
this.tokens.matches2AtIndex(index, tt._export, tt._function) ||
|
||||
this.tokens.matches2AtIndex(index, tt._export, tt._class)
|
||||
) {
|
||||
const exportName = this.tokens.identifierNameAtIndex(index + 2);
|
||||
this.addExportBinding(exportName, exportName);
|
||||
} else if (this.tokens.matches3AtIndex(index, tt._export, tt.name, tt._function)) {
|
||||
const exportName = this.tokens.identifierNameAtIndex(index + 3);
|
||||
this.addExportBinding(exportName, exportName);
|
||||
} else if (this.tokens.matches2AtIndex(index, tt._export, tt.braceL)) {
|
||||
this.preprocessNamedExportAtIndex(index);
|
||||
} else if (this.tokens.matches2AtIndex(index, tt._export, tt.star)) {
|
||||
this.preprocessExportStarAtIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
preprocessVarExportAtIndex(index) {
|
||||
let depth = 0;
|
||||
// Handle cases like `export let {x} = y;`, starting at the open-brace in that case.
|
||||
for (let i = index + 2; ; i++) {
|
||||
if (
|
||||
this.tokens.matches1AtIndex(i, tt.braceL) ||
|
||||
this.tokens.matches1AtIndex(i, tt.dollarBraceL) ||
|
||||
this.tokens.matches1AtIndex(i, tt.bracketL)
|
||||
) {
|
||||
depth++;
|
||||
} else if (
|
||||
this.tokens.matches1AtIndex(i, tt.braceR) ||
|
||||
this.tokens.matches1AtIndex(i, tt.bracketR)
|
||||
) {
|
||||
depth--;
|
||||
} else if (depth === 0 && !this.tokens.matches1AtIndex(i, tt.name)) {
|
||||
break;
|
||||
} else if (this.tokens.matches1AtIndex(1, tt.eq)) {
|
||||
const endIndex = this.tokens.currentToken().rhsEndIndex;
|
||||
if (endIndex == null) {
|
||||
throw new Error("Expected = token with an end index.");
|
||||
}
|
||||
i = endIndex - 1;
|
||||
} else {
|
||||
const token = this.tokens.tokens[i];
|
||||
if (isDeclaration(token)) {
|
||||
const exportName = this.tokens.identifierNameAtIndex(i);
|
||||
this.identifierReplacements.set(exportName, `exports.${exportName}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk this export statement just in case it's an export...from statement.
|
||||
* If it is, combine it into the import info for that path. Otherwise, just
|
||||
* bail out; it'll be handled later.
|
||||
*/
|
||||
preprocessNamedExportAtIndex(index) {
|
||||
// export {
|
||||
index += 2;
|
||||
const {newIndex, namedImports} = this.getNamedImports(index);
|
||||
index = newIndex;
|
||||
|
||||
if (this.tokens.matchesContextualAtIndex(index, ContextualKeyword._from)) {
|
||||
index++;
|
||||
} else {
|
||||
// Reinterpret "a as b" to be local/exported rather than imported/local.
|
||||
for (const {importedName: localName, localName: exportedName} of namedImports) {
|
||||
this.addExportBinding(localName, exportedName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.tokens.matches1AtIndex(index, tt.string)) {
|
||||
throw new Error("Expected string token at the end of import statement.");
|
||||
}
|
||||
const path = this.tokens.stringValueAtIndex(index);
|
||||
const importInfo = this.getImportInfo(path);
|
||||
importInfo.namedExports.push(...namedImports);
|
||||
}
|
||||
|
||||
preprocessExportStarAtIndex(index) {
|
||||
let exportedName = null;
|
||||
if (this.tokens.matches3AtIndex(index, tt._export, tt.star, tt._as)) {
|
||||
// export * as
|
||||
index += 3;
|
||||
exportedName = this.tokens.identifierNameAtIndex(index);
|
||||
// foo from
|
||||
index += 2;
|
||||
} else {
|
||||
// export * from
|
||||
index += 3;
|
||||
}
|
||||
if (!this.tokens.matches1AtIndex(index, tt.string)) {
|
||||
throw new Error("Expected string token at the end of star export statement.");
|
||||
}
|
||||
const path = this.tokens.stringValueAtIndex(index);
|
||||
const importInfo = this.getImportInfo(path);
|
||||
if (exportedName !== null) {
|
||||
importInfo.exportStarNames.push(exportedName);
|
||||
} else {
|
||||
importInfo.hasStarExport = true;
|
||||
}
|
||||
}
|
||||
|
||||
getNamedImports(index) {
|
||||
const namedImports = [];
|
||||
while (true) {
|
||||
if (this.tokens.matches1AtIndex(index, tt.braceR)) {
|
||||
index++;
|
||||
break;
|
||||
}
|
||||
|
||||
const specifierInfo = getImportExportSpecifierInfo(this.tokens, index);
|
||||
index = specifierInfo.endIndex;
|
||||
if (!specifierInfo.isType) {
|
||||
namedImports.push({
|
||||
importedName: specifierInfo.leftName,
|
||||
localName: specifierInfo.rightName,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.tokens.matches2AtIndex(index, tt.comma, tt.braceR)) {
|
||||
index += 2;
|
||||
break;
|
||||
} else if (this.tokens.matches1AtIndex(index, tt.braceR)) {
|
||||
index++;
|
||||
break;
|
||||
} else if (this.tokens.matches1AtIndex(index, tt.comma)) {
|
||||
index++;
|
||||
} else {
|
||||
throw new Error(`Unexpected token: ${JSON.stringify(this.tokens.tokens[index])}`);
|
||||
}
|
||||
}
|
||||
return {newIndex: index, namedImports};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a mutable import info object for this path, creating one if it doesn't
|
||||
* exist yet.
|
||||
*/
|
||||
getImportInfo(path) {
|
||||
const existingInfo = this.importInfoByPath.get(path);
|
||||
if (existingInfo) {
|
||||
return existingInfo;
|
||||
}
|
||||
const newInfo = {
|
||||
defaultNames: [],
|
||||
wildcardNames: [],
|
||||
namedImports: [],
|
||||
namedExports: [],
|
||||
hasBareImport: false,
|
||||
exportStarNames: [],
|
||||
hasStarExport: false,
|
||||
};
|
||||
this.importInfoByPath.set(path, newInfo);
|
||||
return newInfo;
|
||||
}
|
||||
|
||||
addExportBinding(localName, exportedName) {
|
||||
if (!this.exportBindingsByLocalName.has(localName)) {
|
||||
this.exportBindingsByLocalName.set(localName, []);
|
||||
}
|
||||
this.exportBindingsByLocalName.get(localName).push(exportedName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the code to use for the import for this path, or the empty string if
|
||||
* the code has already been "claimed" by a previous import.
|
||||
*/
|
||||
claimImportCode(importPath) {
|
||||
const result = this.importsToReplace.get(importPath);
|
||||
this.importsToReplace.set(importPath, "");
|
||||
return result || "";
|
||||
}
|
||||
|
||||
getIdentifierReplacement(identifierName) {
|
||||
return this.identifierReplacements.get(identifierName) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string like `exports.foo = exports.bar`.
|
||||
*/
|
||||
resolveExportBinding(assignedName) {
|
||||
const exportedNames = this.exportBindingsByLocalName.get(assignedName);
|
||||
if (!exportedNames || exportedNames.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return exportedNames.map((exportedName) => `exports.${exportedName}`).join(" = ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all imported/exported names where we might be interested in whether usages of those
|
||||
* names are shadowed.
|
||||
*/
|
||||
getGlobalNames() {
|
||||
return new Set([
|
||||
...this.identifierReplacements.keys(),
|
||||
...this.exportBindingsByLocalName.keys(),
|
||||
]);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user