vue-eslint-parser
Version:
The ESLint custom parser for `.vue` files.
1,398 lines (1,376 loc) • 286 kB
JavaScript
/**
* @author Toru Nagashima <https://github.com/mysticatea>
* See LICENSE file in root directory for full license.
*/
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var path = require('path');
var Evk = require('eslint-visitor-keys');
var sortedLastIndex = require('lodash/sortedLastIndex');
var assert = require('assert');
var last = require('lodash/last');
var findLastIndex = require('lodash/findLastIndex');
var debugFactory = require('debug');
var first = require('lodash/first');
var sortedIndexBy = require('lodash/sortedIndexBy');
var escope = require('eslint-scope');
var semver = require('semver');
var module$1 = require('module');
var dependencyEspree = require('espree');
var sortedLastIndexBy = require('lodash/sortedLastIndexBy');
var EventEmitter = require('events');
var esquery = require('esquery');
var union = require('lodash/union');
var intersection = require('lodash/intersection');
var memoize = require('lodash/memoize');
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);
}
var path__namespace = /*#__PURE__*/_interopNamespace(path);
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
var Evk__namespace = /*#__PURE__*/_interopNamespace(Evk);
var sortedLastIndex__default = /*#__PURE__*/_interopDefaultLegacy(sortedLastIndex);
var assert__default = /*#__PURE__*/_interopDefaultLegacy(assert);
var last__default = /*#__PURE__*/_interopDefaultLegacy(last);
var findLastIndex__default = /*#__PURE__*/_interopDefaultLegacy(findLastIndex);
var debugFactory__default = /*#__PURE__*/_interopDefaultLegacy(debugFactory);
var first__default = /*#__PURE__*/_interopDefaultLegacy(first);
var sortedIndexBy__default = /*#__PURE__*/_interopDefaultLegacy(sortedIndexBy);
var escope__namespace = /*#__PURE__*/_interopNamespace(escope);
var dependencyEspree__namespace = /*#__PURE__*/_interopNamespace(dependencyEspree);
var sortedLastIndexBy__default = /*#__PURE__*/_interopDefaultLegacy(sortedLastIndexBy);
var EventEmitter__default = /*#__PURE__*/_interopDefaultLegacy(EventEmitter);
var esquery__default = /*#__PURE__*/_interopDefaultLegacy(esquery);
var union__default = /*#__PURE__*/_interopDefaultLegacy(union);
var intersection__default = /*#__PURE__*/_interopDefaultLegacy(intersection);
var memoize__default = /*#__PURE__*/_interopDefaultLegacy(memoize);
function isAcornStyleParseError(x) {
return (typeof x.message === "string" &&
typeof x.pos === "number" &&
typeof x.loc === "object" &&
x.loc !== null &&
typeof x.loc.line === "number" &&
typeof x.loc.column === "number");
}
function isTSError(x) {
return (!(x instanceof ParseError) &&
typeof x.message === "string" &&
typeof x.index === "number" &&
typeof x.lineNumber === "number" &&
typeof x.column === "number" &&
x.name === "TSError");
}
class ParseError extends SyntaxError {
code;
index;
lineNumber;
column;
static fromCode(code, offset, line, column) {
return new ParseError(code, code, offset, line, column);
}
static normalize(x) {
if (isTSError(x)) {
return new ParseError(x.message, undefined, x.index, x.lineNumber, x.column);
}
if (ParseError.isParseError(x)) {
return x;
}
if (isAcornStyleParseError(x)) {
return new ParseError(x.message, undefined, x.pos, x.loc.line, x.loc.column);
}
return null;
}
constructor(message, code, offset, line, column) {
super(message);
this.code = code;
this.index = offset;
this.lineNumber = line;
this.column = column;
}
static isParseError(x) {
return (x instanceof ParseError ||
(typeof x.message === "string" &&
typeof x.index === "number" &&
typeof x.lineNumber === "number" &&
typeof x.column === "number"));
}
}
const NS = Object.freeze({
HTML: "http://www.w3.org/1999/xhtml",
MathML: "http://www.w3.org/1998/Math/MathML",
SVG: "http://www.w3.org/2000/svg",
XLink: "http://www.w3.org/1999/xlink",
XML: "http://www.w3.org/XML/1998/namespace",
XMLNS: "http://www.w3.org/2000/xmlns/",
});
const KEYS = Evk__namespace.unionWith({
VAttribute: ["key", "value"],
VDirectiveKey: ["name", "argument", "modifiers"],
VDocumentFragment: ["children"],
VElement: ["startTag", "children", "endTag"],
VEndTag: [],
VExpressionContainer: ["expression"],
VFilter: ["callee", "arguments"],
VFilterSequenceExpression: ["expression", "filters"],
VForExpression: ["left", "right"],
VIdentifier: [],
VLiteral: [],
VOnExpression: ["body"],
VSlotScopeExpression: ["params"],
VStartTag: ["attributes"],
VText: [],
VGenericExpression: ["params"],
});
function fallbackKeysFilter(key) {
let value = null;
return (key !== "comments" &&
key !== "leadingComments" &&
key !== "loc" &&
key !== "parent" &&
key !== "range" &&
key !== "tokens" &&
key !== "trailingComments" &&
(value = this[key]) !== null &&
typeof value === "object" &&
(typeof value.type === "string" || Array.isArray(value)));
}
function getFallbackKeys(node) {
return Object.keys(node).filter(fallbackKeysFilter, node);
}
function isNode(x) {
return x !== null && typeof x === "object" && typeof x.type === "string";
}
function traverse(node, parent, visitor) {
let i = 0;
let j = 0;
visitor.enterNode(node, parent);
const keys = (visitor.visitorKeys ?? KEYS)[node.type] ?? getFallbackKeys(node);
for (i = 0; i < keys.length; ++i) {
const child = node[keys[i]];
if (Array.isArray(child)) {
for (j = 0; j < child.length; ++j) {
if (isNode(child[j])) {
traverse(child[j], node, visitor);
}
}
}
else if (isNode(child)) {
traverse(child, node, visitor);
}
}
visitor.leaveNode(node, parent);
}
function traverseNodes(node, visitor) {
traverse(node, null, visitor);
}
var index = /*#__PURE__*/Object.freeze({
__proto__: null,
ParseError: ParseError,
NS: NS,
KEYS: KEYS,
traverseNodes: traverseNodes,
getFallbackKeys: getFallbackKeys
});
class LinesAndColumns {
ltOffsets;
constructor(ltOffsets) {
this.ltOffsets = ltOffsets;
}
getLocFromIndex(index) {
const line = sortedLastIndex__default["default"](this.ltOffsets, index) + 1;
const column = index - (line === 1 ? 0 : this.ltOffsets[line - 2]);
return { line, column };
}
createOffsetLocationCalculator(offset) {
return {
getFixOffset() {
return offset;
},
getLocFromIndex: this.getLocFromIndex.bind(this),
};
}
}
class LocationCalculatorForHtml extends LinesAndColumns {
gapOffsets;
baseOffset;
baseIndexOfGap;
shiftOffset;
constructor(gapOffsets, ltOffsets, baseOffset, shiftOffset = 0) {
super(ltOffsets);
this.gapOffsets = gapOffsets;
this.ltOffsets = ltOffsets;
this.baseOffset = baseOffset ?? 0;
this.baseIndexOfGap =
this.baseOffset === 0
? 0
: sortedLastIndex__default["default"](gapOffsets, this.baseOffset);
this.shiftOffset = shiftOffset;
}
getSubCalculatorAfter(offset) {
return new LocationCalculatorForHtml(this.gapOffsets, this.ltOffsets, this.baseOffset + offset, this.shiftOffset);
}
getSubCalculatorShift(offset) {
return new LocationCalculatorForHtml(this.gapOffsets, this.ltOffsets, this.baseOffset, this.shiftOffset + offset);
}
_getGap(index) {
const offsets = this.gapOffsets;
let g0 = sortedLastIndex__default["default"](offsets, index + this.baseOffset);
let pos = index + this.baseOffset + g0 - this.baseIndexOfGap;
while (g0 < offsets.length && offsets[g0] <= pos) {
g0 += 1;
pos += 1;
}
return g0 - this.baseIndexOfGap;
}
getLocation(index) {
return this.getLocFromIndex(this.getOffsetWithGap(index));
}
getOffsetWithGap(index) {
return index + this.getFixOffset(index);
}
getFixOffset(offset) {
const shiftOffset = this.shiftOffset;
const gap = this._getGap(offset + shiftOffset);
return this.baseOffset + gap + shiftOffset;
}
}
const debug = debugFactory__default["default"]("vue-eslint-parser");
function isScriptElement(node) {
return node.type === "VElement" && node.name === "script";
}
function isScriptSetupElement(script) {
return (isScriptElement(script) &&
script.startTag.attributes.some((attr) => !attr.directive && attr.key.name === "setup"));
}
function isTemplateElement(node) {
return node.type === "VElement" && node.name === "template";
}
function isStyleElement(node) {
return node.type === "VElement" && node.name === "style";
}
function getOwnerDocument(leafNode) {
let node = leafNode;
while (node != null && node.type !== "VDocumentFragment") {
node = node.parent;
}
return node;
}
function isLang(attribute) {
return attribute.directive === false && attribute.key.name === "lang";
}
function getLang(element) {
const langAttr = element?.startTag.attributes.find(isLang);
const lang = langAttr?.value?.value;
return lang || null;
}
function isTSLang(element) {
const lang = getLang(element);
return lang === "ts" || lang === "tsx";
}
function findGenericDirective(element) {
return (element.startTag.attributes.find((attr) => attr.directive &&
attr.value?.expression?.type === "VGenericExpression") || null);
}
function isParserObject(value) {
return isEnhancedParserObject(value) || isBasicParserObject(value);
}
function isEnhancedParserObject(value) {
return Boolean(value && typeof value.parseForESLint === "function");
}
function isBasicParserObject(value) {
return Boolean(value && typeof value.parse === "function");
}
function isSFCFile(parserOptions) {
if (parserOptions.filePath === "<input>") {
return true;
}
return path__namespace.extname(parserOptions.filePath || "unknown.vue") === ".vue";
}
function getScriptParser(parser, getParserLang) {
if (isParserObject(parser)) {
return parser;
}
if (parser && typeof parser === "object") {
const parserLang = getParserLang();
const parserLangs = parserLang == null
? []
: typeof parserLang === "string"
? [parserLang]
: parserLang;
for (const lang of parserLangs) {
const parserForLang = lang && parser[lang];
if (typeof parserForLang === "string" ||
isParserObject(parserForLang)) {
return parserForLang;
}
}
return parser.js;
}
return typeof parser === "string" ? parser : undefined;
}
function getParserLangFromSFC(doc) {
if (doc) {
const scripts = doc.children.filter(isScriptElement);
const script = (scripts.length === 2 && scripts.find(isScriptSetupElement)) ||
scripts[0];
if (script) {
return getLang(script);
}
}
return null;
}
let escopeCache = null;
function getEslintScope() {
return escopeCache ?? (escopeCache = getNewest());
}
function getNewest() {
let newest = escope__namespace;
const userEscope = getEslintScopeFromUser();
if (userEscope.version != null && semver.lte(newest.version, userEscope.version)) {
newest = userEscope;
}
return newest;
}
function getEslintScopeFromUser() {
try {
const cwd = process.cwd();
const relativeTo = path__default["default"].join(cwd, "__placeholder__.js");
return module$1.createRequire(relativeTo)("eslint-scope");
}
catch {
return escope__namespace;
}
}
let espreeCache = null;
function getEspree() {
return espreeCache ?? (espreeCache = getNewestEspree());
}
function getEcmaVersionIfUseEspree(parserOptions) {
if (parserOptions.parser != null && parserOptions.parser !== "espree") {
return undefined;
}
if (parserOptions.ecmaVersion === "latest" ||
parserOptions.ecmaVersion == null) {
return getDefaultEcmaVersion();
}
return normalizeEcmaVersion(parserOptions.ecmaVersion);
}
function getEspreeFromUser() {
try {
const cwd = process.cwd();
const relativeTo = path__default["default"].join(cwd, "__placeholder__.js");
return module$1.createRequire(relativeTo)("espree");
}
catch {
return dependencyEspree__namespace;
}
}
function getNewestEspree() {
let newest = dependencyEspree__namespace;
const userEspree = getEspreeFromUser();
if (userEspree.version != null && semver.lte(newest.version, userEspree.version)) {
newest = userEspree;
}
return newest;
}
function getDefaultEcmaVersion() {
return getLatestEcmaVersion(getEspree());
}
function normalizeEcmaVersion(version) {
if (version > 5 && version < 2015) {
return version + 2009;
}
return version;
}
function getLatestEcmaVersion(espree) {
return normalizeEcmaVersion(espree.latestEcmaVersion);
}
const DEFAULT_ECMA_VERSION = "latest";
const ANALYZE_SCOPE_DEFAULT_ECMA_VERSION = 2022;
function isUnique(reference, index, references) {
return (index === 0 || reference.identifier !== references[index - 1].identifier);
}
function hasDefinition(variable) {
return variable.defs.length >= 1;
}
function transformReference(reference) {
const ret = {
id: reference.identifier,
mode: reference.isReadOnly()
? "r"
: reference.isWriteOnly()
? "w"
: "rw",
variable: null,
isValueReference: reference.isValueReference,
isTypeReference: reference.isTypeReference,
};
Object.defineProperty(ret, "variable", { enumerable: false });
return ret;
}
function transformVariable(variable, kind) {
const ret = {
id: variable.defs[0].name,
kind,
references: [],
};
Object.defineProperty(ret, "references", { enumerable: false });
return ret;
}
function getForScope(scope) {
const child = scope.childScopes[0];
return child.block === scope.block ? child.childScopes[0] : child;
}
function analyzeScope(ast, parserOptions) {
const ecmaVersion = getEcmaVersionIfUseEspree(parserOptions) ??
ANALYZE_SCOPE_DEFAULT_ECMA_VERSION;
const ecmaFeatures = parserOptions.ecmaFeatures ?? {};
const sourceType = parserOptions.sourceType ?? "script";
const result = getEslintScope().analyze(ast, {
ignoreEval: true,
nodejsScope: false,
impliedStrict: ecmaFeatures.impliedStrict,
ecmaVersion,
sourceType,
fallback: getFallbackKeys,
});
return result;
}
function analyze(parserResult, parserOptions) {
const scopeManager = parserResult.scopeManager ||
analyzeScope(parserResult.ast, parserOptions);
return scopeManager.globalScope;
}
function analyzeExternalReferences(parserResult, parserOptions) {
const scope = analyze(parserResult, parserOptions);
return scope.through.filter(isUnique).map(transformReference);
}
function analyzeVariablesAndExternalReferences(parserResult, kind, parserOptions) {
const scope = analyze(parserResult, parserOptions);
return {
variables: getForScope(scope)
.variables.filter(hasDefinition)
.map((v) => transformVariable(v, kind)),
references: scope.through.filter(isUnique).map(transformReference),
};
}
function fixLocations(result, locationCalculator) {
fixNodeLocations(result.ast, result.visitorKeys, locationCalculator);
for (const token of result.ast.tokens ?? []) {
fixLocation(token, locationCalculator);
}
for (const comment of result.ast.comments ?? []) {
fixLocation(comment, locationCalculator);
}
}
function fixNodeLocations(rootNode, visitorKeys, locationCalculator) {
const traversed = new Map();
traverseNodes(rootNode, {
visitorKeys,
enterNode(node, parent) {
if (!traversed.has(node)) {
traversed.set(node, node);
node.parent = parent;
if (traversed.has(node.range)) {
if (!traversed.has(node.loc)) {
node.loc.start = locationCalculator.getLocFromIndex(node.range[0]);
node.loc.end = locationCalculator.getLocFromIndex(node.range[1]);
traversed.set(node.loc, node);
}
else if (node.start != null || node.end != null) {
const traversedNode = traversed.get(node.range);
if (traversedNode.type === node.type) {
node.start = traversedNode.start;
node.end = traversedNode.end;
}
}
}
else {
fixLocation(node, locationCalculator);
traversed.set(node.range, node);
traversed.set(node.loc, node);
}
}
},
leaveNode() {
},
});
}
function fixLocation(node, locationCalculator) {
const range = node.range;
const loc = node.loc;
const d0 = locationCalculator.getFixOffset(range[0], "start");
const d1 = locationCalculator.getFixOffset(range[1], "end");
if (d0 !== 0) {
range[0] += d0;
if (node.start != null) {
node.start += d0;
}
loc.start = locationCalculator.getLocFromIndex(range[0]);
}
if (d1 !== 0) {
range[1] += d1;
if (node.end != null) {
node.end += d0;
}
loc.end = locationCalculator.getLocFromIndex(range[1]);
}
return node;
}
function fixErrorLocation(error, locationCalculator) {
const diff = locationCalculator.getFixOffset(error.index, "start");
error.index += diff;
const loc = locationCalculator.getLocFromIndex(error.index);
error.lineNumber = loc.line;
error.column = loc.column;
}
function extractGeneric(element) {
const genericAttr = findGenericDirective(element);
if (!genericAttr) {
return null;
}
const genericNode = genericAttr.value.expression;
const defineTypes = genericNode.params.map((t, i) => ({
node: t,
define: `type ${t.name.name} = ${getConstraint(t, genericNode.rawParams[i])}`,
}));
return {
node: genericNode,
defineTypes,
postprocess({ result, getTypeBlock, isRemoveTarget, getTypeDefScope }) {
const node = getTypeBlock?.(result.ast) ?? result.ast;
removeTypeDeclarations(node, isRemoveTarget);
if (result.ast.tokens) {
removeTypeDeclarationTokens(result.ast.tokens, isRemoveTarget);
}
if (result.ast.comments) {
removeTypeDeclarationTokens(result.ast.comments, isRemoveTarget);
}
if (result.scopeManager) {
const typeDefScope = getTypeDefScope(result.scopeManager);
restoreScope(result.scopeManager, typeDefScope, isRemoveTarget);
}
},
};
function removeTypeDeclarations(node, isRemoveTarget) {
for (let index = node.body.length - 1; index >= 0; index--) {
if (isRemoveTarget(node.body[index])) {
node.body.splice(index, 1);
}
}
}
function removeTypeDeclarationTokens(tokens, isRemoveTarget) {
for (let index = tokens.length - 1; index >= 0; index--) {
if (isRemoveTarget(tokens[index])) {
tokens.splice(index, 1);
}
}
}
function restoreScope(scopeManager, typeDefScope, isRemoveTarget) {
for (const variable of [...typeDefScope.variables]) {
let def = variable.defs.find((d) => isRemoveTarget(d.name));
while (def) {
removeVariableDef(variable, def, typeDefScope);
def = variable.defs.find((d) => isRemoveTarget(d.name));
}
}
for (const reference of [...typeDefScope.references]) {
if (isRemoveTarget(reference.identifier)) {
removeReference(reference, typeDefScope);
}
}
for (const scope of [...scopeManager.scopes]) {
if (isRemoveTarget(scope.block)) {
removeScope(scopeManager, scope);
}
}
}
}
function getConstraint(node, rawParam) {
if (!node.constraint) {
return "unknown";
}
let index = rawParam.indexOf(node.name.name) + node.name.name.length;
let startIndex = null;
while (index < rawParam.length) {
if (startIndex == null) {
if (rawParam.startsWith("extends", index)) {
startIndex = index = index + 7;
continue;
}
}
else if (rawParam[index] === "=") {
if (rawParam[index + 1] === ">") {
index += 2;
continue;
}
return rawParam.slice(startIndex, index);
}
if (rawParam.startsWith("//", index)) {
const lfIndex = rawParam.indexOf("\n", index);
if (lfIndex >= 0) {
index = lfIndex + 1;
continue;
}
return "unknown";
}
if (rawParam.startsWith("/*", index)) {
const endIndex = rawParam.indexOf("*/", index);
if (endIndex >= 0) {
index = endIndex + 2;
continue;
}
return "unknown";
}
index++;
}
if (startIndex == null) {
return "unknown";
}
return rawParam.slice(startIndex);
}
function removeVariableDef(variable, def, scope) {
const defIndex = variable.defs.indexOf(def);
if (defIndex < 0) {
return;
}
variable.defs.splice(defIndex, 1);
if (variable.defs.length === 0) {
referencesToThrough(variable.references, scope);
variable.references.forEach((r) => {
if (r.init) {
r.init = false;
}
r.resolved = null;
});
scope.variables.splice(scope.variables.indexOf(variable), 1);
const name = variable.name;
if (variable === scope.set.get(name)) {
scope.set.delete(name);
}
}
else {
const idIndex = variable.identifiers.indexOf(def.name);
if (idIndex >= 0) {
variable.identifiers.splice(idIndex, 1);
}
}
}
function referencesToThrough(references, baseScope) {
let scope = baseScope;
while (scope) {
addAllReferences(scope.through, references);
scope = scope.upper;
}
}
function addAllReferences(list, elements) {
list.push(...elements);
list.sort((a, b) => a.identifier.range[0] - b.identifier.range[0]);
}
function removeReference(reference, baseScope) {
if (reference.resolved) {
if (reference.resolved.defs.some((d) => d.name === reference.identifier)) {
const varIndex = baseScope.variables.indexOf(reference.resolved);
if (varIndex >= 0) {
baseScope.variables.splice(varIndex, 1);
}
const name = reference.identifier.name;
if (reference.resolved === baseScope.set.get(name)) {
baseScope.set.delete(name);
}
}
else {
const refIndex = reference.resolved.references.indexOf(reference);
if (refIndex >= 0) {
reference.resolved.references.splice(refIndex, 1);
}
}
}
let scope = baseScope;
while (scope) {
const refIndex = scope.references.indexOf(reference);
if (refIndex >= 0) {
scope.references.splice(refIndex, 1);
}
const throughIndex = scope.through.indexOf(reference);
if (throughIndex >= 0) {
scope.through.splice(throughIndex, 1);
}
scope = scope.upper;
}
}
function removeScope(scopeManager, scope) {
for (const childScope of scope.childScopes) {
removeScope(scopeManager, childScope);
}
while (scope.references[0]) {
removeReference(scope.references[0], scope);
}
const upper = scope.upper;
if (upper) {
const index = upper.childScopes.indexOf(scope);
if (index >= 0) {
upper.childScopes.splice(index, 1);
}
}
const index = scopeManager.scopes.indexOf(scope);
if (index >= 0) {
scopeManager.scopes.splice(index, 1);
}
}
const ALIAS_ITERATOR = /^([\s\S]*?(?:\s|\)))(\bin\b|\bof\b)([\s\S]*)$/u;
const PARENS = /^(\s*\()([\s\S]*?)(\)\s*)$/u;
const DUMMY_PARENT$2 = {};
const IS_FUNCTION_EXPRESSION = /^\s*([\w$_]+|(async\s*)?\([^)]*?\))\s*(:[^=]+)?=>|^\s*(async\s+)?function(?:\s+[\w$]+)?\s*\(/u;
const IS_SIMPLE_PATH = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?'\]|\["[^"]*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*$/u;
function processVForAliasAndIterator(code) {
const match = ALIAS_ITERATOR.exec(code);
if (match != null) {
const aliases = match[1];
const parenMatch = PARENS.exec(aliases);
return {
aliases,
hasParens: Boolean(parenMatch),
aliasesWithBrackets: parenMatch
? `${parenMatch[1].slice(0, -1)}[${parenMatch[2]}]${parenMatch[3].slice(1)}`
: `[${aliases.slice(0, -1)}]`,
delimiter: match[2] || "",
iterator: match[3],
};
}
return {
aliases: "",
hasParens: false,
aliasesWithBrackets: "",
delimiter: "",
iterator: code,
};
}
function getCommaTokenBeforeNode(tokens, node) {
let tokenIndex = sortedIndexBy__default["default"](tokens, { range: node.range }, (t) => t.range[0]);
while (tokenIndex >= 0) {
const token = tokens[tokenIndex];
if (token.type === "Punctuator" && token.value === ",") {
return token;
}
tokenIndex -= 1;
}
return null;
}
function throwEmptyError(locationCalculator, expected) {
const loc = locationCalculator.getLocation(0);
const err = new ParseError(`Expected to be ${expected}, but got empty.`, undefined, 0, loc.line, loc.column);
fixErrorLocation(err, locationCalculator);
throw err;
}
function throwUnexpectedTokenError(name, token) {
const err = new ParseError(`Unexpected token '${name}'.`, undefined, token.range[0], token.loc.start.line, token.loc.start.column);
throw err;
}
function throwErrorAsAdjustingOutsideOfCode(err, code, locationCalculator) {
if (ParseError.isParseError(err)) {
const endOffset = locationCalculator.getOffsetWithGap(code.length);
if (err.index >= endOffset) {
err.message = "Unexpected end of expression.";
}
}
throw err;
}
function parseScriptFragment(code, locationCalculator, parserOptions) {
return parseScriptFragmentWithOption(code, locationCalculator, parserOptions);
}
function parseScriptFragmentWithOption(code, locationCalculator, parserOptions, processOptions) {
try {
const result = parseScript$1(code, parserOptions);
processOptions?.preFixLocationProcess?.(result);
fixLocations(result, locationCalculator);
return result;
}
catch (err) {
const perr = ParseError.normalize(err);
if (perr) {
fixErrorLocation(perr, locationCalculator);
throw perr;
}
throw err;
}
}
const validDivisionCharRE = /[\w).+\-_$\]]/u;
function splitFilters(exp) {
const result = [];
let inSingle = false;
let inDouble = false;
let inTemplateString = false;
let inRegex = false;
let curly = 0;
let square = 0;
let paren = 0;
let lastFilterIndex = 0;
let c = 0;
let prev = 0;
for (let i = 0; i < exp.length; i++) {
prev = c;
c = exp.charCodeAt(i);
if (inSingle) {
if (c === 0x27 && prev !== 0x5c) {
inSingle = false;
}
}
else if (inDouble) {
if (c === 0x22 && prev !== 0x5c) {
inDouble = false;
}
}
else if (inTemplateString) {
if (c === 0x60 && prev !== 0x5c) {
inTemplateString = false;
}
}
else if (inRegex) {
if (c === 0x2f && prev !== 0x5c) {
inRegex = false;
}
}
else if (c === 0x7c &&
exp.charCodeAt(i + 1) !== 0x7c &&
exp.charCodeAt(i - 1) !== 0x7c &&
!curly &&
!square &&
!paren) {
result.push(exp.slice(lastFilterIndex, i));
lastFilterIndex = i + 1;
}
else {
switch (c) {
case 0x22:
inDouble = true;
break;
case 0x27:
inSingle = true;
break;
case 0x60:
inTemplateString = true;
break;
case 0x28:
paren++;
break;
case 0x29:
paren--;
break;
case 0x5b:
square++;
break;
case 0x5d:
square--;
break;
case 0x7b:
curly++;
break;
case 0x7d:
curly--;
break;
}
if (c === 0x2f) {
let j = i - 1;
let p;
for (; j >= 0; j--) {
p = exp.charAt(j);
if (p !== " ") {
break;
}
}
if (!p || !validDivisionCharRE.test(p)) {
inRegex = true;
}
}
}
}
result.push(exp.slice(lastFilterIndex));
return result;
}
function parseExpressionBody(code, locationCalculator, parserOptions, allowEmpty = false) {
debug('[script] parse expression: "0(%s)"', code);
try {
const result = parseScriptFragment(`0(${code})`, locationCalculator.getSubCalculatorShift(-2), parserOptions);
const { ast } = result;
const tokens = ast.tokens ?? [];
const comments = ast.comments ?? [];
const references = analyzeExternalReferences(result, parserOptions);
const statement = ast.body[0];
const callExpression = statement.expression;
const expression = callExpression.arguments[0];
if (!allowEmpty && !expression) {
return throwEmptyError(locationCalculator, "an expression");
}
if (expression?.type === "SpreadElement") {
return throwUnexpectedTokenError("...", expression);
}
if (callExpression.arguments[1]) {
const node = callExpression.arguments[1];
return throwUnexpectedTokenError(",", getCommaTokenBeforeNode(tokens, node) || node);
}
tokens.shift();
tokens.shift();
tokens.pop();
return { expression, tokens, comments, references, variables: [] };
}
catch (err) {
return throwErrorAsAdjustingOutsideOfCode(err, code, locationCalculator);
}
}
function parseFilter(code, locationCalculator, parserOptions) {
debug('[script] parse filter: "%s"', code);
try {
const expression = {
type: "VFilter",
parent: null,
range: [0, 0],
loc: {},
callee: null,
arguments: [],
};
const tokens = [];
const comments = [];
const references = [];
const paren = code.indexOf("(");
const calleeCode = paren === -1 ? code : code.slice(0, paren);
const argsCode = paren === -1 ? null : code.slice(paren);
if (calleeCode.trim()) {
const spaces = /^\s*/u.exec(calleeCode)[0];
const subCalculator = locationCalculator.getSubCalculatorShift(spaces.length);
const { ast } = parseScriptFragment(`"${calleeCode.trim()}"`, subCalculator, parserOptions);
const statement = ast.body[0];
const callee = statement.expression;
if (callee.type !== "Literal") {
const { loc, range } = ast.tokens[0];
return throwUnexpectedTokenError('"', {
range: [range[1] - 1, range[1]],
loc: {
start: {
line: loc.end.line,
column: loc.end.column - 1,
},
end: loc.end,
},
});
}
expression.callee = {
type: "Identifier",
parent: expression,
range: [
callee.range[0],
subCalculator.getOffsetWithGap(calleeCode.trim().length),
],
loc: {
start: callee.loc.start,
end: subCalculator.getLocation(calleeCode.trim().length),
},
name: String(callee.value),
};
tokens.push({
type: "Identifier",
value: calleeCode.trim(),
range: expression.callee.range,
loc: expression.callee.loc,
});
}
else {
return throwEmptyError(locationCalculator, "a filter name");
}
if (argsCode != null) {
const result = parseScriptFragment(`0${argsCode}`, locationCalculator
.getSubCalculatorAfter(paren)
.getSubCalculatorShift(-1), parserOptions);
const { ast } = result;
const statement = ast.body[0];
const callExpression = statement.expression;
ast.tokens.shift();
if (callExpression.type !== "CallExpression" ||
callExpression.callee.type !== "Literal") {
let nestCount = 1;
for (const token of ast.tokens.slice(1)) {
if (nestCount === 0) {
return throwUnexpectedTokenError(token.value, token);
}
if (token.type === "Punctuator" && token.value === "(") {
nestCount += 1;
}
if (token.type === "Punctuator" && token.value === ")") {
nestCount -= 1;
}
}
const token = last__default["default"](ast.tokens);
return throwUnexpectedTokenError(token.value, token);
}
for (const argument of callExpression.arguments) {
argument.parent = expression;
expression.arguments.push(argument);
}
tokens.push(...ast.tokens);
comments.push(...ast.comments);
references.push(...analyzeExternalReferences(result, parserOptions));
}
const firstToken = tokens[0];
const lastToken = last__default["default"](tokens);
expression.range = [firstToken.range[0], lastToken.range[1]];
expression.loc = { start: firstToken.loc.start, end: lastToken.loc.end };
return { expression, tokens, comments, references, variables: [] };
}
catch (err) {
return throwErrorAsAdjustingOutsideOfCode(err, code, locationCalculator);
}
}
function loadParser(parser) {
if (parser !== "espree") {
return require(parser);
}
return getEspree();
}
function parseScript$1(code, parserOptions) {
const parser = typeof parserOptions.parser === "string"
? loadParser(parserOptions.parser)
: isParserObject(parserOptions.parser)
? parserOptions.parser
: getEspree();
const result = isEnhancedParserObject(parser)
? parser.parseForESLint(code, parserOptions)
: parser.parse(code, parserOptions);
if (result.ast != null) {
return result;
}
return { ast: result };
}
function parseScriptElement(node, sfcCode, linesAndColumns, originalParserOptions) {
const parserOptions = {
...originalParserOptions,
ecmaVersion: originalParserOptions.ecmaVersion ?? DEFAULT_ECMA_VERSION,
};
let generic = null;
let code;
let offset;
const textNode = node.children[0];
if (textNode?.type === "VText") {
const [scriptStartOffset, scriptEndOffset] = textNode.range;
code = sfcCode.slice(scriptStartOffset, scriptEndOffset);
offset = scriptStartOffset;
generic = extractGeneric(node);
if (generic) {
const defineTypesCode = `${generic.defineTypes
.map((e) => e.define)
.join(";")};\n`;
code = defineTypesCode + code;
offset -= defineTypesCode.length;
}
}
else {
code = "";
offset = node.startTag.range[1];
}
const locationCalculator = linesAndColumns.createOffsetLocationCalculator(offset);
const result = parseScriptFragment(code, locationCalculator, parserOptions);
if (generic) {
generic.postprocess({
result,
isRemoveTarget(nodeOrToken) {
return nodeOrToken.range[1] <= textNode.range[0];
},
getTypeDefScope(scopeManager) {
return (scopeManager.globalScope.childScopes.find((s) => s.type === "module") ?? scopeManager.globalScope);
},
});
const startToken = [
result.ast.body[0],
result.ast.tokens?.[0],
result.ast.comments?.[0],
]
.filter((e) => Boolean(e))
.sort((a, b) => a.range[0] - b.range[0])
.find((t) => Boolean(t));
if (startToken && result.ast.range[0] !== startToken.range[0]) {
result.ast.range[0] = startToken.range[0];
if (result.ast.start != null) {
result.ast.start = startToken.start;
}
result.ast.loc.start = { ...startToken.loc.start };
}
}
if (result.ast.tokens != null) {
const startTag = node.startTag;
const endTag = node.endTag;
result.ast.tokens.unshift({
type: "Punctuator",
range: startTag.range,
loc: startTag.loc,
value: "<script>",
});
if (endTag != null) {
result.ast.tokens.push({
type: "Punctuator",
range: endTag.range,
loc: endTag.loc,
value: "</script>",
});
}
}
return result;
}
function parseExpression(code, locationCalculator, parserOptions, { allowEmpty = false, allowFilters = false } = {}) {
debug('[script] parse expression: "%s"', code);
const [mainCode, ...filterCodes] = allowFilters && (parserOptions.vueFeatures?.filter ?? true)
? splitFilters(code)
: [code];
if (filterCodes.length === 0) {
return parseExpressionBody(code, locationCalculator, parserOptions, allowEmpty);
}
const retB = parseExpressionBody(mainCode, locationCalculator, parserOptions);
if (!retB.expression) {
return retB;
}
const ret = retB;
ret.expression = {
type: "VFilterSequenceExpression",
parent: null,
expression: retB.expression,
filters: [],
range: [...retB.expression.range],
loc: { ...retB.expression.loc },
};
ret.expression.expression.parent = ret.expression;
let prevLoc = mainCode.length;
for (const filterCode of filterCodes) {
ret.tokens.push(fixLocation({
type: "Punctuator",
value: "|",
range: [prevLoc, prevLoc + 1],
loc: {},
}, locationCalculator));
const retF = parseFilter(filterCode, locationCalculator.getSubCalculatorShift(prevLoc + 1), parserOptions);
if (retF) {
if (retF.expression) {
ret.expression.filters.push(retF.expression);
retF.expression.parent = ret.expression;
}
ret.tokens.push(...retF.tokens);
ret.comments.push(...retF.comments);
ret.references.push(...retF.references);
}
prevLoc += 1 + filterCode.length;
}
const lastToken = last__default["default"](ret.tokens);
ret.expression.range[1] = lastToken.range[1];
ret.expression.loc.end = lastToken.loc.end;
return ret;
}
function parseVForExpression(code, locationCalculator, parserOptions) {
if (code.trim() === "") {
throwEmptyError(locationCalculator, "'<alias> in <expression>'");
}
if (isEcmaVersion5(parserOptions)) {
return parseVForExpressionForEcmaVersion5(code, locationCalculator, parserOptions);
}
const processed = processVForAliasAndIterator(code);
if (!processed.aliases.trim()) {
return throwEmptyError(locationCalculator, "an alias");
}
try {
debug('[script] parse v-for expression: "for(%s%s%s);"', processed.aliasesWithBrackets, processed.delimiter, processed.iterator);
const result = parseScriptFragment(`for(let ${processed.aliasesWithBrackets}${processed.delimiter}${processed.iterator});`, locationCalculator.getSubCalculatorShift(processed.hasParens ? -8 : -9), parserOptions);
const { ast } = result;
const tokens = ast.tokens ?? [];
const comments = ast.comments ?? [];
const scope = analyzeVariablesAndExternalReferences(result, "v-for", parserOptions);
const references = scope.references;
const variables = scope.variables;
const statement = ast.body[0];
const varDecl = statement.left;
const id = varDecl.declarations[0].id;
const left = id.elements;
const right = statement.right;
if (!processed.hasParens && !left.length) {
return throwEmptyError(locationCalculator, "an alias");
}
tokens.shift();
tokens.shift();
tokens.shift();
tokens.pop();
tokens.pop();
const closeOffset = statement.left.range[1] - 1;
const closeIndex = tokens.findIndex((t) => t.range[0] === closeOffset);
if (processed.hasParens) {
const open = tokens[0];
if (open != null) {
open.value = "(";
}
const close = tokens[closeIndex];
if (close != null) {
close.value = ")";
}
}
else {
tokens.splice(closeIndex, 1);
tokens.shift();
}
const firstToken = tokens[0] || statement.left;
const lastToken = tokens[tokens.length - 1] || statement.right;
const expression = {
type: "VForExpression",
range: [firstToken.range[0], lastToken.range[1]],
loc: { start: firstToken.loc.start, end: lastToken.loc.end },
parent: DUMMY_PARENT$2,
left,
right,
};
for (const l of left) {
if (l != null) {
l.parent = expression;
}
}
right.parent = expression;
return { expression, tokens, comments, references, variables };
}
catch (err) {
return throwErrorAsAdjustingOutsideOfCode(err, code, locationCalculator);
}
}
function isEcmaVersion5(parserOptions) {
const ecmaVersion = getEcmaVersionIfUseEspree(parserOptions);
return ecmaVersion != null && ecmaVersion <= 5;
}
function parseVForExpressionForEcmaVersion5(code, locationCalculator, parserOptions) {
const processed = processVForAliasAndIterator(code);
if (!processed.aliases.trim()) {
return throwEmptyError(locationCalculator, "an alias");
}
try {
const tokens = [];
const comments = [];
const parsedAliases = parseVForAliasesForEcmaVersion5(processed.aliasesWithBrackets, locationCalculator.getSubCalculatorShift(processed.hasParens ? 0 : -1), parserOptions);
if (processed.hasParens) {
const open = parsedAliases.tokens[0];
if (open != null) {
open.value = "(";
}
const close = last__default["default"](parsedAliases.tokens);
if (close != null) {
close.value = ")";
}
}
else {
parsedAliases.tokens.shift();
parsedAliases.tokens.pop();
}
tokens.push(...parsedAliases.tokens);
comments.push(...parsedAliases.comments);
const { left, variables } = parsedAliases;
if (!processed.hasParens && !left.length) {
return throwEmptyError(locationCalculator, "an alias");
}
const delimiterStart = processed.aliases.length;
const delimiterEnd = delimiterStart + processed.delimiter.length;
tokens.push(fixLocation({
type: processed.delimiter === "in" ? "Keyword" : "Identifier",
value: processed.delimiter,
start: delimiterStart,
end: delimiterEnd,
loc: {},
range: [delimiterStart, delimiterEnd],
}, locationCalculator));
const parsedIterator = parseVForIteratorForEcmaVersion5(processed.iterator, locationCalculator.getSubCalculatorShift(delimiterEnd), parserOptions);
tokens.push(...parsedIterator.tokens);
comments.push(...parsedIterator.comments);
const { right, references } = parsedIterator;
const firstToken = tokens[0];
const lastToken = last__default["default"](tokens) || firstToken;
const expression = {
type: "VForExpression",
range: [firstToken.range[0], lastToken.range[1]],
loc: { start: firstToken.loc.start, end: lastToken.loc.end },
parent: DUMMY_PARENT$2,
left,
right,
};
for (const l of left) {
if (l != null) {
l.parent = expression;
}
}
right.parent = expression;
return { expression, tokens, comments, references, variables };
}
catch (err) {
return throwErrorAsAdjustingOutsideOfCode(err, code, locationCalculator);
}
}
function parseVForAliasesForEcmaVersion5(code, locationCalculator, parserOptions) {
const result = parseScriptFragment(`0(${code})`, locationCalculator.getSubCalculatorShift(-2), parserOptions);
const { ast } = result;
const tokens = ast.tokens ?? [];
const comments = ast.comments ?? [];
const variables = analyzeExternalReferences(result, parserOptions).map(transformVariable);
const statement = ast.body[0];
const callExpression = statement.expression;
const expression = callExpression.arguments[0];
const left = expression.elements.filter((e) => {
if (e == null || e.type === "Identifier") {
return true;
}
const errorToken = tokens.find((t) => e.range[0] <= t.range[0] && t.range[1] <= e.range[1]);
return throwUnexpectedTokenError(errorToken.value, errorToken);
});
tokens.shift();
tokens.shift();
tokens.pop();
return { left, tokens, comments, variables };
function transformVariable(reference) {
const ret = {
id: reference.id,
kind: "v-for",
references: [],
};
Object.defineProperty(ret, "references", { enumerable: false });
return ret;
}
}
function parseVForIteratorForEcmaVersion5(code, locationCalculator, parserOptions) {
const result = parseScriptFragment(`0(${code})`, locationCalculator.getSubCalculatorShift(-2), parserOptions);
const { ast } = result;
const tokens = ast.tokens ?? [];
const comments = ast.comments ?? [];
const references = analyzeExternalReferences(result, parserOptions);
const statement = ast.body[0];
const callExpression = statement.expression;
const expression = callExpression.arguments[0];
if (!expression) {
return throwEmptyError(locationCalculator, "an expression");
}
if (expression?.type === "SpreadElement") {
return throwUnexpectedTokenError("...", expression);
}
const right = expression;
tokens.shift();
tokens.shift();
tokens.pop();
return { right, tokens, comments, references };
}
function parseVOnExpression(code, locationCalculator, parserOptions) {
if (IS_FUNCTION_EXPRESSION.test(code) || IS_SIMPLE_PATH.test(code)) {
return parseExpressionBody(code, locationCalculator, parserOptions);
}
return parseVOnExpressionBody(code, locationCalculator, parserOptions);
}
function parseVOnExpressionBody(code