# What the Parser does The main thing this parser does is parsing the `*.svelte` file and return an AST that can be parsed by ESLint. However, this parser does a few other things for a better experience with ESLint integration. ## Entry Point This parser parses `*.svelte` via `parseForESLint()` and returns the result to ESLint. This is a requirement for ESLint's custom parser. See https://eslint.org/docs/latest/developer-guide/working-with-custom-parsers. ## Results ### `ast` Returns the AST of the parses result. Script AST is [ESTree] compliant AST by default. However, if you used `@typescript-eslint/parser` as script parser, it may contain [TypeScript AST](https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/ast-spec). However, the parser assigns a special node `SvelteReactiveStatement` to the parsed result of `$:`. `SvelteReactiveStatement` is a special node to avoid confusing ESLint check rules with `LabeledStatement`. [ESTree]: https://github.com/estree/estree The HTML template part returns a special AST. See [AST.md](./AST.md). The `Program` node contains `tokens` and `comments`. This is a requirement for ESLint's custom parser. See https://eslint.org/docs/latest/developer-guide/working-with-custom-parsers#the-ast-specification. ### `services` This parser returns the `services` returned by the script parser. In particular, typescript-eslint contains important information such as type information in `services`. The parser does not edit the `services`, but there is a trick in parsing the script to get the correct result of the `services` returned by the script parser. When parsing the script, the parser does not pass only the ` ``` Parse the following virtual script code as a script: ```ts function inputHandler() { // process } function $_render1() { inputHandler as ( e: "input" extends keyof HTMLElementEventMap ? HTMLElementEventMap["input"] : CustomEvent, ) => void; } ``` This gives the correct type information to the inputHandler when used with `on:input={inputHandler}`. The script AST for the HTML template is then remapped to the template AST. You can check what happens to virtual scripts in the Online Demo. https://sveltejs.github.io/svelte-eslint-parser/virtual-script-code/ See also [Scope Types](#scope-types) section. ### `scopeManager` This parser returns a ScopeManager instance. ScopeManager is used in variable analysis such as [no-unused-vars](https://eslint.org/docs/latest/rules/no-unused-vars) and [no-undef](https://eslint.org/docs/latest/rules/no-undef) rules. See https://eslint.org/docs/latest/developer-guide/scope-manager-interface for details. The parser will generate a virtual script so that it can parse the correct scope. For example, when using `{#each}` and `{@const}`: ```svelte {#each array as e} {@const ee = e * 2} {ee} {/each} ``` Parse the following virtual script code as a script: ```ts const array = [1, 2, 3]; function $_render1() { Array.from(array).forEach((e) => { const ee = e * 2; ee; }); } ``` This ensures that the variable `e` defined by `{#each}` is correctly scoped only within `{#each}`. Also, this parser returns special results for variables used in `$: foo = expression` and `$count` for proper analysis. It also adds virtual references for variables that are marked specially used in `*.svelte` (e.g. `export let` and `$ref`). This is a hack that is also used in typescript-eslint. https://github.com/typescript-eslint/typescript-eslint/issues/4508#issuecomment-1030508403 You can also check the results [Online DEMO](https://sveltejs.github.io/svelte-eslint-parser/scope/). ### `visitorKeys` ESLint custom parsers that provide their own AST require `visitorKeys` to properly traverse the node. See https://eslint.org/docs/latest/developer-guide/working-with-custom-parsers. ## Scope Types TypeScript's type inference is pretty good, so parsing Svelte as-is gives some wrong type information. e.g. ```ts export let foo: { bar: number } | null = null; $: console.log(foo && foo.bar); // ^ never type ``` (You can see it on [TypeScript Online Playground](https://www.typescriptlang.org/play?#code/KYDwDg9gTgLgBAG2PAZhCAuOBvOAjAQyiwDsBXAWz2CjgF84AfOchBOAXhbLYFgAoAQBIsAYwgkAzhCQA6BBADmACjQQ4AMg1w1swlACUAbgFwz5i5YsB6a3AB6LYADcacGAE8wwAUA)) In the above code, foo in `$:` should be `object` or `null` in `*.svelte`, but TypeScript infers that it is `null` only. To avoid this problem, the parser generates virtual code and traps statements within `$:` to function scope. Then restore it to have the correct AST and ScopeManager. For example: ```svelte {foo && foo.bar} ``` Parse the following virtual script code as a script: ```ts export let foo: { bar: number } | null = null; $: function $_reactiveStatementScopeFunction1() { console.log(foo && foo.bar); } $: let r = $_reactiveVariableScopeFunction2(); function $_reactiveVariableScopeFunction2() { let $_tmpVar3; return ($_tmpVar3 = foo && foo.bar); } $: let { bar: n } = $_reactiveVariableScopeFunction4(); function $_reactiveVariableScopeFunction4() { let $_tmpVar5; return ($_tmpVar5 = foo || { bar: 42 }); } function $_render6() { foo && foo.bar; } ```