From 88b67b57e4db719bd717b236278c1de695cc3ba4 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Tue, 7 Mar 2023 17:43:22 +0800 Subject: [PATCH] Stop manipulate `options` in parsers (#14463) --- src/language-js/parse/acorn.js | 3 +- src/language-js/parse/babel.js | 18 +++++----- src/language-js/parse/espree.js | 3 +- src/language-js/parse/flow.js | 5 ++- src/language-js/parse/meriyah.js | 3 +- src/language-js/parse/postprocess/index.js | 34 +++++++++---------- .../parse/postprocess/typescript.js | 4 +-- src/language-js/parse/typescript.js | 8 ++--- .../parse/utils/wrap-babel-expression.js | 23 +++++++++---- src/language-js/print/binaryish.js | 6 ++-- src/language-js/utils/index.js | 5 --- src/language-json/parser-json.js | 5 ++- 12 files changed, 56 insertions(+), 61 deletions(-) diff --git a/src/language-js/parse/acorn.js b/src/language-js/parse/acorn.js index d7746b8af..5264f6789 100644 --- a/src/language-js/parse/acorn.js +++ b/src/language-js/parse/acorn.js @@ -79,8 +79,7 @@ function parse(text, options = {}) { throw createParseError(error); } - options.originalText = text; - return postprocess(ast, options); + return postprocess(ast, { text }); } export default createParser(parse); diff --git a/src/language-js/parse/babel.js b/src/language-js/parse/babel.js index 3fabf8a1f..cdba24d77 100644 --- a/src/language-js/parse/babel.js +++ b/src/language-js/parse/babel.js @@ -104,17 +104,17 @@ function parseWithOptions(parse, text, options) { } function createParse({ isExpression = false, optionsCombinations }) { - return (text, opts = {}) => { + return (text, options = {}) => { if ( - (opts.parser === "babel" || opts.parser === "__babel_estree") && - isFlowFile(text, opts) + (options.parser === "babel" || options.parser === "__babel_estree") && + isFlowFile(text, options) ) { - opts.parser = "babel-flow"; - return babelFlow.parse(text, opts); + options.parser = "babel-flow"; + return babelFlow.parse(text, options); } let combinations = optionsCombinations; - const sourceType = opts.__babelSourceType ?? getSourceType(opts); + const sourceType = options.__babelSourceType ?? getSourceType(options); if (sourceType === "script") { combinations = combinations.map((options) => ({ ...options, @@ -158,13 +158,11 @@ function createParse({ isExpression = false, optionsCombinations }) { throw createBabelParseError(error); } - opts.originalText = text; - if (isExpression) { - ast = wrapBabelExpression(ast, opts); + ast = wrapBabelExpression(ast, { text, rootMarker: options.rootMarker }); } - return postprocess(ast, opts); + return postprocess(ast, { parser: "babel", text }); }; } diff --git a/src/language-js/parse/espree.js b/src/language-js/parse/espree.js index 09eb7e837..28e6c0b4a 100644 --- a/src/language-js/parse/espree.js +++ b/src/language-js/parse/espree.js @@ -52,8 +52,7 @@ function parse(text, options = {}) { throw createParseError(error); } - options.originalText = text; - return postprocess(ast, options); + return postprocess(ast, { text }); } export default createParser(parse); diff --git a/src/language-js/parse/flow.js b/src/language-js/parse/flow.js index 94ab981cd..1e4eb5518 100644 --- a/src/language-js/parse/flow.js +++ b/src/language-js/parse/flow.js @@ -40,15 +40,14 @@ function createParseError(error) { }); } -function parse(text, options = {}) { +function parse(text) { const ast = flowParser.parse(replaceHashbang(text), parseOptions); const [error] = ast.errors; if (error) { throw createParseError(error); } - options.originalText = text; - return postprocess(ast, options); + return postprocess(ast, { text }); } // Export as a plugin so we can reuse the same bundle for UMD loading diff --git a/src/language-js/parse/meriyah.js b/src/language-js/parse/meriyah.js index 6d2ff5eb4..3a28c857d 100644 --- a/src/language-js/parse/meriyah.js +++ b/src/language-js/parse/meriyah.js @@ -99,8 +99,7 @@ function parse(text, options = {}) { throw createParseError(error); } - options.originalText = text; - return postprocess(ast, options); + return postprocess(ast, { parser: "meriyah", text }); } const parser = { diff --git a/src/language-js/parse/postprocess/index.js b/src/language-js/parse/postprocess/index.js index a4d92758d..3370789b8 100644 --- a/src/language-js/parse/postprocess/index.js +++ b/src/language-js/parse/postprocess/index.js @@ -6,7 +6,15 @@ import isIndentableBlockComment from "../../utils/is-indentable-block-comment.js import visitNode from "./visit-node.js"; import throwSyntaxError from "./throw-ts-syntax-error.js"; +/** + * @param {{ + * text: string, + * parser?: string, + * }} options + */ function postprocess(ast, options) { + const { parser, text } = options; + // `InterpreterDirective` from babel parser // Other parsers parse it as comment, babel treat it as comment too // https://github.com/babel/babel/issues/15116 @@ -20,13 +28,7 @@ function postprocess(ast, options) { } // Keep Babel's non-standard ParenthesizedExpression nodes only if they have Closure-style type cast comments. - if ( - options.parser !== "typescript" && - options.parser !== "flow" && - options.parser !== "acorn" && - options.parser !== "espree" && - options.parser !== "meriyah" - ) { + if (parser === "babel") { const startOffsetsOfTypeCastedNodes = new Set(); // Comments might be attached not directly to ParenthesizedExpression but to its ancestor. @@ -92,7 +94,7 @@ function postprocess(ast, options) { break; case "ObjectExpression": // #12963 - if (options.parser === "typescript") { + if (parser === "typescript") { const invalidProperty = node.properties.find( (property) => property.type === "Property" && @@ -131,16 +133,14 @@ function postprocess(ast, options) { // For hack-style pipeline case "TopicReference": - options.__isUsingHackPipeline = true; + ast.extra = { ...ast.extra, __isUsingHackPipeline: true }; break; + // TODO: Remove this when https://github.com/meriyah/meriyah/issues/200 get fixed case "ExportAllDeclaration": { const { exported } = node; - if (options.parser === "meriyah" && exported?.type === "Identifier") { - const raw = options.originalText.slice( - locStart(exported), - locEnd(exported) - ); + if (parser === "meriyah" && exported?.type === "Identifier") { + const raw = text.slice(locStart(exported), locEnd(exported)); if (raw.startsWith('"') || raw.startsWith("'")) { node.exported = { ...node.exported, @@ -155,7 +155,7 @@ function postprocess(ast, options) { // TODO: Remove this when https://github.com/meriyah/meriyah/issues/231 get fixed case "PropertyDefinition": if ( - options.parser === "meriyah" && + parser === "meriyah" && node.static && !node.computed && !node.key @@ -197,7 +197,7 @@ function postprocess(ast, options) { // In `typescript`/`espree`/`flow`, `Program` doesn't count whitespace and comments // See https://github.com/eslint/espree/issues/488 if (ast.type === "Program") { - ast.range = [0, options.originalText.length]; + ast.range = [0, text.length]; } return ast; @@ -206,7 +206,7 @@ function postprocess(ast, options) { * - do nothing if there's a semicolon on `toOverrideNode.end` (no need to fix) */ function overrideLocEnd(toBeOverriddenNode, toOverrideNode) { - if (options.originalText[locEnd(toOverrideNode)] === ";") { + if (text[locEnd(toOverrideNode)] === ";") { return; } toBeOverriddenNode.range = [ diff --git a/src/language-js/parse/postprocess/typescript.js b/src/language-js/parse/postprocess/typescript.js index ed43df05d..4b523a4e1 100644 --- a/src/language-js/parse/postprocess/typescript.js +++ b/src/language-js/parse/postprocess/typescript.js @@ -291,8 +291,8 @@ const decoratorOrModifierRegExp = new RegExp( ["@", ...POSSIBLE_MODIFIERS].join("|") ); -function throwErrorForInvalidNodes(tsParseResult, options) { - if (!decoratorOrModifierRegExp.test(options.originalText)) { +function throwErrorForInvalidNodes(tsParseResult, text) { + if (!decoratorOrModifierRegExp.test(text)) { return; } diff --git a/src/language-js/parse/typescript.js b/src/language-js/parse/typescript.js index 60863c49e..527b5f3ea 100644 --- a/src/language-js/parse/typescript.js +++ b/src/language-js/parse/typescript.js @@ -37,7 +37,7 @@ function createParseError(error) { }); } -function parse(text, options = {}) { +function parse(text) { const textToParse = replaceHashbang(text); const jsx = isProbablyJsx(text); @@ -58,11 +58,9 @@ function parse(text, options = {}) { throw createParseError(error); } - options.originalText = text; + throwErrorForInvalidNodes(result, text); - throwErrorForInvalidNodes(result, options); - - return postprocess(result.ast, options); + return postprocess(result.ast, { parser: "typescript", text }); } /** diff --git a/src/language-js/parse/utils/wrap-babel-expression.js b/src/language-js/parse/utils/wrap-babel-expression.js index 70fbffe0f..d7c40e276 100644 --- a/src/language-js/parse/utils/wrap-babel-expression.js +++ b/src/language-js/parse/utils/wrap-babel-expression.js @@ -1,15 +1,24 @@ -function wrapBabelExpression(node, options, type = "JsExpressionRoot") { - const { tokens, comments } = node; - delete node.tokens; - delete node.comments; +/** + * @param {{ + * text: string, + * type?: string, + * rootMarker?: string, + * }} options + */ +function wrapBabelExpression(expression, options) { + const { type = "JsExpressionRoot", rootMarker, text } = options; + + const { tokens, comments } = expression; + delete expression.tokens; + delete expression.comments; return { tokens, comments, type, - node, - range: [0, options.originalText.length], - rootMarker: options.rootMarker, + node: expression, + range: [0, text.length], + rootMarker, }; } diff --git a/src/language-js/print/binaryish.js b/src/language-js/print/binaryish.js index f653de00c..5bc2f880f 100644 --- a/src/language-js/print/binaryish.js +++ b/src/language-js/print/binaryish.js @@ -20,7 +20,6 @@ import { isCallExpression, isMemberExpression, isObjectProperty, - isEnabledHackPipeline, isArrayOrTupleExpression, isObjectOrRecordExpression, } from "../utils/index.js"; @@ -37,7 +36,7 @@ function printBinaryishExpression(path, options, print) { parent.type === "SwitchStatement" || parent.type === "DoWhileStatement"); const isHackPipeline = - isEnabledHackPipeline(options) && node.operator === "|>"; + node.operator === "|>" && path.root.extra?.__isUsingHackPipeline; const parts = printBinaryishExpressions( path, @@ -253,7 +252,8 @@ function printBinaryishExpressions( if (shouldInline) { right = [operator, " ", print("right"), rightSuffix]; } else { - const isHackPipeline = isEnabledHackPipeline(options) && operator === "|>"; + const isHackPipeline = + operator === "|>" && path.root.extra?.__isUsingHackPipeline; const rightContent = isHackPipeline ? path.call( (left) => diff --git a/src/language-js/utils/index.js b/src/language-js/utils/index.js index c846e720f..0eef870ac 100644 --- a/src/language-js/utils/index.js +++ b/src/language-js/utils/index.js @@ -1184,10 +1184,6 @@ function isObjectProperty(node) { ); } -function isEnabledHackPipeline(options) { - return Boolean(options.__isUsingHackPipeline); -} - /** * This is used as a marker for dangling comments. */ @@ -1217,7 +1213,6 @@ export { identity, isBinaryish, isCallLikeExpression, - isEnabledHackPipeline, isLineComment, isPrettierIgnoreComment, isCallExpression, diff --git a/src/language-json/parser-json.js b/src/language-json/parser-json.js index b2f047645..dce561105 100644 --- a/src/language-json/parser-json.js +++ b/src/language-json/parser-json.js @@ -8,7 +8,7 @@ import wrapBabelExpression from "../language-js/parse/utils/wrap-babel-expressio function createJsonParse(options = {}) { const { allowComments = true } = options; - return function parse(text, options = {}) { + return function parse(text) { let ast; try { ast = parseExpression(text, { @@ -37,8 +37,7 @@ function createJsonParse(options = {}) { assertJsonNode(ast); - options.originalText = text; - return wrapBabelExpression(ast, options, "JsonRoot"); + return wrapBabelExpression(ast, { type: "JsonRoot", text }); }; }