svelte-eslint-parser
Advanced tools
Comparing version 0.0.10 to 0.0.11
@@ -5,12 +5,13 @@ import type { Comment, Locations, Token } from "../ast"; | ||
import { TemplateScopeManager } from "./template-scope-manager"; | ||
declare type ContextSourceCode = { | ||
template: string; | ||
scripts: { | ||
code: string; | ||
attrs: Record<string, string | undefined>; | ||
}; | ||
}; | ||
export declare class Context { | ||
readonly code: string; | ||
readonly parserOptions: any; | ||
readonly sourceCode: { | ||
svelte: string; | ||
script: { | ||
code: string; | ||
attrs: Record<string, string | undefined>; | ||
}; | ||
}; | ||
readonly sourceCode: ContextSourceCode; | ||
readonly tokens: Token[]; | ||
@@ -64,1 +65,2 @@ readonly comments: Comment[]; | ||
} | ||
export {}; |
@@ -18,26 +18,29 @@ "use strict"; | ||
this.locs = new LinesAndColumns(code); | ||
const sourceCode = { | ||
svelte: code, | ||
script: { | ||
code: code.replace(/[^\n\r ]/g, " "), | ||
ranges: [], | ||
attrs: {}, | ||
let templateCode = ""; | ||
let scriptCode = ""; | ||
let scriptAttrs = {}; | ||
let start = 0; | ||
for (const block of extractBlocks(code)) { | ||
const before = code.slice(start, block.codeRange[0]); | ||
const blankCode = block.code.replace(/[^\n\r ]/g, " "); | ||
templateCode += before + blankCode; | ||
if (block.tag === "script") { | ||
scriptCode += before.replace(/[^\n\r ]/g, " ") + block.code; | ||
scriptAttrs = Object.assign(scriptAttrs, block.attrs); | ||
} | ||
else { | ||
scriptCode += before.replace(/[^\n\r ]/g, " ") + blankCode; | ||
} | ||
start = block.codeRange[1]; | ||
} | ||
const before = code.slice(start); | ||
templateCode += before; | ||
scriptCode += before.replace(/[^\n\r ]/g, " "); | ||
this.sourceCode = { | ||
template: templateCode, | ||
scripts: { | ||
code: scriptCode, | ||
attrs: scriptAttrs, | ||
}, | ||
}; | ||
for (const script of extractScriptBlocks(code)) { | ||
sourceCode.svelte = | ||
sourceCode.svelte.slice(0, script.codeRange[0]) + | ||
script.code.replace(/[^\n\r ]/g, " ") + | ||
sourceCode.svelte.slice(script.codeRange[1]); | ||
sourceCode.script.code = | ||
sourceCode.script.code.slice(0, script.codeRange[0]) + | ||
script.code + | ||
sourceCode.script.code.slice(script.codeRange[1]); | ||
sourceCode.script.ranges.push({ | ||
code: script.codeRange, | ||
tag: script.tagRange, | ||
}); | ||
sourceCode.script.attrs = Object.assign(sourceCode.script.attrs, script.attrs); | ||
} | ||
this.sourceCode = sourceCode; | ||
} | ||
@@ -95,25 +98,33 @@ getLocFromIndex(index) { | ||
/** Extract <script> blocks */ | ||
function* extractScriptBlocks(code) { | ||
const scriptRe = /<script(\s[\s\S]*?)?>([\s\S]*?)<\/script>/giu; | ||
let res; | ||
while ((res = scriptRe.exec(code))) { | ||
const [tag, attributes = "", context] = res; | ||
const tagRange = [res.index, scriptRe.lastIndex]; | ||
const codeRange = [ | ||
tagRange[0] + 8 + attributes.length, | ||
tagRange[1] - 9, | ||
]; | ||
// eslint-disable-next-line regexp/no-unused-capturing-group -- maybe bug | ||
const attrRe = /(<key>[^\s=]+)(?:=(?:"(<val>[^"]*)"|'(<val>[^"]*)'|(<val>[^\s=]+)))?/giu; | ||
const attrs = {}; | ||
while ((res = attrRe.exec(attributes))) { | ||
attrs[res.groups.key] = res.groups.val; | ||
function* extractBlocks(code) { | ||
const startTagRe = /<(script|style)(\s[\s\S]*?)?>/giu; | ||
const endScriptTagRe = /<\/script(?:\s[\s\S]*?)?>/giu; | ||
const endStyleTagRe = /<\/style(?:\s[\s\S]*?)?>/giu; | ||
let startTagRes; | ||
while ((startTagRes = startTagRe.exec(code))) { | ||
const [startTag, tag, attributes = ""] = startTagRes; | ||
const startTagStart = startTagRes.index; | ||
const startTagEnd = startTagStart + startTag.length; | ||
const endTagRe = tag.toLowerCase() === "script" ? endScriptTagRe : endStyleTagRe; | ||
endTagRe.lastIndex = startTagRe.lastIndex; | ||
const endTagRes = endTagRe.exec(code); | ||
if (endTagRes) { | ||
const endTagStart = endTagRes.index; | ||
const codeRange = [startTagEnd, endTagStart]; | ||
const attrRe = | ||
// eslint-disable-next-line regexp/no-unused-capturing-group -- maybe bug | ||
/(<key>[^\s=]+)(?:=(?:"(<val>[^"]*)"|'(<val>[^"]*)'|(<val>[^\s=]+)))?/giu; | ||
const attrs = {}; | ||
let attrRes; | ||
while ((attrRes = attrRe.exec(attributes))) { | ||
attrs[attrRes.groups.key] = attrRes.groups.val; | ||
} | ||
yield { | ||
code: code.slice(...codeRange), | ||
codeRange, | ||
attrs, | ||
tag: tag, | ||
}; | ||
startTagRe.lastIndex = endTagRe.lastIndex; | ||
} | ||
yield { | ||
code: context, | ||
codeRange, | ||
tag, | ||
tagRange, | ||
attrs, | ||
}; | ||
} | ||
@@ -120,0 +131,0 @@ } |
@@ -68,3 +68,3 @@ "use strict"; | ||
let range = useRanges.shift(); | ||
for (let index = 0; index < ctx.sourceCode.svelte.length; index++) { | ||
for (let index = 0; index < ctx.sourceCode.template.length; index++) { | ||
while (range && range[1] <= index) { | ||
@@ -77,3 +77,3 @@ range = useRanges.shift(); | ||
} | ||
const c = ctx.sourceCode.svelte[index]; | ||
const c = ctx.sourceCode.template[index]; | ||
if (!c.trim()) { | ||
@@ -105,4 +105,4 @@ continue; | ||
const script = element.type === "SvelteScriptElement"; | ||
const code = ctx.sourceCode.svelte.slice(0, element.range[0]).replace(/./g, " ") + | ||
ctx.sourceCode.svelte | ||
const code = " ".repeat(element.range[0]) + | ||
ctx.sourceCode.template | ||
.slice(...element.range) | ||
@@ -109,0 +109,0 @@ .replace(script |
@@ -22,5 +22,5 @@ "use strict"; | ||
const ctx = new context_1.Context(code, parserOptions); | ||
const resultScript = script_1.parseScript(ctx.sourceCode.script, parserOptions); | ||
const resultScript = script_1.parseScript(ctx.sourceCode.scripts, parserOptions); | ||
ctx.readyScopeManager(resultScript.scopeManager); | ||
const resultTemplate = template_1.parseTemplate(ctx.sourceCode.svelte, ctx, parserOptions); | ||
const resultTemplate = template_1.parseTemplate(ctx.sourceCode.template, ctx, parserOptions); | ||
analyze_scope_1.analyzeStoreScope(resultScript.scopeManager); | ||
@@ -27,0 +27,0 @@ // Add $$xxx variable |
{ | ||
"name": "svelte-eslint-parser", | ||
"version": "0.0.10", | ||
"version": "0.0.11", | ||
"description": "Svelte parser for ESLint", | ||
@@ -64,3 +64,4 @@ "main": "lib/index.js", | ||
"eslint-plugin-prettier": "^3.2.0", | ||
"eslint-plugin-regexp": "^0.9.0", | ||
"eslint-plugin-regexp": "^0.10.0", | ||
"eslint-plugin-svelte3": "^3.2.0", | ||
"eslint-plugin-vue": "^7.2.0", | ||
@@ -73,2 +74,3 @@ "estree-walker": "^3.0.0", | ||
"prettier": "^2.0.5", | ||
"string-replace-loader": "^3.0.1", | ||
"svelte": "^3.37.0", | ||
@@ -75,0 +77,0 @@ "ts-node": "^9.0.0", |
@@ -26,2 +26,20 @@ # svelte-eslint-parser | ||
The [`@ota-meshi/eslint-plugin-svelte`] is an ESLint plugin that uses the [svelte-eslint-parser]. I have already [implemented some rules]. | ||
[`@ota-meshi/eslint-plugin-svelte`]: https://github.com/ota-meshi/eslint-plugin-svelte | ||
[implemented some rules]: https://ota-meshi.github.io/eslint-plugin-svelte/rules/ | ||
### Benefits of Using AST | ||
- We can create rules using the information contained in the AST. | ||
e.g. | ||
- [@ota-meshi/svelte/no-dupe-else-if-blocks](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-dupe-else-if-blocks.html) rule | ||
- [@ota-meshi/svelte/no-at-html-tags](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-at-html-tags.html) rule | ||
- [@ota-meshi/svelte/no-at-debug-tags](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-at-debug-tags.html) rule | ||
- Rules that use text work well. | ||
e.g. | ||
- [eol-last](https://eslint.org/docs/rules/eol-last) rule | ||
- [unicode-bom](https://eslint.org/docs/rules/unicode-bom) rule | ||
- [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier) | ||
## ❗ Attention | ||
@@ -121,2 +139,3 @@ | ||
- The parser will generate its own [ScopeManager](https://eslint.org/docs/developer-guide/scope-manager-interface). You can check it on the [Online DEMO](https://ota-meshi.github.io/svelte-eslint-parser/scope). | ||
- I have already [implemented some rules] in the [`@ota-meshi/eslint-plugin-svelte`]. The source code for these rules will be helpful to you. | ||
@@ -123,0 +142,0 @@ ## :beers: Contributing |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
128859
3096
153
31
2
26