diff --git a/packages/babel-generator/src/generators/types.ts b/packages/babel-generator/src/generators/types.ts index 48ab4c3806e5..4a3731b2b2ea 100644 --- a/packages/babel-generator/src/generators/types.ts +++ b/packages/babel-generator/src/generators/types.ts @@ -240,16 +240,14 @@ export function DecimalLiteral(this: Printer, node: t.DecimalLiteral) { // Hack pipe operator export function TopicReference(this: Printer) { const { topicToken } = this.format; - switch (topicToken) { - case "#": - this.token("#"); - break; - - default: { - const givenTopicTokenJSON = JSON.stringify(topicToken); - const message = `The "topicToken" generator option must be "#" (${givenTopicTokenJSON} received instead).`; - throw new Error(message); - } + const validTopicTokenSet = new Set(["^", "%", "#"]); + + if (validTopicTokenSet.has(topicToken)) { + this.token(topicToken); + } else { + const givenTopicTokenJSON = JSON.stringify(topicToken); + const message = `The "topicToken" generator option must be "#" (${givenTopicTokenJSON} received instead).`; + throw new Error(message); } } diff --git a/packages/babel-generator/src/index.ts b/packages/babel-generator/src/index.ts index e16183ce0f3d..5346c24460b3 100644 --- a/packages/babel-generator/src/index.ts +++ b/packages/babel-generator/src/index.ts @@ -203,7 +203,7 @@ export interface GeneratorOptions { * For use with the Hack-style pipe operator. * Changes what token is used for pipe bodies’ topic references. */ - topicToken?: "#"; + topicToken?: "^" | "%" | "#"; } export interface GeneratorResult { diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 0967efbd3cfa..6d27f347eaac 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -1232,26 +1232,15 @@ export default class ExpressionParser extends LValParser { return this.parsePrivateName(); } - case tt.moduloAssign: - if ( - this.getPluginOption("pipelineOperator", "proposal") === "hack" && - this.getPluginOption("pipelineOperator", "topicToken") === "%" - ) { - // If we find %= in an expression position, and the Hack-pipes proposal is active, - // then the % could be the topic token (e.g., in x |> %==y or x |> %===y), and so we - // reparse it as %. - // The next readToken() call will start parsing from =. - - this.state.value = "%"; - this.state.type = tt.modulo; - this.state.pos--; - this.state.end--; - this.state.endLoc.column--; - } else { - throw this.unexpected(); - } + case tt.moduloAssign: { + return this.parseTopicReferenceThenEqualsSign(tt.modulo, "%"); + } + + case tt.xorAssign: { + return this.parseTopicReferenceThenEqualsSign(tt.bitwiseXOR, "^"); + } - // falls through + case tt.bitwiseXOR: case tt.modulo: case tt.hash: { const pipeProposal = this.getPluginOption( @@ -1260,28 +1249,12 @@ export default class ExpressionParser extends LValParser { ); if (pipeProposal) { - // A pipe-operator proposal is active, - // although its configuration might not match the current token’s type. - node = this.startNode(); - const start = this.state.start; - const tokenType = this.state.type; - - // Consume the current token. - this.next(); - - // If the pipe-operator plugin’s configuration matches the current token’s type, - // then this will return `node`, will have been finished as a topic reference. - // Otherwise, this will throw a `PipeTopicUnconfiguredToken` error. - return this.finishTopicReference( - node, - start, - pipeProposal, - tokenType, - ); + return this.parseTopicReference(pipeProposal); + } else { + throw this.unexpected(); } } - // fall through case tt.relational: { if (this.state.value === "<") { const lookaheadCh = this.input.codePointAt(this.nextTokenStart()); @@ -1290,16 +1263,75 @@ export default class ExpressionParser extends LValParser { lookaheadCh === charCodes.greaterThan // Fragment <> ) { this.expectOnePlugin(["jsx", "flow", "typescript"]); + break; + } else { + throw this.unexpected(); } + } else { + throw this.unexpected(); } } - // fall through default: throw this.unexpected(); } } + // This helper method should only be called + // when the parser has reached a potential Hack pipe topic token + // that is followed by an equals sign. + // See . + // If we find ^= or %= in an expression position + // (i.e., the tt.moduloAssign or tt.xorAssign token types), + // and if the Hack-pipes proposal is active with ^ or % as its topicToken, + // then the ^ or % could be the topic token (e.g., in x |> ^==y or x |> ^===y), + // and so we reparse the current token as ^ or %. + // Otherwise, this throws an unexpected-token error. + parseTopicReferenceThenEqualsSign( + topicTokenType: TokenType, + topicTokenValue: string, + ): N.Expression { + const pipeProposal = this.getPluginOption("pipelineOperator", "proposal"); + + if (pipeProposal) { + // Set the most-recent token to be a topic token + // given by the tokenType and tokenValue. + // Now the next readToken() call (in parseTopicReference) + // will consume that “topic token”. + this.state.type = topicTokenType; + this.state.value = topicTokenValue; + // Rewind the tokenizer to the end of the “topic token”, + // so that the following token starts at the equals sign after that topic token. + this.state.pos--; + this.state.end--; + this.state.endLoc.column--; + // Now actually consume the topic token. + return this.parseTopicReference(pipeProposal); + } else { + throw this.unexpected(); + } + } + + // This helper method should only be called + // when the proposal-pipeline-operator plugin is active, + // and when the parser has reached a potential Hack pipe topic token. + // Although a pipe-operator proposal is assumed to be active, + // its configuration might not match the current token’s type. + // See . + parseTopicReference(pipeProposal: string): N.Expression { + const node = this.startNode(); + const start = this.state.start; + const tokenType = this.state.type; + + // Consume the current token. + this.next(); + + // If the pipe-operator plugin’s configuration matches the current token’s type, + // then this will return `node`, will have been finished as a topic reference. + // Otherwise, this will throw a `PipeTopicUnconfiguredToken` error. + return this.finishTopicReference(node, start, pipeProposal, tokenType); + } + // This helper method attempts to finish the given `node` // into a topic-reference node for the given `pipeProposal`. // See . diff --git a/packages/babel-parser/src/plugin-utils.js b/packages/babel-parser/src/plugin-utils.js index 017d158bfcb7..0e2d64c26e6f 100644 --- a/packages/babel-parser/src/plugin-utils.js +++ b/packages/babel-parser/src/plugin-utils.js @@ -39,7 +39,7 @@ export function getPluginOption( } const PIPELINE_PROPOSALS = ["minimal", "fsharp", "hack", "smart"]; -const TOPIC_TOKENS = ["%", "#"]; +const TOPIC_TOKENS = ["^", "%", "#"]; const RECORD_AND_TUPLE_SYNTAX_TYPES = ["hash", "bar"]; export function validatePlugins(plugins: PluginList) { diff --git a/packages/babel-parser/src/tokenizer/index.js b/packages/babel-parser/src/tokenizer/index.js index 85a0a6039547..d77a1b62045c 100644 --- a/packages/babel-parser/src/tokenizer/index.js +++ b/packages/babel-parser/src/tokenizer/index.js @@ -594,20 +594,24 @@ export default class Tokenizer extends ParserErrors { } readToken_mult_modulo(code: number): void { - // '%*' + // '%' or '*' let type = code === charCodes.asterisk ? tt.star : tt.modulo; let width = 1; let next = this.input.charCodeAt(this.state.pos + 1); - // Exponentiation operator ** + // Exponentiation operator '**' if (code === charCodes.asterisk && next === charCodes.asterisk) { width++; next = this.input.charCodeAt(this.state.pos + 2); type = tt.exponent; } + // '%=' or '*=' if (next === charCodes.equalsTo && !this.state.inType) { width++; + // `tt.moduloAssign` is only needed to support % as a Hack-pipe topic token. + // If the proposal ends up choosing a different token, + // it can be merged with tt.assign. type = code === charCodes.percentSign ? tt.moduloAssign : tt.assign; } @@ -681,11 +685,17 @@ export default class Tokenizer extends ParserErrors { } readToken_caret(): void { - // '^' const next = this.input.charCodeAt(this.state.pos + 1); - if (next === charCodes.equalsTo) { - this.finishOp(tt.assign, 2); - } else { + + // '^=' + if (next === charCodes.equalsTo && !this.state.inType) { + // `tt.xorAssign` is only needed to support ^ as a Hack-pipe topic token. + // If the proposal ends up choosing a different token, + // it can be merged with tt.assign. + this.finishOp(tt.xorAssign, 2); + } + // '^' + else { this.finishOp(tt.bitwiseXOR, 1); } } diff --git a/packages/babel-parser/src/tokenizer/types.js b/packages/babel-parser/src/tokenizer/types.js index 9188b7b4aabd..068612d1a7dc 100644 --- a/packages/babel-parser/src/tokenizer/types.js +++ b/packages/babel-parser/src/tokenizer/types.js @@ -140,9 +140,14 @@ export const types: { [name: string]: TokenType } = { eq: new TokenType("=", { beforeExpr, isAssign }), assign: new TokenType("_=", { beforeExpr, isAssign }), slashAssign: new TokenType("_=", { beforeExpr, isAssign }), - // This is only needed to support % as a Hack-pipe topic token. If the proposal - // ends up choosing a different token, it can be merged with tt.assign. + // `tt.moduloAssign` is only needed to support % as a Hack-pipe topic token. + // If the proposal ends up choosing a different token, + // it can be merged with tt.assign. moduloAssign: new TokenType("_=", { beforeExpr, isAssign }), + // `tt.xorAssign` is only needed to support ^ as a Hack-pipe topic token. + // If the proposal ends up choosing a different token, + // it can be merged with tt.assign. + xorAssign: new TokenType("_=", { beforeExpr, isAssign }), incDec: new TokenType("++/--", { prefix, postfix, startsExpr }), bang: new TokenType("!", { beforeExpr, prefix, startsExpr }), tilde: new TokenType("~", { beforeExpr, prefix, startsExpr }), diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-hash-proposal-percent-topic/input.js b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-hash-proposal-percent-topic/input.js deleted file mode 100644 index d63a725e727e..000000000000 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-hash-proposal-percent-topic/input.js +++ /dev/null @@ -1 +0,0 @@ -value |> % diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-hash-proposal-percent-topic/options.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-hash-proposal-percent-topic/options.json deleted file mode 100644 index 2b8981cde576..000000000000 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-hash-proposal-percent-topic/options.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "plugins": [["pipelineOperator", { "proposal": "hack", "topicToken": "#" }]], - "throws": "Invalid topic token %. In order to use % as a topic reference, the pipelineOperator plugin must be configured with { \"proposal\": \"hack\", \"topicToken\": \"%\" }. (1:9)" -} diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-modulo-assignment-with-spaces/input.js b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-modulo-assignment-with-spaces/input.js deleted file mode 100644 index 59813118cee5..000000000000 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-modulo-assignment-with-spaces/input.js +++ /dev/null @@ -1 +0,0 @@ -value |> (variable %= %); diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-modulo-assignment-with-spaces/options.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-modulo-assignment-with-spaces/options.json deleted file mode 100644 index cfbb79338626..000000000000 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-modulo-assignment-with-spaces/options.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "plugins": [["pipelineOperator", { "proposal": "hack", "topicToken": "%" }]] -} diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-modulo-assignment-with-spaces/output.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-modulo-assignment-with-spaces/output.json deleted file mode 100644 index 94ab834b1611..000000000000 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-modulo-assignment-with-spaces/output.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "type": "File", - "start":0,"end":25,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":25}}, - "program": { - "type": "Program", - "start":0,"end":25,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":25}}, - "sourceType": "script", - "interpreter": null, - "body": [ - { - "type": "ExpressionStatement", - "start":0,"end":25,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":25}}, - "expression": { - "type": "BinaryExpression", - "start":0,"end":24,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":24}}, - "left": { - "type": "Identifier", - "start":0,"end":5,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":5},"identifierName":"value"}, - "name": "value" - }, - "operator": "|>", - "right": { - "type": "AssignmentExpression", - "start":10,"end":23,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":23}}, - "extra": { - "parenthesized": true, - "parenStart": 9 - }, - "operator": "%=", - "left": { - "type": "Identifier", - "start":10,"end":18,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":18},"identifierName":"variable"}, - "name": "variable" - }, - "right": { - "type": "TopicReference", - "start":22,"end":23,"loc":{"start":{"line":1,"column":22},"end":{"line":1,"column":23}} - } - } - } - } - ], - "directives": [] - } -} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-modulo-assignment-without-spaces/input.js b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-modulo-assignment-without-spaces/input.js deleted file mode 100644 index 6fac4290fb77..000000000000 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-modulo-assignment-without-spaces/input.js +++ /dev/null @@ -1 +0,0 @@ -value |> (variable%=%); diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-modulo-assignment-without-spaces/options.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-modulo-assignment-without-spaces/options.json deleted file mode 100644 index cfbb79338626..000000000000 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-modulo-assignment-without-spaces/options.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "plugins": [["pipelineOperator", { "proposal": "hack", "topicToken": "%" }]] -} diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-modulo-assignment-without-spaces/output.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-modulo-assignment-without-spaces/output.json deleted file mode 100644 index e9a58291fe3c..000000000000 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-modulo-assignment-without-spaces/output.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "type": "File", - "start":0,"end":23,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":23}}, - "program": { - "type": "Program", - "start":0,"end":23,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":23}}, - "sourceType": "script", - "interpreter": null, - "body": [ - { - "type": "ExpressionStatement", - "start":0,"end":23,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":23}}, - "expression": { - "type": "BinaryExpression", - "start":0,"end":22,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":22}}, - "left": { - "type": "Identifier", - "start":0,"end":5,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":5},"identifierName":"value"}, - "name": "value" - }, - "operator": "|>", - "right": { - "type": "AssignmentExpression", - "start":10,"end":21,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":21}}, - "extra": { - "parenthesized": true, - "parenStart": 9 - }, - "operator": "%=", - "left": { - "type": "Identifier", - "start":10,"end":18,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":18},"identifierName":"variable"}, - "name": "variable" - }, - "right": { - "type": "TopicReference", - "start":20,"end":21,"loc":{"start":{"line":1,"column":20},"end":{"line":1,"column":21}} - } - } - } - } - ], - "directives": [] - } -} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-within-modulo-assignment-with-spaces/input.js b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-within-modulo-assignment-with-spaces/input.js deleted file mode 100644 index cf93fdf68f03..000000000000 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-within-modulo-assignment-with-spaces/input.js +++ /dev/null @@ -1 +0,0 @@ -variable %= value |> %; diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-within-modulo-assignment-with-spaces/options.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-within-modulo-assignment-with-spaces/options.json deleted file mode 100644 index cfbb79338626..000000000000 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-within-modulo-assignment-with-spaces/options.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "plugins": [["pipelineOperator", { "proposal": "hack", "topicToken": "%" }]] -} diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-within-modulo-assignment-with-spaces/output.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-within-modulo-assignment-with-spaces/output.json deleted file mode 100644 index 60818d5b2bd1..000000000000 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-within-modulo-assignment-with-spaces/output.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "type": "File", - "start":0,"end":23,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":23}}, - "program": { - "type": "Program", - "start":0,"end":23,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":23}}, - "sourceType": "script", - "interpreter": null, - "body": [ - { - "type": "ExpressionStatement", - "start":0,"end":23,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":23}}, - "expression": { - "type": "AssignmentExpression", - "start":0,"end":22,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":22}}, - "operator": "%=", - "left": { - "type": "Identifier", - "start":0,"end":8,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":8},"identifierName":"variable"}, - "name": "variable" - }, - "right": { - "type": "BinaryExpression", - "start":12,"end":22,"loc":{"start":{"line":1,"column":12},"end":{"line":1,"column":22}}, - "left": { - "type": "Identifier", - "start":12,"end":17,"loc":{"start":{"line":1,"column":12},"end":{"line":1,"column":17},"identifierName":"value"}, - "name": "value" - }, - "operator": "|>", - "right": { - "type": "TopicReference", - "start":21,"end":22,"loc":{"start":{"line":1,"column":21},"end":{"line":1,"column":22}} - } - } - } - } - ], - "directives": [] - } -} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-within-modulo-assignment-without-spaces/input.js b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-within-modulo-assignment-without-spaces/input.js deleted file mode 100644 index eef896e1d855..000000000000 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-within-modulo-assignment-without-spaces/input.js +++ /dev/null @@ -1 +0,0 @@ -variable%=value |> %; diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-within-modulo-assignment-without-spaces/options.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-within-modulo-assignment-without-spaces/options.json deleted file mode 100644 index cfbb79338626..000000000000 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-within-modulo-assignment-without-spaces/options.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "plugins": [["pipelineOperator", { "proposal": "hack", "topicToken": "%" }]] -} diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-within-modulo-assignment-without-spaces/output.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-within-modulo-assignment-without-spaces/output.json deleted file mode 100644 index 997ad681f30b..000000000000 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/hack-percent-proposal-within-modulo-assignment-without-spaces/output.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "type": "File", - "start":0,"end":21,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":21}}, - "program": { - "type": "Program", - "start":0,"end":21,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":21}}, - "sourceType": "script", - "interpreter": null, - "body": [ - { - "type": "ExpressionStatement", - "start":0,"end":21,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":21}}, - "expression": { - "type": "AssignmentExpression", - "start":0,"end":20,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":20}}, - "operator": "%=", - "left": { - "type": "Identifier", - "start":0,"end":8,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":8},"identifierName":"variable"}, - "name": "variable" - }, - "right": { - "type": "BinaryExpression", - "start":10,"end":20,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":20}}, - "left": { - "type": "Identifier", - "start":10,"end":15,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":15},"identifierName":"value"}, - "name": "value" - }, - "operator": "|>", - "right": { - "type": "TopicReference", - "start":19,"end":20,"loc":{"start":{"line":1,"column":19},"end":{"line":1,"column":20}} - } - } - } - } - ], - "directives": [] - } -} \ No newline at end of file diff --git a/packages/babel-plugin-syntax-pipeline-operator/src/index.js b/packages/babel-plugin-syntax-pipeline-operator/src/index.js index f81201bb2fc9..6ee8d1fbb638 100644 --- a/packages/babel-plugin-syntax-pipeline-operator/src/index.js +++ b/packages/babel-plugin-syntax-pipeline-operator/src/index.js @@ -1,7 +1,7 @@ import { declare } from "@babel/helper-plugin-utils"; const PIPELINE_PROPOSALS = ["minimal", "fsharp", "hack", "smart"]; -const TOPIC_TOKENS = ["%", "#"]; +const TOPIC_TOKENS = ["^", "%", "#"]; const documentationURL = "https://babeljs.io/docs/en/babel-plugin-proposal-pipeline-operator";