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
package/dist/lexer/token.js
CHANGED
package/dist/loader.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
-
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { appendFileSync, existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { createRequire, registerHooks } from 'node:module';
|
|
4
|
-
import { extname, join } from 'node:path';
|
|
4
|
+
import { dirname, extname, join, resolve } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { isMainThread } from 'node:worker_threads';
|
|
7
7
|
import { RUNTIME_MODULE } from "./runtime-module.js";
|
|
8
|
+
import { sourceMapComment } from "./source-map.js";
|
|
8
9
|
// `rook run` imports this module first (`node --import`): Node then imports `.rk` files,
|
|
9
10
|
// compiled when they load, and `app.rk?goroutines` is the worker module of `go` in app.rk.
|
|
10
11
|
// The worker threads of `go` import it too, since they get the `--import` of the process. The main
|
|
@@ -13,7 +14,10 @@ import { RUNTIME_MODULE } from "./runtime-module.js";
|
|
|
13
14
|
// there: compiling again, with the types, would take each of them as long. So a worker does not
|
|
14
15
|
// even load the compiler, which takes ~80 ms, unless a module is missing from the cache; the hooks
|
|
15
16
|
// are synchronous, so it is loaded with require(). ROOK_NO_CHECK turns type checking off, and
|
|
16
|
-
// ROOK_MARKUP, 1 or 0, markup and components on or off for every file.
|
|
17
|
+
// ROOK_MARKUP, 1 or 0, markup and components on or off for every file. The code has its source map
|
|
18
|
+
// in it, and the process runs with --enable-source-maps, so stack traces show the lines of .rk.
|
|
19
|
+
// The main thread lists the files it compiles, and those they read, in `files` of the directory of
|
|
20
|
+
// the run, with the time each was changed, for `rook run --watch` (run-file.ts).
|
|
17
21
|
const typeCheck = process.env['ROOK_NO_CHECK'] === undefined;
|
|
18
22
|
const markupSetting = process.env['ROOK_MARKUP'];
|
|
19
23
|
const markup = markupSetting === undefined ? undefined : markupSetting === '1';
|
|
@@ -45,19 +49,37 @@ registerHooks({
|
|
|
45
49
|
const { displayPath } = require(`./build${extension}`);
|
|
46
50
|
const { compileFile } = require(`./compile-file${extension}`);
|
|
47
51
|
const path = displayPath(fileURLToPath(moduleUrl));
|
|
52
|
+
if (isMainThread && cache)
|
|
53
|
+
list([resolve(path)]);
|
|
48
54
|
const result = compileFile(path, {
|
|
49
55
|
rewriteImports: false,
|
|
50
56
|
typeCheck,
|
|
51
57
|
markup,
|
|
52
58
|
quiet: !isMainThread,
|
|
53
59
|
});
|
|
60
|
+
const code = withMap(result.code, result.map);
|
|
61
|
+
const worker = result.worker === undefined ? undefined : withMap(result.worker, result.workerMap);
|
|
54
62
|
if (isMainThread && cache) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
63
|
+
// The CSS modules it imports; the .rk modules are listed when they are loaded.
|
|
64
|
+
const read = result.dependencies.map((each) => resolve(dirname(path), each));
|
|
65
|
+
list(read.filter((each) => existsSync(each)));
|
|
66
|
+
writeFileSync(cached(moduleUrl), code);
|
|
67
|
+
if (worker !== undefined)
|
|
68
|
+
writeFileSync(cached(`${moduleUrl}?goroutines`), worker);
|
|
59
69
|
}
|
|
60
|
-
const source = search === '?goroutines' ? (
|
|
70
|
+
const source = search === '?goroutines' ? (worker ?? '') : code;
|
|
61
71
|
return { format: 'module', source, shortCircuit: true };
|
|
62
72
|
},
|
|
63
73
|
});
|
|
74
|
+
/** The code with its source map in it. */
|
|
75
|
+
function withMap(code, map) {
|
|
76
|
+
if (map === undefined || code === '')
|
|
77
|
+
return code;
|
|
78
|
+
const data = Buffer.from(JSON.stringify(map)).toString('base64');
|
|
79
|
+
return `${code}${sourceMapComment(`data:application/json;base64,${data}`)}`;
|
|
80
|
+
}
|
|
81
|
+
/** Adds files to the list of the run: a line of the path and the time it was changed. */
|
|
82
|
+
function list(paths) {
|
|
83
|
+
const lines = paths.map((path) => `${path}\t${statSync(path).mtimeMs}\n`);
|
|
84
|
+
appendFileSync(join(cache, 'files'), lines.join(''));
|
|
85
|
+
}
|
package/dist/names.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type * as ast from './ast.ts';
|
|
2
2
|
/** Names assigned anywhere inside `node`: `x = ...`, `x += ...`, `x++`. */
|
|
3
3
|
export declare function assignedNames(node: ast.Node, names?: Set<string>): Set<string>;
|
|
4
|
+
/** `order.delivery.kind`: the variable and the fields of a path, or `null` for other expressions. */
|
|
5
|
+
export declare function pathOf(node: ast.Expression): string[] | null;
|
|
6
|
+
/** Paths of fields assigned anywhere inside `node`, e.g. `order.delivery` of `order.delivery = d`. */
|
|
7
|
+
export declare function assignedPaths(node: ast.Node, paths?: Set<string>): Set<string>;
|
|
4
8
|
/** Whether an identifier with one of `names` occurs in `node`, whatever it refers to. */
|
|
5
9
|
export declare function mentionsName(node: ast.Node, names: ReadonlySet<string>): boolean;
|
|
6
10
|
/** Every name declared inside `node`: parameters and all local declarations, nested ones too. */
|
package/dist/names.js
CHANGED
|
@@ -19,6 +19,30 @@ export function assignedNames(node, names = new Set()) {
|
|
|
19
19
|
forEachChild(node, (child) => assignedNames(child, names));
|
|
20
20
|
return names;
|
|
21
21
|
}
|
|
22
|
+
/** `order.delivery.kind`: the variable and the fields of a path, or `null` for other expressions. */
|
|
23
|
+
export function pathOf(node) {
|
|
24
|
+
if (node.kind === 'Identifier')
|
|
25
|
+
return [node.name];
|
|
26
|
+
if (node.kind !== 'MemberExpression' || node.optional)
|
|
27
|
+
return null;
|
|
28
|
+
const object = pathOf(node.object);
|
|
29
|
+
return object && [...object, node.property.name];
|
|
30
|
+
}
|
|
31
|
+
/** Paths of fields assigned anywhere inside `node`, e.g. `order.delivery` of `order.delivery = d`. */
|
|
32
|
+
export function assignedPaths(node, paths = new Set()) {
|
|
33
|
+
const targets = node.kind === 'AssignmentStatement'
|
|
34
|
+
? node.targets
|
|
35
|
+
: node.kind === 'IncDecStatement'
|
|
36
|
+
? [node.target]
|
|
37
|
+
: [];
|
|
38
|
+
for (const target of targets) {
|
|
39
|
+
const path = pathOf(target);
|
|
40
|
+
if (path && path.length > 1)
|
|
41
|
+
paths.add(path.join('.'));
|
|
42
|
+
}
|
|
43
|
+
forEachChild(node, (child) => assignedPaths(child, paths));
|
|
44
|
+
return paths;
|
|
45
|
+
}
|
|
22
46
|
/** Whether an identifier with one of `names` occurs in `node`, whatever it refers to. */
|
|
23
47
|
export function mentionsName(node, names) {
|
|
24
48
|
if (node.kind === 'Identifier')
|
|
@@ -99,6 +123,7 @@ export function freeNames(component) {
|
|
|
99
123
|
for (const name of node.names)
|
|
100
124
|
declared.add(name.name);
|
|
101
125
|
node.values.forEach(visit);
|
|
126
|
+
visit(node.body);
|
|
102
127
|
return;
|
|
103
128
|
case 'SelectCase':
|
|
104
129
|
for (const name of node.names)
|
|
@@ -120,6 +145,8 @@ export function freeNames(component) {
|
|
|
120
145
|
if (node.key)
|
|
121
146
|
declared.add(node.key.name);
|
|
122
147
|
visit(node.iterable);
|
|
148
|
+
if (node.withKey)
|
|
149
|
+
visit(node.withKey);
|
|
123
150
|
visit(node.body);
|
|
124
151
|
return;
|
|
125
152
|
case 'CatchClause':
|
|
@@ -195,6 +222,7 @@ export function collectValueNames(node, names, isComponent = () => true) {
|
|
|
195
222
|
return;
|
|
196
223
|
case 'VariableDeclaration':
|
|
197
224
|
node.values.forEach(visit);
|
|
225
|
+
visit(node.body);
|
|
198
226
|
return;
|
|
199
227
|
case 'FuncDeclaration':
|
|
200
228
|
case 'MethodDeclaration':
|
|
@@ -237,6 +265,7 @@ export function collectValueNames(node, names, isComponent = () => true) {
|
|
|
237
265
|
return;
|
|
238
266
|
case 'ForInStatement':
|
|
239
267
|
visit(node.iterable);
|
|
268
|
+
visit(node.withKey ?? null);
|
|
240
269
|
visit(node.body);
|
|
241
270
|
return;
|
|
242
271
|
case 'CatchClause':
|
package/dist/parser/base.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ import type { StringToken, Token, TokenKind } from '../lexer/token.ts';
|
|
|
4
4
|
import { type Context } from './syntax.ts';
|
|
5
5
|
export declare abstract class ParserBase {
|
|
6
6
|
protected abstract parseBreakOrContinue(): ast.BreakStatement | ast.ContinueStatement;
|
|
7
|
+
protected abstract parseLabeled(): ast.Statement;
|
|
8
|
+
protected abstract parseReturn(): ast.ReturnStatement;
|
|
7
9
|
protected abstract parseDefer(): ast.DeferStatement;
|
|
8
10
|
protected abstract parseFor(): ast.ForStatement | ast.ForInStatement;
|
|
9
11
|
protected abstract parseGoFor(): ast.ForStatement | ast.ForInStatement;
|
|
@@ -23,6 +25,7 @@ export declare abstract class ParserBase {
|
|
|
23
25
|
protected abstract parseClass(start: number, exported: boolean): ast.ClassDeclaration;
|
|
24
26
|
protected abstract parseInterface(start: number, exported: boolean): ast.InterfaceDeclaration;
|
|
25
27
|
protected abstract parseTypeAlias(start: number, exported: boolean): ast.TypeAliasDeclaration;
|
|
28
|
+
protected abstract parseFunctionBody(async?: boolean): ast.BlockStatement;
|
|
26
29
|
protected abstract canStartType(offset?: number): boolean;
|
|
27
30
|
protected abstract parseType(): ast.TypeNode;
|
|
28
31
|
protected abstract parseTypeArgs(): ast.TypeNode[];
|
|
@@ -37,6 +40,8 @@ export declare abstract class ParserBase {
|
|
|
37
40
|
protected abstract parseMake(): ast.MakeExpression;
|
|
38
41
|
protected abstract parseStreamChan(start: number): ast.StreamChanExpression;
|
|
39
42
|
protected abstract parseQueue(): ast.QueueExpression | null;
|
|
43
|
+
protected abstract parseTopic(): ast.TopicExpression | null;
|
|
44
|
+
protected abstract parseDecode(): ast.DecodeExpression | null;
|
|
40
45
|
protected abstract parseArrowFunction(async?: boolean): ast.ArrowFunction;
|
|
41
46
|
protected abstract parseFuncExpression(async?: boolean): ast.FuncExpression;
|
|
42
47
|
protected abstract parseIdentifier(what?: string): ast.Identifier;
|
package/dist/parser/base.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { STATEMENT_KEYWORDS, BRACKETS, ParseError, describe } from "./syntax.js";
|
|
2
2
|
// The parser is a chain of layers, one per area: base → simple statements → statements → control
|
|
3
|
-
// flow → declarations → decorators → classes → types → expressions → literals → markup → Parser
|
|
3
|
+
// flow → jumps → params → declarations → decorators → classes → types → expressions → literals → markup → Parser
|
|
4
4
|
// (parser.ts). Statements, expressions and markup contain each other, so methods of later layers
|
|
5
5
|
// that earlier ones call are declared here as abstract.
|
|
6
6
|
//
|
|
@@ -21,6 +21,7 @@ export class ParserBase {
|
|
|
21
21
|
noObjectLiteral: false,
|
|
22
22
|
inComponent: false,
|
|
23
23
|
inMarkup: false,
|
|
24
|
+
labels: [],
|
|
24
25
|
};
|
|
25
26
|
/** Expressions written in parentheses, which the tree itself does not record. */
|
|
26
27
|
parenthesized = new WeakSet();
|
package/dist/parser/classes.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { DecoratorParser } from './decorators.ts';
|
|
|
3
3
|
export declare abstract class ClassParser extends DecoratorParser {
|
|
4
4
|
protected parseClass(start: number, exported: boolean): ast.ClassDeclaration;
|
|
5
5
|
protected parseClassMember(): ast.ClassMember[];
|
|
6
|
+
/** A method, a getter or a setter, after its name; an abstract one has no body. */
|
|
7
|
+
private parseMethod;
|
|
6
8
|
protected parseInterface(start: number, exported: boolean): ast.InterfaceDeclaration;
|
|
7
9
|
protected parseTypeAlias(start: number, exported: boolean): ast.TypeAliasDeclaration;
|
|
8
10
|
}
|
package/dist/parser/classes.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { isKeyword } from "../lexer/token.js";
|
|
2
2
|
import { DecoratorParser } from "./decorators.js";
|
|
3
|
-
import { MODIFIERS } from "./syntax.js";
|
|
3
|
+
import { MODIFIERS, VISIBILITIES } from "./syntax.js";
|
|
4
4
|
// Classes and their members, interfaces and `type` aliases.
|
|
5
5
|
export class ClassParser extends DecoratorParser {
|
|
6
6
|
parseClass(start, exported) {
|
|
7
|
+
const abstract = this.acceptWord('abstract');
|
|
8
|
+
const data = this.acceptWord('data');
|
|
7
9
|
this.expect('class');
|
|
8
10
|
const name = this.parseIdentifier('class name');
|
|
9
11
|
const typeParams = this.parseTypeParams();
|
|
@@ -34,6 +36,8 @@ export class ClassParser extends DecoratorParser {
|
|
|
34
36
|
return {
|
|
35
37
|
kind: 'ClassDeclaration',
|
|
36
38
|
exported,
|
|
39
|
+
data,
|
|
40
|
+
...(abstract ? { abstract } : {}),
|
|
37
41
|
name,
|
|
38
42
|
typeParams,
|
|
39
43
|
superClass,
|
|
@@ -45,24 +49,26 @@ export class ClassParser extends DecoratorParser {
|
|
|
45
49
|
parseClassMember() {
|
|
46
50
|
const start = this.peek().start;
|
|
47
51
|
let visibility = null;
|
|
48
|
-
|
|
52
|
+
const modifiers = new Map();
|
|
49
53
|
// Modifiers are contextual: `static` is a modifier only when a member name follows it.
|
|
50
54
|
while (this.peek().kind === 'Identifier' && MODIFIERS.has(this.peek().text)) {
|
|
51
55
|
const following = this.peek(1);
|
|
52
56
|
if (following.kind !== 'Identifier' && !isKeyword(following.kind))
|
|
53
57
|
break;
|
|
54
58
|
const modifier = this.next();
|
|
55
|
-
if (modifier.text
|
|
56
|
-
if (isStatic)
|
|
57
|
-
this.error('duplicate "static" modifier', modifier.start, modifier.end);
|
|
58
|
-
isStatic = true;
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
59
|
+
if (VISIBILITIES.has(modifier.text)) {
|
|
61
60
|
if (visibility)
|
|
62
61
|
this.error('duplicate visibility modifier', modifier.start, modifier.end);
|
|
63
62
|
visibility = modifier.text;
|
|
64
63
|
}
|
|
64
|
+
else {
|
|
65
|
+
if (modifiers.has(modifier.text)) {
|
|
66
|
+
this.error(`duplicate "${modifier.text}" modifier`, modifier.start, modifier.end);
|
|
67
|
+
}
|
|
68
|
+
modifiers.set(modifier.text, modifier);
|
|
69
|
+
}
|
|
65
70
|
}
|
|
71
|
+
const isStatic = modifiers.has('static');
|
|
66
72
|
// `async load()`; a method named `async` is `async()`.
|
|
67
73
|
const asyncToken = this.check('async') && this.peek(1).kind !== '(' ? this.next() : null;
|
|
68
74
|
const async = asyncToken !== null;
|
|
@@ -72,7 +78,12 @@ export class ClassParser extends DecoratorParser {
|
|
|
72
78
|
this.error('constructors cannot be static', start, this.span(start).end);
|
|
73
79
|
if (async)
|
|
74
80
|
this.error('a constructor cannot be async', start, this.span(start).end);
|
|
75
|
-
const
|
|
81
|
+
for (const word of ['readonly', 'abstract']) {
|
|
82
|
+
const modifier = modifiers.get(word);
|
|
83
|
+
if (modifier)
|
|
84
|
+
this.error(`a constructor cannot be ${word}`, modifier.start, modifier.end);
|
|
85
|
+
}
|
|
86
|
+
const params = this.parseParams(false, false, false, true);
|
|
76
87
|
const resultsStart = this.peek().start;
|
|
77
88
|
if (this.parseResults().length > 0) {
|
|
78
89
|
this.error('constructors cannot have result types', resultsStart, this.span(start).end);
|
|
@@ -88,27 +99,24 @@ export class ClassParser extends DecoratorParser {
|
|
|
88
99
|
},
|
|
89
100
|
];
|
|
90
101
|
}
|
|
102
|
+
// `get area()`; a method named `get` is `get()`, a field `get string`.
|
|
103
|
+
const accessorToken = (this.checkWord('get') || this.checkWord('set')) &&
|
|
104
|
+
isName(this.peek(1)) &&
|
|
105
|
+
this.peek(2).kind === '('
|
|
106
|
+
? this.next()
|
|
107
|
+
: null;
|
|
91
108
|
const name = this.parsePropertyName('member name');
|
|
92
109
|
if (this.check('(')) {
|
|
93
|
-
const params = this.parseParams(false);
|
|
94
|
-
const results = this.parseResults();
|
|
95
|
-
const body = this.parseFunctionBody(async);
|
|
96
110
|
return [
|
|
97
|
-
|
|
98
|
-
kind: 'MethodDeclaration',
|
|
99
|
-
visibility: visibility ?? 'public',
|
|
100
|
-
isStatic,
|
|
101
|
-
...(async ? { async } : {}),
|
|
102
|
-
name,
|
|
103
|
-
params,
|
|
104
|
-
results,
|
|
105
|
-
body,
|
|
106
|
-
...this.span(start),
|
|
107
|
-
},
|
|
111
|
+
this.parseMethod(start, name, visibility ?? 'public', modifiers, asyncToken, accessorToken),
|
|
108
112
|
];
|
|
109
113
|
}
|
|
110
114
|
if (asyncToken)
|
|
111
115
|
this.error('only methods can be async', asyncToken.start, asyncToken.end);
|
|
116
|
+
const abstract = modifiers.get('abstract');
|
|
117
|
+
if (abstract) {
|
|
118
|
+
this.error('only methods can be abstract: for a field, declare an abstract getter, e.g. abstract get name() string', abstract.start, abstract.end);
|
|
119
|
+
}
|
|
112
120
|
// Fields: `name string`, `count = 0`, `x, y number`.
|
|
113
121
|
const names = [name];
|
|
114
122
|
while (this.accept(','))
|
|
@@ -127,12 +135,65 @@ export class ClassParser extends DecoratorParser {
|
|
|
127
135
|
kind: 'FieldDeclaration',
|
|
128
136
|
visibility: visibility ?? 'public',
|
|
129
137
|
isStatic,
|
|
138
|
+
...(modifiers.has('readonly') ? { readonly: true } : {}),
|
|
130
139
|
name: fieldName,
|
|
131
140
|
type,
|
|
132
141
|
value,
|
|
133
142
|
...span,
|
|
134
143
|
}));
|
|
135
144
|
}
|
|
145
|
+
/** A method, a getter or a setter, after its name; an abstract one has no body. */
|
|
146
|
+
parseMethod(start, name, visibility, modifiers, asyncToken, accessorToken) {
|
|
147
|
+
const isStatic = modifiers.has('static');
|
|
148
|
+
const readonly = modifiers.get('readonly');
|
|
149
|
+
const abstract = modifiers.get('abstract');
|
|
150
|
+
const accessor = accessorToken?.text;
|
|
151
|
+
const async = asyncToken !== null;
|
|
152
|
+
if (readonly) {
|
|
153
|
+
this.error('only fields can be readonly: a method cannot be assigned anyway', readonly.start, readonly.end);
|
|
154
|
+
}
|
|
155
|
+
if (abstract && isStatic) {
|
|
156
|
+
this.error('a static method cannot be abstract', abstract.start, abstract.end);
|
|
157
|
+
}
|
|
158
|
+
else if (abstract && visibility === 'private') {
|
|
159
|
+
this.error('an abstract method cannot be private: the subclasses that implement it could not see it', abstract.start, abstract.end);
|
|
160
|
+
}
|
|
161
|
+
if (accessor && asyncToken) {
|
|
162
|
+
this.error(`a ${accessor}ter cannot be async`, asyncToken.start, asyncToken.end);
|
|
163
|
+
}
|
|
164
|
+
const params = this.parseParams(false);
|
|
165
|
+
const results = this.parseResults();
|
|
166
|
+
const header = this.span(start);
|
|
167
|
+
if (accessor === 'get' && (params.length > 0 || results.length !== 1)) {
|
|
168
|
+
this.error('a getter takes nothing and returns one value, e.g. get area() number', header.start, header.end);
|
|
169
|
+
}
|
|
170
|
+
else if (accessor === 'set' && (params.length !== 1 || results.length > 0)) {
|
|
171
|
+
this.error('a setter takes one value and returns nothing, e.g. set area(v number)', header.start, header.end);
|
|
172
|
+
}
|
|
173
|
+
let body = null;
|
|
174
|
+
if (!abstract)
|
|
175
|
+
body = this.parseFunctionBody(async);
|
|
176
|
+
else if (this.check('{')) {
|
|
177
|
+
const block = this.parseFunctionBody(async);
|
|
178
|
+
this.error('an abstract method has no body: the subclasses implement it', block.start, block.end);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
this.endStatement();
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
kind: 'MethodDeclaration',
|
|
185
|
+
visibility,
|
|
186
|
+
isStatic,
|
|
187
|
+
...(async ? { async } : {}),
|
|
188
|
+
...(accessor ? { accessor } : {}),
|
|
189
|
+
...(abstract ? { abstract: true } : {}),
|
|
190
|
+
name,
|
|
191
|
+
params,
|
|
192
|
+
results,
|
|
193
|
+
body,
|
|
194
|
+
...this.span(start),
|
|
195
|
+
};
|
|
196
|
+
}
|
|
136
197
|
parseInterface(start, exported) {
|
|
137
198
|
this.expect('interface');
|
|
138
199
|
const name = this.parseIdentifier('interface name');
|
|
@@ -162,3 +223,7 @@ export class ClassParser extends DecoratorParser {
|
|
|
162
223
|
};
|
|
163
224
|
}
|
|
164
225
|
}
|
|
226
|
+
/** A member name: keywords can be names after `.` and in classes. */
|
|
227
|
+
function isName(token) {
|
|
228
|
+
return token.kind === 'Identifier' || isKeyword(token.kind);
|
|
229
|
+
}
|
|
@@ -2,6 +2,9 @@ import type * as ast from '../ast.ts';
|
|
|
2
2
|
import { StatementParser } from './statements.ts';
|
|
3
3
|
export declare abstract class ControlFlowParser extends StatementParser {
|
|
4
4
|
protected parseIf(): ast.IfStatement;
|
|
5
|
+
protected parseHeaderExpression(): ast.Expression;
|
|
6
|
+
/** `const v, err = f();` before the condition of `if` or the value of `switch`. */
|
|
7
|
+
private parseHeaderInit;
|
|
5
8
|
protected parseFor(): ast.ForStatement | ast.ForInStatement;
|
|
6
9
|
/** The rest of a `for` statement that starts at `start`, after the keyword. */
|
|
7
10
|
private parseForAfter;
|
|
@@ -14,6 +17,11 @@ export declare abstract class ControlFlowParser extends StatementParser {
|
|
|
14
17
|
ast.SimpleStatement | null
|
|
15
18
|
];
|
|
16
19
|
protected parseForIn(start: number, go?: boolean): ast.ForInStatement;
|
|
20
|
+
/**
|
|
21
|
+
* `with key todo.id` after the items of a `{for}` in markup: its blocks are found again by the
|
|
22
|
+
* key instead of the item. `with` and `key` are words only here, not keywords.
|
|
23
|
+
*/
|
|
24
|
+
private parseWithKey;
|
|
17
25
|
/** `go for i, v in items { }`: the parts of the array run as goroutines, and the loop waits. */
|
|
18
26
|
protected parseGoFor(): ast.ForStatement | ast.ForInStatement;
|
|
19
27
|
protected parseLoopBody(): ast.BlockStatement;
|
|
@@ -22,7 +30,6 @@ export declare abstract class ControlFlowParser extends StatementParser {
|
|
|
22
30
|
protected parseSelect(): ast.SelectStatement;
|
|
23
31
|
/** `v = <-ch`, `v, ok = <-ch`, `<-ch` or `ch <- v`; the names are new variables of the case. */
|
|
24
32
|
private parseSelectOperation;
|
|
25
|
-
protected parseBreakOrContinue(): ast.BreakStatement | ast.ContinueStatement;
|
|
26
33
|
protected parseThrow(): ast.ThrowStatement;
|
|
27
34
|
protected parseTry(): ast.TryStatement;
|
|
28
35
|
protected parseDefer(): ast.DeferStatement;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { StatementParser } from "./statements.js";
|
|
2
|
-
// if, for, switch,
|
|
2
|
+
// if, for, switch, select, throw, try and defer.
|
|
3
3
|
export class ControlFlowParser extends StatementParser {
|
|
4
4
|
parseIf() {
|
|
5
5
|
const start = this.next().start;
|
|
6
|
+
const init = this.parseHeaderInit('if');
|
|
6
7
|
const condition = this.parseHeaderExpression();
|
|
7
8
|
const consequent = this.parseBlock();
|
|
8
9
|
let alternate = null;
|
|
@@ -10,7 +11,21 @@ export class ControlFlowParser extends StatementParser {
|
|
|
10
11
|
if (this.accept('else')) {
|
|
11
12
|
alternate = this.check('if') ? this.parseIf() : this.parseBlock();
|
|
12
13
|
}
|
|
13
|
-
return { kind: 'IfStatement', condition, consequent, alternate, ...this.span(start) };
|
|
14
|
+
return { kind: 'IfStatement', init, condition, consequent, alternate, ...this.span(start) };
|
|
15
|
+
}
|
|
16
|
+
parseHeaderExpression() {
|
|
17
|
+
return this.withContext({ noObjectLiteral: true }, () => this.parseExpression());
|
|
18
|
+
}
|
|
19
|
+
/** `const v, err = f();` before the condition of `if` or the value of `switch`. */
|
|
20
|
+
parseHeaderInit(keyword) {
|
|
21
|
+
if (!this.check('const') && !this.check('let'))
|
|
22
|
+
return null;
|
|
23
|
+
const init = this.withContext({ noObjectLiteral: true }, () => this.parseVariableDeclaration(this.peek().start, false));
|
|
24
|
+
if (this.context.inMarkup) {
|
|
25
|
+
this.error(`the ${keyword} of markup has no initializer: declare the variable before the markup`, init.start, init.end);
|
|
26
|
+
}
|
|
27
|
+
this.expect(';', `";" after the initializer of ${keyword}`);
|
|
28
|
+
return init;
|
|
14
29
|
}
|
|
15
30
|
parseFor() {
|
|
16
31
|
return this.parseForAfter(this.next().start);
|
|
@@ -54,13 +69,39 @@ export class ControlFlowParser extends StatementParser {
|
|
|
54
69
|
}
|
|
55
70
|
this.expect('in');
|
|
56
71
|
const iterable = this.parseHeaderExpression();
|
|
72
|
+
const withKey = this.parseWithKey(go);
|
|
73
|
+
const keyed = withKey ? { withKey } : {};
|
|
57
74
|
if (!go) {
|
|
58
75
|
const body = this.parseLoopBody();
|
|
59
|
-
return { kind: 'ForInStatement', key, value, iterable, body, ...this.span(start) };
|
|
76
|
+
return { kind: 'ForInStatement', key, value, iterable, ...keyed, body, ...this.span(start) };
|
|
60
77
|
}
|
|
61
78
|
// The parts run at once in workers: nothing can leave the loop but `continue`.
|
|
62
|
-
const body = this.withContext({ inLoop: true, inBreakable: false, inGoFor: true }, () => this.parseBlock());
|
|
63
|
-
return {
|
|
79
|
+
const body = this.withContext({ inLoop: true, inBreakable: false, inGoFor: true, labels: [] }, () => this.parseBlock());
|
|
80
|
+
return {
|
|
81
|
+
kind: 'ForInStatement',
|
|
82
|
+
key,
|
|
83
|
+
value,
|
|
84
|
+
iterable,
|
|
85
|
+
...keyed,
|
|
86
|
+
body,
|
|
87
|
+
go,
|
|
88
|
+
...this.span(start),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* `with key todo.id` after the items of a `{for}` in markup: its blocks are found again by the
|
|
93
|
+
* key instead of the item. `with` and `key` are words only here, not keywords.
|
|
94
|
+
*/
|
|
95
|
+
parseWithKey(go) {
|
|
96
|
+
if (!this.checkWord('with'))
|
|
97
|
+
return null;
|
|
98
|
+
const start = this.next().start;
|
|
99
|
+
this.expectWord('key');
|
|
100
|
+
const key = this.parseHeaderExpression();
|
|
101
|
+
if (go || !this.context.inMarkup) {
|
|
102
|
+
this.error('"with key" finds again the blocks of a {for} in markup, and this loop has none: remove it', start, key.end);
|
|
103
|
+
}
|
|
104
|
+
return key;
|
|
64
105
|
}
|
|
65
106
|
/** `go for i, v in items { }`: the parts of the array run as goroutines, and the loop waits. */
|
|
66
107
|
parseGoFor() {
|
|
@@ -77,6 +118,7 @@ export class ControlFlowParser extends StatementParser {
|
|
|
77
118
|
}
|
|
78
119
|
parseSwitch() {
|
|
79
120
|
const start = this.next().start;
|
|
121
|
+
const init = this.parseHeaderInit('switch');
|
|
80
122
|
const discriminant = this.check('{') ? null : this.parseHeaderExpression();
|
|
81
123
|
this.expect('{');
|
|
82
124
|
const cases = [];
|
|
@@ -101,7 +143,7 @@ export class ControlFlowParser extends StatementParser {
|
|
|
101
143
|
cases.push({ kind: 'SwitchCase', tests, body, ...this.span(caseStart) });
|
|
102
144
|
}
|
|
103
145
|
this.expect('}');
|
|
104
|
-
return { kind: 'SwitchStatement', discriminant, cases, ...this.span(start) };
|
|
146
|
+
return { kind: 'SwitchStatement', init, discriminant, cases, ...this.span(start) };
|
|
105
147
|
}
|
|
106
148
|
/** `select { case v = <-ch: ... case ch <- v: ... default: ... }`; it waits, as `await` does. */
|
|
107
149
|
parseSelect() {
|
|
@@ -157,25 +199,6 @@ export class ControlFlowParser extends StatementParser {
|
|
|
157
199
|
}
|
|
158
200
|
return [names, first];
|
|
159
201
|
}
|
|
160
|
-
parseBreakOrContinue() {
|
|
161
|
-
const token = this.next();
|
|
162
|
-
let statement;
|
|
163
|
-
if (token.kind === 'break') {
|
|
164
|
-
if (!this.context.inBreakable) {
|
|
165
|
-
this.error(this.context.inGoFor
|
|
166
|
-
? '"break" cannot stop "go for": its parts run at once in workers; skip an element with "continue"'
|
|
167
|
-
: '"break" outside of a loop or switch', token.start, token.end);
|
|
168
|
-
}
|
|
169
|
-
statement = { kind: 'BreakStatement', start: token.start, end: token.end };
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
if (!this.context.inLoop)
|
|
173
|
-
this.error('"continue" outside of a loop', token.start, token.end);
|
|
174
|
-
statement = { kind: 'ContinueStatement', start: token.start, end: token.end };
|
|
175
|
-
}
|
|
176
|
-
this.endStatement();
|
|
177
|
-
return statement;
|
|
178
|
-
}
|
|
179
202
|
parseThrow() {
|
|
180
203
|
const start = this.next().start;
|
|
181
204
|
const argument = this.parseExpression();
|
|
@@ -214,7 +237,7 @@ export class ControlFlowParser extends StatementParser {
|
|
|
214
237
|
this.error('"defer" cannot be used in the body of "go for": it runs in workers, apart from the function; defer it before the loop', start, this.span(start).end);
|
|
215
238
|
}
|
|
216
239
|
if (this.check('{')) {
|
|
217
|
-
const body = this.withContext({ inDefer: true, inAsync: false, inLoop: false, inBreakable: false }, () => this.parseBlock());
|
|
240
|
+
const body = this.withContext({ inDefer: true, inAsync: false, inLoop: false, inBreakable: false, labels: [] }, () => this.parseBlock());
|
|
218
241
|
return { kind: 'DeferStatement', body, ...this.span(start) };
|
|
219
242
|
}
|
|
220
243
|
const call = this.withContext({ inDefer: true, inAsync: false }, () => this.parseExpression());
|
|
@@ -1,26 +1,19 @@
|
|
|
1
1
|
import type * as ast from '../ast.ts';
|
|
2
|
-
import {
|
|
3
|
-
export declare abstract class DeclarationParser extends
|
|
2
|
+
import { ParamParser } from './params.ts';
|
|
3
|
+
export declare abstract class DeclarationParser extends ParamParser {
|
|
4
4
|
protected parseImport(): ast.ImportDeclaration;
|
|
5
5
|
protected parseImportSpecifier(): ast.ImportSpecifier;
|
|
6
|
+
/** `state items []Item = []` at the top level of a module: state its components share. */
|
|
7
|
+
protected parseDeclaration(start: number, exported: boolean): ast.Statement | undefined;
|
|
6
8
|
protected parseExport(): ast.Statement;
|
|
7
9
|
protected parseFuncDeclaration(start: number, exported: boolean): ast.FuncDeclaration;
|
|
8
10
|
/**
|
|
9
11
|
* `<T any, U Shape>` after a name; `<K, V any>` gives both the constraint, as in Go.
|
|
10
12
|
*/
|
|
11
13
|
protected parseTypeParams(): ast.TypeParameter[];
|
|
12
|
-
/**
|
|
13
|
-
* `(a, b number, c string)`. Names without a type take the type of the next typed name, as in
|
|
14
|
-
* Go; only arrow functions may leave types out entirely.
|
|
15
|
-
*/
|
|
16
|
-
protected parseParams(typesOptional: boolean, allowDefaults?: boolean, allowRest?: boolean): ast.Parameter[];
|
|
17
|
-
/** `...attrs`: the attributes that a component passes on to one of its elements. */
|
|
18
|
-
private parseRestParam;
|
|
19
|
-
/** Result types after a parameter list: nothing, `T`, or `(T1, T2)`. */
|
|
20
|
-
protected parseResults(): ast.TypeNode[];
|
|
21
14
|
/** `comp Name(properties) { ...; return <markup> }`, maybe after decorators. */
|
|
22
15
|
protected parseComponent(start: number, exported: boolean, htmlTag?: ast.HtmlTag | null, decorators?: ast.DecoratorUse[]): ast.ComponentDeclaration;
|
|
23
|
-
/** Like a function body, but its own statements may also declare `state`, `ref` and `mount
|
|
16
|
+
/** Like a function body, but its own statements may also declare `state`, `ref` and `mount`. */
|
|
24
17
|
protected parseComponentBody(): ast.BlockStatement;
|
|
25
18
|
/** A statement at the top level of a component or a decorator. */
|
|
26
19
|
protected parseComponentStatement(): ast.Statement;
|