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.1.0
to
11.1.1
+771
-759
dist/espree.cjs
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var acorn = require('acorn');
var jsx = require('acorn-jsx');
var visitorKeys = require('eslint-visitor-keys');
var eslintVisitorKeys = require('eslint-visitor-keys');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n["default"] = e;
return Object.freeze(n);
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var acorn__namespace = /*#__PURE__*/_interopNamespace(acorn);
var jsx__default = /*#__PURE__*/_interopDefaultLegacy(jsx);
var visitorKeys__namespace = /*#__PURE__*/_interopNamespace(visitorKeys);
var acorn__namespace = /*#__PURE__*/_interopNamespaceDefault(acorn);

@@ -74,15 +67,15 @@ /**

const Token = {
Boolean: "Boolean",
EOF: "<end>",
Identifier: "Identifier",
PrivateIdentifier: "PrivateIdentifier",
Keyword: "Keyword",
Null: "Null",
Numeric: "Numeric",
Punctuator: "Punctuator",
String: "String",
RegularExpression: "RegularExpression",
Template: "Template",
JSXIdentifier: "JSXIdentifier",
JSXText: "JSXText"
Boolean: "Boolean",
EOF: "<end>",
Identifier: "Identifier",
PrivateIdentifier: "PrivateIdentifier",
Keyword: "Keyword",
Null: "Null",
Numeric: "Numeric",
Punctuator: "Punctuator",
String: "String",
RegularExpression: "RegularExpression",
Template: "Template",
JSXIdentifier: "JSXIdentifier",
JSXText: "JSXText",
};

@@ -98,31 +91,28 @@

function convertTemplatePart(tokens, code) {
const firstToken = tokens[0],
lastTemplateToken =
/**
* @type {acorn.Token & {
* loc: acorn.SourceLocation,
* range: [number, number]
* }}
*/ (tokens.at(-1));
const firstToken = tokens[0],
lastTemplateToken =
/** @type {acorn.Token & { loc: acorn.SourceLocation, range: [number, number] }} */ (
tokens.at(-1)
);
/** @type {EsprimaToken} */
const token = {
type: Token.Template,
value: code.slice(firstToken.start, lastTemplateToken.end)
};
/** @type {EsprimaToken} */
const token = {
type: Token.Template,
value: code.slice(firstToken.start, lastTemplateToken.end),
};
if (firstToken.loc) {
token.loc = {
start: firstToken.loc.start,
end: lastTemplateToken.loc.end
};
}
if (firstToken.loc) {
token.loc = {
start: firstToken.loc.start,
end: lastTemplateToken.loc.end,
};
}
if (firstToken.range) {
token.start = firstToken.range[0];
token.end = lastTemplateToken.range[1];
token.range = [token.start, token.end];
}
if (firstToken.range) {
token.start = firstToken.range[0];
token.end = lastTemplateToken.range[1];
token.range = [token.start, token.end];
}
return token;
return token;
}

@@ -135,201 +125,204 @@

class TokenTranslator {
/**
* 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 */
/**
* 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 types
this._acornTokTypes = acornTokTypes;
// token types
this._acornTokTypes = acornTokTypes;
// token buffer for templates
/** @type {acorn.Token[]} */
this._tokens = [];
// token buffer for templates
/** @type {acorn.Token[]} */
this._tokens = [];
// track the last curly brace
this._curlyBrace = null;
// track the last curly brace
this._curlyBrace = null;
// the source code
this._code = code;
}
// the source code
this._code = code;
/**
* Translates a single Esprima token to a single Acorn token. This may be
* inaccurate due to how templates are handled differently in Esprima and
* Acorn, but should be accurate for all other tokens.
* @param {acorn.Token} token The Acorn token to translate.
* @param {ExtraNoTokens} extra Espree extra object.
* @returns {EsprimaToken} The Esprima version of the token.
*/
translate(token, extra) {
const type = token.type,
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) {
newToken.type = Token.Identifier;
/**
* Translates a single Esprima token to a single Acorn token. This may be
* inaccurate due to how templates are handled differently in Esprima and
* Acorn, but should be accurate for all other tokens.
* @param {acorn.Token} token The Acorn token to translate.
* @param {ExtraNoTokens} extra Espree extra object.
* @returns {EsprimaToken} The Esprima version of the token.
*/
translate(token, extra) {
// TODO: See if this is an Acorn bug
if ("value" in token && token.value === "static") {
newToken.type = Token.Keyword;
}
const type = token.type,
tt = this._acornTokTypes,
if (
extra.ecmaVersion > 5 &&
"value" in token &&
(token.value === "yield" || token.value === "let")
) {
newToken.type = Token.Keyword;
}
} else if (type === tt.privateId) {
newToken.type = Token.PrivateIdentifier;
} else if (
type === tt.semi ||
type === tt.comma ||
type === tt.parenL ||
type === tt.parenR ||
type === tt.braceL ||
type === tt.braceR ||
type === tt.dot ||
type === tt.bracketL ||
type === tt.colon ||
type === tt.question ||
type === tt.bracketR ||
type === tt.ellipsis ||
type === tt.arrow ||
type === tt.jsxTagStart ||
type === tt.incDec ||
type === tt.starstar ||
type === tt.jsxTagEnd ||
type === tt.prefix ||
type === tt.questionDot ||
("binop" in type && type.binop && !type.keyword) ||
("isAssign" in type && type.isAssign)
) {
newToken.type = Token.Punctuator;
newToken.value = this._code.slice(token.start, token.end);
} else if (type === tt.jsxName) {
newToken.type = Token.JSXIdentifier;
} else if (type.label === "jsxText" || type === tt.jsxAttrValueToken) {
newToken.type = Token.JSXText;
} else if (type.keyword) {
if (type.keyword === "true" || type.keyword === "false") {
newToken.type = Token.Boolean;
} else if (type.keyword === "null") {
newToken.type = Token.Null;
} else {
newToken.type = Token.Keyword;
}
} else if (type === tt.num) {
newToken.type = Token.Numeric;
newToken.value = this._code.slice(token.start, token.end);
} else if (type === tt.string) {
if (extra.jsxAttrValueToken) {
extra.jsxAttrValueToken = false;
newToken.type = Token.JSXText;
} else {
newToken.type = Token.String;
}
// 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);
newToken.value = this._code.slice(token.start, token.end);
} else if (type === tt.regexp) {
newToken.type = Token.RegularExpression;
const value = /** @type {{flags: string, pattern: string}} */ (
"value" in token && token.value
);
if (type === tt.name) {
newToken.type = Token.Identifier;
newToken.regex = {
flags: value.flags,
pattern: value.pattern,
};
newToken.value = `/${value.pattern}/${value.flags}`;
}
// TODO: See if this is an Acorn bug
if ("value" in token && token.value === "static") {
newToken.type = Token.Keyword;
}
return newToken;
}
if (extra.ecmaVersion > 5 && ("value" in token && (token.value === "yield" || token.value === "let"))) {
newToken.type = Token.Keyword;
}
/**
* Function to call during Acorn's onToken handler.
* @param {acorn.Token} token The Acorn token.
* @param {Extra} extra The Espree extra object.
* @returns {void}
*/
onToken(token, extra) {
const tt = this._acornTokTypes,
tokens = extra.tokens,
templateTokens = this._tokens;
} else if (type === tt.privateId) {
newToken.type = Token.PrivateIdentifier;
/**
* Flushes the buffered template tokens and resets the template
* tracking.
* @returns {void}
* @private
*/
const translateTemplateTokens = () => {
tokens.push(convertTemplatePart(this._tokens, this._code));
this._tokens = [];
};
} else if (type === tt.semi || type === tt.comma ||
type === tt.parenL || type === tt.parenR ||
type === tt.braceL || type === tt.braceR ||
type === tt.dot || type === tt.bracketL ||
type === tt.colon || type === tt.question ||
type === tt.bracketR || type === tt.ellipsis ||
type === tt.arrow || type === tt.jsxTagStart ||
type === tt.incDec || type === tt.starstar ||
type === tt.jsxTagEnd || type === tt.prefix ||
type === tt.questionDot ||
("binop" in type && type.binop && !type.keyword) ||
("isAssign" in type && type.isAssign)) {
if (token.type === tt.eof) {
// might be one last curlyBrace
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
}
newToken.type = Token.Punctuator;
newToken.value = this._code.slice(token.start, token.end);
} else if (type === tt.jsxName) {
newToken.type = Token.JSXIdentifier;
} else if (type.label === "jsxText" || type === tt.jsxAttrValueToken) {
newToken.type = Token.JSXText;
} else if (type.keyword) {
if (type.keyword === "true" || type.keyword === "false") {
newToken.type = Token.Boolean;
} else if (type.keyword === "null") {
newToken.type = Token.Null;
} else {
newToken.type = Token.Keyword;
}
} else if (type === tt.num) {
newToken.type = Token.Numeric;
newToken.value = this._code.slice(token.start, token.end);
} else if (type === tt.string) {
return;
}
if (extra.jsxAttrValueToken) {
extra.jsxAttrValueToken = false;
newToken.type = Token.JSXText;
} else {
newToken.type = Token.String;
}
if (token.type === tt.backQuote) {
// if there's already a curly, it's not part of the template
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
this._curlyBrace = null;
}
newToken.value = this._code.slice(token.start, token.end);
} else if (type === tt.regexp) {
newToken.type = Token.RegularExpression;
const value = /** @type {{flags: string, pattern: string}} */ (
"value" in token && token.value
);
templateTokens.push(token);
newToken.regex = {
flags: value.flags,
pattern: value.pattern
};
newToken.value = `/${value.pattern}/${value.flags}`;
}
// it's the end
if (templateTokens.length > 1) {
translateTemplateTokens();
}
return newToken;
}
return;
}
if (token.type === tt.dollarBraceL) {
templateTokens.push(token);
translateTemplateTokens();
return;
}
if (token.type === tt.braceR) {
// if there's already a curly, it's not part of the template
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
}
/**
* Function to call during Acorn's onToken handler.
* @param {acorn.Token} token The Acorn token.
* @param {Extra} extra The Espree extra object.
* @returns {void}
*/
onToken(token, extra) {
// store new curly for later
this._curlyBrace = token;
return;
}
if (token.type === tt.template || token.type === tt.invalidTemplate) {
if (this._curlyBrace) {
templateTokens.push(this._curlyBrace);
this._curlyBrace = null;
}
const tt = this._acornTokTypes,
tokens = extra.tokens,
templateTokens = this._tokens;
templateTokens.push(token);
return;
}
/**
* Flushes the buffered template tokens and resets the template
* tracking.
* @returns {void}
* @private
*/
const translateTemplateTokens = () => {
tokens.push(convertTemplatePart(this._tokens, this._code));
this._tokens = [];
};
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
this._curlyBrace = null;
}
if (token.type === tt.eof) {
// might be one last curlyBrace
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
}
return;
}
if (token.type === tt.backQuote) {
// if there's already a curly, it's not part of the template
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
this._curlyBrace = null;
}
templateTokens.push(token);
// it's the end
if (templateTokens.length > 1) {
translateTemplateTokens();
}
return;
}
if (token.type === tt.dollarBraceL) {
templateTokens.push(token);
translateTemplateTokens();
return;
}
if (token.type === tt.braceR) {
// if there's already a curly, it's not part of the template
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
}
// store new curly for later
this._curlyBrace = token;
return;
}
if (token.type === tt.template || token.type === tt.invalidTemplate) {
if (this._curlyBrace) {
templateTokens.push(this._curlyBrace);
this._curlyBrace = null;
}
templateTokens.push(token);
return;
}
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
this._curlyBrace = null;
}
tokens.push(this.translate(token, extra));
}
tokens.push(this.translate(token, extra));
}
}

