summaryrefslogtreecommitdiff
path: root/node_modules/sucrase/dist/transformers/FlowTransformer.js
diff options
context:
space:
mode:
authorPhilipp Tanlak <philipp.tanlak@gmail.com>2025-11-24 20:54:57 +0100
committerPhilipp Tanlak <philipp.tanlak@gmail.com>2025-11-24 20:57:48 +0100
commitb1e2c8fd5cb5dfa46bc440a12eafaf56cd844b1c (patch)
tree49d360fd6cbc6a2754efe93524ac47ff0fbe0f7d /node_modules/sucrase/dist/transformers/FlowTransformer.js
Docs
Diffstat (limited to 'node_modules/sucrase/dist/transformers/FlowTransformer.js')
-rw-r--r--node_modules/sucrase/dist/transformers/FlowTransformer.js182
1 files changed, 182 insertions, 0 deletions
diff --git a/node_modules/sucrase/dist/transformers/FlowTransformer.js b/node_modules/sucrase/dist/transformers/FlowTransformer.js
new file mode 100644
index 0000000..31c9744
--- /dev/null
+++ b/node_modules/sucrase/dist/transformers/FlowTransformer.js
@@ -0,0 +1,182 @@
+"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }var _keywords = require('../parser/tokenizer/keywords');
+var _types = require('../parser/tokenizer/types');
+
+
+var _Transformer = require('./Transformer'); var _Transformer2 = _interopRequireDefault(_Transformer);
+
+ class FlowTransformer extends _Transformer2.default {
+ 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(_types.TokenType._enum)) {
+ this.processEnum();
+ return true;
+ }
+ if (this.tokens.matches2(_types.TokenType._export, _types.TokenType._enum)) {
+ this.processNamedExportEnum();
+ return true;
+ }
+ if (this.tokens.matches3(_types.TokenType._export, _types.TokenType._default, _types.TokenType._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(_types.TokenType.name);
+
+ let isSymbolEnum = false;
+ if (this.tokens.matchesContextual(_keywords.ContextualKeyword._of)) {
+ this.tokens.removeToken();
+ isSymbolEnum = this.tokens.matchesContextual(_keywords.ContextualKeyword._symbol);
+ this.tokens.removeToken();
+ }
+ const hasInitializers = this.tokens.matches3(_types.TokenType.braceL, _types.TokenType.name, _types.TokenType.eq);
+ this.tokens.appendCode(' = require("flow-enums-runtime")');
+
+ const isMirrored = !isSymbolEnum && !hasInitializers;
+ this.tokens.replaceTokenTrimmingLeftWhitespace(isMirrored ? ".Mirrored([" : "({");
+
+ while (!this.tokens.matches1(_types.TokenType.braceR)) {
+ // ... is allowed at the end and has no runtime behavior.
+ if (this.tokens.matches1(_types.TokenType.ellipsis)) {
+ this.tokens.removeToken();
+ break;
+ }
+ this.processEnumElement(isSymbolEnum, hasInitializers);
+ if (this.tokens.matches1(_types.TokenType.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()}"`);
+ }
+ }
+} exports.default = FlowTransformer;