rooklang 0.0.0-stage → 0.3.0
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/LICENSE +21 -0
- package/README.md +177 -2
- package/README.ru.md +178 -0
- package/dist/ast/declarations.d.ts +185 -0
- package/dist/ast/declarations.js +1 -0
- package/dist/ast/expressions.d.ts +201 -0
- package/dist/ast/expressions.js +1 -0
- package/dist/ast/markup.d.ts +141 -0
- package/dist/ast/markup.js +1 -0
- package/dist/ast/statements.d.ts +173 -0
- package/dist/ast/statements.js +1 -0
- package/dist/ast.d.ts +18 -0
- package/dist/ast.js +18 -0
- package/dist/attrs.d.ts +8 -0
- package/dist/attrs.js +23 -0
- package/dist/browser.d.ts +30 -0
- package/dist/browser.js +36 -0
- package/dist/build.d.ts +48 -0
- package/dist/build.js +112 -0
- package/dist/checker/assignments.d.ts +14 -0
- package/dist/checker/assignments.js +197 -0
- package/dist/checker/base.d.ts +124 -0
- package/dist/checker/base.js +180 -0
- package/dist/checker/bigint.d.ts +15 -0
- package/dist/checker/bigint.js +85 -0
- package/dist/checker/builtins.d.ts +9 -0
- package/dist/checker/builtins.js +307 -0
- package/dist/checker/bytes.d.ts +11 -0
- package/dist/checker/bytes.js +72 -0
- package/dist/checker/calls.d.ts +23 -0
- package/dist/checker/calls.js +210 -0
- package/dist/checker/channel.d.ts +14 -0
- package/dist/checker/channel.js +44 -0
- package/dist/checker/channels.d.ts +9 -0
- package/dist/checker/channels.js +95 -0
- package/dist/checker/checker.d.ts +4 -0
- package/dist/checker/checker.js +22 -0
- package/dist/checker/classes.d.ts +24 -0
- package/dist/checker/classes.js +223 -0
- package/dist/checker/completion-names.d.ts +11 -0
- package/dist/checker/completion-names.js +100 -0
- package/dist/checker/completion.d.ts +25 -0
- package/dist/checker/completion.js +222 -0
- package/dist/checker/component-values.d.ts +11 -0
- package/dist/checker/component-values.js +88 -0
- package/dist/checker/components.d.ts +37 -0
- package/dist/checker/components.js +287 -0
- package/dist/checker/context.d.ts +196 -0
- package/dist/checker/context.js +35 -0
- package/dist/checker/control-flow.d.ts +24 -0
- package/dist/checker/control-flow.js +237 -0
- package/dist/checker/declarations.d.ts +26 -0
- package/dist/checker/declarations.js +259 -0
- package/dist/checker/decorator-exports.d.ts +5 -0
- package/dist/checker/decorator-exports.js +40 -0
- package/dist/checker/decorator-members.d.ts +28 -0
- package/dist/checker/decorator-members.js +140 -0
- package/dist/checker/decorator-wrappers.d.ts +20 -0
- package/dist/checker/decorator-wrappers.js +132 -0
- package/dist/checker/decorators.d.ts +28 -0
- package/dist/checker/decorators.js +265 -0
- package/dist/checker/dom-svg.d.ts +7 -0
- package/dist/checker/dom-svg.js +19 -0
- package/dist/checker/dom.d.ts +22 -0
- package/dist/checker/dom.js +361 -0
- package/dist/checker/expressions.d.ts +32 -0
- package/dist/checker/expressions.js +244 -0
- package/dist/checker/flow.d.ts +18 -0
- package/dist/checker/flow.js +134 -0
- package/dist/checker/forwarding.d.ts +15 -0
- package/dist/checker/forwarding.js +78 -0
- package/dist/checker/functions.d.ts +24 -0
- package/dist/checker/functions.js +154 -0
- package/dist/checker/go-for.d.ts +12 -0
- package/dist/checker/go-for.js +93 -0
- package/dist/checker/goroutines.d.ts +19 -0
- package/dist/checker/goroutines.js +110 -0
- package/dist/checker/helpers.d.ts +35 -0
- package/dist/checker/helpers.js +162 -0
- package/dist/checker/imports.d.ts +7 -0
- package/dist/checker/imports.js +83 -0
- package/dist/checker/initializers.d.ts +22 -0
- package/dist/checker/initializers.js +104 -0
- package/dist/checker/iterables.d.ts +5 -0
- package/dist/checker/iterables.js +17 -0
- package/dist/checker/iterators.d.ts +13 -0
- package/dist/checker/iterators.js +95 -0
- package/dist/checker/loops.d.ts +10 -0
- package/dist/checker/loops.js +82 -0
- package/dist/checker/markup.d.ts +28 -0
- package/dist/checker/markup.js +220 -0
- package/dist/checker/members.d.ts +29 -0
- package/dist/checker/members.js +233 -0
- package/dist/checker/operators.d.ts +13 -0
- package/dist/checker/operators.js +177 -0
- package/dist/checker/promise.d.ts +17 -0
- package/dist/checker/promise.js +49 -0
- package/dist/checker/refs.d.ts +26 -0
- package/dist/checker/refs.js +136 -0
- package/dist/checker/resolution.d.ts +23 -0
- package/dist/checker/resolution.js +173 -0
- package/dist/checker/statements.d.ts +28 -0
- package/dist/checker/statements.js +212 -0
- package/dist/checker/styles.d.ts +14 -0
- package/dist/checker/styles.js +49 -0
- package/dist/checker/transfer.d.ts +5 -0
- package/dist/checker/transfer.js +83 -0
- package/dist/checker/types/bytes.d.ts +4 -0
- package/dist/checker/types/bytes.js +51 -0
- package/dist/checker/types/classes.d.ts +22 -0
- package/dist/checker/types/classes.js +93 -0
- package/dist/checker/types/constructors.d.ts +27 -0
- package/dist/checker/types/constructors.js +129 -0
- package/dist/checker/types/generics.d.ts +20 -0
- package/dist/checker/types/generics.js +75 -0
- package/dist/checker/types/lazy.d.ts +30 -0
- package/dist/checker/types/lazy.js +92 -0
- package/dist/checker/types/model.d.ts +149 -0
- package/dist/checker/types/model.js +15 -0
- package/dist/checker/types/params.d.ts +7 -0
- package/dist/checker/types/params.js +220 -0
- package/dist/checker/types/printing.d.ts +6 -0
- package/dist/checker/types/printing.js +109 -0
- package/dist/checker/types/relations.d.ts +16 -0
- package/dist/checker/types/relations.js +294 -0
- package/dist/checker/types.d.ts +9 -0
- package/dist/checker/types.js +10 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +193 -0
- package/dist/codegen/analysis.d.ts +18 -0
- package/dist/codegen/analysis.js +144 -0
- package/dist/codegen/attributes.d.ts +40 -0
- package/dist/codegen/attributes.js +227 -0
- package/dist/codegen/calls.d.ts +22 -0
- package/dist/codegen/calls.js +106 -0
- package/dist/codegen/chan-helpers.d.ts +2 -0
- package/dist/codegen/chan-helpers.js +253 -0
- package/dist/codegen/component-helpers.d.ts +33 -0
- package/dist/codegen/component-helpers.js +18 -0
- package/dist/codegen/component-props.d.ts +42 -0
- package/dist/codegen/component-props.js +173 -0
- package/dist/codegen/component-values.d.ts +27 -0
- package/dist/codegen/component-values.js +146 -0
- package/dist/codegen/components.d.ts +53 -0
- package/dist/codegen/components.js +268 -0
- package/dist/codegen/control-flow.d.ts +25 -0
- package/dist/codegen/control-flow.js +152 -0
- package/dist/codegen/control-statements.d.ts +28 -0
- package/dist/codegen/control-statements.js +226 -0
- package/dist/codegen/creation.d.ts +31 -0
- package/dist/codegen/creation.js +113 -0
- package/dist/codegen/early-returns.d.ts +59 -0
- package/dist/codegen/early-returns.js +244 -0
- package/dist/codegen/element-helpers.d.ts +12 -0
- package/dist/codegen/element-helpers.js +54 -0
- package/dist/codegen/elements.d.ts +71 -0
- package/dist/codegen/elements.js +293 -0
- package/dist/codegen/emitter.d.ts +135 -0
- package/dist/codegen/emitter.js +296 -0
- package/dist/codegen/expressions.d.ts +49 -0
- package/dist/codegen/expressions.js +262 -0
- package/dist/codegen/functions.d.ts +28 -0
- package/dist/codegen/functions.js +170 -0
- package/dist/codegen/go-helpers.d.ts +9 -0
- package/dist/codegen/go-helpers.js +307 -0
- package/dist/codegen/helpers.d.ts +10 -0
- package/dist/codegen/helpers.js +356 -0
- package/dist/codegen/imported.d.ts +38 -0
- package/dist/codegen/imported.js +71 -0
- package/dist/codegen/js.d.ts +20 -0
- package/dist/codegen/js.js +113 -0
- package/dist/codegen/mutations.d.ts +10 -0
- package/dist/codegen/mutations.js +102 -0
- package/dist/codegen/parallel.d.ts +7 -0
- package/dist/codegen/parallel.js +63 -0
- package/dist/codegen/reactive.d.ts +95 -0
- package/dist/codegen/reactive.js +280 -0
- package/dist/codegen/refs.d.ts +62 -0
- package/dist/codegen/refs.js +160 -0
- package/dist/codegen/select-helpers.d.ts +2 -0
- package/dist/codegen/select-helpers.js +135 -0
- package/dist/codegen/simple-statements.d.ts +42 -0
- package/dist/codegen/simple-statements.js +253 -0
- package/dist/codegen/statements.d.ts +22 -0
- package/dist/codegen/statements.js +142 -0
- package/dist/codegen/styles.d.ts +54 -0
- package/dist/codegen/styles.js +157 -0
- package/dist/codegen/syntax.d.ts +18 -0
- package/dist/codegen/syntax.js +70 -0
- package/dist/codegen/thread-helpers.d.ts +2 -0
- package/dist/codegen/thread-helpers.js +198 -0
- package/dist/codegen/updates.d.ts +51 -0
- package/dist/codegen/updates.js +201 -0
- package/dist/codegen/web-components.d.ts +20 -0
- package/dist/codegen/web-components.js +149 -0
- package/dist/compile-file.d.ts +11 -0
- package/dist/compile-file.js +24 -0
- package/dist/compile.d.ts +53 -0
- package/dist/compile.js +187 -0
- package/dist/completion.d.ts +10 -0
- package/dist/completion.js +134 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +44 -0
- package/dist/css/hash.d.ts +1 -0
- package/dist/css/hash.js +10 -0
- package/dist/css/parse.d.ts +42 -0
- package/dist/css/parse.js +138 -0
- package/dist/css/print.d.ts +9 -0
- package/dist/css/print.js +35 -0
- package/dist/css/selectors.d.ts +29 -0
- package/dist/css/selectors.js +168 -0
- package/dist/declarations.d.ts +3 -0
- package/dist/declarations.js +207 -0
- package/dist/decorator-copy.d.ts +18 -0
- package/dist/decorator-copy.js +158 -0
- package/dist/decorators.d.ts +61 -0
- package/dist/decorators.js +241 -0
- package/dist/diagnostics.d.ts +17 -0
- package/dist/diagnostics.js +22 -0
- package/dist/go-for.d.ts +26 -0
- package/dist/go-for.js +155 -0
- package/dist/goroutines.d.ts +37 -0
- package/dist/goroutines.js +253 -0
- package/dist/html-tag.d.ts +21 -0
- package/dist/html-tag.js +103 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +55 -0
- package/dist/inline-packages.d.ts +32 -0
- package/dist/inline-packages.js +129 -0
- package/dist/iterators.d.ts +10 -0
- package/dist/iterators.js +33 -0
- package/dist/lexer/base.d.ts +24 -0
- package/dist/lexer/base.js +87 -0
- package/dist/lexer/lexer.d.ts +8 -0
- package/dist/lexer/lexer.js +134 -0
- package/dist/lexer/literals.d.ts +18 -0
- package/dist/lexer/literals.js +203 -0
- package/dist/lexer/markup.d.ts +10 -0
- package/dist/lexer/markup.js +93 -0
- package/dist/lexer/style.d.ts +17 -0
- package/dist/lexer/style.js +97 -0
- package/dist/lexer/tables.d.ts +53 -0
- package/dist/lexer/tables.js +101 -0
- package/dist/lexer/token.d.ts +42 -0
- package/dist/lexer/token.js +108 -0
- package/dist/loader.d.ts +1 -0
- package/dist/loader.js +50 -0
- package/dist/methods.d.ts +5 -0
- package/dist/methods.js +81 -0
- package/dist/modules.d.ts +3 -0
- package/dist/modules.js +49 -0
- package/dist/names.d.ts +23 -0
- package/dist/names.js +267 -0
- package/dist/parser/base.d.ts +96 -0
- package/dist/parser/base.js +202 -0
- package/dist/parser/classes.d.ts +8 -0
- package/dist/parser/classes.js +164 -0
- package/dist/parser/control-flow.d.ts +29 -0
- package/dist/parser/control-flow.js +232 -0
- package/dist/parser/declarations.d.ts +27 -0
- package/dist/parser/declarations.js +238 -0
- package/dist/parser/decorators.d.ts +30 -0
- package/dist/parser/decorators.js +176 -0
- package/dist/parser/expressions.d.ts +15 -0
- package/dist/parser/expressions.js +255 -0
- package/dist/parser/literals.d.ts +27 -0
- package/dist/parser/literals.js +206 -0
- package/dist/parser/markup.d.ts +22 -0
- package/dist/parser/markup.js +193 -0
- package/dist/parser/parser.d.ts +14 -0
- package/dist/parser/parser.js +22 -0
- package/dist/parser/simple-statements.d.ts +22 -0
- package/dist/parser/simple-statements.js +156 -0
- package/dist/parser/statements.d.ts +37 -0
- package/dist/parser/statements.js +267 -0
- package/dist/parser/syntax.d.ts +51 -0
- package/dist/parser/syntax.js +173 -0
- package/dist/parser/types.d.ts +23 -0
- package/dist/parser/types.js +218 -0
- package/dist/recursion.d.ts +25 -0
- package/dist/recursion.js +170 -0
- package/dist/refs.d.ts +49 -0
- package/dist/refs.js +210 -0
- package/dist/run.d.ts +1 -0
- package/dist/run.js +21 -0
- package/dist/source.d.ts +15 -0
- package/dist/source.js +34 -0
- package/dist/style-modules.d.ts +17 -0
- package/dist/style-modules.js +49 -0
- package/dist/styles.d.ts +36 -0
- package/dist/styles.js +160 -0
- package/dist/svg.d.ts +8 -0
- package/dist/svg.js +77 -0
- package/dist/ts-types.d.ts +11 -0
- package/dist/ts-types.js +133 -0
- package/dist/typed-arrays.d.ts +8 -0
- package/dist/typed-arrays.js +43 -0
- package/dist/typescript/convert-base.d.ts +42 -0
- package/dist/typescript/convert-base.js +135 -0
- package/dist/typescript/convert-objects.d.ts +28 -0
- package/dist/typescript/convert-objects.js +245 -0
- package/dist/typescript/convert.d.ts +14 -0
- package/dist/typescript/convert.js +67 -0
- package/dist/typescript/importer.d.ts +37 -0
- package/dist/typescript/importer.js +152 -0
- package/dist/typescript/library.d.ts +23 -0
- package/dist/typescript/library.js +81 -0
- package/dist/vite.d.ts +11 -0
- package/dist/vite.js +86 -0
- package/dist/walk-types.d.ts +4 -0
- package/dist/walk-types.js +56 -0
- package/dist/walk.d.ts +5 -0
- package/dist/walk.js +315 -0
- package/package.json +104 -4
package/dist/names.js
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { forEachChild } from "./walk.js";
|
|
2
|
+
// The names that code inside a node assigns, mentions or declares, and those it uses from outside.
|
|
3
|
+
/** Names assigned anywhere inside `node`: `x = ...`, `x += ...`, `x++`. */
|
|
4
|
+
export function assignedNames(node, names = new Set()) {
|
|
5
|
+
if (node.kind === 'AssignmentStatement') {
|
|
6
|
+
for (const target of node.targets)
|
|
7
|
+
if (target.kind === 'Identifier')
|
|
8
|
+
names.add(target.name);
|
|
9
|
+
}
|
|
10
|
+
else if (node.kind === 'IncDecStatement' && node.target.kind === 'Identifier') {
|
|
11
|
+
names.add(node.target.name);
|
|
12
|
+
}
|
|
13
|
+
else if (node.kind === 'JsxAttribute' &&
|
|
14
|
+
node.name.name.startsWith('bind:') &&
|
|
15
|
+
node.value?.kind === 'Identifier') {
|
|
16
|
+
// `bind:value={name}` writes what the user enters.
|
|
17
|
+
names.add(node.value.name);
|
|
18
|
+
}
|
|
19
|
+
forEachChild(node, (child) => assignedNames(child, names));
|
|
20
|
+
return names;
|
|
21
|
+
}
|
|
22
|
+
/** Whether an identifier with one of `names` occurs in `node`, whatever it refers to. */
|
|
23
|
+
export function mentionsName(node, names) {
|
|
24
|
+
if (node.kind === 'Identifier')
|
|
25
|
+
return names.has(node.name);
|
|
26
|
+
let found = false;
|
|
27
|
+
forEachChild(node, (child) => {
|
|
28
|
+
found ||= mentionsName(child, names);
|
|
29
|
+
});
|
|
30
|
+
return found;
|
|
31
|
+
}
|
|
32
|
+
/** Every name declared inside `node`: parameters and all local declarations, nested ones too. */
|
|
33
|
+
export function declaredNames(node) {
|
|
34
|
+
const names = new Set();
|
|
35
|
+
const visit = (node) => {
|
|
36
|
+
switch (node.kind) {
|
|
37
|
+
case 'Parameter':
|
|
38
|
+
names.add(node.name.name);
|
|
39
|
+
break;
|
|
40
|
+
case 'VariableDeclaration':
|
|
41
|
+
case 'SelectCase':
|
|
42
|
+
for (const name of node.names)
|
|
43
|
+
names.add(name.name);
|
|
44
|
+
break;
|
|
45
|
+
case 'FuncDeclaration':
|
|
46
|
+
case 'ClassDeclaration':
|
|
47
|
+
names.add(node.name.name);
|
|
48
|
+
break;
|
|
49
|
+
case 'ForInStatement':
|
|
50
|
+
names.add(node.value.name);
|
|
51
|
+
if (node.key)
|
|
52
|
+
names.add(node.key.name);
|
|
53
|
+
break;
|
|
54
|
+
case 'CatchClause':
|
|
55
|
+
if (node.param)
|
|
56
|
+
names.add(node.param.name);
|
|
57
|
+
break;
|
|
58
|
+
case 'EventHandler':
|
|
59
|
+
names.add('event');
|
|
60
|
+
break;
|
|
61
|
+
default:
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
forEachChild(node, visit);
|
|
65
|
+
};
|
|
66
|
+
forEachChild(node, visit);
|
|
67
|
+
return names;
|
|
68
|
+
}
|
|
69
|
+
/** Names a component or a decorator uses as values but does not declare: those come from the module. */
|
|
70
|
+
export function freeNames(component) {
|
|
71
|
+
const used = new Set();
|
|
72
|
+
const declared = new Set(component.params.map((param) => param.name.name));
|
|
73
|
+
const visit = (node) => {
|
|
74
|
+
if (node === null)
|
|
75
|
+
return;
|
|
76
|
+
switch (node.kind) {
|
|
77
|
+
case 'Identifier':
|
|
78
|
+
used.add(node.name);
|
|
79
|
+
return;
|
|
80
|
+
case 'MemberExpression':
|
|
81
|
+
visit(node.object);
|
|
82
|
+
return;
|
|
83
|
+
case 'Property':
|
|
84
|
+
visit(node.value);
|
|
85
|
+
return;
|
|
86
|
+
case 'ElementExpression':
|
|
87
|
+
// Tags are not values: components are found by the generator itself.
|
|
88
|
+
node.attributes.forEach(visit);
|
|
89
|
+
node.children.forEach(visit);
|
|
90
|
+
return;
|
|
91
|
+
case 'JsxAttribute':
|
|
92
|
+
visit(node.value);
|
|
93
|
+
return;
|
|
94
|
+
case 'EventHandler':
|
|
95
|
+
declared.add('event');
|
|
96
|
+
node.body.forEach(visit);
|
|
97
|
+
return;
|
|
98
|
+
case 'VariableDeclaration':
|
|
99
|
+
for (const name of node.names)
|
|
100
|
+
declared.add(name.name);
|
|
101
|
+
node.values.forEach(visit);
|
|
102
|
+
return;
|
|
103
|
+
case 'SelectCase':
|
|
104
|
+
for (const name of node.names)
|
|
105
|
+
declared.add(name.name);
|
|
106
|
+
visit(node.operation);
|
|
107
|
+
node.body.forEach(visit);
|
|
108
|
+
return;
|
|
109
|
+
case 'FuncDeclaration':
|
|
110
|
+
case 'ClassDeclaration':
|
|
111
|
+
declared.add(node.name.name);
|
|
112
|
+
forEachChild(node, visit);
|
|
113
|
+
return;
|
|
114
|
+
case 'Parameter':
|
|
115
|
+
declared.add(node.name.name);
|
|
116
|
+
visit(node.defaultValue);
|
|
117
|
+
return;
|
|
118
|
+
case 'ForInStatement':
|
|
119
|
+
declared.add(node.value.name);
|
|
120
|
+
if (node.key)
|
|
121
|
+
declared.add(node.key.name);
|
|
122
|
+
visit(node.iterable);
|
|
123
|
+
visit(node.body);
|
|
124
|
+
return;
|
|
125
|
+
case 'CatchClause':
|
|
126
|
+
if (node.param)
|
|
127
|
+
declared.add(node.param.name);
|
|
128
|
+
visit(node.body);
|
|
129
|
+
return;
|
|
130
|
+
case 'TypeReference':
|
|
131
|
+
case 'ArrayType':
|
|
132
|
+
case 'NullableType':
|
|
133
|
+
case 'FuncType':
|
|
134
|
+
case 'ComponentType':
|
|
135
|
+
case 'ObjectType':
|
|
136
|
+
case 'UnionType':
|
|
137
|
+
case 'LiteralType':
|
|
138
|
+
case 'TypeParameter':
|
|
139
|
+
return;
|
|
140
|
+
default:
|
|
141
|
+
forEachChild(node, visit);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
component.params.forEach(visit);
|
|
145
|
+
visit(component.body);
|
|
146
|
+
return new Set([...used].filter((name) => !declared.has(name)));
|
|
147
|
+
}
|
|
148
|
+
/** Names declared directly in a list of statements: they hide outer names in the whole block. */
|
|
149
|
+
export function declaredIn(statements) {
|
|
150
|
+
return statements.flatMap((statement) => {
|
|
151
|
+
switch (statement.kind) {
|
|
152
|
+
case 'VariableDeclaration':
|
|
153
|
+
return statement.names.map((name) => name.name);
|
|
154
|
+
case 'FuncDeclaration':
|
|
155
|
+
case 'ClassDeclaration':
|
|
156
|
+
return [statement.name.name];
|
|
157
|
+
default:
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
/** Names declared at the top level of a module, imports included: what its code can use. */
|
|
163
|
+
export function topLevelNames(program) {
|
|
164
|
+
const names = new Set(declaredIn(program.body));
|
|
165
|
+
for (const statement of program.body) {
|
|
166
|
+
if (statement.kind !== 'ImportDeclaration')
|
|
167
|
+
continue;
|
|
168
|
+
if (statement.defaultImport)
|
|
169
|
+
names.add(statement.defaultImport.name);
|
|
170
|
+
if (statement.namespaceImport)
|
|
171
|
+
names.add(statement.namespaceImport.name);
|
|
172
|
+
for (const specifier of statement.namedImports)
|
|
173
|
+
names.add(specifier.local.name);
|
|
174
|
+
}
|
|
175
|
+
return names;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Names used as values, as opposed to declared names, property names and types. A capitalized tag
|
|
179
|
+
* is a value unless `isComponent` says it names a component: `<Page />` with a variable `Page`.
|
|
180
|
+
*/
|
|
181
|
+
export function collectValueNames(node, names, isComponent = () => true) {
|
|
182
|
+
const visit = (child) => {
|
|
183
|
+
if (child)
|
|
184
|
+
collectValueNames(child, names, isComponent);
|
|
185
|
+
};
|
|
186
|
+
switch (node.kind) {
|
|
187
|
+
case 'Identifier':
|
|
188
|
+
names.add(node.name);
|
|
189
|
+
return;
|
|
190
|
+
case 'MemberExpression':
|
|
191
|
+
visit(node.object);
|
|
192
|
+
return;
|
|
193
|
+
case 'Property':
|
|
194
|
+
visit(node.value);
|
|
195
|
+
return;
|
|
196
|
+
case 'VariableDeclaration':
|
|
197
|
+
node.values.forEach(visit);
|
|
198
|
+
return;
|
|
199
|
+
case 'FuncDeclaration':
|
|
200
|
+
case 'MethodDeclaration':
|
|
201
|
+
case 'ConstructorDeclaration':
|
|
202
|
+
case 'FuncExpression':
|
|
203
|
+
case 'ArrowFunction':
|
|
204
|
+
visit(node.body);
|
|
205
|
+
return;
|
|
206
|
+
case 'ComponentDeclaration':
|
|
207
|
+
node.decorators.forEach(visit);
|
|
208
|
+
node.params.forEach(visit);
|
|
209
|
+
visit(node.body);
|
|
210
|
+
return;
|
|
211
|
+
case 'DecoratorDeclaration':
|
|
212
|
+
node.params.forEach(visit);
|
|
213
|
+
visit(node.body);
|
|
214
|
+
return;
|
|
215
|
+
case 'ElementExpression':
|
|
216
|
+
// Tags are not values, except those that take a component from one.
|
|
217
|
+
visit(node.value);
|
|
218
|
+
if (node.value === null && node.tag && /^[A-Z]/.test(node.tag.name)) {
|
|
219
|
+
if (!isComponent(node.tag.name))
|
|
220
|
+
names.add(node.tag.name);
|
|
221
|
+
}
|
|
222
|
+
node.attributes.forEach(visit);
|
|
223
|
+
node.children.forEach(visit);
|
|
224
|
+
return;
|
|
225
|
+
case 'JsxAttribute':
|
|
226
|
+
visit(node.value);
|
|
227
|
+
return;
|
|
228
|
+
case 'Parameter':
|
|
229
|
+
visit(node.defaultValue);
|
|
230
|
+
return;
|
|
231
|
+
case 'ClassDeclaration':
|
|
232
|
+
visit(node.superClass);
|
|
233
|
+
node.members.forEach(visit);
|
|
234
|
+
return;
|
|
235
|
+
case 'FieldDeclaration':
|
|
236
|
+
visit(node.value);
|
|
237
|
+
return;
|
|
238
|
+
case 'ForInStatement':
|
|
239
|
+
visit(node.iterable);
|
|
240
|
+
visit(node.body);
|
|
241
|
+
return;
|
|
242
|
+
case 'CatchClause':
|
|
243
|
+
visit(node.body);
|
|
244
|
+
return;
|
|
245
|
+
case 'ImportDeclaration':
|
|
246
|
+
case 'InterfaceDeclaration':
|
|
247
|
+
case 'TypeAliasDeclaration':
|
|
248
|
+
case 'TypeReference':
|
|
249
|
+
case 'ArrayType':
|
|
250
|
+
case 'NullableType':
|
|
251
|
+
case 'FuncType':
|
|
252
|
+
case 'ComponentType':
|
|
253
|
+
case 'ObjectType':
|
|
254
|
+
case 'UnionType':
|
|
255
|
+
case 'LiteralType':
|
|
256
|
+
case 'TypeParameter':
|
|
257
|
+
return;
|
|
258
|
+
default:
|
|
259
|
+
forEachChild(node, visit);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/** The components that the code in `node` uses as values: `content: Intro`. */
|
|
263
|
+
export function componentValues(node, isComponent) {
|
|
264
|
+
const values = new Set();
|
|
265
|
+
collectValueNames(node, values, isComponent);
|
|
266
|
+
return [...values].filter(isComponent);
|
|
267
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type * as ast from '../ast.ts';
|
|
2
|
+
import type { Diagnostic } from '../diagnostics.ts';
|
|
3
|
+
import type { StringToken, Token, TokenKind } from '../lexer/token.ts';
|
|
4
|
+
import { type Context } from './syntax.ts';
|
|
5
|
+
export declare abstract class ParserBase {
|
|
6
|
+
protected abstract parseBreakOrContinue(): ast.BreakStatement | ast.ContinueStatement;
|
|
7
|
+
protected abstract parseDefer(): ast.DeferStatement;
|
|
8
|
+
protected abstract parseFor(): ast.ForStatement | ast.ForInStatement;
|
|
9
|
+
protected abstract parseGoFor(): ast.ForStatement | ast.ForInStatement;
|
|
10
|
+
protected abstract parseIf(): ast.IfStatement;
|
|
11
|
+
protected abstract parseSwitch(): ast.SwitchStatement;
|
|
12
|
+
protected abstract parseSelect(): ast.SelectStatement;
|
|
13
|
+
protected abstract parseThrow(): ast.ThrowStatement;
|
|
14
|
+
protected abstract parseTry(): ast.TryStatement;
|
|
15
|
+
protected abstract parseComponent(start: number, exported: boolean, htmlTag?: ast.HtmlTag | null, decorators?: ast.DecoratorUse[]): ast.ComponentDeclaration;
|
|
16
|
+
protected abstract parseDecorated(start: number, exported: boolean): ast.ComponentDeclaration;
|
|
17
|
+
protected abstract isDecoratorDeclaration(): boolean;
|
|
18
|
+
protected abstract parseDecoratorDeclaration(start: number, exported: boolean): ast.DecoratorDeclaration;
|
|
19
|
+
protected abstract isDecoratorMember(): boolean;
|
|
20
|
+
protected abstract parseExport(): ast.Statement;
|
|
21
|
+
protected abstract parseFuncDeclaration(start: number, exported: boolean): ast.FuncDeclaration;
|
|
22
|
+
protected abstract parseImport(): ast.ImportDeclaration;
|
|
23
|
+
protected abstract parseClass(start: number, exported: boolean): ast.ClassDeclaration;
|
|
24
|
+
protected abstract parseInterface(start: number, exported: boolean): ast.InterfaceDeclaration;
|
|
25
|
+
protected abstract parseTypeAlias(start: number, exported: boolean): ast.TypeAliasDeclaration;
|
|
26
|
+
protected abstract canStartType(): boolean;
|
|
27
|
+
protected abstract parseType(): ast.TypeNode;
|
|
28
|
+
protected abstract parseTypeArgs(): ast.TypeNode[];
|
|
29
|
+
protected abstract parseTypeMembers(): ast.TypeMember[];
|
|
30
|
+
protected abstract parseExpression(): ast.Expression;
|
|
31
|
+
protected abstract parsePostfix(expression: ast.Expression): ast.Expression;
|
|
32
|
+
protected abstract parsePrimary(): ast.Expression;
|
|
33
|
+
protected abstract isArrowFunctionAhead(): boolean;
|
|
34
|
+
protected abstract parseArguments(): (ast.Expression | ast.SpreadElement)[];
|
|
35
|
+
protected abstract parseArrayLiteral(): ast.ArrayLiteral;
|
|
36
|
+
protected abstract parseConversion(): ast.ConversionExpression;
|
|
37
|
+
protected abstract parseMake(): ast.MakeExpression;
|
|
38
|
+
protected abstract parseArrowFunction(async?: boolean): ast.ArrowFunction;
|
|
39
|
+
protected abstract parseFuncExpression(async?: boolean): ast.FuncExpression;
|
|
40
|
+
protected abstract parseIdentifier(what?: string): ast.Identifier;
|
|
41
|
+
protected abstract parseList<T>(close: TokenKind, parseItem: () => T): T[];
|
|
42
|
+
protected abstract parseNew(): ast.NewExpression;
|
|
43
|
+
protected abstract parseObjectLiteral(): ast.ObjectLiteral;
|
|
44
|
+
protected abstract parseParenthesized(): ast.Expression;
|
|
45
|
+
protected abstract parsePropertyName(what?: string): ast.Identifier;
|
|
46
|
+
protected abstract parseTemplate(first: StringToken): ast.TemplateLiteral;
|
|
47
|
+
protected abstract parseJsxElement(): ast.ElementExpression;
|
|
48
|
+
protected abstract parseStringLiteral(what?: string): ast.StringLiteral;
|
|
49
|
+
readonly diagnostics: Diagnostic[];
|
|
50
|
+
protected readonly tokens: Token[];
|
|
51
|
+
protected pos: number;
|
|
52
|
+
protected context: Context;
|
|
53
|
+
/** Expressions written in parentheses, which the tree itself does not record. */
|
|
54
|
+
protected readonly parenthesized: WeakSet<ast.Expression>;
|
|
55
|
+
/** Markup and components: the entries turn them off unless the package turns them on. */
|
|
56
|
+
protected readonly markup: boolean;
|
|
57
|
+
constructor(tokens: Token[], markup?: boolean);
|
|
58
|
+
/** Fails at markup, a component or a decorator when they are off, saying how to turn them on. */
|
|
59
|
+
protected requireMarkup(what: string): void;
|
|
60
|
+
protected peek(offset?: number): Token;
|
|
61
|
+
protected check(kind: TokenKind): boolean;
|
|
62
|
+
/** Whether the current token is the word `word`, e.g. the contextual keyword `from`. */
|
|
63
|
+
protected checkWord(word: string): boolean;
|
|
64
|
+
protected next(): Token;
|
|
65
|
+
protected accept(kind: TokenKind): boolean;
|
|
66
|
+
protected acceptWord(word: string): boolean;
|
|
67
|
+
protected expect(kind: TokenKind, what?: string): Token;
|
|
68
|
+
/**
|
|
69
|
+
* The `>` that closes type arguments or parameters. In `Box<Box<number>>` the lexer reads `>>`,
|
|
70
|
+
* so a token that starts with `>` is split: its first character closes these.
|
|
71
|
+
*/
|
|
72
|
+
protected expectTypeClose(what: string): void;
|
|
73
|
+
protected expectWord(word: string): void;
|
|
74
|
+
protected isImplicitSemicolon(): boolean;
|
|
75
|
+
/** Start and end of a node that began at `start` and ends with the last consumed token. */
|
|
76
|
+
protected span(start: number): ast.NodeBase;
|
|
77
|
+
/** Reports an error unless one was already reported at the same position. */
|
|
78
|
+
protected error(message: string, start: number, end: number): void;
|
|
79
|
+
/** Reports an error at the current token and abandons the current statement. */
|
|
80
|
+
protected fail(message: string): never;
|
|
81
|
+
protected failAt(message: string, start: number, end: number): never;
|
|
82
|
+
/** Runs `parse` with some context flags changed. */
|
|
83
|
+
protected withContext<T>(changes: Partial<Context>, parse: () => T): T;
|
|
84
|
+
/** Inside brackets `{` starts an object literal again, even within an if/for/switch header. */
|
|
85
|
+
protected nested<T>(parse: () => T): T;
|
|
86
|
+
/**
|
|
87
|
+
* Parses items separated by newlines or `;` until `isEnd`. A syntax error abandons only the item
|
|
88
|
+
* it occurred in: the parser skips to the item's end and continues with the next one.
|
|
89
|
+
*/
|
|
90
|
+
protected parseSeparated(isEnd: () => boolean, parseItem: () => void): void;
|
|
91
|
+
/**
|
|
92
|
+
* Skips the broken statement that began at token index `start`: up to the first `;` outside
|
|
93
|
+
* brackets, or up to a `}` that closes the enclosing block.
|
|
94
|
+
*/
|
|
95
|
+
protected synchronize(start: number): void;
|
|
96
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { STATEMENT_KEYWORDS, BRACKETS, ParseError, describe } from "./syntax.js";
|
|
2
|
+
// The parser is a chain of layers, one per area: base → simple statements → statements → control
|
|
3
|
+
// flow → declarations → decorators → classes → types → expressions → literals → markup → Parser
|
|
4
|
+
// (parser.ts). Statements, expressions and markup contain each other, so methods of later layers
|
|
5
|
+
// that earlier ones call are declared here as abstract.
|
|
6
|
+
//
|
|
7
|
+
// This layer reads tokens, reports errors and recovers from them.
|
|
8
|
+
export class ParserBase {
|
|
9
|
+
diagnostics = [];
|
|
10
|
+
tokens;
|
|
11
|
+
pos = 0;
|
|
12
|
+
context = {
|
|
13
|
+
topLevel: true,
|
|
14
|
+
inFunction: false,
|
|
15
|
+
inLoop: false,
|
|
16
|
+
inBreakable: false,
|
|
17
|
+
inDefer: false,
|
|
18
|
+
inGoFor: false,
|
|
19
|
+
// Modules are ES modules: `await` works at their top level.
|
|
20
|
+
inAsync: true,
|
|
21
|
+
noObjectLiteral: false,
|
|
22
|
+
inComponent: false,
|
|
23
|
+
inMarkup: false,
|
|
24
|
+
};
|
|
25
|
+
/** Expressions written in parentheses, which the tree itself does not record. */
|
|
26
|
+
parenthesized = new WeakSet();
|
|
27
|
+
/** Markup and components: the entries turn them off unless the package turns them on. */
|
|
28
|
+
markup;
|
|
29
|
+
constructor(tokens, markup = true) {
|
|
30
|
+
this.tokens = tokens;
|
|
31
|
+
this.markup = markup;
|
|
32
|
+
}
|
|
33
|
+
/** Fails at markup, a component or a decorator when they are off, saying how to turn them on. */
|
|
34
|
+
requireMarkup(what) {
|
|
35
|
+
if (this.markup)
|
|
36
|
+
return;
|
|
37
|
+
this.fail(`${what} off: turn on markup and components with "rook": { "markup": true } in package.json, or with --markup`);
|
|
38
|
+
}
|
|
39
|
+
peek(offset = 0) {
|
|
40
|
+
return this.tokens[Math.min(this.pos + offset, this.tokens.length - 1)];
|
|
41
|
+
}
|
|
42
|
+
check(kind) {
|
|
43
|
+
return this.peek().kind === kind;
|
|
44
|
+
}
|
|
45
|
+
/** Whether the current token is the word `word`, e.g. the contextual keyword `from`. */
|
|
46
|
+
checkWord(word) {
|
|
47
|
+
const token = this.peek();
|
|
48
|
+
return token.kind === 'Identifier' && token.text === word;
|
|
49
|
+
}
|
|
50
|
+
next() {
|
|
51
|
+
const token = this.peek();
|
|
52
|
+
if (token.kind !== 'EOF')
|
|
53
|
+
this.pos++;
|
|
54
|
+
return token;
|
|
55
|
+
}
|
|
56
|
+
accept(kind) {
|
|
57
|
+
if (!this.check(kind))
|
|
58
|
+
return false;
|
|
59
|
+
this.next();
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
acceptWord(word) {
|
|
63
|
+
if (!this.checkWord(word))
|
|
64
|
+
return false;
|
|
65
|
+
this.next();
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
expect(kind, what = `"${kind}"`) {
|
|
69
|
+
if (this.check(kind))
|
|
70
|
+
return this.next();
|
|
71
|
+
return this.fail(`expected ${what}, found ${describe(this.peek())}`);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The `>` that closes type arguments or parameters. In `Box<Box<number>>` the lexer reads `>>`,
|
|
75
|
+
* so a token that starts with `>` is split: its first character closes these.
|
|
76
|
+
*/
|
|
77
|
+
expectTypeClose(what) {
|
|
78
|
+
const token = this.peek();
|
|
79
|
+
if (token.kind === '>') {
|
|
80
|
+
this.next();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (token.kind.startsWith('>')) {
|
|
84
|
+
const rest = token.kind.slice(1);
|
|
85
|
+
this.tokens[this.pos] = {
|
|
86
|
+
...token,
|
|
87
|
+
kind: rest,
|
|
88
|
+
text: token.text.slice(1),
|
|
89
|
+
start: token.start + 1,
|
|
90
|
+
};
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
this.fail(`expected ${what}, found ${describe(token)}`);
|
|
94
|
+
}
|
|
95
|
+
expectWord(word) {
|
|
96
|
+
if (!this.acceptWord(word))
|
|
97
|
+
this.fail(`expected "${word}", found ${describe(this.peek())}`);
|
|
98
|
+
}
|
|
99
|
+
isImplicitSemicolon() {
|
|
100
|
+
const token = this.peek();
|
|
101
|
+
return token.kind === ';' && token.text === '';
|
|
102
|
+
}
|
|
103
|
+
/** Start and end of a node that began at `start` and ends with the last consumed token. */
|
|
104
|
+
span(start) {
|
|
105
|
+
return { start, end: this.tokens[this.pos - 1]?.end ?? start };
|
|
106
|
+
}
|
|
107
|
+
/** Reports an error unless one was already reported at the same position. */
|
|
108
|
+
error(message, start, end) {
|
|
109
|
+
if (this.diagnostics.some((d) => d.start === start))
|
|
110
|
+
return;
|
|
111
|
+
this.diagnostics.push({ message, start, end });
|
|
112
|
+
}
|
|
113
|
+
/** Reports an error at the current token and abandons the current statement. */
|
|
114
|
+
fail(message) {
|
|
115
|
+
const token = this.peek();
|
|
116
|
+
return this.failAt(message, token.start, token.end);
|
|
117
|
+
}
|
|
118
|
+
failAt(message, start, end) {
|
|
119
|
+
this.error(message, start, end);
|
|
120
|
+
throw new ParseError(message);
|
|
121
|
+
}
|
|
122
|
+
/** Runs `parse` with some context flags changed. */
|
|
123
|
+
withContext(changes, parse) {
|
|
124
|
+
const saved = this.context;
|
|
125
|
+
this.context = { ...saved, ...changes };
|
|
126
|
+
try {
|
|
127
|
+
return parse();
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
this.context = saved;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/** Inside brackets `{` starts an object literal again, even within an if/for/switch header. */
|
|
134
|
+
nested(parse) {
|
|
135
|
+
return this.withContext({ noObjectLiteral: false }, parse);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Parses items separated by newlines or `;` until `isEnd`. A syntax error abandons only the item
|
|
139
|
+
* it occurred in: the parser skips to the item's end and continues with the next one.
|
|
140
|
+
*/
|
|
141
|
+
parseSeparated(isEnd, parseItem) {
|
|
142
|
+
while (!isEnd() && !this.check('EOF')) {
|
|
143
|
+
if (this.accept(';'))
|
|
144
|
+
continue;
|
|
145
|
+
const start = this.pos;
|
|
146
|
+
try {
|
|
147
|
+
parseItem();
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
if (!(error instanceof ParseError))
|
|
151
|
+
throw error;
|
|
152
|
+
this.synchronize(start);
|
|
153
|
+
if (this.pos === start)
|
|
154
|
+
this.next();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Skips the broken statement that began at token index `start`: up to the first `;` outside
|
|
160
|
+
* brackets, or up to a `}` that closes the enclosing block.
|
|
161
|
+
*/
|
|
162
|
+
synchronize(start) {
|
|
163
|
+
this.pos = start;
|
|
164
|
+
// The `;` inside a `for` header do not end the statement.
|
|
165
|
+
const explicitSemicolonEnds = this.peek().kind !== 'for';
|
|
166
|
+
const open = [];
|
|
167
|
+
while (true) {
|
|
168
|
+
const token = this.next();
|
|
169
|
+
const kind = token.kind;
|
|
170
|
+
if (kind === 'EOF')
|
|
171
|
+
return;
|
|
172
|
+
if (kind === ';') {
|
|
173
|
+
if (open.length === 0 && (token.text === '' || explicitSemicolonEnds))
|
|
174
|
+
return;
|
|
175
|
+
// A newline before a statement keyword: probably an unclosed bracket on the line above.
|
|
176
|
+
if (token.text === '' && STATEMENT_KEYWORDS.has(this.peek().kind))
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
else if (kind === '(' || kind === '[' || kind === '{' || kind === 'TemplateHead') {
|
|
180
|
+
open.push(kind);
|
|
181
|
+
}
|
|
182
|
+
else if (kind === 'TemplateMiddle') {
|
|
183
|
+
// Closes one substitution and opens the next one.
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
const opening = BRACKETS[kind];
|
|
187
|
+
if (opening !== undefined) {
|
|
188
|
+
const index = open.lastIndexOf(opening);
|
|
189
|
+
if (index !== -1)
|
|
190
|
+
open.length = index;
|
|
191
|
+
else if (kind === '}') {
|
|
192
|
+
// A `}` without a matching `{` closes the enclosing block: leave it to the block.
|
|
193
|
+
this.pos--;
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (this.check('}') && !open.includes('{'))
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type * as ast from '../ast.ts';
|
|
2
|
+
import { DecoratorParser } from './decorators.ts';
|
|
3
|
+
export declare abstract class ClassParser extends DecoratorParser {
|
|
4
|
+
protected parseClass(start: number, exported: boolean): ast.ClassDeclaration;
|
|
5
|
+
protected parseClassMember(): ast.ClassMember[];
|
|
6
|
+
protected parseInterface(start: number, exported: boolean): ast.InterfaceDeclaration;
|
|
7
|
+
protected parseTypeAlias(start: number, exported: boolean): ast.TypeAliasDeclaration;
|
|
8
|
+
}
|