@@ -351,16 +344,16 @@

const SUPPORTED_VERSIONS = /** @type {const} */ ([
3,
5,
6, // 2015
7, // 2016
8, // 2017
9, // 2018
10, // 2019
11, // 2020
12, // 2021
13, // 2022
14, // 2023
15, // 2024
16, // 2025
17 // 2026
3,
5,
6, // 2015
7, // 2016
8, // 2017
9, // 2018
10, // 2019
11, // 2020
12, // 2021
13, // 2022
14, // 2023
15, // 2024
16, // 2025
17, // 2026
]);

@@ -373,7 +366,7 @@

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 */
);
/* 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 */
);

@@ -385,3 +378,3 @@ /**

function getLatestEcmaVersion() {
return LATEST_ECMA_VERSION;
return LATEST_ECMA_VERSION;
}

@@ -394,3 +387,3 @@

function getSupportedEcmaVersions() {
return [...SUPPORTED_VERSIONS];
return [...SUPPORTED_VERSIONS];
}

@@ -405,24 +398,27 @@

function normalizeEcmaVersion(ecmaVersion = 5) {
let version =
ecmaVersion === "latest" ? getLatestEcmaVersion() : ecmaVersion;
let version = ecmaVersion === "latest" ? getLatestEcmaVersion() : ecmaVersion;
if (typeof version !== "number") {
throw new Error(
`ecmaVersion must be a number or "latest". Received value of type ${typeof ecmaVersion} instead.`,
);
}
if (typeof version !== "number") {
throw new Error(`ecmaVersion must be a number or "latest". Received value of type ${typeof ecmaVersion} instead.`);
}
// Calculate ECMAScript edition number from official year version starting with
// ES2015, which corresponds with ES6 (or a difference of 2009).
if (version >= 2015) {
version -= 2009;
}
// Calculate ECMAScript edition number from official year version starting with
// ES2015, which corresponds with ES6 (or a difference of 2009).
if (version >= 2015) {
version -= 2009;
}
if (
!SUPPORTED_VERSIONS.includes(
/** @type {NormalizedEcmaVersion} */
(version),
)
) {
throw new Error("Invalid ecmaVersion.");
}
if (!SUPPORTED_VERSIONS.includes(
/** @type {NormalizedEcmaVersion} */
(version)
)) {
throw new Error("Invalid ecmaVersion.");
}
return /** @type {NormalizedEcmaVersion} */ (version);
return /** @type {NormalizedEcmaVersion} */ (version);
}

@@ -437,11 +433,11 @@

function normalizeSourceType(sourceType = "script") {
if (sourceType === "script" || sourceType === "module") {
return sourceType;
}
if (sourceType === "script" || sourceType === "module") {
return sourceType;
}
if (sourceType === "commonjs") {
return "script";
}
if (sourceType === "commonjs") {
return "script";
}
throw new Error("Invalid sourceType.");
throw new Error("Invalid sourceType.");
}

@@ -476,32 +472,41 @@

function normalizeOptions(options) {
const ecmaVersion = normalizeEcmaVersion(options.ecmaVersion);
const sourceType = normalizeSourceType(options.sourceType);
const ranges = options.range === true;
const locations = options.loc === true;
const ecmaVersion = normalizeEcmaVersion(options.ecmaVersion);
const sourceType = normalizeSourceType(options.sourceType);
const ranges = options.range === true;
const locations = options.loc === true;
if (ecmaVersion !== 3 && options.allowReserved) {
if (ecmaVersion !== 3 && options.allowReserved) {
// a value of `false` is intentionally allowed here, so a shared config can overwrite it when needed
throw new Error(
"`allowReserved` is only supported when ecmaVersion is 3",
);
}
if (
typeof options.allowReserved !== "undefined" &&
typeof options.allowReserved !== "boolean"
) {
throw new Error(
"`allowReserved`, when present, must be `true` or `false`",
);
}
const allowReserved =
ecmaVersion === 3 ? options.allowReserved || "never" : false;
const ecmaFeatures = options.ecmaFeatures || {};
const allowReturnOutsideFunction =
options.sourceType === "commonjs" || Boolean(ecmaFeatures.globalReturn);
// a value of `false` is intentionally allowed here, so a shared config can overwrite it when needed
throw new Error("`allowReserved` is only supported when ecmaVersion is 3");
}
if (typeof options.allowReserved !== "undefined" && typeof options.allowReserved !== "boolean") {
throw new Error("`allowReserved`, when present, must be `true` or `false`");
}
const allowReserved = ecmaVersion === 3 ? (options.allowReserved || "never") : false;
const ecmaFeatures = options.ecmaFeatures || {};
const allowReturnOutsideFunction = options.sourceType === "commonjs" ||
Boolean(ecmaFeatures.globalReturn);
if (sourceType === "module" && ecmaVersion < 6) {
throw new Error(
"sourceType 'module' is not supported when ecmaVersion < 2015. Consider adding `{ ecmaVersion: 2015 }` to the parser options.",
);
}
if (sourceType === "module" && ecmaVersion < 6) {
throw new Error("sourceType 'module' is not supported when ecmaVersion < 2015. Consider adding `{ ecmaVersion: 2015 }` to the parser options.");
}
return Object.assign({}, options, {
ecmaVersion,
sourceType,
ranges,
locations,
allowReserved,
allowReturnOutsideFunction
});
return Object.assign({}, options, {
ecmaVersion,
sourceType,
ranges,
locations,
allowReserved,
allowReturnOutsideFunction,
});
}

