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
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
// Selectors: split into compound selectors, given the class of a component, with the classes of
|
|
2
|
+
// a CSS module renamed, or read for what elements they ask for. `:global(...)` keeps what is
|
|
3
|
+
// inside it as it is.
|
|
4
|
+
/** A selector list split at the commas outside brackets. */
|
|
5
|
+
export function splitList(selector) {
|
|
6
|
+
return splitTopLevel(selector, (c) => c === ',').map((part) => part.trim());
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* A complex selector as compound selectors and the combinators between them:
|
|
10
|
+
* `ul > li.item a` → ["ul", " > ", "li.item", " ", "a"]. A relative selector starts with a
|
|
11
|
+
* combinator: `> a` → ["", "> ", "a"].
|
|
12
|
+
*/
|
|
13
|
+
export function splitComplex(selector) {
|
|
14
|
+
const parts = [];
|
|
15
|
+
let current = '';
|
|
16
|
+
let depth = 0;
|
|
17
|
+
for (let i = 0; i < selector.length; i++) {
|
|
18
|
+
const c = selector[i];
|
|
19
|
+
if (c === '(' || c === '[')
|
|
20
|
+
depth++;
|
|
21
|
+
if (c === ')' || c === ']')
|
|
22
|
+
depth--;
|
|
23
|
+
if (depth === 0 &&
|
|
24
|
+
(c === ' ' || c === '>' || c === '+' || c === '~') &&
|
|
25
|
+
!escaped(selector, i)) {
|
|
26
|
+
let combinator = '';
|
|
27
|
+
while (i < selector.length && /[\s>+~]/.test(selector[i]))
|
|
28
|
+
combinator += selector[i++];
|
|
29
|
+
i--;
|
|
30
|
+
parts.push(current, combinator.trim() === '' ? ' ' : ` ${combinator.trim()} `);
|
|
31
|
+
current = '';
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
current += c;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
parts.push(current);
|
|
38
|
+
return parts;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Gives every compound selector the class of a component, before its pseudo-elements, so that the
|
|
42
|
+
* rule applies only to its elements. Compounds with `&` refer to the rule around them, and those
|
|
43
|
+
* in `:global(...)` are left to the page.
|
|
44
|
+
*/
|
|
45
|
+
export function scopeSelector(selector, scope) {
|
|
46
|
+
return splitList(selector)
|
|
47
|
+
.map((complex) => splitComplex(complex)
|
|
48
|
+
.map((part, i) => (i % 2 === 1 || part === '' ? part : scopeCompound(part, scope)))
|
|
49
|
+
.join('')
|
|
50
|
+
.trim())
|
|
51
|
+
.join(', ');
|
|
52
|
+
}
|
|
53
|
+
function scopeCompound(compound, scope) {
|
|
54
|
+
if (compound.includes(':global('))
|
|
55
|
+
return unwrapGlobal(compound);
|
|
56
|
+
if (compound.includes('&'))
|
|
57
|
+
return compound;
|
|
58
|
+
const pseudo = pseudoElementStart(compound);
|
|
59
|
+
return `${compound.slice(0, pseudo)}.${scope}${compound.slice(pseudo)}`;
|
|
60
|
+
}
|
|
61
|
+
/** Where the pseudo-element of a compound starts: `a::before` → 1, or its length if none. */
|
|
62
|
+
function pseudoElementStart(compound) {
|
|
63
|
+
let depth = 0;
|
|
64
|
+
for (let i = 0; i < compound.length; i++) {
|
|
65
|
+
const c = compound[i];
|
|
66
|
+
if (c === '(' || c === '[')
|
|
67
|
+
depth++;
|
|
68
|
+
if (c === ')' || c === ']')
|
|
69
|
+
depth--;
|
|
70
|
+
if (depth === 0 && c === ':' && LEGACY_PSEUDO_ELEMENT.test(compound.slice(i)))
|
|
71
|
+
return i;
|
|
72
|
+
}
|
|
73
|
+
return compound.length;
|
|
74
|
+
}
|
|
75
|
+
/** `::before`, and the pseudo-elements that may be written with one colon. */
|
|
76
|
+
const LEGACY_PSEUDO_ELEMENT = /^(?:::|:(?:before|after|first-line|first-letter)(?![\w-]))/;
|
|
77
|
+
/** `:global(.a) .b` → `.a .b`. */
|
|
78
|
+
export function unwrapGlobal(selector) {
|
|
79
|
+
let result = selector;
|
|
80
|
+
while (true) {
|
|
81
|
+
const start = result.indexOf(':global(');
|
|
82
|
+
if (start === -1)
|
|
83
|
+
return result;
|
|
84
|
+
const close = matchingParen(result, start + ':global'.length);
|
|
85
|
+
result =
|
|
86
|
+
result.slice(0, start) +
|
|
87
|
+
result.slice(start + ':global('.length, close) +
|
|
88
|
+
result.slice(close + 1);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The classes of a CSS module get its names: `.button:hover` → `.button_k3f9:hover`. Classes in
|
|
93
|
+
* `:global(...)` keep their names. Calls `found` for every local class.
|
|
94
|
+
*/
|
|
95
|
+
export function renameClasses(selector, rename, found) {
|
|
96
|
+
let result = '';
|
|
97
|
+
let i = 0;
|
|
98
|
+
while (i < selector.length) {
|
|
99
|
+
if (selector.startsWith(':global(', i)) {
|
|
100
|
+
const close = matchingParen(selector, i + ':global'.length);
|
|
101
|
+
result += selector.slice(i + ':global('.length, close);
|
|
102
|
+
i = close + 1;
|
|
103
|
+
}
|
|
104
|
+
else if (selector[i] === '[' || selector[i] === '"' || selector[i] === "'") {
|
|
105
|
+
// Attribute selectors and strings are not classes: `[class~="a"]`.
|
|
106
|
+
const end = selector[i] === '[' ? selector.indexOf(']', i) : selector.indexOf(selector[i], i + 1);
|
|
107
|
+
const stop = end === -1 ? selector.length : end + 1;
|
|
108
|
+
result += selector.slice(i, stop);
|
|
109
|
+
i = stop;
|
|
110
|
+
}
|
|
111
|
+
else if (selector[i] === '.' &&
|
|
112
|
+
!escaped(selector, i) &&
|
|
113
|
+
/[\w-]/.test(selector[i + 1] ?? '')) {
|
|
114
|
+
const name = /^[\w-]+/.exec(selector.slice(i + 1))[0];
|
|
115
|
+
found(name);
|
|
116
|
+
result += `.${rename(name)}`;
|
|
117
|
+
i += name.length + 1;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
result += selector[i];
|
|
121
|
+
i++;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
/** The tag, classes and ids a compound requires; those inside `:not(...)` and others are not. */
|
|
127
|
+
export function requirements(compound) {
|
|
128
|
+
const outside = compound.replace(/\([^)]*\)/g, '()').replace(/\[[^\]]*\]/g, '[]');
|
|
129
|
+
const tag = /^[a-zA-Z][\w-]*|^\*/.exec(outside)?.[0] ?? null;
|
|
130
|
+
return {
|
|
131
|
+
tag: tag === '*' ? null : tag,
|
|
132
|
+
classes: [...outside.matchAll(/\.([\w-]+)/g)].map((match) => match[1]),
|
|
133
|
+
ids: [...outside.matchAll(/#([\w-]+)/g)].map((match) => match[1]),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function splitTopLevel(text, at) {
|
|
137
|
+
const parts = [];
|
|
138
|
+
let current = '';
|
|
139
|
+
let depth = 0;
|
|
140
|
+
for (const c of text) {
|
|
141
|
+
if (c === '(' || c === '[')
|
|
142
|
+
depth++;
|
|
143
|
+
if (c === ')' || c === ']')
|
|
144
|
+
depth--;
|
|
145
|
+
if (depth === 0 && at(c)) {
|
|
146
|
+
parts.push(current);
|
|
147
|
+
current = '';
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
current += c;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
parts.push(current);
|
|
154
|
+
return parts;
|
|
155
|
+
}
|
|
156
|
+
function matchingParen(text, open) {
|
|
157
|
+
let depth = 0;
|
|
158
|
+
for (let i = open; i < text.length; i++) {
|
|
159
|
+
if (text[i] === '(')
|
|
160
|
+
depth++;
|
|
161
|
+
if (text[i] === ')' && --depth === 0)
|
|
162
|
+
return i;
|
|
163
|
+
}
|
|
164
|
+
return text.length;
|
|
165
|
+
}
|
|
166
|
+
function escaped(text, i) {
|
|
167
|
+
return i > 0 && text[i - 1] === '\\';
|
|
168
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { JS_RESERVED } from "./codegen/syntax.js";
|
|
2
|
+
import { generatorType, property, resultType, tsType } from "./ts-types.js";
|
|
3
|
+
// A TypeScript declaration file (`.d.ts`) for a compiled module, so that TypeScript code can use
|
|
4
|
+
// it with types. Parameter names come from the code, types from the type checker:
|
|
5
|
+
//
|
|
6
|
+
// number, string, bool → number, string, boolean
|
|
7
|
+
// ?T, error → T | null, Error | null
|
|
8
|
+
// []T → T[]
|
|
9
|
+
// (A, B) results → [A, B], the array that the JS function returns
|
|
10
|
+
//
|
|
11
|
+
// Interfaces, type aliases and classes are declared even when they are not exported, since the
|
|
12
|
+
// exported declarations may use them. Components exist only at compile time and are left out.
|
|
13
|
+
export function printDeclarations(program, checked) {
|
|
14
|
+
const printer = new DeclarationPrinter(checked);
|
|
15
|
+
return printer.print(program);
|
|
16
|
+
}
|
|
17
|
+
class DeclarationPrinter {
|
|
18
|
+
checked;
|
|
19
|
+
lines = [];
|
|
20
|
+
constructor(checked) {
|
|
21
|
+
this.checked = checked;
|
|
22
|
+
}
|
|
23
|
+
print(program) {
|
|
24
|
+
let exports = false;
|
|
25
|
+
for (const statement of program.body) {
|
|
26
|
+
if ('exported' in statement && statement.exported)
|
|
27
|
+
exports = true;
|
|
28
|
+
switch (statement.kind) {
|
|
29
|
+
case 'ImportDeclaration':
|
|
30
|
+
this.importDeclaration(statement);
|
|
31
|
+
break;
|
|
32
|
+
case 'FuncDeclaration':
|
|
33
|
+
if (statement.exported)
|
|
34
|
+
this.functionDeclaration(statement);
|
|
35
|
+
break;
|
|
36
|
+
case 'VariableDeclaration':
|
|
37
|
+
if (statement.exported)
|
|
38
|
+
this.variableDeclaration(statement);
|
|
39
|
+
break;
|
|
40
|
+
case 'ClassDeclaration':
|
|
41
|
+
this.classDeclaration(statement);
|
|
42
|
+
break;
|
|
43
|
+
case 'InterfaceDeclaration':
|
|
44
|
+
this.interfaceDeclaration(statement);
|
|
45
|
+
break;
|
|
46
|
+
case 'TypeAliasDeclaration':
|
|
47
|
+
this.typeAlias(statement);
|
|
48
|
+
break;
|
|
49
|
+
default:
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// A declaration file without imports or exports would declare global names.
|
|
54
|
+
if (!exports)
|
|
55
|
+
this.lines.push('export {};');
|
|
56
|
+
return this.lines.join('\n') + '\n';
|
|
57
|
+
}
|
|
58
|
+
/** Imports are repeated, so that the names they bring can be used in types. */
|
|
59
|
+
importDeclaration(node) {
|
|
60
|
+
const parts = [];
|
|
61
|
+
if (node.defaultImport)
|
|
62
|
+
parts.push(node.defaultImport.name);
|
|
63
|
+
if (node.namespaceImport)
|
|
64
|
+
parts.push(`* as ${node.namespaceImport.name}`);
|
|
65
|
+
if (node.namedImports.length > 0) {
|
|
66
|
+
const names = node.namedImports.map((specifier) => specifier.imported.name === specifier.local.name
|
|
67
|
+
? specifier.local.name
|
|
68
|
+
: `${specifier.imported.name} as ${specifier.local.name}`);
|
|
69
|
+
parts.push(`{ ${names.join(', ')} }`);
|
|
70
|
+
}
|
|
71
|
+
if (parts.length === 0)
|
|
72
|
+
return;
|
|
73
|
+
const source = node.source.value.replace(/\.rk$/, '.js');
|
|
74
|
+
this.lines.push(`import ${parts.join(', ')} from ${JSON.stringify(source)};`);
|
|
75
|
+
}
|
|
76
|
+
functionDeclaration(node) {
|
|
77
|
+
const type = this.checked.declarations.values.get(node.name.name);
|
|
78
|
+
if (type?.kind !== 'function')
|
|
79
|
+
return;
|
|
80
|
+
const name = jsName(node.name.name);
|
|
81
|
+
this.lines.push(`export declare function ${name}${this.typeParams(type.typeParams)}${this.signature(node.params, type)};`);
|
|
82
|
+
}
|
|
83
|
+
variableDeclaration(node) {
|
|
84
|
+
const keyword = node.keyword === 'let' ? 'let' : 'const';
|
|
85
|
+
for (const name of node.names) {
|
|
86
|
+
if (name.name === '_')
|
|
87
|
+
continue;
|
|
88
|
+
const type = this.checked.declarations.values.get(name.name);
|
|
89
|
+
this.lines.push(`export declare ${keyword} ${jsName(name.name)}: ${type ? tsType(type) : 'any'};`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
interfaceDeclaration(node) {
|
|
93
|
+
const type = this.checked.declarations.types.get(node.name.name);
|
|
94
|
+
if (type?.kind !== 'object')
|
|
95
|
+
return;
|
|
96
|
+
const exported = node.exported ? 'export ' : '';
|
|
97
|
+
this.lines.push(`${exported}interface ${node.name.name}${this.typeParams(type.typeParams ?? [])} {`, ...this.objectMembers(node.members, type).map((line) => ` ${line}`), '}');
|
|
98
|
+
}
|
|
99
|
+
typeAlias(node) {
|
|
100
|
+
const type = this.checked.declarations.types.get(node.name.name);
|
|
101
|
+
if (!type)
|
|
102
|
+
return;
|
|
103
|
+
const exported = node.exported ? 'export ' : '';
|
|
104
|
+
const params = this.typeParams(type.kind === 'object' ? (type.typeParams ?? []) : []);
|
|
105
|
+
// `type Pair<A, B any> { ... }` names an object type; other aliases are another name.
|
|
106
|
+
if (node.type.kind === 'ObjectType' && type.kind === 'object') {
|
|
107
|
+
const members = this.objectMembers(node.type.members, type);
|
|
108
|
+
this.lines.push(`${exported}type ${node.name.name}${params} = {`, ...members.map((line) => ` ${line}`), '};');
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
this.lines.push(`${exported}type ${node.name.name}${params} = ${tsType(type, true)};`);
|
|
112
|
+
}
|
|
113
|
+
/** Members of an interface or an object type, with the parameter names of its methods. */
|
|
114
|
+
objectMembers(members, type) {
|
|
115
|
+
return members.map((member) => {
|
|
116
|
+
if (member.kind === 'IndexSignature') {
|
|
117
|
+
return `[key: string]: ${type.index ? tsType(type.index, false) : 'any'};`;
|
|
118
|
+
}
|
|
119
|
+
const name = member.name.name;
|
|
120
|
+
const memberType = type.members.get(name)?.type;
|
|
121
|
+
if (member.kind === 'MethodSignature' && memberType?.kind === 'function') {
|
|
122
|
+
return `${name}${this.signature(member.params, memberType)};`;
|
|
123
|
+
}
|
|
124
|
+
return memberType ? property(name, memberType) : `${name}: any;`;
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
classDeclaration(node) {
|
|
128
|
+
const instance = this.checked.declarations.types.get(node.name.name);
|
|
129
|
+
if (instance?.kind !== 'class')
|
|
130
|
+
return;
|
|
131
|
+
const { info } = instance;
|
|
132
|
+
const exported = node.exported ? 'export ' : '';
|
|
133
|
+
const base = node.superClass && expressionName(node.superClass);
|
|
134
|
+
const heritage = base ? ` extends ${base}` : '';
|
|
135
|
+
const lines = [];
|
|
136
|
+
for (const member of node.members) {
|
|
137
|
+
switch (member.kind) {
|
|
138
|
+
case 'FieldDeclaration': {
|
|
139
|
+
const found = (member.isStatic ? info.statics : info.members).get(member.name.name);
|
|
140
|
+
const modifiers = this.modifiers(member.visibility, member.isStatic);
|
|
141
|
+
// As in the declaration files TypeScript writes, private members have no type.
|
|
142
|
+
if (member.visibility === 'private')
|
|
143
|
+
lines.push(`${modifiers}${member.name.name};`);
|
|
144
|
+
else if (found)
|
|
145
|
+
lines.push(`${modifiers}${member.name.name}: ${tsType(found.type)};`);
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
case 'ConstructorDeclaration': {
|
|
149
|
+
const modifiers = this.modifiers(member.visibility, false);
|
|
150
|
+
if (info.ctor) {
|
|
151
|
+
lines.push(`${modifiers}constructor${parameters(member.params, info.ctor)};`);
|
|
152
|
+
}
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
case 'MethodDeclaration': {
|
|
156
|
+
const found = (member.isStatic ? info.statics : info.members).get(member.name.name);
|
|
157
|
+
const modifiers = this.modifiers(member.visibility, member.isStatic);
|
|
158
|
+
if (member.visibility === 'private')
|
|
159
|
+
lines.push(`${modifiers}${member.name.name}();`);
|
|
160
|
+
else if (found?.type.kind === 'function') {
|
|
161
|
+
lines.push(`${modifiers}${member.name.name}${this.signature(member.params, found.type)};`);
|
|
162
|
+
}
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
this.lines.push(`${exported}declare class ${jsName(node.name.name)}${this.typeParams(info.typeParams)}${heritage} {`, ...lines.map((line) => ` ${line}`), '}');
|
|
168
|
+
}
|
|
169
|
+
modifiers(visibility, isStatic) {
|
|
170
|
+
return `${visibility === 'public' ? '' : `${visibility} `}${isStatic ? 'static ' : ''}`;
|
|
171
|
+
}
|
|
172
|
+
/** `<T, U extends Shape>` */
|
|
173
|
+
typeParams(params) {
|
|
174
|
+
if (params.length === 0)
|
|
175
|
+
return '';
|
|
176
|
+
const list = params.map((param) => param.constraint ? `${param.name} extends ${tsType(param.constraint)}` : param.name);
|
|
177
|
+
return `<${list.join(', ')}>`;
|
|
178
|
+
}
|
|
179
|
+
/** `(a: number, b?: string): R` with the names of the parameters in the code. */
|
|
180
|
+
signature(params, type) {
|
|
181
|
+
// An iterator is a generator function: it takes no function and gives the generator.
|
|
182
|
+
if (type.iterator)
|
|
183
|
+
return `(): ${generatorType(type)}`;
|
|
184
|
+
return `${parameters(params, type)}: ${resultType(type.results)}`;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function parameters(params, type) {
|
|
188
|
+
const list = type.params.map((param, i) => {
|
|
189
|
+
const name = params[i] ? jsName(params[i].name.name) : `arg${i + 1}`;
|
|
190
|
+
return `${name}${i < type.required ? '' : '?'}: ${tsType(param)}`;
|
|
191
|
+
});
|
|
192
|
+
return `(${list.join(', ')})`;
|
|
193
|
+
}
|
|
194
|
+
/** `Base` or `events.EventEmitter` in `extends`; other expressions cannot be written in types. */
|
|
195
|
+
function expressionName(node) {
|
|
196
|
+
if (node.kind === 'Identifier')
|
|
197
|
+
return node.name;
|
|
198
|
+
if (node.kind === 'MemberExpression') {
|
|
199
|
+
const object = expressionName(node.object);
|
|
200
|
+
return object && `${object}.${node.property.name}`;
|
|
201
|
+
}
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
/** Names that are reserved in JS get `$`, as in the generated code. */
|
|
205
|
+
function jsName(name) {
|
|
206
|
+
return JS_RESERVED.has(name) ? `${name}$` : name;
|
|
207
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type * as ast from './ast.ts';
|
|
2
|
+
/** Called with each copy of a node, so that the generator keeps the types of the originals. */
|
|
3
|
+
export type CopyListener = (copy: ast.Node, original: ast.Node) => void;
|
|
4
|
+
/** The node in the code as written that `node` is a copy of, through copies of copies. */
|
|
5
|
+
export declare function originOf(node: ast.Node): ast.Node;
|
|
6
|
+
/**
|
|
7
|
+
* Renames of the names that are not values: tags of components, `<Icon />`, and decorators,
|
|
8
|
+
* `get(@visible.shown)`. Code of another module refers to those of its own module.
|
|
9
|
+
*/
|
|
10
|
+
export interface OtherNames {
|
|
11
|
+
tags?: ReadonlyMap<string, string>;
|
|
12
|
+
decorators?: ReadonlyMap<string, string>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Copies nodes, renaming names where a local declaration does not hide them. Names of properties,
|
|
16
|
+
* attributes and types are left as they are, and so are tags and decorators without `other`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function renamer(renames: ReadonlyMap<string, string>, copied: CopyListener | undefined, other?: OtherNames): <T extends ast.Node>(node: T, hidden: ReadonlySet<string>) => T;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { declaredIn } from "./names.js";
|
|
2
|
+
/** The node each copy was made from. */
|
|
3
|
+
const origins = new WeakMap();
|
|
4
|
+
/** The node in the code as written that `node` is a copy of, through copies of copies. */
|
|
5
|
+
export function originOf(node) {
|
|
6
|
+
let current = node;
|
|
7
|
+
while (true) {
|
|
8
|
+
const origin = origins.get(current);
|
|
9
|
+
if (!origin)
|
|
10
|
+
return current;
|
|
11
|
+
current = origin;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const TYPE_NODES = new Set([
|
|
15
|
+
'TypeReference',
|
|
16
|
+
'ArrayType',
|
|
17
|
+
'NullableType',
|
|
18
|
+
'FuncType',
|
|
19
|
+
'ComponentType',
|
|
20
|
+
'ObjectType',
|
|
21
|
+
'UnionType',
|
|
22
|
+
'LiteralType',
|
|
23
|
+
'TypeParameter',
|
|
24
|
+
'PropertySignature',
|
|
25
|
+
'MethodSignature',
|
|
26
|
+
'IndexSignature',
|
|
27
|
+
]);
|
|
28
|
+
function isNode(value) {
|
|
29
|
+
return typeof value === 'object' && value !== null && 'kind' in value;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Copies nodes, renaming names where a local declaration does not hide them. Names of properties,
|
|
33
|
+
* attributes and types are left as they are, and so are tags and decorators without `other`.
|
|
34
|
+
*/
|
|
35
|
+
export function renamer(renames, copied, other = {}) {
|
|
36
|
+
const done = (copy, original) => {
|
|
37
|
+
origins.set(copy, original);
|
|
38
|
+
copied?.(copy, original);
|
|
39
|
+
return copy;
|
|
40
|
+
};
|
|
41
|
+
const statements = (list, hidden) => {
|
|
42
|
+
const inner = new Set([...hidden, ...declaredIn(list)]);
|
|
43
|
+
return list.map((statement) => copy(statement, inner));
|
|
44
|
+
};
|
|
45
|
+
const scoped = (names, hidden) => new Set([...hidden, ...names]);
|
|
46
|
+
const paramNames = (params) => params.map((param) => param.name.name);
|
|
47
|
+
const generic = (node, hidden) => {
|
|
48
|
+
const result = {};
|
|
49
|
+
for (const [key, value] of Object.entries(node)) {
|
|
50
|
+
if (Array.isArray(value)) {
|
|
51
|
+
result[key] = value.map((item) => (isNode(item) ? copy(item, hidden) : item));
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
result[key] = isNode(value) ? copy(value, hidden) : value;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return done(result, node);
|
|
58
|
+
};
|
|
59
|
+
const copy = (original, hidden) => {
|
|
60
|
+
const node = original;
|
|
61
|
+
if (TYPE_NODES.has(node.kind))
|
|
62
|
+
return original;
|
|
63
|
+
switch (node.kind) {
|
|
64
|
+
// The names of `@cart.count` are the other decorator's.
|
|
65
|
+
case 'DecoratorMember': {
|
|
66
|
+
const name = other.decorators?.get(node.decorator.name);
|
|
67
|
+
return name === undefined
|
|
68
|
+
? original
|
|
69
|
+
: done({ ...node, decorator: { ...node.decorator, name } }, node);
|
|
70
|
+
}
|
|
71
|
+
case 'Identifier': {
|
|
72
|
+
const name = hidden.has(node.name) ? undefined : renames.get(node.name);
|
|
73
|
+
return name === undefined ? original : done({ ...node, name }, node);
|
|
74
|
+
}
|
|
75
|
+
case 'MemberExpression':
|
|
76
|
+
return done({ ...node, object: copy(node.object, hidden) }, node);
|
|
77
|
+
case 'Property': {
|
|
78
|
+
const value = copy(node.value, hidden);
|
|
79
|
+
// `{ shown }` becomes `{ shown: $$visible$shown }`.
|
|
80
|
+
const shorthand = node.shorthand && value === node.value;
|
|
81
|
+
return done({ ...node, value, shorthand }, node);
|
|
82
|
+
}
|
|
83
|
+
case 'JsxAttribute':
|
|
84
|
+
return done({ ...node, value: node.value && copy(node.value, hidden) }, node);
|
|
85
|
+
case 'ElementExpression': {
|
|
86
|
+
const name = node.tag && other.tags?.get(node.tag.name);
|
|
87
|
+
// `<Page />` with a variable `Page`: a renamed variable becomes the value of the tag.
|
|
88
|
+
const variable = node.tag && name === undefined && /^[A-Z]/.test(node.tag.name)
|
|
89
|
+
? copy(node.tag, hidden)
|
|
90
|
+
: null;
|
|
91
|
+
const value = node.value
|
|
92
|
+
? copy(node.value, hidden)
|
|
93
|
+
: variable !== node.tag
|
|
94
|
+
? variable
|
|
95
|
+
: null;
|
|
96
|
+
return done({
|
|
97
|
+
...node,
|
|
98
|
+
tag: name ? { ...node.tag, name } : node.tag,
|
|
99
|
+
value,
|
|
100
|
+
attributes: node.attributes.map((attribute) => copy(attribute, hidden)),
|
|
101
|
+
children: node.children.map((child) => copy(child, hidden)),
|
|
102
|
+
}, node);
|
|
103
|
+
}
|
|
104
|
+
case 'MethodDeclaration': {
|
|
105
|
+
const inner = scoped(paramNames(node.params), hidden);
|
|
106
|
+
return done({
|
|
107
|
+
...node,
|
|
108
|
+
params: node.params.map((param) => copy(param, inner)),
|
|
109
|
+
body: copy(node.body, inner),
|
|
110
|
+
}, node);
|
|
111
|
+
}
|
|
112
|
+
case 'FieldDeclaration':
|
|
113
|
+
return done({ ...node, value: node.value && copy(node.value, hidden) }, node);
|
|
114
|
+
case 'FuncDeclaration':
|
|
115
|
+
case 'FuncExpression':
|
|
116
|
+
case 'ArrowFunction':
|
|
117
|
+
case 'ConstructorDeclaration': {
|
|
118
|
+
const inner = scoped(paramNames(node.params), hidden);
|
|
119
|
+
const renamed = generic(node, inner);
|
|
120
|
+
// The name of a declared function is in the enclosing scope.
|
|
121
|
+
if (node.kind === 'FuncDeclaration') {
|
|
122
|
+
renamed.name = copy(node.name, hidden);
|
|
123
|
+
}
|
|
124
|
+
return renamed;
|
|
125
|
+
}
|
|
126
|
+
case 'Parameter':
|
|
127
|
+
return done({ ...node, defaultValue: node.defaultValue && copy(node.defaultValue, hidden) }, node);
|
|
128
|
+
case 'BlockStatement':
|
|
129
|
+
return done({ ...node, body: statements(node.body, hidden) }, node);
|
|
130
|
+
case 'SwitchCase':
|
|
131
|
+
return done({
|
|
132
|
+
...node,
|
|
133
|
+
tests: node.tests.map((test) => copy(test, hidden)),
|
|
134
|
+
body: statements(node.body, hidden),
|
|
135
|
+
}, node);
|
|
136
|
+
case 'EventHandler':
|
|
137
|
+
return done({ ...node, body: statements(node.body, scoped(['event'], hidden)) }, node);
|
|
138
|
+
case 'ForInStatement': {
|
|
139
|
+
const names = [node.value.name, ...(node.key ? [node.key.name] : [])];
|
|
140
|
+
return done({
|
|
141
|
+
...node,
|
|
142
|
+
iterable: copy(node.iterable, hidden),
|
|
143
|
+
body: copy(node.body, scoped(names, hidden)),
|
|
144
|
+
}, node);
|
|
145
|
+
}
|
|
146
|
+
case 'ForStatement':
|
|
147
|
+
return generic(node, scoped(node.init ? declaredIn([node.init]) : [], hidden));
|
|
148
|
+
case 'CatchClause':
|
|
149
|
+
return done({
|
|
150
|
+
...node,
|
|
151
|
+
body: copy(node.body, scoped(node.param ? [node.param.name] : [], hidden)),
|
|
152
|
+
}, node);
|
|
153
|
+
default:
|
|
154
|
+
return generic(original, hidden);
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
return copy;
|
|
158
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type * as ast from './ast.ts';
|
|
2
|
+
import { type CopyListener } from './decorator-copy.ts';
|
|
3
|
+
/** The JS name of a member or a parameter of a decorator, in the components it is applied to. */
|
|
4
|
+
export declare function decoratedName(decorator: string, member: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* Whether a declaration of an applied component gets an argument of a decorator. When the
|
|
7
|
+
* argument reads the component's properties, the declaration is a `state` that the properties
|
|
8
|
+
* set again.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isDecoratorArgument(node: ast.Statement): node is ast.VariableDeclaration;
|
|
11
|
+
/**
|
|
12
|
+
* Whether markup is what a component returns to the wrapper of a decorator, as in
|
|
13
|
+
* `const $$visible$content = <section>...</section>`: it updates like returned markup.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isWrappedContent(node: ast.Expression): boolean;
|
|
16
|
+
/** The markup that an applied component gives to the wrappers, whichever `return` it takes. */
|
|
17
|
+
export declare function wrappedMarkup(component: ast.ComponentDeclaration): ast.Expression[];
|
|
18
|
+
/** `return (content Element) => ...` at the end of a decorator's body. */
|
|
19
|
+
export interface Wrapper {
|
|
20
|
+
fn: ast.ArrowFunction | ast.FuncExpression;
|
|
21
|
+
param: ast.Parameter;
|
|
22
|
+
}
|
|
23
|
+
/** The wrapper of a decorator, when it returns a function literal with one parameter. */
|
|
24
|
+
export declare function wrapperOf(decorator: ast.DecoratorDeclaration): Wrapper | null;
|
|
25
|
+
/** The statements of a wrapper; an expression body is what it returns. */
|
|
26
|
+
export declare function wrapperBody(fn: ast.ArrowFunction | ast.FuncExpression): ast.Statement[];
|
|
27
|
+
/** The parameter of a wrapper and its declarations, which go into the component's body too. */
|
|
28
|
+
export declare function wrapperNames(wrapper: Wrapper): string[];
|
|
29
|
+
/**
|
|
30
|
+
* A decorator that components can apply. One from another module uses the names of its own module
|
|
31
|
+
* through hidden exports, `$$visible$log`, so its code gets them renamed.
|
|
32
|
+
*/
|
|
33
|
+
export interface DecoratorSource {
|
|
34
|
+
node: ast.DecoratorDeclaration;
|
|
35
|
+
moduleNames: readonly string[];
|
|
36
|
+
/** For one of another module: the tags here of the components of that module its code uses. */
|
|
37
|
+
tags?: ReadonlyMap<string, string> | undefined;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The names of its module that a decorator's code uses. Other modules that apply it get them
|
|
41
|
+
* through hidden exports: `export { log as $$visible$log }`.
|
|
42
|
+
*/
|
|
43
|
+
export declare function moduleNamesOf(decorator: ast.DecoratorDeclaration, program: ast.Program): string[];
|
|
44
|
+
/**
|
|
45
|
+
* The component with its decorators applied. Its body first declares the arguments of each
|
|
46
|
+
* decorator and runs its body, from the top decorator down, then runs the component's own body.
|
|
47
|
+
* The names of a decorator get its prefix, `$$visible$shown`, so they clash neither with each other
|
|
48
|
+
* nor with the component's names, and `get(@visible.shown)` reads that variable. The `mount()` of
|
|
49
|
+
* the decorators runs after the component's own, from the inside out, so it goes before every
|
|
50
|
+
* `return` of the component's body.
|
|
51
|
+
*
|
|
52
|
+
* A wrapper is inlined at every `return` too: `return <section />` becomes
|
|
53
|
+
* `const $$visible$content = <section />`, then the body of the wrapper, whose `return` is the
|
|
54
|
+
* component's. The wrappers apply from the bottom decorator up.
|
|
55
|
+
*
|
|
56
|
+
* `prefixes` replace the names of decorators in the prefixes: a module that inlines a component of
|
|
57
|
+
* another one keeps the decorators of that module apart from its own, `$$Card$visible$shown`.
|
|
58
|
+
*/
|
|
59
|
+
export declare function decorate(component: ast.ComponentDeclaration, decorators: ReadonlyMap<string, DecoratorSource>, copied?: CopyListener, prefixes?: ReadonlyMap<string, string>): ast.ComponentDeclaration;
|
|
60
|
+
/** The parameters of a decorator and the declarations of its body: the names it renames. */
|
|
61
|
+
export declare function decoratorNames(decorator: ast.DecoratorDeclaration): Set<string>;
|