rooklang 0.3.2 → 0.3.4
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 +32 -7
- package/README.ru.md +32 -7
- package/dist/ast/declarations.d.ts +20 -1
- package/dist/ast/expressions.d.ts +31 -1
- package/dist/ast/markup.d.ts +6 -1
- package/dist/ast/statements.d.ts +25 -1
- 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 +7 -0
- package/dist/checker/assignments.js +48 -8
- package/dist/checker/base.d.ts +2 -1
- package/dist/checker/base.js +6 -12
- package/dist/checker/builtins.js +15 -5
- 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 +16 -2
- 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 +41 -12
- package/dist/checker/closing.d.ts +21 -0
- package/dist/checker/closing.js +164 -0
- package/dist/checker/completion.d.ts +2 -2
- package/dist/checker/completion.js +2 -2
- package/dist/checker/context.d.ts +19 -0
- package/dist/checker/control-flow.d.ts +6 -0
- package/dist/checker/control-flow.js +34 -0
- package/dist/checker/declarations.js +1 -0
- package/dist/checker/decode.d.ts +8 -0
- package/dist/checker/decode.js +32 -0
- package/dist/checker/error-results.d.ts +6 -0
- package/dist/checker/error-results.js +31 -0
- package/dist/checker/expressions.d.ts +5 -1
- package/dist/checker/expressions.js +13 -34
- package/dist/checker/flow.js +8 -4
- package/dist/checker/helpers.d.ts +1 -1
- package/dist/checker/helpers.js +9 -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.js +23 -3
- package/dist/checker/members.js +7 -0
- 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/signals.d.ts +8 -0
- package/dist/checker/signals.js +48 -0
- package/dist/checker/statements.d.ts +5 -0
- package/dist/checker/statements.js +19 -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/cli.js +18 -36
- package/dist/codegen/calls.d.ts +23 -0
- package/dist/codegen/calls.js +88 -7
- package/dist/codegen/control-statements.d.ts +19 -3
- package/dist/codegen/control-statements.js +105 -20
- package/dist/codegen/decode.d.ts +14 -0
- package/dist/codegen/decode.js +93 -0
- package/dist/codegen/emitter.d.ts +10 -41
- package/dist/codegen/emitter.js +9 -4
- package/dist/codegen/expressions.d.ts +9 -0
- package/dist/codegen/expressions.js +15 -24
- package/dist/codegen/js.d.ts +2 -2
- package/dist/codegen/js.js +5 -2
- package/dist/codegen/options.d.ts +40 -0
- package/dist/codegen/options.js +1 -0
- package/dist/codegen/runtime.d.ts +7 -5
- package/dist/codegen/runtime.js +28 -20
- package/dist/codegen/simple-statements.d.ts +10 -4
- package/dist/codegen/simple-statements.js +40 -15
- package/dist/codegen/statements.js +64 -4
- package/dist/codegen/try.d.ts +5 -0
- package/dist/codegen/try.js +40 -0
- package/dist/compile.d.ts +9 -0
- package/dist/compile.js +19 -6
- package/dist/completion.d.ts +4 -2
- package/dist/completion.js +10 -5
- package/dist/declarations.js +32 -6
- package/dist/decorator-copy.js +5 -2
- 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/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 +40 -13
- package/dist/parser/base.d.ts +4 -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 +3 -1
- package/dist/parser/control-flow.js +21 -24
- package/dist/parser/declarations.d.ts +7 -4
- package/dist/parser/declarations.js +45 -6
- 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/simple-statements.d.ts +1 -1
- package/dist/parser/simple-statements.js +16 -9
- package/dist/parser/statements.d.ts +0 -3
- package/dist/parser/statements.js +22 -25
- 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 +11 -5
- package/dist/runtime-module.d.ts +1 -0
- package/dist/runtime-module.js +3 -0
- package/dist/source-map.d.ts +17 -0
- package/dist/source-map.js +75 -0
- package/dist/ts-types.d.ts +4 -0
- package/dist/ts-types.js +20 -3
- package/dist/typescript/convert-objects.d.ts +2 -1
- package/dist/typescript/convert-objects.js +18 -9
- package/dist/vite.js +13 -5
- package/dist/walk-types.js +1 -0
- package/dist/walk.d.ts +0 -2
- package/dist/walk.js +11 -28
- package/package.json +1 -1
- 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 +190 -0
- package/src/runtime/go.js +14 -5
- package/src/runtime/index.js +6 -0
- package/src/runtime/select.js +14 -9
- 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,5 +1,4 @@
|
|
|
1
1
|
import { decoratedName } from "../decorators.js";
|
|
2
|
-
import { goCaptures, goParams, goTarget } from "../goroutines.js";
|
|
3
2
|
import { isIterator, usesThis } from "../iterators.js";
|
|
4
3
|
import { containsElement, startsWithObjectLiteral } from "./analysis.js";
|
|
5
4
|
import { Emitter } from "./emitter.js";
|
|
@@ -59,8 +58,9 @@ export class ExpressionEmitter extends Emitter {
|
|
|
59
58
|
return [this.functionNames.get(component) ?? `$$${component.name.name}`, PRIMARY];
|
|
60
59
|
}
|
|
61
60
|
// `close(ch)` and the like are predeclared; JS has a `close` of its own, the window's.
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
const predeclared = PREDECLARED.get(node.name);
|
|
62
|
+
if (predeclared !== undefined && this.lookup(node.name) === undefined) {
|
|
63
|
+
return [predeclared, PRIMARY];
|
|
64
64
|
}
|
|
65
65
|
// The predeclared `error` used as a value is JS's `Error`, which also works without `new`.
|
|
66
66
|
return [this.isBuiltinError(node) ? 'Error' : this.name(node.name), PRIMARY];
|
|
@@ -69,6 +69,8 @@ export class ExpressionEmitter extends Emitter {
|
|
|
69
69
|
case 'BigIntLiteral':
|
|
70
70
|
case 'StringLiteral':
|
|
71
71
|
return [node.raw, PRIMARY];
|
|
72
|
+
case 'RegExpLiteral':
|
|
73
|
+
return [`/${node.pattern}/${node.flags}`, PRIMARY];
|
|
72
74
|
case 'TemplateLiteral':
|
|
73
75
|
return [this.template(node), PRIMARY];
|
|
74
76
|
case 'BooleanLiteral':
|
|
@@ -112,23 +114,14 @@ export class ExpressionEmitter extends Emitter {
|
|
|
112
114
|
return [this.streamChan(node), POSTFIX];
|
|
113
115
|
case 'QueueExpression':
|
|
114
116
|
return [this.queue(node), POSTFIX];
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
...captured.map((name) => this.name(name)),
|
|
124
|
-
this.elements(node.call.arguments),
|
|
125
|
-
];
|
|
126
|
-
// Without type checking, a callee that is neither fails when the call runs.
|
|
127
|
-
const fn = literal && this.inWorker
|
|
128
|
-
? this.expression({ ...literal, params: [...goParams(literal, captured), ...literal.params] }, ARROW)
|
|
129
|
-
: JSON.stringify(goTarget(this.program, node));
|
|
130
|
-
return [`$$go(${fn}, [${args.filter((arg) => arg !== '').join(', ')}])`, POSTFIX];
|
|
131
|
-
}
|
|
117
|
+
case 'TopicExpression':
|
|
118
|
+
return [this.topic(node), POSTFIX];
|
|
119
|
+
case 'GoExpression':
|
|
120
|
+
return [this.go(node), POSTFIX];
|
|
121
|
+
case 'DecodeExpression':
|
|
122
|
+
return [this.decode(node), POSTFIX];
|
|
123
|
+
case 'TryExpression':
|
|
124
|
+
return this.tryValue(node);
|
|
132
125
|
case 'UnaryExpression':
|
|
133
126
|
return [this.unary(node), UNARY];
|
|
134
127
|
case 'BinaryExpression':
|
|
@@ -221,10 +214,8 @@ export class ExpressionEmitter extends Emitter {
|
|
|
221
214
|
});
|
|
222
215
|
}
|
|
223
216
|
unary(node) {
|
|
224
|
-
if (node.operator === '<-')
|
|
225
|
-
|
|
226
|
-
return `await $$receive(${channel}${this.commaOk.has(node) ? ', true' : ''})`;
|
|
227
|
-
}
|
|
217
|
+
if (node.operator === '<-')
|
|
218
|
+
return `await ${this.receive(node.argument, this.commaOk.has(node))}`;
|
|
228
219
|
const argument = this.expression(node.argument, UNARY);
|
|
229
220
|
if (node.operator === 'typeof' || node.operator === 'await') {
|
|
230
221
|
return `${node.operator} ${argument}`;
|
package/dist/codegen/js.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type * as ast from '../ast.ts';
|
|
2
|
-
import type { JsOptions } from './
|
|
3
|
-
export type { JsOptions } from './
|
|
2
|
+
import type { JsOptions } from './options.ts';
|
|
3
|
+
export type { JsOptions } from './options.ts';
|
|
4
4
|
/** A component whose inlined copies add more lines than this to its module becomes a function. */
|
|
5
5
|
export declare const INLINE_LIMIT = 100;
|
|
6
6
|
/**
|
package/dist/codegen/js.js
CHANGED
|
@@ -62,12 +62,14 @@ class JsGenerator extends FunctionEmitter {
|
|
|
62
62
|
// What is the module's own: its `go`, and the CSS of its components for their shadow roots.
|
|
63
63
|
const own = [
|
|
64
64
|
...(/(?<![.\w$])\$\$go(?![\w$])/.test(rest.join('\n'))
|
|
65
|
-
? moduleGo(inWorker ? null : (goroutines?.workerUrl ?? ''))
|
|
65
|
+
? moduleGo(inWorker ? null : (goroutines?.workerUrl ?? ''), goroutines && 'nodeLoader' in goroutines ? goroutines.nodeLoader : undefined)
|
|
66
66
|
: []),
|
|
67
67
|
...(styles.length > 0 ? ['const $$styles = [];'] : []),
|
|
68
68
|
];
|
|
69
|
+
// The types that decode checks against, before the code that may decode at the top level.
|
|
70
|
+
const types = this.decodeTypeLines();
|
|
69
71
|
const mode = this.options.runtime ?? 'import';
|
|
70
|
-
const runtime = runtimeCode(runtimeNames([...own, ...styles, ...rest].join('\n')), mode);
|
|
72
|
+
const runtime = runtimeCode(runtimeNames([...own, ...types, ...styles, ...rest].join('\n')), mode);
|
|
71
73
|
if (runtime.length === 0 && own.length === 0 && styles.length === 0) {
|
|
72
74
|
return this.lines.length === 0 ? '' : `${this.lines.join('\n')}\n`;
|
|
73
75
|
}
|
|
@@ -79,6 +81,7 @@ class JsGenerator extends FunctionEmitter {
|
|
|
79
81
|
mode === 'import' ? [...head, ...runtime] : head,
|
|
80
82
|
mode === 'inline' ? runtime : [],
|
|
81
83
|
own,
|
|
84
|
+
types,
|
|
82
85
|
styles,
|
|
83
86
|
rest,
|
|
84
87
|
].filter((section) => section.length > 0);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type * as ast from '../ast.ts';
|
|
2
|
+
import type { Type } from '../checker/types.ts';
|
|
3
|
+
import type { DecoratorSource } from '../decorators.ts';
|
|
4
|
+
import type { InlinePackage } from '../inline-packages.ts';
|
|
5
|
+
import type { StyleModule } from '../style-modules.ts';
|
|
6
|
+
import type { ImportedComponent } from './imported.ts';
|
|
7
|
+
import type { RuntimeMode } from './runtime.ts';
|
|
8
|
+
export interface JsOptions {
|
|
9
|
+
/** The Rook source, used to keep the blank lines between statements. */
|
|
10
|
+
source: string;
|
|
11
|
+
/** Replace `.rk` with `.js` in relative import paths, for output written next to the sources. */
|
|
12
|
+
rewriteImports: boolean;
|
|
13
|
+
/** Types from the checker, when it ran; without them the generated code is more general. */
|
|
14
|
+
types?: WeakMap<ast.Expression, Type> | undefined;
|
|
15
|
+
/** Decorators imported from other modules, by name: their code is inlined here. */
|
|
16
|
+
decorators?: ReadonlyMap<string, ImportedDecorator> | undefined;
|
|
17
|
+
/** Components imported from other modules, by name: called, or inlined when they are small. */
|
|
18
|
+
components?: ReadonlyMap<string, ImportedComponent> | undefined;
|
|
19
|
+
/** Components of the module that become functions, since inlining them adds too many lines. */
|
|
20
|
+
functions?: ReadonlySet<string> | undefined;
|
|
21
|
+
/** The CSS modules the module imports, by their paths as written. */
|
|
22
|
+
styleModules?: ReadonlyMap<string, StyleModule> | undefined;
|
|
23
|
+
/** For `go`: where the worker module is (`./app.worker.js`), or in it, the functions it runs. */
|
|
24
|
+
goroutines?: {
|
|
25
|
+
workerUrl: string;
|
|
26
|
+
nodeLoader?: string | undefined;
|
|
27
|
+
} | {
|
|
28
|
+
targets: readonly string[];
|
|
29
|
+
} | undefined;
|
|
30
|
+
/** How the module gets the runtime it uses: imported, by default, or in it (runtime.ts). */
|
|
31
|
+
runtime?: RuntimeMode | undefined;
|
|
32
|
+
/** The data classes of the module, whose imports stay even if only types use them. */
|
|
33
|
+
dataClasses?: ReadonlySet<string> | undefined;
|
|
34
|
+
}
|
|
35
|
+
/** A decorator of another module, with the types of the expressions of that module. */
|
|
36
|
+
export interface ImportedDecorator extends DecoratorSource {
|
|
37
|
+
types: WeakMap<ast.Expression, Type> | null;
|
|
38
|
+
/** The components of that module its code uses, which go with it into the components here. */
|
|
39
|
+
inline: InlinePackage | null;
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
/** Where compiled code imports the runtime from. */
|
|
2
|
-
export declare const RUNTIME_MODULE = "rooklang/runtime";
|
|
3
1
|
/** How a module gets the runtime: by an import, or with the code of the runtime in it. */
|
|
4
2
|
export type RuntimeMode = 'import' | 'inline';
|
|
5
|
-
/**
|
|
6
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Predeclared names of goroutines and channels, and what they are in JS: `close(ch)` is
|
|
5
|
+
* `$$Channel.close(ch)`, and `Channel` itself is `$$Channel`, so that the names of a program stay
|
|
6
|
+
* its own.
|
|
7
|
+
*/
|
|
8
|
+
export declare const PREDECLARED: ReadonlyMap<string, string>;
|
|
7
9
|
/** The names of the runtime that code uses, in order. */
|
|
8
10
|
export declare function runtimeNames(code: string): string[];
|
|
9
11
|
/** What gives a module these names of the runtime: an import, or the files that have them. */
|
|
@@ -12,4 +14,4 @@ export declare function runtimeCode(names: readonly string[], mode: RuntimeMode)
|
|
|
12
14
|
* The `go` of a module: in a module, a call in a worker that starts with its worker module; in the
|
|
13
15
|
* worker module, a call in the same worker, of a function of `$$goroutines`.
|
|
14
16
|
*/
|
|
15
|
-
export declare function moduleGo(workerUrl: string | null): string[];
|
|
17
|
+
export declare function moduleGo(workerUrl: string | null, nodeLoader?: string): string[];
|
package/dist/codegen/runtime.js
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
|
+
import { RUNTIME_MODULE } from "../runtime-module.js";
|
|
1
2
|
import { RUNTIME_FILES } from "../runtime/sources.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
'
|
|
12
|
-
'
|
|
13
|
-
'
|
|
14
|
-
'
|
|
15
|
-
'
|
|
16
|
-
'
|
|
3
|
+
/**
|
|
4
|
+
* Predeclared names of goroutines and channels, and what they are in JS: `close(ch)` is
|
|
5
|
+
* `$$Channel.close(ch)`, and `Channel` itself is `$$Channel`, so that the names of a program stay
|
|
6
|
+
* its own.
|
|
7
|
+
*/
|
|
8
|
+
export const PREDECLARED = new Map([
|
|
9
|
+
['abortSignal', '$$Channel.abortSignal'],
|
|
10
|
+
['after', '$$Channel.after'],
|
|
11
|
+
['cancel', '$$cancel'],
|
|
12
|
+
['Channel', '$$Channel'],
|
|
13
|
+
['close', '$$Channel.close'],
|
|
14
|
+
['done', '$$Channel.done'],
|
|
15
|
+
['signal', '$$Channel.signal'],
|
|
16
|
+
['stream', '$$Channel.stream'],
|
|
17
|
+
['tick', '$$Channel.tick'],
|
|
18
|
+
['Topic', '$$Topic'],
|
|
19
|
+
['transfer', '$$transfer'],
|
|
17
20
|
]);
|
|
18
21
|
/** A name of generated code, but not a member: `$$chan(...)`, and not `channel.$$chan`. */
|
|
19
22
|
const NAME = /(?<![.\w$])\$\$[A-Za-z_][\w$]*/g;
|
|
@@ -64,12 +67,12 @@ export function runtimeCode(names, mode) {
|
|
|
64
67
|
* The `go` of a module: in a module, a call in a worker that starts with its worker module; in the
|
|
65
68
|
* worker module, a call in the same worker, of a function of `$$goroutines`.
|
|
66
69
|
*/
|
|
67
|
-
export function moduleGo(workerUrl) {
|
|
70
|
+
export function moduleGo(workerUrl, nodeLoader) {
|
|
68
71
|
if (workerUrl === null) {
|
|
69
72
|
return ['const $$go = (fn, args) => $$goHere($$goroutines, fn, args);'];
|
|
70
73
|
}
|
|
71
74
|
return [
|
|
72
|
-
...startWorker(workerUrl),
|
|
75
|
+
...startWorker(workerUrl, nodeLoader),
|
|
73
76
|
'',
|
|
74
77
|
'const $$go = (name, args) => $$goWorker($$startWorker, name, args);',
|
|
75
78
|
];
|
|
@@ -78,9 +81,14 @@ export function moduleGo(workerUrl) {
|
|
|
78
81
|
* The start of a worker of a module: a Web Worker, or a worker thread of Node. Node takes only the
|
|
79
82
|
* path of a `file:` URL, without the query of `app.rk?goroutines`, so its worker starts with a
|
|
80
83
|
* module that imports the whole URL. An absolute URL, such as the Blob of the playground, is used
|
|
81
|
-
* as it is.
|
|
84
|
+
* as it is. With `nodeLoader`, as under Vitest, the worker of Node imports the loader of `.rk`
|
|
85
|
+
* files first, since its thread has neither Vite nor the loader of `rook run`.
|
|
82
86
|
*/
|
|
83
|
-
function startWorker(url) {
|
|
87
|
+
function startWorker(url, nodeLoader) {
|
|
88
|
+
// The loader registers its hooks when it runs, so the module comes after it, by a dynamic import.
|
|
89
|
+
const code = nodeLoader === undefined
|
|
90
|
+
? '`import ${JSON.stringify(url.href)};`'
|
|
91
|
+
: `\`import ${JSON.stringify(nodeLoader)}; await import(\${JSON.stringify(url.href)});\``;
|
|
84
92
|
const base = /^[a-z][a-z\d+.-]*:/i.test(url) ? '' : ', import.meta.url';
|
|
85
93
|
const workerUrl = `new URL(${JSON.stringify(url)}${base})`;
|
|
86
94
|
return [
|
|
@@ -92,7 +100,7 @@ function startWorker(url) {
|
|
|
92
100
|
' const { Worker: NodeWorker } = await import(/* @vite-ignore */ threads);',
|
|
93
101
|
// Vite bundles the Web Worker; this URL is only for Node.
|
|
94
102
|
` const url = new URL(/* @vite-ignore */ ${JSON.stringify(url)}${base});`,
|
|
95
|
-
|
|
103
|
+
` const code = ${code};`,
|
|
96
104
|
' return new NodeWorker(new URL(`data:text/javascript,${encodeURIComponent(code)}`));',
|
|
97
105
|
'}',
|
|
98
106
|
];
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import type * as ast from '../ast.ts';
|
|
2
|
-
import {
|
|
2
|
+
import { TryEmitter } from './try.ts';
|
|
3
3
|
/** Statements: lists and blocks of them, variables, assignments, `return`; the others are in later layers. */
|
|
4
|
-
export declare abstract class SimpleStatementEmitter extends
|
|
4
|
+
export declare abstract class SimpleStatementEmitter extends TryEmitter {
|
|
5
5
|
protected abstract forInStatement(node: ast.ForInStatement): void;
|
|
6
6
|
protected abstract selectStatement(node: ast.SelectStatement): void;
|
|
7
7
|
protected abstract forStatement(node: ast.ForStatement): void;
|
|
8
8
|
protected abstract ifStatement(node: ast.IfStatement): string;
|
|
9
|
-
protected abstract switchStatement(node: ast.SwitchStatement
|
|
10
|
-
protected abstract taglessSwitch(node: ast.SwitchStatement): void;
|
|
9
|
+
protected abstract switchStatement(node: ast.SwitchStatement): void;
|
|
11
10
|
protected abstract tryStatement(node: ast.TryStatement): string;
|
|
12
11
|
protected abstract classDeclaration(node: ast.ClassDeclaration): void;
|
|
13
12
|
protected abstract importDeclaration(node: ast.ImportDeclaration): void;
|
|
@@ -29,7 +28,14 @@ export declare abstract class SimpleStatementEmitter extends CallEmitter {
|
|
|
29
28
|
/** A block's statements in a new scope, without the braces; `then` writes more code in it. */
|
|
30
29
|
protected blockStatements(statements: readonly ast.Statement[], then?: () => void): void;
|
|
31
30
|
protected blockStatement(node: ast.BlockStatement): string;
|
|
31
|
+
/**
|
|
32
|
+
* The start of the statement being written, which its first line gets as a mark for the source
|
|
33
|
+
* map (source-map.ts). Imports have none, since the import of the runtime goes among them, and
|
|
34
|
+
* neither does the code of other modules, whose places are in their own sources.
|
|
35
|
+
*/
|
|
36
|
+
private sourceMark;
|
|
32
37
|
protected statement(node: ast.Statement): void;
|
|
38
|
+
protected line(text: string): void;
|
|
33
39
|
protected emitStatement(node: ast.Statement): void;
|
|
34
40
|
/** `let a, b = 1, 2` → `let a = 1, b = 2`; `const q, err = f()` → `const [q, err] = f()`. */
|
|
35
41
|
protected variableDeclaration(node: ast.VariableDeclaration): string;
|
|
@@ -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':
|
|
@@ -1,3 +1,4 @@
|
|
|
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";
|
|
@@ -16,7 +17,9 @@ export class StatementEmitter extends ParallelLoopEmitter {
|
|
|
16
17
|
return;
|
|
17
18
|
// Imports used only as types (e.g. interfaces) do not exist at runtime, and neither do
|
|
18
19
|
// components: a component used as a value is its function, imported below.
|
|
19
|
-
|
|
20
|
+
// A data class, even used only as a type, registers itself where it is imported.
|
|
21
|
+
const used = (name) => (this.valueNames.has(name.name) || this.options.dataClasses?.has(name.name) === true) &&
|
|
22
|
+
!this.options.components?.has(name.name);
|
|
20
23
|
const clauses = [];
|
|
21
24
|
if (node.defaultImport && used(node.defaultImport)) {
|
|
22
25
|
clauses.push(this.name(node.defaultImport.name));
|
|
@@ -100,7 +103,10 @@ export class StatementEmitter extends ParallelLoopEmitter {
|
|
|
100
103
|
: '';
|
|
101
104
|
const body = this.block(() => {
|
|
102
105
|
let previous;
|
|
106
|
+
// An abstract method has no code: only the subclasses have it.
|
|
103
107
|
for (const member of node.members) {
|
|
108
|
+
if (member.kind === 'MethodDeclaration' && member.abstract)
|
|
109
|
+
continue;
|
|
104
110
|
const bothFields = previous?.kind === 'FieldDeclaration' && member.kind === 'FieldDeclaration';
|
|
105
111
|
if (previous && (!bothFields || this.blankLineBetween(previous, member)))
|
|
106
112
|
this.blankLine();
|
|
@@ -109,6 +115,12 @@ export class StatementEmitter extends ParallelLoopEmitter {
|
|
|
109
115
|
}
|
|
110
116
|
});
|
|
111
117
|
this.line(`${exported}class ${this.name(node.name.name)}${superClass} ${body}`);
|
|
118
|
+
// A data class is registered, so that its instances get it back in another thread
|
|
119
|
+
// (runtime/classes.js); the id is the same in the worker module, which has a copy of it.
|
|
120
|
+
if (node.data) {
|
|
121
|
+
const id = `${node.name.name}:${hash(this.options.source.slice(node.start, node.end))}`;
|
|
122
|
+
this.line(`$$dataClass(${this.name(node.name.name)}, ${JSON.stringify(id)});`);
|
|
123
|
+
}
|
|
112
124
|
}
|
|
113
125
|
/** Visibility modifiers are checked by the compiler and do not exist in the output. */
|
|
114
126
|
classMember(member) {
|
|
@@ -126,17 +138,65 @@ export class StatementEmitter extends ParallelLoopEmitter {
|
|
|
126
138
|
break;
|
|
127
139
|
}
|
|
128
140
|
case 'ConstructorDeclaration': {
|
|
129
|
-
const [params, body] = this.func(member.params, member
|
|
141
|
+
const [params, body] = this.func(member.params, assignProperties(member));
|
|
130
142
|
this.line(`constructor(${params}) ${body}`);
|
|
131
143
|
break;
|
|
132
144
|
}
|
|
133
145
|
case 'MethodDeclaration': {
|
|
146
|
+
if (!member.body)
|
|
147
|
+
break;
|
|
134
148
|
const [params, body] = this.func(member.params, member.body);
|
|
135
|
-
const modifiers = `${member.isStatic ? 'static ' : ''}${member.async ? 'async ' : ''}
|
|
136
|
-
|
|
149
|
+
const modifiers = `${member.isStatic ? 'static ' : ''}${member.async ? 'async ' : ''}` +
|
|
150
|
+
(member.accessor ? `${member.accessor} ` : '');
|
|
151
|
+
const star = isIterator(member.params) && !member.accessor ? '*' : '';
|
|
137
152
|
this.line(`${modifiers}${star}${member.name.name}(${params}) ${body}`);
|
|
138
153
|
break;
|
|
139
154
|
}
|
|
140
155
|
}
|
|
141
156
|
}
|
|
142
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* The body of a constructor whose parameters are properties, `constructor(private name string)`:
|
|
160
|
+
* it assigns them first, `this.name = name`, or right after `super(...)` in a derived class.
|
|
161
|
+
*/
|
|
162
|
+
function assignProperties(node) {
|
|
163
|
+
const assignments = node.params.flatMap((param) => {
|
|
164
|
+
if (!param.property)
|
|
165
|
+
return [];
|
|
166
|
+
const at = { start: param.start, end: param.end };
|
|
167
|
+
const self = { kind: 'ThisExpression', ...at };
|
|
168
|
+
const target = {
|
|
169
|
+
kind: 'MemberExpression',
|
|
170
|
+
object: self,
|
|
171
|
+
property: param.name,
|
|
172
|
+
optional: false,
|
|
173
|
+
...at,
|
|
174
|
+
};
|
|
175
|
+
return [
|
|
176
|
+
{
|
|
177
|
+
kind: 'AssignmentStatement',
|
|
178
|
+
operator: '=',
|
|
179
|
+
targets: [target],
|
|
180
|
+
values: [param.name],
|
|
181
|
+
...at,
|
|
182
|
+
},
|
|
183
|
+
];
|
|
184
|
+
});
|
|
185
|
+
if (assignments.length === 0)
|
|
186
|
+
return node.body;
|
|
187
|
+
const statements = node.body.body;
|
|
188
|
+
const after = statements.findIndex(isSuperCall) + 1;
|
|
189
|
+
return {
|
|
190
|
+
...node.body,
|
|
191
|
+
body: [...statements.slice(0, after), ...assignments, ...statements.slice(after)],
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/** FNV-1a of a text, as 8 hex digits: an id that changes only with the text. */
|
|
195
|
+
function hash(text) {
|
|
196
|
+
let value = 0x811c9dc5;
|
|
197
|
+
for (let i = 0; i < text.length; i++) {
|
|
198
|
+
value ^= text.charCodeAt(i);
|
|
199
|
+
value = Math.imul(value, 0x01000193) >>> 0;
|
|
200
|
+
}
|
|
201
|
+
return value.toString(16).padStart(8, '0');
|
|
202
|
+
}
|
|
@@ -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
|
+
}
|
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
|
/**
|