@@ -511,2 +516,3 @@

/**

@@ -570,7 +576,5 @@ * @import {

const STATE = Symbol("espree's internal state");
const ESPRIMA_FINISH_NODE = Symbol("espree's esprimaFinishNode");
/**

@@ -588,47 +592,54 @@ * Converts an Acorn comment to a Esprima comment.

*/
function convertAcornCommentToEsprimaComment(block, text, start, end, startLoc, endLoc, code) {
function convertAcornCommentToEsprimaComment(
block,
text,
start,
end,
startLoc,
endLoc,
code,
) {
/** @type {CommentType} */
let type;
/** @type {CommentType} */
let type;
if (block) {
type = "Block";
} else if (code.slice(start, start + 2) === "#!") {
type = "Hashbang";
} else {
type = "Line";
}
if (block) {
type = "Block";
} else if (code.slice(start, start + 2) === "#!") {
type = "Hashbang";
} else {
type = "Line";
}
/**
* @type {{
* type: CommentType,
* value: string,
* start?: number,
* end?: number,
* range?: [number, number],
* loc?: {
* start: acorn.Position | undefined,
* end: acorn.Position | undefined
* }
* }}
*/
const comment = {
type,
value: text,
};
/**
* @type {{
* type: CommentType,
* value: string,
* start?: number,
* end?: number,
* range?: [number, number],
* loc?: {
* start: acorn.Position | undefined,
* end: acorn.Position | undefined
* }
* }}
*/
const comment = {
type,
value: text
};
if (typeof start === "number") {
comment.start = start;
comment.end = end;
comment.range = [start, end];
}
if (typeof start === "number") {
comment.start = start;
comment.end = end;
comment.range = [start, end];
}
if (typeof startLoc === "object") {
comment.loc = {
start: startLoc,
end: endLoc,
};
}
if (typeof startLoc === "object") {
comment.loc = {
start: startLoc,
end: endLoc
};
}
return comment;
return comment;
}

@@ -638,354 +649,360 @@

var espree = () => {
/**
* 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)
);
/**
* 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)
);
if (Parser.acornJsx) {
Object.assign(tokTypes, Parser.acornJsx.tokTypes);
}
if (Parser.acornJsx) {
Object.assign(tokTypes, Parser.acornJsx.tokTypes);
}
return class Espree extends Parser {
/**
* @param {Options | null | undefined} opts The parser options
* @param {string | object} code The code which will be converted to a string.
*/
constructor(opts, code) {
if (typeof opts !== "object" || opts === null) {
opts = {};
}
if (typeof code !== "string" && !(code instanceof String)) {
code = String(code);
}
return class Espree extends Parser {
// 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,
/**
* @param {Options | null | undefined} opts The parser options
* @param {string | object} code The code which will be converted to a string.
*/
constructor(opts, code) {
if (typeof opts !== "object" || opts === null) {
opts = {};
}
if (typeof code !== "string" && !(code instanceof String)) {
code = String(code);
}
// @ts-expect-error Appears to be a TS bug since the type is indeed string|String
code,
)
: null;
// 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,
/**
* 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: [],
};
// @ts-expect-error Appears to be a TS bug since the type is indeed string|String
code
)
: null;
// Initialize acorn parser.
super(
{
// 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,
/**
* 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: []
};
// Truthy value is true for backward compatibility.
allowReturnOutsideFunction:
options.allowReturnOutsideFunction,
// Initialize acorn parser.
super({
// Collect tokens
onToken(token) {
if (tokenTranslator) {
// Use `tokens`, `ecmaVersion`, and `jsxAttrValueToken` in the state.
tokenTranslator.onToken(
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,
/**
* @type {Omit<State, "tokens"> & {
* tokens: EsprimaToken[]
* }}
*/
(state),
);
}
if (token.type !== tokTypes.eof) {
state.lastToken = token;
}
},
// Truthy value is true for backward compatibility.
allowReturnOutsideFunction: options.allowReturnOutsideFunction,
// Collect comments
onComment(block, text, start, end, startLoc, endLoc) {
if (state.comments) {
const comment =
convertAcornCommentToEsprimaComment(
block,
text,
start,
end,
startLoc,
endLoc,
// Collect tokens
onToken(token) {
if (tokenTranslator) {
// @ts-expect-error Appears to be a TS bug
// since the type is indeed string|String
code,
);
// Use `tokens`, `ecmaVersion`, and `jsxAttrValueToken` in the state.
tokenTranslator.onToken(
token,
state.comments.push(comment);
}
},
},
// @ts-expect-error Appears to be a TS bug
// since the type is indeed string|String
code,
);
/**
* @type {Omit<State, "tokens"> & {
* tokens: EsprimaToken[]
* }}
*/
(state)
);
}
if (token.type !== tokTypes.eof) {
state.lastToken = token;
}
},
/*
* 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;
}
// Collect comments
onComment(block, text, start, end, startLoc, endLoc) {
if (state.comments) {
const comment = convertAcornCommentToEsprimaComment(
block,
text,
start,
end,
startLoc,
endLoc,
/**
* Returns Espree tokens.
* @returns {EsprimaTokens} The Esprima-compatible tokens
*/
tokenize() {
do {
this.next();
} while (this.type !== tokTypes.eof);
// @ts-expect-error Appears to be a TS bug
// since the type is indeed string|String
code
);
// Consume the final eof token
this.next();
state.comments.push(comment);
}
}
const extra = this[STATE];
const tokens = /** @type {EsprimaTokens} */ (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;
}
/*
* 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);
/**
* 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);
// Consume the final eof token
this.next();
return this[ESPRIMA_FINISH_NODE](result);
}
const extra = this[STATE];
const tokens = /** @type {EsprimaTokens} */ (extra.tokens);
/**
* 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);
if (extra.comments) {
tokens.comments = extra.comments;
}
return this[ESPRIMA_FINISH_NODE](result);
}
return tokens;
}
/**
* Parses.
* @returns {EsprimaProgramNode} The program Node
*/
parse() {
const extra = this[STATE];
const prog = 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);
const program = /** @type {EsprimaProgramNode} */ (prog);
return this[ESPRIMA_FINISH_NODE](result);
}
// @ts-expect-error TS bug? We've already converted to `EsprimaProgramNode`
program.sourceType = extra.originalSourceType;
/**
* 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);
if (extra.comments) {
program.comments = extra.comments;
}
if (extra.tokens) {
program.tokens = extra.tokens;
}
return this[ESPRIMA_FINISH_NODE](result);
}
/*
* 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;
/**
* Parses.
* @returns {EsprimaProgramNode} The program Node
*/
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;
/**
* 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);
}
templateElement.start += startOffset;
templateElement.end += endOffset;
/**
* 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)
);
if (templateElement.range) {
templateElement.range[0] += startOffset;
templateElement.range[1] += endOffset;
}
err.index = pos;
err.lineNumber = loc.line;
err.column = loc.column + 1; // acorn uses 0-based columns
throw err;
}
if (templateElement.loc) {
templateElement.loc.start.column += startOffset;
templateElement.loc.end.column += endOffset;
}
});
/**
* 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);
}
return program;
}
/**
* 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";
/**
* 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);
}
if (pos !== null && pos !== void 0) {
this.pos = pos;
/**
* 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)
);
if (this.options.locations) {
while (this.pos < this.lineStart) {
this.lineStart =
this.input.lastIndexOf(
"\n",
this.lineStart - 2,
) + 1;
--this.curLine;
}
}
err.index = pos;
err.lineNumber = loc.line;
err.column = loc.column + 1; // acorn uses 0-based columns
throw err;
}
this.nextToken();
}
/**
* 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 (this.end > this.start) {
message += ` ${this.input.slice(this.start, this.end)}`;
}
/**
* 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";
this.raise(this.start, message);
}
if (pos !== null && pos !== void 0) {
this.pos = pos;
/**
* 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}
*/ // eslint-disable-next-line camelcase -- required by API
jsx_readString(quote) {
const result = super.jsx_readString(quote);
if (this.options.locations) {
while (this.pos < this.lineStart) {
this.lineStart = this.input.lastIndexOf("\n", this.lineStart - 2) + 1;
--this.curLine;
}
}
if (this.type === tokTypes.string) {
this[STATE].jsxAttrValueToken = true;
}
return result;
}
this.nextToken();
}
/**
* 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) {
// 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") {
// save template element references to fix start/end later
this[STATE].templateElements.push(
/** @type {acorn.TemplateElement} */
(result),
);
}
if (this.end > this.start) {
message += ` ${this.input.slice(this.start, this.end)}`;
}
if (
result.type.includes("Function") &&
!("generator" in result)
) {
/**
* @type {acorn.FunctionDeclaration|acorn.FunctionExpression|
* acorn.ArrowFunctionExpression}
*/
(result).generator = false;
}
this.raise(this.start, message);
}
/**
* 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;
}
/**
* 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) {
// 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") {
// save template element references to fix start/end later
this[STATE].templateElements.push(
/** @type {acorn.TemplateElement} */
(result)
);
}
if (result.type.includes("Function") && (!("generator" in result))) {
/**
* @type {acorn.FunctionDeclaration|acorn.FunctionExpression|
* acorn.ArrowFunctionExpression}
*/
(result).generator = false;
}
return result;
}
};
};
return result;
}
};
};
};

