140 lines
5.8 KiB
JavaScript
140 lines
5.8 KiB
JavaScript
|
"use strict";
|
||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
exports.parseForESLint = void 0;
|
||
|
const visitor_keys_1 = require("../visitor-keys");
|
||
|
const context_1 = require("../context");
|
||
|
const eslint_scope_1 = require("eslint-scope");
|
||
|
const script_1 = require("./script");
|
||
|
const sort_1 = require("./sort");
|
||
|
const template_1 = require("./template");
|
||
|
const analyze_scope_1 = require("./analyze-scope");
|
||
|
const errors_1 = require("../errors");
|
||
|
const typescript_1 = require("./typescript");
|
||
|
const scope_1 = require("../scope");
|
||
|
const style_context_1 = require("./style-context");
|
||
|
/**
|
||
|
* Parse source code
|
||
|
*/
|
||
|
function parseForESLint(code, options) {
|
||
|
const parserOptions = Object.assign({ ecmaVersion: 2020, sourceType: "module", loc: true, range: true, raw: true, tokens: true, comment: true, eslintVisitorKeys: true, eslintScopeManager: true }, (options || {}));
|
||
|
parserOptions.sourceType = "module";
|
||
|
if (parserOptions.ecmaVersion <= 5 || parserOptions.ecmaVersion == null) {
|
||
|
parserOptions.ecmaVersion = 2015;
|
||
|
}
|
||
|
const ctx = new context_1.Context(code, parserOptions);
|
||
|
const resultTemplate = (0, template_1.parseTemplate)(ctx.sourceCode.template, ctx, parserOptions);
|
||
|
const scripts = ctx.sourceCode.scripts;
|
||
|
const resultScript = ctx.isTypeScript()
|
||
|
? (0, typescript_1.parseTypeScript)(scripts.getCurrentVirtualCodeInfo(), scripts.attrs, parserOptions, { slots: ctx.slots })
|
||
|
: (0, script_1.parseScript)(scripts.getCurrentVirtualCode(), scripts.attrs, parserOptions);
|
||
|
ctx.scriptLet.restore(resultScript);
|
||
|
ctx.tokens.push(...resultScript.ast.tokens);
|
||
|
ctx.comments.push(...resultScript.ast.comments);
|
||
|
(0, sort_1.sortNodes)(ctx.comments);
|
||
|
(0, sort_1.sortNodes)(ctx.tokens);
|
||
|
extractTokens(ctx);
|
||
|
(0, analyze_scope_1.analyzeStoreScope)(resultScript.scopeManager);
|
||
|
(0, analyze_scope_1.analyzeReactiveScope)(resultScript.scopeManager);
|
||
|
(0, analyze_scope_1.analyzeStoreScope)(resultScript.scopeManager); // for reactive vars
|
||
|
// Add $$xxx variable
|
||
|
for (const $$name of ["$$slots", "$$props", "$$restProps"]) {
|
||
|
const globalScope = resultScript.scopeManager.globalScope;
|
||
|
const variable = new eslint_scope_1.Variable();
|
||
|
variable.name = $$name;
|
||
|
variable.scope = globalScope;
|
||
|
globalScope.variables.push(variable);
|
||
|
globalScope.set.set($$name, variable);
|
||
|
globalScope.through = globalScope.through.filter((reference) => {
|
||
|
if (reference.identifier.name === $$name) {
|
||
|
// Links the variable and the reference.
|
||
|
// And this reference is removed from `Scope#through`.
|
||
|
reference.resolved = variable;
|
||
|
(0, scope_1.addReference)(variable.references, reference);
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
});
|
||
|
}
|
||
|
const ast = resultTemplate.ast;
|
||
|
const statements = [...resultScript.ast.body];
|
||
|
ast.sourceType = resultScript.ast.sourceType;
|
||
|
const scriptElements = ast.body.filter((b) => b.type === "SvelteScriptElement");
|
||
|
for (let index = 0; index < scriptElements.length; index++) {
|
||
|
const body = scriptElements[index];
|
||
|
let statement = statements[0];
|
||
|
while (statement &&
|
||
|
body.range[0] <= statement.range[0] &&
|
||
|
(statement.range[1] <= body.range[1] ||
|
||
|
index === scriptElements.length - 1)) {
|
||
|
statement.parent = body;
|
||
|
body.body.push(statement);
|
||
|
statements.shift();
|
||
|
statement = statements[0];
|
||
|
}
|
||
|
if (!body.startTag.attributes.some((attr) => attr.type === "SvelteAttribute" &&
|
||
|
attr.key.name === "context" &&
|
||
|
attr.value.length === 1 &&
|
||
|
attr.value[0].type === "SvelteLiteral" &&
|
||
|
attr.value[0].value === "module")) {
|
||
|
(0, analyze_scope_1.analyzePropsScope)(body, resultScript.scopeManager);
|
||
|
}
|
||
|
}
|
||
|
if (statements.length) {
|
||
|
throw new errors_1.ParseError("The script is unterminated", statements[0].range[1], ctx);
|
||
|
}
|
||
|
const styleElement = ast.body.find((b) => b.type === "SvelteStyleElement");
|
||
|
let styleContext = null;
|
||
|
resultScript.ast = ast;
|
||
|
resultScript.services = Object.assign(resultScript.services || {}, {
|
||
|
isSvelte: true,
|
||
|
getSvelteHtmlAst() {
|
||
|
return resultTemplate.svelteAst.html;
|
||
|
},
|
||
|
getStyleContext() {
|
||
|
if (styleContext === null) {
|
||
|
styleContext = (0, style_context_1.parseStyleContext)(styleElement, ctx);
|
||
|
}
|
||
|
return styleContext;
|
||
|
},
|
||
|
styleNodeLoc: style_context_1.styleNodeLoc,
|
||
|
styleNodeRange: style_context_1.styleNodeRange,
|
||
|
});
|
||
|
resultScript.visitorKeys = Object.assign({}, visitor_keys_1.KEYS, resultScript.visitorKeys);
|
||
|
return resultScript;
|
||
|
}
|
||
|
exports.parseForESLint = parseForESLint;
|
||
|
/** Extract tokens */
|
||
|
function extractTokens(ctx) {
|
||
|
const useRanges = (0, sort_1.sortNodes)([...ctx.tokens, ...ctx.comments]).map((t) => t.range);
|
||
|
let range = useRanges.shift();
|
||
|
for (let index = 0; index < ctx.sourceCode.template.length; index++) {
|
||
|
while (range && range[1] <= index) {
|
||
|
range = useRanges.shift();
|
||
|
}
|
||
|
if (range && range[0] <= index) {
|
||
|
index = range[1] - 1;
|
||
|
continue;
|
||
|
}
|
||
|
const c = ctx.sourceCode.template[index];
|
||
|
if (!c.trim()) {
|
||
|
continue;
|
||
|
}
|
||
|
if (isPunctuator(c)) {
|
||
|
ctx.addToken("Punctuator", { start: index, end: index + 1 });
|
||
|
}
|
||
|
else {
|
||
|
// unknown
|
||
|
// It is may be a bug.
|
||
|
ctx.addToken("Identifier", { start: index, end: index + 1 });
|
||
|
}
|
||
|
}
|
||
|
(0, sort_1.sortNodes)(ctx.comments);
|
||
|
(0, sort_1.sortNodes)(ctx.tokens);
|
||
|
/**
|
||
|
* Checks if the given char is punctuator
|
||
|
*/
|
||
|
function isPunctuator(c) {
|
||
|
return /^[^\w$]$/iu.test(c);
|
||
|
}
|
||
|
}
|