summaryrefslogtreecommitdiff
path: root/node_modules/sucrase/dist/esm/transformers
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/sucrase/dist/esm/transformers')
-rw-r--r--node_modules/sucrase/dist/esm/transformers/CJSImportTransformer.js916
-rw-r--r--node_modules/sucrase/dist/esm/transformers/ESMImportTransformer.js415
-rw-r--r--node_modules/sucrase/dist/esm/transformers/FlowTransformer.js182
-rw-r--r--node_modules/sucrase/dist/esm/transformers/JSXTransformer.js733
-rw-r--r--node_modules/sucrase/dist/esm/transformers/JestHoistTransformer.js111
-rw-r--r--node_modules/sucrase/dist/esm/transformers/NumericSeparatorTransformer.js20
-rw-r--r--node_modules/sucrase/dist/esm/transformers/OptionalCatchBindingTransformer.js19
-rw-r--r--node_modules/sucrase/dist/esm/transformers/OptionalChainingNullishTransformer.js155
-rw-r--r--node_modules/sucrase/dist/esm/transformers/ReactDisplayNameTransformer.js160
-rw-r--r--node_modules/sucrase/dist/esm/transformers/ReactHotLoaderTransformer.js69
-rw-r--r--node_modules/sucrase/dist/esm/transformers/RootTransformer.js462
-rw-r--r--node_modules/sucrase/dist/esm/transformers/Transformer.js16
-rw-r--r--node_modules/sucrase/dist/esm/transformers/TypeScriptTransformer.js279
13 files changed, 3537 insertions, 0 deletions
diff --git a/node_modules/sucrase/dist/esm/transformers/CJSImportTransformer.js b/node_modules/sucrase/dist/esm/transformers/CJSImportTransformer.js
new file mode 100644
index 0000000..78cf896
--- /dev/null
+++ b/node_modules/sucrase/dist/esm/transformers/CJSImportTransformer.js
@@ -0,0 +1,916 @@
+
+
+
+import {IdentifierRole, isDeclaration, isObjectShorthandDeclaration} from "../parser/tokenizer";
+import {ContextualKeyword} from "../parser/tokenizer/keywords";
+import {TokenType as tt} from "../parser/tokenizer/types";
+
+import elideImportEquals from "../util/elideImportEquals";
+import getDeclarationInfo, {
+
+ EMPTY_DECLARATION_INFO,
+} from "../util/getDeclarationInfo";
+import getImportExportSpecifierInfo from "../util/getImportExportSpecifierInfo";
+import isExportFrom from "../util/isExportFrom";
+import {removeMaybeImportAttributes} from "../util/removeMaybeImportAttributes";
+import shouldElideDefaultExport from "../util/shouldElideDefaultExport";
+
+
+import Transformer from "./Transformer";
+
+/**
+ * Class for editing import statements when we are transforming to commonjs.
+ */
+export default class CJSImportTransformer extends Transformer {
+ __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
+ ? getDeclarationInfo(tokens)
+ : 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(tt._import, tt.name, tt.eq)) {
+ return this.processImportEquals();
+ }
+ if (this.tokens.matches1(tt._import)) {
+ this.processImport();
+ return true;
+ }
+ if (this.tokens.matches2(tt._export, tt.eq)) {
+ this.tokens.replaceToken("module.exports");
+ return true;
+ }
+ if (this.tokens.matches1(tt._export) && !this.tokens.currentToken().isType) {
+ this.hadExport = true;
+ return this.processExport();
+ }
+ if (this.tokens.matches2(tt.name, tt.postIncDec)) {
+ // Fall through to normal identifier matching if this doesn't apply.
+ if (this.processPostIncDec()) {
+ return true;
+ }
+ }
+ if (this.tokens.matches1(tt.name) || this.tokens.matches1(tt.jsxName)) {
+ return this.processIdentifier();
+ }
+ if (this.tokens.matches1(tt.eq)) {
+ return this.processAssignment();
+ }
+ if (this.tokens.matches1(tt.assign)) {
+ return this.processComplexAssignment();
+ }
+ if (this.tokens.matches1(tt.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.
+ elideImportEquals(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(tt._import, tt.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(tt.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(this.tokens);
+ if (this.tokens.matches1(tt.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(ContextualKeyword._type) &&
+ !this.tokens.matches1AtIndex(this.tokens.currentIndex() + 1, tt.comma) &&
+ !this.tokens.matchesContextualAtIndex(this.tokens.currentIndex() + 1, ContextualKeyword._from)
+ ) {
+ // This is an "import type" statement, so exit early.
+ this.removeRemainingImport();
+ return true;
+ }
+
+ if (this.tokens.matches1(tt.name) || this.tokens.matches1(tt.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(tt.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(tt.string)) {
+ // Check if any named imports are of the form "foo" or "foo as bar", with
+ // no leading "type".
+ if (
+ (!foundNonTypeImport && this.tokens.matches1(tt.braceL)) ||
+ this.tokens.matches1(tt.comma)
+ ) {
+ this.tokens.removeToken();
+ if (!this.tokens.matches1(tt.braceR)) {
+ foundAnyNamedImport = true;
+ }
+ if (
+ this.tokens.matches2(tt.name, tt.comma) ||
+ this.tokens.matches2(tt.name, tt.braceR) ||
+ this.tokens.matches4(tt.name, tt.name, tt.name, tt.comma) ||
+ this.tokens.matches4(tt.name, tt.name, tt.name, tt.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(tt.string)) {
+ this.tokens.removeToken();
+ }
+ }
+
+ processIdentifier() {
+ const token = this.tokens.currentToken();
+ if (token.shadowsGlobal) {
+ return false;
+ }
+
+ if (token.identifierRole === IdentifierRole.ObjectShorthand) {
+ return this.processObjectShorthand();
+ }
+
+ if (token.identifierRole !== 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 === tt.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 === tt.parenL) {
+ if (
+ this.tokens.tokenAtRelativeIndex(1).type === tt.parenL &&
+ this.tokens.tokenAtRelativeIndex(-1).type !== tt._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(tt.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(tt._export, tt._enum) ||
+ this.tokens.matches3(tt._export, tt._const, tt._enum)
+ ) {
+ this.hadNamedExport = true;
+ // Let the TypeScript transform handle it.
+ return false;
+ }
+ if (this.tokens.matches2(tt._export, tt._default)) {
+ if (this.tokens.matches3(tt._export, tt._default, tt._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(tt._export, tt.braceL)) {
+ this.processExportBindings();
+ return true;
+ } else if (
+ this.tokens.matches2(tt._export, tt.name) &&
+ this.tokens.matchesContextualAtIndex(this.tokens.currentIndex() + 1, 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(tt.braceL)) {
+ while (!this.tokens.matches1(tt.braceR)) {
+ this.tokens.removeToken();
+ }
+ this.tokens.removeToken();
+ } else {
+ // *
+ this.tokens.removeToken();
+ if (this.tokens.matches1(tt._as)) {
+ // as
+ this.tokens.removeToken();
+ // ns
+ this.tokens.removeToken();
+ }
+ }
+ // Remove type re-export `... } from './T'`
+ if (
+ this.tokens.matchesContextual(ContextualKeyword._from) &&
+ this.tokens.matches1AtIndex(this.tokens.currentIndex() + 1, tt.string)
+ ) {
+ this.tokens.removeToken();
+ this.tokens.removeToken();
+ removeMaybeImportAttributes(this.tokens);
+ }
+ return true;
+ }
+ this.hadNamedExport = true;
+ if (
+ this.tokens.matches2(tt._export, tt._var) ||
+ this.tokens.matches2(tt._export, tt._let) ||
+ this.tokens.matches2(tt._export, tt._const)
+ ) {
+ this.processExportVar();
+ return true;
+ } else if (
+ this.tokens.matches2(tt._export, tt._function) ||
+ // export async function
+ this.tokens.matches3(tt._export, tt.name, tt._function)
+ ) {
+ this.processExportFunction();
+ return true;
+ } else if (
+ this.tokens.matches2(tt._export, tt._class) ||
+ this.tokens.matches3(tt._export, tt._abstract, tt._class) ||
+ this.tokens.matches2(tt._export, tt.at)
+ ) {
+ this.processExportClass();
+ return true;
+ } else if (this.tokens.matches2(tt._export, tt.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 !== tt.name) {
+ return false;
+ }
+ if (identifierToken.shadowsGlobal) {
+ return false;
+ }
+ if (index >= 2 && this.tokens.matches1AtIndex(index - 2, tt.dot)) {
+ return false;
+ }
+ if (index >= 2 && [tt._var, tt._let, tt._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 !== tt.name) {
+ return false;
+ }
+ if (identifierToken.shadowsGlobal) {
+ return false;
+ }
+ if (index >= 2 && this.tokens.matches1AtIndex(index - 2, tt.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 !== tt.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, tt.dot) ||
+ this.tokens.matches1AtIndex(index + 2, tt.bracketL) ||
+ this.tokens.matches1AtIndex(index + 2, tt.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 !== tt.name) {
+ return false;
+ }
+ if (identifierToken.shadowsGlobal) {
+ return false;
+ }
+ if (index >= 1 && this.tokens.matches1AtIndex(index - 1, tt.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(tt._export, tt._default, tt._function, tt.name) ||
+ // export default async function
+ (this.tokens.matches5(tt._export, tt._default, tt.name, tt._function, tt.name) &&
+ this.tokens.matchesContextualAtIndex(
+ this.tokens.currentIndex() + 2,
+ 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(tt._export, tt._default, tt._class, tt.name) ||
+ this.tokens.matches5(tt._export, tt._default, tt._abstract, tt._class, tt.name) ||
+ this.tokens.matches3(tt._export, tt._default, tt.at)
+ ) {
+ this.tokens.removeInitialToken();
+ this.tokens.removeToken();
+ this.copyDecorators();
+ if (this.tokens.matches1(tt._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 (
+ shouldElideDefaultExport(
+ 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(tt.at)) {
+ this.tokens.copyToken();
+ if (this.tokens.matches1(tt.parenL)) {
+ this.tokens.copyExpectedToken(tt.parenL);
+ this.rootTransformer.processBalancedCode();
+ this.tokens.copyExpectedToken(tt.parenR);
+ } else {
+ this.tokens.copyExpectedToken(tt.name);
+ while (this.tokens.matches1(tt.dot)) {
+ this.tokens.copyExpectedToken(tt.dot);
+ this.tokens.copyExpectedToken(tt.name);
+ }
+ if (this.tokens.matches1(tt.parenL)) {
+ this.tokens.copyExpectedToken(tt.parenL);
+ this.rootTransformer.processBalancedCode();
+ this.tokens.copyExpectedToken(tt.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, tt.name)) {
+ return false;
+ }
+ tokenIndex++;
+ while (tokenIndex < this.tokens.tokens.length && this.tokens.tokens[tokenIndex].isType) {
+ tokenIndex++;
+ }
+ if (!this.tokens.matches1AtIndex(tokenIndex, tt.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(tt.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(tt.braceL);
+ if (needsParens) {
+ this.tokens.appendCode("(");
+ }
+
+ let depth = 0;
+ while (true) {
+ if (
+ this.tokens.matches1(tt.braceL) ||
+ this.tokens.matches1(tt.dollarBraceL) ||
+ this.tokens.matches1(tt.bracketL)
+ ) {
+ depth++;
+ this.tokens.copyToken();
+ } else if (this.tokens.matches1(tt.braceR) || this.tokens.matches1(tt.bracketR)) {
+ depth--;
+ this.tokens.copyToken();
+ } else if (
+ depth === 0 &&
+ !this.tokens.matches1(tt.name) &&
+ !this.tokens.currentToken().isType
+ ) {
+ break;
+ } else if (this.tokens.matches1(tt.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 (isDeclaration(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 (isObjectShorthandDeclaration(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(tt._function)) {
+ this.tokens.copyToken();
+ } else if (this.tokens.matches2(tt.name, tt._function)) {
+ if (!this.tokens.matchesContextual(ContextualKeyword._async)) {
+ throw new Error("Expected async keyword in function export.");
+ }
+ this.tokens.copyToken();
+ this.tokens.copyToken();
+ }
+ if (this.tokens.matches1(tt.star)) {
+ this.tokens.copyToken();
+ }
+ if (!this.tokens.matches1(tt.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(tt.parenL);
+ this.rootTransformer.processBalancedCode();
+ this.tokens.copyExpectedToken(tt.parenR);
+ this.rootTransformer.processPossibleTypeRange();
+ this.tokens.copyExpectedToken(tt.braceL);
+ this.rootTransformer.processBalancedCode();
+ this.tokens.copyExpectedToken(tt.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(tt._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 = isExportFrom(this.tokens);
+
+ const exportStatements = [];
+ while (true) {
+ if (this.tokens.matches1(tt.braceR)) {
+ this.tokens.removeToken();
+ break;
+ }
+
+ const specifierInfo = getImportExportSpecifierInfo(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(tt.braceR)) {
+ this.tokens.removeToken();
+ break;
+ }
+ if (this.tokens.matches2(tt.comma, tt.braceR)) {
+ this.tokens.removeToken();
+ this.tokens.removeToken();
+ break;
+ } else if (this.tokens.matches1(tt.comma)) {
+ this.tokens.removeToken();
+ } else {
+ throw new Error(`Unexpected token: ${JSON.stringify(this.tokens.currentToken())}`);
+ }
+ }
+
+ if (this.tokens.matchesContextual(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(this.tokens);
+ } else {
+ // This is a normal named export, so use that.
+ this.tokens.appendCode(exportStatements.join(" "));
+ }
+
+ if (this.tokens.matches1(tt.semi)) {
+ this.tokens.removeToken();
+ }
+ }
+
+ processExportStar() {
+ this.tokens.removeInitialToken();
+ while (!this.tokens.matches1(tt.string)) {
+ this.tokens.removeToken();
+ }
+ const path = this.tokens.stringValue();
+ this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path));
+ removeMaybeImportAttributes(this.tokens);
+ if (this.tokens.matches1(tt.semi)) {
+ this.tokens.removeToken();
+ }
+ }
+
+ shouldElideExportedIdentifier(name) {
+ return (
+ this.isTypeScriptTransformEnabled &&
+ !this.keepUnusedImports &&
+ !this.declarationInfo.valueDeclarations.has(name)
+ );
+ }
+}
diff --git a/node_modules/sucrase/dist/esm/transformers/ESMImportTransformer.js b/node_modules/sucrase/dist/esm/transformers/ESMImportTransformer.js
new file mode 100644
index 0000000..b45cd3e
--- /dev/null
+++ b/node_modules/sucrase/dist/esm/transformers/ESMImportTransformer.js
@@ -0,0 +1,415 @@
+
+
+
+import {ContextualKeyword} from "../parser/tokenizer/keywords";
+import {TokenType as tt} from "../parser/tokenizer/types";
+
+import elideImportEquals from "../util/elideImportEquals";
+import getDeclarationInfo, {
+
+ EMPTY_DECLARATION_INFO,
+} from "../util/getDeclarationInfo";
+import getImportExportSpecifierInfo from "../util/getImportExportSpecifierInfo";
+import {getNonTypeIdentifiers} from "../util/getNonTypeIdentifiers";
+import isExportFrom from "../util/isExportFrom";
+import {removeMaybeImportAttributes} from "../util/removeMaybeImportAttributes";
+import shouldElideDefaultExport from "../util/shouldElideDefaultExport";
+
+import Transformer from "./Transformer";
+
+/**
+ * Class for editing import statements when we are keeping the code as ESM. We still need to remove
+ * type-only imports in TypeScript and Flow.
+ */
+export default class ESMImportTransformer extends Transformer {
+
+
+
+
+ constructor(
+ tokens,
+ nameManager,
+ helperManager,
+ reactHotLoaderTransformer,
+ isTypeScriptTransformEnabled,
+ isFlowTransformEnabled,
+ keepUnusedImports,
+ options,
+ ) {
+ super();this.tokens = tokens;this.nameManager = nameManager;this.helperManager = helperManager;this.reactHotLoaderTransformer = reactHotLoaderTransformer;this.isTypeScriptTransformEnabled = isTypeScriptTransformEnabled;this.isFlowTransformEnabled = isFlowTransformEnabled;this.keepUnusedImports = keepUnusedImports;;
+ this.nonTypeIdentifiers =
+ isTypeScriptTransformEnabled && !keepUnusedImports
+ ? getNonTypeIdentifiers(tokens, options)
+ : new Set();
+ this.declarationInfo =
+ isTypeScriptTransformEnabled && !keepUnusedImports
+ ? getDeclarationInfo(tokens)
+ : EMPTY_DECLARATION_INFO;
+ this.injectCreateRequireForImportRequire = Boolean(options.injectCreateRequireForImportRequire);
+ }
+
+ process() {
+ // TypeScript `import foo = require('foo');` should always just be translated to plain require.
+ if (this.tokens.matches3(tt._import, tt.name, tt.eq)) {
+ return this.processImportEquals();
+ }
+ if (
+ this.tokens.matches4(tt._import, tt.name, tt.name, tt.eq) &&
+ this.tokens.matchesContextualAtIndex(this.tokens.currentIndex() + 1, ContextualKeyword._type)
+ ) {
+ // import type T = require('T')
+ this.tokens.removeInitialToken();
+ // This construct is always exactly 8 tokens long, so remove the 7 remaining tokens.
+ for (let i = 0; i < 7; i++) {
+ this.tokens.removeToken();
+ }
+ return true;
+ }
+ if (this.tokens.matches2(tt._export, tt.eq)) {
+ this.tokens.replaceToken("module.exports");
+ return true;
+ }
+ if (
+ this.tokens.matches5(tt._export, tt._import, tt.name, tt.name, tt.eq) &&
+ this.tokens.matchesContextualAtIndex(this.tokens.currentIndex() + 2, ContextualKeyword._type)
+ ) {
+ // export import type T = require('T')
+ this.tokens.removeInitialToken();
+ // This construct is always exactly 9 tokens long, so remove the 8 remaining tokens.
+ for (let i = 0; i < 8; i++) {
+ this.tokens.removeToken();
+ }
+ return true;
+ }
+ if (this.tokens.matches1(tt._import)) {
+ return this.processImport();
+ }
+ if (this.tokens.matches2(tt._export, tt._default)) {
+ return this.processExportDefault();
+ }
+ if (this.tokens.matches2(tt._export, tt.braceL)) {
+ return this.processNamedExports();
+ }
+ if (
+ this.tokens.matches2(tt._export, tt.name) &&
+ this.tokens.matchesContextualAtIndex(this.tokens.currentIndex() + 1, 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(tt.braceL)) {
+ while (!this.tokens.matches1(tt.braceR)) {
+ this.tokens.removeToken();
+ }
+ this.tokens.removeToken();
+ } else {
+ // *
+ this.tokens.removeToken();
+ if (this.tokens.matches1(tt._as)) {
+ // as
+ this.tokens.removeToken();
+ // ns
+ this.tokens.removeToken();
+ }
+ }
+ // Remove type re-export `... } from './T'`
+ if (
+ this.tokens.matchesContextual(ContextualKeyword._from) &&
+ this.tokens.matches1AtIndex(this.tokens.currentIndex() + 1, tt.string)
+ ) {
+ this.tokens.removeToken();
+ this.tokens.removeToken();
+ removeMaybeImportAttributes(this.tokens);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ processImportEquals() {
+ const importName = this.tokens.identifierNameAtIndex(this.tokens.currentIndex() + 1);
+ if (this.shouldAutomaticallyElideImportedName(importName)) {
+ // If this name is only used as a type, elide the whole import.
+ elideImportEquals(this.tokens);
+ } else if (this.injectCreateRequireForImportRequire) {
+ // We're using require in an environment (Node ESM) that doesn't provide
+ // it as a global, so generate a helper to import it.
+ // import -> const
+ this.tokens.replaceToken("const");
+ // Foo
+ this.tokens.copyToken();
+ // =
+ this.tokens.copyToken();
+ // require
+ this.tokens.replaceToken(this.helperManager.getHelperName("require"));
+ } else {
+ // Otherwise, just switch `import` to `const`.
+ this.tokens.replaceToken("const");
+ }
+ return true;
+ }
+
+ processImport() {
+ if (this.tokens.matches2(tt._import, tt.parenL)) {
+ // Dynamic imports don't need to be transformed.
+ return false;
+ }
+
+ const snapshot = this.tokens.snapshot();
+ const allImportsRemoved = this.removeImportTypeBindings();
+ if (allImportsRemoved) {
+ this.tokens.restoreToSnapshot(snapshot);
+ while (!this.tokens.matches1(tt.string)) {
+ this.tokens.removeToken();
+ }
+ this.tokens.removeToken();
+ removeMaybeImportAttributes(this.tokens);
+ if (this.tokens.matches1(tt.semi)) {
+ this.tokens.removeToken();
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Remove type bindings from this import, leaving the rest of the import intact.
+ *
+ * Return true if this import was ONLY types, and thus is eligible for removal. This will bail out
+ * of the replacement operation, so we can return early here.
+ */
+ removeImportTypeBindings() {
+ this.tokens.copyExpectedToken(tt._import);
+ if (
+ this.tokens.matchesContextual(ContextualKeyword._type) &&
+ !this.tokens.matches1AtIndex(this.tokens.currentIndex() + 1, tt.comma) &&
+ !this.tokens.matchesContextualAtIndex(this.tokens.currentIndex() + 1, ContextualKeyword._from)
+ ) {
+ // This is an "import type" statement, so exit early.
+ return true;
+ }
+
+ if (this.tokens.matches1(tt.string)) {
+ // This is a bare import, so we should proceed with the import.
+ this.tokens.copyToken();
+ return false;
+ }
+
+ // Skip the "module" token in import reflection.
+ if (
+ this.tokens.matchesContextual(ContextualKeyword._module) &&
+ this.tokens.matchesContextualAtIndex(this.tokens.currentIndex() + 2, ContextualKeyword._from)
+ ) {
+ this.tokens.copyToken();
+ }
+
+ let foundNonTypeImport = false;
+ let foundAnyNamedImport = false;
+ let needsComma = false;
+
+ // Handle default import.
+ if (this.tokens.matches1(tt.name)) {
+ if (this.shouldAutomaticallyElideImportedName(this.tokens.identifierName())) {
+ this.tokens.removeToken();
+ if (this.tokens.matches1(tt.comma)) {
+ this.tokens.removeToken();
+ }
+ } else {
+ foundNonTypeImport = true;
+ this.tokens.copyToken();
+ if (this.tokens.matches1(tt.comma)) {
+ // We're in a statement like:
+ // import A, * as B from './A';
+ // or
+ // import A, {foo} from './A';
+ // where the `A` is being kept. The comma should be removed if an only
+ // if the next part of the import statement is elided, but that's hard
+ // to determine at this point in the code. Instead, always remove it
+ // and set a flag to add it back if necessary.
+ needsComma = true;
+ this.tokens.removeToken();
+ }
+ }
+ }
+
+ if (this.tokens.matches1(tt.star)) {
+ if (this.shouldAutomaticallyElideImportedName(this.tokens.identifierNameAtRelativeIndex(2))) {
+ this.tokens.removeToken();
+ this.tokens.removeToken();
+ this.tokens.removeToken();
+ } else {
+ if (needsComma) {
+ this.tokens.appendCode(",");
+ }
+ foundNonTypeImport = true;
+ this.tokens.copyExpectedToken(tt.star);
+ this.tokens.copyExpectedToken(tt.name);
+ this.tokens.copyExpectedToken(tt.name);
+ }
+ } else if (this.tokens.matches1(tt.braceL)) {
+ if (needsComma) {
+ this.tokens.appendCode(",");
+ }
+ this.tokens.copyToken();
+ while (!this.tokens.matches1(tt.braceR)) {
+ foundAnyNamedImport = true;
+ const specifierInfo = getImportExportSpecifierInfo(this.tokens);
+ if (
+ specifierInfo.isType ||
+ this.shouldAutomaticallyElideImportedName(specifierInfo.rightName)
+ ) {
+ while (this.tokens.currentIndex() < specifierInfo.endIndex) {
+ this.tokens.removeToken();
+ }
+ if (this.tokens.matches1(tt.comma)) {
+ this.tokens.removeToken();
+ }
+ } else {
+ foundNonTypeImport = true;
+ while (this.tokens.currentIndex() < specifierInfo.endIndex) {
+ this.tokens.copyToken();
+ }
+ if (this.tokens.matches1(tt.comma)) {
+ this.tokens.copyToken();
+ }
+ }
+ }
+ this.tokens.copyExpectedToken(tt.braceR);
+ }
+
+ 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;
+ }
+ }
+
+ shouldAutomaticallyElideImportedName(name) {
+ return (
+ this.isTypeScriptTransformEnabled &&
+ !this.keepUnusedImports &&
+ !this.nonTypeIdentifiers.has(name)
+ );
+ }
+
+ processExportDefault() {
+ if (
+ shouldElideDefaultExport(
+ 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.
+ this.tokens.removeInitialToken();
+ this.tokens.removeToken();
+ this.tokens.removeToken();
+ return true;
+ }
+
+ const alreadyHasName =
+ this.tokens.matches4(tt._export, tt._default, tt._function, tt.name) ||
+ // export default async function
+ (this.tokens.matches5(tt._export, tt._default, tt.name, tt._function, tt.name) &&
+ this.tokens.matchesContextualAtIndex(
+ this.tokens.currentIndex() + 2,
+ ContextualKeyword._async,
+ )) ||
+ this.tokens.matches4(tt._export, tt._default, tt._class, tt.name) ||
+ this.tokens.matches5(tt._export, tt._default, tt._abstract, tt._class, tt.name);
+
+ if (!alreadyHasName && this.reactHotLoaderTransformer) {
+ // This is a plain "export default E" statement and we need to assign E to a variable.
+ // Change "export default E" to "let _default; export default _default = E"
+ const defaultVarName = this.nameManager.claimFreeName("_default");
+ this.tokens.replaceToken(`let ${defaultVarName}; export`);
+ this.tokens.copyToken();
+ this.tokens.appendCode(` ${defaultVarName} =`);
+ this.reactHotLoaderTransformer.setExtractedDefaultExportName(defaultVarName);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Handle a statement with one of these forms:
+ * export {a, type b};
+ * export {c, type d} from 'foo';
+ *
+ * In both cases, any explicit type exports should be removed. In the first
+ * case, we also need to handle implicit export elision for names declared as
+ * types. In the second case, we must NOT do implicit named export elision,
+ * but we must remove the runtime import if all exports are type exports.
+ */
+ processNamedExports() {
+ if (!this.isTypeScriptTransformEnabled) {
+ return false;
+ }
+ this.tokens.copyExpectedToken(tt._export);
+ this.tokens.copyExpectedToken(tt.braceL);
+
+ const isReExport = isExportFrom(this.tokens);
+ let foundNonTypeExport = false;
+ while (!this.tokens.matches1(tt.braceR)) {
+ const specifierInfo = getImportExportSpecifierInfo(this.tokens);
+ if (
+ specifierInfo.isType ||
+ (!isReExport && this.shouldElideExportedName(specifierInfo.leftName))
+ ) {
+ // Type export, so remove all tokens, including any comma.
+ while (this.tokens.currentIndex() < specifierInfo.endIndex) {
+ this.tokens.removeToken();
+ }
+ if (this.tokens.matches1(tt.comma)) {
+ this.tokens.removeToken();
+ }
+ } else {
+ // Non-type export, so copy all tokens, including any comma.
+ foundNonTypeExport = true;
+ while (this.tokens.currentIndex() < specifierInfo.endIndex) {
+ this.tokens.copyToken();
+ }
+ if (this.tokens.matches1(tt.comma)) {
+ this.tokens.copyToken();
+ }
+ }
+ }
+ this.tokens.copyExpectedToken(tt.braceR);
+
+ if (!this.keepUnusedImports && isReExport && !foundNonTypeExport) {
+ // This is a type-only re-export, so skip evaluating the other module. Technically this
+ // leaves the statement as `export {}`, but that's ok since that's a no-op.
+ this.tokens.removeToken();
+ this.tokens.removeToken();
+ removeMaybeImportAttributes(this.tokens);
+ }
+
+ return true;
+ }
+
+ /**
+ * ESM elides all imports with the rule that we only elide if we see that it's
+ * a type and never see it as a value. This is in contrast to CJS, which
+ * elides imports that are completely unknown.
+ */
+ shouldElideExportedName(name) {
+ return (
+ this.isTypeScriptTransformEnabled &&
+ !this.keepUnusedImports &&
+ this.declarationInfo.typeDeclarations.has(name) &&
+ !this.declarationInfo.valueDeclarations.has(name)
+ );
+ }
+}
diff --git a/node_modules/sucrase/dist/esm/transformers/FlowTransformer.js b/node_modules/sucrase/dist/esm/transformers/FlowTransformer.js
new file mode 100644
index 0000000..7df0aca
--- /dev/null
+++ b/node_modules/sucrase/dist/esm/transformers/FlowTransformer.js
@@ -0,0 +1,182 @@
+import {ContextualKeyword} from "../parser/tokenizer/keywords";
+import {TokenType as tt} from "../parser/tokenizer/types";
+
+
+import Transformer from "./Transformer";
+
+export default class FlowTransformer extends Transformer {
+ constructor(
+ rootTransformer,
+ tokens,
+ isImportsTransformEnabled,
+ ) {
+ super();this.rootTransformer = rootTransformer;this.tokens = tokens;this.isImportsTransformEnabled = isImportsTransformEnabled;;
+ }
+
+ process() {
+ if (
+ this.rootTransformer.processPossibleArrowParamEnd() ||
+ this.rootTransformer.processPossibleAsyncArrowWithTypeParams() ||
+ this.rootTransformer.processPossibleTypeRange()
+ ) {
+ return true;
+ }
+ if (this.tokens.matches1(tt._enum)) {
+ this.processEnum();
+ return true;
+ }
+ if (this.tokens.matches2(tt._export, tt._enum)) {
+ this.processNamedExportEnum();
+ return true;
+ }
+ if (this.tokens.matches3(tt._export, tt._default, tt._enum)) {
+ this.processDefaultExportEnum();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Handle a declaration like:
+ * export enum E ...
+ *
+ * With this imports transform, this becomes:
+ * const E = [[enum]]; exports.E = E;
+ *
+ * otherwise, it becomes:
+ * export const E = [[enum]];
+ */
+ processNamedExportEnum() {
+ if (this.isImportsTransformEnabled) {
+ // export
+ this.tokens.removeInitialToken();
+ const enumName = this.tokens.identifierNameAtRelativeIndex(1);
+ this.processEnum();
+ this.tokens.appendCode(` exports.${enumName} = ${enumName};`);
+ } else {
+ this.tokens.copyToken();
+ this.processEnum();
+ }
+ }
+
+ /**
+ * Handle a declaration like:
+ * export default enum E
+ *
+ * With the imports transform, this becomes:
+ * const E = [[enum]]; exports.default = E;
+ *
+ * otherwise, it becomes:
+ * const E = [[enum]]; export default E;
+ */
+ processDefaultExportEnum() {
+ // export
+ this.tokens.removeInitialToken();
+ // default
+ this.tokens.removeToken();
+ const enumName = this.tokens.identifierNameAtRelativeIndex(1);
+ this.processEnum();
+ if (this.isImportsTransformEnabled) {
+ this.tokens.appendCode(` exports.default = ${enumName};`);
+ } else {
+ this.tokens.appendCode(` export default ${enumName};`);
+ }
+ }
+
+ /**
+ * Transpile flow enums to invoke the "flow-enums-runtime" library.
+ *
+ * Currently, the transpiled code always uses `require("flow-enums-runtime")`,
+ * but if future flexibility is needed, we could expose a config option for
+ * this string (similar to configurable JSX). Even when targeting ESM, the
+ * default behavior of babel-plugin-transform-flow-enums is to use require
+ * rather than injecting an import.
+ *
+ * Flow enums are quite a bit simpler than TS enums and have some convenient
+ * constraints:
+ * - Element initializers must be either always present or always absent. That
+ * means that we can use fixed lookahead on the first element (if any) and
+ * assume that all elements are like that.
+ * - The right-hand side of an element initializer must be a literal value,
+ * not a complex expression and not referencing other elements. That means
+ * we can simply copy a single token.
+ *
+ * Enums can be broken up into three basic cases:
+ *
+ * Mirrored enums:
+ * enum E {A, B}
+ * ->
+ * const E = require("flow-enums-runtime").Mirrored(["A", "B"]);
+ *
+ * Initializer enums:
+ * enum E {A = 1, B = 2}
+ * ->
+ * const E = require("flow-enums-runtime")({A: 1, B: 2});
+ *
+ * Symbol enums:
+ * enum E of symbol {A, B}
+ * ->
+ * const E = require("flow-enums-runtime")({A: Symbol("A"), B: Symbol("B")});
+ *
+ * We can statically detect which of the three cases this is by looking at the
+ * "of" declaration (if any) and seeing if the first element has an initializer.
+ * Since the other transform details are so similar between the three cases, we
+ * use a single implementation and vary the transform within processEnumElement
+ * based on case.
+ */
+ processEnum() {
+ // enum E -> const E
+ this.tokens.replaceToken("const");
+ this.tokens.copyExpectedToken(tt.name);
+
+ let isSymbolEnum = false;
+ if (this.tokens.matchesContextual(ContextualKeyword._of)) {
+ this.tokens.removeToken();
+ isSymbolEnum = this.tokens.matchesContextual(ContextualKeyword._symbol);
+ this.tokens.removeToken();
+ }
+ const hasInitializers = this.tokens.matches3(tt.braceL, tt.name, tt.eq);
+ this.tokens.appendCode(' = require("flow-enums-runtime")');
+
+ const isMirrored = !isSymbolEnum && !hasInitializers;
+ this.tokens.replaceTokenTrimmingLeftWhitespace(isMirrored ? ".Mirrored([" : "({");
+
+ while (!this.tokens.matches1(tt.braceR)) {
+ // ... is allowed at the end and has no runtime behavior.
+ if (this.tokens.matches1(tt.ellipsis)) {
+ this.tokens.removeToken();
+ break;
+ }
+ this.processEnumElement(isSymbolEnum, hasInitializers);
+ if (this.tokens.matches1(tt.comma)) {
+ this.tokens.copyToken();
+ }
+ }
+
+ this.tokens.replaceToken(isMirrored ? "]);" : "});");
+ }
+
+ /**
+ * Process an individual enum element, producing either an array element or an
+ * object element based on what type of enum this is.
+ */
+ processEnumElement(isSymbolEnum, hasInitializers) {
+ if (isSymbolEnum) {
+ // Symbol enums never have initializers and are expanded to object elements.
+ // A, -> A: Symbol("A"),
+ const elementName = this.tokens.identifierName();
+ this.tokens.copyToken();
+ this.tokens.appendCode(`: Symbol("${elementName}")`);
+ } else if (hasInitializers) {
+ // Initializers are expanded to object elements.
+ // A = 1, -> A: 1,
+ this.tokens.copyToken();
+ this.tokens.replaceTokenTrimmingLeftWhitespace(":");
+ this.tokens.copyToken();
+ } else {
+ // Enum elements without initializers become string literal array elements.
+ // A, -> "A",
+ this.tokens.replaceToken(`"${this.tokens.identifierName()}"`);
+ }
+ }
+}
diff --git a/node_modules/sucrase/dist/esm/transformers/JSXTransformer.js b/node_modules/sucrase/dist/esm/transformers/JSXTransformer.js
new file mode 100644
index 0000000..e5f5ae5
--- /dev/null
+++ b/node_modules/sucrase/dist/esm/transformers/JSXTransformer.js
@@ -0,0 +1,733 @@
+
+
+
+import XHTMLEntities from "../parser/plugins/jsx/xhtml";
+import {JSXRole} from "../parser/tokenizer";
+import {TokenType as tt} from "../parser/tokenizer/types";
+import {charCodes} from "../parser/util/charcodes";
+
+import getJSXPragmaInfo, {} from "../util/getJSXPragmaInfo";
+
+import Transformer from "./Transformer";
+
+export default class JSXTransformer extends Transformer {
+
+
+
+
+ // State for calculating the line number of each JSX tag in development.
+ __init() {this.lastLineNumber = 1}
+ __init2() {this.lastIndex = 0}
+
+ // In development, variable name holding the name of the current file.
+ __init3() {this.filenameVarName = null}
+ // Mapping of claimed names for imports in the automatic transform, e,g.
+ // {jsx: "_jsx"}. This determines which imports to generate in the prefix.
+ __init4() {this.esmAutomaticImportNameResolutions = {}}
+ // When automatically adding imports in CJS mode, we store the variable name
+ // holding the imported CJS module so we can require it in the prefix.
+ __init5() {this.cjsAutomaticModuleNameResolutions = {}}
+
+ constructor(
+ rootTransformer,
+ tokens,
+ importProcessor,
+ nameManager,
+ options,
+ ) {
+ super();this.rootTransformer = rootTransformer;this.tokens = tokens;this.importProcessor = importProcessor;this.nameManager = nameManager;this.options = options;JSXTransformer.prototype.__init.call(this);JSXTransformer.prototype.__init2.call(this);JSXTransformer.prototype.__init3.call(this);JSXTransformer.prototype.__init4.call(this);JSXTransformer.prototype.__init5.call(this);;
+ this.jsxPragmaInfo = getJSXPragmaInfo(options);
+ this.isAutomaticRuntime = options.jsxRuntime === "automatic";
+ this.jsxImportSource = options.jsxImportSource || "react";
+ }
+
+ process() {
+ if (this.tokens.matches1(tt.jsxTagStart)) {
+ this.processJSXTag();
+ return true;
+ }
+ return false;
+ }
+
+ getPrefixCode() {
+ let prefix = "";
+ if (this.filenameVarName) {
+ prefix += `const ${this.filenameVarName} = ${JSON.stringify(this.options.filePath || "")};`;
+ }
+ if (this.isAutomaticRuntime) {
+ if (this.importProcessor) {
+ // CJS mode: emit require statements for all modules that were referenced.
+ for (const [path, resolvedName] of Object.entries(this.cjsAutomaticModuleNameResolutions)) {
+ prefix += `var ${resolvedName} = require("${path}");`;
+ }
+ } else {
+ // ESM mode: consolidate and emit import statements for referenced names.
+ const {createElement: createElementResolution, ...otherResolutions} =
+ this.esmAutomaticImportNameResolutions;
+ if (createElementResolution) {
+ prefix += `import {createElement as ${createElementResolution}} from "${this.jsxImportSource}";`;
+ }
+ const importSpecifiers = Object.entries(otherResolutions)
+ .map(([name, resolvedName]) => `${name} as ${resolvedName}`)
+ .join(", ");
+ if (importSpecifiers) {
+ const importPath =
+ this.jsxImportSource + (this.options.production ? "/jsx-runtime" : "/jsx-dev-runtime");
+ prefix += `import {${importSpecifiers}} from "${importPath}";`;
+ }
+ }
+ }
+ return prefix;
+ }
+
+ processJSXTag() {
+ const {jsxRole, start} = this.tokens.currentToken();
+ // Calculate line number information at the very start (if in development
+ // mode) so that the information is guaranteed to be queried in token order.
+ const elementLocationCode = this.options.production ? null : this.getElementLocationCode(start);
+ if (this.isAutomaticRuntime && jsxRole !== JSXRole.KeyAfterPropSpread) {
+ this.transformTagToJSXFunc(elementLocationCode, jsxRole);
+ } else {
+ this.transformTagToCreateElement(elementLocationCode);
+ }
+ }
+
+ getElementLocationCode(firstTokenStart) {
+ const lineNumber = this.getLineNumberForIndex(firstTokenStart);
+ return `lineNumber: ${lineNumber}`;
+ }
+
+ /**
+ * Get the line number for this source position. This is calculated lazily and
+ * must be called in increasing order by index.
+ */
+ getLineNumberForIndex(index) {
+ const code = this.tokens.code;
+ while (this.lastIndex < index && this.lastIndex < code.length) {
+ if (code[this.lastIndex] === "\n") {
+ this.lastLineNumber++;
+ }
+ this.lastIndex++;
+ }
+ return this.lastLineNumber;
+ }
+
+ /**
+ * Convert the current JSX element to a call to jsx, jsxs, or jsxDEV. This is
+ * the primary transformation for the automatic transform.
+ *
+ * Example:
+ * <div a={1} key={2}>Hello{x}</div>
+ * becomes
+ * jsxs('div', {a: 1, children: ["Hello", x]}, 2)
+ */
+ transformTagToJSXFunc(elementLocationCode, jsxRole) {
+ const isStatic = jsxRole === JSXRole.StaticChildren;
+ // First tag is always jsxTagStart.
+ this.tokens.replaceToken(this.getJSXFuncInvocationCode(isStatic));
+
+ let keyCode = null;
+ if (this.tokens.matches1(tt.jsxTagEnd)) {
+ // Fragment syntax.
+ this.tokens.replaceToken(`${this.getFragmentCode()}, {`);
+ this.processAutomaticChildrenAndEndProps(jsxRole);
+ } else {
+ // Normal open tag or self-closing tag.
+ this.processTagIntro();
+ this.tokens.appendCode(", {");
+ keyCode = this.processProps(true);
+
+ if (this.tokens.matches2(tt.slash, tt.jsxTagEnd)) {
+ // Self-closing tag, no children to add, so close the props.
+ this.tokens.appendCode("}");
+ } else if (this.tokens.matches1(tt.jsxTagEnd)) {
+ // Tag with children.
+ this.tokens.removeToken();
+ this.processAutomaticChildrenAndEndProps(jsxRole);
+ } else {
+ throw new Error("Expected either /> or > at the end of the tag.");
+ }
+ // If a key was present, move it to its own arg. Note that moving code
+ // like this will cause line numbers to get out of sync within the JSX
+ // element if the key expression has a newline in it. This is unfortunate,
+ // but hopefully should be rare.
+ if (keyCode) {
+ this.tokens.appendCode(`, ${keyCode}`);
+ }
+ }
+ if (!this.options.production) {
+ // If the key wasn't already added, add it now so we can correctly set
+ // positional args for jsxDEV.
+ if (keyCode === null) {
+ this.tokens.appendCode(", void 0");
+ }
+ this.tokens.appendCode(`, ${isStatic}, ${this.getDevSource(elementLocationCode)}, this`);
+ }
+ // We're at the close-tag or the end of a self-closing tag, so remove
+ // everything else and close the function call.
+ this.tokens.removeInitialToken();
+ while (!this.tokens.matches1(tt.jsxTagEnd)) {
+ this.tokens.removeToken();
+ }
+ this.tokens.replaceToken(")");
+ }
+
+ /**
+ * Convert the current JSX element to a createElement call. In the classic
+ * runtime, this is the only case. In the automatic runtime, this is called
+ * as a fallback in some situations.
+ *
+ * Example:
+ * <div a={1} key={2}>Hello{x}</div>
+ * becomes
+ * React.createElement('div', {a: 1, key: 2}, "Hello", x)
+ */
+ transformTagToCreateElement(elementLocationCode) {
+ // First tag is always jsxTagStart.
+ this.tokens.replaceToken(this.getCreateElementInvocationCode());
+
+ if (this.tokens.matches1(tt.jsxTagEnd)) {
+ // Fragment syntax.
+ this.tokens.replaceToken(`${this.getFragmentCode()}, null`);
+ this.processChildren(true);
+ } else {
+ // Normal open tag or self-closing tag.
+ this.processTagIntro();
+ this.processPropsObjectWithDevInfo(elementLocationCode);
+
+ if (this.tokens.matches2(tt.slash, tt.jsxTagEnd)) {
+ // Self-closing tag; no children to process.
+ } else if (this.tokens.matches1(tt.jsxTagEnd)) {
+ // Tag with children and a close-tag; process the children as args.
+ this.tokens.removeToken();
+ this.processChildren(true);
+ } else {
+ throw new Error("Expected either /> or > at the end of the tag.");
+ }
+ }
+ // We're at the close-tag or the end of a self-closing tag, so remove
+ // everything else and close the function call.
+ this.tokens.removeInitialToken();
+ while (!this.tokens.matches1(tt.jsxTagEnd)) {
+ this.tokens.removeToken();
+ }
+ this.tokens.replaceToken(")");
+ }
+
+ /**
+ * Get the code for the relevant function for this context: jsx, jsxs,
+ * or jsxDEV. The following open-paren is included as well.
+ *
+ * These functions are only used for the automatic runtime, so they are always
+ * auto-imported, but the auto-import will be either CJS or ESM based on the
+ * target module format.
+ */
+ getJSXFuncInvocationCode(isStatic) {
+ if (this.options.production) {
+ if (isStatic) {
+ return this.claimAutoImportedFuncInvocation("jsxs", "/jsx-runtime");
+ } else {
+ return this.claimAutoImportedFuncInvocation("jsx", "/jsx-runtime");
+ }
+ } else {
+ return this.claimAutoImportedFuncInvocation("jsxDEV", "/jsx-dev-runtime");
+ }
+ }
+
+ /**
+ * Return the code to use for the createElement function, e.g.
+ * `React.createElement`, including the following open-paren.
+ *
+ * This is the main function to use for the classic runtime. For the
+ * automatic runtime, this function is used as a fallback function to
+ * preserve behavior when there is a prop spread followed by an explicit
+ * key. In that automatic runtime case, the function should be automatically
+ * imported.
+ */
+ getCreateElementInvocationCode() {
+ if (this.isAutomaticRuntime) {
+ return this.claimAutoImportedFuncInvocation("createElement", "");
+ } else {
+ const {jsxPragmaInfo} = this;
+ const resolvedPragmaBaseName = this.importProcessor
+ ? this.importProcessor.getIdentifierReplacement(jsxPragmaInfo.base) || jsxPragmaInfo.base
+ : jsxPragmaInfo.base;
+ return `${resolvedPragmaBaseName}${jsxPragmaInfo.suffix}(`;
+ }
+ }
+
+ /**
+ * Return the code to use as the component when compiling a shorthand
+ * fragment, e.g. `React.Fragment`.
+ *
+ * This may be called from either the classic or automatic runtime, and
+ * the value should be auto-imported for the automatic runtime.
+ */
+ getFragmentCode() {
+ if (this.isAutomaticRuntime) {
+ return this.claimAutoImportedName(
+ "Fragment",
+ this.options.production ? "/jsx-runtime" : "/jsx-dev-runtime",
+ );
+ } else {
+ const {jsxPragmaInfo} = this;
+ const resolvedFragmentPragmaBaseName = this.importProcessor
+ ? this.importProcessor.getIdentifierReplacement(jsxPragmaInfo.fragmentBase) ||
+ jsxPragmaInfo.fragmentBase
+ : jsxPragmaInfo.fragmentBase;
+ return resolvedFragmentPragmaBaseName + jsxPragmaInfo.fragmentSuffix;
+ }
+ }
+
+ /**
+ * Return code that invokes the given function.
+ *
+ * When the imports transform is enabled, use the CJSImportTransformer
+ * strategy of using `.call(void 0, ...` to avoid passing a `this` value in a
+ * situation that would otherwise look like a method call.
+ */
+ claimAutoImportedFuncInvocation(funcName, importPathSuffix) {
+ const funcCode = this.claimAutoImportedName(funcName, importPathSuffix);
+ if (this.importProcessor) {
+ return `${funcCode}.call(void 0, `;
+ } else {
+ return `${funcCode}(`;
+ }
+ }
+
+ claimAutoImportedName(funcName, importPathSuffix) {
+ if (this.importProcessor) {
+ // CJS mode: claim a name for the module and mark it for import.
+ const path = this.jsxImportSource + importPathSuffix;
+ if (!this.cjsAutomaticModuleNameResolutions[path]) {
+ this.cjsAutomaticModuleNameResolutions[path] =
+ this.importProcessor.getFreeIdentifierForPath(path);
+ }
+ return `${this.cjsAutomaticModuleNameResolutions[path]}.${funcName}`;
+ } else {
+ // ESM mode: claim a name for this function and add it to the names that
+ // should be auto-imported when the prefix is generated.
+ if (!this.esmAutomaticImportNameResolutions[funcName]) {
+ this.esmAutomaticImportNameResolutions[funcName] = this.nameManager.claimFreeName(
+ `_${funcName}`,
+ );
+ }
+ return this.esmAutomaticImportNameResolutions[funcName];
+ }
+ }
+
+ /**
+ * Process the first part of a tag, before any props.
+ */
+ processTagIntro() {
+ // Walk forward until we see one of these patterns:
+ // jsxName to start the first prop, preceded by another jsxName to end the tag name.
+ // jsxName to start the first prop, preceded by greaterThan to end the type argument.
+ // [open brace] to start the first prop.
+ // [jsxTagEnd] to end the open-tag.
+ // [slash, jsxTagEnd] to end the self-closing tag.
+ let introEnd = this.tokens.currentIndex() + 1;
+ while (
+ this.tokens.tokens[introEnd].isType ||
+ (!this.tokens.matches2AtIndex(introEnd - 1, tt.jsxName, tt.jsxName) &&
+ !this.tokens.matches2AtIndex(introEnd - 1, tt.greaterThan, tt.jsxName) &&
+ !this.tokens.matches1AtIndex(introEnd, tt.braceL) &&
+ !this.tokens.matches1AtIndex(introEnd, tt.jsxTagEnd) &&
+ !this.tokens.matches2AtIndex(introEnd, tt.slash, tt.jsxTagEnd))
+ ) {
+ introEnd++;
+ }
+ if (introEnd === this.tokens.currentIndex() + 1) {
+ const tagName = this.tokens.identifierName();
+ if (startsWithLowerCase(tagName)) {
+ this.tokens.replaceToken(`'${tagName}'`);
+ }
+ }
+ while (this.tokens.currentIndex() < introEnd) {
+ this.rootTransformer.processToken();
+ }
+ }
+
+ /**
+ * Starting at the beginning of the props, add the props argument to
+ * React.createElement, including the comma before it.
+ */
+ processPropsObjectWithDevInfo(elementLocationCode) {
+ const devProps = this.options.production
+ ? ""
+ : `__self: this, __source: ${this.getDevSource(elementLocationCode)}`;
+ if (!this.tokens.matches1(tt.jsxName) && !this.tokens.matches1(tt.braceL)) {
+ if (devProps) {
+ this.tokens.appendCode(`, {${devProps}}`);
+ } else {
+ this.tokens.appendCode(`, null`);
+ }
+ return;
+ }
+ this.tokens.appendCode(`, {`);
+ this.processProps(false);
+ if (devProps) {
+ this.tokens.appendCode(` ${devProps}}`);
+ } else {
+ this.tokens.appendCode("}");
+ }
+ }
+
+ /**
+ * Transform the core part of the props, assuming that a { has already been
+ * inserted before us and that a } will be inserted after us.
+ *
+ * If extractKeyCode is true (i.e. when using any jsx... function), any prop
+ * named "key" has its code captured and returned rather than being emitted to
+ * the output code. This shifts line numbers, and emitting the code later will
+ * correct line numbers again. If no key is found or if extractKeyCode is
+ * false, this function returns null.
+ */
+ processProps(extractKeyCode) {
+ let keyCode = null;
+ while (true) {
+ if (this.tokens.matches2(tt.jsxName, tt.eq)) {
+ // This is a regular key={value} or key="value" prop.
+ const propName = this.tokens.identifierName();
+ if (extractKeyCode && propName === "key") {
+ if (keyCode !== null) {
+ // The props list has multiple keys. Different implementations are
+ // inconsistent about what to do here: as of this writing, Babel and
+ // swc keep the *last* key and completely remove the rest, while
+ // TypeScript uses the *first* key and leaves the others as regular
+ // props. The React team collaborated with Babel on the
+ // implementation of this behavior, so presumably the Babel behavior
+ // is the one to use.
+ // Since we won't ever be emitting the previous key code, we need to
+ // at least emit its newlines here so that the line numbers match up
+ // in the long run.
+ this.tokens.appendCode(keyCode.replace(/[^\n]/g, ""));
+ }
+ // key
+ this.tokens.removeToken();
+ // =
+ this.tokens.removeToken();
+ const snapshot = this.tokens.snapshot();
+ this.processPropValue();
+ keyCode = this.tokens.dangerouslyGetAndRemoveCodeSinceSnapshot(snapshot);
+ // Don't add a comma
+ continue;
+ } else {
+ this.processPropName(propName);
+ this.tokens.replaceToken(": ");
+ this.processPropValue();
+ }
+ } else if (this.tokens.matches1(tt.jsxName)) {
+ // This is a shorthand prop like <input disabled />.
+ const propName = this.tokens.identifierName();
+ this.processPropName(propName);
+ this.tokens.appendCode(": true");
+ } else if (this.tokens.matches1(tt.braceL)) {
+ // This is prop spread, like <div {...getProps()}>, which we can pass
+ // through fairly directly as an object spread.
+ this.tokens.replaceToken("");
+ this.rootTransformer.processBalancedCode();
+ this.tokens.replaceToken("");
+ } else {
+ break;
+ }
+ this.tokens.appendCode(",");
+ }
+ return keyCode;
+ }
+
+ processPropName(propName) {
+ if (propName.includes("-")) {
+ this.tokens.replaceToken(`'${propName}'`);
+ } else {
+ this.tokens.copyToken();
+ }
+ }
+
+ processPropValue() {
+ if (this.tokens.matches1(tt.braceL)) {
+ this.tokens.replaceToken("");
+ this.rootTransformer.processBalancedCode();
+ this.tokens.replaceToken("");
+ } else if (this.tokens.matches1(tt.jsxTagStart)) {
+ this.processJSXTag();
+ } else {
+ this.processStringPropValue();
+ }
+ }
+
+ processStringPropValue() {
+ const token = this.tokens.currentToken();
+ const valueCode = this.tokens.code.slice(token.start + 1, token.end - 1);
+ const replacementCode = formatJSXTextReplacement(valueCode);
+ const literalCode = formatJSXStringValueLiteral(valueCode);
+ this.tokens.replaceToken(literalCode + replacementCode);
+ }
+
+ /**
+ * Starting in the middle of the props object literal, produce an additional
+ * prop for the children and close the object literal.
+ */
+ processAutomaticChildrenAndEndProps(jsxRole) {
+ if (jsxRole === JSXRole.StaticChildren) {
+ this.tokens.appendCode(" children: [");
+ this.processChildren(false);
+ this.tokens.appendCode("]}");
+ } else {
+ // The parser information tells us whether we will see a real child or if
+ // all remaining children (if any) will resolve to empty. If there are no
+ // non-empty children, don't emit a children prop at all, but still
+ // process children so that we properly transform the code into nothing.
+ if (jsxRole === JSXRole.OneChild) {
+ this.tokens.appendCode(" children: ");
+ }
+ this.processChildren(false);
+ this.tokens.appendCode("}");
+ }
+ }
+
+ /**
+ * Transform children into a comma-separated list, which will be either
+ * arguments to createElement or array elements of a children prop.
+ */
+ processChildren(needsInitialComma) {
+ let needsComma = needsInitialComma;
+ while (true) {
+ if (this.tokens.matches2(tt.jsxTagStart, tt.slash)) {
+ // Closing tag, so no more children.
+ return;
+ }
+ let didEmitElement = false;
+ if (this.tokens.matches1(tt.braceL)) {
+ if (this.tokens.matches2(tt.braceL, tt.braceR)) {
+ // Empty interpolations and comment-only interpolations are allowed
+ // and don't create an extra child arg.
+ this.tokens.replaceToken("");
+ this.tokens.replaceToken("");
+ } else {
+ // Interpolated expression.
+ this.tokens.replaceToken(needsComma ? ", " : "");
+ this.rootTransformer.processBalancedCode();
+ this.tokens.replaceToken("");
+ didEmitElement = true;
+ }
+ } else if (this.tokens.matches1(tt.jsxTagStart)) {
+ // Child JSX element
+ this.tokens.appendCode(needsComma ? ", " : "");
+ this.processJSXTag();
+ didEmitElement = true;
+ } else if (this.tokens.matches1(tt.jsxText) || this.tokens.matches1(tt.jsxEmptyText)) {
+ didEmitElement = this.processChildTextElement(needsComma);
+ } else {
+ throw new Error("Unexpected token when processing JSX children.");
+ }
+ if (didEmitElement) {
+ needsComma = true;
+ }
+ }
+ }
+
+ /**
+ * Turn a JSX text element into a string literal, or nothing at all if the JSX
+ * text resolves to the empty string.
+ *
+ * Returns true if a string literal is emitted, false otherwise.
+ */
+ processChildTextElement(needsComma) {
+ const token = this.tokens.currentToken();
+ const valueCode = this.tokens.code.slice(token.start, token.end);
+ const replacementCode = formatJSXTextReplacement(valueCode);
+ const literalCode = formatJSXTextLiteral(valueCode);
+ if (literalCode === '""') {
+ this.tokens.replaceToken(replacementCode);
+ return false;
+ } else {
+ this.tokens.replaceToken(`${needsComma ? ", " : ""}${literalCode}${replacementCode}`);
+ return true;
+ }
+ }
+
+ getDevSource(elementLocationCode) {
+ return `{fileName: ${this.getFilenameVarName()}, ${elementLocationCode}}`;
+ }
+
+ getFilenameVarName() {
+ if (!this.filenameVarName) {
+ this.filenameVarName = this.nameManager.claimFreeName("_jsxFileName");
+ }
+ return this.filenameVarName;
+ }
+}
+
+/**
+ * Spec for identifiers: https://tc39.github.io/ecma262/#prod-IdentifierStart.
+ *
+ * Really only treat anything starting with a-z as tag names. `_`, `$`, `é`
+ * should be treated as component names
+ */
+export function startsWithLowerCase(s) {
+ const firstChar = s.charCodeAt(0);
+ return firstChar >= charCodes.lowercaseA && firstChar <= charCodes.lowercaseZ;
+}
+
+/**
+ * Turn the given jsxText string into a JS string literal. Leading and trailing
+ * whitespace on lines is removed, except immediately after the open-tag and
+ * before the close-tag. Empty lines are completely removed, and spaces are
+ * added between lines after that.
+ *
+ * We use JSON.stringify to introduce escape characters as necessary, and trim
+ * the start and end of each line and remove blank lines.
+ */
+function formatJSXTextLiteral(text) {
+ let result = "";
+ let whitespace = "";
+
+ let isInInitialLineWhitespace = false;
+ let seenNonWhitespace = false;
+ for (let i = 0; i < text.length; i++) {
+ const c = text[i];
+ if (c === " " || c === "\t" || c === "\r") {
+ if (!isInInitialLineWhitespace) {
+ whitespace += c;
+ }
+ } else if (c === "\n") {
+ whitespace = "";
+ isInInitialLineWhitespace = true;
+ } else {
+ if (seenNonWhitespace && isInInitialLineWhitespace) {
+ result += " ";
+ }
+ result += whitespace;
+ whitespace = "";
+ if (c === "&") {
+ const {entity, newI} = processEntity(text, i + 1);
+ i = newI - 1;
+ result += entity;
+ } else {
+ result += c;
+ }
+ seenNonWhitespace = true;
+ isInInitialLineWhitespace = false;
+ }
+ }
+ if (!isInInitialLineWhitespace) {
+ result += whitespace;
+ }
+ return JSON.stringify(result);
+}
+
+/**
+ * Produce the code that should be printed after the JSX text string literal,
+ * with most content removed, but all newlines preserved and all spacing at the
+ * end preserved.
+ */
+function formatJSXTextReplacement(text) {
+ let numNewlines = 0;
+ let numSpaces = 0;
+ for (const c of text) {
+ if (c === "\n") {
+ numNewlines++;
+ numSpaces = 0;
+ } else if (c === " ") {
+ numSpaces++;
+ }
+ }
+ return "\n".repeat(numNewlines) + " ".repeat(numSpaces);
+}
+
+/**
+ * Format a string in the value position of a JSX prop.
+ *
+ * Use the same implementation as convertAttribute from
+ * babel-helper-builder-react-jsx.
+ */
+function formatJSXStringValueLiteral(text) {
+ let result = "";
+ for (let i = 0; i < text.length; i++) {
+ const c = text[i];
+ if (c === "\n") {
+ if (/\s/.test(text[i + 1])) {
+ result += " ";
+ while (i < text.length && /\s/.test(text[i + 1])) {
+ i++;
+ }
+ } else {
+ result += "\n";
+ }
+ } else if (c === "&") {
+ const {entity, newI} = processEntity(text, i + 1);
+ result += entity;
+ i = newI - 1;
+ } else {
+ result += c;
+ }
+ }
+ return JSON.stringify(result);
+}
+
+/**
+ * Starting at a &, see if there's an HTML entity (specified by name, decimal
+ * char code, or hex char code) and return it if so.
+ *
+ * Modified from jsxReadString in babel-parser.
+ */
+function processEntity(text, indexAfterAmpersand) {
+ let str = "";
+ let count = 0;
+ let entity;
+ let i = indexAfterAmpersand;
+
+ if (text[i] === "#") {
+ let radix = 10;
+ i++;
+ let numStart;
+ if (text[i] === "x") {
+ radix = 16;
+ i++;
+ numStart = i;
+ while (i < text.length && isHexDigit(text.charCodeAt(i))) {
+ i++;
+ }
+ } else {
+ numStart = i;
+ while (i < text.length && isDecimalDigit(text.charCodeAt(i))) {
+ i++;
+ }
+ }
+ if (text[i] === ";") {
+ const numStr = text.slice(numStart, i);
+ if (numStr) {
+ i++;
+ entity = String.fromCodePoint(parseInt(numStr, radix));
+ }
+ }
+ } else {
+ while (i < text.length && count++ < 10) {
+ const ch = text[i];
+ i++;
+ if (ch === ";") {
+ entity = XHTMLEntities.get(str);
+ break;
+ }
+ str += ch;
+ }
+ }
+
+ if (!entity) {
+ return {entity: "&", newI: indexAfterAmpersand};
+ }
+ return {entity, newI: i};
+}
+
+function isDecimalDigit(code) {
+ return code >= charCodes.digit0 && code <= charCodes.digit9;
+}
+
+function isHexDigit(code) {
+ return (
+ (code >= charCodes.digit0 && code <= charCodes.digit9) ||
+ (code >= charCodes.lowercaseA && code <= charCodes.lowercaseF) ||
+ (code >= charCodes.uppercaseA && code <= charCodes.uppercaseF)
+ );
+}
diff --git a/node_modules/sucrase/dist/esm/transformers/JestHoistTransformer.js b/node_modules/sucrase/dist/esm/transformers/JestHoistTransformer.js
new file mode 100644
index 0000000..8f45d06
--- /dev/null
+++ b/node_modules/sucrase/dist/esm/transformers/JestHoistTransformer.js
@@ -0,0 +1,111 @@
+ function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
+
+import {TokenType as tt} from "../parser/tokenizer/types";
+
+
+import Transformer from "./Transformer";
+
+const JEST_GLOBAL_NAME = "jest";
+const HOISTED_METHODS = ["mock", "unmock", "enableAutomock", "disableAutomock"];
+
+/**
+ * Implementation of babel-plugin-jest-hoist, which hoists up some jest method
+ * calls above the imports to allow them to override other imports.
+ *
+ * To preserve line numbers, rather than directly moving the jest.mock code, we
+ * wrap each invocation in a function statement and then call the function from
+ * the top of the file.
+ */
+export default class JestHoistTransformer extends Transformer {
+ __init() {this.hoistedFunctionNames = []}
+
+ constructor(
+ rootTransformer,
+ tokens,
+ nameManager,
+ importProcessor,
+ ) {
+ super();this.rootTransformer = rootTransformer;this.tokens = tokens;this.nameManager = nameManager;this.importProcessor = importProcessor;JestHoistTransformer.prototype.__init.call(this);;
+ }
+
+ process() {
+ if (
+ this.tokens.currentToken().scopeDepth === 0 &&
+ this.tokens.matches4(tt.name, tt.dot, tt.name, tt.parenL) &&
+ this.tokens.identifierName() === JEST_GLOBAL_NAME
+ ) {
+ // TODO: This only works if imports transform is active, which it will be for jest.
+ // But if jest adds module support and we no longer need the import transform, this needs fixing.
+ if (_optionalChain([this, 'access', _ => _.importProcessor, 'optionalAccess', _2 => _2.getGlobalNames, 'call', _3 => _3(), 'optionalAccess', _4 => _4.has, 'call', _5 => _5(JEST_GLOBAL_NAME)])) {
+ return false;
+ }
+ return this.extractHoistedCalls();
+ }
+
+ return false;
+ }
+
+ getHoistedCode() {
+ if (this.hoistedFunctionNames.length > 0) {
+ // This will be placed before module interop code, but that's fine since
+ // imports aren't allowed in module mock factories.
+ return this.hoistedFunctionNames.map((name) => `${name}();`).join("");
+ }
+ return "";
+ }
+
+ /**
+ * Extracts any methods calls on the jest-object that should be hoisted.
+ *
+ * According to the jest docs, https://jestjs.io/docs/en/jest-object#jestmockmodulename-factory-options,
+ * mock, unmock, enableAutomock, disableAutomock, are the methods that should be hoisted.
+ *
+ * We do not apply the same checks of the arguments as babel-plugin-jest-hoist does.
+ */
+ extractHoistedCalls() {
+ // We're handling a chain of calls where `jest` may or may not need to be inserted for each call
+ // in the chain, so remove the initial `jest` to make the loop implementation cleaner.
+ this.tokens.removeToken();
+ // Track some state so that multiple non-hoisted chained calls in a row keep their chaining
+ // syntax.
+ let followsNonHoistedJestCall = false;
+
+ // Iterate through all chained calls on the jest object.
+ while (this.tokens.matches3(tt.dot, tt.name, tt.parenL)) {
+ const methodName = this.tokens.identifierNameAtIndex(this.tokens.currentIndex() + 1);
+ const shouldHoist = HOISTED_METHODS.includes(methodName);
+ if (shouldHoist) {
+ // We've matched e.g. `.mock(...)` or similar call.
+ // Replace the initial `.` with `function __jestHoist(){jest.`
+ const hoistedFunctionName = this.nameManager.claimFreeName("__jestHoist");
+ this.hoistedFunctionNames.push(hoistedFunctionName);
+ this.tokens.replaceToken(`function ${hoistedFunctionName}(){${JEST_GLOBAL_NAME}.`);
+ this.tokens.copyToken();
+ this.tokens.copyToken();
+ this.rootTransformer.processBalancedCode();
+ this.tokens.copyExpectedToken(tt.parenR);
+ this.tokens.appendCode(";}");
+ followsNonHoistedJestCall = false;
+ } else {
+ // This is a non-hoisted method, so just transform the code as usual.
+ if (followsNonHoistedJestCall) {
+ // If we didn't hoist the previous call, we can leave the code as-is to chain off of the
+ // previous method call. It's important to preserve the code here because we don't know
+ // for sure that the method actually returned the jest object for chaining.
+ this.tokens.copyToken();
+ } else {
+ // If we hoisted the previous call, we know it returns the jest object back, so we insert
+ // the identifier `jest` to continue the chain.
+ this.tokens.replaceToken(`${JEST_GLOBAL_NAME}.`);
+ }
+ this.tokens.copyToken();
+ this.tokens.copyToken();
+ this.rootTransformer.processBalancedCode();
+ this.tokens.copyExpectedToken(tt.parenR);
+ followsNonHoistedJestCall = true;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/node_modules/sucrase/dist/esm/transformers/NumericSeparatorTransformer.js b/node_modules/sucrase/dist/esm/transformers/NumericSeparatorTransformer.js
new file mode 100644
index 0000000..0cb01a1
--- /dev/null
+++ b/node_modules/sucrase/dist/esm/transformers/NumericSeparatorTransformer.js
@@ -0,0 +1,20 @@
+import {TokenType as tt} from "../parser/tokenizer/types";
+
+import Transformer from "./Transformer";
+
+export default class NumericSeparatorTransformer extends Transformer {
+ constructor( tokens) {
+ super();this.tokens = tokens;;
+ }
+
+ process() {
+ if (this.tokens.matches1(tt.num)) {
+ const code = this.tokens.currentTokenCode();
+ if (code.includes("_")) {
+ this.tokens.replaceToken(code.replace(/_/g, ""));
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/node_modules/sucrase/dist/esm/transformers/OptionalCatchBindingTransformer.js b/node_modules/sucrase/dist/esm/transformers/OptionalCatchBindingTransformer.js
new file mode 100644
index 0000000..547273b
--- /dev/null
+++ b/node_modules/sucrase/dist/esm/transformers/OptionalCatchBindingTransformer.js
@@ -0,0 +1,19 @@
+
+import {TokenType as tt} from "../parser/tokenizer/types";
+
+import Transformer from "./Transformer";
+
+export default class OptionalCatchBindingTransformer extends Transformer {
+ constructor( tokens, nameManager) {
+ super();this.tokens = tokens;this.nameManager = nameManager;;
+ }
+
+ process() {
+ if (this.tokens.matches2(tt._catch, tt.braceL)) {
+ this.tokens.copyToken();
+ this.tokens.appendCode(` (${this.nameManager.claimFreeName("e")})`);
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/node_modules/sucrase/dist/esm/transformers/OptionalChainingNullishTransformer.js b/node_modules/sucrase/dist/esm/transformers/OptionalChainingNullishTransformer.js
new file mode 100644
index 0000000..571d97f
--- /dev/null
+++ b/node_modules/sucrase/dist/esm/transformers/OptionalChainingNullishTransformer.js
@@ -0,0 +1,155 @@
+
+import {TokenType as tt} from "../parser/tokenizer/types";
+
+import Transformer from "./Transformer";
+
+/**
+ * Transformer supporting the optional chaining and nullish coalescing operators.
+ *
+ * Tech plan here:
+ * https://github.com/alangpierce/sucrase/wiki/Sucrase-Optional-Chaining-and-Nullish-Coalescing-Technical-Plan
+ *
+ * The prefix and suffix code snippets are handled by TokenProcessor, and this transformer handles
+ * the operators themselves.
+ */
+export default class OptionalChainingNullishTransformer extends Transformer {
+ constructor( tokens, nameManager) {
+ super();this.tokens = tokens;this.nameManager = nameManager;;
+ }
+
+ process() {
+ if (this.tokens.matches1(tt.nullishCoalescing)) {
+ const token = this.tokens.currentToken();
+ if (this.tokens.tokens[token.nullishStartIndex].isAsyncOperation) {
+ this.tokens.replaceTokenTrimmingLeftWhitespace(", async () => (");
+ } else {
+ this.tokens.replaceTokenTrimmingLeftWhitespace(", () => (");
+ }
+ return true;
+ }
+ if (this.tokens.matches1(tt._delete)) {
+ const nextToken = this.tokens.tokenAtRelativeIndex(1);
+ if (nextToken.isOptionalChainStart) {
+ this.tokens.removeInitialToken();
+ return true;
+ }
+ }
+ const token = this.tokens.currentToken();
+ const chainStart = token.subscriptStartIndex;
+ if (
+ chainStart != null &&
+ this.tokens.tokens[chainStart].isOptionalChainStart &&
+ // Super subscripts can't be optional (since super is never null/undefined), and the syntax
+ // relies on the subscript being intact, so leave this token alone.
+ this.tokens.tokenAtRelativeIndex(-1).type !== tt._super
+ ) {
+ const param = this.nameManager.claimFreeName("_");
+ let arrowStartSnippet;
+ if (
+ chainStart > 0 &&
+ this.tokens.matches1AtIndex(chainStart - 1, tt._delete) &&
+ this.isLastSubscriptInChain()
+ ) {
+ // Delete operations are special: we already removed the delete keyword, and to still
+ // perform a delete, we need to insert a delete in the very last part of the chain, which
+ // in correct code will always be a property access.
+ arrowStartSnippet = `${param} => delete ${param}`;
+ } else {
+ arrowStartSnippet = `${param} => ${param}`;
+ }
+ if (this.tokens.tokens[chainStart].isAsyncOperation) {
+ arrowStartSnippet = `async ${arrowStartSnippet}`;
+ }
+ if (
+ this.tokens.matches2(tt.questionDot, tt.parenL) ||
+ this.tokens.matches2(tt.questionDot, tt.lessThan)
+ ) {
+ if (this.justSkippedSuper()) {
+ this.tokens.appendCode(".bind(this)");
+ }
+ this.tokens.replaceTokenTrimmingLeftWhitespace(`, 'optionalCall', ${arrowStartSnippet}`);
+ } else if (this.tokens.matches2(tt.questionDot, tt.bracketL)) {
+ this.tokens.replaceTokenTrimmingLeftWhitespace(`, 'optionalAccess', ${arrowStartSnippet}`);
+ } else if (this.tokens.matches1(tt.questionDot)) {
+ this.tokens.replaceTokenTrimmingLeftWhitespace(`, 'optionalAccess', ${arrowStartSnippet}.`);
+ } else if (this.tokens.matches1(tt.dot)) {
+ this.tokens.replaceTokenTrimmingLeftWhitespace(`, 'access', ${arrowStartSnippet}.`);
+ } else if (this.tokens.matches1(tt.bracketL)) {
+ this.tokens.replaceTokenTrimmingLeftWhitespace(`, 'access', ${arrowStartSnippet}[`);
+ } else if (this.tokens.matches1(tt.parenL)) {
+ if (this.justSkippedSuper()) {
+ this.tokens.appendCode(".bind(this)");
+ }
+ this.tokens.replaceTokenTrimmingLeftWhitespace(`, 'call', ${arrowStartSnippet}(`);
+ } else {
+ throw new Error("Unexpected subscript operator in optional chain.");
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the current token is the last of its chain, so that we know whether it's eligible
+ * to have a delete op inserted.
+ *
+ * We can do this by walking forward until we determine one way or another. Each
+ * isOptionalChainStart token must be paired with exactly one isOptionalChainEnd token after it in
+ * a nesting way, so we can track depth and walk to the end of the chain (the point where the
+ * depth goes negative) and see if any other subscript token is after us in the chain.
+ */
+ isLastSubscriptInChain() {
+ let depth = 0;
+ for (let i = this.tokens.currentIndex() + 1; ; i++) {
+ if (i >= this.tokens.tokens.length) {
+ throw new Error("Reached the end of the code while finding the end of the access chain.");
+ }
+ if (this.tokens.tokens[i].isOptionalChainStart) {
+ depth++;
+ } else if (this.tokens.tokens[i].isOptionalChainEnd) {
+ depth--;
+ }
+ if (depth < 0) {
+ return true;
+ }
+
+ // This subscript token is a later one in the same chain.
+ if (depth === 0 && this.tokens.tokens[i].subscriptStartIndex != null) {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Determine if we are the open-paren in an expression like super.a()?.b.
+ *
+ * We can do this by walking backward to find the previous subscript. If that subscript was
+ * preceded by a super, then we must be the subscript after it, so if this is a call expression,
+ * we'll need to attach the right context.
+ */
+ justSkippedSuper() {
+ let depth = 0;
+ let index = this.tokens.currentIndex() - 1;
+ while (true) {
+ if (index < 0) {
+ throw new Error(
+ "Reached the start of the code while finding the start of the access chain.",
+ );
+ }
+ if (this.tokens.tokens[index].isOptionalChainStart) {
+ depth--;
+ } else if (this.tokens.tokens[index].isOptionalChainEnd) {
+ depth++;
+ }
+ if (depth < 0) {
+ return false;
+ }
+
+ // This subscript token is a later one in the same chain.
+ if (depth === 0 && this.tokens.tokens[index].subscriptStartIndex != null) {
+ return this.tokens.tokens[index - 1].type === tt._super;
+ }
+ index--;
+ }
+ }
+}
diff --git a/node_modules/sucrase/dist/esm/transformers/ReactDisplayNameTransformer.js b/node_modules/sucrase/dist/esm/transformers/ReactDisplayNameTransformer.js
new file mode 100644
index 0000000..0c44c81
--- /dev/null
+++ b/node_modules/sucrase/dist/esm/transformers/ReactDisplayNameTransformer.js
@@ -0,0 +1,160 @@
+
+
+import {IdentifierRole} from "../parser/tokenizer";
+import {TokenType as tt} from "../parser/tokenizer/types";
+
+
+import Transformer from "./Transformer";
+
+/**
+ * Implementation of babel-plugin-transform-react-display-name, which adds a
+ * display name to usages of React.createClass and createReactClass.
+ */
+export default class ReactDisplayNameTransformer extends Transformer {
+ constructor(
+ rootTransformer,
+ tokens,
+ importProcessor,
+ options,
+ ) {
+ super();this.rootTransformer = rootTransformer;this.tokens = tokens;this.importProcessor = importProcessor;this.options = options;;
+ }
+
+ process() {
+ const startIndex = this.tokens.currentIndex();
+ if (this.tokens.identifierName() === "createReactClass") {
+ const newName =
+ this.importProcessor && this.importProcessor.getIdentifierReplacement("createReactClass");
+ if (newName) {
+ this.tokens.replaceToken(`(0, ${newName})`);
+ } else {
+ this.tokens.copyToken();
+ }
+ this.tryProcessCreateClassCall(startIndex);
+ return true;
+ }
+ if (
+ this.tokens.matches3(tt.name, tt.dot, tt.name) &&
+ this.tokens.identifierName() === "React" &&
+ this.tokens.identifierNameAtIndex(this.tokens.currentIndex() + 2) === "createClass"
+ ) {
+ const newName = this.importProcessor
+ ? this.importProcessor.getIdentifierReplacement("React") || "React"
+ : "React";
+ if (newName) {
+ this.tokens.replaceToken(newName);
+ this.tokens.copyToken();
+ this.tokens.copyToken();
+ } else {
+ this.tokens.copyToken();
+ this.tokens.copyToken();
+ this.tokens.copyToken();
+ }
+ this.tryProcessCreateClassCall(startIndex);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * This is called with the token position at the open-paren.
+ */
+ tryProcessCreateClassCall(startIndex) {
+ const displayName = this.findDisplayName(startIndex);
+ if (!displayName) {
+ return;
+ }
+
+ if (this.classNeedsDisplayName()) {
+ this.tokens.copyExpectedToken(tt.parenL);
+ this.tokens.copyExpectedToken(tt.braceL);
+ this.tokens.appendCode(`displayName: '${displayName}',`);
+ this.rootTransformer.processBalancedCode();
+ this.tokens.copyExpectedToken(tt.braceR);
+ this.tokens.copyExpectedToken(tt.parenR);
+ }
+ }
+
+ findDisplayName(startIndex) {
+ if (startIndex < 2) {
+ return null;
+ }
+ if (this.tokens.matches2AtIndex(startIndex - 2, tt.name, tt.eq)) {
+ // This is an assignment (or declaration) and the LHS is either an identifier or a member
+ // expression ending in an identifier, so use that identifier name.
+ return this.tokens.identifierNameAtIndex(startIndex - 2);
+ }
+ if (
+ startIndex >= 2 &&
+ this.tokens.tokens[startIndex - 2].identifierRole === IdentifierRole.ObjectKey
+ ) {
+ // This is an object literal value.
+ return this.tokens.identifierNameAtIndex(startIndex - 2);
+ }
+ if (this.tokens.matches2AtIndex(startIndex - 2, tt._export, tt._default)) {
+ return this.getDisplayNameFromFilename();
+ }
+ return null;
+ }
+
+ getDisplayNameFromFilename() {
+ const filePath = this.options.filePath || "unknown";
+ const pathSegments = filePath.split("/");
+ const filename = pathSegments[pathSegments.length - 1];
+ const dotIndex = filename.lastIndexOf(".");
+ const baseFilename = dotIndex === -1 ? filename : filename.slice(0, dotIndex);
+ if (baseFilename === "index" && pathSegments[pathSegments.length - 2]) {
+ return pathSegments[pathSegments.length - 2];
+ } else {
+ return baseFilename;
+ }
+ }
+
+ /**
+ * We only want to add a display name when this is a function call containing
+ * one argument, which is an object literal without `displayName` as an
+ * existing key.
+ */
+ classNeedsDisplayName() {
+ let index = this.tokens.currentIndex();
+ if (!this.tokens.matches2(tt.parenL, tt.braceL)) {
+ return false;
+ }
+ // The block starts on the {, and we expect any displayName key to be in
+ // that context. We need to ignore other other contexts to avoid matching
+ // nested displayName keys.
+ const objectStartIndex = index + 1;
+ const objectContextId = this.tokens.tokens[objectStartIndex].contextId;
+ if (objectContextId == null) {
+ throw new Error("Expected non-null context ID on object open-brace.");
+ }
+
+ for (; index < this.tokens.tokens.length; index++) {
+ const token = this.tokens.tokens[index];
+ if (token.type === tt.braceR && token.contextId === objectContextId) {
+ index++;
+ break;
+ }
+
+ if (
+ this.tokens.identifierNameAtIndex(index) === "displayName" &&
+ this.tokens.tokens[index].identifierRole === IdentifierRole.ObjectKey &&
+ token.contextId === objectContextId
+ ) {
+ // We found a displayName key, so bail out.
+ return false;
+ }
+ }
+
+ if (index === this.tokens.tokens.length) {
+ throw new Error("Unexpected end of input when processing React class.");
+ }
+
+ // If we got this far, we know we have createClass with an object with no
+ // display name, so we want to proceed as long as that was the only argument.
+ return (
+ this.tokens.matches1AtIndex(index, tt.parenR) ||
+ this.tokens.matches2AtIndex(index, tt.comma, tt.parenR)
+ );
+ }
+}
diff --git a/node_modules/sucrase/dist/esm/transformers/ReactHotLoaderTransformer.js b/node_modules/sucrase/dist/esm/transformers/ReactHotLoaderTransformer.js
new file mode 100644
index 0000000..873902e
--- /dev/null
+++ b/node_modules/sucrase/dist/esm/transformers/ReactHotLoaderTransformer.js
@@ -0,0 +1,69 @@
+import {IdentifierRole, isTopLevelDeclaration} from "../parser/tokenizer";
+
+import Transformer from "./Transformer";
+
+export default class ReactHotLoaderTransformer extends Transformer {
+ __init() {this.extractedDefaultExportName = null}
+
+ constructor( tokens, filePath) {
+ super();this.tokens = tokens;this.filePath = filePath;ReactHotLoaderTransformer.prototype.__init.call(this);;
+ }
+
+ setExtractedDefaultExportName(extractedDefaultExportName) {
+ this.extractedDefaultExportName = extractedDefaultExportName;
+ }
+
+ getPrefixCode() {
+ return `
+ (function () {
+ var enterModule = require('react-hot-loader').enterModule;
+ enterModule && enterModule(module);
+ })();`
+ .replace(/\s+/g, " ")
+ .trim();
+ }
+
+ getSuffixCode() {
+ const topLevelNames = new Set();
+ for (const token of this.tokens.tokens) {
+ if (
+ !token.isType &&
+ isTopLevelDeclaration(token) &&
+ token.identifierRole !== IdentifierRole.ImportDeclaration
+ ) {
+ topLevelNames.add(this.tokens.identifierNameForToken(token));
+ }
+ }
+ const namesToRegister = Array.from(topLevelNames).map((name) => ({
+ variableName: name,
+ uniqueLocalName: name,
+ }));
+ if (this.extractedDefaultExportName) {
+ namesToRegister.push({
+ variableName: this.extractedDefaultExportName,
+ uniqueLocalName: "default",
+ });
+ }
+ return `
+;(function () {
+ var reactHotLoader = require('react-hot-loader').default;
+ var leaveModule = require('react-hot-loader').leaveModule;
+ if (!reactHotLoader) {
+ return;
+ }
+${namesToRegister
+ .map(
+ ({variableName, uniqueLocalName}) =>
+ ` reactHotLoader.register(${variableName}, "${uniqueLocalName}", ${JSON.stringify(
+ this.filePath || "",
+ )});`,
+ )
+ .join("\n")}
+ leaveModule(module);
+})();`;
+ }
+
+ process() {
+ return false;
+ }
+}
diff --git a/node_modules/sucrase/dist/esm/transformers/RootTransformer.js b/node_modules/sucrase/dist/esm/transformers/RootTransformer.js
new file mode 100644
index 0000000..c7a83fe
--- /dev/null
+++ b/node_modules/sucrase/dist/esm/transformers/RootTransformer.js
@@ -0,0 +1,462 @@
+
+
+
+import {ContextualKeyword} from "../parser/tokenizer/keywords";
+import {TokenType as tt} from "../parser/tokenizer/types";
+
+import getClassInfo, {} from "../util/getClassInfo";
+import CJSImportTransformer from "./CJSImportTransformer";
+import ESMImportTransformer from "./ESMImportTransformer";
+import FlowTransformer from "./FlowTransformer";
+import JestHoistTransformer from "./JestHoistTransformer";
+import JSXTransformer from "./JSXTransformer";
+import NumericSeparatorTransformer from "./NumericSeparatorTransformer";
+import OptionalCatchBindingTransformer from "./OptionalCatchBindingTransformer";
+import OptionalChainingNullishTransformer from "./OptionalChainingNullishTransformer";
+import ReactDisplayNameTransformer from "./ReactDisplayNameTransformer";
+import ReactHotLoaderTransformer from "./ReactHotLoaderTransformer";
+
+import TypeScriptTransformer from "./TypeScriptTransformer";
+
+
+
+
+
+
+
+
+export default class RootTransformer {
+ __init() {this.transformers = []}
+
+
+ __init2() {this.generatedVariables = []}
+
+
+
+
+
+ constructor(
+ sucraseContext,
+ transforms,
+ enableLegacyBabel5ModuleInterop,
+ options,
+ ) {;RootTransformer.prototype.__init.call(this);RootTransformer.prototype.__init2.call(this);
+ this.nameManager = sucraseContext.nameManager;
+ this.helperManager = sucraseContext.helperManager;
+ const {tokenProcessor, importProcessor} = sucraseContext;
+ this.tokens = tokenProcessor;
+ this.isImportsTransformEnabled = transforms.includes("imports");
+ this.isReactHotLoaderTransformEnabled = transforms.includes("react-hot-loader");
+ this.disableESTransforms = Boolean(options.disableESTransforms);
+
+ if (!options.disableESTransforms) {
+ this.transformers.push(
+ new OptionalChainingNullishTransformer(tokenProcessor, this.nameManager),
+ );
+ this.transformers.push(new NumericSeparatorTransformer(tokenProcessor));
+ this.transformers.push(new OptionalCatchBindingTransformer(tokenProcessor, this.nameManager));
+ }
+
+ if (transforms.includes("jsx")) {
+ if (options.jsxRuntime !== "preserve") {
+ this.transformers.push(
+ new JSXTransformer(this, tokenProcessor, importProcessor, this.nameManager, options),
+ );
+ }
+ this.transformers.push(
+ new ReactDisplayNameTransformer(this, tokenProcessor, importProcessor, options),
+ );
+ }
+
+ let reactHotLoaderTransformer = null;
+ if (transforms.includes("react-hot-loader")) {
+ if (!options.filePath) {
+ throw new Error("filePath is required when using the react-hot-loader transform.");
+ }
+ reactHotLoaderTransformer = new ReactHotLoaderTransformer(tokenProcessor, options.filePath);
+ this.transformers.push(reactHotLoaderTransformer);
+ }
+
+ // Note that we always want to enable the imports transformer, even when the import transform
+ // itself isn't enabled, since we need to do type-only import pruning for both Flow and
+ // TypeScript.
+ if (transforms.includes("imports")) {
+ if (importProcessor === null) {
+ throw new Error("Expected non-null importProcessor with imports transform enabled.");
+ }
+ this.transformers.push(
+ new CJSImportTransformer(
+ this,
+ tokenProcessor,
+ importProcessor,
+ this.nameManager,
+ this.helperManager,
+ reactHotLoaderTransformer,
+ enableLegacyBabel5ModuleInterop,
+ Boolean(options.enableLegacyTypeScriptModuleInterop),
+ transforms.includes("typescript"),
+ transforms.includes("flow"),
+ Boolean(options.preserveDynamicImport),
+ Boolean(options.keepUnusedImports),
+ ),
+ );
+ } else {
+ this.transformers.push(
+ new ESMImportTransformer(
+ tokenProcessor,
+ this.nameManager,
+ this.helperManager,
+ reactHotLoaderTransformer,
+ transforms.includes("typescript"),
+ transforms.includes("flow"),
+ Boolean(options.keepUnusedImports),
+ options,
+ ),
+ );
+ }
+
+ if (transforms.includes("flow")) {
+ this.transformers.push(
+ new FlowTransformer(this, tokenProcessor, transforms.includes("imports")),
+ );
+ }
+ if (transforms.includes("typescript")) {
+ this.transformers.push(
+ new TypeScriptTransformer(this, tokenProcessor, transforms.includes("imports")),
+ );
+ }
+ if (transforms.includes("jest")) {
+ this.transformers.push(
+ new JestHoistTransformer(this, tokenProcessor, this.nameManager, importProcessor),
+ );
+ }
+ }
+
+ transform() {
+ this.tokens.reset();
+ this.processBalancedCode();
+ const shouldAddUseStrict = this.isImportsTransformEnabled;
+ // "use strict" always needs to be first, so override the normal transformer order.
+ let prefix = shouldAddUseStrict ? '"use strict";' : "";
+ for (const transformer of this.transformers) {
+ prefix += transformer.getPrefixCode();
+ }
+ prefix += this.helperManager.emitHelpers();
+ prefix += this.generatedVariables.map((v) => ` var ${v};`).join("");
+ for (const transformer of this.transformers) {
+ prefix += transformer.getHoistedCode();
+ }
+ let suffix = "";
+ for (const transformer of this.transformers) {
+ suffix += transformer.getSuffixCode();
+ }
+ const result = this.tokens.finish();
+ let {code} = result;
+ if (code.startsWith("#!")) {
+ let newlineIndex = code.indexOf("\n");
+ if (newlineIndex === -1) {
+ newlineIndex = code.length;
+ code += "\n";
+ }
+ return {
+ code: code.slice(0, newlineIndex + 1) + prefix + code.slice(newlineIndex + 1) + suffix,
+ // The hashbang line has no tokens, so shifting the tokens to account
+ // for prefix can happen normally.
+ mappings: this.shiftMappings(result.mappings, prefix.length),
+ };
+ } else {
+ return {
+ code: prefix + code + suffix,
+ mappings: this.shiftMappings(result.mappings, prefix.length),
+ };
+ }
+ }
+
+ processBalancedCode() {
+ let braceDepth = 0;
+ let parenDepth = 0;
+ while (!this.tokens.isAtEnd()) {
+ if (this.tokens.matches1(tt.braceL) || this.tokens.matches1(tt.dollarBraceL)) {
+ braceDepth++;
+ } else if (this.tokens.matches1(tt.braceR)) {
+ if (braceDepth === 0) {
+ return;
+ }
+ braceDepth--;
+ }
+ if (this.tokens.matches1(tt.parenL)) {
+ parenDepth++;
+ } else if (this.tokens.matches1(tt.parenR)) {
+ if (parenDepth === 0) {
+ return;
+ }
+ parenDepth--;
+ }
+ this.processToken();
+ }
+ }
+
+ processToken() {
+ if (this.tokens.matches1(tt._class)) {
+ this.processClass();
+ return;
+ }
+ for (const transformer of this.transformers) {
+ const wasProcessed = transformer.process();
+ if (wasProcessed) {
+ return;
+ }
+ }
+ this.tokens.copyToken();
+ }
+
+ /**
+ * Skip past a class with a name and return that name.
+ */
+ processNamedClass() {
+ if (!this.tokens.matches2(tt._class, tt.name)) {
+ throw new Error("Expected identifier for exported class name.");
+ }
+ const name = this.tokens.identifierNameAtIndex(this.tokens.currentIndex() + 1);
+ this.processClass();
+ return name;
+ }
+
+ processClass() {
+ const classInfo = getClassInfo(this, this.tokens, this.nameManager, this.disableESTransforms);
+
+ // Both static and instance initializers need a class name to use to invoke the initializer, so
+ // assign to one if necessary.
+ const needsCommaExpression =
+ (classInfo.headerInfo.isExpression || !classInfo.headerInfo.className) &&
+ classInfo.staticInitializerNames.length + classInfo.instanceInitializerNames.length > 0;
+
+ let className = classInfo.headerInfo.className;
+ if (needsCommaExpression) {
+ className = this.nameManager.claimFreeName("_class");
+ this.generatedVariables.push(className);
+ this.tokens.appendCode(` (${className} =`);
+ }
+
+ const classToken = this.tokens.currentToken();
+ const contextId = classToken.contextId;
+ if (contextId == null) {
+ throw new Error("Expected class to have a context ID.");
+ }
+ this.tokens.copyExpectedToken(tt._class);
+ while (!this.tokens.matchesContextIdAndLabel(tt.braceL, contextId)) {
+ this.processToken();
+ }
+
+ this.processClassBody(classInfo, className);
+
+ const staticInitializerStatements = classInfo.staticInitializerNames.map(
+ (name) => `${className}.${name}()`,
+ );
+ if (needsCommaExpression) {
+ this.tokens.appendCode(
+ `, ${staticInitializerStatements.map((s) => `${s}, `).join("")}${className})`,
+ );
+ } else if (classInfo.staticInitializerNames.length > 0) {
+ this.tokens.appendCode(` ${staticInitializerStatements.map((s) => `${s};`).join(" ")}`);
+ }
+ }
+
+ /**
+ * We want to just handle class fields in all contexts, since TypeScript supports them. Later,
+ * when some JS implementations support class fields, this should be made optional.
+ */
+ processClassBody(classInfo, className) {
+ const {
+ headerInfo,
+ constructorInsertPos,
+ constructorInitializerStatements,
+ fields,
+ instanceInitializerNames,
+ rangesToRemove,
+ } = classInfo;
+ let fieldIndex = 0;
+ let rangeToRemoveIndex = 0;
+ const classContextId = this.tokens.currentToken().contextId;
+ if (classContextId == null) {
+ throw new Error("Expected non-null context ID on class.");
+ }
+ this.tokens.copyExpectedToken(tt.braceL);
+ if (this.isReactHotLoaderTransformEnabled) {
+ this.tokens.appendCode(
+ "__reactstandin__regenerateByEval(key, code) {this[key] = eval(code);}",
+ );
+ }
+
+ const needsConstructorInit =
+ constructorInitializerStatements.length + instanceInitializerNames.length > 0;
+
+ if (constructorInsertPos === null && needsConstructorInit) {
+ const constructorInitializersCode = this.makeConstructorInitCode(
+ constructorInitializerStatements,
+ instanceInitializerNames,
+ className,
+ );
+ if (headerInfo.hasSuperclass) {
+ const argsName = this.nameManager.claimFreeName("args");
+ this.tokens.appendCode(
+ `constructor(...${argsName}) { super(...${argsName}); ${constructorInitializersCode}; }`,
+ );
+ } else {
+ this.tokens.appendCode(`constructor() { ${constructorInitializersCode}; }`);
+ }
+ }
+
+ while (!this.tokens.matchesContextIdAndLabel(tt.braceR, classContextId)) {
+ if (fieldIndex < fields.length && this.tokens.currentIndex() === fields[fieldIndex].start) {
+ let needsCloseBrace = false;
+ if (this.tokens.matches1(tt.bracketL)) {
+ this.tokens.copyTokenWithPrefix(`${fields[fieldIndex].initializerName}() {this`);
+ } else if (this.tokens.matches1(tt.string) || this.tokens.matches1(tt.num)) {
+ this.tokens.copyTokenWithPrefix(`${fields[fieldIndex].initializerName}() {this[`);
+ needsCloseBrace = true;
+ } else {
+ this.tokens.copyTokenWithPrefix(`${fields[fieldIndex].initializerName}() {this.`);
+ }
+ while (this.tokens.currentIndex() < fields[fieldIndex].end) {
+ if (needsCloseBrace && this.tokens.currentIndex() === fields[fieldIndex].equalsIndex) {
+ this.tokens.appendCode("]");
+ }
+ this.processToken();
+ }
+ this.tokens.appendCode("}");
+ fieldIndex++;
+ } else if (
+ rangeToRemoveIndex < rangesToRemove.length &&
+ this.tokens.currentIndex() >= rangesToRemove[rangeToRemoveIndex].start
+ ) {
+ if (this.tokens.currentIndex() < rangesToRemove[rangeToRemoveIndex].end) {
+ this.tokens.removeInitialToken();
+ }
+ while (this.tokens.currentIndex() < rangesToRemove[rangeToRemoveIndex].end) {
+ this.tokens.removeToken();
+ }
+ rangeToRemoveIndex++;
+ } else if (this.tokens.currentIndex() === constructorInsertPos) {
+ this.tokens.copyToken();
+ if (needsConstructorInit) {
+ this.tokens.appendCode(
+ `;${this.makeConstructorInitCode(
+ constructorInitializerStatements,
+ instanceInitializerNames,
+ className,
+ )};`,
+ );
+ }
+ this.processToken();
+ } else {
+ this.processToken();
+ }
+ }
+ this.tokens.copyExpectedToken(tt.braceR);
+ }
+
+ makeConstructorInitCode(
+ constructorInitializerStatements,
+ instanceInitializerNames,
+ className,
+ ) {
+ return [
+ ...constructorInitializerStatements,
+ ...instanceInitializerNames.map((name) => `${className}.prototype.${name}.call(this)`),
+ ].join(";");
+ }
+
+ /**
+ * Normally it's ok to simply remove type tokens, but we need to be more careful when dealing with
+ * arrow function return types since they can confuse the parser. In that case, we want to move
+ * the close-paren to the same line as the arrow.
+ *
+ * See https://github.com/alangpierce/sucrase/issues/391 for more details.
+ */
+ processPossibleArrowParamEnd() {
+ if (this.tokens.matches2(tt.parenR, tt.colon) && this.tokens.tokenAtRelativeIndex(1).isType) {
+ let nextNonTypeIndex = this.tokens.currentIndex() + 1;
+ // Look ahead to see if this is an arrow function or something else.
+ while (this.tokens.tokens[nextNonTypeIndex].isType) {
+ nextNonTypeIndex++;
+ }
+ if (this.tokens.matches1AtIndex(nextNonTypeIndex, tt.arrow)) {
+ this.tokens.removeInitialToken();
+ while (this.tokens.currentIndex() < nextNonTypeIndex) {
+ this.tokens.removeToken();
+ }
+ this.tokens.replaceTokenTrimmingLeftWhitespace(") =>");
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * An async arrow function might be of the form:
+ *
+ * async <
+ * T
+ * >() => {}
+ *
+ * in which case, removing the type parameters will cause a syntax error. Detect this case and
+ * move the open-paren earlier.
+ */
+ processPossibleAsyncArrowWithTypeParams() {
+ if (
+ !this.tokens.matchesContextual(ContextualKeyword._async) &&
+ !this.tokens.matches1(tt._async)
+ ) {
+ return false;
+ }
+ const nextToken = this.tokens.tokenAtRelativeIndex(1);
+ if (nextToken.type !== tt.lessThan || !nextToken.isType) {
+ return false;
+ }
+
+ let nextNonTypeIndex = this.tokens.currentIndex() + 1;
+ // Look ahead to see if this is an arrow function or something else.
+ while (this.tokens.tokens[nextNonTypeIndex].isType) {
+ nextNonTypeIndex++;
+ }
+ if (this.tokens.matches1AtIndex(nextNonTypeIndex, tt.parenL)) {
+ this.tokens.replaceToken("async (");
+ this.tokens.removeInitialToken();
+ while (this.tokens.currentIndex() < nextNonTypeIndex) {
+ this.tokens.removeToken();
+ }
+ this.tokens.removeToken();
+ // We ate a ( token, so we need to process the tokens in between and then the ) token so that
+ // we remain balanced.
+ this.processBalancedCode();
+ this.processToken();
+ return true;
+ }
+ return false;
+ }
+
+ processPossibleTypeRange() {
+ if (this.tokens.currentToken().isType) {
+ this.tokens.removeInitialToken();
+ while (this.tokens.currentToken().isType) {
+ this.tokens.removeToken();
+ }
+ return true;
+ }
+ return false;
+ }
+
+ shiftMappings(
+ mappings,
+ prefixLength,
+ ) {
+ for (let i = 0; i < mappings.length; i++) {
+ const mapping = mappings[i];
+ if (mapping !== undefined) {
+ mappings[i] = mapping + prefixLength;
+ }
+ }
+ return mappings;
+ }
+}
diff --git a/node_modules/sucrase/dist/esm/transformers/Transformer.js b/node_modules/sucrase/dist/esm/transformers/Transformer.js
new file mode 100644
index 0000000..5e8e9e7
--- /dev/null
+++ b/node_modules/sucrase/dist/esm/transformers/Transformer.js
@@ -0,0 +1,16 @@
+export default class Transformer {
+ // Return true if anything was processed, false otherwise.
+
+
+ getPrefixCode() {
+ return "";
+ }
+
+ getHoistedCode() {
+ return "";
+ }
+
+ getSuffixCode() {
+ return "";
+ }
+}
diff --git a/node_modules/sucrase/dist/esm/transformers/TypeScriptTransformer.js b/node_modules/sucrase/dist/esm/transformers/TypeScriptTransformer.js
new file mode 100644
index 0000000..67e1274
--- /dev/null
+++ b/node_modules/sucrase/dist/esm/transformers/TypeScriptTransformer.js
@@ -0,0 +1,279 @@
+
+import {TokenType as tt} from "../parser/tokenizer/types";
+
+import isIdentifier from "../util/isIdentifier";
+
+import Transformer from "./Transformer";
+
+export default class TypeScriptTransformer extends Transformer {
+ constructor(
+ rootTransformer,
+ tokens,
+ isImportsTransformEnabled,
+ ) {
+ super();this.rootTransformer = rootTransformer;this.tokens = tokens;this.isImportsTransformEnabled = isImportsTransformEnabled;;
+ }
+
+ process() {
+ if (
+ this.rootTransformer.processPossibleArrowParamEnd() ||
+ this.rootTransformer.processPossibleAsyncArrowWithTypeParams() ||
+ this.rootTransformer.processPossibleTypeRange()
+ ) {
+ return true;
+ }
+ if (
+ this.tokens.matches1(tt._public) ||
+ this.tokens.matches1(tt._protected) ||
+ this.tokens.matches1(tt._private) ||
+ this.tokens.matches1(tt._abstract) ||
+ this.tokens.matches1(tt._readonly) ||
+ this.tokens.matches1(tt._override) ||
+ this.tokens.matches1(tt.nonNullAssertion)
+ ) {
+ this.tokens.removeInitialToken();
+ return true;
+ }
+ if (this.tokens.matches1(tt._enum) || this.tokens.matches2(tt._const, tt._enum)) {
+ this.processEnum();
+ return true;
+ }
+ if (
+ this.tokens.matches2(tt._export, tt._enum) ||
+ this.tokens.matches3(tt._export, tt._const, tt._enum)
+ ) {
+ this.processEnum(true);
+ return true;
+ }
+ return false;
+ }
+
+ processEnum(isExport = false) {
+ // We might have "export const enum", so just remove all relevant tokens.
+ this.tokens.removeInitialToken();
+ while (this.tokens.matches1(tt._const) || this.tokens.matches1(tt._enum)) {
+ this.tokens.removeToken();
+ }
+ const enumName = this.tokens.identifierName();
+ this.tokens.removeToken();
+ if (isExport && !this.isImportsTransformEnabled) {
+ this.tokens.appendCode("export ");
+ }
+ this.tokens.appendCode(`var ${enumName}; (function (${enumName})`);
+ this.tokens.copyExpectedToken(tt.braceL);
+ this.processEnumBody(enumName);
+ this.tokens.copyExpectedToken(tt.braceR);
+ if (isExport && this.isImportsTransformEnabled) {
+ this.tokens.appendCode(`)(${enumName} || (exports.${enumName} = ${enumName} = {}));`);
+ } else {
+ this.tokens.appendCode(`)(${enumName} || (${enumName} = {}));`);
+ }
+ }
+
+ /**
+ * Transform an enum into equivalent JS. This has complexity in a few places:
+ * - TS allows string enums, numeric enums, and a mix of the two styles within an enum.
+ * - Enum keys are allowed to be referenced in later enum values.
+ * - Enum keys are allowed to be strings.
+ * - When enum values are omitted, they should follow an auto-increment behavior.
+ */
+ processEnumBody(enumName) {
+ // Code that can be used to reference the previous enum member, or null if this is the first
+ // enum member.
+ let previousValueCode = null;
+ while (true) {
+ if (this.tokens.matches1(tt.braceR)) {
+ break;
+ }
+ const {nameStringCode, variableName} = this.extractEnumKeyInfo(this.tokens.currentToken());
+ this.tokens.removeInitialToken();
+
+ if (
+ this.tokens.matches3(tt.eq, tt.string, tt.comma) ||
+ this.tokens.matches3(tt.eq, tt.string, tt.braceR)
+ ) {
+ this.processStringLiteralEnumMember(enumName, nameStringCode, variableName);
+ } else if (this.tokens.matches1(tt.eq)) {
+ this.processExplicitValueEnumMember(enumName, nameStringCode, variableName);
+ } else {
+ this.processImplicitValueEnumMember(
+ enumName,
+ nameStringCode,
+ variableName,
+ previousValueCode,
+ );
+ }
+ if (this.tokens.matches1(tt.comma)) {
+ this.tokens.removeToken();
+ }
+
+ if (variableName != null) {
+ previousValueCode = variableName;
+ } else {
+ previousValueCode = `${enumName}[${nameStringCode}]`;
+ }
+ }
+ }
+
+ /**
+ * Detect name information about this enum key, which will be used to determine which code to emit
+ * and whether we should declare a variable as part of this declaration.
+ *
+ * Some cases to keep in mind:
+ * - Enum keys can be implicitly referenced later, e.g. `X = 1, Y = X`. In Sucrase, we implement
+ * this by declaring a variable `X` so that later expressions can use it.
+ * - In addition to the usual identifier key syntax, enum keys are allowed to be string literals,
+ * e.g. `"hello world" = 3,`. Template literal syntax is NOT allowed.
+ * - Even if the enum key is defined as a string literal, it may still be referenced by identifier
+ * later, e.g. `"X" = 1, Y = X`. That means that we need to detect whether or not a string
+ * literal is identifier-like and emit a variable if so, even if the declaration did not use an
+ * identifier.
+ * - Reserved keywords like `break` are valid enum keys, but are not valid to be referenced later
+ * and would be a syntax error if we emitted a variable, so we need to skip the variable
+ * declaration in those cases.
+ *
+ * The variableName return value captures these nuances: if non-null, we can and must emit a
+ * variable declaration, and if null, we can't and shouldn't.
+ */
+ extractEnumKeyInfo(nameToken) {
+ if (nameToken.type === tt.name) {
+ const name = this.tokens.identifierNameForToken(nameToken);
+ return {
+ nameStringCode: `"${name}"`,
+ variableName: isIdentifier(name) ? name : null,
+ };
+ } else if (nameToken.type === tt.string) {
+ const name = this.tokens.stringValueForToken(nameToken);
+ return {
+ nameStringCode: this.tokens.code.slice(nameToken.start, nameToken.end),
+ variableName: isIdentifier(name) ? name : null,
+ };
+ } else {
+ throw new Error("Expected name or string at beginning of enum element.");
+ }
+ }
+
+ /**
+ * Handle an enum member where the RHS is just a string literal (not omitted, not a number, and
+ * not a complex expression). This is the typical form for TS string enums, and in this case, we
+ * do *not* create a reverse mapping.
+ *
+ * This is called after deleting the key token, when the token processor is at the equals sign.
+ *
+ * Example 1:
+ * someKey = "some value"
+ * ->
+ * const someKey = "some value"; MyEnum["someKey"] = someKey;
+ *
+ * Example 2:
+ * "some key" = "some value"
+ * ->
+ * MyEnum["some key"] = "some value";
+ */
+ processStringLiteralEnumMember(
+ enumName,
+ nameStringCode,
+ variableName,
+ ) {
+ if (variableName != null) {
+ this.tokens.appendCode(`const ${variableName}`);
+ // =
+ this.tokens.copyToken();
+ // value string
+ this.tokens.copyToken();
+ this.tokens.appendCode(`; ${enumName}[${nameStringCode}] = ${variableName};`);
+ } else {
+ this.tokens.appendCode(`${enumName}[${nameStringCode}]`);
+ // =
+ this.tokens.copyToken();
+ // value string
+ this.tokens.copyToken();
+ this.tokens.appendCode(";");
+ }
+ }
+
+ /**
+ * Handle an enum member initialized with an expression on the right-hand side (other than a
+ * string literal). In these cases, we should transform the expression and emit code that sets up
+ * a reverse mapping.
+ *
+ * The TypeScript implementation of this operation distinguishes between expressions that can be
+ * "constant folded" at compile time (i.e. consist of number literals and simple math operations
+ * on those numbers) and ones that are dynamic. For constant expressions, it emits the resolved
+ * numeric value, and auto-incrementing is only allowed in that case. Evaluating expressions at
+ * compile time would add significant complexity to Sucrase, so Sucrase instead leaves the
+ * expression as-is, and will later emit something like `MyEnum["previousKey"] + 1` to implement
+ * auto-incrementing.
+ *
+ * This is called after deleting the key token, when the token processor is at the equals sign.
+ *
+ * Example 1:
+ * someKey = 1 + 1
+ * ->
+ * const someKey = 1 + 1; MyEnum[MyEnum["someKey"] = someKey] = "someKey";
+ *
+ * Example 2:
+ * "some key" = 1 + 1
+ * ->
+ * MyEnum[MyEnum["some key"] = 1 + 1] = "some key";
+ */
+ processExplicitValueEnumMember(
+ enumName,
+ nameStringCode,
+ variableName,
+ ) {
+ const rhsEndIndex = this.tokens.currentToken().rhsEndIndex;
+ if (rhsEndIndex == null) {
+ throw new Error("Expected rhsEndIndex on enum assign.");
+ }
+
+ if (variableName != null) {
+ this.tokens.appendCode(`const ${variableName}`);
+ this.tokens.copyToken();
+ while (this.tokens.currentIndex() < rhsEndIndex) {
+ this.rootTransformer.processToken();
+ }
+ this.tokens.appendCode(
+ `; ${enumName}[${enumName}[${nameStringCode}] = ${variableName}] = ${nameStringCode};`,
+ );
+ } else {
+ this.tokens.appendCode(`${enumName}[${enumName}[${nameStringCode}]`);
+ this.tokens.copyToken();
+ while (this.tokens.currentIndex() < rhsEndIndex) {
+ this.rootTransformer.processToken();
+ }
+ this.tokens.appendCode(`] = ${nameStringCode};`);
+ }
+ }
+
+ /**
+ * Handle an enum member with no right-hand side expression. In this case, the value is the
+ * previous value plus 1, or 0 if there was no previous value. We should also always emit a
+ * reverse mapping.
+ *
+ * Example 1:
+ * someKey2
+ * ->
+ * const someKey2 = someKey1 + 1; MyEnum[MyEnum["someKey2"] = someKey2] = "someKey2";
+ *
+ * Example 2:
+ * "some key 2"
+ * ->
+ * MyEnum[MyEnum["some key 2"] = someKey1 + 1] = "some key 2";
+ */
+ processImplicitValueEnumMember(
+ enumName,
+ nameStringCode,
+ variableName,
+ previousValueCode,
+ ) {
+ let valueCode = previousValueCode != null ? `${previousValueCode} + 1` : "0";
+ if (variableName != null) {
+ this.tokens.appendCode(`const ${variableName} = ${valueCode}; `);
+ valueCode = variableName;
+ }
+ this.tokens.appendCode(
+ `${enumName}[${enumName}[${nameStringCode}] = ${valueCode}] = ${nameStringCode};`,
+ );
+ }
+}