yuku-analyzer 0.5.32

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/index.d.ts ADDED
@@ -0,0 +1,578 @@
1
+ /**
2
+ * yuku-analyzer: semantic analysis for JavaScript and TypeScript.
3
+ */
4
+
5
+ import type {
6
+ Comment,
7
+ Diagnostic,
8
+ DiagnosticSeverity,
9
+ Identifier,
10
+ JSXIdentifier,
11
+ Node,
12
+ NodeOfType,
13
+ NodeType,
14
+ Program,
15
+ ScanCursor as BaseScanCursor,
16
+ SourceLang,
17
+ SourceLocation,
18
+ SourceType,
19
+ WalkContext as BaseWalkContext,
20
+ } from "@yuku/types";
21
+
22
+ /** A diagnostic produced by {@link Analyzer.link}. */
23
+ interface LinkDiagnostic {
24
+ severity: DiagnosticSeverity;
25
+ message: string;
26
+ /** Path of the module the diagnostic belongs to. */
27
+ module: string;
28
+ start: number;
29
+ end: number;
30
+ }
31
+
32
+ /** Options for {@link Analyzer.addFile}. */
33
+ interface AddFileOptions {
34
+ /**
35
+ * Language variant. Defaults to the file extension via
36
+ * {@link langFromPath}.
37
+ */
38
+ lang?: SourceLang;
39
+ /**
40
+ * Parse as a script or an ES module. Defaults to the file extension
41
+ * via {@link sourceTypeFromPath}.
42
+ */
43
+ sourceType?: SourceType;
44
+ /**
45
+ * Represent parenthesized expressions as `ParenthesizedExpression`
46
+ * nodes.
47
+ * @default true
48
+ */
49
+ preserveParens?: boolean;
50
+ /**
51
+ * Allow `return` at the top level.
52
+ * @default false
53
+ */
54
+ allowReturnOutsideFunction?: boolean;
55
+ /**
56
+ * Attach comments to their host AST nodes.
57
+ * @default false
58
+ */
59
+ attachComments?: boolean;
60
+ }
61
+
62
+ /** Options for {@link Analyzer}. */
63
+ interface AnalyzerOptions {
64
+ /**
65
+ * Host module resolution. Maps an import specifier and the importing
66
+ * module's path to the path of an added file, or null for external
67
+ * modules. Defaults to relative-path resolution among added files
68
+ * with standard extension and index probing.
69
+ */
70
+ resolve?: (specifier: string, importerPath: string) => string | null;
71
+ }
72
+
73
+ /**
74
+ * Bit flags describing a {@link Symbol}: which declaration kinds it
75
+ * carries (one symbol can merge several under TS declaration merging)
76
+ * and its modifiers, plus a few composite categories. Every categorical
77
+ * question about a symbol is `symbol.has(SymbolFlags.X)` (any of the
78
+ * bits) or `symbol.hasAll(...)` (all of them); there is one way to ask.
79
+ */
80
+ declare const SymbolFlags: {
81
+ /** `var`, parameter, or catch variable. */
82
+ readonly FunctionScopedVariable: number;
83
+ /** `let`, `const`, `using`, `await using`. */
84
+ readonly BlockScopedVariable: number;
85
+ /** Function declaration or expression. */
86
+ readonly Function: number;
87
+ /** Class declaration or expression. */
88
+ readonly Class: number;
89
+ /** TS `enum`. */
90
+ readonly RegularEnum: number;
91
+ /** TS `const enum`. */
92
+ readonly ConstEnum: number;
93
+ /** TS namespace with runtime content. */
94
+ readonly ValueModule: number;
95
+ /** TS `interface`. */
96
+ readonly Interface: number;
97
+ /** TS `type` alias. */
98
+ readonly TypeAlias: number;
99
+ /** TS `<T>`, `infer T`, or mapped-type key. */
100
+ readonly TypeParameter: number;
101
+ /** TS namespace of any kind. */
102
+ readonly NamespaceModule: number;
103
+ /** A value import binding (`import x` / `import { x }`). */
104
+ readonly ValueImport: number;
105
+ /** `import type` / `import { type x }` binding. */
106
+ readonly TypeImport: number;
107
+ /** `const` or `using` binding. */
108
+ readonly Const: number;
109
+ /** TS `declare`. */
110
+ readonly Ambient: number;
111
+ /** Function or method parameter. */
112
+ readonly Parameter: number;
113
+ /** `catch (e)` binding. */
114
+ readonly CatchVariable: number;
115
+ /** Exported from its module. */
116
+ readonly Exported: number;
117
+ /** The default export. */
118
+ readonly Default: number;
119
+
120
+ /** Composite: any variable (`var` / `let` / `const`, params, catch). */
121
+ readonly Variable: number;
122
+ /** Composite: any import binding, value or `import type`. */
123
+ readonly Import: number;
124
+ /** Composite: visible at runtime (var, function, class, enum, value namespace). */
125
+ readonly ValueSpace: number;
126
+ /** Composite: referencable from a type position (class, enum, interface, alias, type param). */
127
+ readonly TypeSpace: number;
128
+ };
129
+
130
+ /** What kind of construct created a {@link Scope}. */
131
+ type ScopeKind =
132
+ | "global"
133
+ | "module"
134
+ | "function"
135
+ | "block"
136
+ | "class"
137
+ | "staticBlock"
138
+ | "expressionName"
139
+ | "tsModule";
140
+
141
+ /** A lexical scope in a module's scope tree. */
142
+ interface Scope {
143
+ /** The owning module. */
144
+ readonly module: Module;
145
+ /** Stable id, the index into {@link Module.scopes}. */
146
+ readonly id: number;
147
+ readonly kind: ScopeKind;
148
+ /** Whether this scope is in strict mode. */
149
+ readonly strict: boolean;
150
+ /** The AST node that created this scope. */
151
+ readonly node: Node;
152
+ /** The parent scope, or null for the global scope. */
153
+ readonly parent: Scope | null;
154
+ /** The nearest scope (or self) where `var` declarations land. */
155
+ readonly hoistTarget: Scope;
156
+ /** Symbols declared directly in this scope. */
157
+ readonly bindings: Symbol[];
158
+ /** Looks up `name` declared directly in this scope. */
159
+ find(name: string): Symbol | null;
160
+ /** True when `other` is this scope or a descendant of it. */
161
+ contains(other: Scope): boolean;
162
+ /** Walks from this scope up to the global scope, inclusive. */
163
+ ancestors(): IterableIterator<Scope>;
164
+ }
165
+
166
+ /**
167
+ * A declared binding. One symbol can have several declarations under
168
+ * TS declaration merging (overloads, class + interface, namespace
169
+ * merges).
170
+ */
171
+ interface Symbol {
172
+ /** The owning module. */
173
+ readonly module: Module;
174
+ /**
175
+ * Stable id, the index into {@link Module.symbols}. Deterministic per
176
+ * parse: `(module.path, id)` is a persistable key.
177
+ */
178
+ readonly id: number;
179
+ readonly name: string;
180
+ /** Raw {@link SymbolFlags} bitset. */
181
+ readonly flags: number;
182
+ /** The scope this symbol is declared in. */
183
+ readonly scope: Scope;
184
+ /** Every declarator node, in source order. */
185
+ readonly declarations: Node[];
186
+ /** Every resolved use site within this module, in source order. */
187
+ readonly references: Reference[];
188
+ /**
189
+ * True when any flag in `mask` is set. The single way to ask what a
190
+ * symbol is: `symbol.has(SymbolFlags.Function)`, or a composite like
191
+ * `symbol.has(SymbolFlags.ValueSpace)`.
192
+ */
193
+ has(mask: number): boolean;
194
+ /** True when every flag in `mask` is set. */
195
+ hasAll(mask: number): boolean;
196
+ /**
197
+ * The defining site of this symbol, following import/re-export chains
198
+ * across modules. Shorthand for {@link Analyzer.definitionOf}.
199
+ */
200
+ definition(): Definition | null;
201
+ }
202
+
203
+ /** One use of a name: a single identifier in reference position. */
204
+ interface Reference {
205
+ /** The owning module. */
206
+ readonly module: Module;
207
+ /** Stable id, the index into {@link Module.references}. */
208
+ readonly id: number;
209
+ readonly name: string;
210
+ /** The scope the reference occurs in. */
211
+ readonly scope: Scope;
212
+ /** The identifier node, the same object as in the walked AST. */
213
+ readonly node: Identifier | JSXIdentifier;
214
+ /** `"value"` for runtime uses, `"type"` for TS type-position uses. */
215
+ readonly kind: "value" | "type";
216
+ /**
217
+ * True when this reference (re)assigns its binding: assignment
218
+ * targets, `++`/`--` operands, for-in/of iteration variables, and
219
+ * destructuring assignment leaves. Compound targets (`+=`) both read
220
+ * and write.
221
+ */
222
+ readonly isWrite: boolean;
223
+ /** The symbol this resolves to, or null for free/global names. */
224
+ readonly symbol: Symbol | null;
225
+ }
226
+
227
+ /**
228
+ * The semantic walk context: the toolchain's {@link BaseWalkContext} (the
229
+ * same position info and mutation operations, exact same semantics)
230
+ * plus the module's semantic surface. One object is reused across the
231
+ * whole walk; do not hold onto it across nodes.
232
+ *
233
+ * On mutation: semantic tables are a snapshot of the parsed source, so
234
+ * new nodes have no symbols, references, or spans of their own.
235
+ * Analyze, transform, then print (or re-analyze the printed output for
236
+ * fresh semantics).
237
+ */
238
+ declare class WalkContext<T extends Node = Node> extends BaseWalkContext<T> {
239
+ /** The module being walked. Every semantic query is in reach. */
240
+ readonly module: Module;
241
+ /**
242
+ * The innermost scope at the current node, replayed from the native
243
+ * scope tree (catch-scope sharing, named-expression scopes, and
244
+ * hoist targets are all exact).
245
+ */
246
+ readonly scope: Scope;
247
+ /** Shorthand for `module.symbolOf(node)`. */
248
+ readonly symbol: Symbol | null;
249
+ /** Shorthand for `module.referenceOf(node)`. */
250
+ readonly reference: Reference | null;
251
+ }
252
+
253
+ /** Handler invoked with the precisely-typed node and the walk context. */
254
+ type WalkHandler<T extends Node = Node> = (node: T, ctx: WalkContext<T>) => void;
255
+
256
+ /** Enter/leave pair for one node type. */
257
+ interface WalkHooks<T extends Node = Node> {
258
+ enter?: WalkHandler<T>;
259
+ leave?: WalkHandler<T>;
260
+ }
261
+
262
+ /**
263
+ * Visitors passed to {@link Module.walk}: keys are node `type` strings, plus optional `enter` /
264
+ * `leave` catch-alls. Order per node: catch-all `enter`, typed enter,
265
+ * children, typed leave, catch-all `leave`.
266
+ */
267
+ type Visitors = {
268
+ [K in NodeType]?: WalkHandler<NodeOfType<K>> | WalkHooks<NodeOfType<K>>;
269
+ } & {
270
+ enter?: WalkHandler;
271
+ leave?: WalkHandler;
272
+ };
273
+
274
+ /**
275
+ * The semantic scan cursor: the toolchain's {@link BaseScanCursor} plus
276
+ * symbol and reference lookups. Both are index-keyed, so a scan can
277
+ * resolve semantics without materializing any AST nodes.
278
+ */
279
+ interface ScanCursor<T extends Node = Node> extends BaseScanCursor<T> {
280
+ /** The module being scanned. */
281
+ readonly module: Module;
282
+ /** Shorthand for `module.symbolOf(node)`, without materializing. */
283
+ readonly symbol: Symbol | null;
284
+ /** Shorthand for `module.referenceOf(node)`, without materializing. */
285
+ readonly reference: Reference | null;
286
+ }
287
+
288
+ /** Scan handlers keyed by node `type`, plus the universal `enter`. */
289
+ type ScanVisitors = {
290
+ [K in NodeType]?: (cursor: ScanCursor<NodeOfType<K>>) => void;
291
+ } & {
292
+ enter?: (cursor: ScanCursor) => void;
293
+ };
294
+
295
+ /** A free variable of a function, as reported by {@link Module.capturesOf}. */
296
+ interface Capture {
297
+ /** The outer binding being closed over. */
298
+ readonly symbol: Symbol;
299
+ /** The capturing reference sites inside the function. */
300
+ readonly references: Reference[];
301
+ /** True when the function writes to the binding. */
302
+ readonly isWritten: boolean;
303
+ }
304
+
305
+ /** One imported binding (or side-effect import) of a module. */
306
+ interface Import {
307
+ /** The importing module. */
308
+ readonly module: Module;
309
+ /** Stable id, the index into {@link Module.imports}. */
310
+ readonly id: number;
311
+ /** The local binding symbol, or null for side-effect imports. */
312
+ readonly local: Symbol | null;
313
+ /**
314
+ * The imported export name, `"default"` for default imports (the
315
+ * spec models default as a name). Null for namespace and side-effect
316
+ * imports.
317
+ */
318
+ readonly name: string | null;
319
+ /** True for `import * as ns`. */
320
+ readonly isNamespace: boolean;
321
+ /** True for bare `import "m"`. */
322
+ readonly isSideEffect: boolean;
323
+ /** True for `import type` / `import { type x }`. */
324
+ readonly typeOnly: boolean;
325
+ /** Stage 3 phase modifier, or null. */
326
+ readonly phase: "source" | "defer" | null;
327
+ readonly specifier: string;
328
+ /** The specifier node (the declaration for side-effect imports). */
329
+ readonly node: Node;
330
+ /** The defining module, or null when external. Links on demand. */
331
+ readonly resolvedModule: Module | null;
332
+ }
333
+
334
+ /** One exported name of a module. */
335
+ interface Export {
336
+ /** The exporting module. */
337
+ readonly module: Module;
338
+ /** Stable id, the index into {@link Module.exports}. */
339
+ readonly id: number;
340
+ /**
341
+ * The exported name (`"default"` included), or null for `export *`,
342
+ * `export =`, and `export as namespace`.
343
+ */
344
+ readonly name: string | null;
345
+ /** True for `export * from "m"` without an alias. */
346
+ readonly isStar: boolean;
347
+ /** True for TS `export = expr` (the module's entire export value). */
348
+ readonly isExportEquals: boolean;
349
+ /** The TS `export as namespace N` global name, or null. */
350
+ readonly globalName: string | null;
351
+ readonly typeOnly: boolean;
352
+ /** The backing local symbol, or null (re-exports, anonymous defaults). */
353
+ readonly local: Symbol | null;
354
+ /** The re-export source specifier, or null for local exports. */
355
+ readonly specifier: string | null;
356
+ /** The name taken from the source module, or null (namespace / `export *`). */
357
+ readonly fromName: string | null;
358
+ /** True for `export *` and `export * as ns from "m"`. */
359
+ readonly isNamespaceReexport: boolean;
360
+ readonly node: Node;
361
+ /** The re-export source module, or null. Links on demand. */
362
+ readonly resolvedModule: Module | null;
363
+ }
364
+
365
+ /**
366
+ * One analyzed source file: its AST, per-file semantics, and module
367
+ * records. Created by {@link Analyzer.addFile}. All queries are local
368
+ * (no native calls).
369
+ */
370
+ interface Module {
371
+ readonly analyzer: Analyzer;
372
+ readonly path: string;
373
+ readonly source: string;
374
+
375
+ /**
376
+ * The ESTree / TypeScript-ESTree program. Lazily decoded. Nodes are
377
+ * identity-shared with every semantic query result.
378
+ *
379
+ * Nodes are plain mutable objects: edit them in place, mutate them
380
+ * during a walk with {@link WalkContext.replace} and friends, and
381
+ * print the result with `yuku-codegen`. Semantic tables stay a
382
+ * snapshot of the parsed source and do not track mutations.
383
+ */
384
+ readonly ast: Program;
385
+ /** Syntax and semantic diagnostics for this file. */
386
+ readonly diagnostics: Diagnostic[];
387
+ /** Every comment in source order. */
388
+ readonly comments: Comment[];
389
+ /** Sorted offsets where each line begins. */
390
+ readonly lineStarts: number[];
391
+ /** Resolves an offset to a `(line, column)` pair. */
392
+ locOf(offset: number): SourceLocation;
393
+
394
+ /** Every lexical scope; index is the scope id. `scopes[0]` is global. */
395
+ readonly scopes: Scope[];
396
+ /** The scope top-level code runs in: module scope, or global for scripts. */
397
+ readonly rootScope: Scope;
398
+ /** Every declared symbol; index is the symbol id. */
399
+ readonly symbols: Symbol[];
400
+ /** Every identifier reference in source order; index is the reference id. */
401
+ readonly references: Reference[];
402
+ /** References resolving to no binding: globals and free names. */
403
+ readonly unresolvedReferences: Reference[];
404
+
405
+ /**
406
+ * The symbol a node refers to: its own symbol for a declaration
407
+ * identifier, the resolved symbol for a reference identifier. Null
408
+ * for nodes that are neither, or for unresolved references.
409
+ */
410
+ symbolOf(node: Node): Symbol | null;
411
+ /** The reference recorded for an identifier node, or null. */
412
+ referenceOf(node: Node): Reference | null;
413
+ /** The innermost scope whose extent contains `node`. */
414
+ scopeOf(node: Node): Scope;
415
+ /**
416
+ * Walks the scope chain from `from` (default: the root scope) to
417
+ * find the nearest binding of `name`.
418
+ */
419
+ resolve(name: string, from?: Scope): Symbol | null;
420
+ /**
421
+ * The free variables of a function or arrow: every binding referenced
422
+ * inside it (nested closures included, value positions only) that is
423
+ * declared outside it. Shadowing- and alias-correct, because it rides
424
+ * the resolved reference table.
425
+ *
426
+ * Only bindings count: `this`, `arguments`, and unresolved/global
427
+ * names carry no symbol and never appear. Module-scope and import
428
+ * bindings count like any other outer binding; filter on the
429
+ * symbol's scope to narrow.
430
+ *
431
+ * Throws when `node` is not a function of this module's AST.
432
+ */
433
+ capturesOf(node: Node): Capture[];
434
+ /**
435
+ * Every name this module exports, directly or through `export *`
436
+ * chains (the spec's GetExportedNames). Ambiguous star names are
437
+ * included; `"default"` never crosses an `export *` boundary. Links
438
+ * on demand.
439
+ */
440
+ exportedNames(): string[];
441
+
442
+ /**
443
+ * Walks the AST (or the subtree under `root`) with semantic context.
444
+ * Scope information is replayed from the native scope tree, so
445
+ * non-scope nodes pay a single type lookup and nothing else.
446
+ */
447
+ walk(visitors: Visitors, root?: Node): void;
448
+
449
+ /**
450
+ * Readonly buffer scan with semantic context: visits the parsed node
451
+ * records directly without materializing AST objects, and resolves
452
+ * symbols and references in index space. Many times faster than
453
+ * {@link walk} for sparse queries; call {@link ScanCursor.node} to
454
+ * materialize a matched node (identity-shared with the walked AST).
455
+ */
456
+ scan(visitors: ScanVisitors): void;
457
+ /** Collects every node of the given type(s), in source order. */
458
+ findAll<K extends NodeType>(type: K): NodeOfType<K>[];
459
+ findAll<K extends NodeType>(types: readonly K[]): NodeOfType<K>[];
460
+
461
+ /** Import records, in source order. */
462
+ readonly imports: Import[];
463
+ /** Export records, in source order. */
464
+ readonly exports: Export[];
465
+ /** Modules this module imports from. Links on demand. */
466
+ readonly dependencies: Module[];
467
+ /** Modules that import from this module. Links on demand. */
468
+ readonly dependents: Module[];
469
+ }
470
+
471
+ /** A symbol's defining site, possibly in another module. */
472
+ interface Definition {
473
+ readonly module: Module;
474
+ /**
475
+ * The defining symbol, or null when the definition is a whole module
476
+ * namespace (`import * as ns`, `export * as ns`).
477
+ */
478
+ readonly symbol: Symbol | null;
479
+ }
480
+
481
+ /** A cross-module reference, as reported by {@link Analyzer.referencesOf}. */
482
+ interface ModuleReference {
483
+ readonly module: Module;
484
+ readonly reference: Reference;
485
+ }
486
+
487
+ /**
488
+ * The project: a set of analyzed modules and the links between them.
489
+ *
490
+ * ```ts
491
+ * const analyzer = new Analyzer();
492
+ * analyzer.addFile("src/app.tsx", source);
493
+ * const sym = analyzer.module("src/app.tsx")!.symbolOf(node);
494
+ * const def = sym?.definition();
495
+ * ```
496
+ */
497
+ declare class Analyzer {
498
+ constructor(options?: AnalyzerOptions);
499
+
500
+ /**
501
+ * Parses and analyzes one file natively, returning its {@link Module}.
502
+ * Adding an existing path replaces it and marks the graph for
503
+ * relinking.
504
+ */
505
+ addFile(path: string, source: string, options?: AddFileOptions): Module;
506
+ /** Removes a file. Returns whether it existed. */
507
+ removeFile(path: string): boolean;
508
+ /** The module added under `path`, if any. */
509
+ module(path: string): Module | undefined;
510
+ /** All modules, keyed by path. */
511
+ readonly modules: ReadonlyMap<string, Module>;
512
+ /** Graph-level diagnostics. Links on demand. */
513
+ readonly diagnostics: LinkDiagnostic[];
514
+
515
+ /**
516
+ * Joins imports to exports across every added module: resolves
517
+ * specifiers through the host resolver, populates
518
+ * {@link Import.resolvedModule}, {@link Module.dependencies} /
519
+ * {@link Module.dependents}, and reports unresolvable or ambiguous
520
+ * names. Resolution follows the spec's ResolveExport semantics: a
521
+ * name supplied by multiple `export *` declarations through
522
+ * different bindings is an error, and `"default"` is never satisfied
523
+ * by `export *`.
524
+ *
525
+ * Calling this is optional: every cross-file surface links on demand
526
+ * after files change. Call it explicitly to control when the work
527
+ * (and its diagnostics) happen.
528
+ */
529
+ link(): void;
530
+
531
+ /**
532
+ * Follows import -> export -> re-export chains to the symbol that
533
+ * actually defines `symbol`. A null `symbol` in the result means a
534
+ * module namespace. Returns null when the chain leaves the added
535
+ * file set (external modules), does not resolve, or is ambiguous.
536
+ */
537
+ definitionOf(symbol: Symbol): Definition | null;
538
+
539
+ /**
540
+ * Every reference to `symbol` across the whole graph: local uses
541
+ * plus uses of every import binding that resolves back to it.
542
+ */
543
+ referencesOf(symbol: Symbol): ModuleReference[];
544
+ }
545
+
546
+ /** Resolves a {@link SourceLang} from a file path's extension. */
547
+ declare function langFromPath(path: string): SourceLang;
548
+
549
+ /** Resolves a {@link SourceType} from a file path's extension. */
550
+ declare function sourceTypeFromPath(path: string): SourceType;
551
+
552
+ export {
553
+ Analyzer,
554
+ SymbolFlags,
555
+ langFromPath,
556
+ sourceTypeFromPath,
557
+ type AddFileOptions,
558
+ type AnalyzerOptions,
559
+ type Capture,
560
+ type Definition,
561
+ type Export,
562
+ type Import,
563
+ type LinkDiagnostic,
564
+ type Module,
565
+ type ModuleReference,
566
+ type NodeOfType,
567
+ type NodeType,
568
+ type Reference,
569
+ type ScanCursor,
570
+ type ScanVisitors,
571
+ type Scope,
572
+ type ScopeKind,
573
+ type Symbol,
574
+ type Visitors,
575
+ type WalkContext,
576
+ type WalkHandler,
577
+ type WalkHooks,
578
+ };
package/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { Analyzer } from "./analyzer.js";
2
+ export { SymbolFlags, langFromPath, sourceTypeFromPath } from "./module.js";