@@ -1050,2 +1067,3 @@

/**

@@ -1124,71 +1142,72 @@ * @import { EspreeParserCtor, EspreeParserJsxCtor } from "./lib/types.js";

const parsers = {
/** @type {EspreeParserCtor|null} */
_regular: null,
/** @type {EspreeParserCtor|null} */
_regular: null,
/** @type {EspreeParserJsxCtor|null} */
_jsx: null,
/** @type {EspreeParserJsxCtor|null} */
_jsx: null,
/**
* Returns regular Parser
* @returns {EspreeParserCtor} Regular Acorn parser
*/
get regular() {
if (this._regular === null) {
const espreeParserFactory = /** @type {unknown} */ (espree());
/**
* Returns regular Parser
* @returns {EspreeParserCtor} Regular Acorn parser
*/
get regular() {
if (this._regular === null) {
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),
)
)
);
}
return this._regular;
},
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)
))
);
}
return this._regular;
},
/**
* Returns JSX Parser
* @returns {EspreeParserJsxCtor} JSX Acorn parser
*/
get jsx() {
if (this._jsx === null) {
const espreeParserFactory = /** @type {unknown} */ (espree());
const jsxFactory = jsx();
/**
* Returns JSX Parser
* @returns {EspreeParserJsxCtor} JSX Acorn parser
*/
get jsx() {
if (this._jsx === null) {
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,
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),
)
)
);
}
return this._jsx;
},
/** @type {(BaseParser: typeof acorn.Parser) => typeof acorn.Parser} */
(espreeParserFactory)
))
);
}
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) {
const useJsx = Boolean(
options && options.ecmaFeatures && options.ecmaFeatures.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) {
const useJsx = Boolean(
options &&
options.ecmaFeatures &&
options.ecmaFeatures.jsx
);
return useJsx ? this.jsx : this.regular;
}
return useJsx ? this.jsx : this.regular;
},
};

@@ -1209,10 +1228,10 @@

function tokenize(code, options) {
const Parser = parsers.get(options);
const Parser = parsers.get(options);
// Ensure to collect tokens.
if (!options || options.tokens !== true) {
options = Object.assign({}, options, { tokens: true }); // eslint-disable-line no-param-reassign -- stylistic choice
}
// Ensure to collect tokens.
if (!options || options.tokens !== true) {
options = Object.assign({}, options, { tokens: true }); // eslint-disable-line no-param-reassign -- stylistic choice
}
return /** @type {EspreeTokens} */ (new Parser(options, code).tokenize());
return /** @type {EspreeTokens} */ (new Parser(options, code).tokenize());
}

@@ -1232,5 +1251,5 @@

function parse(code, options) {
const Parser = parsers.get(options);
const Parser = parsers.get(options);
return new Parser(options, code).parse();
return new Parser(options, code).parse();
}

@@ -1243,44 +1262,37 @@

/** @type {string} */
const version = "11.1.0"; // x-release-please-version
const version = "11.1.1"; // x-release-please-version
const name = "espree";
/* istanbul ignore next */
/**
* @type {visitorKeys.VisitorKeys}
*/
const VisitorKeys = (function() {
return visitorKeys__namespace.KEYS;
}());
// Derive node types from VisitorKeys
/* istanbul ignore next */
const Syntax = (function() {
let key,
const Syntax = /* #__PURE__ */ (function () {
let key,
/** @type {Record<string,string>} */
types = {};
/** @type {Record<string,string>} */
types = {};
if (typeof Object.create === "function") {
types = Object.create(null);
}
if (typeof Object.create === "function") {
types = Object.create(null);
}
for (key in eslintVisitorKeys.KEYS) {
if (Object.hasOwn(eslintVisitorKeys.KEYS, key)) {
types[key] = key;
}
}
for (key in VisitorKeys) {
if (Object.hasOwn(VisitorKeys, key)) {
types[key] = key;
}
}
if (typeof Object.freeze === "function") {
Object.freeze(types);
}
if (typeof Object.freeze === "function") {
Object.freeze(types);
}
return types;
})();
return types;
}());
const latestEcmaVersion = /* #__PURE__ */ getLatestEcmaVersion();
const latestEcmaVersion = getLatestEcmaVersion();
const supportedEcmaVersions = /* #__PURE__ */ getSupportedEcmaVersions();
const supportedEcmaVersions = getSupportedEcmaVersions();
Object.defineProperty(exports, "VisitorKeys", {
enumerable: true,
get: function () { return eslintVisitorKeys.KEYS; }
});
exports.Syntax = Syntax;
exports.VisitorKeys = VisitorKeys;
exports.latestEcmaVersion = latestEcmaVersion;

@@ -1287,0 +1299,0 @@ exports.name = name;

@@ -21,9 +21,6 @@ /**

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 { KEYS as VisitorKeys } from "eslint-visitor-keys";
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";

@@ -71,3 +68,2 @@ export type EspreeToken = {

import * as acorn from "acorn";
import * as visitorKeys from "eslint-visitor-keys";
//# sourceMappingURL=espree.d.ts.map
+96
-100

@@ -61,4 +61,7 @@ /**

import espree from "./lib/espree.js";
import * as visitorKeys from "eslint-visitor-keys";
import { getLatestEcmaVersion, getSupportedEcmaVersions } from "./lib/options.js";
import { KEYS as VisitorKeys } from "eslint-visitor-keys";
import {
getLatestEcmaVersion,
getSupportedEcmaVersions,
} from "./lib/options.js";

@@ -138,71 +141,72 @@ /**

const parsers = {
/** @type {EspreeParserCtor|null} */
_regular: null,
/** @type {EspreeParserCtor|null} */
_regular: null,
/** @type {EspreeParserJsxCtor|null} */
_jsx: null,
/** @type {EspreeParserJsxCtor|null} */
_jsx: null,
/**
* Returns regular Parser
* @returns {EspreeParserCtor} Regular Acorn parser
*/
get regular() {
if (this._regular === null) {
const espreeParserFactory = /** @type {unknown} */ (espree());
/**
* Returns regular Parser
* @returns {EspreeParserCtor} Regular Acorn parser
*/
get regular() {
if (this._regular === null) {
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),
)
)
);
}
return this._regular;
},
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)
))
);
}
return this._regular;
},
/**
* Returns JSX Parser
* @returns {EspreeParserJsxCtor} JSX Acorn parser
*/
get jsx() {
if (this._jsx === null) {
const espreeParserFactory = /** @type {unknown} */ (espree());
const jsxFactory = jsx();
/**
* Returns JSX Parser
* @returns {EspreeParserJsxCtor} JSX Acorn parser
*/
get jsx() {
if (this._jsx === null) {
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,
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),
)
)
);
}
return this._jsx;
},
/** @type {(BaseParser: typeof acorn.Parser) => typeof acorn.Parser} */
(espreeParserFactory)
))
);
}
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) {
const useJsx = Boolean(
options && options.ecmaFeatures && options.ecmaFeatures.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) {
const useJsx = Boolean(
options &&
options.ecmaFeatures &&
options.ecmaFeatures.jsx
);
return useJsx ? this.jsx : this.regular;
}
return useJsx ? this.jsx : this.regular;
},
};

@@ -223,10 +227,10 @@

export function tokenize(code, options) {
const Parser = parsers.get(options);
const Parser = parsers.get(options);
// Ensure to collect tokens.
if (!options || options.tokens !== true) {
options = Object.assign({}, options, { tokens: true }); // eslint-disable-line no-param-reassign -- stylistic choice
}
// Ensure to collect tokens.
if (!options || options.tokens !== true) {
options = Object.assign({}, options, { tokens: true }); // eslint-disable-line no-param-reassign -- stylistic choice
}
return /** @type {EspreeTokens} */ (new Parser(options, code).tokenize());
return /** @type {EspreeTokens} */ (new Parser(options, code).tokenize());
}

@@ -246,5 +250,5 @@

