| import * as espree from "./espree.js"; | ||
| export = espree; | ||
| //# sourceMappingURL=espree.d.cts.map |
| {"version":3,"file":"espree.d.cts","sourceRoot":"","sources":["../espree.cts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,SAAS,MAAM,CAAC"} |
| /** | ||
| * Tokenizes the given code. | ||
| * @param {string} code The code to tokenize. | ||
| * @param {Options} [options] Options defining how to tokenize. | ||
| * @returns {EspreeTokens} An array of tokens. | ||
| * @throws {EnhancedSyntaxError} If the input code is invalid. | ||
| * @private | ||
| */ | ||
| export function tokenize(code: string, options?: Options): EspreeTokens; | ||
| /** | ||
| * Parses the given code. | ||
| * @param {string} code The code to tokenize. | ||
| * @param {Options} [options] Options defining how to tokenize. | ||
| * @returns {acorn.Program} The "Program" AST node. | ||
| * @throws {EnhancedSyntaxError} If the input code is invalid. | ||
| */ | ||
| export function parse(code: string, options?: Options): acorn.Program; | ||
| /** @type {string} */ | ||
| export const version: string; | ||
| export const name: "espree"; | ||
| /** | ||
| * @type {visitorKeys.VisitorKeys} | ||
| */ | ||
| export const VisitorKeys: visitorKeys.VisitorKeys; | ||
| export const Syntax: Record<string, string>; | ||
| export const latestEcmaVersion: 17; | ||
| export const supportedEcmaVersions: [3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]; | ||
| export type EcmaVersion = 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | 2026 | "latest"; | ||
| export type EspreeToken = { | ||
| type: string; | ||
| value: any; | ||
| start?: number; | ||
| end?: number; | ||
| loc?: acorn.SourceLocation; | ||
| range?: [number, number]; | ||
| regex?: { | ||
| flags: string; | ||
| pattern: string; | ||
| }; | ||
| }; | ||
| export type EspreeComment = { | ||
| type: "Block" | "Hashbang" | "Line"; | ||
| value: string; | ||
| range?: [number, number]; | ||
| start?: number; | ||
| end?: number; | ||
| loc?: { | ||
| start: acorn.Position | undefined; | ||
| end: acorn.Position | undefined; | ||
| }; | ||
| }; | ||
| export type EspreeTokens = { | ||
| comments?: EspreeComment[]; | ||
| } & EspreeToken[]; | ||
| export type Options = { | ||
| allowReserved?: boolean; | ||
| ecmaVersion?: EcmaVersion; | ||
| sourceType?: "script" | "module" | "commonjs"; | ||
| ecmaFeatures?: { | ||
| jsx?: boolean; | ||
| globalReturn?: boolean; | ||
| impliedStrict?: boolean; | ||
| }; | ||
| range?: boolean; | ||
| loc?: boolean; | ||
| tokens?: boolean; | ||
| comment?: boolean; | ||
| }; | ||
| import * as acorn from "acorn"; | ||
| import * as visitorKeys from "eslint-visitor-keys"; | ||
| //# sourceMappingURL=espree.d.ts.map |
| {"version":3,"file":"espree.d.ts","sourceRoot":"","sources":["../espree.js"],"names":[],"mappings":"AAmNA;;;;;;;GAOG;AACH,+BANW,MAAM,YACN,OAAO,GACL,YAAY,CAaxB;AAMD;;;;;;GAMG;AACH,4BALW,MAAM,YACN,OAAO,GACL,KAAK,CAAC,OAAO,CAOzB;AAMD,qBAAqB;AACrB,sBADW,MAAM,CACe;AAChC,mBAAoB,QAAQ,CAAC;AAG7B;;GAEG;AACH,0BAFU,WAAW,CAAC,WAAW,CAI5B;AAIL,4CAqBK;AAEL,mCAAwD;AAExD,uFAAgE;0BA3NnD,CAAC,GAAC,CAAC,GAAC,CAAC,GAAC,CAAC,GAAC,CAAC,GAAC,CAAC,GAAC,EAAE,GAAC,EAAE,GAAC,EAAE,GAAC,EAAE,GAAC,EAAE,GAAC,EAAE,GAAC,EAAE,GAAC,EAAE,GAAC,IAAI,GAAC,IAAI,GAAC,IAAI,GAAC,IAAI,GAAC,IAAI,GAAC,IAAI,GAAC,IAAI,GAAC,IAAI,GAAC,IAAI,GAAC,IAAI,GAAC,IAAI,GAAC,IAAI,GAAC,QAAQ;0BAIxG;IACR,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC;IAC3B,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzB,KAAK,CAAC,EAAE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,CAAC;CAC1C;4BAIS;IACR,IAAI,EAAE,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE;QACJ,KAAK,EAAE,KAAK,CAAC,QAAQ,GAAG,SAAS,CAAC;QAClC,GAAG,EAAE,KAAK,CAAC,QAAQ,GAAG,SAAS,CAAA;KAChC,CAAA;CACF;2BAIS;IACR,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAA;CAC3B,GAAG,WAAW,EAAE;sBAeP;IACR,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,UAAU,CAAC,EAAE,QAAQ,GAAC,QAAQ,GAAC,UAAU,CAAC;IAC1C,YAAY,CAAC,EAAE;QACb,GAAG,CAAC,EAAE,OAAO,CAAC;QACd,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,aAAa,CAAC,EAAE,OAAO,CAAA;KACxB,CAAC;IACF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;uBA1EmB,OAAO;6BAGD,qBAAqB"} |
+118
| /** | ||
| * @import * as acorn from "acorn"; | ||
| * @import { Options, EspreeTokens } from "../espree.js"; | ||
| */ | ||
| /** | ||
| * @typedef {acorn.tokTypes & { | ||
| * jsxName: acorn.TokenType, | ||
| * jsxText: acorn.TokenType, | ||
| * jsxTagEnd: acorn.TokenType, | ||
| * jsxTagStart: acorn.TokenType | ||
| * }} TokTypes | ||
| */ | ||
| /** | ||
| * @typedef {new ( | ||
| * token: string, | ||
| * isExpr: boolean, | ||
| * preserveSpace: boolean, | ||
| * override?: (parser: any) => void | ||
| * ) => void} TokContext | ||
| */ | ||
| /** | ||
| * @typedef {{ | ||
| * tc_oTag: TokContext, | ||
| * tc_cTag: TokContext, | ||
| * tc_expr: TokContext | ||
| * }} TokContexts | ||
| */ | ||
| /** | ||
| * @typedef {{ | ||
| * generator?: boolean | ||
| * } & acorn.Node} EsprimaNode | ||
| */ | ||
| /** | ||
| * @typedef {"Block"|"Hashbang"|"Line"} CommentType | ||
| */ | ||
| /** | ||
| * @typedef {{ | ||
| * tokenize: () => EspreeTokens, | ||
| * parse: () => acorn.Program | ||
| * }} EspreeParser | ||
| */ | ||
| /* eslint-disable jsdoc/valid-types -- Waiting on jsdoc plugin update */ | ||
| /** | ||
| * @typedef {acorn.Parser & { | ||
| * jsx_readToken(): string; | ||
| * jsx_readNewLine(normalizeCRLF: boolean): void; | ||
| * jsx_readString(quote: number): void; | ||
| * jsx_readEntity(): string; | ||
| * jsx_readWord(): void; | ||
| * jsx_parseIdentifier(): acorn.Node; | ||
| * jsx_parseNamespacedName(): acorn.Node; | ||
| * jsx_parseElementName(): acorn.Node | string; | ||
| * jsx_parseAttributeValue(): acorn.Node; | ||
| * jsx_parseEmptyExpression(): acorn.Node; | ||
| * jsx_parseExpressionContainer(): acorn.Node; | ||
| * jsx_parseAttribute(): acorn.Node; | ||
| * jsx_parseOpeningElementAt(startPos: number, startLoc?: acorn.SourceLocation): acorn.Node; | ||
| * jsx_parseClosingElementAt(startPos: number, startLoc?: acorn.SourceLocation): acorn.Node; | ||
| * jsx_parseElementAt(startPos: number, startLoc?: acorn.SourceLocation): acorn.Node; | ||
| * jsx_parseText(): acorn.Node; | ||
| * jsx_parseElement(): acorn.Node; | ||
| * }} AcornJsxParser | ||
| */ | ||
| /** | ||
| * We pick (statics) from acorn rather than plain extending to avoid complaint | ||
| * about base constructors needing the same return type (i.e., we return | ||
| * `AcornJsxParser` here) | ||
| * @typedef {Pick<typeof acorn.Parser, keyof typeof acorn.Parser> & { | ||
| * readonly acornJsx: { | ||
| * tokTypes: TokTypes; | ||
| * tokContexts: TokContexts | ||
| * }; | ||
| * new (options: acorn.Options, input: string, startPos?: number): AcornJsxParser; | ||
| * }} AcornJsxParserCtor | ||
| */ | ||
| /** | ||
| * @typedef {{ | ||
| * new (opts: Options | null | undefined, code: string | object): EspreeParser | ||
| * } & Pick<typeof acorn.Parser, keyof typeof acorn.Parser>} EspreeParserCtor | ||
| */ | ||
| /** | ||
| * @typedef {{ | ||
| * new (opts: Options | null | undefined, code: string | object): EspreeParser | ||
| * } & Pick<AcornJsxParserCtor, keyof AcornJsxParserCtor>} EspreeParserJsxCtor | ||
| */ | ||
| /** | ||
| * @typedef {Pick<AcornJsxParserCtor, keyof AcornJsxParserCtor> & { | ||
| * acorn: { | ||
| * tokTypes: TokTypes, | ||
| * getLineInfo: (input: string, pos: number) => { | ||
| * line: number, | ||
| * column: number | ||
| * } | ||
| * } | ||
| * new (options: acorn.Options, input: string, startPos?: number): AcornJsxParser & { | ||
| * next: () => void, | ||
| * type: acorn.TokenType, | ||
| * curLine: number, | ||
| * start: number, | ||
| * end: number, | ||
| * finishNode (node: acorn.Node, type: string): acorn.Node, | ||
| * finishNodeAt (node: acorn.Node, type: string, pos: number, loc: acorn.Position): acorn.Node, | ||
| * parseTopLevel (node: acorn.Node): acorn.Node, | ||
| * nextToken (): void | ||
| * } | ||
| * }} AcornJsxParserCtorEnhanced | ||
| */ | ||
| /* eslint-enable jsdoc/valid-types -- Bug in older versions */ |
+654
-293
@@ -38,8 +38,32 @@ 'use strict'; | ||
| //------------------------------------------------------------------------------ | ||
| // Requirements | ||
| //------------------------------------------------------------------------------ | ||
| /** | ||
| * @import * as acorn from "acorn"; | ||
| * @import { EnhancedTokTypes } from "./espree.js" | ||
| * @import { NormalizedEcmaVersion } from "./options.js"; | ||
| * @import { EspreeToken as EsprimaToken } from "../espree.js"; | ||
| */ | ||
| /** | ||
| * Based on the `acorn.Token` class, but without a fixed `type` (since we need | ||
| * it to be a string). Avoiding `type` lets us make one extending interface | ||
| * more strict and another more lax. | ||
| * | ||
| * We could make `value` more strict to `string` even though the original is | ||
| * `any`. | ||
| * | ||
| * `start` and `end` are required in `acorn.Token` | ||
| * | ||
| * `loc` and `range` are from `acorn.Token` | ||
| * | ||
| * Adds `regex`. | ||
| */ | ||
| /** | ||
| * @typedef {{ | ||
| * jsxAttrValueToken: boolean; | ||
| * ecmaVersion: NormalizedEcmaVersion; | ||
| * }} ExtraNoTokens | ||
| * @typedef {{ | ||
| * tokens: EsprimaToken[] | ||
| * } & ExtraNoTokens} Extra | ||
| */ | ||
| // none! | ||
| //------------------------------------------------------------------------------ | ||
@@ -49,3 +73,2 @@ // Private | ||
| // Esprima Token Types | ||
@@ -70,3 +93,3 @@ const Token = { | ||
| * Converts part of a template into an Esprima token. | ||
| * @param {AcornToken[]} tokens The Acorn tokens representing the template. | ||
| * @param {acorn.Token[]} tokens The Acorn tokens representing the template. | ||
| * @param {string} code The source code. | ||
@@ -78,4 +101,11 @@ * @returns {EsprimaToken} The Esprima equivalent of the template token. | ||
| const firstToken = tokens[0], | ||
| lastTemplateToken = tokens.at(-1); | ||
| lastTemplateToken = | ||
| /** | ||
| * @type {acorn.Token & { | ||
| * loc: acorn.SourceLocation, | ||
| * range: [number, number] | ||
| * }} | ||
| */ (tokens.at(-1)); | ||
| /** @type {EsprimaToken} */ | ||
| const token = { | ||
@@ -102,27 +132,31 @@ type: Token.Template, | ||
| /* eslint-disable jsdoc/check-types -- The API allows either */ | ||
| /** | ||
| * Contains logic to translate Acorn tokens into Esprima tokens. | ||
| * @param {Object} acornTokTypes The Acorn token types. | ||
| * @param {string} code The source code Acorn is parsing. This is necessary | ||
| * to correct the "value" property of some tokens. | ||
| * @constructor | ||
| */ | ||
| function TokenTranslator(acornTokTypes, code) { | ||
| class TokenTranslator { | ||
| // token types | ||
| this._acornTokTypes = acornTokTypes; | ||
| /** | ||
| * Contains logic to translate Acorn tokens into Esprima tokens. | ||
| * @param {EnhancedTokTypes} acornTokTypes The Acorn token types. | ||
| * @param {string|String} code The source code Acorn is parsing. This is necessary | ||
| * to correct the "value" property of some tokens. | ||
| */ | ||
| constructor(acornTokTypes, code) { | ||
| /* eslint-enable jsdoc/check-types -- The API allows either */ | ||
| // token buffer for templates | ||
| this._tokens = []; | ||
| // token types | ||
| this._acornTokTypes = acornTokTypes; | ||
| // track the last curly brace | ||
| this._curlyBrace = null; | ||
| // token buffer for templates | ||
| /** @type {acorn.Token[]} */ | ||
| this._tokens = []; | ||
| // the source code | ||
| this._code = code; | ||
| // track the last curly brace | ||
| this._curlyBrace = null; | ||
| } | ||
| // the source code | ||
| this._code = code; | ||
| TokenTranslator.prototype = { | ||
| constructor: TokenTranslator, | ||
| } | ||
@@ -133,4 +167,4 @@ /** | ||
| * Acorn, but should be accurate for all other tokens. | ||
| * @param {AcornToken} token The Acorn token to translate. | ||
| * @param {Object} extra Espree extra object. | ||
| * @param {acorn.Token} token The Acorn token to translate. | ||
| * @param {ExtraNoTokens} extra Espree extra object. | ||
| * @returns {EsprimaToken} The Esprima version of the token. | ||
@@ -141,18 +175,25 @@ */ | ||
| const type = token.type, | ||
| tt = this._acornTokTypes; | ||
| tt = this._acornTokTypes, | ||
| // We use an unknown type because `acorn.Token` is a class whose | ||
| // `type` property we cannot override to our desired `string`; | ||
| // this also allows us to define a stricter `EsprimaToken` with | ||
| // a string-only `type` property | ||
| unknownTokenType = /** @type {unknown} */ (token), | ||
| newToken = /** @type {EsprimaToken} */ (unknownTokenType); | ||
| if (type === tt.name) { | ||
| token.type = Token.Identifier; | ||
| newToken.type = Token.Identifier; | ||
| // TODO: See if this is an Acorn bug | ||
| if (token.value === "static") { | ||
| token.type = Token.Keyword; | ||
| if ("value" in token && token.value === "static") { | ||
| newToken.type = Token.Keyword; | ||
| } | ||
| if (extra.ecmaVersion > 5 && (token.value === "yield" || token.value === "let")) { | ||
| token.type = Token.Keyword; | ||
| if (extra.ecmaVersion > 5 && ("value" in token && (token.value === "yield" || token.value === "let"))) { | ||
| newToken.type = Token.Keyword; | ||
| } | ||
| } else if (type === tt.privateId) { | ||
| token.type = Token.PrivateIdentifier; | ||
| newToken.type = Token.PrivateIdentifier; | ||
@@ -169,22 +210,22 @@ } else if (type === tt.semi || type === tt.comma || | ||
| type === tt.questionDot || | ||
| (type.binop && !type.keyword) || | ||
| type.isAssign) { | ||
| ("binop" in type && type.binop && !type.keyword) || | ||
| ("isAssign" in type && type.isAssign)) { | ||
| token.type = Token.Punctuator; | ||
| token.value = this._code.slice(token.start, token.end); | ||
| newToken.type = Token.Punctuator; | ||
| newToken.value = this._code.slice(token.start, token.end); | ||
| } else if (type === tt.jsxName) { | ||
| token.type = Token.JSXIdentifier; | ||
| newToken.type = Token.JSXIdentifier; | ||
| } else if (type.label === "jsxText" || type === tt.jsxAttrValueToken) { | ||
| token.type = Token.JSXText; | ||
| newToken.type = Token.JSXText; | ||
| } else if (type.keyword) { | ||
| if (type.keyword === "true" || type.keyword === "false") { | ||
| token.type = Token.Boolean; | ||
| newToken.type = Token.Boolean; | ||
| } else if (type.keyword === "null") { | ||
| token.type = Token.Null; | ||
| newToken.type = Token.Null; | ||
| } else { | ||
| token.type = Token.Keyword; | ||
| newToken.type = Token.Keyword; | ||
| } | ||
| } else if (type === tt.num) { | ||
| token.type = Token.Numeric; | ||
| token.value = this._code.slice(token.start, token.end); | ||
| newToken.type = Token.Numeric; | ||
| newToken.value = this._code.slice(token.start, token.end); | ||
| } else if (type === tt.string) { | ||
@@ -194,26 +235,28 @@ | ||
| extra.jsxAttrValueToken = false; | ||
| token.type = Token.JSXText; | ||
| newToken.type = Token.JSXText; | ||
| } else { | ||
| token.type = Token.String; | ||
| newToken.type = Token.String; | ||
| } | ||
| token.value = this._code.slice(token.start, token.end); | ||
| newToken.value = this._code.slice(token.start, token.end); | ||
| } else if (type === tt.regexp) { | ||
| token.type = Token.RegularExpression; | ||
| const value = token.value; | ||
| newToken.type = Token.RegularExpression; | ||
| const value = /** @type {{flags: string, pattern: string}} */ ( | ||
| "value" in token && token.value | ||
| ); | ||
| token.regex = { | ||
| newToken.regex = { | ||
| flags: value.flags, | ||
| pattern: value.pattern | ||
| }; | ||
| token.value = `/${value.pattern}/${value.flags}`; | ||
| newToken.value = `/${value.pattern}/${value.flags}`; | ||
| } | ||
| return token; | ||
| }, | ||
| return newToken; | ||
| } | ||
| /** | ||
| * Function to call during Acorn's onToken handler. | ||
| * @param {AcornToken} token The Acorn token. | ||
| * @param {Object} extra The Espree extra object. | ||
| * @param {acorn.Token} token The Acorn token. | ||
| * @param {Extra} extra The Espree extra object. | ||
| * @returns {void} | ||
@@ -298,3 +341,3 @@ */ | ||
| } | ||
| }; | ||
| } | ||
@@ -306,2 +349,6 @@ /** | ||
| /** | ||
| * @import { EcmaVersion, Options } from "../espree.js"; | ||
| */ | ||
| //------------------------------------------------------------------------------ | ||
@@ -311,3 +358,3 @@ // Helpers | ||
| const SUPPORTED_VERSIONS = [ | ||
| const SUPPORTED_VERSIONS = /** @type {const} */ ([ | ||
| 3, | ||
@@ -327,10 +374,21 @@ 5, | ||
| 17 // 2026 | ||
| ]; | ||
| ]); | ||
| /** | ||
| * @typedef {typeof SUPPORTED_VERSIONS[number]} NormalizedEcmaVersion | ||
| */ | ||
| const LATEST_ECMA_VERSION = | ||
| /* eslint-disable jsdoc/valid-types -- Bug */ | ||
| /** @type {typeof SUPPORTED_VERSIONS extends readonly [...unknown[], infer L] ? L : never} */ ( | ||
| SUPPORTED_VERSIONS.at(-1) | ||
| /* eslint-enable jsdoc/valid-types -- Bug */ | ||
| ); | ||
| /** | ||
| * Get the latest ECMAScript version supported by Espree. | ||
| * @returns {number} The latest ECMAScript version. | ||
| * @returns {typeof LATEST_ECMA_VERSION} The latest ECMAScript version. | ||
| */ | ||
| function getLatestEcmaVersion() { | ||
| return SUPPORTED_VERSIONS.at(-1); | ||
| return LATEST_ECMA_VERSION; | ||
| } | ||
@@ -340,3 +398,3 @@ | ||
| * Get the list of ECMAScript versions supported by Espree. | ||
| * @returns {number[]} An array containing the supported ECMAScript versions. | ||
| * @returns {[...typeof SUPPORTED_VERSIONS]} An array containing the supported ECMAScript versions. | ||
| */ | ||
@@ -349,5 +407,5 @@ function getSupportedEcmaVersions() { | ||
| * Normalize ECMAScript version from the initial config | ||
| * @param {(number|"latest")} ecmaVersion ECMAScript version from the initial config | ||
| * @param {EcmaVersion} ecmaVersion ECMAScript version from the initial config | ||
| * @throws {Error} throws an error if the ecmaVersion is invalid. | ||
| * @returns {number} normalized ECMAScript version | ||
| * @returns {NormalizedEcmaVersion} normalized ECMAScript version | ||
| */ | ||
@@ -368,7 +426,11 @@ function normalizeEcmaVersion(ecmaVersion = 5) { | ||
| if (!SUPPORTED_VERSIONS.includes(version)) { | ||
| if (!SUPPORTED_VERSIONS.includes( | ||
| /** @type {NormalizedEcmaVersion} */ | ||
| (version) | ||
| )) { | ||
| throw new Error("Invalid ecmaVersion."); | ||
| } | ||
| return version; | ||
| return /** @type {NormalizedEcmaVersion} */ (version); | ||
| } | ||
@@ -380,3 +442,3 @@ | ||
| * @throws {Error} throw an error if sourceType is invalid | ||
| * @returns {string} normalized sourceType | ||
| * @returns {"script"|"module"} normalized sourceType | ||
| */ | ||
@@ -396,6 +458,26 @@ function normalizeSourceType(sourceType = "script") { | ||
| /** | ||
| * @typedef {{ | ||
| * ecmaVersion: NormalizedEcmaVersion, | ||
| * sourceType: "script"|"module", | ||
| * range?: boolean, | ||
| * loc?: boolean, | ||
| * allowReserved: boolean | "never", | ||
| * ecmaFeatures?: { | ||
| * jsx?: boolean, | ||
| * globalReturn?: boolean, | ||
| * impliedStrict?: boolean | ||
| * }, | ||
| * ranges: boolean, | ||
| * locations: boolean, | ||
| * allowReturnOutsideFunction: boolean, | ||
| * tokens?: boolean, | ||
| * comment?: boolean | ||
| * }} NormalizedParserOptions | ||
| */ | ||
| /** | ||
| * Normalize parserOptions | ||
| * @param {Object} options the parser options to normalize | ||
| * @param {Options} options the parser options to normalize | ||
| * @throws {Error} throw an error if found invalid option. | ||
| * @returns {Object} normalized options | ||
| * @returns {NormalizedParserOptions} normalized options | ||
| */ | ||
@@ -437,3 +519,61 @@ function normalizeOptions(options) { | ||
| /** | ||
| * @import { | ||
| * CommentType, | ||
| * EspreeParserCtor, | ||
| * EsprimaNode, | ||
| * AcornJsxParserCtorEnhanced, | ||
| * TokTypes | ||
| * } from "./types.js"; | ||
| * @import { | ||
| * Options, | ||
| * EspreeToken as EsprimaToken, | ||
| * EspreeTokens as EsprimaTokens, | ||
| * EspreeComment as EsprimaComment | ||
| * } from "../espree.js"; | ||
| * @import { NormalizedEcmaVersion } from "./options.js"; | ||
| * @import * as acorn from "acorn"; | ||
| */ | ||
| /** | ||
| * @typedef {{ | ||
| * originalSourceType: "script" | "module" | "commonjs" | undefined | ||
| * tokens: EsprimaToken[] | null, | ||
| * comments: EsprimaComment[] | null, | ||
| * impliedStrict: boolean, | ||
| * ecmaVersion: NormalizedEcmaVersion, | ||
| * jsxAttrValueToken: boolean, | ||
| * lastToken: acorn.Token | null, | ||
| * templateElements: acorn.TemplateElement[] | ||
| * }} State | ||
| */ | ||
| /** | ||
| * @typedef {{ | ||
| * sourceType?: "script"|"module"|"commonjs"; | ||
| * comments?: EsprimaComment[]; | ||
| * tokens?: EsprimaToken[]; | ||
| * body: acorn.Node[]; | ||
| * } & acorn.Program} EsprimaProgramNode | ||
| */ | ||
| // ---------------------------------------------------------------------------- | ||
| // Types exported from file | ||
| // ---------------------------------------------------------------------------- | ||
| /** | ||
| * @typedef {{ | ||
| * index?: number; | ||
| * lineNumber?: number; | ||
| * column?: number; | ||
| * } & SyntaxError} EnhancedSyntaxError | ||
| */ | ||
| // We add `jsxAttrValueToken` ourselves. | ||
| /** | ||
| * @typedef {{ | ||
| * jsxAttrValueToken?: acorn.TokenType; | ||
| * } & TokTypes} EnhancedTokTypes | ||
| */ | ||
| const STATE = Symbol("espree's internal state"); | ||
@@ -447,11 +587,13 @@ const ESPRIMA_FINISH_NODE = Symbol("espree's esprimaFinishNode"); | ||
| * @param {string} text The text of the comment. | ||
| * @param {int} start The index at which the comment starts. | ||
| * @param {int} end The index at which the comment ends. | ||
| * @param {Location} startLoc The location at which the comment starts. | ||
| * @param {Location} endLoc The location at which the comment ends. | ||
| * @param {number} start The index at which the comment starts. | ||
| * @param {number} end The index at which the comment ends. | ||
| * @param {acorn.Position | undefined} startLoc The location at which the comment starts. | ||
| * @param {acorn.Position | undefined} endLoc The location at which the comment ends. | ||
| * @param {string} code The source code being parsed. | ||
| * @returns {Object} The comment object. | ||
| * @returns {EsprimaComment} The comment object. | ||
| * @private | ||
| */ | ||
| function convertAcornCommentToEsprimaComment(block, text, start, end, startLoc, endLoc, code) { | ||
| /** @type {CommentType} */ | ||
| let type; | ||
@@ -467,2 +609,15 @@ | ||
| /** | ||
| * @type {{ | ||
| * type: CommentType, | ||
| * value: string, | ||
| * start?: number, | ||
| * end?: number, | ||
| * range?: [number, number], | ||
| * loc?: { | ||
| * start: acorn.Position | undefined, | ||
| * end: acorn.Position | undefined | ||
| * } | ||
| * }} | ||
| */ | ||
| const comment = { | ||
@@ -489,271 +644,358 @@ type, | ||
| var espree = () => Parser => { | ||
| const tokTypes = Object.assign({}, Parser.acorn.tokTypes); | ||
| // eslint-disable-next-line arrow-body-style -- For TS | ||
| var espree = () => { | ||
| if (Parser.acornJsx) { | ||
| Object.assign(tokTypes, Parser.acornJsx.tokTypes); | ||
| } | ||
| /** | ||
| * Returns the Espree parser. | ||
| * @param {AcornJsxParserCtorEnhanced} Parser The Acorn parser. The `acorn` property is missing from acorn's | ||
| * TypeScript but is present statically on the class. | ||
| * @returns {EspreeParserCtor} The Espree Parser constructor. | ||
| */ | ||
| return Parser => { | ||
| const tokTypes = /** @type {EnhancedTokTypes} */ ( | ||
| Object.assign({}, Parser.acorn.tokTypes) | ||
| ); | ||
| return class Espree extends Parser { | ||
| constructor(opts, code) { | ||
| if (typeof opts !== "object" || opts === null) { | ||
| opts = {}; | ||
| } | ||
| if (typeof code !== "string" && !(code instanceof String)) { | ||
| code = String(code); | ||
| } | ||
| if (Parser.acornJsx) { | ||
| Object.assign(tokTypes, Parser.acornJsx.tokTypes); | ||
| } | ||
| // save original source type in case of commonjs | ||
| const originalSourceType = opts.sourceType; | ||
| const options = normalizeOptions(opts); | ||
| const ecmaFeatures = options.ecmaFeatures || {}; | ||
| const tokenTranslator = | ||
| options.tokens === true | ||
| ? new TokenTranslator(tokTypes, code) | ||
| : null; | ||
| return class Espree extends Parser { | ||
| /* | ||
| * Data that is unique to Espree and is not represented internally | ||
| * in Acorn. | ||
| * | ||
| * For ES2023 hashbangs, Espree will call `onComment()` during the | ||
| * constructor, so we must define state before having access to | ||
| * `this`. | ||
| /** | ||
| * @param {Options | null | undefined} opts The parser options | ||
| * @param {string | object} code The code which will be converted to a string. | ||
| */ | ||
| const state = { | ||
| originalSourceType: originalSourceType || options.sourceType, | ||
| tokens: tokenTranslator ? [] : null, | ||
| comments: options.comment === true ? [] : null, | ||
| impliedStrict: ecmaFeatures.impliedStrict === true && options.ecmaVersion >= 5, | ||
| ecmaVersion: options.ecmaVersion, | ||
| jsxAttrValueToken: false, | ||
| lastToken: null, | ||
| templateElements: [] | ||
| }; | ||
| constructor(opts, code) { | ||
| if (typeof opts !== "object" || opts === null) { | ||
| opts = {}; | ||
| } | ||
| if (typeof code !== "string" && !(code instanceof String)) { | ||
| code = String(code); | ||
| } | ||
| // Initialize acorn parser. | ||
| super({ | ||
| // save original source type in case of commonjs | ||
| const originalSourceType = opts.sourceType; | ||
| const options = normalizeOptions(opts); | ||
| const ecmaFeatures = options.ecmaFeatures || {}; | ||
| const tokenTranslator = | ||
| options.tokens === true | ||
| ? new TokenTranslator( | ||
| tokTypes, | ||
| // do not use spread, because we don't want to pass any unknown options to acorn | ||
| ecmaVersion: options.ecmaVersion, | ||
| sourceType: options.sourceType, | ||
| ranges: options.ranges, | ||
| locations: options.locations, | ||
| allowReserved: options.allowReserved, | ||
| // @ts-expect-error Appears to be a TS bug since the type is indeed string|String | ||
| code | ||
| ) | ||
| : null; | ||
| // Truthy value is true for backward compatibility. | ||
| allowReturnOutsideFunction: options.allowReturnOutsideFunction, | ||
| /** | ||
| * Data that is unique to Espree and is not represented internally | ||
| * in Acorn. | ||
| * | ||
| * For ES2023 hashbangs, Espree will call `onComment()` during the | ||
| * constructor, so we must define state before having access to | ||
| * `this`. | ||
| * @type {State} | ||
| */ | ||
| const state = { | ||
| originalSourceType: originalSourceType || options.sourceType, | ||
| tokens: tokenTranslator ? [] : null, | ||
| comments: options.comment === true ? [] : null, | ||
| impliedStrict: ecmaFeatures.impliedStrict === true && options.ecmaVersion >= 5, | ||
| ecmaVersion: options.ecmaVersion, | ||
| jsxAttrValueToken: false, | ||
| lastToken: null, | ||
| templateElements: [] | ||
| }; | ||
| // Collect tokens | ||
| onToken(token) { | ||
| if (tokenTranslator) { | ||
| // Initialize acorn parser. | ||
| super({ | ||
| // Use `tokens`, `ecmaVersion`, and `jsxAttrValueToken` in the state. | ||
| tokenTranslator.onToken(token, state); | ||
| } | ||
| if (token.type !== tokTypes.eof) { | ||
| state.lastToken = token; | ||
| } | ||
| }, | ||
| // do not use spread, because we don't want to pass any unknown options to acorn | ||
| ecmaVersion: options.ecmaVersion, | ||
| sourceType: options.sourceType, | ||
| ranges: options.ranges, | ||
| locations: options.locations, | ||
| allowReserved: options.allowReserved, | ||
| // Collect comments | ||
| onComment(block, text, start, end, startLoc, endLoc) { | ||
| if (state.comments) { | ||
| const comment = convertAcornCommentToEsprimaComment(block, text, start, end, startLoc, endLoc, code); | ||
| // Truthy value is true for backward compatibility. | ||
| allowReturnOutsideFunction: options.allowReturnOutsideFunction, | ||
| state.comments.push(comment); | ||
| } | ||
| } | ||
| }, code); | ||
| // Collect tokens | ||
| onToken(token) { | ||
| if (tokenTranslator) { | ||
| /* | ||
| * We put all of this data into a symbol property as a way to avoid | ||
| * potential naming conflicts with future versions of Acorn. | ||
| */ | ||
| this[STATE] = state; | ||
| } | ||
| // Use `tokens`, `ecmaVersion`, and `jsxAttrValueToken` in the state. | ||
| tokenTranslator.onToken( | ||
| token, | ||
| tokenize() { | ||
| do { | ||
| this.next(); | ||
| } while (this.type !== tokTypes.eof); | ||
| /** | ||
| * @type {Omit<State, "tokens"> & { | ||
| * tokens: EsprimaToken[] | ||
| * }} | ||
| */ | ||
| (state) | ||
| ); | ||
| } | ||
| if (token.type !== tokTypes.eof) { | ||
| state.lastToken = token; | ||
| } | ||
| }, | ||
| // Consume the final eof token | ||
| this.next(); | ||
| // Collect comments | ||
| onComment(block, text, start, end, startLoc, endLoc) { | ||
| if (state.comments) { | ||
| const comment = convertAcornCommentToEsprimaComment( | ||
| block, | ||
| text, | ||
| start, | ||
| end, | ||
| startLoc, | ||
| endLoc, | ||
| const extra = this[STATE]; | ||
| const tokens = extra.tokens; | ||
| // @ts-expect-error Appears to be a TS bug | ||
| // since the type is indeed string|String | ||
| code | ||
| ); | ||
| if (extra.comments) { | ||
| tokens.comments = extra.comments; | ||
| state.comments.push(comment); | ||
| } | ||
| } | ||
| // @ts-expect-error Appears to be a TS bug | ||
| // since the type is indeed string|String | ||
| }, code); | ||
| /* | ||
| * We put all of this data into a symbol property as a way to avoid | ||
| * potential naming conflicts with future versions of Acorn. | ||
| */ | ||
| this[STATE] = state; | ||
| } | ||
| return tokens; | ||
| } | ||
| /** | ||
| * Returns Espree tokens. | ||
| * @returns {EsprimaTokens} The Esprima-compatible tokens | ||
| */ | ||
| tokenize() { | ||
| do { | ||
| this.next(); | ||
| } while (this.type !== tokTypes.eof); | ||
| finishNode(...args) { | ||
| const result = super.finishNode(...args); | ||
| // Consume the final eof token | ||
| this.next(); | ||
| return this[ESPRIMA_FINISH_NODE](result); | ||
| } | ||
| const extra = this[STATE]; | ||
| const tokens = /** @type {EsprimaTokens} */ (extra.tokens); | ||
| finishNodeAt(...args) { | ||
| const result = super.finishNodeAt(...args); | ||
| if (extra.comments) { | ||
| tokens.comments = extra.comments; | ||
| } | ||
| return this[ESPRIMA_FINISH_NODE](result); | ||
| } | ||
| return tokens; | ||
| } | ||
| parse() { | ||
| const extra = this[STATE]; | ||
| const program = super.parse(); | ||
| /** | ||
| * Calls parent. | ||
| * @param {acorn.Node} node The node | ||
| * @param {string} type The type | ||
| * @returns {acorn.Node} The altered Node | ||
| */ | ||
| finishNode(node, type) { | ||
| const result = super.finishNode(node, type); | ||
| program.sourceType = extra.originalSourceType; | ||
| return this[ESPRIMA_FINISH_NODE](result); | ||
| } | ||
| if (extra.comments) { | ||
| program.comments = extra.comments; | ||
| /** | ||
| * Calls parent. | ||
| * @param {acorn.Node} node The node | ||
| * @param {string} type The type | ||
| * @param {number} pos The position | ||
| * @param {acorn.Position} loc The location | ||
| * @returns {acorn.Node} The altered Node | ||
| */ | ||
| finishNodeAt(node, type, pos, loc) { | ||
| const result = super.finishNodeAt(node, type, pos, loc); | ||
| return this[ESPRIMA_FINISH_NODE](result); | ||
| } | ||
| if (extra.tokens) { | ||
| program.tokens = extra.tokens; | ||
| } | ||
| /* | ||
| * https://github.com/eslint/espree/issues/349 | ||
| * Ensure that template elements have correct range information. | ||
| * This is one location where Acorn produces a different value | ||
| * for its start and end properties vs. the values present in the | ||
| * range property. In order to avoid confusion, we set the start | ||
| * and end properties to the values that are present in range. | ||
| * This is done here, instead of in finishNode(), because Acorn | ||
| * uses the values of start and end internally while parsing, making | ||
| * it dangerous to change those values while parsing is ongoing. | ||
| * By waiting until the end of parsing, we can safely change these | ||
| * values without affect any other part of the process. | ||
| /** | ||
| * Parses. | ||
| * @returns {EsprimaProgramNode} The program Node | ||
| */ | ||
| this[STATE].templateElements.forEach(templateElement => { | ||
| const startOffset = -1; | ||
| const endOffset = templateElement.tail ? 1 : 2; | ||
| parse() { | ||
| const extra = this[STATE]; | ||
| const prog = super.parse(); | ||
| templateElement.start += startOffset; | ||
| templateElement.end += endOffset; | ||
| const program = /** @type {EsprimaProgramNode} */ (prog); | ||
| if (templateElement.range) { | ||
| templateElement.range[0] += startOffset; | ||
| templateElement.range[1] += endOffset; | ||
| } | ||
| // @ts-expect-error TS bug? We've already converted to `EsprimaProgramNode` | ||
| program.sourceType = extra.originalSourceType; | ||
| if (templateElement.loc) { | ||
| templateElement.loc.start.column += startOffset; | ||
| templateElement.loc.end.column += endOffset; | ||
| if (extra.comments) { | ||
| program.comments = extra.comments; | ||
| } | ||
| }); | ||
| if (extra.tokens) { | ||
| program.tokens = extra.tokens; | ||
| } | ||
| return program; | ||
| } | ||
| /* | ||
| * https://github.com/eslint/espree/issues/349 | ||
| * Ensure that template elements have correct range information. | ||
| * This is one location where Acorn produces a different value | ||
| * for its start and end properties vs. the values present in the | ||
| * range property. In order to avoid confusion, we set the start | ||
| * and end properties to the values that are present in range. | ||
| * This is done here, instead of in finishNode(), because Acorn | ||
| * uses the values of start and end internally while parsing, making | ||
| * it dangerous to change those values while parsing is ongoing. | ||
| * By waiting until the end of parsing, we can safely change these | ||
| * values without affect any other part of the process. | ||
| */ | ||
| this[STATE].templateElements.forEach(templateElement => { | ||
| const startOffset = -1; | ||
| const endOffset = templateElement.tail ? 1 : 2; | ||
| parseTopLevel(node) { | ||
| if (this[STATE].impliedStrict) { | ||
| this.strict = true; | ||
| templateElement.start += startOffset; | ||
| templateElement.end += endOffset; | ||
| if (templateElement.range) { | ||
| templateElement.range[0] += startOffset; | ||
| templateElement.range[1] += endOffset; | ||
| } | ||
| if (templateElement.loc) { | ||
| templateElement.loc.start.column += startOffset; | ||
| templateElement.loc.end.column += endOffset; | ||
| } | ||
| }); | ||
| return program; | ||
| } | ||
| return super.parseTopLevel(node); | ||
| } | ||
| /** | ||
| * Overwrites the default raise method to throw Esprima-style errors. | ||
| * @param {int} pos The position of the error. | ||
| * @param {string} message The error message. | ||
| * @throws {SyntaxError} A syntax error. | ||
| * @returns {void} | ||
| */ | ||
| raise(pos, message) { | ||
| const loc = Parser.acorn.getLineInfo(this.input, pos); | ||
| const err = new SyntaxError(message); | ||
| /** | ||
| * Parses top level. | ||
| * @param {acorn.Node} node AST Node | ||
| * @returns {acorn.Node} The changed node | ||
| */ | ||
| parseTopLevel(node) { | ||
| if (this[STATE].impliedStrict) { | ||
| this.strict = true; | ||
| } | ||
| return super.parseTopLevel(node); | ||
| } | ||
| err.index = pos; | ||
| err.lineNumber = loc.line; | ||
| err.column = loc.column + 1; // acorn uses 0-based columns | ||
| throw err; | ||
| } | ||
| /** | ||
| * Overwrites the default raise method to throw Esprima-style errors. | ||
| * @param {number} pos The position of the error. | ||
| * @param {string} message The error message. | ||
| * @throws {EnhancedSyntaxError} A syntax error. | ||
| * @returns {void} | ||
| */ | ||
| raise(pos, message) { | ||
| const loc = Parser.acorn.getLineInfo(this.input, pos); | ||
| const err = /** @type {EnhancedSyntaxError} */ ( | ||
| new SyntaxError(message) | ||
| ); | ||
| /** | ||
| * Overwrites the default raise method to throw Esprima-style errors. | ||
| * @param {int} pos The position of the error. | ||
| * @param {string} message The error message. | ||
| * @throws {SyntaxError} A syntax error. | ||
| * @returns {void} | ||
| */ | ||
| raiseRecoverable(pos, message) { | ||
| this.raise(pos, message); | ||
| } | ||
| err.index = pos; | ||
| err.lineNumber = loc.line; | ||
| err.column = loc.column + 1; // acorn uses 0-based columns | ||
| throw err; | ||
| } | ||
| /** | ||
| * Overwrites the default unexpected method to throw Esprima-style errors. | ||
| * @param {int} pos The position of the error. | ||
| * @throws {SyntaxError} A syntax error. | ||
| * @returns {void} | ||
| */ | ||
| unexpected(pos) { | ||
| let message = "Unexpected token"; | ||
| /** | ||
| * Overwrites the default raise method to throw Esprima-style errors. | ||
| * @param {number} pos The position of the error. | ||
| * @param {string} message The error message. | ||
| * @throws {SyntaxError} A syntax error. | ||
| * @returns {void} | ||
| */ | ||
| raiseRecoverable(pos, message) { | ||
| this.raise(pos, message); | ||
| } | ||
| if (pos !== null && pos !== void 0) { | ||
| this.pos = pos; | ||
| /** | ||
| * Overwrites the default unexpected method to throw Esprima-style errors. | ||
| * @param {number} pos The position of the error. | ||
| * @throws {SyntaxError} A syntax error. | ||
| * @returns {void} | ||
| */ | ||
| unexpected(pos) { | ||
| let message = "Unexpected token"; | ||
| if (this.options.locations) { | ||
| while (this.pos < this.lineStart) { | ||
| this.lineStart = this.input.lastIndexOf("\n", this.lineStart - 2) + 1; | ||
| --this.curLine; | ||
| if (pos !== null && pos !== void 0) { | ||
| this.pos = pos; | ||
| if (this.options.locations) { | ||
| while (this.pos < this.lineStart) { | ||
| this.lineStart = this.input.lastIndexOf("\n", this.lineStart - 2) + 1; | ||
| --this.curLine; | ||
| } | ||
| } | ||
| this.nextToken(); | ||
| } | ||
| this.nextToken(); | ||
| if (this.end > this.start) { | ||
| message += ` ${this.input.slice(this.start, this.end)}`; | ||
| } | ||
| this.raise(this.start, message); | ||
| } | ||
| if (this.end > this.start) { | ||
| message += ` ${this.input.slice(this.start, this.end)}`; | ||
| /** | ||
| * Esprima-FB represents JSX strings as tokens called "JSXText", but Acorn-JSX | ||
| * uses regular tt.string without any distinction between this and regular JS | ||
| * strings. As such, we intercept an attempt to read a JSX string and set a flag | ||
| * on extra so that when tokens are converted, the next token will be switched | ||
| * to JSXText via onToken. | ||
| * @param {number} quote A character code | ||
| * @returns {void} | ||
| */ | ||
| jsx_readString(quote) { // eslint-disable-line camelcase -- required by API | ||
| const result = super.jsx_readString(quote); | ||
| if (this.type === tokTypes.string) { | ||
| this[STATE].jsxAttrValueToken = true; | ||
| } | ||
| return result; | ||
| } | ||
| this.raise(this.start, message); | ||
| } | ||
| /** | ||
| * Performs last-minute Esprima-specific compatibility checks and fixes. | ||
| * @param {acorn.Node} result The node to check. | ||
| * @returns {EsprimaNode} The finished node. | ||
| */ | ||
| [ESPRIMA_FINISH_NODE](result) { | ||
| /* | ||
| * Esprima-FB represents JSX strings as tokens called "JSXText", but Acorn-JSX | ||
| * uses regular tt.string without any distinction between this and regular JS | ||
| * strings. As such, we intercept an attempt to read a JSX string and set a flag | ||
| * on extra so that when tokens are converted, the next token will be switched | ||
| * to JSXText via onToken. | ||
| */ | ||
| jsx_readString(quote) { // eslint-disable-line camelcase -- required by API | ||
| const result = super.jsx_readString(quote); | ||
| // Acorn doesn't count the opening and closing backticks as part of templates | ||
| // so we have to adjust ranges/locations appropriately. | ||
| if (result.type === "TemplateElement") { | ||
| if (this.type === tokTypes.string) { | ||
| this[STATE].jsxAttrValueToken = true; | ||
| } | ||
| return result; | ||
| } | ||
| // save template element references to fix start/end later | ||
| this[STATE].templateElements.push( | ||
| /** | ||
| * Performs last-minute Esprima-specific compatibility checks and fixes. | ||
| * @param {ASTNode} result The node to check. | ||
| * @returns {ASTNode} The finished node. | ||
| */ | ||
| [ESPRIMA_FINISH_NODE](result) { | ||
| /** @type {acorn.TemplateElement} */ | ||
| (result) | ||
| ); | ||
| } | ||
| // Acorn doesn't count the opening and closing backticks as part of templates | ||
| // so we have to adjust ranges/locations appropriately. | ||
| if (result.type === "TemplateElement") { | ||
| if (result.type.includes("Function") && (!("generator" in result))) { | ||
| // save template element references to fix start/end later | ||
| this[STATE].templateElements.push(result); | ||
| } | ||
| /** | ||
| * @type {acorn.FunctionDeclaration|acorn.FunctionExpression| | ||
| * acorn.ArrowFunctionExpression} | ||
| */ | ||
| (result).generator = false; | ||
| } | ||
| if (result.type.includes("Function") && !result.generator) { | ||
| result.generator = false; | ||
| return result; | ||
| } | ||
| return result; | ||
| } | ||
| }; | ||
| }; | ||
| }; | ||
| const version$1 = "11.0.0"; | ||
| /** | ||
@@ -816,11 +1058,102 @@ * @fileoverview Main Espree file that converts Acorn into Esprima output. | ||
| /** | ||
| * @import { EspreeParserCtor, EspreeParserJsxCtor } from "./lib/types.js"; | ||
| */ | ||
| // ---------------------------------------------------------------------------- | ||
| // Types exported from file | ||
| // ---------------------------------------------------------------------------- | ||
| /** | ||
| * @typedef {3|5|6|7|8|9|10|11|12|13|14|15|16|17|2015|2016|2017|2018|2019|2020|2021|2022|2023|2024|2025|2026|'latest'} EcmaVersion | ||
| */ | ||
| /** | ||
| * @typedef {{ | ||
| * type: string; | ||
| * value: any; | ||
| * start?: number; | ||
| * end?: number; | ||
| * loc?: acorn.SourceLocation; | ||
| * range?: [number, number]; | ||
| * regex?: {flags: string, pattern: string}; | ||
| * }} EspreeToken | ||
| */ | ||
| /** | ||
| * @typedef {{ | ||
| * type: "Block" | "Hashbang" | "Line", | ||
| * value: string, | ||
| * range?: [number, number], | ||
| * start?: number, | ||
| * end?: number, | ||
| * loc?: { | ||
| * start: acorn.Position | undefined, | ||
| * end: acorn.Position | undefined | ||
| * } | ||
| * }} EspreeComment | ||
| */ | ||
| /** | ||
| * @typedef {{ | ||
| * comments?: EspreeComment[] | ||
| * } & EspreeToken[]} EspreeTokens | ||
| */ | ||
| /** | ||
| * `allowReserved` is as in `acorn.Options` | ||
| * | ||
| * `ecmaVersion` currently as in `acorn.Options` though optional | ||
| * | ||
| * `sourceType` as in `acorn.Options` but also allows `commonjs` | ||
| * | ||
| * `ecmaFeatures`, `range`, `loc`, `tokens` are not in `acorn.Options` | ||
| * | ||
| * `comment` is not in `acorn.Options` and doesn't err without it, but is used | ||
| */ | ||
| /** | ||
| * @typedef {{ | ||
| * allowReserved?: boolean, | ||
| * ecmaVersion?: EcmaVersion, | ||
| * sourceType?: "script"|"module"|"commonjs", | ||
| * ecmaFeatures?: { | ||
| * jsx?: boolean, | ||
| * globalReturn?: boolean, | ||
| * impliedStrict?: boolean | ||
| * }, | ||
| * range?: boolean, | ||
| * loc?: boolean, | ||
| * tokens?: boolean, | ||
| * comment?: boolean, | ||
| * }} Options | ||
| */ | ||
| // To initialize lazily. | ||
| const parsers = { | ||
| /** @type {EspreeParserCtor|null} */ | ||
| _regular: null, | ||
| /** @type {EspreeParserJsxCtor|null} */ | ||
| _jsx: null, | ||
| /** | ||
| * Returns regular Parser | ||
| * @returns {EspreeParserCtor} Regular Acorn parser | ||
| */ | ||
| get regular() { | ||
| if (this._regular === null) { | ||
| this._regular = acorn__namespace.Parser.extend(espree()); | ||
| const espreeParserFactory = /** @type {unknown} */ (espree()); | ||
| this._regular = /** @type {EspreeParserCtor} */ ( | ||
| // Without conversion, types are incompatible, as | ||
| // acorn's has a protected constructor | ||
| /** @type {unknown} */ | ||
| (acorn__namespace.Parser.extend( | ||
| /** | ||
| * @type {( | ||
| * BaseParser: typeof acorn.Parser | ||
| * ) => typeof acorn.Parser} | ||
| */ (espreeParserFactory) | ||
| )) | ||
| ); | ||
| } | ||
@@ -830,5 +1163,22 @@ return this._regular; | ||
| /** | ||
| * Returns JSX Parser | ||
| * @returns {EspreeParserJsxCtor} JSX Acorn parser | ||
| */ | ||
| get jsx() { | ||
| if (this._jsx === null) { | ||
| this._jsx = acorn__namespace.Parser.extend(jsx__default["default"](), espree()); | ||
| const espreeParserFactory = /** @type {unknown} */ (espree()); | ||
| const jsxFactory = jsx__default["default"](); | ||
| this._jsx = /** @type {EspreeParserJsxCtor} */ ( | ||
| // Without conversion, types are incompatible, as | ||
| // acorn's has a protected constructor | ||
| /** @type {unknown} */ | ||
| (acorn__namespace.Parser.extend( | ||
| jsxFactory, | ||
| /** @type {(BaseParser: typeof acorn.Parser) => typeof acorn.Parser} */ | ||
| (espreeParserFactory) | ||
| )) | ||
| ); | ||
| } | ||
@@ -838,2 +1188,7 @@ return this._jsx; | ||
| /** | ||
| * Gets the parser object based on the supplied options. | ||
| * @param {Options} [options] The parser options. | ||
| * @returns {EspreeParserJsxCtor|EspreeParserCtor} Regular or JSX Acorn parser | ||
| */ | ||
| get(options) { | ||
@@ -857,5 +1212,5 @@ const useJsx = Boolean( | ||
| * @param {string} code The code to tokenize. | ||
| * @param {Object} options Options defining how to tokenize. | ||
| * @returns {Token[]} An array of tokens. | ||
| * @throws {SyntaxError} If the input code is invalid. | ||
| * @param {Options} [options] Options defining how to tokenize. | ||
| * @returns {EspreeTokens} An array of tokens. | ||
| * @throws {EnhancedSyntaxError} If the input code is invalid. | ||
| * @private | ||
@@ -871,3 +1226,3 @@ */ | ||
| return new Parser(options, code).tokenize(); | ||
| return /** @type {EspreeTokens} */ (new Parser(options, code).tokenize()); | ||
| } | ||
@@ -882,5 +1237,5 @@ | ||
| * @param {string} code The code to tokenize. | ||
| * @param {Object} options Options defining how to tokenize. | ||
| * @returns {ASTNode} The "Program" AST node. | ||
| * @throws {SyntaxError} If the input code is invalid. | ||
| * @param {Options} [options] Options defining how to tokenize. | ||
| * @returns {acorn.Program} The "Program" AST node. | ||
| * @throws {EnhancedSyntaxError} If the input code is invalid. | ||
| */ | ||
@@ -897,6 +1252,10 @@ function parse(code, options) { | ||
| const version = version$1; | ||
| /** @type {string} */ | ||
| const version = "11.1.0"; // x-release-please-version | ||
| const name = "espree"; | ||
| /* istanbul ignore next */ | ||
| /** | ||
| * @type {visitorKeys.VisitorKeys} | ||
| */ | ||
| const VisitorKeys = (function() { | ||
@@ -910,2 +1269,4 @@ return visitorKeys__namespace.KEYS; | ||
| let key, | ||
| /** @type {Record<string,string>} */ | ||
| types = {}; | ||
@@ -912,0 +1273,0 @@ |
+129
-12
@@ -58,19 +58,108 @@ /** | ||
| import * as acorn from "acorn"; | ||
| import jsx from "acorn-jsx"; | ||
| import espree from "./lib/espree.js"; | ||
| import espreeVersion from "./lib/version.js"; | ||
| import * as visitorKeys from "eslint-visitor-keys"; | ||
| import { getLatestEcmaVersion, getSupportedEcmaVersions } from "./lib/options.js"; | ||
| /** | ||
| * @import { EspreeParserCtor, EspreeParserJsxCtor } from "./lib/types.js"; | ||
| */ | ||
| // ---------------------------------------------------------------------------- | ||
| // Types exported from file | ||
| // ---------------------------------------------------------------------------- | ||
| /** | ||
| * @typedef {3|5|6|7|8|9|10|11|12|13|14|15|16|17|2015|2016|2017|2018|2019|2020|2021|2022|2023|2024|2025|2026|'latest'} EcmaVersion | ||
| */ | ||
| /** | ||
| * @typedef {{ | ||
| * type: string; | ||
| * value: any; | ||
| * start?: number; | ||
| * end?: number; | ||
| * loc?: acorn.SourceLocation; | ||
| * range?: [number, number]; | ||
| * regex?: {flags: string, pattern: string}; | ||
| * }} EspreeToken | ||
| */ | ||
| /** | ||
| * @typedef {{ | ||
| * type: "Block" | "Hashbang" | "Line", | ||
| * value: string, | ||
| * range?: [number, number], | ||
| * start?: number, | ||
| * end?: number, | ||
| * loc?: { | ||
| * start: acorn.Position | undefined, | ||
| * end: acorn.Position | undefined | ||
| * } | ||
| * }} EspreeComment | ||
| */ | ||
| /** | ||
| * @typedef {{ | ||
| * comments?: EspreeComment[] | ||
| * } & EspreeToken[]} EspreeTokens | ||
| */ | ||
| /** | ||
| * `allowReserved` is as in `acorn.Options` | ||
| * | ||
| * `ecmaVersion` currently as in `acorn.Options` though optional | ||
| * | ||
| * `sourceType` as in `acorn.Options` but also allows `commonjs` | ||
| * | ||
| * `ecmaFeatures`, `range`, `loc`, `tokens` are not in `acorn.Options` | ||
| * | ||
| * `comment` is not in `acorn.Options` and doesn't err without it, but is used | ||
| */ | ||
| /** | ||
| * @typedef {{ | ||
| * allowReserved?: boolean, | ||
| * ecmaVersion?: EcmaVersion, | ||
| * sourceType?: "script"|"module"|"commonjs", | ||
| * ecmaFeatures?: { | ||
| * jsx?: boolean, | ||
| * globalReturn?: boolean, | ||
| * impliedStrict?: boolean | ||
| * }, | ||
| * range?: boolean, | ||
| * loc?: boolean, | ||
| * tokens?: boolean, | ||
| * comment?: boolean, | ||
| * }} Options | ||
| */ | ||
| // To initialize lazily. | ||
| const parsers = { | ||
| /** @type {EspreeParserCtor|null} */ | ||
| _regular: null, | ||
| /** @type {EspreeParserJsxCtor|null} */ | ||
| _jsx: null, | ||
| /** | ||
| * Returns regular Parser | ||
| * @returns {EspreeParserCtor} Regular Acorn parser | ||
| */ | ||
| get regular() { | ||
| if (this._regular === null) { | ||
| this._regular = acorn.Parser.extend(espree()); | ||
| const espreeParserFactory = /** @type {unknown} */ (espree()); | ||
| this._regular = /** @type {EspreeParserCtor} */ ( | ||
| // Without conversion, types are incompatible, as | ||
| // acorn's has a protected constructor | ||
| /** @type {unknown} */ | ||
| (acorn.Parser.extend( | ||
| /** | ||
| * @type {( | ||
| * BaseParser: typeof acorn.Parser | ||
| * ) => typeof acorn.Parser} | ||
| */ (espreeParserFactory) | ||
| )) | ||
| ); | ||
| } | ||
@@ -80,5 +169,22 @@ return this._regular; | ||
| /** | ||
| * Returns JSX Parser | ||
| * @returns {EspreeParserJsxCtor} JSX Acorn parser | ||
| */ | ||
| get jsx() { | ||
| if (this._jsx === null) { | ||
| this._jsx = acorn.Parser.extend(jsx(), espree()); | ||
| const espreeParserFactory = /** @type {unknown} */ (espree()); | ||
| const jsxFactory = jsx(); | ||
| this._jsx = /** @type {EspreeParserJsxCtor} */ ( | ||
| // Without conversion, types are incompatible, as | ||
| // acorn's has a protected constructor | ||
| /** @type {unknown} */ | ||
| (acorn.Parser.extend( | ||
| jsxFactory, | ||
| /** @type {(BaseParser: typeof acorn.Parser) => typeof acorn.Parser} */ | ||
| (espreeParserFactory) | ||
| )) | ||
| ); | ||
| } | ||
@@ -88,2 +194,7 @@ return this._jsx; | ||
| /** | ||
| * Gets the parser object based on the supplied options. | ||
| * @param {Options} [options] The parser options. | ||
| * @returns {EspreeParserJsxCtor|EspreeParserCtor} Regular or JSX Acorn parser | ||
| */ | ||
| get(options) { | ||
@@ -107,5 +218,5 @@ const useJsx = Boolean( | ||
| * @param {string} code The code to tokenize. | ||
| * @param {Object} options Options defining how to tokenize. | ||
| * @returns {Token[]} An array of tokens. | ||
| * @throws {SyntaxError} If the input code is invalid. | ||
| * @param {Options} [options] Options defining how to tokenize. | ||
| * @returns {EspreeTokens} An array of tokens. | ||
| * @throws {EnhancedSyntaxError} If the input code is invalid. | ||
| * @private | ||
@@ -121,3 +232,3 @@ */ | ||
| return new Parser(options, code).tokenize(); | ||
| return /** @type {EspreeTokens} */ (new Parser(options, code).tokenize()); | ||
| } | ||
@@ -132,5 +243,5 @@ | ||
| * @param {string} code The code to tokenize. | ||
| * @param {Object} options Options defining how to tokenize. | ||
| * @returns {ASTNode} The "Program" AST node. | ||
| * @throws {SyntaxError} If the input code is invalid. | ||
| * @param {Options} [options] Options defining how to tokenize. | ||
| * @returns {acorn.Program} The "Program" AST node. | ||
| * @throws {EnhancedSyntaxError} If the input code is invalid. | ||
| */ | ||
@@ -147,6 +258,10 @@ export function parse(code, options) { | ||
| export const version = espreeVersion; | ||
| /** @type {string} */ | ||
| export const version = "11.1.0"; // x-release-please-version | ||
| export const name = "espree"; | ||
| /* istanbul ignore next */ | ||
| /** | ||
| * @type {visitorKeys.VisitorKeys} | ||
| */ | ||
| export const VisitorKeys = (function() { | ||
@@ -160,2 +275,4 @@ return visitorKeys.KEYS; | ||
| let key, | ||
| /** @type {Record<string,string>} */ | ||
| types = {}; | ||
@@ -162,0 +279,0 @@ |
+375
-213
@@ -6,3 +6,61 @@ /* eslint no-param-reassign: 0 -- stylistic choice */ | ||
| /** | ||
| * @import { | ||
| * CommentType, | ||
| * EspreeParserCtor, | ||
| * EsprimaNode, | ||
| * AcornJsxParserCtorEnhanced, | ||
| * TokTypes | ||
| * } from "./types.js"; | ||
| * @import { | ||
| * Options, | ||
| * EspreeToken as EsprimaToken, | ||
| * EspreeTokens as EsprimaTokens, | ||
| * EspreeComment as EsprimaComment | ||
| * } from "../espree.js"; | ||
| * @import { NormalizedEcmaVersion } from "./options.js"; | ||
| * @import * as acorn from "acorn"; | ||
| */ | ||
| /** | ||
| * @typedef {{ | ||
| * originalSourceType: "script" | "module" | "commonjs" | undefined | ||
| * tokens: EsprimaToken[] | null, | ||
| * comments: EsprimaComment[] | null, | ||
| * impliedStrict: boolean, | ||
| * ecmaVersion: NormalizedEcmaVersion, | ||
| * jsxAttrValueToken: boolean, | ||
| * lastToken: acorn.Token | null, | ||
| * templateElements: acorn.TemplateElement[] | ||
| * }} State | ||
| */ | ||
| /** | ||
| * @typedef {{ | ||
| * sourceType?: "script"|"module"|"commonjs"; | ||
| * comments?: EsprimaComment[]; | ||
| * tokens?: EsprimaToken[]; | ||
| * body: acorn.Node[]; | ||
| * } & acorn.Program} EsprimaProgramNode | ||
| */ | ||
| // ---------------------------------------------------------------------------- | ||
| // Types exported from file | ||
| // ---------------------------------------------------------------------------- | ||
| /** | ||
| * @typedef {{ | ||
| * index?: number; | ||
| * lineNumber?: number; | ||
| * column?: number; | ||
| * } & SyntaxError} EnhancedSyntaxError | ||
| */ | ||
| // We add `jsxAttrValueToken` ourselves. | ||
| /** | ||
| * @typedef {{ | ||
| * jsxAttrValueToken?: acorn.TokenType; | ||
| * } & TokTypes} EnhancedTokTypes | ||
| */ | ||
| const STATE = Symbol("espree's internal state"); | ||
@@ -16,11 +74,13 @@ const ESPRIMA_FINISH_NODE = Symbol("espree's esprimaFinishNode"); | ||
| * @param {string} text The text of the comment. | ||
| * @param {int} start The index at which the comment starts. | ||
| * @param {int} end The index at which the comment ends. | ||
| * @param {Location} startLoc The location at which the comment starts. | ||
| * @param {Location} endLoc The location at which the comment ends. | ||
| * @param {number} start The index at which the comment starts. | ||
| * @param {number} end The index at which the comment ends. | ||
| * @param {acorn.Position | undefined} startLoc The location at which the comment starts. | ||
| * @param {acorn.Position | undefined} endLoc The location at which the comment ends. | ||
| * @param {string} code The source code being parsed. | ||
| * @returns {Object} The comment object. | ||
| * @returns {EsprimaComment} The comment object. | ||
| * @private | ||
| */ | ||
| function convertAcornCommentToEsprimaComment(block, text, start, end, startLoc, endLoc, code) { | ||
| /** @type {CommentType} */ | ||
| let type; | ||
@@ -36,2 +96,15 @@ | ||
| /** | ||
| * @type {{ | ||
| * type: CommentType, | ||
| * value: string, | ||
| * start?: number, | ||
| * end?: number, | ||
| * range?: [number, number], | ||
| * loc?: { | ||
| * start: acorn.Position | undefined, | ||
| * end: acorn.Position | undefined | ||
| * } | ||
| * }} | ||
| */ | ||
| const comment = { | ||
@@ -58,267 +131,356 @@ type, | ||
| export default () => Parser => { | ||
| const tokTypes = Object.assign({}, Parser.acorn.tokTypes); | ||
| // eslint-disable-next-line arrow-body-style -- For TS | ||
| export default () => { | ||
| if (Parser.acornJsx) { | ||
| Object.assign(tokTypes, Parser.acornJsx.tokTypes); | ||
| } | ||
| /** | ||
| * Returns the Espree parser. | ||
| * @param {AcornJsxParserCtorEnhanced} Parser The Acorn parser. The `acorn` property is missing from acorn's | ||
| * TypeScript but is present statically on the class. | ||
| * @returns {EspreeParserCtor} The Espree Parser constructor. | ||
| */ | ||
| return Parser => { | ||
| const tokTypes = /** @type {EnhancedTokTypes} */ ( | ||
| Object.assign({}, Parser.acorn.tokTypes) | ||
| ); | ||
| return class Espree extends Parser { | ||
| constructor(opts, code) { | ||
| if (typeof opts !== "object" || opts === null) { | ||
| opts = {}; | ||
| } | ||
| if (typeof code !== "string" && !(code instanceof String)) { | ||
| code = String(code); | ||
| } | ||
| if (Parser.acornJsx) { | ||
| Object.assign(tokTypes, Parser.acornJsx.tokTypes); | ||
| } | ||
| // save original source type in case of commonjs | ||
| const originalSourceType = opts.sourceType; | ||
| const options = normalizeOptions(opts); | ||
| const ecmaFeatures = options.ecmaFeatures || {}; | ||
| const tokenTranslator = | ||
| options.tokens === true | ||
| ? new TokenTranslator(tokTypes, code) | ||
| : null; | ||
| return class Espree extends Parser { | ||
| /* | ||
| * Data that is unique to Espree and is not represented internally | ||
| * in Acorn. | ||
| * | ||
| * For ES2023 hashbangs, Espree will call `onComment()` during the | ||
| * constructor, so we must define state before having access to | ||
| * `this`. | ||
| /** | ||
| * @param {Options | null | undefined} opts The parser options | ||
| * @param {string | object} code The code which will be converted to a string. | ||
| */ | ||
| const state = { | ||
| originalSourceType: originalSourceType || options.sourceType, | ||
| tokens: tokenTranslator ? [] : null, | ||
| comments: options.comment === true ? [] : null, | ||
| impliedStrict: ecmaFeatures.impliedStrict === true && options.ecmaVersion >= 5, | ||
| ecmaVersion: options.ecmaVersion, | ||
| jsxAttrValueToken: false, | ||
| lastToken: null, | ||
| templateElements: [] | ||
| }; | ||
| constructor(opts, code) { | ||
| if (typeof opts !== "object" || opts === null) { | ||
| opts = {}; | ||
| } | ||
| if (typeof code !== "string" && !(code instanceof String)) { | ||
| code = String(code); | ||
| } | ||
| // Initialize acorn parser. | ||
| super({ | ||
| // save original source type in case of commonjs | ||
| const originalSourceType = opts.sourceType; | ||
| const options = normalizeOptions(opts); | ||
| const ecmaFeatures = options.ecmaFeatures || {}; | ||
| const tokenTranslator = | ||
| options.tokens === true | ||
| ? new TokenTranslator( | ||
| tokTypes, | ||
| // do not use spread, because we don't want to pass any unknown options to acorn | ||
| ecmaVersion: options.ecmaVersion, | ||
| sourceType: options.sourceType, | ||
| ranges: options.ranges, | ||
| locations: options.locations, | ||
| allowReserved: options.allowReserved, | ||
| // @ts-expect-error Appears to be a TS bug since the type is indeed string|String | ||
| code | ||
| ) | ||
| : null; | ||
| // Truthy value is true for backward compatibility. | ||
| allowReturnOutsideFunction: options.allowReturnOutsideFunction, | ||
| /** | ||
| * Data that is unique to Espree and is not represented internally | ||
| * in Acorn. | ||
| * | ||
| * For ES2023 hashbangs, Espree will call `onComment()` during the | ||
| * constructor, so we must define state before having access to | ||
| * `this`. | ||
| * @type {State} | ||
| */ | ||
| const state = { | ||
| originalSourceType: originalSourceType || options.sourceType, | ||
| tokens: tokenTranslator ? [] : null, | ||
| comments: options.comment === true ? [] : null, | ||
| impliedStrict: ecmaFeatures.impliedStrict === true && options.ecmaVersion >= 5, | ||
| ecmaVersion: options.ecmaVersion, | ||
| jsxAttrValueToken: false, | ||
| lastToken: null, | ||
| templateElements: [] | ||
| }; | ||
| // Collect tokens | ||
| onToken(token) { | ||
| if (tokenTranslator) { | ||
| // Initialize acorn parser. | ||
| super({ | ||
| // Use `tokens`, `ecmaVersion`, and `jsxAttrValueToken` in the state. | ||
| tokenTranslator.onToken(token, state); | ||
| } | ||
| if (token.type !== tokTypes.eof) { | ||
| state.lastToken = token; | ||
| } | ||
| }, | ||
| // do not use spread, because we don't want to pass any unknown options to acorn | ||
| ecmaVersion: options.ecmaVersion, | ||
| sourceType: options.sourceType, | ||
| ranges: options.ranges, | ||
| locations: options.locations, | ||
| allowReserved: options.allowReserved, | ||
| // Collect comments | ||
| onComment(block, text, start, end, startLoc, endLoc) { | ||
| if (state.comments) { | ||
| const comment = convertAcornCommentToEsprimaComment(block, text, start, end, startLoc, endLoc, code); | ||
| // Truthy value is true for backward compatibility. | ||
| allowReturnOutsideFunction: options.allowReturnOutsideFunction, | ||
| state.comments.push(comment); | ||
| } | ||
| } | ||
| }, code); | ||
| // Collect tokens | ||
| onToken(token) { | ||
| if (tokenTranslator) { | ||
| /* | ||
| * We put all of this data into a symbol property as a way to avoid | ||
| * potential naming conflicts with future versions of Acorn. | ||
| */ | ||
| this[STATE] = state; | ||
| } | ||
| // Use `tokens`, `ecmaVersion`, and `jsxAttrValueToken` in the state. | ||
| tokenTranslator.onToken( | ||
| token, | ||
| tokenize() { | ||
| do { | ||
| this.next(); | ||
| } while (this.type !== tokTypes.eof); | ||
| /** | ||
| * @type {Omit<State, "tokens"> & { | ||
| * tokens: EsprimaToken[] | ||
| * }} | ||
| */ | ||
| (state) | ||
| ); | ||
| } | ||
| if (token.type !== tokTypes.eof) { | ||
| state.lastToken = token; | ||
| } | ||
| }, | ||
| // Consume the final eof token | ||
| this.next(); | ||
| // Collect comments | ||
| onComment(block, text, start, end, startLoc, endLoc) { | ||
| if (state.comments) { | ||
| const comment = convertAcornCommentToEsprimaComment( | ||
| block, | ||
| text, | ||
| start, | ||
| end, | ||
| startLoc, | ||
| endLoc, | ||
| const extra = this[STATE]; | ||
| const tokens = extra.tokens; | ||
| // @ts-expect-error Appears to be a TS bug | ||
| // since the type is indeed string|String | ||
| code | ||
| ); | ||
| if (extra.comments) { | ||
| tokens.comments = extra.comments; | ||
| state.comments.push(comment); | ||
| } | ||
| } | ||
| // @ts-expect-error Appears to be a TS bug | ||
| // since the type is indeed string|String | ||
| }, code); | ||
| /* | ||
| * We put all of this data into a symbol property as a way to avoid | ||
| * potential naming conflicts with future versions of Acorn. | ||
| */ | ||
| this[STATE] = state; | ||
| } | ||
| return tokens; | ||
| } | ||
| /** | ||
| * Returns Espree tokens. | ||
| * @returns {EsprimaTokens} The Esprima-compatible tokens | ||
| */ | ||
| tokenize() { | ||
| do { | ||
| this.next(); | ||
| } while (this.type !== tokTypes.eof); | ||
| finishNode(...args) { | ||
| const result = super.finishNode(...args); | ||
| // Consume the final eof token | ||
| this.next(); | ||
| return this[ESPRIMA_FINISH_NODE](result); | ||
| } | ||
| const extra = this[STATE]; | ||
| const tokens = /** @type {EsprimaTokens} */ (extra.tokens); | ||
| finishNodeAt(...args) { | ||
| const result = super.finishNodeAt(...args); | ||
| if (extra.comments) { | ||
| tokens.comments = extra.comments; | ||
| } | ||
| return this[ESPRIMA_FINISH_NODE](result); | ||
| } | ||
| return tokens; | ||
| } | ||
| parse() { | ||
| const extra = this[STATE]; | ||
| const program = super.parse(); | ||
| /** | ||
| * Calls parent. | ||
| * @param {acorn.Node} node The node | ||
| * @param {string} type The type | ||
| * @returns {acorn.Node} The altered Node | ||
| */ | ||
| finishNode(node, type) { | ||
| const result = super.finishNode(node, type); | ||
| program.sourceType = extra.originalSourceType; | ||
| return this[ESPRIMA_FINISH_NODE](result); | ||
| } | ||
| if (extra.comments) { | ||
| program.comments = extra.comments; | ||
| /** | ||
| * Calls parent. | ||
| * @param {acorn.Node} node The node | ||
| * @param {string} type The type | ||
| * @param {number} pos The position | ||
| * @param {acorn.Position} loc The location | ||
| * @returns {acorn.Node} The altered Node | ||
| */ | ||
| finishNodeAt(node, type, pos, loc) { | ||
| const result = super.finishNodeAt(node, type, pos, loc); | ||
| return this[ESPRIMA_FINISH_NODE](result); | ||
| } | ||
| if (extra.tokens) { | ||
| program.tokens = extra.tokens; | ||
| } | ||
| /* | ||
| * https://github.com/eslint/espree/issues/349 | ||
| * Ensure that template elements have correct range information. | ||
| * This is one location where Acorn produces a different value | ||
| * for its start and end properties vs. the values present in the | ||
| * range property. In order to avoid confusion, we set the start | ||
| * and end properties to the values that are present in range. | ||
| * This is done here, instead of in finishNode(), because Acorn | ||
| * uses the values of start and end internally while parsing, making | ||
| * it dangerous to change those values while parsing is ongoing. | ||
| * By waiting until the end of parsing, we can safely change these | ||
| * values without affect any other part of the process. | ||
| /** | ||
| * Parses. | ||
| * @returns {EsprimaProgramNode} The program Node | ||
| */ | ||
| this[STATE].templateElements.forEach(templateElement => { | ||
| const startOffset = -1; | ||
| const endOffset = templateElement.tail ? 1 : 2; | ||
| parse() { | ||
| const extra = this[STATE]; | ||
| const prog = super.parse(); | ||
| templateElement.start += startOffset; | ||
| templateElement.end += endOffset; | ||
| const program = /** @type {EsprimaProgramNode} */ (prog); | ||
| if (templateElement.range) { | ||
| templateElement.range[0] += startOffset; | ||
| templateElement.range[1] += endOffset; | ||
| } | ||
| // @ts-expect-error TS bug? We've already converted to `EsprimaProgramNode` | ||
| program.sourceType = extra.originalSourceType; | ||
| if (templateElement.loc) { | ||
| templateElement.loc.start.column += startOffset; | ||
| templateElement.loc.end.column += endOffset; | ||
| if (extra.comments) { | ||
| program.comments = extra.comments; | ||
| } | ||
| }); | ||
| if (extra.tokens) { | ||
| program.tokens = extra.tokens; | ||
| } | ||
| return program; | ||
| } | ||
| /* | ||
| * https://github.com/eslint/espree/issues/349 | ||
| * Ensure that template elements have correct range information. | ||
| * This is one location where Acorn produces a different value | ||
| * for its start and end properties vs. the values present in the | ||
| * range property. In order to avoid confusion, we set the start | ||
| * and end properties to the values that are present in range. | ||
| * This is done here, instead of in finishNode(), because Acorn | ||
| * uses the values of start and end internally while parsing, making | ||
| * it dangerous to change those values while parsing is ongoing. | ||
| * By waiting until the end of parsing, we can safely change these | ||
| * values without affect any other part of the process. | ||
| */ | ||
| this[STATE].templateElements.forEach(templateElement => { | ||
| const startOffset = -1; | ||
| const endOffset = templateElement.tail ? 1 : 2; | ||
| parseTopLevel(node) { | ||
| if (this[STATE].impliedStrict) { | ||
| this.strict = true; | ||
| templateElement.start += startOffset; | ||
| templateElement.end += endOffset; | ||
| if (templateElement.range) { | ||
| templateElement.range[0] += startOffset; | ||
| templateElement.range[1] += endOffset; | ||
| } | ||
| if (templateElement.loc) { | ||
| templateElement.loc.start.column += startOffset; | ||
| templateElement.loc.end.column += endOffset; | ||
| } | ||
| }); | ||
| return program; | ||
| } | ||
| return super.parseTopLevel(node); | ||
| } | ||
| /** | ||
| * Overwrites the default raise method to throw Esprima-style errors. | ||
| * @param {int} pos The position of the error. | ||
| * @param {string} message The error message. | ||
| * @throws {SyntaxError} A syntax error. | ||
| * @returns {void} | ||
| */ | ||
| raise(pos, message) { | ||
| const loc = Parser.acorn.getLineInfo(this.input, pos); | ||
| const err = new SyntaxError(message); | ||
| /** | ||
| * Parses top level. | ||
| * @param {acorn.Node} node AST Node | ||
| * @returns {acorn.Node} The changed node | ||
| */ | ||
| parseTopLevel(node) { | ||
| if (this[STATE].impliedStrict) { | ||
| this.strict = true; | ||
| } | ||
| return super.parseTopLevel(node); | ||
| } | ||
| err.index = pos; | ||
| err.lineNumber = loc.line; | ||
| err.column = loc.column + 1; // acorn uses 0-based columns | ||
| throw err; | ||
| } | ||
| /** | ||
| * Overwrites the default raise method to throw Esprima-style errors. | ||
| * @param {number} pos The position of the error. | ||
| * @param {string} message The error message. | ||
| * @throws {EnhancedSyntaxError} A syntax error. | ||
| * @returns {void} | ||
| */ | ||
| raise(pos, message) { | ||
| const loc = Parser.acorn.getLineInfo(this.input, pos); | ||
| const err = /** @type {EnhancedSyntaxError} */ ( | ||
| new SyntaxError(message) | ||
| ); | ||
| /** | ||
| * Overwrites the default raise method to throw Esprima-style errors. | ||
| * @param {int} pos The position of the error. | ||
| * @param {string} message The error message. | ||
| * @throws {SyntaxError} A syntax error. | ||
| * @returns {void} | ||
| */ | ||
| raiseRecoverable(pos, message) { | ||
| this.raise(pos, message); | ||
| } | ||
| err.index = pos; | ||
| err.lineNumber = loc.line; | ||
| err.column = loc.column + 1; // acorn uses 0-based columns | ||
| throw err; | ||
| } | ||
| /** | ||
| * Overwrites the default unexpected method to throw Esprima-style errors. | ||
| * @param {int} pos The position of the error. | ||
| * @throws {SyntaxError} A syntax error. | ||
| * @returns {void} | ||
| */ | ||
| unexpected(pos) { | ||
| let message = "Unexpected token"; | ||
| /** | ||
| * Overwrites the default raise method to throw Esprima-style errors. | ||
| * @param {number} pos The position of the error. | ||
| * @param {string} message The error message. | ||
| * @throws {SyntaxError} A syntax error. | ||
| * @returns {void} | ||
| */ | ||
| raiseRecoverable(pos, message) { | ||
| this.raise(pos, message); | ||
| } | ||
| if (pos !== null && pos !== void 0) { | ||
| this.pos = pos; | ||
| /** | ||
| * Overwrites the default unexpected method to throw Esprima-style errors. | ||
| * @param {number} pos The position of the error. | ||
| * @throws {SyntaxError} A syntax error. | ||
| * @returns {void} | ||
| */ | ||
| unexpected(pos) { | ||
| let message = "Unexpected token"; | ||
| if (this.options.locations) { | ||
| while (this.pos < this.lineStart) { | ||
| this.lineStart = this.input.lastIndexOf("\n", this.lineStart - 2) + 1; | ||
| --this.curLine; | ||
| if (pos !== null && pos !== void 0) { | ||
| this.pos = pos; | ||
| if (this.options.locations) { | ||
| while (this.pos < this.lineStart) { | ||
| this.lineStart = this.input.lastIndexOf("\n", this.lineStart - 2) + 1; | ||
| --this.curLine; | ||
| } | ||
| } | ||
| this.nextToken(); | ||
| } | ||
| this.nextToken(); | ||
| if (this.end > this.start) { | ||
| message += ` ${this.input.slice(this.start, this.end)}`; | ||
| } | ||
| this.raise(this.start, message); | ||
| } | ||
| if (this.end > this.start) { | ||
| message += ` ${this.input.slice(this.start, this.end)}`; | ||
| /** | ||
| * Esprima-FB represents JSX strings as tokens called "JSXText", but Acorn-JSX | ||
| * uses regular tt.string without any distinction between this and regular JS | ||
| * strings. As such, we intercept an attempt to read a JSX string and set a flag | ||
| * on extra so that when tokens are converted, the next token will be switched | ||
| * to JSXText via onToken. | ||
| * @param {number} quote A character code | ||
| * @returns {void} | ||
| */ | ||
| jsx_readString(quote) { // eslint-disable-line camelcase -- required by API | ||
| const result = super.jsx_readString(quote); | ||
| if (this.type === tokTypes.string) { | ||
| this[STATE].jsxAttrValueToken = true; | ||
| } | ||
| return result; | ||
| } | ||
| this.raise(this.start, message); | ||
| } | ||
| /** | ||
| * Performs last-minute Esprima-specific compatibility checks and fixes. | ||
| * @param {acorn.Node} result The node to check. | ||
| * @returns {EsprimaNode} The finished node. | ||
| */ | ||
| [ESPRIMA_FINISH_NODE](result) { | ||
| /* | ||
| * Esprima-FB represents JSX strings as tokens called "JSXText", but Acorn-JSX | ||
| * uses regular tt.string without any distinction between this and regular JS | ||
| * strings. As such, we intercept an attempt to read a JSX string and set a flag | ||
| * on extra so that when tokens are converted, the next token will be switched | ||
| * to JSXText via onToken. | ||
| */ | ||
| jsx_readString(quote) { // eslint-disable-line camelcase -- required by API | ||
| const result = super.jsx_readString(quote); | ||
| // Acorn doesn't count the opening and closing backticks as part of templates | ||
| // so we have to adjust ranges/locations appropriately. | ||
| if (result.type === "TemplateElement") { | ||
| if (this.type === tokTypes.string) { | ||
| this[STATE].jsxAttrValueToken = true; | ||
| } | ||
| return result; | ||
| } | ||
| // save template element references to fix start/end later | ||
| this[STATE].templateElements.push( | ||
| /** | ||
| * Performs last-minute Esprima-specific compatibility checks and fixes. | ||
| * @param {ASTNode} result The node to check. | ||
| * @returns {ASTNode} The finished node. | ||
| */ | ||
| [ESPRIMA_FINISH_NODE](result) { | ||
| /** @type {acorn.TemplateElement} */ | ||
| (result) | ||
| ); | ||
| } | ||
| // Acorn doesn't count the opening and closing backticks as part of templates | ||
| // so we have to adjust ranges/locations appropriately. | ||
| if (result.type === "TemplateElement") { | ||
| if (result.type.includes("Function") && (!("generator" in result))) { | ||
| // save template element references to fix start/end later | ||
| this[STATE].templateElements.push(result); | ||
| } | ||
| /** | ||
| * @type {acorn.FunctionDeclaration|acorn.FunctionExpression| | ||
| * acorn.ArrowFunctionExpression} | ||
| */ | ||
| (result).generator = false; | ||
| } | ||
| if (result.type.includes("Function") && !result.generator) { | ||
| result.generator = false; | ||
| return result; | ||
| } | ||
| return result; | ||
| } | ||
| }; | ||
| }; | ||
| }; |
+0
-6
@@ -8,8 +8,2 @@ /** | ||
| //------------------------------------------------------------------------------ | ||
| // Requirements | ||
| //------------------------------------------------------------------------------ | ||
| // None! | ||
| //------------------------------------------------------------------------------ | ||
| // Public | ||
@@ -16,0 +10,0 @@ //------------------------------------------------------------------------------ |
+51
-12
@@ -6,2 +6,6 @@ /** | ||
| /** | ||
| * @import { EcmaVersion, Options } from "../espree.js"; | ||
| */ | ||
| //------------------------------------------------------------------------------ | ||
@@ -11,3 +15,3 @@ // Helpers | ||
| const SUPPORTED_VERSIONS = [ | ||
| const SUPPORTED_VERSIONS = /** @type {const} */ ([ | ||
| 3, | ||
@@ -27,10 +31,21 @@ 5, | ||
| 17 // 2026 | ||
| ]; | ||
| ]); | ||
| /** | ||
| * @typedef {typeof SUPPORTED_VERSIONS[number]} NormalizedEcmaVersion | ||
| */ | ||
| const LATEST_ECMA_VERSION = | ||
| /* eslint-disable jsdoc/valid-types -- Bug */ | ||
| /** @type {typeof SUPPORTED_VERSIONS extends readonly [...unknown[], infer L] ? L : never} */ ( | ||
| SUPPORTED_VERSIONS.at(-1) | ||
| /* eslint-enable jsdoc/valid-types -- Bug */ | ||
| ); | ||
| /** | ||
| * Get the latest ECMAScript version supported by Espree. | ||
| * @returns {number} The latest ECMAScript version. | ||
| * @returns {typeof LATEST_ECMA_VERSION} The latest ECMAScript version. | ||
| */ | ||
| export function getLatestEcmaVersion() { | ||
| return SUPPORTED_VERSIONS.at(-1); | ||
| return LATEST_ECMA_VERSION; | ||
| } | ||
@@ -40,3 +55,3 @@ | ||
| * Get the list of ECMAScript versions supported by Espree. | ||
| * @returns {number[]} An array containing the supported ECMAScript versions. | ||
| * @returns {[...typeof SUPPORTED_VERSIONS]} An array containing the supported ECMAScript versions. | ||
| */ | ||
@@ -49,5 +64,5 @@ export function getSupportedEcmaVersions() { | ||
| * Normalize ECMAScript version from the initial config | ||
| * @param {(number|"latest")} ecmaVersion ECMAScript version from the initial config | ||
| * @param {EcmaVersion} ecmaVersion ECMAScript version from the initial config | ||
| * @throws {Error} throws an error if the ecmaVersion is invalid. | ||
| * @returns {number} normalized ECMAScript version | ||
| * @returns {NormalizedEcmaVersion} normalized ECMAScript version | ||
| */ | ||
@@ -68,7 +83,11 @@ function normalizeEcmaVersion(ecmaVersion = 5) { | ||
| if (!SUPPORTED_VERSIONS.includes(version)) { | ||
| if (!SUPPORTED_VERSIONS.includes( | ||
| /** @type {NormalizedEcmaVersion} */ | ||
| (version) | ||
| )) { | ||
| throw new Error("Invalid ecmaVersion."); | ||
| } | ||
| return version; | ||
| return /** @type {NormalizedEcmaVersion} */ (version); | ||
| } | ||
@@ -80,3 +99,3 @@ | ||
| * @throws {Error} throw an error if sourceType is invalid | ||
| * @returns {string} normalized sourceType | ||
| * @returns {"script"|"module"} normalized sourceType | ||
| */ | ||
@@ -96,6 +115,26 @@ function normalizeSourceType(sourceType = "script") { | ||
| /** | ||
| * @typedef {{ | ||
| * ecmaVersion: NormalizedEcmaVersion, | ||
| * sourceType: "script"|"module", | ||
| * range?: boolean, | ||
| * loc?: boolean, | ||
| * allowReserved: boolean | "never", | ||
| * ecmaFeatures?: { | ||
| * jsx?: boolean, | ||
| * globalReturn?: boolean, | ||
| * impliedStrict?: boolean | ||
| * }, | ||
| * ranges: boolean, | ||
| * locations: boolean, | ||
| * allowReturnOutsideFunction: boolean, | ||
| * tokens?: boolean, | ||
| * comment?: boolean | ||
| * }} NormalizedParserOptions | ||
| */ | ||
| /** | ||
| * Normalize parserOptions | ||
| * @param {Object} options the parser options to normalize | ||
| * @param {Options} options the parser options to normalize | ||
| * @throws {Error} throw an error if found invalid option. | ||
| * @returns {Object} normalized options | ||
| * @returns {NormalizedParserOptions} normalized options | ||
| */ | ||
@@ -102,0 +141,0 @@ export function normalizeOptions(options) { |
+99
-56
@@ -6,8 +6,32 @@ /** | ||
| //------------------------------------------------------------------------------ | ||
| // Requirements | ||
| //------------------------------------------------------------------------------ | ||
| /** | ||
| * @import * as acorn from "acorn"; | ||
| * @import { EnhancedTokTypes } from "./espree.js" | ||
| * @import { NormalizedEcmaVersion } from "./options.js"; | ||
| * @import { EspreeToken as EsprimaToken } from "../espree.js"; | ||
| */ | ||
| /** | ||
| * Based on the `acorn.Token` class, but without a fixed `type` (since we need | ||
| * it to be a string). Avoiding `type` lets us make one extending interface | ||
| * more strict and another more lax. | ||
| * | ||
| * We could make `value` more strict to `string` even though the original is | ||
| * `any`. | ||
| * | ||
| * `start` and `end` are required in `acorn.Token` | ||
| * | ||
| * `loc` and `range` are from `acorn.Token` | ||
| * | ||
| * Adds `regex`. | ||
| */ | ||
| /** | ||
| * @typedef {{ | ||
| * jsxAttrValueToken: boolean; | ||
| * ecmaVersion: NormalizedEcmaVersion; | ||
| * }} ExtraNoTokens | ||
| * @typedef {{ | ||
| * tokens: EsprimaToken[] | ||
| * } & ExtraNoTokens} Extra | ||
| */ | ||
| // none! | ||
| //------------------------------------------------------------------------------ | ||
@@ -17,3 +41,2 @@ // Private | ||
| // Esprima Token Types | ||
@@ -38,3 +61,3 @@ const Token = { | ||
| * Converts part of a template into an Esprima token. | ||
| * @param {AcornToken[]} tokens The Acorn tokens representing the template. | ||
| * @param {acorn.Token[]} tokens The Acorn tokens representing the template. | ||
| * @param {string} code The source code. | ||
@@ -46,4 +69,11 @@ * @returns {EsprimaToken} The Esprima equivalent of the template token. | ||
| const firstToken = tokens[0], | ||
| lastTemplateToken = tokens.at(-1); | ||
| lastTemplateToken = | ||
| /** | ||
| * @type {acorn.Token & { | ||
| * loc: acorn.SourceLocation, | ||
| * range: [number, number] | ||
| * }} | ||
| */ (tokens.at(-1)); | ||
| /** @type {EsprimaToken} */ | ||
| const token = { | ||
@@ -70,27 +100,31 @@ type: Token.Template, | ||
| /* eslint-disable jsdoc/check-types -- The API allows either */ | ||
| /** | ||
| * Contains logic to translate Acorn tokens into Esprima tokens. | ||
| * @param {Object} acornTokTypes The Acorn token types. | ||
| * @param {string} code The source code Acorn is parsing. This is necessary | ||
| * to correct the "value" property of some tokens. | ||
| * @constructor | ||
| */ | ||
| function TokenTranslator(acornTokTypes, code) { | ||
| class TokenTranslator { | ||
| // token types | ||
| this._acornTokTypes = acornTokTypes; | ||
| /** | ||
| * Contains logic to translate Acorn tokens into Esprima tokens. | ||
| * @param {EnhancedTokTypes} acornTokTypes The Acorn token types. | ||
| * @param {string|String} code The source code Acorn is parsing. This is necessary | ||
| * to correct the "value" property of some tokens. | ||
| */ | ||
| constructor(acornTokTypes, code) { | ||
| /* eslint-enable jsdoc/check-types -- The API allows either */ | ||
| // token buffer for templates | ||
| this._tokens = []; | ||
| // token types | ||
| this._acornTokTypes = acornTokTypes; | ||
| // track the last curly brace | ||
| this._curlyBrace = null; | ||
| // token buffer for templates | ||
| /** @type {acorn.Token[]} */ | ||
| this._tokens = []; | ||
| // the source code | ||
| this._code = code; | ||
| // track the last curly brace | ||
| this._curlyBrace = null; | ||
| } | ||
| // the source code | ||
| this._code = code; | ||
| TokenTranslator.prototype = { | ||
| constructor: TokenTranslator, | ||
| } | ||
@@ -101,4 +135,4 @@ /** | ||
| * Acorn, but should be accurate for all other tokens. | ||
| * @param {AcornToken} token The Acorn token to translate. | ||
| * @param {Object} extra Espree extra object. | ||
| * @param {acorn.Token} token The Acorn token to translate. | ||
| * @param {ExtraNoTokens} extra Espree extra object. | ||
| * @returns {EsprimaToken} The Esprima version of the token. | ||
@@ -109,18 +143,25 @@ */ | ||
| const type = token.type, | ||
| tt = this._acornTokTypes; | ||
| tt = this._acornTokTypes, | ||
| // We use an unknown type because `acorn.Token` is a class whose | ||
| // `type` property we cannot override to our desired `string`; | ||
| // this also allows us to define a stricter `EsprimaToken` with | ||
| // a string-only `type` property | ||
| unknownTokenType = /** @type {unknown} */ (token), | ||
| newToken = /** @type {EsprimaToken} */ (unknownTokenType); | ||
| if (type === tt.name) { | ||
| token.type = Token.Identifier; | ||
| newToken.type = Token.Identifier; | ||
| // TODO: See if this is an Acorn bug | ||
| if (token.value === "static") { | ||
| token.type = Token.Keyword; | ||
| if ("value" in token && token.value === "static") { | ||
| newToken.type = Token.Keyword; | ||
| } | ||
| if (extra.ecmaVersion > 5 && (token.value === "yield" || token.value === "let")) { | ||
| token.type = Token.Keyword; | ||
| if (extra.ecmaVersion > 5 && ("value" in token && (token.value === "yield" || token.value === "let"))) { | ||
| newToken.type = Token.Keyword; | ||
| } | ||
| } else if (type === tt.privateId) { | ||
| token.type = Token.PrivateIdentifier; | ||
| newToken.type = Token.PrivateIdentifier; | ||
@@ -137,22 +178,22 @@ } else if (type === tt.semi || type === tt.comma || | ||
| type === tt.questionDot || | ||
| (type.binop && !type.keyword) || | ||
| type.isAssign) { | ||
| ("binop" in type && type.binop && !type.keyword) || | ||
| ("isAssign" in type && type.isAssign)) { | ||
| token.type = Token.Punctuator; | ||
| token.value = this._code.slice(token.start, token.end); | ||
| newToken.type = Token.Punctuator; | ||
| newToken.value = this._code.slice(token.start, token.end); | ||
| } else if (type === tt.jsxName) { | ||
| token.type = Token.JSXIdentifier; | ||
| newToken.type = Token.JSXIdentifier; | ||
| } else if (type.label === "jsxText" || type === tt.jsxAttrValueToken) { | ||
| token.type = Token.JSXText; | ||
| newToken.type = Token.JSXText; | ||
| } else if (type.keyword) { | ||
| if (type.keyword === "true" || type.keyword === "false") { | ||
| token.type = Token.Boolean; | ||
| newToken.type = Token.Boolean; | ||
| } else if (type.keyword === "null") { | ||
| token.type = Token.Null; | ||
| newToken.type = Token.Null; | ||
| } else { | ||
| token.type = Token.Keyword; | ||
| newToken.type = Token.Keyword; | ||
| } | ||
| } else if (type === tt.num) { | ||
| token.type = Token.Numeric; | ||
| token.value = this._code.slice(token.start, token.end); | ||
| newToken.type = Token.Numeric; | ||
| newToken.value = this._code.slice(token.start, token.end); | ||
| } else if (type === tt.string) { | ||
@@ -162,26 +203,28 @@ | ||
| extra.jsxAttrValueToken = false; | ||
| token.type = Token.JSXText; | ||
| newToken.type = Token.JSXText; | ||
| } else { | ||
| token.type = Token.String; | ||
| newToken.type = Token.String; | ||
| } | ||
| token.value = this._code.slice(token.start, token.end); | ||
| newToken.value = this._code.slice(token.start, token.end); | ||
| } else if (type === tt.regexp) { | ||
| token.type = Token.RegularExpression; | ||
| const value = token.value; | ||
| newToken.type = Token.RegularExpression; | ||
| const value = /** @type {{flags: string, pattern: string}} */ ( | ||
| "value" in token && token.value | ||
| ); | ||
| token.regex = { | ||
| newToken.regex = { | ||
| flags: value.flags, | ||
| pattern: value.pattern | ||
| }; | ||
| token.value = `/${value.pattern}/${value.flags}`; | ||
| newToken.value = `/${value.pattern}/${value.flags}`; | ||
| } | ||
| return token; | ||
| }, | ||
| return newToken; | ||
| } | ||
| /** | ||
| * Function to call during Acorn's onToken handler. | ||
| * @param {AcornToken} token The Acorn token. | ||
| * @param {Object} extra The Espree extra object. | ||
| * @param {acorn.Token} token The Acorn token. | ||
| * @param {Extra} extra The Espree extra object. | ||
| * @returns {void} | ||
@@ -266,3 +309,3 @@ */ | ||
| } | ||
| }; | ||
| } | ||
@@ -269,0 +312,0 @@ //------------------------------------------------------------------------------ |
+21
-18
@@ -7,18 +7,20 @@ { | ||
| "main": "dist/espree.cjs", | ||
| "types": "./dist/espree.d.cts", | ||
| "type": "module", | ||
| "exports": { | ||
| ".": [ | ||
| { | ||
| "import": "./espree.js", | ||
| "require": "./dist/espree.cjs", | ||
| "default": "./dist/espree.cjs" | ||
| ".": { | ||
| "types": { | ||
| "import": "./dist/espree.d.ts", | ||
| "require": "./dist/espree.d.cts" | ||
| }, | ||
| "./dist/espree.cjs" | ||
| ], | ||
| "import": "./espree.js", | ||
| "require": "./dist/espree.cjs", | ||
| "default": "./dist/espree.cjs" | ||
| }, | ||
| "./package.json": "./package.json" | ||
| }, | ||
| "version": "11.0.0", | ||
| "version": "11.1.0", | ||
| "files": [ | ||
| "lib", | ||
| "dist/espree.cjs", | ||
| "dist", | ||
| "espree.js" | ||
@@ -45,7 +47,7 @@ ], | ||
| "devDependencies": { | ||
| "@rollup/plugin-commonjs": "^28.0.0", | ||
| "@rollup/plugin-json": "^6.1.0", | ||
| "@rollup/plugin-node-resolve": "^15.3.0", | ||
| "@arethetypeswrong/cli": "^0.18.2", | ||
| "rollup": "^2.79.1", | ||
| "shelljs": "^0.8.5" | ||
| "shelljs": "^0.8.5", | ||
| "tsd": "^0.33.0", | ||
| "typescript": "^5.9.3" | ||
| }, | ||
@@ -61,12 +63,13 @@ "keywords": [ | ||
| "scripts": { | ||
| "build": "rollup -c rollup.config.js", | ||
| "build": "rollup -c rollup.config.js && npm run build:types && node -e \"fs.rmSync('dist/lib', { recursive: true })\"", | ||
| "build:debug": "npm run build -- -m", | ||
| "build:docs": "node tools/sync-docs.js", | ||
| "build:update-version": "node tools/update-version.js", | ||
| "prepublishOnly": "npm run build:update-version && npm run build", | ||
| "build:types": "tsc && tsc -p tsconfig-cjs.json", | ||
| "lint:types": "attw --pack", | ||
| "pretest": "npm run build", | ||
| "test": "npm run test:cjs && npm run test:esm", | ||
| "test": "npm run test:types && npm run test:cjs && npm run test:esm", | ||
| "test:cjs": "mocha --color --reporter progress --timeout 30000 \"tests/**/*.test.cjs\"", | ||
| "test:esm": "c8 mocha --color --reporter progress --timeout 30000 \"tests/**/*.test.js\"" | ||
| "test:esm": "c8 mocha --color --reporter progress --timeout 30000 \"tests/**/*.test.js\"", | ||
| "test:types": "tsd --typings dist/espree.d.ts" | ||
| } | ||
| } |
+3
-3
@@ -255,6 +255,6 @@ [](https://www.npmjs.com/package/espree) | ||
| <h3>Platinum Sponsors</h3> | ||
| <p><a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="128"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="128"></a></p><h3>Gold Sponsors</h3> | ||
| <p><a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="128"></a></p><h3>Gold Sponsors</h3> | ||
| <p><a href="https://qlty.sh/"><img src="https://images.opencollective.com/qltysh/33d157d/logo.png" alt="Qlty Software" height="96"></a> <a href="https://shopify.engineering/"><img src="https://avatars.githubusercontent.com/u/8085" alt="Shopify" height="96"></a></p><h3>Silver Sponsors</h3> | ||
| <p><a href="https://vite.dev/"><img src="https://images.opencollective.com/vite/e6d15e1/logo.png" alt="Vite" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/2d6c3b6/logo.png" alt="Liftoff" height="64"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301" alt="American Express" height="64"></a> <a href="https://stackblitz.com"><img src="https://avatars.githubusercontent.com/u/28635252" alt="StackBlitz" height="64"></a></p><h3>Bronze Sponsors</h3> | ||
| <p><a href="https://cybozu.co.jp/"><img src="https://images.opencollective.com/cybozu/933e46d/logo.png" alt="Cybozu" height="32"></a> <a href="https://icons8.com/"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://www.gitbook.com"><img src="https://avatars.githubusercontent.com/u/7111340" alt="GitBook" height="32"></a> <a href="https://nx.dev"><img src="https://avatars.githubusercontent.com/u/23692104" alt="Nx" height="32"></a> <a href="https://opensource.mercedes-benz.com/"><img src="https://avatars.githubusercontent.com/u/34240465" alt="Mercedes-Benz Group" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774" alt="HeroCoders" height="32"></a> <a href="https://www.lambdatest.com"><img src="https://avatars.githubusercontent.com/u/171592363" alt="LambdaTest" height="32"></a></p> | ||
| <p><a href="https://vite.dev/"><img src="https://images.opencollective.com/vite/d472863/logo.png" alt="Vite" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/2d6c3b6/logo.png" alt="Liftoff" height="64"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301" alt="American Express" height="64"></a> <a href="https://stackblitz.com"><img src="https://avatars.githubusercontent.com/u/28635252" alt="StackBlitz" height="64"></a></p><h3>Bronze Sponsors</h3> | ||
| <p><a href="https://cybozu.co.jp/"><img src="https://images.opencollective.com/cybozu/933e46d/logo.png" alt="Cybozu" height="32"></a> <a href="https://www.crawljobs.com/"><img src="https://images.opencollective.com/crawljobs-poland/fa43a17/logo.png" alt="CrawlJobs" height="32"></a> <a href="https://syntax.fm"><img src="https://github.com/syntaxfm.png" alt="Syntax" height="32"></a> <a href="https://www.n-ix.com/"><img src="https://images.opencollective.com/n-ix-ltd/575a7a5/logo.png" alt="N-iX Ltd" height="32"></a> <a href="https://icons8.com/"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://www.gitbook.com"><img src="https://avatars.githubusercontent.com/u/7111340" alt="GitBook" height="32"></a> <a href="https://nx.dev"><img src="https://avatars.githubusercontent.com/u/23692104" alt="Nx" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774" alt="HeroCoders" height="32"></a> <a href="https://www.lambdatest.com"><img src="https://avatars.githubusercontent.com/u/171592363" alt="LambdaTest" height="32"></a></p> | ||
| <h3>Technology Sponsors</h3> | ||
@@ -261,0 +261,0 @@ Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work. |
| const version = "11.0.0"; | ||
| export default version; |
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
109030
41.89%14
40%2351
55.18%8
700%