yuku-ast 0.1.7 → 0.6.7
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 +86 -103
- package/dist/index.d.ts +493 -0
- package/dist/index.js +1393 -0
- package/package.json +29 -40
- package/src/aliases.ts +190 -0
- package/src/builders.ts +27 -0
- package/src/context.ts +110 -0
- package/src/generated.ts +372 -0
- package/src/identifier.ts +138 -0
- package/src/index.ts +44 -0
- package/src/is.ts +94 -0
- package/src/modules.ts +175 -0
- package/src/utils.ts +143 -0
- package/src/walk.ts +343 -0
- package/dist/identifier.d.mts +0 -79
- package/dist/identifier.mjs +0 -153
- package/dist/index.d.mts +0 -544
- package/dist/index.mjs +0 -1801
- package/dist/utils.d.mts +0 -18
- package/dist/utils.mjs +0 -20
package/README.md
CHANGED
|
@@ -1,146 +1,129 @@
|
|
|
1
1
|
# yuku-ast
|
|
2
2
|
|
|
3
|
-
A
|
|
4
|
-
node builders, type guards, and identifier validators.
|
|
3
|
+
A typed, mutating AST walker and syntactic utilities for JavaScript and TypeScript ESTree trees, powered by [Yuku](https://github.com/yuku-toolchain/yuku).
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
| --------------------- | --------------------------------------- |
|
|
8
|
-
| `yuku-ast` | `b` (node builders), `is` (type guards) |
|
|
9
|
-
| `yuku-ast/utils` | node utilities such as `nameOf` |
|
|
10
|
-
| `yuku-ast/identifier` | identifier and reserved-word validators |
|
|
11
|
-
|
|
12
|
-
```ts
|
|
13
|
-
import { parse } from "yuku-parser";
|
|
14
|
-
import { b, is } from "yuku-ast";
|
|
15
|
-
|
|
16
|
-
const { program } = parse("const greet = 1;");
|
|
17
|
-
|
|
18
|
-
const decl = program.body[0];
|
|
19
|
-
if (is.VariableDeclaration(decl)) {
|
|
20
|
-
// `decl` is narrowed; swap the initializer for a freshly built node.
|
|
21
|
-
decl.declarations[0].init = b.numericLiteral(42);
|
|
22
|
-
}
|
|
23
|
-
```
|
|
5
|
+
Works with any ESTree / TypeScript-ESTree AST. Traversal order is driven by tables generated from the [yuku-parser](https://www.npmjs.com/package/yuku-parser) AST definition, so it can never drift from the parser, and there is no runtime key discovery.
|
|
24
6
|
|
|
25
7
|
## Install
|
|
26
8
|
|
|
27
|
-
```
|
|
28
|
-
|
|
9
|
+
```bash
|
|
10
|
+
npm install yuku-ast
|
|
29
11
|
```
|
|
30
12
|
|
|
31
|
-
##
|
|
13
|
+
## Walking
|
|
32
14
|
|
|
33
|
-
|
|
34
|
-
`type` string. All accept `null` / `undefined` and return `false`.
|
|
15
|
+
Handlers are keyed by node `type`, by alias group, or the universal `enter` / `leave`. Every handler receives the exact node type.
|
|
35
16
|
|
|
36
17
|
```ts
|
|
37
|
-
import {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
18
|
+
import { parse } from "yuku-parser";
|
|
19
|
+
import { walk } from "yuku-ast";
|
|
20
|
+
|
|
21
|
+
const { program } = parse(source);
|
|
22
|
+
|
|
23
|
+
walk(program, {
|
|
24
|
+
Identifier(node) {
|
|
25
|
+
console.log(node.name);
|
|
26
|
+
},
|
|
27
|
+
CallExpression: {
|
|
28
|
+
enter(node, ctx) {},
|
|
29
|
+
leave(node, ctx) {},
|
|
30
|
+
},
|
|
31
|
+
Function(node) {
|
|
32
|
+
// fires for function declarations, expressions, and arrows
|
|
33
|
+
},
|
|
34
|
+
enter(node) {},
|
|
35
|
+
});
|
|
46
36
|
```
|
|
47
37
|
|
|
48
|
-
`
|
|
49
|
-
`is.Identifier(node, name?)` narrows to `Identifier`. A matching guard narrows the
|
|
50
|
-
node for typed field access:
|
|
38
|
+
Aliases: `Expression`, `Statement`, `Declaration`, `ModuleDeclaration`, `Function`, `Class`, `Method`, `Loop`, `Pattern`, `JSX`, `TSType`. Per node the order is universal `enter`, alias enters, the typed enter, children, then the mirror for leave.
|
|
51
39
|
|
|
52
|
-
|
|
53
|
-
const element = arrayExpression.elements[0];
|
|
54
|
-
if (is.Identifier(element)) {
|
|
55
|
-
element.name; // `element` is narrowed to Identifier
|
|
56
|
-
}
|
|
57
|
-
```
|
|
40
|
+
The context exposes the position (`ctx.parent`, `ctx.key`, `ctx.index`, `ctx.ancestors()`), flow control (`ctx.skip()`, `ctx.stop()`), and in-place mutation: `ctx.replace(node)` continues into the replacement, `ctx.remove()` skips the removed subtree, `ctx.insertBefore(node)` inserts a sibling without visiting it, `ctx.insertAfter(node)` inserts one the walk visits. An optional third argument threads state to every handler as `ctx.state`.
|
|
58
41
|
|
|
59
|
-
|
|
60
|
-
`Function`, `Class`, `Method`, `Loop`, `Pattern`, `JSX`, `TSType`.
|
|
42
|
+
`walkAsync` is the async counterpart: identical traversal and mutation semantics, every handler awaited before the walk moves on.
|
|
61
43
|
|
|
62
|
-
##
|
|
44
|
+
## Builders
|
|
63
45
|
|
|
64
|
-
|
|
65
|
-
or a string `Literal`'s `value`, and `null` for anything else (including `null`
|
|
66
|
-
or `undefined`). It reads the common `Identifier | StringLiteral` slots, such as
|
|
67
|
-
a `ModuleExportName` or a static property or member key, in one call.
|
|
46
|
+
One constructor per node type, its fields derived from the node type itself, so a builder can never drift from the AST. Spans default to 0, which `ctx.replace` fills from the replaced node.
|
|
68
47
|
|
|
69
48
|
```ts
|
|
70
|
-
import {
|
|
49
|
+
import { b } from "yuku-ast";
|
|
50
|
+
|
|
51
|
+
b.Identifier({ name: "x" });
|
|
52
|
+
b.CallExpression({ callee: b.Identifier({ name: "f" }), arguments: [], optional: false });
|
|
53
|
+
```
|
|
71
54
|
|
|
72
|
-
|
|
73
|
-
nameOf(specifier.exported); // "y", "z"
|
|
55
|
+
## Guards
|
|
74
56
|
|
|
75
|
-
|
|
76
|
-
|
|
57
|
+
```ts
|
|
58
|
+
import { is } from "yuku-ast";
|
|
59
|
+
|
|
60
|
+
is.CallExpression(node);
|
|
61
|
+
is.Identifier(node, "require");
|
|
62
|
+
is.oneOf(node, ["FunctionDeclaration", "ClassDeclaration"]);
|
|
63
|
+
is.Expression(node);
|
|
64
|
+
is.StringLiteral(node);
|
|
65
|
+
is.StaticMemberExpression(node);
|
|
66
|
+
is.Directive(node);
|
|
77
67
|
```
|
|
78
68
|
|
|
79
|
-
|
|
69
|
+
One guard per concrete node type, per alias group, and for the common shapes ESTree folds into one type: literal kinds, member expression kinds, and directives. Every guard accepts `null` and `undefined` and narrows.
|
|
80
70
|
|
|
81
|
-
|
|
82
|
-
trailing options object. Synthetic nodes get a zero span.
|
|
71
|
+
## Modules
|
|
83
72
|
|
|
84
73
|
```ts
|
|
85
|
-
import {
|
|
74
|
+
import { collectImports, collectExports } from "yuku-ast";
|
|
75
|
+
|
|
76
|
+
for (const record of collectImports(program)) {
|
|
77
|
+
record.source; // "./m"
|
|
78
|
+
record.local; // the local binding name
|
|
79
|
+
record.imported; // "default", "*", or the export name
|
|
80
|
+
record.typeOnly; // import type / import { type x }
|
|
81
|
+
record.phase; // "source" | "defer" | null
|
|
82
|
+
}
|
|
86
83
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
84
|
+
for (const record of collectExports(program)) {
|
|
85
|
+
record.exported; // the exported name, null for bare export *
|
|
86
|
+
record.local; // the backing local name, when there is one
|
|
87
|
+
record.source; // the re-export specifier, when there is one
|
|
88
|
+
record.typeOnly;
|
|
89
|
+
}
|
|
91
90
|
```
|
|
92
91
|
|
|
93
|
-
|
|
94
|
-
`start` / `end` first so [`yuku-codegen`](https://www.npmjs.com/package/yuku-codegen)
|
|
95
|
-
source maps still point back to the original input.
|
|
92
|
+
Declaration forms expand to one record per bound name, destructuring included. The per-declaration forms `collectImportDeclaration` and `collectExportDeclaration` return the records of a single statement, composing with a walk:
|
|
96
93
|
|
|
97
|
-
|
|
94
|
+
```ts
|
|
95
|
+
walk(program, {
|
|
96
|
+
ImportDeclaration(node) {
|
|
97
|
+
records.push(...collectImportDeclaration(node));
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
```
|
|
98
101
|
|
|
99
|
-
|
|
100
|
-
a built tree back to source.
|
|
102
|
+
## Utilities
|
|
101
103
|
|
|
102
104
|
```ts
|
|
103
|
-
import {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
]),
|
|
112
|
-
),
|
|
113
|
-
]);
|
|
114
|
-
|
|
115
|
-
console.log(print(program).code);
|
|
116
|
-
// const x = 42;
|
|
117
|
-
// console.log(x);
|
|
105
|
+
import {
|
|
106
|
+
nameOf, // Identifier name or string Literal value
|
|
107
|
+
literalValue, // string | number | boolean | bigint | RegExp | null
|
|
108
|
+
unwrap, // strips parens and erased TS assertion wrappers
|
|
109
|
+
isCallOf, // isCallOf(node, "require")
|
|
110
|
+
bindingIdentifiers, // every binding Identifier a pattern introduces
|
|
111
|
+
findAll, // findAll(program, "CallExpression")
|
|
112
|
+
} from "yuku-ast";
|
|
118
113
|
```
|
|
119
114
|
|
|
120
115
|
## Identifiers
|
|
121
116
|
|
|
122
|
-
Identifier and reserved-word helpers for raw strings and code points.
|
|
123
|
-
|
|
124
117
|
```ts
|
|
125
|
-
import { isIdentifierName,
|
|
118
|
+
import { isValidIdentifier, isIdentifierName, isKeyword } from "yuku-ast";
|
|
126
119
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
isValidIdentifier("π"); // true
|
|
120
|
+
isValidIdentifier("foo"); // true
|
|
121
|
+
isValidIdentifier("class"); // false, reserved
|
|
122
|
+
isIdentifierName("class"); // true, syntactically an IdentifierName
|
|
131
123
|
```
|
|
132
124
|
|
|
133
|
-
|
|
134
|
-
| ------------------------------------------------ | ------------------------------------------------------------------------- |
|
|
135
|
-
| `isIdentifierName(name)` | `name` is a syntactically valid `IdentifierName` |
|
|
136
|
-
| `isValidIdentifier(name, reserved?)` | a valid binding name; rejects reserved words unless `reserved` is `false` |
|
|
137
|
-
| `isIdentifierStart(cp)` / `isIdentifierChar(cp)` | a code point may start / continue an identifier |
|
|
138
|
-
| `isKeyword(word)` | `word` is a core grammar keyword (`if`, `class`, …) |
|
|
139
|
-
| `isReservedWord(word, inModule?)` | reserved everywhere (`enum`; `await` in modules) |
|
|
140
|
-
| `isStrictReservedWord(word, inModule?)` | also reserved in strict mode (`let`, `yield`, …) |
|
|
141
|
-
| `isStrictBindOnlyReservedWord(word)` | `eval` / `arguments` |
|
|
142
|
-
| `isStrictBindReservedWord(word, inModule?)` | strict reserved, plus `eval` / `arguments` |
|
|
125
|
+
Plus `isIdentifierStart`, `isIdentifierChar`, `isReservedWord`, `isStrictReservedWord`, `isStrictBindReservedWord`, `isStrictBindOnlyReservedWord`.
|
|
143
126
|
|
|
144
|
-
##
|
|
127
|
+
## Semantic analysis
|
|
145
128
|
|
|
146
|
-
|
|
129
|
+
[`yuku-analyzer`](https://www.npmjs.com/package/yuku-analyzer) builds on this walker and adds full semantics: scopes, symbols, resolved references, closure analysis, and cross-file module linking, computed natively. Its `module.walk` carries the semantic model in context (`ctx.scope`, `ctx.symbol`, `ctx.reference`).
|