export function parse(code, options) {
const Parser = parsers.get(options);
const Parser = parsers.get(options);
return new Parser(options, code).parse();
return new Parser(options, code).parse();
}

@@ -257,40 +261,32 @@

/** @type {string} */
export const version = "11.1.0"; // x-release-please-version
export const version = "11.1.1"; // x-release-please-version
export const name = "espree";
/* istanbul ignore next */
/**
* @type {visitorKeys.VisitorKeys}
*/
export const VisitorKeys = (function() {
return visitorKeys.KEYS;
}());
// Derive node types from VisitorKeys
/* istanbul ignore next */
export const Syntax = (function() {
let key,
export const Syntax = /* #__PURE__ */ (function () {
let key,
/** @type {Record<string,string>} */
types = {};
/** @type {Record<string,string>} */
types = {};
if (typeof Object.create === "function") {
types = Object.create(null);
}
if (typeof Object.create === "function") {
types = Object.create(null);
}
for (key in VisitorKeys) {
if (Object.hasOwn(VisitorKeys, key)) {
types[key] = key;
}
}
for (key in VisitorKeys) {
if (Object.hasOwn(VisitorKeys, key)) {
types[key] = key;
}
}
if (typeof Object.freeze === "function") {
Object.freeze(types);
}
if (typeof Object.freeze === "function") {
Object.freeze(types);
}
return types;
})();
return types;
}());
export const latestEcmaVersion = /* #__PURE__ */ getLatestEcmaVersion();
export const latestEcmaVersion = getLatestEcmaVersion();
export const supportedEcmaVersions = /* #__PURE__ */ getSupportedEcmaVersions();
export const supportedEcmaVersions = getSupportedEcmaVersions();
export { KEYS as VisitorKeys } from "eslint-visitor-keys";

@@ -64,7 +64,5 @@ /* eslint no-param-reassign: 0 -- stylistic choice */

const STATE = Symbol("espree's internal state");
const ESPRIMA_FINISH_NODE = Symbol("espree's esprimaFinishNode");
/**

@@ -82,47 +80,54 @@ * Converts an Acorn comment to a Esprima comment.

*/
function convertAcornCommentToEsprimaComment(block, text, start, end, startLoc, endLoc, code) {
function convertAcornCommentToEsprimaComment(
block,
text,
start,
end,
startLoc,
endLoc,
code,
) {
/** @type {CommentType} */
let type;
/** @type {CommentType} */
let type;
if (block) {
type = "Block";
} else if (code.slice(start, start + 2) === "#!") {
type = "Hashbang";
} else {
type = "Line";
}
if (block) {
type = "Block";
} else if (code.slice(start, start + 2) === "#!") {
type = "Hashbang";
} else {
type = "Line";
}
/**
* @type {{
* type: CommentType,
* value: string,
* start?: number,
* end?: number,
* range?: [number, number],
* loc?: {
* start: acorn.Position | undefined,
* end: acorn.Position | undefined
* }
* }}
*/
const comment = {
type,
value: text,
};
/**
* @type {{
* type: CommentType,
* value: string,
* start?: number,
* end?: number,
* range?: [number, number],
* loc?: {
* start: acorn.Position | undefined,
* end: acorn.Position | undefined
* }
* }}
*/
const comment = {
type,
value: text
};
if (typeof start === "number") {
comment.start = start;
comment.end = end;
comment.range = [start, end];
}
if (typeof start === "number") {
comment.start = start;
comment.end = end;
comment.range = [start, end];
}
if (typeof startLoc === "object") {
comment.loc = {
start: startLoc,
end: endLoc,
};
}
if (typeof startLoc === "object") {
comment.loc = {
start: startLoc,
end: endLoc
};
}
return comment;
return comment;
}

@@ -132,354 +137,360 @@

export default () => {
/**
* 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)
);
/**
* 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)
);
if (Parser.acornJsx) {
Object.assign(tokTypes, Parser.acornJsx.tokTypes);
}
if (Parser.acornJsx) {
Object.assign(tokTypes, Parser.acornJsx.tokTypes);
}
return class Espree extends Parser {
/**
* @param {Options | null | undefined} opts The parser options
* @param {string | object} code The code which will be converted to a string.
*/
constructor(opts, code) {
if (typeof opts !== "object" || opts === null) {
opts = {};
}
if (typeof code !== "string" && !(code instanceof String)) {
code = String(code);
}
return class Espree extends Parser {
// 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,
/**
* @param {Options | null | undefined} opts The parser options
* @param {string | object} code The code which will be converted to a string.
*/
constructor(opts, code) {
if (typeof opts !== "object" || opts === null) {
opts = {};
}
if (typeof code !== "string" && !(code instanceof String)) {
code = String(code);
}
// @ts-expect-error Appears to be a TS bug since the type is indeed string|String
code,
)
: null;
// 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,
/**
* 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: [],
};
// @ts-expect-error Appears to be a TS bug since the type is indeed string|String
code
)
: null;
// Initialize acorn parser.
super(
{
// 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,
/**
* 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: []
};
// Truthy value is true for backward compatibility.
allowReturnOutsideFunction:
options.allowReturnOutsideFunction,
// Initialize acorn parser.
super({
// Collect tokens
onToken(token) {
if (tokenTranslator) {
// Use `tokens`, `ecmaVersion`, and `jsxAttrValueToken` in the state.
tokenTranslator.onToken(
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,
/**
* @type {Omit<State, "tokens"> & {
* tokens: EsprimaToken[]
* }}
*/
(state),
);
}
if (token.type !== tokTypes.eof) {
state.lastToken = token;
}
},
// Truthy value is true for backward compatibility.
allowReturnOutsideFunction: options.allowReturnOutsideFunction,
// Collect comments
onComment(block, text, start, end, startLoc, endLoc) {
if (state.comments) {
const comment =
convertAcornCommentToEsprimaComment(
block,
text,
start,
end,
startLoc,
endLoc,
// Collect tokens
onToken(token) {
if (tokenTranslator) {
// @ts-expect-error Appears to be a TS bug
// since the type is indeed string|String
code,
);
// Use `tokens`, `ecmaVersion`, and `jsxAttrValueToken` in the state.
tokenTranslator.onToken(
token,
state.comments.push(comment);
}
},
},
// @ts-expect-error Appears to be a TS bug
// since the type is indeed string|String
code,
);
/**
* @type {Omit<State, "tokens"> & {
* tokens: EsprimaToken[]
* }}
*/
(state)
);
}
if (token.type !== tokTypes.eof) {
state.lastToken = token;
}
},
/*
* 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;
}
// Collect comments
onComment(block, text, start, end, startLoc, endLoc) {
if (state.comments) {
const comment = convertAcornCommentToEsprimaComment(
block,
text,
start,
end,
startLoc,
endLoc,
/**
* Returns Espree tokens.
* @returns {EsprimaTokens} The Esprima-compatible tokens
*/
tokenize() {
do {
this.next();
} while (this.type !== tokTypes.eof);
// @ts-expect-error Appears to be a TS bug
// since the type is indeed string|String
code
);
// Consume the final eof token
this.next();
state.comments.push(comment);
}
}
const extra = this[STATE];
const tokens = /** @type {EsprimaTokens} */ (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;
}
/*
* 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);
/**
* 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);
// Consume the final eof token
this.next();
return this[ESPRIMA_FINISH_NODE](result);
}
const extra = this[STATE];
const tokens = /** @type {EsprimaTokens} */ (extra.tokens);
/**
* 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);
if (extra.comments) {
tokens.comments = extra.comments;
}
return this[ESPRIMA_FINISH_NODE](result);
}
return tokens;
}
/**
* Parses.
* @returns {EsprimaProgramNode} The program Node
*/
parse() {
const extra = this[STATE];
const prog = 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);
const program = /** @type {EsprimaProgramNode} */ (prog);
return this[ESPRIMA_FINISH_NODE](result);
}
// @ts-expect-error TS bug? We've already converted to `EsprimaProgramNode`
program.sourceType = extra.originalSourceType;
/**
* 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);
if (extra.comments) {
program.comments = extra.comments;
}
if (extra.tokens) {
program.tokens = extra.tokens;
}
return this[ESPRIMA_FINISH_NODE](result);
}
/*
* 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;
/**
* Parses.
* @returns {EsprimaProgramNode} The program Node
*/
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;
/**
* 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);
}
templateElement.start += startOffset;
templateElement.end += endOffset;
/**
* 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)
);
if (templateElement.range) {
templateElement.range[0] += startOffset;
templateElement.range[1] += endOffset;
}
err.index = pos;
err.lineNumber = loc.line;
err.column = loc.column + 1; // acorn uses 0-based columns
throw err;
}
if (templateElement.loc) {
templateElement.loc.start.column += startOffset;
templateElement.loc.end.column += endOffset;
}
});
/**
* 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);
}
return program;
}
/**
* 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";
/**
* 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);
}
if (pos !== null && pos !== void 0) {
this.pos = pos;
/**
* 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)
);
if (this.options.locations) {
while (this.pos < this.lineStart) {
this.lineStart =
this.input.lastIndexOf(
"\n",
this.lineStart - 2,
) + 1;
--this.curLine;
}
}
err.index = pos;
err.lineNumber = loc.line;
err.column = loc.column + 1; // acorn uses 0-based columns
throw err;
}
this.nextToken();
}
/**
* 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 (this.end > this.start) {
message += ` ${this.input.slice(this.start, this.end)}`;
}
/**
* 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";
this.raise(this.start, message);
}
if (pos !== null && pos !== void 0) {
this.pos = pos;
/**
* 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}
*/ // eslint-disable-next-line camelcase -- required by API
jsx_readString(quote) {
const result = super.jsx_readString(quote);
if (this.options.locations) {
while (this.pos < this.lineStart) {
this.lineStart = this.input.lastIndexOf("\n", this.lineStart - 2) + 1;
--this.curLine;
}
}
if (this.type === tokTypes.string) {
this[STATE].jsxAttrValueToken = true;
}
return result;
}
this.nextToken();
}
/**
* 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) {
// 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") {
// save template element references to fix start/end later
this[STATE].templateElements.push(
/** @type {acorn.TemplateElement} */
(result),
);
}
if (this.end > this.start) {
message += ` ${this.input.slice(this.start, this.end)}`;
}
if (
result.type.includes("Function") &&
!("generator" in result)
) {
/**
* @type {acorn.FunctionDeclaration|acorn.FunctionExpression|
* acorn.ArrowFunctionExpression}
*/
(result).generator = false;
}
this.raise(this.start, message);
}
/**
* 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;
}
/**
* 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) {
// 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") {
// save template element references to fix start/end later
this[STATE].templateElements.push(
/** @type {acorn.TemplateElement} */
(result)
);
}
if (result.type.includes("Function") && (!("generator" in result))) {
/**
* @type {acorn.FunctionDeclaration|acorn.FunctionExpression|
* acorn.ArrowFunctionExpression}
*/
(result).generator = false;
}
return result;
}
};
};
return result;
}
};
};
};

