"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var _tokenizer = require('../parser/tokenizer'); var _keywords = require('../parser/tokenizer/keywords'); var _types = require('../parser/tokenizer/types'); var _elideImportEquals = require('../util/elideImportEquals'); var _elideImportEquals2 = _interopRequireDefault(_elideImportEquals); var _getDeclarationInfo = require('../util/getDeclarationInfo'); var _getDeclarationInfo2 = _interopRequireDefault(_getDeclarationInfo); var _getImportExportSpecifierInfo = require('../util/getImportExportSpecifierInfo'); var _getImportExportSpecifierInfo2 = _interopRequireDefault(_getImportExportSpecifierInfo); var _isExportFrom = require('../util/isExportFrom'); var _isExportFrom2 = _interopRequireDefault(_isExportFrom); var _removeMaybeImportAttributes = require('../util/removeMaybeImportAttributes'); var _shouldElideDefaultExport = require('../util/shouldElideDefaultExport'); var _shouldElideDefaultExport2 = _interopRequireDefault(_shouldElideDefaultExport); var _Transformer = require('./Transformer'); var _Transformer2 = _interopRequireDefault(_Transformer); /** * Class for editing import statements when we are transforming to commonjs. */ class CJSImportTransformer extends _Transformer2.default { __init() {this.hadExport = false} __init2() {this.hadNamedExport = false} __init3() {this.hadDefaultExport = false} constructor( rootTransformer, tokens, importProcessor, nameManager, helperManager, reactHotLoaderTransformer, enableLegacyBabel5ModuleInterop, enableLegacyTypeScriptModuleInterop, isTypeScriptTransformEnabled, isFlowTransformEnabled, preserveDynamicImport, keepUnusedImports, ) { super();this.rootTransformer = rootTransformer;this.tokens = tokens;this.importProcessor = importProcessor;this.nameManager = nameManager;this.helperManager = helperManager;this.reactHotLoaderTransformer = reactHotLoaderTransformer;this.enableLegacyBabel5ModuleInterop = enableLegacyBabel5ModuleInterop;this.enableLegacyTypeScriptModuleInterop = enableLegacyTypeScriptModuleInterop;this.isTypeScriptTransformEnabled = isTypeScriptTransformEnabled;this.isFlowTransformEnabled = isFlowTransformEnabled;this.preserveDynamicImport = preserveDynamicImport;this.keepUnusedImports = keepUnusedImports;CJSImportTransformer.prototype.__init.call(this);CJSImportTransformer.prototype.__init2.call(this);CJSImportTransformer.prototype.__init3.call(this);; this.declarationInfo = isTypeScriptTransformEnabled ? _getDeclarationInfo2.default.call(void 0, tokens) : _getDeclarationInfo.EMPTY_DECLARATION_INFO; } getPrefixCode() { let prefix = ""; if (this.hadExport) { prefix += 'Object.defineProperty(exports, "__esModule", {value: true});'; } return prefix; } getSuffixCode() { if (this.enableLegacyBabel5ModuleInterop && this.hadDefaultExport && !this.hadNamedExport) { return "\nmodule.exports = exports.default;\n"; } return ""; } process() { // TypeScript `import foo = require('foo');` should always just be translated to plain require. if (this.tokens.matches3(_types.TokenType._import, _types.TokenType.name, _types.TokenType.eq)) { return this.processImportEquals(); } if (this.tokens.matches1(_types.TokenType._import)) { this.processImport(); return true; } if (this.tokens.matches2(_types.TokenType._export, _types.TokenType.eq)) { this.tokens.replaceToken("module.exports"); return true; } if (this.tokens.matches1(_types.TokenType._export) && !this.tokens.currentToken().isType) { this.hadExport = true; return this.processExport(); } if (this.tokens.matches2(_types.TokenType.name, _types.TokenType.postIncDec)) { // Fall through to normal identifier matching if this doesn't apply. if (this.processPostIncDec()) { return true; } } if (this.tokens.matches1(_types.TokenType.name) || this.tokens.matches1(_types.TokenType.jsxName)) { return this.processIdentifier(); } if (this.tokens.matches1(_types.TokenType.eq)) { return this.processAssignment(); } if (this.tokens.matches1(_types.TokenType.assign)) { return this.processComplexAssignment(); } if (this.tokens.matches1(_types.TokenType.preIncDec)) { return this.processPreIncDec(); } return false; } processImportEquals() { const importName = this.tokens.identifierNameAtIndex(this.tokens.currentIndex() + 1); if (this.importProcessor.shouldAutomaticallyElideImportedName(importName)) { // If this name is only used as a type, elide the whole import. _elideImportEquals2.default.call(void 0, this.tokens); } else { // Otherwise, switch `import` to `const`. this.tokens.replaceToken("const"); } return true; } /** * Transform this: * import foo, {bar} from 'baz'; * into * var _baz = require('baz'); var _baz2 = _interopRequireDefault(_baz); * * The import code was already generated in the import preprocessing step, so * we just need to look it up. */ processImport() { if (this.tokens.matches2(_types.TokenType._import, _types.TokenType.parenL)) { if (this.preserveDynamicImport) { // Bail out, only making progress for this one token. this.tokens.copyToken(); return; } const requireWrapper = this.enableLegacyTypeScriptModuleInterop ? "" : `${this.helperManager.getHelperName("interopRequireWildcard")}(`; this.tokens.replaceToken(`Promise.resolve().then(() => ${requireWrapper}require`); const contextId = this.tokens.currentToken().contextId; if (contextId == null) { throw new Error("Expected context ID on dynamic import invocation."); } this.tokens.copyToken(); while (!this.tokens.matchesContextIdAndLabel(_types.TokenType.parenR, contextId)) { this.rootTransformer.processToken(); } this.tokens.replaceToken(requireWrapper ? ")))" : "))"); return; } const shouldElideImport = this.removeImportAndDetectIfShouldElide(); if (shouldElideImport) { this.tokens.removeToken(); } else { const path = this.tokens.stringValue(); this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path)); this.tokens.appendCode(this.importProcessor.claimImportCode(path)); } _removeMaybeImportAttributes.removeMaybeImportAttributes.call(void 0, this.tokens); if (this.tokens.matches1(_types.TokenType.semi)) { this.tokens.removeToken(); } } /** * Erase this import (since any CJS output would be completely different), and * return true if this import is should be elided due to being a type-only * import. Such imports will not be emitted at all to avoid side effects. * * Import elision only happens with the TypeScript or Flow transforms enabled. * * TODO: This function has some awkward overlap with * CJSImportProcessor.pruneTypeOnlyImports , and the two should be unified. * That function handles TypeScript implicit import name elision, and removes * an import if all typical imported names (without `type`) are removed due * to being type-only imports. This function handles Flow import removal and * properly distinguishes `import 'foo'` from `import {} from 'foo'` for TS * purposes. * * The position should end at the import string. */ removeImportAndDetectIfShouldElide() { this.tokens.removeInitialToken(); if ( this.tokens.matchesContextual(_keywords.ContextualKeyword._type) && !this.tokens.matches1AtIndex(this.tokens.currentIndex() + 1, _types.TokenType.comma) && !this.tokens.matchesContextualAtIndex(this.tokens.currentIndex() + 1, _keywords.ContextualKeyword._from) ) { // This is an "import type" statement, so exit early. this.removeRemainingImport(); return true; } if (this.tokens.matches1(_types.TokenType.name) || this.tokens.matches1(_types.TokenType.star)) { // We have a default import or namespace import, so there must be some // non-type import. this.removeRemainingImport(); return false; } if (this.tokens.matches1(_types.TokenType.string)) { // This is a bare import, so we should proceed with the import. return false; } let foundNonTypeImport = false; let foundAnyNamedImport = false; while (!this.tokens.matches1(_types.TokenType.string)) { // Check if any named imports are of the form "foo" or "foo as bar", with // no leading "type". if ( (!foundNonTypeImport && this.tokens.matches1(_types.TokenType.braceL)) || this.tokens.matches1(_types.TokenType.comma) ) { this.tokens.removeToken(); if (!this.tokens.matches1(_types.TokenType.braceR)) { foundAnyNamedImport = true; } if ( this.tokens.matches2(_types.TokenType.name, _types.TokenType.comma) || this.tokens.matches2(_types.TokenType.name, _types.TokenType.braceR) || this.tokens.matches4(_types.TokenType.name, _types.TokenType.name, _types.TokenType.name, _types.TokenType.comma) || this.tokens.matches4(_types.TokenType.name, _types.TokenType.name, _types.TokenType.name, _types.TokenType.braceR) ) { foundNonTypeImport = true; } } this.tokens.removeToken(); } if (this.keepUnusedImports) { return false; } if (this.isTypeScriptTransformEnabled) { return !foundNonTypeImport; } else if (this.isFlowTransformEnabled) { // In Flow, unlike TS, `import {} from 'foo';` preserves the import. return foundAnyNamedImport && !foundNonTypeImport; } else { return false; } } removeRemainingImport() { while (!this.tokens.matches1(_types.TokenType.string)) { this.tokens.removeToken(); } } processIdentifier() { const token = this.tokens.currentToken(); if (token.shadowsGlobal) { return false; } if (token.identifierRole === _tokenizer.IdentifierRole.ObjectShorthand) { return this.processObjectShorthand(); } if (token.identifierRole !== _tokenizer.IdentifierRole.Access) { return false; } const replacement = this.importProcessor.getIdentifierReplacement( this.tokens.identifierNameForToken(token), ); if (!replacement) { return false; } // Tolerate any number of closing parens while looking for an opening paren // that indicates a function call. let possibleOpenParenIndex = this.tokens.currentIndex() + 1; while ( possibleOpenParenIndex < this.tokens.tokens.length && this.tokens.tokens[possibleOpenParenIndex].type === _types.TokenType.parenR ) { possibleOpenParenIndex++; } // Avoid treating imported functions as methods of their `exports` object // by using `(0, f)` when the identifier is in a paren expression. Else // use `Function.prototype.call` when the identifier is a guaranteed // function call. When using `call`, pass undefined as the context. if (this.tokens.tokens[possibleOpenParenIndex].type === _types.TokenType.parenL) { if ( this.tokens.tokenAtRelativeIndex(1).type === _types.TokenType.parenL && this.tokens.tokenAtRelativeIndex(-1).type !== _types.TokenType._new ) { this.tokens.replaceToken(`${replacement}.call(void 0, `); // Remove the old paren. this.tokens.removeToken(); // Balance out the new paren. this.rootTransformer.processBalancedCode(); this.tokens.copyExpectedToken(_types.TokenType.parenR); } else { // See here: http://2ality.com/2015/12/references.html this.tokens.replaceToken(`(0, ${replacement})`); } } else { this.tokens.replaceToken(replacement); } return true; } processObjectShorthand() { const identifier = this.tokens.identifierName(); const replacement = this.importProcessor.getIdentifierReplacement(identifier); if (!replacement) { return false; } this.tokens.replaceToken(`${identifier}: ${replacement}`); return true; } processExport() { if ( this.tokens.matches2(_types.TokenType._export, _types.TokenType._enum) || this.tokens.matches3(_types.TokenType._export, _types.TokenType._const, _types.TokenType._enum) ) { this.hadNamedExport = true; // Let the TypeScript transform handle it. return false; } if (this.tokens.matches2(_types.TokenType._export, _types.TokenType._default)) { if (this.tokens.matches3(_types.TokenType._export, _types.TokenType._default, _types.TokenType._enum)) { this.hadDefaultExport = true; // Flow export default enums need some special handling, so handle them // in that tranform rather than this one. return false; } this.processExportDefault(); return true; } else if (this.tokens.matches2(_types.TokenType._export, _types.TokenType.braceL)) { this.processExportBindings(); return true; } else if ( this.tokens.matches2(_types.TokenType._export, _types.TokenType.name) && this.tokens.matchesContextualAtIndex(this.tokens.currentIndex() + 1, _keywords.ContextualKeyword._type) ) { // export type {a}; // export type {a as b}; // export type {a} from './b'; // export type * from './b'; // export type * as ns from './b'; this.tokens.removeInitialToken(); this.tokens.removeToken(); if (this.tokens.matches1(_types.TokenType.braceL)) { while (!this.tokens.matches1(_types.TokenType.braceR)) { this.tokens.removeToken(); } this.tokens.removeToken(); } else { // * this.tokens.removeToken(); if (this.tokens.matches1(_types.TokenType._as)) { // as this.tokens.removeToken(); // ns this.tokens.removeToken(); } } // Remove type re-export `... } from './T'` if ( this.tokens.matchesContextual(_keywords.ContextualKeyword._from) && this.tokens.matches1AtIndex(this.tokens.currentIndex() + 1, _types.TokenType.string) ) { this.tokens.removeToken(); this.tokens.removeToken(); _removeMaybeImportAttributes.removeMaybeImportAttributes.call(void 0, this.tokens); } return true; } this.hadNamedExport = true; if ( this.tokens.matches2(_types.TokenType._export, _types.TokenType._var) || this.tokens.matches2(_types.TokenType._export, _types.TokenType._let) || this.tokens.matches2(_types.TokenType._export, _types.TokenType._const) ) { this.processExportVar(); return true; } else if ( this.tokens.matches2(_types.TokenType._export, _types.TokenType._function) || // export async function this.tokens.matches3(_types.TokenType._export, _types.TokenType.name, _types.TokenType._function) ) { this.processExportFunction(); return true; } else if ( this.tokens.matches2(_types.TokenType._export, _types.TokenType._class) || this.tokens.matches3(_types.TokenType._export, _types.TokenType._abstract, _types.TokenType._class) || this.tokens.matches2(_types.TokenType._export, _types.TokenType.at) ) { this.processExportClass(); return true; } else if (this.tokens.matches2(_types.TokenType._export, _types.TokenType.star)) { this.processExportStar(); return true; } else { throw new Error("Unrecognized export syntax."); } } processAssignment() { const index = this.tokens.currentIndex(); const identifierToken = this.tokens.tokens[index - 1]; // If the LHS is a type identifier, this must be a declaration like `let a: b = c;`, // with `b` as the identifier, so nothing needs to be done in that case. if (identifierToken.isType || identifierToken.type !== _types.TokenType.name) { return false; } if (identifierToken.shadowsGlobal) { return false; } if (index >= 2 && this.tokens.matches1AtIndex(index - 2, _types.TokenType.dot)) { return false; } if (index >= 2 && [_types.TokenType._var, _types.TokenType._let, _types.TokenType._const].includes(this.tokens.tokens[index - 2].type)) { // Declarations don't need an extra assignment. This doesn't avoid the // assignment for comma-separated declarations, but it's still correct // since the assignment is just redundant. return false; } const assignmentSnippet = this.importProcessor.resolveExportBinding( this.tokens.identifierNameForToken(identifierToken), ); if (!assignmentSnippet) { return false; } this.tokens.copyToken(); this.tokens.appendCode(` ${assignmentSnippet} =`); return true; } /** * Process something like `a += 3`, where `a` might be an exported value. */ processComplexAssignment() { const index = this.tokens.currentIndex(); const identifierToken = this.tokens.tokens[index - 1]; if (identifierToken.type !== _types.TokenType.name) { return false; } if (identifierToken.shadowsGlobal) { return false; } if (index >= 2 && this.tokens.matches1AtIndex(index - 2, _types.TokenType.dot)) { return false; } const assignmentSnippet = this.importProcessor.resolveExportBinding( this.tokens.identifierNameForToken(identifierToken), ); if (!assignmentSnippet) { return false; } this.tokens.appendCode(` = ${assignmentSnippet}`); this.tokens.copyToken(); return true; } /** * Process something like `++a`, where `a` might be an exported value. */ processPreIncDec() { const index = this.tokens.currentIndex(); const identifierToken = this.tokens.tokens[index + 1]; if (identifierToken.type !== _types.TokenType.name) { return false; } if (identifierToken.shadowsGlobal) { return false; } // Ignore things like ++a.b and ++a[b] and ++a().b. if ( index + 2 < this.tokens.tokens.length && (this.tokens.matches1AtIndex(index + 2, _types.TokenType.dot) || this.tokens.matches1AtIndex(index + 2, _types.TokenType.bracketL) || this.tokens.matches1AtIndex(index + 2, _types.TokenType.parenL)) ) { return false; } const identifierName = this.tokens.identifierNameForToken(identifierToken); const assignmentSnippet = this.importProcessor.resolveExportBinding(identifierName); if (!assignmentSnippet) { return false; } this.tokens.appendCode(`${assignmentSnippet} = `); this.tokens.copyToken(); return true; } /** * Process something like `a++`, where `a` might be an exported value. * This starts at the `a`, not at the `++`. */ processPostIncDec() { const index = this.tokens.currentIndex(); const identifierToken = this.tokens.tokens[index]; const operatorToken = this.tokens.tokens[index + 1]; if (identifierToken.type !== _types.TokenType.name) { return false; } if (identifierToken.shadowsGlobal) { return false; } if (index >= 1 && this.tokens.matches1AtIndex(index - 1, _types.TokenType.dot)) { return false; } const identifierName = this.tokens.identifierNameForToken(identifierToken); const assignmentSnippet = this.importProcessor.resolveExportBinding(identifierName); if (!assignmentSnippet) { return false; } const operatorCode = this.tokens.rawCodeForToken(operatorToken); // We might also replace the identifier with something like exports.x, so // do that replacement here as well. const base = this.importProcessor.getIdentifierReplacement(identifierName) || identifierName; if (operatorCode === "++") { this.tokens.replaceToken(`(${base} = ${assignmentSnippet} = ${base} + 1, ${base} - 1)`); } else if (operatorCode === "--") { this.tokens.replaceToken(`(${base} = ${assignmentSnippet} = ${base} - 1, ${base} + 1)`); } else { throw new Error(`Unexpected operator: ${operatorCode}`); } this.tokens.removeToken(); return true; } processExportDefault() { let exportedRuntimeValue = true; if ( this.tokens.matches4(_types.TokenType._export, _types.TokenType._default, _types.TokenType._function, _types.TokenType.name) || // export default async function (this.tokens.matches5(_types.TokenType._export, _types.TokenType._default, _types.TokenType.name, _types.TokenType._function, _types.TokenType.name) && this.tokens.matchesContextualAtIndex( this.tokens.currentIndex() + 2, _keywords.ContextualKeyword._async, )) ) { this.tokens.removeInitialToken(); this.tokens.removeToken(); // Named function export case: change it to a top-level function // declaration followed by exports statement. const name = this.processNamedFunction(); this.tokens.appendCode(` exports.default = ${name};`); } else if ( this.tokens.matches4(_types.TokenType._export, _types.TokenType._default, _types.TokenType._class, _types.TokenType.name) || this.tokens.matches5(_types.TokenType._export, _types.TokenType._default, _types.TokenType._abstract, _types.TokenType._class, _types.TokenType.name) || this.tokens.matches3(_types.TokenType._export, _types.TokenType._default, _types.TokenType.at) ) { this.tokens.removeInitialToken(); this.tokens.removeToken(); this.copyDecorators(); if (this.tokens.matches1(_types.TokenType._abstract)) { this.tokens.removeToken(); } const name = this.rootTransformer.processNamedClass(); this.tokens.appendCode(` exports.default = ${name};`); // After this point, this is a plain "export default E" statement. } else if ( _shouldElideDefaultExport2.default.call(void 0, this.isTypeScriptTransformEnabled, this.keepUnusedImports, this.tokens, this.declarationInfo, ) ) { // If the exported value is just an identifier and should be elided by TypeScript // rules, then remove it entirely. It will always have the form `export default e`, // where `e` is an identifier. exportedRuntimeValue = false; this.tokens.removeInitialToken(); this.tokens.removeToken(); this.tokens.removeToken(); } else if (this.reactHotLoaderTransformer) { // We need to assign E to a variable. Change "export default E" to // "let _default; exports.default = _default = E" const defaultVarName = this.nameManager.claimFreeName("_default"); this.tokens.replaceToken(`let ${defaultVarName}; exports.`); this.tokens.copyToken(); this.tokens.appendCode(` = ${defaultVarName} =`); this.reactHotLoaderTransformer.setExtractedDefaultExportName(defaultVarName); } else { // Change "export default E" to "exports.default = E" this.tokens.replaceToken("exports."); this.tokens.copyToken(); this.tokens.appendCode(" ="); } if (exportedRuntimeValue) { this.hadDefaultExport = true; } } copyDecorators() { while (this.tokens.matches1(_types.TokenType.at)) { this.tokens.copyToken(); if (this.tokens.matches1(_types.TokenType.parenL)) { this.tokens.copyExpectedToken(_types.TokenType.parenL); this.rootTransformer.processBalancedCode(); this.tokens.copyExpectedToken(_types.TokenType.parenR); } else { this.tokens.copyExpectedToken(_types.TokenType.name); while (this.tokens.matches1(_types.TokenType.dot)) { this.tokens.copyExpectedToken(_types.TokenType.dot); this.tokens.copyExpectedToken(_types.TokenType.name); } if (this.tokens.matches1(_types.TokenType.parenL)) { this.tokens.copyExpectedToken(_types.TokenType.parenL); this.rootTransformer.processBalancedCode(); this.tokens.copyExpectedToken(_types.TokenType.parenR); } } } } /** * Transform a declaration like `export var`, `export let`, or `export const`. */ processExportVar() { if (this.isSimpleExportVar()) { this.processSimpleExportVar(); } else { this.processComplexExportVar(); } } /** * Determine if the export is of the form: * export var/let/const [varName] = [expr]; * In other words, determine if function name inference might apply. */ isSimpleExportVar() { let tokenIndex = this.tokens.currentIndex(); // export tokenIndex++; // var/let/const tokenIndex++; if (!this.tokens.matches1AtIndex(tokenIndex, _types.TokenType.name)) { return false; } tokenIndex++; while (tokenIndex < this.tokens.tokens.length && this.tokens.tokens[tokenIndex].isType) { tokenIndex++; } if (!this.tokens.matches1AtIndex(tokenIndex, _types.TokenType.eq)) { return false; } return true; } /** * Transform an `export var` declaration initializing a single variable. * * For example, this: * export const f = () => {}; * becomes this: * const f = () => {}; exports.f = f; * * The variable is unused (e.g. exports.f has the true value of the export). * We need to produce an assignment of this form so that the function will * have an inferred name of "f", which wouldn't happen in the more general * case below. */ processSimpleExportVar() { // export this.tokens.removeInitialToken(); // var/let/const this.tokens.copyToken(); const varName = this.tokens.identifierName(); // x: number -> x while (!this.tokens.matches1(_types.TokenType.eq)) { this.rootTransformer.processToken(); } const endIndex = this.tokens.currentToken().rhsEndIndex; if (endIndex == null) { throw new Error("Expected = token with an end index."); } while (this.tokens.currentIndex() < endIndex) { this.rootTransformer.processToken(); } this.tokens.appendCode(`; exports.${varName} = ${varName}`); } /** * Transform normal declaration exports, including handling destructuring. * For example, this: * export const {x: [a = 2, b], c} = d; * becomes this: * ({x: [exports.a = 2, exports.b], c: exports.c} = d;) */ processComplexExportVar() { this.tokens.removeInitialToken(); this.tokens.removeToken(); const needsParens = this.tokens.matches1(_types.TokenType.braceL); if (needsParens) { this.tokens.appendCode("("); } let depth = 0; while (true) { if ( this.tokens.matches1(_types.TokenType.braceL) || this.tokens.matches1(_types.TokenType.dollarBraceL) || this.tokens.matches1(_types.TokenType.bracketL) ) { depth++; this.tokens.copyToken(); } else if (this.tokens.matches1(_types.TokenType.braceR) || this.tokens.matches1(_types.TokenType.bracketR)) { depth--; this.tokens.copyToken(); } else if ( depth === 0 && !this.tokens.matches1(_types.TokenType.name) && !this.tokens.currentToken().isType ) { break; } else if (this.tokens.matches1(_types.TokenType.eq)) { // Default values might have assignments in the RHS that we want to ignore, so skip past // them. const endIndex = this.tokens.currentToken().rhsEndIndex; if (endIndex == null) { throw new Error("Expected = token with an end index."); } while (this.tokens.currentIndex() < endIndex) { this.rootTransformer.processToken(); } } else { const token = this.tokens.currentToken(); if (_tokenizer.isDeclaration.call(void 0, token)) { const name = this.tokens.identifierName(); let replacement = this.importProcessor.getIdentifierReplacement(name); if (replacement === null) { throw new Error(`Expected a replacement for ${name} in \`export var\` syntax.`); } if (_tokenizer.isObjectShorthandDeclaration.call(void 0, token)) { replacement = `${name}: ${replacement}`; } this.tokens.replaceToken(replacement); } else { this.rootTransformer.processToken(); } } } if (needsParens) { // Seek to the end of the RHS. const endIndex = this.tokens.currentToken().rhsEndIndex; if (endIndex == null) { throw new Error("Expected = token with an end index."); } while (this.tokens.currentIndex() < endIndex) { this.rootTransformer.processToken(); } this.tokens.appendCode(")"); } } /** * Transform this: * export function foo() {} * into this: * function foo() {} exports.foo = foo; */ processExportFunction() { this.tokens.replaceToken(""); const name = this.processNamedFunction(); this.tokens.appendCode(` exports.${name} = ${name};`); } /** * Skip past a function with a name and return that name. */ processNamedFunction() { if (this.tokens.matches1(_types.TokenType._function)) { this.tokens.copyToken(); } else if (this.tokens.matches2(_types.TokenType.name, _types.TokenType._function)) { if (!this.tokens.matchesContextual(_keywords.ContextualKeyword._async)) { throw new Error("Expected async keyword in function export."); } this.tokens.copyToken(); this.tokens.copyToken(); } if (this.tokens.matches1(_types.TokenType.star)) { this.tokens.copyToken(); } if (!this.tokens.matches1(_types.TokenType.name)) { throw new Error("Expected identifier for exported function name."); } const name = this.tokens.identifierName(); this.tokens.copyToken(); if (this.tokens.currentToken().isType) { this.tokens.removeInitialToken(); while (this.tokens.currentToken().isType) { this.tokens.removeToken(); } } this.tokens.copyExpectedToken(_types.TokenType.parenL); this.rootTransformer.processBalancedCode(); this.tokens.copyExpectedToken(_types.TokenType.parenR); this.rootTransformer.processPossibleTypeRange(); this.tokens.copyExpectedToken(_types.TokenType.braceL); this.rootTransformer.processBalancedCode(); this.tokens.copyExpectedToken(_types.TokenType.braceR); return name; } /** * Transform this: * export class A {} * into this: * class A {} exports.A = A; */ processExportClass() { this.tokens.removeInitialToken(); this.copyDecorators(); if (this.tokens.matches1(_types.TokenType._abstract)) { this.tokens.removeToken(); } const name = this.rootTransformer.processNamedClass(); this.tokens.appendCode(` exports.${name} = ${name};`); } /** * Transform this: * export {a, b as c}; * into this: * exports.a = a; exports.c = b; * * OR * * Transform this: * export {a, b as c} from './foo'; * into the pre-generated Object.defineProperty code from the ImportProcessor. * * For the first case, if the TypeScript transform is enabled, we need to skip * exports that are only defined as types. */ processExportBindings() { this.tokens.removeInitialToken(); this.tokens.removeToken(); const isReExport = _isExportFrom2.default.call(void 0, this.tokens); const exportStatements = []; while (true) { if (this.tokens.matches1(_types.TokenType.braceR)) { this.tokens.removeToken(); break; } const specifierInfo = _getImportExportSpecifierInfo2.default.call(void 0, this.tokens); while (this.tokens.currentIndex() < specifierInfo.endIndex) { this.tokens.removeToken(); } const shouldRemoveExport = specifierInfo.isType || (!isReExport && this.shouldElideExportedIdentifier(specifierInfo.leftName)); if (!shouldRemoveExport) { const exportedName = specifierInfo.rightName; if (exportedName === "default") { this.hadDefaultExport = true; } else { this.hadNamedExport = true; } const localName = specifierInfo.leftName; const newLocalName = this.importProcessor.getIdentifierReplacement(localName); exportStatements.push(`exports.${exportedName} = ${newLocalName || localName};`); } if (this.tokens.matches1(_types.TokenType.braceR)) { this.tokens.removeToken(); break; } if (this.tokens.matches2(_types.TokenType.comma, _types.TokenType.braceR)) { this.tokens.removeToken(); this.tokens.removeToken(); break; } else if (this.tokens.matches1(_types.TokenType.comma)) { this.tokens.removeToken(); } else { throw new Error(`Unexpected token: ${JSON.stringify(this.tokens.currentToken())}`); } } if (this.tokens.matchesContextual(_keywords.ContextualKeyword._from)) { // This is an export...from, so throw away the normal named export code // and use the Object.defineProperty code from ImportProcessor. this.tokens.removeToken(); const path = this.tokens.stringValue(); this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path)); _removeMaybeImportAttributes.removeMaybeImportAttributes.call(void 0, this.tokens); } else { // This is a normal named export, so use that. this.tokens.appendCode(exportStatements.join(" ")); } if (this.tokens.matches1(_types.TokenType.semi)) { this.tokens.removeToken(); } } processExportStar() { this.tokens.removeInitialToken(); while (!this.tokens.matches1(_types.TokenType.string)) { this.tokens.removeToken(); } const path = this.tokens.stringValue(); this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path)); _removeMaybeImportAttributes.removeMaybeImportAttributes.call(void 0, this.tokens); if (this.tokens.matches1(_types.TokenType.semi)) { this.tokens.removeToken(); } } shouldElideExportedIdentifier(name) { return ( this.isTypeScriptTransformEnabled && !this.keepUnusedImports && !this.declarationInfo.valueDeclarations.has(name) ); } } exports.default = CJSImportTransformer;