diff --git a/eslint.config.js b/eslint.config.js index 178f0e1fa..9e3615764 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -454,7 +454,7 @@ const configs = [ "src/language-js/parse/json.js", "src/language-js/parse/acorn.js", "src/language-js/parse/oxc.js", - "src/language-js/parse/utilities/wrap-babel-expression.js", + "src/language-js/parse/utilities/wrap-expression.js", ], "prettier-internal-rules/prefer-create-type-check-function": [ "error", diff --git a/src/language-js/parse/angular.js b/src/language-js/parse/angular.js index 7781d12b7..b2bd366fd 100644 --- a/src/language-js/parse/angular.js +++ b/src/language-js/parse/angular.js @@ -6,6 +6,11 @@ import { } from "angular-estree-parser"; import createError from "../../common/parser-create-error.js"; import { locEnd, locStart } from "../loc.js"; +import wrapExpression from "./utilities/wrap-expression.js"; + +/** +@import {TupleTypeAnnotation} from "@babel/types" +*/ function createParseError(error) { /* c8 ignore next 3 */ @@ -27,7 +32,12 @@ function createParseError(error) { } /** -@typedef {parseAction | parseBinding | parseInterpolationExpression | parseTemplateBindings} Parsers +@typedef { + | parseAction + | parseBinding + | parseInterpolationExpression + | parseTemplateBindings +} Parsers */ /** @@ -38,7 +48,7 @@ function createParser(parseMethod) { return { astFormat: "estree", parse(text) { - /** @type {ReturnType} */ + /** @type {Exclude, TupleTypeAnnotation>} */ let node; try { @@ -57,11 +67,12 @@ function createParser(parseMethod) { node = { ...node, type: "NGChainedExpression", expressions: [node] }; } - return { + return wrapExpression({ type: "NGRoot", - node, + expression: node, comments, - }; + text, + }); }, locStart, locEnd, diff --git a/src/language-js/parse/babel.js b/src/language-js/parse/babel.js index b215c91fc..5693ce601 100644 --- a/src/language-js/parse/babel.js +++ b/src/language-js/parse/babel.js @@ -10,7 +10,7 @@ import { SOURCE_TYPE_COMMONJS, SOURCE_TYPE_MODULE, } from "./utilities/source-types.js"; -import wrapBabelExpression from "./utilities/wrap-babel-expression.js"; +import wrapExpression from "./utilities/wrap-expression.js"; const createBabelParser = (options) => createParser(createParse(options)); @@ -166,7 +166,11 @@ function createParse({ isExpression = false, optionsCombinations }) { } if (isExpression) { - ast = wrapBabelExpression(ast, { text, rootMarker: options.rootMarker }); + ast = wrapExpression({ + expression: ast, + text, + rootMarker: options.rootMarker, + }); } return postprocess(ast, { text }); diff --git a/src/language-js/parse/utilities/wrap-babel-expression.js b/src/language-js/parse/utilities/wrap-babel-expression.js deleted file mode 100644 index d7c40e276..000000000 --- a/src/language-js/parse/utilities/wrap-babel-expression.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @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: expression, - range: [0, text.length], - rootMarker, - }; -} - -export default wrapBabelExpression; diff --git a/src/language-js/parse/utilities/wrap-expression.js b/src/language-js/parse/utilities/wrap-expression.js new file mode 100644 index 000000000..a4dd23a8a --- /dev/null +++ b/src/language-js/parse/utilities/wrap-expression.js @@ -0,0 +1,38 @@ +/** +@import {Comment, Node} from "../../types/estree.js" +*/ + +/** + * @param {{ + * text: string, + * expression?: Node, + * type?: string, + * rootMarker?: string, + * comments?: Comment[], + * }} options + */ +function wrapExpression(options) { + const { + type = "JsExpressionRoot", + expression, + comments = expression?.comments ?? [], + text, + rootMarker, + } = options; + + const root = { + type, + comments, + range: [0, text.length], + rootMarker, + }; + + if (expression) { + delete expression.comments; + root.node = expression; + } + + return root; +} + +export default wrapExpression; diff --git a/src/language-json/parse/json.js b/src/language-json/parse/json.js index c8a362fdf..4288bff24 100644 --- a/src/language-json/parse/json.js +++ b/src/language-json/parse/json.js @@ -1,7 +1,7 @@ import { parse, parseExpression } from "@babel/parser"; import createError from "../../common/parser-create-error.js"; import createBabelParseError from "../../language-js/parse/utilities/create-babel-parse-error.js"; -import wrapBabelExpression from "../../language-js/parse/utilities/wrap-babel-expression.js"; +import wrapExpression from "../../language-js/parse/utilities/wrap-expression.js"; import isNonEmptyArray from "../../utilities/is-non-empty-array.js"; const babelParseOptions = { @@ -30,15 +30,17 @@ function parseEmptyJson(text) { return; } - return file; + return { comments: file.comments }; } function parseJson(text, options = {}) { const { allowComments = true, allowEmpty = false } = options; let ast; + let comments; try { ast = parseExpression(text, babelParseOptions); + comments = ast.comments; } catch (/** @type {any} */ error) { if ( allowEmpty && @@ -46,29 +48,27 @@ function parseJson(text, options = {}) { error.reasonCode === "ParseExpressionEmptyInput" ) { try { - ast = parseEmptyJson(text); + ({ comments } = parseEmptyJson(text)); } catch { // No op } } - if (!ast) { + if (!comments) { throw createBabelParseError(error); } } - if (!allowComments && isNonEmptyArray(ast.comments)) { - throw createJsonError(ast.comments[0], "Comment"); + if (!allowComments && isNonEmptyArray(comments)) { + throw createJsonError(comments[0], "Comment"); } - ast = wrapBabelExpression(ast, { type: "JsonRoot", text }); - - if (ast.node.type === "File") { - delete ast.node; - } else { - assertJsonNode(ast.node); + if (!allowEmpty || ast) { + assertJsonNode(ast); } + ast = wrapExpression({ type: "JsonRoot", expression: ast, comments, text }); + return ast; }