@@ -12,11 +12,10 @@ /**

export default {
// React JSX parsing
jsx: false,
// React JSX parsing
jsx: false,
// allow return statement in global scope
globalReturn: false,
// allow return statement in global scope
globalReturn: false,
// allow implied strict mode
impliedStrict: false
// allow implied strict mode
impliedStrict: false,
};

@@ -15,16 +15,16 @@ /**

const SUPPORTED_VERSIONS = /** @type {const} */ ([
3,
5,
6, // 2015
7, // 2016
8, // 2017
9, // 2018
10, // 2019
11, // 2020
12, // 2021
13, // 2022
14, // 2023
15, // 2024
16, // 2025
17 // 2026
3,
5,
6, // 2015
7, // 2016
8, // 2017
9, // 2018
10, // 2019
11, // 2020
12, // 2021
13, // 2022
14, // 2023
15, // 2024
16, // 2025
17, // 2026
]);

@@ -37,7 +37,7 @@

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 */
);
/* 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 */
);

@@ -49,3 +49,3 @@ /**

export function getLatestEcmaVersion() {
return LATEST_ECMA_VERSION;
return LATEST_ECMA_VERSION;
}

@@ -58,3 +58,3 @@

export function getSupportedEcmaVersions() {
return [...SUPPORTED_VERSIONS];
return [...SUPPORTED_VERSIONS];
}

@@ -69,24 +69,27 @@

function normalizeEcmaVersion(ecmaVersion = 5) {
let version =
ecmaVersion === "latest" ? getLatestEcmaVersion() : ecmaVersion;
let version = ecmaVersion === "latest" ? getLatestEcmaVersion() : ecmaVersion;
if (typeof version !== "number") {
throw new Error(
`ecmaVersion must be a number or "latest". Received value of type ${typeof ecmaVersion} instead.`,
);
}
if (typeof version !== "number") {
throw new Error(`ecmaVersion must be a number or "latest". Received value of type ${typeof ecmaVersion} instead.`);
}
// Calculate ECMAScript edition number from official year version starting with
// ES2015, which corresponds with ES6 (or a difference of 2009).
if (version >= 2015) {
version -= 2009;
}
// Calculate ECMAScript edition number from official year version starting with
// ES2015, which corresponds with ES6 (or a difference of 2009).
if (version >= 2015) {
version -= 2009;
}
if (
!SUPPORTED_VERSIONS.includes(
/** @type {NormalizedEcmaVersion} */
(version),
)
) {
throw new Error("Invalid ecmaVersion.");
}
if (!SUPPORTED_VERSIONS.includes(
/** @type {NormalizedEcmaVersion} */
(version)
)) {
throw new Error("Invalid ecmaVersion.");
}
return /** @type {NormalizedEcmaVersion} */ (version);
return /** @type {NormalizedEcmaVersion} */ (version);
}

@@ -101,11 +104,11 @@

function normalizeSourceType(sourceType = "script") {
if (sourceType === "script" || sourceType === "module") {
return sourceType;
}
if (sourceType === "script" || sourceType === "module") {
return sourceType;
}
if (sourceType === "commonjs") {
return "script";
}
if (sourceType === "commonjs") {
return "script";
}
throw new Error("Invalid sourceType.");
throw new Error("Invalid sourceType.");
}

@@ -140,32 +143,41 @@

export function normalizeOptions(options) {
const ecmaVersion = normalizeEcmaVersion(options.ecmaVersion);
const sourceType = normalizeSourceType(options.sourceType);
const ranges = options.range === true;
const locations = options.loc === true;
const ecmaVersion = normalizeEcmaVersion(options.ecmaVersion);
const sourceType = normalizeSourceType(options.sourceType);
const ranges = options.range === true;
const locations = options.loc === true;
if (ecmaVersion !== 3 && options.allowReserved) {
if (ecmaVersion !== 3 && options.allowReserved) {
// a value of `false` is intentionally allowed here, so a shared config can overwrite it when needed
throw new Error(
"`allowReserved` is only supported when ecmaVersion is 3",
);
}
if (
typeof options.allowReserved !== "undefined" &&
typeof options.allowReserved !== "boolean"
) {
throw new Error(
"`allowReserved`, when present, must be `true` or `false`",
);
}
const allowReserved =
ecmaVersion === 3 ? options.allowReserved || "never" : false;
const ecmaFeatures = options.ecmaFeatures || {};
const allowReturnOutsideFunction =
options.sourceType === "commonjs" || Boolean(ecmaFeatures.globalReturn);
// a value of `false` is intentionally allowed here, so a shared config can overwrite it when needed
throw new Error("`allowReserved` is only supported when ecmaVersion is 3");
}
if (typeof options.allowReserved !== "undefined" && typeof options.allowReserved !== "boolean") {
throw new Error("`allowReserved`, when present, must be `true` or `false`");
}
const allowReserved = ecmaVersion === 3 ? (options.allowReserved || "never") : false;
const ecmaFeatures = options.ecmaFeatures || {};
const allowReturnOutsideFunction = options.sourceType === "commonjs" ||
Boolean(ecmaFeatures.globalReturn);
if (sourceType === "module" && ecmaVersion < 6) {
throw new Error(
"sourceType 'module' is not supported when ecmaVersion < 2015. Consider adding `{ ecmaVersion: 2015 }` to the parser options.",
);
}
if (sourceType === "module" && ecmaVersion < 6) {
throw new Error("sourceType 'module' is not supported when ecmaVersion < 2015. Consider adding `{ ecmaVersion: 2015 }` to the parser options.");
}
return Object.assign({}, options, {
ecmaVersion,
sourceType,
ranges,
locations,
allowReserved,
allowReturnOutsideFunction
});
return Object.assign({}, options, {
ecmaVersion,
sourceType,
ranges,
locations,
allowReserved,
allowReturnOutsideFunction,
});
}

