You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

espree

Package Overview
Dependencies
Maintainers
2
Versions
103
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

espree - npm Package Compare versions

Comparing version
11.0.0
to
11.1.0
+3
dist/espree.d.cts
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"}
/**
* @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 @@

@@ -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;
}
};
};
};

@@ -8,8 +8,2 @@ /**

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
// None!
//------------------------------------------------------------------------------
// Public

@@ -16,0 +10,0 @@ //------------------------------------------------------------------------------

@@ -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) {

@@ -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 @@ //------------------------------------------------------------------------------

@@ -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"
}
}

@@ -255,6 +255,6 @@ [![npm version](https://img.shields.io/npm/v/espree.svg)](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;