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,356 @@
|
|
|
1
|
+
import { CHAN_HELPERS } from "./chan-helpers.js";
|
|
2
|
+
import { GO_HELPERS } from "./go-helpers.js";
|
|
3
|
+
import { SELECT_HELPERS } from "./select-helpers.js";
|
|
4
|
+
import { THREAD_HELPERS } from "./thread-helpers.js";
|
|
5
|
+
/** Predeclared functions of goroutines and channels, by the helpers that define them. */
|
|
6
|
+
export const PREDECLARED = {
|
|
7
|
+
close: 'chan',
|
|
8
|
+
transfer: 'threads',
|
|
9
|
+
after: 'timers',
|
|
10
|
+
tick: 'timers',
|
|
11
|
+
cancel: 'cancel',
|
|
12
|
+
};
|
|
13
|
+
/** Helpers that use other helpers. */
|
|
14
|
+
export const HELPER_NEEDS = {
|
|
15
|
+
go: ['threads'],
|
|
16
|
+
goFor: ['threads'],
|
|
17
|
+
goLocal: ['threads'],
|
|
18
|
+
serve: ['threads'],
|
|
19
|
+
chan: ['threads', 'select'],
|
|
20
|
+
timers: ['chan'],
|
|
21
|
+
cancel: ['threads'],
|
|
22
|
+
select: ['chan'],
|
|
23
|
+
owner: ['runDeferred'],
|
|
24
|
+
mount: ['owner'],
|
|
25
|
+
content: ['owner'],
|
|
26
|
+
branches: ['owner'],
|
|
27
|
+
dynamic: ['owner'],
|
|
28
|
+
list: ['owner'],
|
|
29
|
+
};
|
|
30
|
+
export const HELPERS = {
|
|
31
|
+
...GO_HELPERS,
|
|
32
|
+
...CHAN_HELPERS,
|
|
33
|
+
...SELECT_HELPERS,
|
|
34
|
+
...THREAD_HELPERS,
|
|
35
|
+
/** `for v in x` over an untyped value: a Map gives its values, as a typed one does. */
|
|
36
|
+
values: [
|
|
37
|
+
'function $$values(iterable) {',
|
|
38
|
+
" if (typeof iterable === 'function') return iterable();",
|
|
39
|
+
' return iterable instanceof Map ? iterable.values() : iterable;',
|
|
40
|
+
'}',
|
|
41
|
+
],
|
|
42
|
+
/** Runs deferred calls in reverse order; every call runs even if an earlier one throws. */
|
|
43
|
+
runDeferred: [
|
|
44
|
+
'function $$runDeferred(deferred) {',
|
|
45
|
+
' let failure;',
|
|
46
|
+
' for (let i = deferred.length - 1; i >= 0; i--) {',
|
|
47
|
+
' try {',
|
|
48
|
+
' deferred[i]();',
|
|
49
|
+
' } catch (error) {',
|
|
50
|
+
' failure = { error };',
|
|
51
|
+
' }',
|
|
52
|
+
' }',
|
|
53
|
+
' if (failure) throw failure.error;',
|
|
54
|
+
'}',
|
|
55
|
+
],
|
|
56
|
+
/**
|
|
57
|
+
* Owners of markup that `{if}`, `{switch}` and `{for}` may remove: the functions returned by the
|
|
58
|
+
* `mount()` of its components, and the removal of the blocks inside it, run when it is removed.
|
|
59
|
+
* The current owner is shared by the modules of a page, since the blocks of one module may hold
|
|
60
|
+
* the components of another.
|
|
61
|
+
*/
|
|
62
|
+
owner: [
|
|
63
|
+
'const $$owner = Symbol.for("rook.owner");',
|
|
64
|
+
'',
|
|
65
|
+
'function $$owned(create) {',
|
|
66
|
+
' const owner = { removed: false, cleanups: [] };',
|
|
67
|
+
' const parent = globalThis[$$owner];',
|
|
68
|
+
' globalThis[$$owner] = owner;',
|
|
69
|
+
' let result;',
|
|
70
|
+
' try {',
|
|
71
|
+
' result = create();',
|
|
72
|
+
' } finally {',
|
|
73
|
+
' globalThis[$$owner] = parent;',
|
|
74
|
+
' }',
|
|
75
|
+
' const remove = () => {',
|
|
76
|
+
' if (owner.removed) return;',
|
|
77
|
+
' owner.removed = true;',
|
|
78
|
+
' $$runDeferred(owner.cleanups);',
|
|
79
|
+
' };',
|
|
80
|
+
' return [result, remove];',
|
|
81
|
+
'}',
|
|
82
|
+
'',
|
|
83
|
+
'function $$onRemove(cleanup) {',
|
|
84
|
+
' globalThis[$$owner]?.cleanups.push(cleanup);',
|
|
85
|
+
'}',
|
|
86
|
+
],
|
|
87
|
+
/**
|
|
88
|
+
* `mount() { ... }` of a component: runs when its markup is in the document. That is checked
|
|
89
|
+
* after the code that creates the component; markup that is not in the document yet is waited
|
|
90
|
+
* for with a MutationObserver, which watches only while some markup waits. Markup that its
|
|
91
|
+
* owner removes before that never mounts. The function `mount` returns runs when the owner is
|
|
92
|
+
* removed.
|
|
93
|
+
*/
|
|
94
|
+
mount: [
|
|
95
|
+
'const $$waiting = new Set();',
|
|
96
|
+
'let $$observer = null;',
|
|
97
|
+
'',
|
|
98
|
+
'function $$mount(node, mount) {',
|
|
99
|
+
' const entry = { node, mount, owner: globalThis[$$owner] };',
|
|
100
|
+
' entry.owner?.cleanups.push(() => $$waiting.delete(entry));',
|
|
101
|
+
' queueMicrotask(() => $$tryMount(entry));',
|
|
102
|
+
'}',
|
|
103
|
+
'',
|
|
104
|
+
'function $$tryMount(entry) {',
|
|
105
|
+
' if (entry.owner?.removed) return;',
|
|
106
|
+
' const node = entry.node();',
|
|
107
|
+
' if (node != null && !node.isConnected) {',
|
|
108
|
+
' $$waiting.add(entry);',
|
|
109
|
+
' if (!$$observer) {',
|
|
110
|
+
' $$observer = new MutationObserver($$mountWaiting);',
|
|
111
|
+
' $$observer.observe(node.ownerDocument ?? document, { childList: true, subtree: true });',
|
|
112
|
+
' }',
|
|
113
|
+
' return;',
|
|
114
|
+
' }',
|
|
115
|
+
' const cleanup = entry.mount();',
|
|
116
|
+
' if (typeof cleanup === "function") entry.owner?.cleanups.push(cleanup);',
|
|
117
|
+
'}',
|
|
118
|
+
'',
|
|
119
|
+
'function $$mountWaiting() {',
|
|
120
|
+
' for (const entry of $$waiting) {',
|
|
121
|
+
' if (!entry.node().isConnected) continue;',
|
|
122
|
+
' $$waiting.delete(entry);',
|
|
123
|
+
' $$tryMount(entry);',
|
|
124
|
+
' }',
|
|
125
|
+
' if ($$waiting.size === 0) {',
|
|
126
|
+
' $$observer.disconnect();',
|
|
127
|
+
' $$observer = null;',
|
|
128
|
+
' }',
|
|
129
|
+
'}',
|
|
130
|
+
],
|
|
131
|
+
/** Appends element content whose type is not known: null adds nothing, arrays add each item. */
|
|
132
|
+
append: [
|
|
133
|
+
'function $$append(parent, value) {',
|
|
134
|
+
' if (value == null || value === false) return;',
|
|
135
|
+
' if (Array.isArray(value)) {',
|
|
136
|
+
' for (const item of value) $$append(parent, item);',
|
|
137
|
+
' } else {',
|
|
138
|
+
' parent.append(value);',
|
|
139
|
+
' }',
|
|
140
|
+
'}',
|
|
141
|
+
],
|
|
142
|
+
/**
|
|
143
|
+
* Nodes of markup that change, `{list}` or `{ok ? <b /> : null}`: they are kept before an end
|
|
144
|
+
* marker. Nodes that stay are moved rather than created again. Returns the markers with the
|
|
145
|
+
* first nodes, to be inserted, and the update.
|
|
146
|
+
*/
|
|
147
|
+
content: [
|
|
148
|
+
'function $$content(value) {',
|
|
149
|
+
' const end = document.createTextNode("");',
|
|
150
|
+
' const fragment = document.createDocumentFragment();',
|
|
151
|
+
' fragment.append(end);',
|
|
152
|
+
' let nodes = [];',
|
|
153
|
+
' let remove;',
|
|
154
|
+
' const update = () => {',
|
|
155
|
+
' const next = [];',
|
|
156
|
+
' const add = (item) => {',
|
|
157
|
+
' if (item == null || item === false) return;',
|
|
158
|
+
' if (Array.isArray(item)) {',
|
|
159
|
+
' for (const each of item) add(each);',
|
|
160
|
+
' } else if (item.nodeType === 11) {',
|
|
161
|
+
' next.push(...item.childNodes);',
|
|
162
|
+
' } else {',
|
|
163
|
+
' next.push(typeof item === "object" ? item : document.createTextNode(String(item)));',
|
|
164
|
+
' }',
|
|
165
|
+
' };',
|
|
166
|
+
' const [created, removeCreated] = $$owned(value);',
|
|
167
|
+
' add(created);',
|
|
168
|
+
' remove?.();',
|
|
169
|
+
' remove = removeCreated;',
|
|
170
|
+
' const kept = new Set(next);',
|
|
171
|
+
' for (const node of nodes) if (!kept.has(node)) node.remove();',
|
|
172
|
+
' end.before(...next);',
|
|
173
|
+
' nodes = next;',
|
|
174
|
+
' };',
|
|
175
|
+
' update();',
|
|
176
|
+
' $$onRemove(() => remove?.());',
|
|
177
|
+
' return [fragment, update];',
|
|
178
|
+
'}',
|
|
179
|
+
],
|
|
180
|
+
/**
|
|
181
|
+
* `{if ...}` and `{switch ...}` in markup: shows the block that `choose` picks (-1 for none)
|
|
182
|
+
* between two markers. The block is created again only when the choice changes; otherwise it is
|
|
183
|
+
* updated.
|
|
184
|
+
*/
|
|
185
|
+
branches: [
|
|
186
|
+
'function $$branches(choose, blocks) {',
|
|
187
|
+
' const start = document.createTextNode("");',
|
|
188
|
+
' const end = document.createTextNode("");',
|
|
189
|
+
' const fragment = document.createDocumentFragment();',
|
|
190
|
+
' fragment.append(start, end);',
|
|
191
|
+
' let current = null;',
|
|
192
|
+
' let update;',
|
|
193
|
+
' let remove;',
|
|
194
|
+
' const render = () => {',
|
|
195
|
+
' const next = choose();',
|
|
196
|
+
' if (next === current) {',
|
|
197
|
+
' update?.();',
|
|
198
|
+
' return;',
|
|
199
|
+
' }',
|
|
200
|
+
' current = next;',
|
|
201
|
+
' remove?.();',
|
|
202
|
+
' while (start.nextSibling !== end) start.nextSibling.remove();',
|
|
203
|
+
' update = undefined;',
|
|
204
|
+
' remove = undefined;',
|
|
205
|
+
' if (next >= 0) {',
|
|
206
|
+
' const [[content, blockUpdate], removeBlock] = $$owned(blocks[next]);',
|
|
207
|
+
' end.before(content);',
|
|
208
|
+
' update = blockUpdate;',
|
|
209
|
+
' remove = removeBlock;',
|
|
210
|
+
' }',
|
|
211
|
+
' };',
|
|
212
|
+
' render();',
|
|
213
|
+
' $$onRemove(() => remove?.());',
|
|
214
|
+
' return [fragment, render];',
|
|
215
|
+
'}',
|
|
216
|
+
],
|
|
217
|
+
/**
|
|
218
|
+
* `<Page />` whose component is a value that changes: when it does, the block that `create`
|
|
219
|
+
* makes with it is created again between two markers; otherwise the block is updated.
|
|
220
|
+
*/
|
|
221
|
+
dynamic: [
|
|
222
|
+
'function $$dynamic(component, create) {',
|
|
223
|
+
' const start = document.createTextNode("");',
|
|
224
|
+
' const end = document.createTextNode("");',
|
|
225
|
+
' const fragment = document.createDocumentFragment();',
|
|
226
|
+
' fragment.append(start, end);',
|
|
227
|
+
' let current;',
|
|
228
|
+
' let update;',
|
|
229
|
+
' let remove;',
|
|
230
|
+
' const render = () => {',
|
|
231
|
+
' const next = component();',
|
|
232
|
+
' if (remove && next === current) {',
|
|
233
|
+
' update?.();',
|
|
234
|
+
' return;',
|
|
235
|
+
' }',
|
|
236
|
+
' current = next;',
|
|
237
|
+
' remove?.();',
|
|
238
|
+
' while (start.nextSibling !== end) start.nextSibling.remove();',
|
|
239
|
+
' const [[content, blockUpdate], removeBlock] = $$owned(() => create(next));',
|
|
240
|
+
' end.before(content);',
|
|
241
|
+
' update = blockUpdate;',
|
|
242
|
+
' remove = removeBlock;',
|
|
243
|
+
' };',
|
|
244
|
+
' render();',
|
|
245
|
+
' $$onRemove(() => remove?.());',
|
|
246
|
+
' return [fragment, render];',
|
|
247
|
+
'}',
|
|
248
|
+
],
|
|
249
|
+
/**
|
|
250
|
+
* `{for item in items { ... }}` in markup: a block for each item, between its own markers. On
|
|
251
|
+
* updates the blocks are found again by the item itself: blocks of items that stay are updated
|
|
252
|
+
* and moved into place, others are created or removed.
|
|
253
|
+
*/
|
|
254
|
+
list: [
|
|
255
|
+
'function $$list(items, create) {',
|
|
256
|
+
' const end = document.createTextNode("");',
|
|
257
|
+
' const fragment = document.createDocumentFragment();',
|
|
258
|
+
' fragment.append(end);',
|
|
259
|
+
' let blocks = [];',
|
|
260
|
+
' const nodesOf = (block) => {',
|
|
261
|
+
' const nodes = [];',
|
|
262
|
+
' for (let node = block.start; node !== block.end; node = node.nextSibling) nodes.push(node);',
|
|
263
|
+
' nodes.push(block.end);',
|
|
264
|
+
' return nodes;',
|
|
265
|
+
' };',
|
|
266
|
+
' const update = () => {',
|
|
267
|
+
' const old = new Map();',
|
|
268
|
+
' for (const block of blocks) {',
|
|
269
|
+
' const same = old.get(block.item);',
|
|
270
|
+
' if (same) same.push(block);',
|
|
271
|
+
' else old.set(block.item, [block]);',
|
|
272
|
+
' }',
|
|
273
|
+
' const next = [];',
|
|
274
|
+
' let index = 0;',
|
|
275
|
+
' for (const item of items()) {',
|
|
276
|
+
' let block = old.get(item)?.shift();',
|
|
277
|
+
' if (block) {',
|
|
278
|
+
' block.update?.(index);',
|
|
279
|
+
' } else {',
|
|
280
|
+
' const [[content, blockUpdate], remove] = $$owned(() => create(item, index));',
|
|
281
|
+
' block = { item, start: document.createTextNode(""), end: document.createTextNode("") };',
|
|
282
|
+
' block.update = blockUpdate;',
|
|
283
|
+
' block.remove = remove;',
|
|
284
|
+
' block.content = document.createDocumentFragment();',
|
|
285
|
+
' block.content.append(block.start, content, block.end);',
|
|
286
|
+
' }',
|
|
287
|
+
' next.push(block);',
|
|
288
|
+
' index++;',
|
|
289
|
+
' }',
|
|
290
|
+
' for (const same of old.values()) {',
|
|
291
|
+
' for (const block of same) {',
|
|
292
|
+
' block.remove();',
|
|
293
|
+
' for (const node of nodesOf(block)) node.remove();',
|
|
294
|
+
' }',
|
|
295
|
+
' }',
|
|
296
|
+
' let before = end;',
|
|
297
|
+
' for (let i = next.length - 1; i >= 0; i--) {',
|
|
298
|
+
' const block = next[i];',
|
|
299
|
+
' if (block.content) {',
|
|
300
|
+
' before.before(block.content);',
|
|
301
|
+
' block.content = null;',
|
|
302
|
+
' } else if (block.end.nextSibling !== before) {',
|
|
303
|
+
' before.before(...nodesOf(block));',
|
|
304
|
+
' }',
|
|
305
|
+
' before = block.start;',
|
|
306
|
+
' }',
|
|
307
|
+
' blocks = next;',
|
|
308
|
+
' };',
|
|
309
|
+
' update();',
|
|
310
|
+
' $$onRemove(() => {',
|
|
311
|
+
' for (const block of blocks) block.remove();',
|
|
312
|
+
' });',
|
|
313
|
+
' return [fragment, update];',
|
|
314
|
+
'}',
|
|
315
|
+
],
|
|
316
|
+
/** Creates an element with its properties and the attributes that are set with setAttribute. */
|
|
317
|
+
element: [
|
|
318
|
+
'function $$element(tag, properties, attributes) {',
|
|
319
|
+
' const element = Object.assign(document.createElement(tag), properties);',
|
|
320
|
+
' for (const name in attributes) element.setAttribute(name, attributes[name]);',
|
|
321
|
+
' return element;',
|
|
322
|
+
'}',
|
|
323
|
+
],
|
|
324
|
+
/** Creates an SVG element with its attributes. */
|
|
325
|
+
svgElement: [
|
|
326
|
+
'function $$svgElement(tag, attributes) {',
|
|
327
|
+
' const element = document.createElementNS("http://www.w3.org/2000/svg", tag);',
|
|
328
|
+
' for (const name in attributes) element.setAttribute(name, attributes[name]);',
|
|
329
|
+
' return element;',
|
|
330
|
+
'}',
|
|
331
|
+
],
|
|
332
|
+
/** Sets an attribute whose value may be null: then the attribute is removed. */
|
|
333
|
+
attribute: [
|
|
334
|
+
'function $$attribute(element, name, value) {',
|
|
335
|
+
' if (value == null) element.removeAttribute(name);',
|
|
336
|
+
' else element.setAttribute(name, value);',
|
|
337
|
+
'}',
|
|
338
|
+
],
|
|
339
|
+
/**
|
|
340
|
+
* Adds the CSS of a component to the page once: modules that inline the same component add it
|
|
341
|
+
* with the same id. `$$styles` keeps the CSS of the module for the shadow roots of its web
|
|
342
|
+
* components, which the page's styles do not reach.
|
|
343
|
+
*/
|
|
344
|
+
style: [
|
|
345
|
+
'const $$styles = [];',
|
|
346
|
+
'',
|
|
347
|
+
'function $$style(id, css) {',
|
|
348
|
+
' $$styles.push(css);',
|
|
349
|
+
' if (document.getElementById(id)) return;',
|
|
350
|
+
' const style = document.createElement("style");',
|
|
351
|
+
' style.id = id;',
|
|
352
|
+
' style.textContent = css;',
|
|
353
|
+
' document.head.append(style);',
|
|
354
|
+
'}',
|
|
355
|
+
],
|
|
356
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type * as ast from '../ast.ts';
|
|
2
|
+
import type { Type } from '../checker/types.ts';
|
|
3
|
+
import { type CopyListener } from '../decorator-copy.ts';
|
|
4
|
+
import type { InlinePackage } from '../inline-packages.ts';
|
|
5
|
+
import { type Root } from '../refs.ts';
|
|
6
|
+
export interface ImportedComponent {
|
|
7
|
+
node: ast.ComponentDeclaration;
|
|
8
|
+
/** What inlining needs; null when the component can only be called. */
|
|
9
|
+
inline: InlinePackage | null;
|
|
10
|
+
/** The types of the expressions of its module. */
|
|
11
|
+
types: WeakMap<ast.Expression, Type> | null;
|
|
12
|
+
/** The element at the top of what it creates, found in its module, or why it is not known. */
|
|
13
|
+
root: Root;
|
|
14
|
+
}
|
|
15
|
+
/** An inlined component of another module, with the components it brings, by their tags here. */
|
|
16
|
+
export interface LocalizedPackage {
|
|
17
|
+
/** The tags here of the components of the other module. */
|
|
18
|
+
tags: Map<string, string>;
|
|
19
|
+
inline: Map<string, ast.ComponentDeclaration>;
|
|
20
|
+
/** Components it calls, with the names of their functions here and the elements at their top. */
|
|
21
|
+
functions: Map<string, {
|
|
22
|
+
node: ast.ComponentDeclaration;
|
|
23
|
+
name: string;
|
|
24
|
+
root: Root;
|
|
25
|
+
}>;
|
|
26
|
+
/** The hidden names it imports: as exported there, as named here. */
|
|
27
|
+
imports: [string, string][];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The package of a component or a decorator `root` of another module, ready to be inlined here.
|
|
31
|
+
* `name` is the prefix of its names here: the name it is imported as.
|
|
32
|
+
*/
|
|
33
|
+
export declare function localize(name: string, root: string, found: InlinePackage, copied: CopyListener): LocalizedPackage;
|
|
34
|
+
/**
|
|
35
|
+
* `export { PREFIX as $$Card$PREFIX }` and the like: what the modules that inline the exported
|
|
36
|
+
* components of this one import from it, by the name they are exported under.
|
|
37
|
+
*/
|
|
38
|
+
export declare function packageExports(packages: ReadonlyMap<string, InlinePackage>, jsName: (name: string) => string): Map<string, string>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { renamer } from "../decorator-copy.js";
|
|
2
|
+
import { decorate, decoratedName } from "../decorators.js";
|
|
3
|
+
import { componentRoot } from "../refs.js";
|
|
4
|
+
/**
|
|
5
|
+
* The package of a component or a decorator `root` of another module, ready to be inlined here.
|
|
6
|
+
* `name` is the prefix of its names here: the name it is imported as.
|
|
7
|
+
*/
|
|
8
|
+
export function localize(name, root, found, copied) {
|
|
9
|
+
const tag = (other) => (other === root ? name : `${name}$${other}`);
|
|
10
|
+
const tags = new Map([...found.components.keys(), ...found.functions.keys()].map((other) => [other, tag(other)]));
|
|
11
|
+
const prefixes = new Map([...found.decorators.keys()].map((other) => [other, `${name}$${other}`]));
|
|
12
|
+
const renames = new Map(found.moduleNames.map((used) => [used, decoratedName(name, used)]));
|
|
13
|
+
const copy = renamer(renames, copied, { tags, decorators: prefixes });
|
|
14
|
+
const inline = new Map();
|
|
15
|
+
const functions = new Map();
|
|
16
|
+
// Here the copy is not exported: it is inlined like a component of this module.
|
|
17
|
+
for (const [other, node] of found.components) {
|
|
18
|
+
const component = copy(decorate(node, found.decorators, copied, prefixes), new Set());
|
|
19
|
+
inline.set(tag(other), { ...component, exported: false });
|
|
20
|
+
}
|
|
21
|
+
// A copy of its own: the same component may be imported here directly too.
|
|
22
|
+
for (const [other, node] of found.functions) {
|
|
23
|
+
const root = packageRoot(found, other, new Set());
|
|
24
|
+
functions.set(tag(other), { node: { ...node }, name: `$$${tag(other)}`, root });
|
|
25
|
+
}
|
|
26
|
+
const imports = [
|
|
27
|
+
...found.moduleNames.map((used) => [
|
|
28
|
+
decoratedName(root, used),
|
|
29
|
+
decoratedName(name, used),
|
|
30
|
+
]),
|
|
31
|
+
...[...found.decorators].flatMap(([other, source]) => source.moduleNames.map((used) => [
|
|
32
|
+
decoratedName(other, used),
|
|
33
|
+
decoratedName(prefixes.get(other), used),
|
|
34
|
+
])),
|
|
35
|
+
...[...found.functions.keys()].map((other) => [
|
|
36
|
+
`$$${other}`,
|
|
37
|
+
`$$${tag(other)}`,
|
|
38
|
+
]),
|
|
39
|
+
];
|
|
40
|
+
return { tags, inline, functions, imports };
|
|
41
|
+
}
|
|
42
|
+
/** The element at the top of what a component of a package creates, by its name there. */
|
|
43
|
+
function packageRoot(found, name, seen) {
|
|
44
|
+
const node = found.components.get(name) ?? found.functions.get(name);
|
|
45
|
+
if (!node || seen.has(name))
|
|
46
|
+
return 'is not known in advance';
|
|
47
|
+
seen.add(name);
|
|
48
|
+
return componentRoot(decorate(node, found.decorators), (tag) => packageRoot(found, tag, seen));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* `export { PREFIX as $$Card$PREFIX }` and the like: what the modules that inline the exported
|
|
52
|
+
* components of this one import from it, by the name they are exported under.
|
|
53
|
+
*/
|
|
54
|
+
export function packageExports(packages, jsName) {
|
|
55
|
+
const exports = new Map();
|
|
56
|
+
for (const [root, found] of packages) {
|
|
57
|
+
for (const used of found.moduleNames)
|
|
58
|
+
exports.set(decoratedName(root, used), jsName(used));
|
|
59
|
+
for (const [other, source] of found.decorators) {
|
|
60
|
+
for (const used of source.moduleNames) {
|
|
61
|
+
exports.set(decoratedName(other, used), jsName(used));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// An exported component's function is exported already.
|
|
65
|
+
for (const [other, node] of found.functions) {
|
|
66
|
+
if (!node.exported)
|
|
67
|
+
exports.set(`$$${other}`, `$$${other}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return exports;
|
|
71
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type * as ast from '../ast.ts';
|
|
2
|
+
import type { JsOptions } from './emitter.ts';
|
|
3
|
+
export type { JsOptions } from './emitter.ts';
|
|
4
|
+
/** A component whose inlined copies add more lines than this to its module becomes a function. */
|
|
5
|
+
export declare const INLINE_LIMIT = 100;
|
|
6
|
+
/**
|
|
7
|
+
* A module whose code creates more elements than this creates them with $$element, which takes
|
|
8
|
+
* their attributes: its definition takes less than the statements it saves.
|
|
9
|
+
*/
|
|
10
|
+
export declare const ELEMENT_HELPER_LIMIT = 20;
|
|
11
|
+
/**
|
|
12
|
+
* Generates a readable ES module from a program that has parsed without errors. A component is
|
|
13
|
+
* inlined where it is used, unless that adds more than INLINE_LIMIT lines compared to a function
|
|
14
|
+
* and its calls. The module is generated again with each such candidate as a function, and the one
|
|
15
|
+
* that saves the most goes first: that changes the sizes of the components inside it. A component
|
|
16
|
+
* of another module is a candidate too; its function is in that module, and counts as one copy.
|
|
17
|
+
* Then, if the code creates more than ELEMENT_HELPER_LIMIT elements, it is generated again with
|
|
18
|
+
* the helper that creates them.
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateJs(program: ast.Program, options: JsOptions): string;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { declarationsOf } from "./analysis.js";
|
|
2
|
+
import { FunctionEmitter } from "./functions.js";
|
|
3
|
+
import { startWorker } from "./go-helpers.js";
|
|
4
|
+
import { HELPER_NEEDS, HELPERS } from "./helpers.js";
|
|
5
|
+
/** A component whose inlined copies add more lines than this to its module becomes a function. */
|
|
6
|
+
export const INLINE_LIMIT = 100;
|
|
7
|
+
/**
|
|
8
|
+
* A module whose code creates more elements than this creates them with $$element, which takes
|
|
9
|
+
* their attributes: its definition takes less than the statements it saves.
|
|
10
|
+
*/
|
|
11
|
+
export const ELEMENT_HELPER_LIMIT = 20;
|
|
12
|
+
/**
|
|
13
|
+
* Generates a readable ES module from a program that has parsed without errors. A component is
|
|
14
|
+
* inlined where it is used, unless that adds more than INLINE_LIMIT lines compared to a function
|
|
15
|
+
* and its calls. The module is generated again with each such candidate as a function, and the one
|
|
16
|
+
* that saves the most goes first: that changes the sizes of the components inside it. A component
|
|
17
|
+
* of another module is a candidate too; its function is in that module, and counts as one copy.
|
|
18
|
+
* Then, if the code creates more than ELEMENT_HELPER_LIMIT elements, it is generated again with
|
|
19
|
+
* the helper that creates them.
|
|
20
|
+
*/
|
|
21
|
+
export function generateJs(program, options) {
|
|
22
|
+
const { code, functions, elements } = chooseFunctions(program, options);
|
|
23
|
+
if (elements <= ELEMENT_HELPER_LIMIT)
|
|
24
|
+
return code;
|
|
25
|
+
return new JsGenerator(program, { ...options, functions, elementHelper: true }).generate();
|
|
26
|
+
}
|
|
27
|
+
/** The code with the components that become functions; see generateJs. */
|
|
28
|
+
function chooseFunctions(program, options) {
|
|
29
|
+
const functions = new Set();
|
|
30
|
+
const generate = (names) => {
|
|
31
|
+
const generator = new JsGenerator(program, { ...options, functions: names });
|
|
32
|
+
const code = generator.generate();
|
|
33
|
+
const lines = code.split('\n').filter((line) => line.trim() !== '').length;
|
|
34
|
+
return { code, lines, generator };
|
|
35
|
+
};
|
|
36
|
+
let current = generate(functions);
|
|
37
|
+
while (true) {
|
|
38
|
+
let best = null;
|
|
39
|
+
const { inlined, alwaysInlined } = current.generator;
|
|
40
|
+
for (const [name, { copies, lines }] of inlined) {
|
|
41
|
+
// A function and its calls are larger than one copy, and save no more than the copies take.
|
|
42
|
+
if (copies < 2 || lines <= INLINE_LIMIT || alwaysInlined.has(name))
|
|
43
|
+
continue;
|
|
44
|
+
const trial = generate(new Set([...functions, name]));
|
|
45
|
+
const own = options.components?.has(name) ? Math.ceil(lines / copies) : 0;
|
|
46
|
+
const saved = current.lines - trial.lines - own;
|
|
47
|
+
if (saved > INLINE_LIMIT && (!best || saved > best.saved))
|
|
48
|
+
best = { ...trial, name, saved };
|
|
49
|
+
}
|
|
50
|
+
if (!best) {
|
|
51
|
+
return { code: current.code, functions, elements: current.generator.createdElements };
|
|
52
|
+
}
|
|
53
|
+
functions.add(best.name);
|
|
54
|
+
current = best;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** The whole module: its statements, plus the helpers that its code needs. */
|
|
58
|
+
class JsGenerator extends FunctionEmitter {
|
|
59
|
+
generate() {
|
|
60
|
+
this.withScope(declarationsOf(this.program.body), () => {
|
|
61
|
+
this.statements(this.program.body);
|
|
62
|
+
this.webComponentClasses();
|
|
63
|
+
this.hiddenExports();
|
|
64
|
+
});
|
|
65
|
+
const { goroutines } = this.options;
|
|
66
|
+
// The worker module runs the functions that `go` calls (see goroutines.ts).
|
|
67
|
+
if (goroutines && 'targets' in goroutines) {
|
|
68
|
+
const names = goroutines.targets.map((name) => this.name(name));
|
|
69
|
+
this.helpers.add('serve');
|
|
70
|
+
this.lines.push('', `const $$goroutines = { ${names.join(', ')} };`, '$$serve($$goroutines);');
|
|
71
|
+
}
|
|
72
|
+
// The CSS of the components goes before the code, so that the page has it before the markup.
|
|
73
|
+
const styles = this.styleRegistrations();
|
|
74
|
+
let lines = this.lines;
|
|
75
|
+
if (styles.length > 0)
|
|
76
|
+
this.helpers.add('style');
|
|
77
|
+
if (this.helpers.size > 0) {
|
|
78
|
+
const needed = new Set();
|
|
79
|
+
const add = (helper) => {
|
|
80
|
+
if (needed.has(helper))
|
|
81
|
+
return;
|
|
82
|
+
needed.add(helper);
|
|
83
|
+
for (const other of HELPER_NEEDS[helper] ?? [])
|
|
84
|
+
add(other);
|
|
85
|
+
};
|
|
86
|
+
for (const helper of this.helpers)
|
|
87
|
+
add(helper);
|
|
88
|
+
const workerUrl = goroutines && 'workerUrl' in goroutines ? goroutines.workerUrl : '';
|
|
89
|
+
const helpers = [...needed]
|
|
90
|
+
.sort()
|
|
91
|
+
.flatMap((helper, i) => [
|
|
92
|
+
...(i > 0 ? [''] : []),
|
|
93
|
+
...HELPERS[helper],
|
|
94
|
+
...(helper === 'go' ? ['', ...startWorker(workerUrl)] : []),
|
|
95
|
+
]);
|
|
96
|
+
let imports = 0;
|
|
97
|
+
while (lines[imports]?.startsWith('import '))
|
|
98
|
+
imports++;
|
|
99
|
+
const rest = lines.slice(imports);
|
|
100
|
+
while (rest[0] === '')
|
|
101
|
+
rest.shift();
|
|
102
|
+
lines = [
|
|
103
|
+
...lines.slice(0, imports),
|
|
104
|
+
...(imports > 0 ? [''] : []),
|
|
105
|
+
...helpers,
|
|
106
|
+
...(styles.length > 0 ? ['', ...styles] : []),
|
|
107
|
+
...(rest.length > 0 ? [''] : []),
|
|
108
|
+
...rest,
|
|
109
|
+
];
|
|
110
|
+
}
|
|
111
|
+
return lines.length === 0 ? '' : `${lines.join('\n')}\n`;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type * as ast from '../ast.ts';
|
|
2
|
+
/** The variable at the start of `a.b[i].c()`, or `null`. */
|
|
3
|
+
export declare function rootName(node: ast.Expression): string | null;
|
|
4
|
+
/** Names whose values a node reads, not counting code that runs on events. */
|
|
5
|
+
export declare function readNames(node: ast.Node, names: Set<string>): void;
|
|
6
|
+
/**
|
|
7
|
+
* Names an effect reads while it runs: not in the functions it creates, which run later, nor in
|
|
8
|
+
* its `defer`, nor the variables it writes, or `count++` would run it again.
|
|
9
|
+
*/
|
|
10
|
+
export declare function effectReads(node: ast.Node, names: Set<string>): void;
|