@@ -42,15 +42,15 @@ /**

const Token = {
Boolean: "Boolean",
EOF: "<end>",
Identifier: "Identifier",
PrivateIdentifier: "PrivateIdentifier",
Keyword: "Keyword",
Null: "Null",
Numeric: "Numeric",
Punctuator: "Punctuator",
String: "String",
RegularExpression: "RegularExpression",
Template: "Template",
JSXIdentifier: "JSXIdentifier",
JSXText: "JSXText"
Boolean: "Boolean",
EOF: "<end>",
Identifier: "Identifier",
PrivateIdentifier: "PrivateIdentifier",
Keyword: "Keyword",
Null: "Null",
Numeric: "Numeric",
Punctuator: "Punctuator",
String: "String",
RegularExpression: "RegularExpression",
Template: "Template",
JSXIdentifier: "JSXIdentifier",
JSXText: "JSXText",
};

@@ -66,31 +66,28 @@

function convertTemplatePart(tokens, code) {
const firstToken = tokens[0],
lastTemplateToken =
/**
* @type {acorn.Token & {
* loc: acorn.SourceLocation,
* range: [number, number]
* }}
*/ (tokens.at(-1));
const firstToken = tokens[0],
lastTemplateToken =
/** @type {acorn.Token & { loc: acorn.SourceLocation, range: [number, number] }} */ (
tokens.at(-1)
);
/** @type {EsprimaToken} */
const token = {
type: Token.Template,
value: code.slice(firstToken.start, lastTemplateToken.end)
};
/** @type {EsprimaToken} */
const token = {
type: Token.Template,
value: code.slice(firstToken.start, lastTemplateToken.end),
};
if (firstToken.loc) {
token.loc = {
start: firstToken.loc.start,
end: lastTemplateToken.loc.end
};
}
if (firstToken.loc) {
token.loc = {
start: firstToken.loc.start,
end: lastTemplateToken.loc.end,
};
}
if (firstToken.range) {
token.start = firstToken.range[0];
token.end = lastTemplateToken.range[1];
token.range = [token.start, token.end];
}
if (firstToken.range) {
token.start = firstToken.range[0];
token.end = lastTemplateToken.range[1];
token.range = [token.start, token.end];
}
return token;
return token;
}

@@ -103,201 +100,204 @@

class TokenTranslator {
/**
* 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 */
/**
* 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 types
this._acornTokTypes = acornTokTypes;
// token types
this._acornTokTypes = acornTokTypes;
// token buffer for templates
/** @type {acorn.Token[]} */
this._tokens = [];
// token buffer for templates
/** @type {acorn.Token[]} */
this._tokens = [];
// track the last curly brace
this._curlyBrace = null;
// track the last curly brace
this._curlyBrace = null;
// the source code
this._code = code;
}
// the source code
this._code = code;
/**
* Translates a single Esprima token to a single Acorn token. This may be
* inaccurate due to how templates are handled differently in Esprima and
* Acorn, but should be accurate for all other tokens.
* @param {acorn.Token} token The Acorn token to translate.
* @param {ExtraNoTokens} extra Espree extra object.
* @returns {EsprimaToken} The Esprima version of the token.
*/
translate(token, extra) {
const type = token.type,
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) {
newToken.type = Token.Identifier;
/**
* Translates a single Esprima token to a single Acorn token. This may be
* inaccurate due to how templates are handled differently in Esprima and
* Acorn, but should be accurate for all other tokens.
* @param {acorn.Token} token The Acorn token to translate.
* @param {ExtraNoTokens} extra Espree extra object.
* @returns {EsprimaToken} The Esprima version of the token.
*/
translate(token, extra) {
// TODO: See if this is an Acorn bug
if ("value" in token && token.value === "static") {
newToken.type = Token.Keyword;
}
const type = token.type,
tt = this._acornTokTypes,
if (
extra.ecmaVersion > 5 &&
"value" in token &&
(token.value === "yield" || token.value === "let")
) {
newToken.type = Token.Keyword;
}
} else if (type === tt.privateId) {
newToken.type = Token.PrivateIdentifier;
} else if (
type === tt.semi ||
type === tt.comma ||
type === tt.parenL ||
type === tt.parenR ||
type === tt.braceL ||
type === tt.braceR ||
type === tt.dot ||
type === tt.bracketL ||
type === tt.colon ||
type === tt.question ||
type === tt.bracketR ||
type === tt.ellipsis ||
type === tt.arrow ||
type === tt.jsxTagStart ||
type === tt.incDec ||
type === tt.starstar ||
type === tt.jsxTagEnd ||
type === tt.prefix ||
type === tt.questionDot ||
("binop" in type && type.binop && !type.keyword) ||
("isAssign" in type && type.isAssign)
) {
newToken.type = Token.Punctuator;
newToken.value = this._code.slice(token.start, token.end);
} else if (type === tt.jsxName) {
newToken.type = Token.JSXIdentifier;
} else if (type.label === "jsxText" || type === tt.jsxAttrValueToken) {
newToken.type = Token.JSXText;
} else if (type.keyword) {
if (type.keyword === "true" || type.keyword === "false") {
newToken.type = Token.Boolean;
} else if (type.keyword === "null") {
newToken.type = Token.Null;
} else {
newToken.type = Token.Keyword;
}
} else if (type === tt.num) {
newToken.type = Token.Numeric;
newToken.value = this._code.slice(token.start, token.end);
} else if (type === tt.string) {
if (extra.jsxAttrValueToken) {
extra.jsxAttrValueToken = false;
newToken.type = Token.JSXText;
} else {
newToken.type = Token.String;
}
// 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);
newToken.value = this._code.slice(token.start, token.end);
} else if (type === tt.regexp) {
newToken.type = Token.RegularExpression;
const value = /** @type {{flags: string, pattern: string}} */ (
"value" in token && token.value
);
if (type === tt.name) {
newToken.type = Token.Identifier;
newToken.regex = {
flags: value.flags,
pattern: value.pattern,
};
newToken.value = `/${value.pattern}/${value.flags}`;
}
// TODO: See if this is an Acorn bug
if ("value" in token && token.value === "static") {
newToken.type = Token.Keyword;
}
return newToken;
}
if (extra.ecmaVersion > 5 && ("value" in token && (token.value === "yield" || token.value === "let"))) {
newToken.type = Token.Keyword;
}
/**
* Function to call during Acorn's onToken handler.
* @param {acorn.Token} token The Acorn token.
* @param {Extra} extra The Espree extra object.
* @returns {void}
*/
onToken(token, extra) {
const tt = this._acornTokTypes,
tokens = extra.tokens,
templateTokens = this._tokens;
} else if (type === tt.privateId) {
newToken.type = Token.PrivateIdentifier;
/**
* Flushes the buffered template tokens and resets the template
* tracking.
* @returns {void}
* @private
*/
const translateTemplateTokens = () => {
tokens.push(convertTemplatePart(this._tokens, this._code));
this._tokens = [];
};
} else if (type === tt.semi || type === tt.comma ||
type === tt.parenL || type === tt.parenR ||
type === tt.braceL || type === tt.braceR ||
type === tt.dot || type === tt.bracketL ||
type === tt.colon || type === tt.question ||
type === tt.bracketR || type === tt.ellipsis ||
type === tt.arrow || type === tt.jsxTagStart ||
type === tt.incDec || type === tt.starstar ||
type === tt.jsxTagEnd || type === tt.prefix ||
type === tt.questionDot ||
("binop" in type && type.binop && !type.keyword) ||
("isAssign" in type && type.isAssign)) {
if (token.type === tt.eof) {
// might be one last curlyBrace
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
}
newToken.type = Token.Punctuator;
newToken.value = this._code.slice(token.start, token.end);
} else if (type === tt.jsxName) {
newToken.type = Token.JSXIdentifier;
} else if (type.label === "jsxText" || type === tt.jsxAttrValueToken) {
newToken.type = Token.JSXText;
} else if (type.keyword) {
if (type.keyword === "true" || type.keyword === "false") {
newToken.type = Token.Boolean;
} else if (type.keyword === "null") {
newToken.type = Token.Null;
} else {
newToken.type = Token.Keyword;
}
} else if (type === tt.num) {
newToken.type = Token.Numeric;
newToken.value = this._code.slice(token.start, token.end);
} else if (type === tt.string) {
return;
}
if (extra.jsxAttrValueToken) {
extra.jsxAttrValueToken = false;
newToken.type = Token.JSXText;
} else {
newToken.type = Token.String;
}
if (token.type === tt.backQuote) {
// if there's already a curly, it's not part of the template
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
this._curlyBrace = null;
}
newToken.value = this._code.slice(token.start, token.end);
} else if (type === tt.regexp) {
newToken.type = Token.RegularExpression;
const value = /** @type {{flags: string, pattern: string}} */ (
"value" in token && token.value
);
templateTokens.push(token);
newToken.regex = {
flags: value.flags,
pattern: value.pattern
};
newToken.value = `/${value.pattern}/${value.flags}`;
}
// it's the end
if (templateTokens.length > 1) {
translateTemplateTokens();
}
return newToken;
}
return;
}
if (token.type === tt.dollarBraceL) {
templateTokens.push(token);
translateTemplateTokens();
return;
}
if (token.type === tt.braceR) {
// if there's already a curly, it's not part of the template
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
}
/**
* Function to call during Acorn's onToken handler.
* @param {acorn.Token} token The Acorn token.
* @param {Extra} extra The Espree extra object.
* @returns {void}
*/
onToken(token, extra) {
// store new curly for later
this._curlyBrace = token;
return;
}
if (token.type === tt.template || token.type === tt.invalidTemplate) {
if (this._curlyBrace) {
templateTokens.push(this._curlyBrace);
this._curlyBrace = null;
}
const tt = this._acornTokTypes,
tokens = extra.tokens,
templateTokens = this._tokens;
templateTokens.push(token);
return;
}
/**
* Flushes the buffered template tokens and resets the template
* tracking.
* @returns {void}
* @private
*/
const translateTemplateTokens = () => {
tokens.push(convertTemplatePart(this._tokens, this._code));
this._tokens = [];
};
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
this._curlyBrace = null;
}
if (token.type === tt.eof) {
// might be one last curlyBrace
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
}
return;
}
if (token.type === tt.backQuote) {
// if there's already a curly, it's not part of the template
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
this._curlyBrace = null;
}
templateTokens.push(token);
// it's the end
if (templateTokens.length > 1) {
translateTemplateTokens();
}
return;
}
if (token.type === tt.dollarBraceL) {
templateTokens.push(token);
translateTemplateTokens();
return;
}
if (token.type === tt.braceR) {
// if there's already a curly, it's not part of the template
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
}
// store new curly for later
this._curlyBrace = token;
return;
}
if (token.type === tt.template || token.type === tt.invalidTemplate) {
if (this._curlyBrace) {
templateTokens.push(this._curlyBrace);
this._curlyBrace = null;
}
templateTokens.push(token);
return;
}
if (this._curlyBrace) {
tokens.push(this.translate(this._curlyBrace, extra));
this._curlyBrace = null;
}
tokens.push(this.translate(token, extra));
}
tokens.push(this.translate(token, extra));
}
}

