sveast 0.9.7 → 0.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -35,7 +35,7 @@ ast.fragment.nodes; // [Text, RegularElement]
35
35
  | [`walk`, `visitorKeys`, `markupVisitorKeys`, `valueVisitorKeys`, `skipTypeWrappers`](#walknode-visitor-keys--void) | Visit, skip, stop at or replace nodes, in the whole AST, only the markup, or everything but TypeScript's types | `sveast`, `sveast/walk` |
36
36
  | [`children`, `forEachChild`](#childrennode-keys--node-and-foreachchildnode-callback-keys--void) | A node's children, cached or without allocating | `sveast`, `sveast/walk` |
37
37
  | [`isReference`](#isreferencenode-parent--boolean), [`extractIdentifiers`](#extractidentifierspattern--identifier) | Which identifiers are references, and which ones a pattern declares | `sveast`, `sveast/walk` |
38
- | [`analyzeScopes`](#analyzescopesast--scopes) | Which declaration each name refers to, and every read and write of it | `sveast`, `sveast/scope` |
38
+ | [`analyzeScopes`](#analyzescopesast-options--scopes) | Which declaration each name refers to, and every read and write of it | `sveast`, `sveast/scope` |
39
39
  | [`a11yWarnings`](#a11ywarningsast-options--a11ywarning) | svelte's accessibility warnings, without compiling | `sveast/a11y` |
40
40
  | [`createLocator`, `locate`](#createlocatorsource--offset--position) | Lines and columns for the nodes you report, without parsing with `loc` | `sveast`, `sveast/walk` |
41
41
 
@@ -383,7 +383,7 @@ if (declaration.type === "VariableDeclaration") {
383
383
  }
384
384
  ```
385
385
 
386
- ### `analyzeScopes(ast) => Scopes`
386
+ ### `analyzeScopes(ast, options?) => Scopes`
387
387
 
388
388
  Finds the scopes of a component, its scripts and markup together, or of a module: which declaration each name refers to, and where each binding is read, written or subscribed to. It resolves names as svelte's analyzer does, which `tests/scope.test.ts` checks on the corpus: on 12,548 components from the corpus, svelte's tests and the Svelte projects listed under parity, they agree on all 208,797 names they both resolve, but for a class expression's name inside its body, a snippet's own name and a `var` declared twice, where sveast follows JavaScript.
389
389
 
@@ -408,7 +408,7 @@ size?.references.some((reference) => reference.writes || reference.mutates); //
408
408
 
409
409
  It returns:
410
410
 
411
- - **`module`** and **`instance`**, the scopes of `<script module>` and `<script>` (one scope, for a module). A `Scope` has the `node` that makes it, its `parent`, its `declarations` by name, and `get(name)`, the binding a name refers to there, or `null` for a global.
411
+ - **`module`** and **`instance`**, the scopes of `<script module>` and `<script>` (one scope, for a module). A `Scope` has the `node` that makes it, its `parent`, its `declarations` by name, and `get(name)`, the binding a name refers to there, or `null` for a global. With `types: true`, its `types` holds its `type`, `interface` and type parameter bindings, and `getType(name)` is the binding a name refers to in a type.
412
412
  - **`scopeOf(node)`**, the scope a node is in; `null` in a type, the `<style>` or another AST. The first call walks the AST again to record every node's scope, so a tool that only resolves names doesn't keep a map of every node.
413
413
  - **`bindingOf(identifier)`**, the binding an `Identifier` declares or refers to; `null` for a global, a property key or a name in a type.
414
414
  - **`referenceOf(identifier)`**, the `Reference` an `Identifier` is, to tell a read from a write or a store subscription; `null` for one that declares a binding or isn't a reference.
@@ -429,6 +429,21 @@ The markup's scopes are svelte's:
429
429
 
430
430
  Names in TypeScript's types aren't references, and `type` and `interface` declare nothing; it skips them with `valueVisitorKeys`. Enums, enum members and namespaces are declared. It doesn't change the AST, and takes less than half as long as parsing it.
431
431
 
432
+ | Option | Default | Description |
433
+ |:---|:---|:---|
434
+ | `types` | `false` | Resolve the names in types too, for a tool that asks which declarations some code uses, such as one that copies a statement with the imports it needs. |
435
+
436
+ With `types: true`, `type` and `interface` declare bindings of those kinds, and a type parameter or `infer U` one of kind `"type-param"`, in a scope's `types`, apart from its values, so `type A` and `const A` are two bindings. A name in a type is a `Reference` with `type: true` that neither reads, writes nor mutates: `A` in `let a: A`, `a` in `typeof a`, `I` in `implements I` and `extends I`, `N` in `N.T`, and the local name in `export type { A }`. A name in a type refers to a type, an import, a class or an enum; `typeof a` to a value; `N` in `N.T` to a namespace, an enum or an import, so `import type { A }` and `import { type A }` get the references. Property and method names in type literals and interfaces aren't references, but for a computed key's value. Type parameters are in scope for their function, class, method, type alias, interface or function type, `infer U` for its conditional type's true branch, and the parameters of a function type or signature are bindings of kind `"param"`, for `typeof x` and `x is T`. `<script generics="...">`'s names aren't declared. The value references are those it finds without `types`.
437
+
438
+ ```ts
439
+ const ast = parse(`<script lang="ts">
440
+ import type { DataTableHeader } from "carbon-components-svelte";
441
+ let headers: DataTableHeader[] = [];
442
+ </script>`);
443
+ const { instance } = analyzeScopes(ast, { types: true });
444
+ instance.get("DataTableHeader")?.references[0]?.type; // true
445
+ ```
446
+
432
447
  ### `a11yWarnings(ast, options?) => A11yWarning[]`
433
448
 
434
449
  From `sveast/a11y`. The `a11y_…` warnings svelte's compiler gives for a component, with the same `code`, `message` and offsets, and without the ones a `<!-- svelte-ignore -->` comment before an element, or one of its ancestors, silences. For a linter that already has the AST: on Carbon's 2,202 components it takes 60 ms, against 735 ms for `compile(source, { generate: false })`. It loads neither acorn nor the parser.
package/index.d.ts CHANGED
@@ -2051,7 +2051,18 @@ export declare function parseSections(source: string, options?: ParseOptions): A
2051
2051
  export declare function isRunesMode(source: string): boolean;
2052
2052
 
2053
2053
  /** How a {@link Binding} is declared. */
2054
- export type BindingKind = "import" | "var" | "let" | "const" | "using" | "function" | "class" | "enum" | "enum-member" | "namespace" | "param" | "catch" | "reactive" | "each" | "each-index" | "let-directive" | "snippet" | "snippet-param" | "const-tag" | "await-value" | "await-error";
2054
+ export type BindingKind = "import" | "var" | "let" | "const" | "using" | "function" | "class" | "enum" | "enum-member" | "namespace" | "param" | "catch" | "reactive" | "each" | "each-index" | "let-directive" | "snippet" | "snippet-param" | "const-tag" | "await-value" | "await-error" | "type" | "interface" | "type-param";
2055
+
2056
+ /** Options for {@link analyzeScopes}. */
2057
+ export interface AnalyzeScopesOptions {
2058
+ /**
2059
+ * Resolve the names in TypeScript's types too: `type`, `interface` and
2060
+ * type parameters declare bindings, in a scope's `types`, and a name in
2061
+ * a type is a {@link Reference} with `type: true`. Defaults to `false`,
2062
+ * which resolves values only, as svelte's analyzer does.
2063
+ */
2064
+ types?: boolean;
2065
+ }
2055
2066
 
2056
2067
  /** A name declared in a {@link Scope}. */
2057
2068
  export interface Binding {
@@ -2064,12 +2075,15 @@ export interface Binding {
2064
2075
  * `"each"` and `"each-index"` (`item` and `i` in `{#each items as item,
2065
2076
  * i}`), `"let-directive"`, `"snippet"` (its name), `"snippet-param"`,
2066
2077
  * `"const-tag"` (`{@const}`), `"await-value"` and `"await-error"` (`{:then
2067
- * value}` and `{:catch error}`).
2078
+ * value}` and `{:catch error}`). With `{ types: true }`, `"type"`,
2079
+ * `"interface"` and `"type-param"` (a type parameter or `infer U`), which
2080
+ * are in a scope's `types`, not its `declarations`, and `"param"` for a
2081
+ * parameter of a function type or signature too.
2068
2082
  */
2069
2083
  readonly kind: BindingKind;
2070
2084
  /**
2071
- * The `Identifier` that declares it; `null` for an each block's index
2072
- * and `let:x` without a value, whose names are strings.
2085
+ * The `Identifier` that declares it; `null` for an each block's index,
2086
+ * `let:x` without a value and a type parameter, whose names are strings.
2073
2087
  */
2074
2088
  readonly node: Identifier | null;
2075
2089
  /**
@@ -2077,14 +2091,17 @@ export interface Binding {
2077
2091
  * `VariableDeclarator`, the function or class, the function a
2078
2092
  * parameter belongs to, the `CatchClause`, the `LabeledStatement` of
2079
2093
  * `$:`, the `EachBlock`, `LetDirective`, `SnippetBlock` or `AwaitBlock`,
2080
- * the enum, enum member or namespace, or `import a = b`.
2094
+ * the enum, enum member or namespace, or `import a = b`; the type
2095
+ * alias, interface or `TSTypeParameter`, or the function type or
2096
+ * signature a parameter belongs to.
2081
2097
  */
2082
2098
  readonly declaration: AST.SvelteNode;
2083
2099
  /**
2084
2100
  * What it starts as, as svelte's analyzer has it: a variable's
2085
2101
  * initializer, the function or class, the `ImportDeclaration`, the
2086
2102
  * `SnippetBlock` for a snippet's name, the `EachBlock` for an index,
2087
- * the right side of `$: x = ...`, an enum member's initializer. For a
2103
+ * the right side of `$: x = ...`, an enum member's initializer, the type
2104
+ * alias or interface. For a
2088
2105
  * prop destructured from `$props()`, its default, without `$bindable`:
2089
2106
  * `"md"` in `let { size = "md" } = $props()` or in `let { size =
2090
2107
  * $bindable("md") } = $props()`. `null` otherwise.
@@ -2148,6 +2165,12 @@ export interface Reference {
2148
2165
  * `$count = 1` mutates it.
2149
2166
  */
2150
2167
  readonly store: boolean;
2168
+ /**
2169
+ * Whether it's in a type, or in `export type { a }`, where it neither
2170
+ * reads, writes nor mutates. Only with `{ types: true }`: `A` in `let
2171
+ * a: A`, `a` in `typeof a`, `I` in `implements I`, `N` in `N.T`.
2172
+ */
2173
+ readonly type: boolean;
2151
2174
  }
2152
2175
 
2153
2176
  /**
@@ -2161,13 +2184,26 @@ export interface Scope {
2161
2184
  */
2162
2185
  readonly node: AST.SvelteNode | null;
2163
2186
  readonly parent: Scope | null;
2164
- /** Its own bindings, by name, in the order they're declared. */
2187
+ /**
2188
+ * Its own bindings, by name, in the order they're declared: the values,
2189
+ * including imports, classes, enums and namespaces, which are types too.
2190
+ */
2165
2191
  readonly declarations: ReadonlyMap<string, Binding>;
2166
2192
  /**
2167
- * The binding `name` refers to here, declared in this scope or one
2168
- * around it; `null` if none does.
2193
+ * Its own type-only bindings, by name: `type`, `interface` and type
2194
+ * parameters. Empty unless `{ types: true }`.
2195
+ */
2196
+ readonly types: ReadonlyMap<string, Binding>;
2197
+ /**
2198
+ * The binding `name` refers to here as a value, declared in this scope
2199
+ * or one around it; `null` if none does.
2169
2200
  */
2170
2201
  get(name: string): Binding | null;
2202
+ /**
2203
+ * The binding `name` refers to here as a type: a `type`, `interface` or
2204
+ * type parameter, or an import, class or enum; `null` if none does.
2205
+ */
2206
+ getType(name: string): Binding | null;
2171
2207
  }
2172
2208
 
2173
2209
  /** What {@link analyzeScopes} found. */
@@ -2223,7 +2259,8 @@ export interface Scopes {
2223
2259
  * prop is passed as.
2224
2260
  *
2225
2261
  * Names in TypeScript types aren't references, and types aren't
2226
- * declarations: `interface` and `type` declare nothing. A top-level
2262
+ * declarations: `interface` and `type` declare nothing, unless `{ types:
2263
+ * true }`, which resolves the names in types too. A top-level
2227
2264
  * snippet is declared in the markup's scope, as in svelte's analyzer, so
2228
2265
  * a `<script>` that uses it refers to a global.
2229
2266
  *
@@ -2240,7 +2277,7 @@ export interface Scopes {
2240
2277
  *
2241
2278
  * It reads the AST but doesn't change it.
2242
2279
  */
2243
- export declare function analyzeScopes(ast: AST.Root | Program): Scopes;
2280
+ export declare function analyzeScopes(ast: AST.Root | Program, options?: AnalyzeScopesOptions): Scopes;
2244
2281
 
2245
2282
  /** The fields of each node type that hold child nodes, in source order. */
2246
2283
  export declare const visitorKeys: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sveast",
3
- "version": "0.9.7",
3
+ "version": "0.9.8",
4
4
  "license": "MIT",
5
5
  "description": "Fast, zero-dependency Svelte 5 parser with svelte/compiler's AST.",
6
6
  "author": "Eric Liu (https://github.com/metonym)",
package/scope.d.ts CHANGED
@@ -1,5 +1,16 @@
1
1
  /** How a {@link Binding} is declared. */
2
- export type BindingKind = "import" | "var" | "let" | "const" | "using" | "function" | "class" | "enum" | "enum-member" | "namespace" | "param" | "catch" | "reactive" | "each" | "each-index" | "let-directive" | "snippet" | "snippet-param" | "const-tag" | "await-value" | "await-error";
2
+ export type BindingKind = "import" | "var" | "let" | "const" | "using" | "function" | "class" | "enum" | "enum-member" | "namespace" | "param" | "catch" | "reactive" | "each" | "each-index" | "let-directive" | "snippet" | "snippet-param" | "const-tag" | "await-value" | "await-error" | "type" | "interface" | "type-param";
3
+
4
+ /** Options for {@link analyzeScopes}. */
5
+ export interface AnalyzeScopesOptions {
6
+ /**
7
+ * Resolve the names in TypeScript's types too: `type`, `interface` and
8
+ * type parameters declare bindings, in a scope's `types`, and a name in
9
+ * a type is a {@link Reference} with `type: true`. Defaults to `false`,
10
+ * which resolves values only, as svelte's analyzer does.
11
+ */
12
+ types?: boolean;
13
+ }
3
14
 
4
15
  /** A name declared in a {@link Scope}. */
5
16
  export interface Binding {
@@ -12,12 +23,15 @@ export interface Binding {
12
23
  * `"each"` and `"each-index"` (`item` and `i` in `{#each items as item,
13
24
  * i}`), `"let-directive"`, `"snippet"` (its name), `"snippet-param"`,
14
25
  * `"const-tag"` (`{@const}`), `"await-value"` and `"await-error"` (`{:then
15
- * value}` and `{:catch error}`).
26
+ * value}` and `{:catch error}`). With `{ types: true }`, `"type"`,
27
+ * `"interface"` and `"type-param"` (a type parameter or `infer U`), which
28
+ * are in a scope's `types`, not its `declarations`, and `"param"` for a
29
+ * parameter of a function type or signature too.
16
30
  */
17
31
  readonly kind: BindingKind;
18
32
  /**
19
- * The `Identifier` that declares it; `null` for an each block's index
20
- * and `let:x` without a value, whose names are strings.
33
+ * The `Identifier` that declares it; `null` for an each block's index,
34
+ * `let:x` without a value and a type parameter, whose names are strings.
21
35
  */
22
36
  readonly node: Identifier | null;
23
37
  /**
@@ -25,14 +39,17 @@ export interface Binding {
25
39
  * `VariableDeclarator`, the function or class, the function a
26
40
  * parameter belongs to, the `CatchClause`, the `LabeledStatement` of
27
41
  * `$:`, the `EachBlock`, `LetDirective`, `SnippetBlock` or `AwaitBlock`,
28
- * the enum, enum member or namespace, or `import a = b`.
42
+ * the enum, enum member or namespace, or `import a = b`; the type
43
+ * alias, interface or `TSTypeParameter`, or the function type or
44
+ * signature a parameter belongs to.
29
45
  */
30
46
  readonly declaration: AST.SvelteNode;
31
47
  /**
32
48
  * What it starts as, as svelte's analyzer has it: a variable's
33
49
  * initializer, the function or class, the `ImportDeclaration`, the
34
50
  * `SnippetBlock` for a snippet's name, the `EachBlock` for an index,
35
- * the right side of `$: x = ...`, an enum member's initializer. For a
51
+ * the right side of `$: x = ...`, an enum member's initializer, the type
52
+ * alias or interface. For a
36
53
  * prop destructured from `$props()`, its default, without `$bindable`:
37
54
  * `"md"` in `let { size = "md" } = $props()` or in `let { size =
38
55
  * $bindable("md") } = $props()`. `null` otherwise.
@@ -96,6 +113,12 @@ export interface Reference {
96
113
  * `$count = 1` mutates it.
97
114
  */
98
115
  readonly store: boolean;
116
+ /**
117
+ * Whether it's in a type, or in `export type { a }`, where it neither
118
+ * reads, writes nor mutates. Only with `{ types: true }`: `A` in `let
119
+ * a: A`, `a` in `typeof a`, `I` in `implements I`, `N` in `N.T`.
120
+ */
121
+ readonly type: boolean;
99
122
  }
100
123
 
101
124
  /**
@@ -109,13 +132,26 @@ export interface Scope {
109
132
  */
110
133
  readonly node: AST.SvelteNode | null;
111
134
  readonly parent: Scope | null;
112
- /** Its own bindings, by name, in the order they're declared. */
135
+ /**
136
+ * Its own bindings, by name, in the order they're declared: the values,
137
+ * including imports, classes, enums and namespaces, which are types too.
138
+ */
113
139
  readonly declarations: ReadonlyMap<string, Binding>;
114
140
  /**
115
- * The binding `name` refers to here, declared in this scope or one
116
- * around it; `null` if none does.
141
+ * Its own type-only bindings, by name: `type`, `interface` and type
142
+ * parameters. Empty unless `{ types: true }`.
143
+ */
144
+ readonly types: ReadonlyMap<string, Binding>;
145
+ /**
146
+ * The binding `name` refers to here as a value, declared in this scope
147
+ * or one around it; `null` if none does.
117
148
  */
118
149
  get(name: string): Binding | null;
150
+ /**
151
+ * The binding `name` refers to here as a type: a `type`, `interface` or
152
+ * type parameter, or an import, class or enum; `null` if none does.
153
+ */
154
+ getType(name: string): Binding | null;
119
155
  }
120
156
 
121
157
  /** What {@link analyzeScopes} found. */
@@ -171,7 +207,8 @@ export interface Scopes {
171
207
  * prop is passed as.
172
208
  *
173
209
  * Names in TypeScript types aren't references, and types aren't
174
- * declarations: `interface` and `type` declare nothing. A top-level
210
+ * declarations: `interface` and `type` declare nothing, unless `{ types:
211
+ * true }`, which resolves the names in types too. A top-level
175
212
  * snippet is declared in the markup's scope, as in svelte's analyzer, so
176
213
  * a `<script>` that uses it refers to a global.
177
214
  *
@@ -188,7 +225,7 @@ export interface Scopes {
188
225
  *
189
226
  * It reads the AST but doesn't change it.
190
227
  */
191
- export declare function analyzeScopes(ast: AST.Root | Program): Scopes;
228
+ export declare function analyzeScopes(ast: AST.Root | Program, options?: AnalyzeScopesOptions): Scopes;
192
229
 
193
230
  interface BaseNodeWithoutComments {
194
231
  type: string;
package/scope.js CHANGED
@@ -1 +1 @@
1
- import{isNode,fieldsOf}from"./shared-m0dcdh24.js";import{extractIdentifiers2,isReference2,valueVisitorKeys2}from"./shared-jpvd0875.js";import{RUNES,RUNE_NAMES}from"./shared-m3dr31c3.js";class ScopeNode{node;parent;porous;index;declarations=new Map;constructor(node,parent,porous,index){this.node=node,this.parent=parent,this.porous=porous,this.index=index}get(name){for(let scope=this;scope;scope=scope.parent){let binding=scope.declarations.get(name);if(binding!==void 0)return binding}return null}}class BindingNode{name;kind;node;declaration;initial;scope;references=[];rune=null;prop=null;constructor(name,kind,node,declaration,initial,scope){this.name=name,this.kind=kind,this.node=node,this.declaration=declaration,this.initial=initial,this.scope=scope}}class ReferenceNode{node;parent;scope;binding=null;reads;writes;mutates;store=!1;constructor(node,parent,scope,reads,writes,mutates){this.node=node,this.parent=parent,this.scope=scope,this.reads=reads,this.writes=writes,this.mutates=mutates}}var keysByType=Object.assign(Object.create(null),valueVisitorKeys2),ELEMENTS=new Set(["SvelteElement","RegularElement","SvelteFragment","Component","SvelteComponent","SvelteSelf","SlotElement"]),NO_BINDINGS=new Map;function analyzeScopes(ast){return new Analysis(ast,!1)}class Analysis{module;instance;instanceProgram=null;component;ast;scopes=[];scopeIn;synthetic=new Map;recorded;made=new Map;declared=new Map;references=new Map;pending=[];declarators=[];implicit=[];stores=new Map;constructor(ast,record){if(this.ast=ast,this.scopeIn=record?new Map:null,ast.type==="Program")this.component=!1,this.module=this.scope(ast,null,!1),this.instance=this.module,this.made.set(ast,this.module),this.visit(ast,null,this.module);else{this.component=!0;let module=ast.module?.content??null,instance=ast.instance?.content??null;this.module=this.scope(module,null,!1),this.instance=this.scope(instance,this.module,!1),this.instanceProgram=instance,this.scopeIn?.set(ast,this.module);for(let[script,scope]of[[ast.module,this.module],[ast.instance,this.instance]]){if(script===void 0)continue;this.scopeIn?.set(script,scope),this.made.set(script.content,scope);for(let attribute of script.attributes)this.visit(attribute,script,scope);this.visit(script.content,script,scope)}this.visit(ast.fragment,ast,this.instance)}this.declareImplicit(),this.resolve(),this.findRunesAndProps()}scopeOf(node){let synthetic=this.synthetic.get(node);if(synthetic!==void 0)return synthetic;if(this.scopeIn!==null)return this.scopeIn.get(node)??null;this.recorded??=new Analysis(this.ast,!0);let recorded=this.recorded.scopeIn?.get(node);return recorded===void 0?null:this.scopes[recorded.index]}scope(node,parent,porous){let scope=new ScopeNode(node,parent,porous,this.scopes.length);return this.scopes.push(scope),scope}bindingOf(node){return this.declared.get(node)??this.references.get(node)?.binding??null}referenceOf(node){return this.references.get(node)??null}declaredIn(node){return this.made.get(node)?.declarations??NO_BINDINGS}child(scope,node,porous){let made=this.scope(node,scope,porous);return this.made.set(node,made),made}declare(scope,node,name,kind,declaration,initial){let target=scope;if(kind==="var")while(target.porous&&target.parent!==null)target=target.parent;let existing=target.declarations.get(name);if(existing!==void 0&&existing.declaration.type!=="TSDeclareFunction"){if(node!==null)this.declared.set(node,existing);return}let binding=new BindingNode(name,kind,node,declaration,initial,target);if(target.declarations.set(name,binding),node!==null)this.declared.set(node,binding)}reference(node,parent,scope,reads,writes,mutates){this.pending.push(new ReferenceNode(node,parent,scope,reads,writes,mutates))}referenceName(name,start,parent,scope){let root=name.split(".")[0],node={type:"Identifier",name:root,start,end:start+root.length};this.synthetic.set(node,scope),this.reference(node,parent,scope,!0,!1,!1)}visit(node,parent,scope){switch(this.scopeIn?.set(node,scope),node.type){case"Identifier":if(parent!==null&&isReference2(node,parent))this.reference(node,parent,scope,!0,!1,!1);this.visitFields(node,scope);return;case"ImportDeclaration":for(let specifier of node.specifiers){if(this.scopeIn?.set(specifier,scope),this.scopeIn?.set(specifier.local,scope),specifier.type==="ImportSpecifier")this.scopeIn?.set(specifier.imported,scope);this.declare(scope,specifier.local,specifier.local.name,"import",specifier,node)}this.visit(node.source,node,scope);for(let attribute of node.attributes??[])this.visit(attribute,node,scope);return;case"ExportNamedDeclaration":if(node.declaration)this.visit(node.declaration,node,scope);for(let specifier of node.specifiers)if(this.scopeIn?.set(specifier,scope),this.scopeIn?.set(specifier.local,scope),this.scopeIn?.set(specifier.exported,scope),!node.source&&specifier.local.type==="Identifier")this.reference(specifier.local,specifier,scope,!0,!1,!1);if(node.source)this.visit(node.source,node,scope);for(let attribute of node.attributes??[])this.visit(attribute,node,scope);return;case"VariableDeclaration":this.visitDeclaration(node,parent,scope);return;case"FunctionDeclaration":if(node.id)this.scopeIn?.set(node.id,scope),this.declare(scope,node.id,node.id.name,"function",node,node);this.visitFunction(node,this.child(scope,node,!0));return;case"FunctionExpression":{let inner=this.child(scope,node,!0);if(node.id)this.scopeIn?.set(node.id,inner),this.declare(inner,node.id,node.id.name,"function",node,node);this.visitFunction(node,inner);return}case"ArrowFunctionExpression":this.visitFunction(node,this.child(scope,node,!0));return;case"ClassDeclaration":case"ClassExpression":{let inner=scope;if(node.id){if(node.type==="ClassExpression")inner=this.child(scope,node,!1);this.scopeIn?.set(node.id,inner),this.declare(inner,node.id,node.id.name,"class",node,node)}for(let decorator of node.decorators??[])this.visit(decorator,node,scope);if(node.superClass)this.visit(node.superClass,node,inner);this.visit(node.body,node,inner);return}case"BlockStatement":this.visitFields(node,this.child(scope,node,!(parent!==null&&isFunction(parent)&&parent.body===node)));return;case"StaticBlock":this.visitFields(node,this.child(scope,node,!1));return;case"ForStatement":case"SwitchStatement":this.visitFields(node,this.child(scope,node,!0));return;case"ForInStatement":case"ForOfStatement":{let inner=this.child(scope,node,!0);if(node.left.type==="VariableDeclaration")this.visit(node.left,node,inner);else this.visitTarget(node.left,node,inner,!1);this.visit(node.right,node,inner),this.visit(node.body,node,inner);return}case"CatchClause":{if(!node.param)break;let inner=this.child(scope,node,!0);this.declarePattern(node.param,node,inner,"catch",node,null),this.visit(node.body,node,inner);return}case"AssignmentExpression":this.visitTarget(node.left,node,scope,node.operator!=="="),this.visit(node.right,node,scope);return;case"UpdateExpression":this.visitTarget(node.argument,node,scope,!0);return;case"LabeledStatement":if(parent===this.instanceProgram&&node.label.name==="$"){this.visitReactive(node,scope);return}break;case"TSEnumDeclaration":{this.scopeIn?.set(node.id,scope),this.declare(scope,node.id,node.id.name,"enum",node,node);let inner=this.child(scope,node,!1);for(let member of node.members)if(this.scopeIn?.set(member,inner),this.scopeIn?.set(member.id,inner),member.id.type==="Identifier")this.declare(inner,member.id,member.id.name,"enum-member",member,member.initializer??null);for(let member of node.members)if(member.initializer)this.visit(member.initializer,member,inner);return}case"TSModuleDeclaration":if(this.scopeIn?.set(node.id,scope),node.id.type==="Identifier"&&!node.global)this.declare(scope,node.id,node.id.name,"namespace",node,node);if(node.body)this.visit(node.body,node,this.child(scope,node,!1));return;case"TSImportEqualsDeclaration":{this.scopeIn?.set(node.id,scope),this.declare(scope,node.id,node.id.name,"import",node,node.moduleReference);let name=node.moduleReference;while(name.type==="TSQualifiedName")this.scopeIn?.set(name,scope),this.scopeIn?.set(name.right,scope),name=name.left;if(name.type==="Identifier")this.scopeIn?.set(name,scope),this.reference(name,node,scope,!0,!1,!1);else this.visit(name,node,scope);return}case"TSDeclareFunction":if(node.id){if(this.scopeIn?.set(node.id,scope),!scope.declarations.has(node.id.name))this.declare(scope,node.id,node.id.name,"function",node,node)}return;case"Fragment":this.visitFields(node,this.child(scope,node,!1));return;case"RegularElement":case"SvelteElement":case"SlotElement":case"SvelteFragment":this.visitFields(node,this.child(scope,node,!1));return;case"Component":case"SvelteComponent":case"SvelteSelf":this.visitComponent(node,scope);return;case"LetDirective":this.visitLet(node,scope);return;case"EachBlock":this.visitEach(node,scope);return;case"AwaitBlock":this.visitAwait(node,scope);return;case"SnippetBlock":{this.scopeIn?.set(node.expression,scope);let{name}=node.expression;this.declare(scope,node.expression,name,"snippet",node,node);let inner=this.child(scope,node,!1);for(let parameter of node.parameters??[])this.declarePattern(parameter,node,inner,"snippet-param",node,null);this.visit(node.body,node,inner);return}case"BindDirective":if(node.expression.type==="SequenceExpression")break;this.visitTarget(node.expression,node,scope,!0);return;case"TransitionDirective":case"AnimateDirective":case"UseDirective":{this.referenceName(node.name,node.start+prefixLength(node),node,scope);break}case"StyleDirective":if(node.value===!0)this.referenceName(node.name,node.start+6,node,scope);break}this.visitFields(node,scope)}visitFields(node,scope){let keys=keysByType[node.type];if(keys===void 0)throw Error(`unknown node type: ${node.type}`);let fields=fieldsOf(node);for(let k=0;k<keys.length;k++){let value=fields[keys[k]];if(Array.isArray(value))for(let i=0;i<value.length;i++){let child=value[i];if(isNode(child))this.visit(child,node,scope)}else if(isNode(value))this.visit(value,node,scope)}}visitDeclaration(node,parent,scope){let kind=node.kind==="await using"?"using":node.kind;if(parent?.type==="ConstTag")kind="const-tag";for(let declarator of node.declarations)if(this.scopeIn?.set(declarator,scope),this.declarePattern(declarator.id,declarator,scope,kind,declarator,declarator.init??null),this.declarators.push([declarator,scope]),declarator.init)this.visit(declarator.init,declarator,scope)}visitFunction(node,scope){for(let param of node.params){if(param.type==="Identifier"&&param.name==="this"){this.scopeIn?.set(param,scope);continue}this.declarePattern(param,node,scope,"param",node,null)}this.visit(node.body,node,scope)}declarePattern(pattern,parent,scope,kind,declaration,initial){switch(this.scopeIn?.set(pattern,scope),pattern.type){case"Identifier":this.declare(scope,pattern,pattern.name,kind,declaration,initial);break;case"ObjectPattern":for(let property of pattern.properties){if(this.scopeIn?.set(property,scope),property.type==="RestElement"){this.declarePattern(property,pattern,scope,kind,declaration,initial);continue}if(property.computed)this.visit(property.key,property,scope);else this.scopeIn?.set(property.key,scope);this.declarePattern(property.value,property,scope,kind,declaration,initial)}break;case"ArrayPattern":for(let element of pattern.elements)if(element)this.declarePattern(element,pattern,scope,kind,declaration,initial);break;case"RestElement":this.declarePattern(pattern.argument,pattern,scope,kind,declaration,initial);break;case"AssignmentPattern":this.declarePattern(pattern.left,pattern,scope,kind,declaration,initial),this.visit(pattern.right,pattern,scope);break;case"TSParameterProperty":this.declarePattern(pattern.parameter,pattern,scope,kind,declaration,initial);break;default:this.visit(pattern,parent,scope);return}if("decorators"in pattern&&pattern.decorators)for(let decorator of pattern.decorators)this.visit(decorator,pattern,scope)}visitTarget(target,parent,scope,reads){switch(this.scopeIn?.set(target,scope),target.type){case"Identifier":this.reference(target,parent,scope,reads,!0,!1);return;case"MemberExpression":{let object=target,holder=parent;while(object.type==="MemberExpression"){if(this.scopeIn?.set(object,scope),object.computed)this.visit(object.property,object,scope);else this.scopeIn?.set(object.property,scope);holder=object,object=object.object}if(object.type==="Identifier")this.scopeIn?.set(object,scope),this.reference(object,holder,scope,!0,!1,!0);else this.visit(object,holder,scope);return}case"ObjectPattern":for(let property of target.properties){if(this.scopeIn?.set(property,scope),property.type==="RestElement"){this.visitTarget(property,target,scope,!1);continue}if(property.computed)this.visit(property.key,property,scope);else this.scopeIn?.set(property.key,scope);this.visitTarget(property.value,property,scope,!1)}return;case"ArrayPattern":for(let element of target.elements)if(element)this.visitTarget(element,target,scope,!1);return;case"RestElement":this.visitTarget(target.argument,target,scope,!1);return;case"AssignmentPattern":this.visitTarget(target.left,target,scope,!1),this.visit(target.right,target,scope);return}if(target.type==="TSAsExpression"||target.type==="TSSatisfiesExpression"||target.type==="TSNonNullExpression"||target.type==="TSTypeAssertion"){this.visitTarget(target.expression,target,scope,reads);return}this.visit(target,parent,scope)}visitReactive(node,scope){let inner=this.child(scope,node,!1);this.scopeIn?.set(node.label,scope);let{body}=node;if(body.type==="ExpressionStatement"&&body.expression.type==="AssignmentExpression"){let{left,right}=body.expression;for(let id of extractIdentifiers2(left))if(!id.name.startsWith("$"))this.implicit.push([id,node,right])}this.visit(body,node,inner)}visitComponent(node,scope){if(node.type==="Component")this.referenceName(node.name,node.start+1,node,scope);let slotted=slotOf(node)!==null,defaults=this.scope(node,scope,!1),lets=slotted?scope:defaults;if(this.made.set(node,lets),node.type==="SvelteComponent")this.visit(node.expression,node,scope);for(let attribute of node.attributes)this.visit(attribute,node,attribute.type==="LetDirective"?lets:scope);this.scopeIn?.set(node.fragment,defaults);for(let child of node.fragment.nodes){let slot=slotOf(child);this.visit(child,node.fragment,slot===null?defaults:this.child(scope,child,!1))}}visitLet(node,scope){if(node.expression===null){this.declare(scope,null,node.name,"let-directive",node,null);return}let declare=(expression)=>{switch(this.scopeIn?.set(expression,scope),expression.type){case"Identifier":this.declare(scope,expression,expression.name,"let-directive",node,null);return;case"ObjectExpression":for(let property of expression.properties)if(this.scopeIn?.set(property,scope),property.type==="SpreadElement")declare(property.argument);else this.scopeIn?.set(property.key,scope),declare(property.value);return;case"ArrayExpression":for(let element of expression.elements){if(element===null)continue;if(element.type==="SpreadElement")this.scopeIn?.set(element,scope),declare(element.argument);else declare(element)}}};declare(node.expression)}visitEach(node,scope){if(this.visit(node.expression,node,scope),node.fallback)this.visit(node.fallback,node,scope);let inner=this.child(scope,node,!1);if(node.context)this.declarePattern(node.context,node,inner,"each",node,null);if(node.index!==void 0)this.declare(inner,null,node.index,"each-index",node,node);if(node.key)this.visit(node.key,node,inner);this.scopeIn?.set(node.body,inner);for(let child of node.body.nodes)this.visit(child,node.body,inner)}visitAwait(node,scope){if(this.visit(node.expression,node,scope),node.pending)this.visit(node.pending,node,scope);for(let[fragment,pattern,kind]of[[node.then,node.value,"await-value"],[node.catch,node.error,"await-error"]]){if(fragment===null)continue;this.visit(fragment,node,scope);let inner=this.made.get(fragment);if(pattern!==null&&inner!==void 0)this.declarePattern(pattern,node,inner,kind,node,null)}}declareImplicit(){for(let[id,label,right]of this.implicit)if(this.instance.get(id.name)===null)this.declare(this.instance,id,id.name,"reactive",label,right)}resolve(){let unordered=new Set;for(let reference of this.pending){let{node}=reference,declared=this.declared.get(node);if(declared!==void 0&&declared.kind!=="reactive")continue;this.references.set(node,reference);let binding=reference.scope.get(node.name);if(binding===null&&this.component){let store=this.storeOf(node.name);if(store!==!1)reference.store=!0,reference.mutates||=reference.writes,reference.reads=!0,reference.writes=!1,binding=store}if(binding!==null){reference.binding=binding;let last=binding.references.at(-1);if(last!==void 0&&last.node.start>node.start)unordered.add(binding);binding.references.push(reference)}}for(let binding of unordered)binding.references.sort((a,b)=>a.node.start-b.node.start)}storeOf(name){let cached=this.stores.get(name);if(cached!==void 0)return cached;let store=!1;if(name.length>1&&name.startsWith("$")&&!name.startsWith("$$")){let declaration=this.instance.get(name.slice(1));if(!RUNE_NAMES.has(name))store=declaration;else if(declaration!==null){let initial=declaration.initial,rune=runeOf(initial,this.instance,null);if((rune===null||name!=="$props"&&rune==="$props")&&!(name==="$derived"&&initial?.type==="ImportDeclaration"&&initial.source.value==="svelte/store"))store=declaration}}return this.stores.set(name,store),store}findRunesAndProps(){for(let[declarator,scope]of this.declarators){let rune=runeOf(declarator.init??null,scope,this.references);if(rune===null)continue;for(let id of extractIdentifiers2(declarator.id)){let binding=this.declared.get(id);if(binding?.declaration===declarator)binding.rune=rune}if(rune!=="$props")continue;if(declarator.id.type==="Identifier"){let binding=this.declared.get(declarator.id);if(binding)binding.initial=null;continue}if(declarator.id.type!=="ObjectPattern")continue;for(let property of declarator.id.properties){if(property.type==="RestElement"){for(let id of extractIdentifiers2(property)){let binding=this.declared.get(id);if(binding)binding.initial=null}continue}let value=property.value.type==="AssignmentPattern"?property.value.left:property.value,binding=value.type==="Identifier"?this.declared.get(value):void 0;if(binding===void 0||property.computed)continue;binding.prop=keyName(property.key),binding.initial=property.value.type==="AssignmentPattern"?unwrapBindable(property.value.right):null}}this.findLegacyProps()}findLegacyProps(){if(this.instanceProgram===null)return;for(let statement of this.instanceProgram.body){if(statement.type!=="ExportNamedDeclaration")continue;let{declaration}=statement;if(declaration?.type==="VariableDeclaration"){if(declaration.kind!=="let"&&declaration.kind!=="var")continue;for(let declarator of declaration.declarations)for(let id of extractIdentifiers2(declarator.id)){let binding=this.declared.get(id);if(binding)binding.prop=id.name}continue}if(statement.source)continue;for(let specifier of statement.specifiers){if(specifier.local.type!=="Identifier")continue;let binding=this.instance.declarations.get(specifier.local.name);if(binding?.kind!=="let"&&binding?.kind!=="var")continue;binding.prop=specifier.exported.type==="Identifier"?specifier.exported.name:String(specifier.exported.value)}}}}function isFunction(node){return node.type==="ArrowFunctionExpression"||node.type==="FunctionExpression"||node.type==="FunctionDeclaration"}function slotOf(node){if(!ELEMENTS.has(node.type)||!("attributes"in node))return null;for(let attribute of node.attributes??[])if(attribute.type==="Attribute"&&attribute.name==="slot"&&Array.isArray(attribute.value)&&attribute.value.length===1&&attribute.value[0].type==="Text")return attribute.value[0].data;return null}function runeOf(initial,scope,references){if(initial?.type!=="CallExpression")return null;let node=initial.callee,keypath="";while(node.type==="MemberExpression"){if(node.computed||node.property.type!=="Identifier")return null;keypath=`.${node.property.name}${keypath}`,node=node.object}if(node.type==="CallExpression"&&node.callee.type==="Identifier")keypath=`()${keypath}`,node=node.callee;if(node.type!=="Identifier")return null;if(references!==null){let reference=references.get(node);if(reference?.binding!==null||reference.store)return null}else if(scope.get(node.name)!==null)return null;return keypath=node.name+keypath,RUNES.has(keypath)?keypath:null}function unwrapBindable(node){if(node.type==="CallExpression"&&node.callee.type==="Identifier"&&node.callee.name==="$bindable"){let[argument]=node.arguments;return argument===void 0||argument.type==="SpreadElement"?null:argument}return node}function prefixLength(node){if(node.type==="UseDirective")return 4;if(node.type==="AnimateDirective")return 8;if(node.intro&&node.outro)return 11;return node.intro?3:4}function keyName(key){if(key.type==="Identifier")return key.name;return key.type==="Literal"?String(key.value):null}export{analyzeScopes};
1
+ import{isNode,fieldsOf}from"./shared-m0dcdh24.js";import{extractIdentifiers2,isReference2,visitorKeys2,valueVisitorKeys2}from"./shared-jpvd0875.js";import{RUNES,RUNE_NAMES}from"./shared-m3dr31c3.js";class ScopeNode{node;parent;porous;index;declarations=new Map;types=new Map;constructor(node,parent,porous,index){this.node=node,this.parent=parent,this.porous=porous,this.index=index}get(name){for(let scope=this;scope;scope=scope.parent){let binding=scope.declarations.get(name);if(binding!==void 0)return binding}return null}getType(name){return this.lookup(name,TYPE)}lookup(name,meaning){if(meaning===VALUE)return this.get(name);let kinds=meaning===TYPE?TYPE_KINDS:NAMESPACE_KINDS;for(let scope=this;scope;scope=scope.parent){if(meaning===TYPE){let type=scope.types.get(name);if(type!==void 0)return type}let binding=scope.declarations.get(name);if(binding!==void 0&&kinds.has(binding.kind))return binding}return null}}class BindingNode{name;kind;node;declaration;initial;scope;references=[];rune=null;prop=null;constructor(name,kind,node,declaration,initial,scope){this.name=name,this.kind=kind,this.node=node,this.declaration=declaration,this.initial=initial,this.scope=scope}}class ReferenceNode{node;parent;scope;binding=null;reads;writes;mutates;store=!1;type;meaning;constructor(node,parent,scope,reads,writes,mutates,type,meaning){this.node=node,this.parent=parent,this.scope=scope,this.reads=reads,this.writes=writes,this.mutates=mutates,this.type=type,this.meaning=meaning}}var VALUE=0,TYPE=1,NAMESPACE=2,ANY=3,TYPE_KINDS=new Set(["import","class","enum"]),NAMESPACE_KINDS=new Set(["import","enum","namespace"]);function holdsTypes(type){return type==="MethodDefinition"||type.startsWith("TS")}var keysByType=Object.assign(Object.create(null),valueVisitorKeys2),typedKeysByType=Object.create(null);for(let[type,all]of Object.entries(visitorKeys2)){let values=keysByType[type]??[],types=all.filter((key)=>!values.includes(key));typedKeysByType[type]={values,types:types.length>0?types:null,all}}var ELEMENTS=new Set(["SvelteElement","RegularElement","SvelteFragment","Component","SvelteComponent","SvelteSelf","SlotElement"]),NO_BINDINGS=new Map;function analyzeScopes(ast,options){return new Analysis(ast,!1,options?.types===!0)}class Analysis{module;instance;instanceProgram=null;component;ast;scopes=[];scopeIn;synthetic=new Map;recorded;made=new Map;declared=new Map;references=new Map;pending=[];declarators=[];implicit=[];stores=new Map;types;inType=!1;inferScope=null;constructor(ast,record,types){if(this.ast=ast,this.scopeIn=record?new Map:null,this.types=types,ast.type==="Program")this.component=!1,this.module=this.scope(ast,null,!1),this.instance=this.module,this.made.set(ast,this.module),this.visit(ast,null,this.module);else{this.component=!0;let module=ast.module?.content??null,instance=ast.instance?.content??null;this.module=this.scope(module,null,!1),this.instance=this.scope(instance,this.module,!1),this.instanceProgram=instance,this.scopeIn?.set(ast,this.module);for(let[script,scope]of[[ast.module,this.module],[ast.instance,this.instance]]){if(script===void 0)continue;this.scopeIn?.set(script,scope),this.made.set(script.content,scope);for(let attribute of script.attributes)this.visit(attribute,script,scope);this.visit(script.content,script,scope)}this.visit(ast.fragment,ast,this.instance)}this.declareImplicit(),this.resolve(),this.findRunesAndProps()}scopeOf(node){let synthetic=this.synthetic.get(node);if(synthetic!==void 0)return synthetic;if(this.scopeIn!==null)return this.scopeIn.get(node)??null;this.recorded??=new Analysis(this.ast,!0,this.types);let recorded=this.recorded.scopeIn?.get(node);return recorded===void 0?null:this.scopes[recorded.index]}scope(node,parent,porous){let scope=new ScopeNode(node,parent,porous,this.scopes.length);return this.scopes.push(scope),scope}bindingOf(node){return this.declared.get(node)??this.references.get(node)?.binding??null}referenceOf(node){return this.references.get(node)??null}declaredIn(node){return this.made.get(node)?.declarations??NO_BINDINGS}child(scope,node,porous){let made=this.scope(node,scope,porous);return this.made.set(node,made),made}declare(scope,node,name,kind,declaration,initial){let target=scope;if(kind==="var")while(target.porous&&target.parent!==null)target=target.parent;let declarations=kind==="type"||kind==="interface"||kind==="type-param"?target.types:target.declarations,existing=declarations.get(name);if(existing!==void 0&&existing.declaration.type!=="TSDeclareFunction"){if(node!==null)this.declared.set(node,existing);return}let binding=new BindingNode(name,kind,node,declaration,initial,target);if(declarations.set(name,binding),node!==null)this.declared.set(node,binding)}reference(node,parent,scope,reads,writes,mutates,meaning=VALUE,type=this.inType){this.pending.push(type?new ReferenceNode(node,parent,scope,!1,!1,!1,!0,meaning):new ReferenceNode(node,parent,scope,reads,writes,mutates,!1,meaning))}referenceName(name,start,parent,scope){let root=name.split(".")[0],node={type:"Identifier",name:root,start,end:start+root.length};this.synthetic.set(node,scope),this.reference(node,parent,scope,!0,!1,!1)}visit(node,parent,scope){switch(this.scopeIn?.set(node,scope),node.type){case"Identifier":if(parent!==null&&(this.inType?isReferenceInType(node,parent):isReference2(node,parent)))this.reference(node,parent,scope,!0,!1,!1);this.visitFields(node,scope);return;case"ImportDeclaration":for(let specifier of node.specifiers){if(this.scopeIn?.set(specifier,scope),this.scopeIn?.set(specifier.local,scope),specifier.type==="ImportSpecifier")this.scopeIn?.set(specifier.imported,scope);this.declare(scope,specifier.local,specifier.local.name,"import",specifier,node)}this.visit(node.source,node,scope);for(let attribute of node.attributes??[])this.visit(attribute,node,scope);return;case"ExportNamedDeclaration":if(node.declaration)this.visit(node.declaration,node,scope);for(let specifier of node.specifiers)if(this.scopeIn?.set(specifier,scope),this.scopeIn?.set(specifier.local,scope),this.scopeIn?.set(specifier.exported,scope),!node.source&&specifier.local.type==="Identifier")this.reference(specifier.local,specifier,scope,!0,!1,!1,this.types?ANY:VALUE,this.types&&(node.exportKind==="type"||specifier.exportKind==="type"));if(node.source)this.visit(node.source,node,scope);for(let attribute of node.attributes??[])this.visit(attribute,node,scope);return;case"VariableDeclaration":this.visitDeclaration(node,parent,scope);return;case"FunctionDeclaration":if(node.id)this.scopeIn?.set(node.id,scope),this.declare(scope,node.id,node.id.name,"function",node,node);this.visitFunction(node,this.child(scope,node,!0));return;case"FunctionExpression":{let inner=this.child(scope,node,!0);if(node.id)this.scopeIn?.set(node.id,inner),this.declare(inner,node.id,node.id.name,"function",node,node);this.visitFunction(node,inner);return}case"ArrowFunctionExpression":this.visitFunction(node,this.child(scope,node,!0));return;case"ClassDeclaration":case"ClassExpression":{let generic=this.types&&node.typeParameters!==void 0,inner=node.id&&node.type==="ClassExpression"||generic?this.child(scope,node,!1):scope;if(node.id){let at=node.type==="ClassExpression"?inner:scope;this.scopeIn?.set(node.id,at),this.declare(at,node.id,node.id.name,"class",node,node)}for(let decorator of node.decorators??[])this.visit(decorator,node,scope);if(this.declareTypeParameters(node.typeParameters,inner),node.superClass)this.visit(node.superClass,node,inner);this.visitType(node.superTypeParameters,node,inner),this.visitType(node.implements,node,inner),this.visit(node.body,node,inner);return}case"BlockStatement":this.visitFields(node,this.child(scope,node,!(parent!==null&&isFunction(parent)&&parent.body===node)));return;case"StaticBlock":this.visitFields(node,this.child(scope,node,!1));return;case"ForStatement":case"SwitchStatement":this.visitFields(node,this.child(scope,node,!0));return;case"ForInStatement":case"ForOfStatement":{let inner=this.child(scope,node,!0);if(node.left.type==="VariableDeclaration")this.visit(node.left,node,inner);else this.visitTarget(node.left,node,inner,!1);this.visit(node.right,node,inner),this.visit(node.body,node,inner);return}case"CatchClause":{if(!node.param)break;let inner=this.child(scope,node,!0);this.declarePattern(node.param,node,inner,"catch",node,null),this.visit(node.body,node,inner);return}case"AssignmentExpression":this.visitTarget(node.left,node,scope,node.operator!=="="),this.visit(node.right,node,scope);return;case"UpdateExpression":this.visitTarget(node.argument,node,scope,!0);return;case"LabeledStatement":if(parent===this.instanceProgram&&node.label.name==="$"){this.visitReactive(node,scope);return}break;case"TSEnumDeclaration":{this.scopeIn?.set(node.id,scope),this.declare(scope,node.id,node.id.name,"enum",node,node);let inner=this.child(scope,node,!1);for(let member of node.members)if(this.scopeIn?.set(member,inner),this.scopeIn?.set(member.id,inner),member.id.type==="Identifier")this.declare(inner,member.id,member.id.name,"enum-member",member,member.initializer??null);for(let member of node.members)if(member.initializer)this.visit(member.initializer,member,inner);return}case"TSModuleDeclaration":if(this.scopeIn?.set(node.id,scope),node.id.type==="Identifier"&&!node.global)this.declare(scope,node.id,node.id.name,"namespace",node,node);if(node.body)this.visit(node.body,node,this.child(scope,node,!1));return;case"TSImportEqualsDeclaration":{this.scopeIn?.set(node.id,scope),this.declare(scope,node.id,node.id.name,"import",node,node.moduleReference);let name=node.moduleReference;while(name.type==="TSQualifiedName")this.scopeIn?.set(name,scope),this.scopeIn?.set(name.right,scope),name=name.left;if(name.type==="Identifier")this.scopeIn?.set(name,scope),this.reference(name,node,scope,!0,!1,!1);else this.visit(name,node,scope);return}case"TSDeclareFunction":if(node.id){if(this.scopeIn?.set(node.id,scope),!scope.declarations.has(node.id.name))this.declare(scope,node.id,node.id.name,"function",node,node)}if(this.types)this.visitSignature(node,node.typeParameters,node.params,node.returnType,scope);return;case"Fragment":this.visitFields(node,this.child(scope,node,!1));return;case"RegularElement":case"SvelteElement":case"SlotElement":case"SvelteFragment":this.visitFields(node,this.child(scope,node,!1));return;case"Component":case"SvelteComponent":case"SvelteSelf":this.visitComponent(node,scope);return;case"LetDirective":this.visitLet(node,scope);return;case"EachBlock":this.visitEach(node,scope);return;case"AwaitBlock":this.visitAwait(node,scope);return;case"SnippetBlock":{this.scopeIn?.set(node.expression,scope);let{name}=node.expression;this.declare(scope,node.expression,name,"snippet",node,node);let inner=this.child(scope,node,!1);for(let parameter of node.parameters??[])this.declarePattern(parameter,node,inner,"snippet-param",node,null);this.visit(node.body,node,inner);return}case"BindDirective":if(node.expression.type==="SequenceExpression")break;this.visitTarget(node.expression,node,scope,!0);return;case"TransitionDirective":case"AnimateDirective":case"UseDirective":{this.referenceName(node.name,node.start+prefixLength(node),node,scope);break}case"StyleDirective":if(node.value===!0)this.referenceName(node.name,node.start+6,node,scope);break}if(this.types&&holdsTypes(node.type)&&this.visitTyped(node,scope))return;this.visitFields(node,scope)}visitTyped(node,scope){switch(node.type){case"MethodDefinition":{if(node.typeParameters===void 0)return!1;this.visitChild(node.decorators,node,scope),this.visit(node.key,node,scope);let inner=this.child(scope,node,!1);return this.declareTypeParameters(node.typeParameters,inner),this.visit(node.value,node,inner),!0}case"TSDeclareMethod":return this.visitSignature(node,node.typeParameters,node.params,node.returnType,scope),!0;case"TSFunctionType":case"TSConstructorType":case"TSCallSignatureDeclaration":case"TSConstructSignatureDeclaration":return this.visitSignature(node,node.typeParameters,node.parameters,node.typeAnnotation,scope),!0;case"TSMethodSignature":if(node.computed)this.visit(node.key,node,scope);else this.scopeIn?.set(node.key,scope);return this.visitSignature(node,node.typeParameters,node.parameters,node.typeAnnotation,scope),!0;case"TSTypeAliasDeclaration":case"TSInterfaceDeclaration":{let kind=node.type==="TSTypeAliasDeclaration"?"type":"interface";this.scopeIn?.set(node.id,scope),this.declare(scope,node.id,node.id.name,kind,node,node);let inner=node.typeParameters?this.child(scope,node,!1):scope;if(this.declareTypeParameters(node.typeParameters,inner),node.type==="TSTypeAliasDeclaration")this.visitType(node.typeAnnotation,node,inner);else this.visitType(node.extends,node,inner),this.visitType(node.body,node,inner);return!0}case"TSTypeReference":return this.visitEntityName(node.typeName,node,scope,TYPE),this.visitChild(node.typeArguments,node,scope),!0;case"TSExpressionWithTypeArguments":return this.visitEntityName(node.expression,node,scope,TYPE),this.visitChild(node.typeParameters,node,scope),!0;case"TSTypeQuery":return this.visitEntityName(node.exprName,node,scope,VALUE),this.visitChild(node.typeArguments,node,scope),!0;case"TSImportType":{this.visit(node.argument,node,scope);let name=node.qualifier;while(name!==void 0){if(this.scopeIn?.set(name,scope),name.type!=="TSQualifiedName")break;this.scopeIn?.set(name.right,scope),name=name.left}return this.visitChild(node.typeArguments,node,scope),!0}case"TSMappedType":{let parameter=node.typeParameter;this.scopeIn?.set(parameter,scope),this.visitChild(parameter.constraint,parameter,scope);let inner=this.child(scope,node,!1);return this.declare(inner,null,parameter.name,"type-param",parameter,null),this.visitChild(node.nameType,node,inner),this.visitChild(node.typeAnnotation,node,inner),!0}case"TSConditionalType":{this.visit(node.checkType,node,scope);let inner=this.child(scope,node,!1),outer=this.inferScope;return this.inferScope=inner,this.visit(node.extendsType,node,inner),this.inferScope=outer,this.visit(node.trueType,node,inner),this.visit(node.falseType,node,scope),!0}case"TSInferType":{let parameter=node.typeParameter;return this.scopeIn?.set(parameter,scope),this.declare(this.inferScope??scope,null,parameter.name,"type-param",parameter,null),this.visitChild(parameter.constraint,parameter,scope),!0}}return!1}visitFields(node,scope){if(this.types){this.visitTypedFields(node,scope);return}let keys=keysByType[node.type];if(keys===void 0)throw Error(`unknown node type: ${node.type}`);let fields=fieldsOf(node);for(let k=0;k<keys.length;k++){let value=fields[keys[k]];if(Array.isArray(value))for(let i=0;i<value.length;i++){let child=value[i];if(isNode(child))this.visit(child,node,scope)}else if(isNode(value))this.visit(value,node,scope)}}visitTypedFields(node,scope){let keys=typedKeysByType[node.type];if(keys===void 0)throw Error(`unknown node type: ${node.type}`);if(this.inType){this.visitKeys(node,keys.all,scope);return}if(keys.types!==null){let fields=fieldsOf(node);for(let k=0;k<keys.types.length;k++){let value=fields[keys.types[k]];if(value!=null)this.visitType(value,node,scope)}}this.visitKeys(node,keys.values,scope)}visitKeys(node,keys,scope){let fields=fieldsOf(node);for(let k=0;k<keys.length;k++){let value=fields[keys[k]];if(Array.isArray(value))for(let i=0;i<value.length;i++){let child=value[i];if(isNode(child))this.visit(child,node,scope)}else if(isNode(value))this.visit(value,node,scope)}}visitChild(value,parent,scope){if(Array.isArray(value))for(let i=0;i<value.length;i++){let child=value[i];if(isNode(child))this.visit(child,parent,scope)}else if(isNode(value))this.visit(value,parent,scope)}visitType(value,parent,scope){if(!this.types||value===void 0||value===null)return;let outer=this.inType;this.inType=!0,this.visitChild(value,parent,scope),this.inType=outer}declareTypeParameters(declaration,scope){if(!this.types||declaration===void 0)return;this.scopeIn?.set(declaration,scope);for(let parameter of declaration.params)this.scopeIn?.set(parameter,scope),this.declare(scope,null,parameter.name,"type-param",parameter,null);for(let parameter of declaration.params)this.visitType(parameter.constraint,parameter,scope),this.visitType(parameter.default,parameter,scope)}visitSignature(node,typeParameters,parameters,returnType,scope){let inner=this.child(scope,node,!0);this.declareTypeParameters(typeParameters,inner),this.declareParameters(parameters,node,inner),this.visitType(returnType,node,inner)}declareParameters(parameters,node,scope){for(let param of parameters){if(param.type==="Identifier"&&param.name==="this"){if(this.scopeIn?.set(param,scope),this.types)this.visitType(param.typeAnnotation,param,scope);continue}this.declarePattern(param,node,scope,"param",node,null)}}visitEntityName(entity,parent,scope,meaning){if(entity.type==="TSImportType"){this.visit(entity,parent,scope);return}let name=entity,holder=parent;while(name.type==="TSQualifiedName")this.scopeIn?.set(name,scope),this.scopeIn?.set(name.right,scope),holder=name,name=name.left;if(this.scopeIn?.set(name,scope),name.name==="this")return;let qualified=name!==entity&&meaning===TYPE;this.reference(name,holder,scope,!0,!1,!1,qualified?NAMESPACE:meaning)}visitDeclaration(node,parent,scope){let kind=node.kind==="await using"?"using":node.kind;if(parent?.type==="ConstTag")kind="const-tag";for(let declarator of node.declarations)if(this.scopeIn?.set(declarator,scope),this.declarePattern(declarator.id,declarator,scope,kind,declarator,declarator.init??null),this.declarators.push([declarator,scope]),declarator.init)this.visit(declarator.init,declarator,scope)}visitFunction(node,scope){if(this.types)this.declareTypeParameters(node.typeParameters,scope);if(this.declareParameters(node.params,node,scope),this.types)this.visitType(node.returnType,node,scope);this.visit(node.body,node,scope)}declarePattern(pattern,parent,scope,kind,declaration,initial){switch(this.scopeIn?.set(pattern,scope),pattern.type){case"Identifier":this.declare(scope,pattern,pattern.name,kind,declaration,initial);break;case"ObjectPattern":for(let property of pattern.properties){if(this.scopeIn?.set(property,scope),property.type==="RestElement"){this.declarePattern(property,pattern,scope,kind,declaration,initial);continue}if(property.computed)this.visit(property.key,property,scope);else this.scopeIn?.set(property.key,scope);this.declarePattern(property.value,property,scope,kind,declaration,initial)}break;case"ArrayPattern":for(let element of pattern.elements)if(element)this.declarePattern(element,pattern,scope,kind,declaration,initial);break;case"RestElement":this.declarePattern(pattern.argument,pattern,scope,kind,declaration,initial);break;case"AssignmentPattern":this.declarePattern(pattern.left,pattern,scope,kind,declaration,initial),this.visit(pattern.right,pattern,scope);break;case"TSParameterProperty":this.declarePattern(pattern.parameter,pattern,scope,kind,declaration,initial);break;default:this.visit(pattern,parent,scope);return}if("decorators"in pattern&&pattern.decorators)for(let decorator of pattern.decorators)this.visit(decorator,pattern,scope);if(this.types&&"typeAnnotation"in pattern&&pattern.typeAnnotation)this.visitType(pattern.typeAnnotation,pattern,scope)}visitTarget(target,parent,scope,reads){switch(this.scopeIn?.set(target,scope),target.type){case"Identifier":this.reference(target,parent,scope,reads,!0,!1);return;case"MemberExpression":{let object=target,holder=parent;while(object.type==="MemberExpression"){if(this.scopeIn?.set(object,scope),object.computed)this.visit(object.property,object,scope);else this.scopeIn?.set(object.property,scope);holder=object,object=object.object}if(object.type==="Identifier")this.scopeIn?.set(object,scope),this.reference(object,holder,scope,!0,!1,!0);else this.visit(object,holder,scope);return}case"ObjectPattern":for(let property of target.properties){if(this.scopeIn?.set(property,scope),property.type==="RestElement"){this.visitTarget(property,target,scope,!1);continue}if(property.computed)this.visit(property.key,property,scope);else this.scopeIn?.set(property.key,scope);this.visitTarget(property.value,property,scope,!1)}return;case"ArrayPattern":for(let element of target.elements)if(element)this.visitTarget(element,target,scope,!1);return;case"RestElement":this.visitTarget(target.argument,target,scope,!1);return;case"AssignmentPattern":this.visitTarget(target.left,target,scope,!1),this.visit(target.right,target,scope);return}if(target.type==="TSAsExpression"||target.type==="TSSatisfiesExpression"||target.type==="TSNonNullExpression"||target.type==="TSTypeAssertion"){if(this.visitTarget(target.expression,target,scope,reads),target.type!=="TSNonNullExpression")this.visitType(target.typeAnnotation,target,scope);return}this.visit(target,parent,scope)}visitReactive(node,scope){let inner=this.child(scope,node,!1);this.scopeIn?.set(node.label,scope);let{body}=node;if(body.type==="ExpressionStatement"&&body.expression.type==="AssignmentExpression"){let{left,right}=body.expression;for(let id of extractIdentifiers2(left))if(!id.name.startsWith("$"))this.implicit.push([id,node,right])}this.visit(body,node,inner)}visitComponent(node,scope){if(node.type==="Component")this.referenceName(node.name,node.start+1,node,scope);let slotted=slotOf(node)!==null,defaults=this.scope(node,scope,!1),lets=slotted?scope:defaults;if(this.made.set(node,lets),node.type==="SvelteComponent")this.visit(node.expression,node,scope);for(let attribute of node.attributes)this.visit(attribute,node,attribute.type==="LetDirective"?lets:scope);this.scopeIn?.set(node.fragment,defaults);for(let child of node.fragment.nodes){let slot=slotOf(child);this.visit(child,node.fragment,slot===null?defaults:this.child(scope,child,!1))}}visitLet(node,scope){if(node.expression===null){this.declare(scope,null,node.name,"let-directive",node,null);return}let declare=(expression)=>{switch(this.scopeIn?.set(expression,scope),expression.type){case"Identifier":this.declare(scope,expression,expression.name,"let-directive",node,null);return;case"ObjectExpression":for(let property of expression.properties)if(this.scopeIn?.set(property,scope),property.type==="SpreadElement")declare(property.argument);else this.scopeIn?.set(property.key,scope),declare(property.value);return;case"ArrayExpression":for(let element of expression.elements){if(element===null)continue;if(element.type==="SpreadElement")this.scopeIn?.set(element,scope),declare(element.argument);else declare(element)}}};declare(node.expression)}visitEach(node,scope){if(this.visit(node.expression,node,scope),node.fallback)this.visit(node.fallback,node,scope);let inner=this.child(scope,node,!1);if(node.context)this.declarePattern(node.context,node,inner,"each",node,null);if(node.index!==void 0)this.declare(inner,null,node.index,"each-index",node,node);if(node.key)this.visit(node.key,node,inner);this.scopeIn?.set(node.body,inner);for(let child of node.body.nodes)this.visit(child,node.body,inner)}visitAwait(node,scope){if(this.visit(node.expression,node,scope),node.pending)this.visit(node.pending,node,scope);for(let[fragment,pattern,kind]of[[node.then,node.value,"await-value"],[node.catch,node.error,"await-error"]]){if(fragment===null)continue;this.visit(fragment,node,scope);let inner=this.made.get(fragment);if(pattern!==null&&inner!==void 0)this.declarePattern(pattern,node,inner,kind,node,null)}}declareImplicit(){for(let[id,label,right]of this.implicit)if(this.instance.get(id.name)===null)this.declare(this.instance,id,id.name,"reactive",label,right)}resolve(){let unordered=new Set;for(let reference of this.pending){let{node}=reference,declared=this.declared.get(node);if(declared!==void 0&&declared.kind!=="reactive")continue;this.references.set(node,reference);let{meaning}=reference,binding;if(meaning===VALUE)binding=reference.scope.get(node.name);else if(meaning!==ANY)binding=reference.scope.lookup(node.name,meaning);else if(reference.type)binding=reference.scope.getType(node.name)??reference.scope.get(node.name);else if(binding=reference.scope.get(node.name),binding===null){if(binding=reference.scope.getType(node.name),binding!==null)reference.type=!0,reference.reads=!1}if(binding===null&&this.component&&meaning!==TYPE){let store=this.storeOf(node.name);if(store!==!1)reference.store=!0,reference.mutates||=reference.writes,reference.reads=!reference.type,reference.writes=!1,binding=store}if(binding!==null){reference.binding=binding;let last=binding.references.at(-1);if(last!==void 0&&last.node.start>node.start)unordered.add(binding);binding.references.push(reference)}}for(let binding of unordered)binding.references.sort((a,b)=>a.node.start-b.node.start)}storeOf(name){let cached=this.stores.get(name);if(cached!==void 0)return cached;let store=!1;if(name.length>1&&name.startsWith("$")&&!name.startsWith("$$")){let declaration=this.instance.get(name.slice(1));if(!RUNE_NAMES.has(name))store=declaration;else if(declaration!==null){let initial=declaration.initial,rune=runeOf(initial,this.instance,null);if((rune===null||name!=="$props"&&rune==="$props")&&!(name==="$derived"&&initial?.type==="ImportDeclaration"&&initial.source.value==="svelte/store"))store=declaration}}return this.stores.set(name,store),store}findRunesAndProps(){for(let[declarator,scope]of this.declarators){let rune=runeOf(declarator.init??null,scope,this.references);if(rune===null)continue;for(let id of extractIdentifiers2(declarator.id)){let binding=this.declared.get(id);if(binding?.declaration===declarator)binding.rune=rune}if(rune!=="$props")continue;if(declarator.id.type==="Identifier"){let binding=this.declared.get(declarator.id);if(binding)binding.initial=null;continue}if(declarator.id.type!=="ObjectPattern")continue;for(let property of declarator.id.properties){if(property.type==="RestElement"){for(let id of extractIdentifiers2(property)){let binding=this.declared.get(id);if(binding)binding.initial=null}continue}let value=property.value.type==="AssignmentPattern"?property.value.left:property.value,binding=value.type==="Identifier"?this.declared.get(value):void 0;if(binding===void 0||property.computed)continue;binding.prop=keyName(property.key),binding.initial=property.value.type==="AssignmentPattern"?unwrapBindable(property.value.right):null}}this.findLegacyProps()}findLegacyProps(){if(this.instanceProgram===null)return;for(let statement of this.instanceProgram.body){if(statement.type!=="ExportNamedDeclaration")continue;let{declaration}=statement;if(declaration?.type==="VariableDeclaration"){if(declaration.kind!=="let"&&declaration.kind!=="var")continue;for(let declarator of declaration.declarations)for(let id of extractIdentifiers2(declarator.id)){let binding=this.declared.get(id);if(binding)binding.prop=id.name}continue}if(statement.source)continue;for(let specifier of statement.specifiers){if(specifier.local.type!=="Identifier")continue;let binding=this.instance.declarations.get(specifier.local.name);if(binding?.kind!=="let"&&binding?.kind!=="var")continue;binding.prop=specifier.exported.type==="Identifier"?specifier.exported.name:String(specifier.exported.value)}}}}function isReferenceInType(node,parent){switch(parent.type){case"TSPropertySignature":case"TSMethodSignature":return parent.computed===!0&&node===parent.key;case"TSTypePredicate":return node===parent.parameterName;default:return isReference2(node,parent)}}function isFunction(node){return node.type==="ArrowFunctionExpression"||node.type==="FunctionExpression"||node.type==="FunctionDeclaration"}function slotOf(node){if(!ELEMENTS.has(node.type)||!("attributes"in node))return null;for(let attribute of node.attributes??[])if(attribute.type==="Attribute"&&attribute.name==="slot"&&Array.isArray(attribute.value)&&attribute.value.length===1&&attribute.value[0].type==="Text")return attribute.value[0].data;return null}function runeOf(initial,scope,references){if(initial?.type!=="CallExpression")return null;let node=initial.callee,keypath="";while(node.type==="MemberExpression"){if(node.computed||node.property.type!=="Identifier")return null;keypath=`.${node.property.name}${keypath}`,node=node.object}if(node.type==="CallExpression"&&node.callee.type==="Identifier")keypath=`()${keypath}`,node=node.callee;if(node.type!=="Identifier")return null;if(references!==null){let reference=references.get(node);if(reference?.binding!==null||reference.store)return null}else if(scope.get(node.name)!==null)return null;return keypath=node.name+keypath,RUNES.has(keypath)?keypath:null}function unwrapBindable(node){if(node.type==="CallExpression"&&node.callee.type==="Identifier"&&node.callee.name==="$bindable"){let[argument]=node.arguments;return argument===void 0||argument.type==="SpreadElement"?null:argument}return node}function prefixLength(node){if(node.type==="UseDirective")return 4;if(node.type==="AnimateDirective")return 8;if(node.intro&&node.outro)return 11;return node.intro?3:4}function keyName(key){if(key.type==="Identifier")return key.name;return key.type==="Literal"?String(key.value):null}export{analyzeScopes};