rooklang 0.3.3 → 0.4.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/README.md +34 -7
- package/README.ru.md +34 -7
- package/dist/ast/declarations.d.ts +39 -4
- package/dist/ast/expressions.d.ts +34 -8
- package/dist/ast/markup.d.ts +6 -1
- package/dist/ast/statements.d.ts +28 -2
- package/dist/auto-import.d.ts +11 -0
- package/dist/auto-import.js +81 -0
- package/dist/breaks.d.ts +6 -0
- package/dist/breaks.js +36 -0
- package/dist/build.d.ts +7 -0
- package/dist/build.js +23 -2
- package/dist/checker/array-literals.d.ts +6 -0
- package/dist/checker/array-literals.js +59 -0
- package/dist/checker/assignments.d.ts +4 -0
- package/dist/checker/assignments.js +23 -3
- package/dist/checker/base.d.ts +8 -2
- package/dist/checker/base.js +7 -7
- package/dist/checker/builtins.js +22 -8
- package/dist/checker/bytes.d.ts +2 -2
- package/dist/checker/bytes.js +2 -2
- package/dist/checker/calls.js +3 -0
- package/dist/checker/channel-objects.d.ts +3 -0
- package/dist/checker/channel-objects.js +40 -0
- package/dist/checker/channels.d.ts +1 -0
- package/dist/checker/channels.js +17 -4
- package/dist/checker/checker.d.ts +1 -1
- package/dist/checker/checker.js +19 -0
- package/dist/checker/class-members.d.ts +22 -0
- package/dist/checker/class-members.js +105 -0
- package/dist/checker/classes.d.ts +5 -4
- package/dist/checker/classes.js +48 -13
- package/dist/checker/closing.d.ts +21 -0
- package/dist/checker/closing.js +164 -0
- package/dist/checker/completion.d.ts +3 -3
- package/dist/checker/completion.js +4 -3
- package/dist/checker/component-bindings.d.ts +7 -0
- package/dist/checker/component-bindings.js +45 -0
- package/dist/checker/component-values.js +10 -7
- package/dist/checker/components.d.ts +2 -2
- package/dist/checker/components.js +8 -3
- package/dist/checker/context.d.ts +41 -5
- package/dist/checker/context.js +23 -0
- package/dist/checker/control-flow.d.ts +11 -5
- package/dist/checker/control-flow.js +65 -40
- package/dist/checker/declarations.d.ts +2 -2
- package/dist/checker/declarations.js +4 -2
- package/dist/checker/decode.d.ts +8 -0
- package/dist/checker/decode.js +32 -0
- package/dist/checker/decorator-exports.js +4 -0
- package/dist/checker/decorator-includes.d.ts +9 -0
- package/dist/checker/decorator-includes.js +71 -0
- package/dist/checker/decorator-members.d.ts +8 -10
- package/dist/checker/decorator-members.js +28 -31
- package/dist/checker/decorator-wrappers.d.ts +1 -1
- package/dist/checker/decorator-wrappers.js +3 -2
- package/dist/checker/decorators.d.ts +14 -5
- package/dist/checker/decorators.js +52 -25
- package/dist/checker/expressions.d.ts +6 -2
- package/dist/checker/expressions.js +20 -40
- package/dist/checker/flow.d.ts +25 -3
- package/dist/checker/flow.js +56 -12
- package/dist/checker/functions.d.ts +2 -2
- package/dist/checker/functions.js +9 -5
- package/dist/checker/helpers.d.ts +5 -2
- package/dist/checker/helpers.js +16 -4
- package/dist/checker/imports.js +5 -2
- package/dist/checker/iterables.d.ts +3 -1
- package/dist/checker/iterables.js +13 -0
- package/dist/checker/iterators.d.ts +4 -1
- package/dist/checker/iterators.js +12 -4
- package/dist/checker/json.d.ts +5 -0
- package/dist/checker/json.js +92 -0
- package/dist/checker/loops.d.ts +2 -0
- package/dist/checker/loops.js +50 -5
- package/dist/checker/markup.js +14 -2
- package/dist/checker/members.js +10 -1
- package/dist/checker/operators.d.ts +2 -2
- package/dist/checker/operators.js +7 -5
- package/dist/checker/queues.d.ts +2 -2
- package/dist/checker/queues.js +2 -2
- package/dist/checker/resolution.js +5 -3
- package/dist/checker/shared-state.d.ts +11 -0
- package/dist/checker/shared-state.js +37 -0
- package/dist/checker/signals.d.ts +8 -0
- package/dist/checker/signals.js +48 -0
- package/dist/checker/statements.d.ts +5 -2
- package/dist/checker/statements.js +51 -22
- package/dist/checker/tagged-unions.d.ts +37 -0
- package/dist/checker/tagged-unions.js +132 -0
- package/dist/checker/topics.d.ts +6 -0
- package/dist/checker/topics.js +17 -0
- package/dist/checker/transfer.d.ts +3 -1
- package/dist/checker/transfer.js +25 -5
- package/dist/checker/try.d.ts +6 -0
- package/dist/checker/try.js +19 -0
- package/dist/checker/types/constructors.d.ts +1 -1
- package/dist/checker/types/constructors.js +2 -2
- package/dist/checker/types/generics.js +1 -1
- package/dist/checker/types/iterables.d.ts +13 -0
- package/dist/checker/types/iterables.js +52 -0
- package/dist/checker/types/model.d.ts +25 -0
- package/dist/checker/types/params.js +22 -3
- package/dist/checker/types/printing.js +4 -3
- package/dist/checker/types/relations.js +19 -25
- package/dist/checker/types/topic.d.ts +6 -0
- package/dist/checker/types/topic.js +23 -0
- package/dist/checker/types.d.ts +2 -0
- package/dist/checker/types.js +2 -0
- package/dist/checker/untyped-globals.d.ts +1 -0
- package/dist/checker/untyped-globals.js +3 -1
- package/dist/cli.js +18 -36
- package/dist/codegen/attributes.d.ts +4 -0
- package/dist/codegen/attributes.js +24 -2
- package/dist/codegen/calls.d.ts +23 -0
- package/dist/codegen/calls.js +88 -7
- package/dist/codegen/component-helpers.d.ts +6 -1
- package/dist/codegen/component-helpers.js +6 -1
- package/dist/codegen/component-props.d.ts +11 -2
- package/dist/codegen/component-props.js +50 -5
- package/dist/codegen/components.d.ts +6 -5
- package/dist/codegen/components.js +44 -21
- package/dist/codegen/control-flow.d.ts +2 -0
- package/dist/codegen/control-flow.js +23 -9
- package/dist/codegen/control-statements.d.ts +10 -2
- package/dist/codegen/control-statements.js +56 -19
- package/dist/codegen/creation.js +5 -2
- package/dist/codegen/decode.d.ts +14 -0
- package/dist/codegen/decode.js +93 -0
- package/dist/codegen/early-returns.d.ts +4 -3
- package/dist/codegen/early-returns.js +17 -5
- package/dist/codegen/emitter.d.ts +13 -41
- package/dist/codegen/emitter.js +27 -8
- package/dist/codegen/expressions.d.ts +9 -0
- package/dist/codegen/expressions.js +15 -26
- package/dist/codegen/functions.d.ts +11 -1
- package/dist/codegen/functions.js +31 -3
- package/dist/codegen/js.d.ts +2 -2
- package/dist/codegen/js.js +5 -2
- package/dist/codegen/live.d.ts +60 -0
- package/dist/codegen/live.js +29 -0
- package/dist/codegen/mutations.d.ts +7 -0
- package/dist/codegen/mutations.js +43 -2
- package/dist/codegen/options.d.ts +42 -0
- package/dist/codegen/options.js +1 -0
- package/dist/codegen/reactive.d.ts +4 -59
- package/dist/codegen/reactive.js +34 -72
- package/dist/codegen/runtime.d.ts +7 -3
- package/dist/codegen/runtime.js +33 -14
- package/dist/codegen/shared.d.ts +22 -0
- package/dist/codegen/shared.js +93 -0
- package/dist/codegen/simple-statements.d.ts +11 -5
- package/dist/codegen/simple-statements.js +40 -15
- package/dist/codegen/statements.d.ts +5 -0
- package/dist/codegen/statements.js +99 -4
- package/dist/codegen/try.d.ts +5 -0
- package/dist/codegen/try.js +40 -0
- package/dist/codegen/updates.d.ts +11 -3
- package/dist/codegen/updates.js +52 -4
- package/dist/codegen/web-components.d.ts +2 -2
- package/dist/codegen/web-components.js +2 -2
- package/dist/compile.d.ts +9 -0
- package/dist/compile.js +25 -8
- package/dist/completion.d.ts +4 -2
- package/dist/completion.js +10 -5
- package/dist/declarations.js +32 -6
- package/dist/decorator-copy.d.ts +1 -1
- package/dist/decorator-copy.js +6 -2
- package/dist/decorator-names.d.ts +14 -0
- package/dist/decorator-names.js +56 -0
- package/dist/decorators.d.ts +2 -3
- package/dist/decorators.js +36 -14
- package/dist/goroutines.d.ts +1 -1
- package/dist/goroutines.js +5 -4
- package/dist/index.d.ts +6 -2
- package/dist/index.js +14 -5
- package/dist/inline-packages.d.ts +2 -1
- package/dist/inline-packages.js +9 -4
- package/dist/lexer/base.d.ts +2 -0
- package/dist/lexer/base.js +6 -1
- package/dist/lexer/lexer.js +3 -0
- package/dist/lexer/literals.d.ts +5 -0
- package/dist/lexer/literals.js +51 -1
- package/dist/lexer/markup.js +3 -4
- package/dist/lexer/tables.js +2 -0
- package/dist/lexer/token.d.ts +4 -3
- package/dist/lexer/token.js +0 -2
- package/dist/loader.js +30 -8
- package/dist/names.d.ts +4 -0
- package/dist/names.js +29 -0
- package/dist/parser/base.d.ts +5 -0
- package/dist/parser/base.js +2 -1
- package/dist/parser/classes.d.ts +2 -0
- package/dist/parser/classes.js +88 -23
- package/dist/parser/control-flow.d.ts +8 -1
- package/dist/parser/control-flow.js +49 -26
- package/dist/parser/declarations.d.ts +5 -12
- package/dist/parser/declarations.js +14 -79
- package/dist/parser/decorators.d.ts +6 -2
- package/dist/parser/decorators.js +43 -19
- package/dist/parser/expressions.js +27 -3
- package/dist/parser/jumps.d.ts +11 -0
- package/dist/parser/jumps.js +77 -0
- package/dist/parser/literals.d.ts +9 -0
- package/dist/parser/literals.js +45 -6
- package/dist/parser/markup.js +1 -1
- package/dist/parser/params.d.ts +21 -0
- package/dist/parser/params.js +143 -0
- package/dist/parser/simple-statements.d.ts +2 -1
- package/dist/parser/simple-statements.js +38 -15
- package/dist/parser/statements.d.ts +5 -5
- package/dist/parser/statements.js +39 -35
- package/dist/parser/syntax.d.ts +11 -1
- package/dist/parser/syntax.js +16 -2
- package/dist/parser/types.js +8 -3
- package/dist/project-modules.d.ts +12 -0
- package/dist/project-modules.js +106 -0
- package/dist/run-file.d.ts +6 -0
- package/dist/run-file.js +111 -0
- package/dist/runtime/sources.js +13 -6
- package/dist/source-map.d.ts +17 -0
- package/dist/source-map.js +75 -0
- package/dist/ts-types.js +4 -1
- package/dist/typescript/convert-objects.d.ts +2 -1
- package/dist/typescript/convert-objects.js +18 -9
- package/dist/vite.js +12 -4
- package/dist/walk-types.js +1 -0
- package/dist/walk.d.ts +0 -2
- package/dist/walk.js +14 -31
- package/package.json +2 -2
- package/src/runtime/chan.js +15 -5
- package/src/runtime/channel.js +28 -0
- package/src/runtime/classes.js +32 -0
- package/src/runtime/core.js +10 -1
- package/src/runtime/decode.js +221 -0
- package/src/runtime/go.js +3 -0
- package/src/runtime/index.js +7 -0
- package/src/runtime/markup.js +27 -17
- package/src/runtime/select.js +14 -9
- package/src/runtime/shared.js +17 -0
- package/src/runtime/signals.js +59 -0
- package/src/runtime/threads.js +32 -5
- package/src/runtime/topic.js +118 -0
- package/src/runtime/try.js +45 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { isIterator } from "../iterators.js";
|
|
2
|
+
import { sourceMark } from "../source-map.js";
|
|
2
3
|
import { holdsBigInts, TYPED_ARRAYS, TYPED_ELEMENTS } from "../typed-arrays.js";
|
|
3
4
|
import { declarationsOf } from "./analysis.js";
|
|
4
|
-
import {
|
|
5
|
+
import { TryEmitter } from "./try.js";
|
|
5
6
|
import { ARROW, arrayPattern, POSTFIX } from "./syntax.js";
|
|
6
7
|
/** Statements: lists and blocks of them, variables, assignments, `return`; the others are in later layers. */
|
|
7
|
-
export class SimpleStatementEmitter extends
|
|
8
|
+
export class SimpleStatementEmitter extends TryEmitter {
|
|
8
9
|
/** Counter for the labels of switches compiled to if/else. */
|
|
9
10
|
labels = 0;
|
|
10
11
|
statements(list) {
|
|
@@ -34,8 +35,34 @@ export class SimpleStatementEmitter extends CallEmitter {
|
|
|
34
35
|
blockStatement(node) {
|
|
35
36
|
return this.block(() => this.blockStatements(node.body));
|
|
36
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* The start of the statement being written, which its first line gets as a mark for the source
|
|
40
|
+
* map (source-map.ts). Imports have none, since the import of the runtime goes among them, and
|
|
41
|
+
* neither does the code of other modules, whose places are in their own sources.
|
|
42
|
+
*/
|
|
43
|
+
sourceMark = null;
|
|
37
44
|
statement(node) {
|
|
38
|
-
|
|
45
|
+
// A statement may write the statements inside it first, as a function writes its body before
|
|
46
|
+
// its first line: then the mark waits for that line.
|
|
47
|
+
const outer = this.sourceMark;
|
|
48
|
+
this.sourceMark =
|
|
49
|
+
node.kind === 'ImportDeclaration' || this.foreign.has(node) ? null : node.start;
|
|
50
|
+
try {
|
|
51
|
+
this.withHoisting(true, () => this.emitStatement(node));
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
this.sourceMark = outer;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// The marks of the updates of components stand alone in their lines (updates.ts).
|
|
58
|
+
line(text) {
|
|
59
|
+
if (this.sourceMark === null || text.startsWith('\uE000')) {
|
|
60
|
+
super.line(text);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const mark = sourceMark(this.sourceMark);
|
|
64
|
+
this.sourceMark = null;
|
|
65
|
+
super.line(mark + text);
|
|
39
66
|
}
|
|
40
67
|
emitStatement(node) {
|
|
41
68
|
switch (node.kind) {
|
|
@@ -115,18 +142,15 @@ export class SimpleStatementEmitter extends CallEmitter {
|
|
|
115
142
|
this.selectStatement(node);
|
|
116
143
|
break;
|
|
117
144
|
case 'SwitchStatement':
|
|
118
|
-
|
|
119
|
-
this.taglessSwitch(node);
|
|
120
|
-
else
|
|
121
|
-
this.switchStatement(node, node.discriminant);
|
|
145
|
+
this.switchStatement(node);
|
|
122
146
|
break;
|
|
123
147
|
case 'BreakStatement': {
|
|
124
|
-
const label = this.fn.breakTargets.at(-1);
|
|
148
|
+
const label = node.label ? this.label(node.label) : this.fn.breakTargets.at(-1);
|
|
125
149
|
this.line(label ? `break ${label};` : 'break;');
|
|
126
150
|
break;
|
|
127
151
|
}
|
|
128
152
|
case 'ContinueStatement':
|
|
129
|
-
this.line('continue;');
|
|
153
|
+
this.line(node.label ? `continue ${this.label(node.label)};` : 'continue;');
|
|
130
154
|
break;
|
|
131
155
|
case 'ThrowStatement':
|
|
132
156
|
this.line(`throw ${this.expression(node.argument, 0)};`);
|
|
@@ -137,12 +161,9 @@ export class SimpleStatementEmitter extends CallEmitter {
|
|
|
137
161
|
case 'DeferStatement':
|
|
138
162
|
this.deferStatement(node);
|
|
139
163
|
break;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const channel = this.expression(node.channel, ARROW);
|
|
143
|
-
this.line(`await $$send(${channel}, ${this.expression(node.value, ARROW)});`);
|
|
164
|
+
case 'SendStatement':
|
|
165
|
+
this.line(`${this.send(node)};`);
|
|
144
166
|
break;
|
|
145
|
-
}
|
|
146
167
|
case 'MountStatement':
|
|
147
168
|
this.mountStatement(node);
|
|
148
169
|
break;
|
|
@@ -192,9 +213,13 @@ export class SimpleStatementEmitter extends CallEmitter {
|
|
|
192
213
|
// An empty queue, as `[]` is an empty array.
|
|
193
214
|
case 'QueueType':
|
|
194
215
|
return 'new $$Queue()';
|
|
216
|
+
// Closed, the same for all types: what is sent to them goes nowhere.
|
|
217
|
+
case 'ChanType':
|
|
218
|
+
return '$$Channel.EMPTY';
|
|
219
|
+
case 'TopicType':
|
|
220
|
+
return '$$Topic.EMPTY';
|
|
195
221
|
case 'FuncType':
|
|
196
222
|
case 'ComponentType':
|
|
197
|
-
case 'ChanType':
|
|
198
223
|
case 'ObjectType':
|
|
199
224
|
case 'UnionType':
|
|
200
225
|
case 'LiteralType':
|
|
@@ -9,6 +9,11 @@ import { ParallelLoopEmitter } from './parallel.ts';
|
|
|
9
9
|
export declare abstract class StatementEmitter extends ParallelLoopEmitter {
|
|
10
10
|
/** A CSS module: its object and CSS go with the styles (StyleEmitter), not to an import. */
|
|
11
11
|
protected abstract styleModuleImport(node: ast.ImportDeclaration): boolean;
|
|
12
|
+
private sharedReads;
|
|
13
|
+
/** State of the module: the updates of the components that read it are kept beside it. */
|
|
14
|
+
protected emitStatement(node: ast.Statement): void;
|
|
15
|
+
/** Whether the components or decorators of the module read `name`, and so listen to it. */
|
|
16
|
+
protected readsShared(name: string): boolean;
|
|
12
17
|
protected importDeclaration(node: ast.ImportDeclaration): void;
|
|
13
18
|
/**
|
|
14
19
|
* `export { log as $$visible$log }`: the names of the module that the code of exported
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { isSuperCall } from "../checker/helpers.js";
|
|
1
2
|
import { isIterator } from "../iterators.js";
|
|
2
3
|
import { decoratedName, moduleNamesOf } from "../decorators.js";
|
|
3
4
|
import { inlinePackages } from "../inline-packages.js";
|
|
4
5
|
import { packageExports } from "./imported.js";
|
|
6
|
+
import { readNames } from "./mutations.js";
|
|
5
7
|
import { ParallelLoopEmitter } from "./parallel.js";
|
|
8
|
+
import { listenersName } from "./shared.js";
|
|
6
9
|
import { ARROW, POSTFIX } from "./syntax.js";
|
|
7
10
|
/**
|
|
8
11
|
* Imports and classes; with the layers below, all statements and declarations. A decorator of
|
|
@@ -11,12 +14,42 @@ import { ARROW, POSTFIX } from "./syntax.js";
|
|
|
11
14
|
* So does an inlined component of another module; a called one brings its function, `$$Card`.
|
|
12
15
|
*/
|
|
13
16
|
export class StatementEmitter extends ParallelLoopEmitter {
|
|
17
|
+
sharedReads = null;
|
|
18
|
+
/** State of the module: the updates of the components that read it are kept beside it. */
|
|
19
|
+
emitStatement(node) {
|
|
20
|
+
super.emitStatement(node);
|
|
21
|
+
if (node.kind !== 'VariableDeclaration' || node.keyword !== 'state')
|
|
22
|
+
return;
|
|
23
|
+
if (!this.program.body.includes(node))
|
|
24
|
+
return;
|
|
25
|
+
const exported = node.exported ? 'export ' : '';
|
|
26
|
+
for (const name of node.names) {
|
|
27
|
+
const listeners = this.shared.listeners.get(name.name);
|
|
28
|
+
if (listeners)
|
|
29
|
+
this.line(`${exported}const ${listeners} = new Set();`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Whether the components or decorators of the module read `name`, and so listen to it. */
|
|
33
|
+
readsShared(name) {
|
|
34
|
+
if (!this.sharedReads) {
|
|
35
|
+
this.sharedReads = new Set();
|
|
36
|
+
for (const statement of this.program.body) {
|
|
37
|
+
if (statement.kind === 'ComponentDeclaration' ||
|
|
38
|
+
statement.kind === 'DecoratorDeclaration') {
|
|
39
|
+
readNames(statement, this.sharedReads);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return this.sharedReads.has(name);
|
|
44
|
+
}
|
|
14
45
|
importDeclaration(node) {
|
|
15
46
|
if (this.styleModuleImport(node))
|
|
16
47
|
return;
|
|
17
48
|
// Imports used only as types (e.g. interfaces) do not exist at runtime, and neither do
|
|
18
49
|
// components: a component used as a value is its function, imported below.
|
|
19
|
-
|
|
50
|
+
// A data class, even used only as a type, registers itself where it is imported.
|
|
51
|
+
const used = (name) => (this.valueNames.has(name.name) || this.options.dataClasses?.has(name.name) === true) &&
|
|
52
|
+
!this.options.components?.has(name.name);
|
|
20
53
|
const clauses = [];
|
|
21
54
|
if (node.defaultImport && used(node.defaultImport)) {
|
|
22
55
|
clauses.push(this.name(node.defaultImport.name));
|
|
@@ -33,6 +66,11 @@ export class StatementEmitter extends ParallelLoopEmitter {
|
|
|
33
66
|
const hidden = (exported, local) => named.push(exported === local ? exported : `${exported} as ${local}`);
|
|
34
67
|
for (const specifier of node.namedImports) {
|
|
35
68
|
const component = this.options.components?.get(specifier.local.name);
|
|
69
|
+
const state = this.options.shared?.get(specifier.local.name);
|
|
70
|
+
// State of that module: the components here that read it listen to its changes.
|
|
71
|
+
if (state !== undefined && this.readsShared(specifier.local.name)) {
|
|
72
|
+
hidden(listenersName(state), this.shared.listeners.get(specifier.local.name));
|
|
73
|
+
}
|
|
36
74
|
const inlined = this.inlinedImports.get(specifier.local.name);
|
|
37
75
|
if (inlined) {
|
|
38
76
|
for (const [exported, local] of inlined.imports)
|
|
@@ -100,7 +138,10 @@ export class StatementEmitter extends ParallelLoopEmitter {
|
|
|
100
138
|
: '';
|
|
101
139
|
const body = this.block(() => {
|
|
102
140
|
let previous;
|
|
141
|
+
// An abstract method has no code: only the subclasses have it.
|
|
103
142
|
for (const member of node.members) {
|
|
143
|
+
if (member.kind === 'MethodDeclaration' && member.abstract)
|
|
144
|
+
continue;
|
|
104
145
|
const bothFields = previous?.kind === 'FieldDeclaration' && member.kind === 'FieldDeclaration';
|
|
105
146
|
if (previous && (!bothFields || this.blankLineBetween(previous, member)))
|
|
106
147
|
this.blankLine();
|
|
@@ -109,6 +150,12 @@ export class StatementEmitter extends ParallelLoopEmitter {
|
|
|
109
150
|
}
|
|
110
151
|
});
|
|
111
152
|
this.line(`${exported}class ${this.name(node.name.name)}${superClass} ${body}`);
|
|
153
|
+
// A data class is registered, so that its instances get it back in another thread
|
|
154
|
+
// (runtime/classes.js); the id is the same in the worker module, which has a copy of it.
|
|
155
|
+
if (node.data) {
|
|
156
|
+
const id = `${node.name.name}:${hash(this.options.source.slice(node.start, node.end))}`;
|
|
157
|
+
this.line(`$$dataClass(${this.name(node.name.name)}, ${JSON.stringify(id)});`);
|
|
158
|
+
}
|
|
112
159
|
}
|
|
113
160
|
/** Visibility modifiers are checked by the compiler and do not exist in the output. */
|
|
114
161
|
classMember(member) {
|
|
@@ -126,17 +173,65 @@ export class StatementEmitter extends ParallelLoopEmitter {
|
|
|
126
173
|
break;
|
|
127
174
|
}
|
|
128
175
|
case 'ConstructorDeclaration': {
|
|
129
|
-
const [params, body] = this.func(member.params, member
|
|
176
|
+
const [params, body] = this.func(member.params, assignProperties(member));
|
|
130
177
|
this.line(`constructor(${params}) ${body}`);
|
|
131
178
|
break;
|
|
132
179
|
}
|
|
133
180
|
case 'MethodDeclaration': {
|
|
181
|
+
if (!member.body)
|
|
182
|
+
break;
|
|
134
183
|
const [params, body] = this.func(member.params, member.body);
|
|
135
|
-
const modifiers = `${member.isStatic ? 'static ' : ''}${member.async ? 'async ' : ''}
|
|
136
|
-
|
|
184
|
+
const modifiers = `${member.isStatic ? 'static ' : ''}${member.async ? 'async ' : ''}` +
|
|
185
|
+
(member.accessor ? `${member.accessor} ` : '');
|
|
186
|
+
const star = isIterator(member.params) && !member.accessor ? '*' : '';
|
|
137
187
|
this.line(`${modifiers}${star}${member.name.name}(${params}) ${body}`);
|
|
138
188
|
break;
|
|
139
189
|
}
|
|
140
190
|
}
|
|
141
191
|
}
|
|
142
192
|
}
|
|
193
|
+
/**
|
|
194
|
+
* The body of a constructor whose parameters are properties, `constructor(private name string)`:
|
|
195
|
+
* it assigns them first, `this.name = name`, or right after `super(...)` in a derived class.
|
|
196
|
+
*/
|
|
197
|
+
function assignProperties(node) {
|
|
198
|
+
const assignments = node.params.flatMap((param) => {
|
|
199
|
+
if (!param.property)
|
|
200
|
+
return [];
|
|
201
|
+
const at = { start: param.start, end: param.end };
|
|
202
|
+
const self = { kind: 'ThisExpression', ...at };
|
|
203
|
+
const target = {
|
|
204
|
+
kind: 'MemberExpression',
|
|
205
|
+
object: self,
|
|
206
|
+
property: param.name,
|
|
207
|
+
optional: false,
|
|
208
|
+
...at,
|
|
209
|
+
};
|
|
210
|
+
return [
|
|
211
|
+
{
|
|
212
|
+
kind: 'AssignmentStatement',
|
|
213
|
+
operator: '=',
|
|
214
|
+
targets: [target],
|
|
215
|
+
values: [param.name],
|
|
216
|
+
...at,
|
|
217
|
+
},
|
|
218
|
+
];
|
|
219
|
+
});
|
|
220
|
+
if (assignments.length === 0)
|
|
221
|
+
return node.body;
|
|
222
|
+
const statements = node.body.body;
|
|
223
|
+
const after = statements.findIndex(isSuperCall) + 1;
|
|
224
|
+
return {
|
|
225
|
+
...node.body,
|
|
226
|
+
body: [...statements.slice(0, after), ...assignments, ...statements.slice(after)],
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
/** FNV-1a of a text, as 8 hex digits: an id that changes only with the text. */
|
|
230
|
+
function hash(text) {
|
|
231
|
+
let value = 0x811c9dc5;
|
|
232
|
+
for (let i = 0; i < text.length; i++) {
|
|
233
|
+
value ^= text.charCodeAt(i);
|
|
234
|
+
value = Math.imul(value, 0x01000193) >>> 0;
|
|
235
|
+
}
|
|
236
|
+
return value.toString(16).padStart(8, '0');
|
|
237
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { isErrorType } from "../checker/error-results.js";
|
|
2
|
+
import { forEachChild } from "../walk.js";
|
|
3
|
+
import { startsWithObjectLiteral } from "./analysis.js";
|
|
4
|
+
import { DecodeEmitter } from "./decode.js";
|
|
5
|
+
import { ARROW, POSTFIX, UNARY } from "./syntax.js";
|
|
6
|
+
// `try expr`: the expression runs in a function that the runtime calls inside try/catch
|
|
7
|
+
// (runtime/try.js), `$$catch(() => JSON.parse(text))`. One that waits is an async function, whose
|
|
8
|
+
// rejected Promise is caught as well: `await $$catchAsync(async () => await fetch(url))`. The runtime
|
|
9
|
+
// is told how many values the expression gives, and whether the last of them is an error already.
|
|
10
|
+
export class TryEmitter extends DecodeEmitter {
|
|
11
|
+
tryValue(node) {
|
|
12
|
+
// The expression may not run to the end, so it creates no elements in advance.
|
|
13
|
+
const code = this.withHoisting(false, () => this.expression(node.argument, ARROW));
|
|
14
|
+
const body = startsWithObjectLiteral(node.argument) ? `(${code})` : code;
|
|
15
|
+
const type = this.options.types?.get(node.argument);
|
|
16
|
+
let results = '';
|
|
17
|
+
if (type?.kind === 'void' || (type !== undefined && isErrorType(type))) {
|
|
18
|
+
results = type.kind === 'void' ? ', 0' : ', 1, true';
|
|
19
|
+
}
|
|
20
|
+
else if (type?.kind === 'tuple') {
|
|
21
|
+
results = `, ${type.types.length}${isErrorType(type.types.at(-1)) ? ', true' : ''}`;
|
|
22
|
+
}
|
|
23
|
+
return waits(node.argument)
|
|
24
|
+
? [`await $$catchAsync(async () => ${body}${results})`, UNARY]
|
|
25
|
+
: [`$$catch(() => ${body}${results})`, POSTFIX];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** Whether the expression waits, with `await` or `<-`, outside the functions in it. */
|
|
29
|
+
function waits(node) {
|
|
30
|
+
if (node.kind === 'UnaryExpression' && (node.operator === 'await' || node.operator === '<-')) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
if (node.kind === 'FuncExpression' || node.kind === 'ArrowFunction')
|
|
34
|
+
return false;
|
|
35
|
+
let found = false;
|
|
36
|
+
forEachChild(node, (child) => {
|
|
37
|
+
found ||= waits(child);
|
|
38
|
+
});
|
|
39
|
+
return found;
|
|
40
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type * as ast from '../ast.ts';
|
|
2
2
|
import { type Type } from '../checker/types.ts';
|
|
3
|
-
import type
|
|
3
|
+
import { type Reactive, type Source, type Write } from './reactive.ts';
|
|
4
4
|
import { StatementEmitter } from './statements.ts';
|
|
5
5
|
/**
|
|
6
6
|
* Updates after changes of component state. Each state variable gets an update function; every
|
|
@@ -19,8 +19,13 @@ export declare abstract class UpdateEmitter extends StatementEmitter {
|
|
|
19
19
|
* the markup, which would update it again; code that runs later (handlers) is not included.
|
|
20
20
|
*/
|
|
21
21
|
protected rendering: number;
|
|
22
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* After a statement that changes state of the module, the updates of the components that read
|
|
24
|
+
* it; code that renders markup changes none, as with the state of a component.
|
|
25
|
+
*/
|
|
23
26
|
protected statement(node: ast.Statement): void;
|
|
27
|
+
/** After a statement that changes state, the update of what depends on it. */
|
|
28
|
+
private statementWithUpdates;
|
|
24
29
|
protected changesState(body: ast.Expression): boolean;
|
|
25
30
|
protected withRendering<T>(rendering: number, emit: () => T): T;
|
|
26
31
|
/** Records a place that changes a source and returns its marker; see resolveMarkers. */
|
|
@@ -45,7 +50,10 @@ export declare abstract class UpdateEmitter extends StatementEmitter {
|
|
|
45
50
|
* update statement, or by nothing when no markup depends on the source.
|
|
46
51
|
*/
|
|
47
52
|
export declare function resolveMarkers(block: string, reactive: Reactive): string;
|
|
48
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* The update statements that a place changing the source needs: the computations, the call that
|
|
55
|
+
* gives a bound property to the parent, then the updates of the nodes.
|
|
56
|
+
*/
|
|
49
57
|
export declare function needed(source: Source, write: Write): string[];
|
|
50
58
|
/** One place changes the source, after the markup exists, and needs one update statement. */
|
|
51
59
|
export declare function inlinesUpdate(source: Source): boolean;
|
package/dist/codegen/updates.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { widenLiterals } from "../checker/types.js";
|
|
2
|
+
import { updatesOf } from "./reactive.js";
|
|
2
3
|
import { StatementEmitter } from "./statements.js";
|
|
3
4
|
import { startsWithObjectLiteral } from "./analysis.js";
|
|
5
|
+
import { sharedWrites } from "./shared.js";
|
|
4
6
|
import { ARROW } from "./syntax.js";
|
|
5
7
|
/**
|
|
6
8
|
* Updates after changes of component state. Each state variable gets an update function; every
|
|
@@ -19,8 +21,37 @@ export class UpdateEmitter extends StatementEmitter {
|
|
|
19
21
|
* the markup, which would update it again; code that runs later (handlers) is not included.
|
|
20
22
|
*/
|
|
21
23
|
rendering = 0;
|
|
22
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* After a statement that changes state of the module, the updates of the components that read
|
|
26
|
+
* it; code that renders markup changes none, as with the state of a component.
|
|
27
|
+
*/
|
|
23
28
|
statement(node) {
|
|
29
|
+
const shared = this.rendering > 0 ? [] : sharedWrites(node, this.shared, (each) => this.typeOf(each));
|
|
30
|
+
if (shared.length === 0) {
|
|
31
|
+
this.statementWithUpdates(node);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const notify = () => {
|
|
35
|
+
for (const name of shared)
|
|
36
|
+
this.line(`$$changed(${this.shared.listeners.get(name)});`);
|
|
37
|
+
};
|
|
38
|
+
if (node.kind !== 'ReturnStatement' && node.kind !== 'ThrowStatement') {
|
|
39
|
+
this.statementWithUpdates(node);
|
|
40
|
+
notify();
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// The value is computed first, then the updates run, then the function leaves.
|
|
44
|
+
const values = node.kind === 'ThrowStatement' ? [node.argument] : node.values;
|
|
45
|
+
const temp = this.temp();
|
|
46
|
+
this.withHoisting(true, () => {
|
|
47
|
+
const rendered = values.map((value) => this.expression(value, ARROW));
|
|
48
|
+
this.line(`const ${temp} = ${rendered.length === 1 ? rendered[0] : `[${rendered.join(', ')}]`};`);
|
|
49
|
+
});
|
|
50
|
+
notify();
|
|
51
|
+
this.line(`${node.kind === 'ThrowStatement' ? 'throw' : 'return'} ${temp};`);
|
|
52
|
+
}
|
|
53
|
+
/** After a statement that changes state, the update of what depends on it. */
|
|
54
|
+
statementWithUpdates(node) {
|
|
24
55
|
const { reactive } = this;
|
|
25
56
|
if (reactive && this.fn === reactive.setup && reactive.declaresRenderFunction(node)) {
|
|
26
57
|
this.withRendering(this.rendering + 1, () => super.statement(node));
|
|
@@ -33,6 +64,9 @@ export class UpdateEmitter extends StatementEmitter {
|
|
|
33
64
|
for (const source of changed) {
|
|
34
65
|
for (const computation of source.computations)
|
|
35
66
|
this.line(computation);
|
|
67
|
+
// The parent of a bound property gets the value the body gave it.
|
|
68
|
+
if (source.bound)
|
|
69
|
+
this.line(source.bound);
|
|
36
70
|
}
|
|
37
71
|
return;
|
|
38
72
|
}
|
|
@@ -137,7 +171,14 @@ export function resolveMarkers(block, reactive) {
|
|
|
137
171
|
const sources = new Map();
|
|
138
172
|
for (const source of reactive.sources.values())
|
|
139
173
|
sources.set(source.id, source);
|
|
140
|
-
|
|
174
|
+
// `$$watch(...)` of state of the module stays if something depends on it.
|
|
175
|
+
const listened = block.replace(/^([ \t]*)\uE004(\d+)\uE004(.*)\n/gm, (line, indent, id, text) => {
|
|
176
|
+
const source = sources.get(Number(id));
|
|
177
|
+
if (!source)
|
|
178
|
+
return line;
|
|
179
|
+
return updatesOf(source).length > 0 ? `${indent}${text}\n` : '';
|
|
180
|
+
});
|
|
181
|
+
return listened.replace(/^([ \t]*)\uE000(\d+)(?::(\d+))?\uE001;\n/gm, (line, indent, id, skip) => {
|
|
141
182
|
const source = sources.get(Number(id));
|
|
142
183
|
if (!source)
|
|
143
184
|
return line;
|
|
@@ -148,9 +189,16 @@ export function resolveMarkers(block, reactive) {
|
|
|
148
189
|
return `${indent}${text}\n`;
|
|
149
190
|
});
|
|
150
191
|
}
|
|
151
|
-
/**
|
|
192
|
+
/**
|
|
193
|
+
* The update statements that a place changing the source needs: the computations, the call that
|
|
194
|
+
* gives a bound property to the parent, then the updates of the nodes.
|
|
195
|
+
*/
|
|
152
196
|
export function needed(source, write) {
|
|
153
|
-
return [
|
|
197
|
+
return [
|
|
198
|
+
...source.computations,
|
|
199
|
+
...(source.bound ? [source.bound] : []),
|
|
200
|
+
...source.dependents.filter((_, i) => i !== write.skip),
|
|
201
|
+
];
|
|
154
202
|
}
|
|
155
203
|
/** One place changes the source, after the markup exists, and needs one update statement. */
|
|
156
204
|
export function inlinesUpdate(source) {
|
|
@@ -6,8 +6,8 @@ import { ComponentEmitter } from './components.ts';
|
|
|
6
6
|
* have their values.
|
|
7
7
|
*
|
|
8
8
|
* The element renders the component into its shadow root when it is connected. When it is
|
|
9
|
-
* disconnected and not put back in the same task, the component is removed:
|
|
10
|
-
*
|
|
9
|
+
* disconnected and not put back in the same task, the component is removed: what its
|
|
10
|
+
* `mount` deferred runs. Moving the element keeps its markup.
|
|
11
11
|
*
|
|
12
12
|
* Every property except `children` is a JS property of the element; its setter updates the markup.
|
|
13
13
|
* Strings, numbers and bools also have attributes: `item-count="3"` sets `itemCount` to 3, and a
|
|
@@ -6,8 +6,8 @@ import { ComponentEmitter } from "./components.js";
|
|
|
6
6
|
* have their values.
|
|
7
7
|
*
|
|
8
8
|
* The element renders the component into its shadow root when it is connected. When it is
|
|
9
|
-
* disconnected and not put back in the same task, the component is removed:
|
|
10
|
-
*
|
|
9
|
+
* disconnected and not put back in the same task, the component is removed: what its
|
|
10
|
+
* `mount` deferred runs. Moving the element keeps its markup.
|
|
11
11
|
*
|
|
12
12
|
* Every property except `children` is a JS property of the element; its setter updates the markup.
|
|
13
13
|
* Strings, numbers and bools also have attributes: `item-count="3"` sets `itemCount` to 3, and a
|
package/dist/compile.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type * as ast from './ast.ts';
|
|
|
2
2
|
import { type CheckOptions, type ImportResult, type Library } from './checker/checker.ts';
|
|
3
3
|
import type { RuntimeMode } from './codegen/runtime.ts';
|
|
4
4
|
import type { Diagnostic } from './diagnostics.ts';
|
|
5
|
+
import { type SourceMap } from './source-map.ts';
|
|
5
6
|
import { type StyleModule } from './style-modules.ts';
|
|
6
7
|
export interface CoreCompileOptions {
|
|
7
8
|
/** Replace `.rk` with `.js` in relative import paths. Defaults to `true`. */
|
|
@@ -22,12 +23,16 @@ export interface CoreCompileOptions {
|
|
|
22
23
|
readStyleModule?: ((specifier: string) => string | null) | undefined;
|
|
23
24
|
/** Where the worker module of `go` is, relative to the module; see workerUrl(). */
|
|
24
25
|
workerUrl?: string | undefined;
|
|
26
|
+
/** A module that a worker thread of Node imports first, to load `.rk` files (vite.ts). */
|
|
27
|
+
nodeLoader?: string | undefined;
|
|
25
28
|
/**
|
|
26
29
|
* How the code gets the runtime of Rook: `import`, the default, imports it from
|
|
27
30
|
* "rooklang/runtime"; `inline` puts the parts it uses into the module, for code that runs
|
|
28
31
|
* without imports (src/codegen/runtime.ts).
|
|
29
32
|
*/
|
|
30
33
|
runtime?: RuntimeMode | undefined;
|
|
34
|
+
/** The name of the source in the source maps, `app.rk`. */
|
|
35
|
+
sourceName?: string | undefined;
|
|
31
36
|
}
|
|
32
37
|
/**
|
|
33
38
|
* Where the worker module of a module is: a `.worker.js` next to its `.js`, or, where `.rk`
|
|
@@ -45,6 +50,10 @@ export interface CompileResult {
|
|
|
45
50
|
dependencies: string[];
|
|
46
51
|
/** The `.d.ts` for the module, with the `declarations` option. */
|
|
47
52
|
declarations?: string;
|
|
53
|
+
/** Where the lines of `code` come from in the source, when there is code. */
|
|
54
|
+
map?: SourceMap;
|
|
55
|
+
/** That of the worker module. */
|
|
56
|
+
workerMap?: SourceMap;
|
|
48
57
|
/** The worker module that runs the functions `go` calls, when the module has `go`. */
|
|
49
58
|
worker?: string;
|
|
50
59
|
}
|
package/dist/compile.js
CHANGED
|
@@ -3,6 +3,7 @@ import { property, STRING } from "./checker/types.js";
|
|
|
3
3
|
import { generateJs } from "./codegen/js.js";
|
|
4
4
|
import { printDeclarations } from "./declarations.js";
|
|
5
5
|
import { goroutines, goTarget, workerProgram } from "./goroutines.js";
|
|
6
|
+
import { withoutMarks } from "./source-map.js";
|
|
6
7
|
import { parse } from "./parser/parser.js";
|
|
7
8
|
import { isStyleModule, styleModule, unusedClasses } from "./style-modules.js";
|
|
8
9
|
/**
|
|
@@ -24,6 +25,8 @@ export function compileModule(source, options = {}) {
|
|
|
24
25
|
return { code: '', diagnostics: problems, warnings: [], dependencies };
|
|
25
26
|
let types;
|
|
26
27
|
let declarations;
|
|
28
|
+
// Without the checker, only the data classes that the module declares are known.
|
|
29
|
+
let dataClasses = new Set(program.body.flatMap((each) => each.kind === 'ClassDeclaration' && each.data ? [each.name.name] : []));
|
|
27
30
|
let warnings = [];
|
|
28
31
|
if (options.typeCheck ?? true) {
|
|
29
32
|
const checked = check(program, checkOptions);
|
|
@@ -32,6 +35,7 @@ export function compileModule(source, options = {}) {
|
|
|
32
35
|
return { code: '', diagnostics: checked.diagnostics, warnings, dependencies };
|
|
33
36
|
}
|
|
34
37
|
types = checked.types;
|
|
38
|
+
dataClasses = checked.dataClasses;
|
|
35
39
|
if (options.declarations)
|
|
36
40
|
declarations = printDeclarations(program, checked);
|
|
37
41
|
}
|
|
@@ -42,25 +46,34 @@ export function compileModule(source, options = {}) {
|
|
|
42
46
|
types,
|
|
43
47
|
styleModules,
|
|
44
48
|
runtime: options.runtime,
|
|
49
|
+
dataClasses,
|
|
45
50
|
...importedCode(program, options.importModule),
|
|
46
51
|
};
|
|
47
|
-
const
|
|
52
|
+
const sourceName = options.sourceName ?? 'main.rk';
|
|
53
|
+
const main = withoutMarks(generateJs(program, {
|
|
48
54
|
...jsOptions,
|
|
49
|
-
goroutines: {
|
|
50
|
-
|
|
55
|
+
goroutines: {
|
|
56
|
+
workerUrl: options.workerUrl ?? workerUrl('main.rk', rewriteImports),
|
|
57
|
+
nodeLoader: options.nodeLoader,
|
|
58
|
+
},
|
|
59
|
+
}), source, sourceName);
|
|
51
60
|
const targets = [
|
|
52
61
|
...new Set(goroutines(program).flatMap((node) => goTarget(program, node) ?? [])),
|
|
53
62
|
];
|
|
54
63
|
const worker = targets.length > 0
|
|
55
|
-
? generateJs(workerProgram(program, targets
|
|
64
|
+
? withoutMarks(generateJs(workerProgram(program, targets, dataClasses), {
|
|
65
|
+
...jsOptions,
|
|
66
|
+
goroutines: { targets },
|
|
67
|
+
}), source, sourceName)
|
|
56
68
|
: undefined;
|
|
57
69
|
return {
|
|
58
|
-
code,
|
|
70
|
+
code: main.code,
|
|
59
71
|
diagnostics: [],
|
|
60
72
|
warnings,
|
|
61
73
|
dependencies,
|
|
62
74
|
...(declarations ? { declarations } : {}),
|
|
63
|
-
|
|
75
|
+
map: main.map,
|
|
76
|
+
...(worker === undefined ? {} : { worker: worker.code, workerMap: worker.map }),
|
|
64
77
|
};
|
|
65
78
|
}
|
|
66
79
|
/**
|
|
@@ -89,11 +102,12 @@ export function prepareCheck(program, options) {
|
|
|
89
102
|
}
|
|
90
103
|
/**
|
|
91
104
|
* What the module imports from other `.rk` modules for the generator: decorators, whose code is
|
|
92
|
-
* inlined,
|
|
105
|
+
* inlined, components, which are called or inlined, and state, whose changes it listens to.
|
|
93
106
|
*/
|
|
94
107
|
function importedCode(program, importModule) {
|
|
95
108
|
const found = new Map();
|
|
96
109
|
const components = new Map();
|
|
110
|
+
const shared = new Map();
|
|
97
111
|
for (const statement of program.body) {
|
|
98
112
|
if (statement.kind !== 'ImportDeclaration' || !statement.source.value.endsWith('.rk')) {
|
|
99
113
|
continue;
|
|
@@ -103,6 +117,9 @@ function importedCode(program, importModule) {
|
|
|
103
117
|
const decorators = exports?.decorators;
|
|
104
118
|
for (const specifier of statement.namedImports) {
|
|
105
119
|
const component = exports?.components?.get(specifier.imported.name);
|
|
120
|
+
if (exports?.shared?.has(specifier.imported.name)) {
|
|
121
|
+
shared.set(specifier.local.name, specifier.imported.name);
|
|
122
|
+
}
|
|
106
123
|
if (component) {
|
|
107
124
|
components.set(specifier.local.name, {
|
|
108
125
|
node: component.node,
|
|
@@ -122,7 +139,7 @@ function importedCode(program, importModule) {
|
|
|
122
139
|
});
|
|
123
140
|
}
|
|
124
141
|
}
|
|
125
|
-
return { decorators: found, components };
|
|
142
|
+
return { decorators: found, components, shared };
|
|
126
143
|
}
|
|
127
144
|
/** The CSS modules that the program imports, read and parsed, or what is wrong with them. */
|
|
128
145
|
function readStyleModules(program, read) {
|
package/dist/completion.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { type Completion } from './checker/checker.ts';
|
|
1
|
+
import { type Completion, type CompletionContext } from './checker/checker.ts';
|
|
2
2
|
import { type CoreCompileOptions } from './compile.ts';
|
|
3
|
-
export type { Completion, CompletionContext } from './checker/checker.ts';
|
|
3
|
+
export type { Completion, CompletionContext, TextEdit } from './checker/checker.ts';
|
|
4
4
|
export interface CompletionList {
|
|
5
5
|
/** Offsets of what the chosen item replaces: the part of the name before the cursor. */
|
|
6
6
|
start: number;
|
|
7
7
|
end: number;
|
|
8
|
+
/** What the cursor is in; none where nothing is suggested or the check did not reach it. */
|
|
9
|
+
context?: CompletionContext;
|
|
8
10
|
items: Completion[];
|
|
9
11
|
}
|
|
10
12
|
export declare function completeModule(source: string, offset: number, options?: CoreCompileOptions): CompletionList;
|
package/dist/completion.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { check } from "./checker/checker.js";
|
|
1
|
+
import { check, } from "./checker/checker.js";
|
|
2
2
|
import { prepareCheck } from "./compile.js";
|
|
3
3
|
import { tokenize } from "./lexer/lexer.js";
|
|
4
4
|
import { KEYWORDS } from "./lexer/token.js";
|
|
5
5
|
import { parse } from "./parser/parser.js";
|
|
6
|
-
import { RESERVED } from "./parser/syntax.js";
|
|
7
6
|
import { forEachChild } from "./walk.js";
|
|
8
7
|
const CURSOR = '$$cursor';
|
|
9
8
|
const STRINGS = new Set([
|
|
@@ -15,10 +14,11 @@ const STRINGS = new Set([
|
|
|
15
14
|
'JsxText',
|
|
16
15
|
'JsxString',
|
|
17
16
|
'CssText',
|
|
17
|
+
'RegExp',
|
|
18
18
|
]);
|
|
19
|
-
const VALUE_KEYWORDS = KEYWORDS
|
|
19
|
+
const VALUE_KEYWORDS = KEYWORDS;
|
|
20
20
|
// `queue` is a type of its own only in a type: elsewhere it is a name.
|
|
21
|
-
const TYPE_KEYWORDS = ['func', 'comp', 'chan', 'queue'];
|
|
21
|
+
const TYPE_KEYWORDS = ['func', 'comp', 'chan', 'queue', 'topic'];
|
|
22
22
|
/** Keywords only at the start of a statement at the top level of a component or a decorator. */
|
|
23
23
|
const COMPONENT_KEYWORDS = ['state', 'derived', 'ref', 'style', 'effect', 'mount'];
|
|
24
24
|
export function completeModule(source, offset, options = {}) {
|
|
@@ -55,7 +55,12 @@ export function completeModule(source, offset, options = {}) {
|
|
|
55
55
|
const { program } = parse(text, { markup: options.markup ?? true });
|
|
56
56
|
const result = completeIn(program, options);
|
|
57
57
|
if (result) {
|
|
58
|
-
return {
|
|
58
|
+
return {
|
|
59
|
+
start,
|
|
60
|
+
end: offset,
|
|
61
|
+
context: result.context,
|
|
62
|
+
items: withKeywords(result, statementKeywords(program)),
|
|
63
|
+
};
|
|
59
64
|
}
|
|
60
65
|
// The cursor is where a name is declared, `let ti|`: nothing to suggest.
|
|
61
66
|
if (pathTo(program, CURSOR).length > 0)
|