@@ -304,0 +304,0 @@

@@ -21,3 +21,3 @@ {

},
"version": "11.1.0",
"version": "11.1.1",
"files": [

@@ -42,12 +42,9 @@ "lib",

"dependencies": {
"acorn": "^8.15.0",
"acorn": "^8.16.0",
"acorn-jsx": "^5.3.2",
"eslint-visitor-keys": "^5.0.0"
"eslint-visitor-keys": "^5.0.1"
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.18.2",
"rollup": "^2.79.1",
"shelljs": "^0.8.5",
"tsd": "^0.33.0",
"typescript": "^5.9.3"
"tsd": "^0.33.0"
},

@@ -73,3 +70,4 @@ "keywords": [

"test:types": "tsd --typings dist/espree.d.ts"
}
},
"sideEffects": false
}
+40
-41

@@ -131,37 +131,36 @@ [![npm version](https://img.shields.io/npm/v/espree.svg)](https://www.npmjs.com/package/espree)

const options = {
// attach range information to each node
range: false,
// attach range information to each node
range: false,
// attach line/column location information to each node
loc: false,
// attach line/column location information to each node
loc: false,
// create a top-level comments array containing all comments
comment: false,
// create a top-level comments array containing all comments
comment: false,
// create a top-level tokens array containing all tokens
tokens: false,
// create a top-level tokens array containing all tokens
tokens: false,
// Set to 3, 5 (the default), 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 or 17 to specify the version of ECMAScript syntax you want to use.
// You can also set to 2015 (same as 6), 2016 (same as 7), 2017 (same as 8), 2018 (same as 9), 2019 (same as 10), 2020 (same as 11), 2021 (same as 12), 2022 (same as 13), 2023 (same as 14), 2024 (same as 15), 2025 (same as 16) or 2026 (same as 17) to use the year-based naming.
// You can also set "latest" to use the most recently supported version.
ecmaVersion: 3,
// Set to 3, 5 (the default), 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 or 17 to specify the version of ECMAScript syntax you want to use.
// You can also set to 2015 (same as 6), 2016 (same as 7), 2017 (same as 8), 2018 (same as 9), 2019 (same as 10), 2020 (same as 11), 2021 (same as 12), 2022 (same as 13), 2023 (same as 14), 2024 (same as 15), 2025 (same as 16) or 2026 (same as 17) to use the year-based naming.
// You can also set "latest" to use the most recently supported version.
ecmaVersion: 3,
allowReserved: true, // only allowed when ecmaVersion is 3
allowReserved: true, // only allowed when ecmaVersion is 3
// specify which type of script you're parsing ("script", "module", or "commonjs")
sourceType: "script",
// specify which type of script you're parsing ("script", "module", or "commonjs")
sourceType: "script",
// specify additional language features
ecmaFeatures: {
// specify additional language features
ecmaFeatures: {
// enable JSX parsing
jsx: false,
// enable JSX parsing
jsx: false,
// enable return in global scope (set to true automatically when sourceType is "commonjs")
globalReturn: false,
// enable return in global scope (set to true automatically when sourceType is "commonjs")
globalReturn: false,
// enable implied strict mode (if ecmaVersion >= 5)
impliedStrict: false
}
}
// enable implied strict mode (if ecmaVersion >= 5)
impliedStrict: false,
},
};
```

@@ -187,12 +186,12 @@

* `npm test` - run all tests
* `npm run lint` - run all linting
- `npm test` - run all tests
- `npm run lint` - run all linting
## Differences from Espree 2.x
* The `tokenize()` method does not use `ecmaFeatures`. Any string will be tokenized completely based on ECMAScript 6 semantics.
* Trailing whitespace no longer is counted as part of a node.
* `let` and `const` declarations are no longer parsed by default. You must opt-in by using an `ecmaVersion` newer than `5` or setting `sourceType` to `module`.
* The `esparse` and `esvalidate` binary scripts have been removed.
* There is no `tolerant` option. We will investigate adding this back in the future.
- The `tokenize()` method does not use `ecmaFeatures`. Any string will be tokenized completely based on ECMAScript 6 semantics.
- Trailing whitespace no longer is counted as part of a node.
- `let` and `const` declarations are no longer parsed by default. You must opt-in by using an `ecmaVersion` newer than `5` or setting `sourceType` to `module`.
- The `esparse` and `esvalidate` binary scripts have been removed.
- There is no `tolerant` option. We will investigate adding this back in the future.

@@ -205,10 +204,10 @@ ## Known Incompatibilities

* Esprima counts trailing whitespace as part of each AST node while Espree does not. In Espree, the end of a node is where the last token occurs.
* Espree does not parse `let` and `const` declarations by default.
* Error messages returned for parsing errors are different.
* There are two addition properties on every node and token: `start` and `end`. These represent the same data as `range` and are used internally by Acorn.
- Esprima counts trailing whitespace as part of each AST node while Espree does not. In Espree, the end of a node is where the last token occurs.
- Espree does not parse `let` and `const` declarations by default.
- Error messages returned for parsing errors are different.
- There are two addition properties on every node and token: `start` and `end`. These represent the same data as `range` and are used internally by Acorn.
### Esprima 2.x
* Esprima 2.x uses a different comment attachment algorithm that results in some comments being added in different places than Espree. The algorithm Espree uses is the same one used in Esprima 1.2.2.
- Esprima 2.x uses a different comment attachment algorithm that results in some comments being added in different places than Espree. The algorithm Espree uses is the same one used in Esprima 1.2.2.

@@ -241,3 +240,3 @@ ## Frequently Asked Questions

* [Explicit Resource Management](https://github.com/tc39/proposal-explicit-resource-management)
- [Explicit Resource Management](https://github.com/tc39/proposal-explicit-resource-management)

@@ -261,4 +260,4 @@ See [finished-proposals.md](https://github.com/tc39/proposals/blob/master/finished-proposals.md) to know what features are finalized.

<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/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>
<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://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://opensource.sap.com"><img src="https://avatars.githubusercontent.com/u/2531208" alt="SAP" 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://depot.dev"><img src="https://images.opencollective.com/depot/39125a1/logo.png" alt="Depot" 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://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="TestMu AI Open Source Office (Formerly LambdaTest)" height="32"></a></p>
<h3>Technology Sponsors</h3>

@@ -265,0 +264,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.

Sorry, the diff of this file is not supported yet