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/declarations.js
CHANGED
|
@@ -137,7 +137,7 @@ class DeclarationPrinter {
|
|
|
137
137
|
switch (member.kind) {
|
|
138
138
|
case 'FieldDeclaration': {
|
|
139
139
|
const found = (member.isStatic ? info.statics : info.members).get(member.name.name);
|
|
140
|
-
const modifiers = this.modifiers(member.visibility, member.isStatic);
|
|
140
|
+
const modifiers = this.modifiers(member.visibility, member.isStatic, member.readonly);
|
|
141
141
|
// As in the declaration files TypeScript writes, private members have no type.
|
|
142
142
|
if (member.visibility === 'private')
|
|
143
143
|
lines.push(`${modifiers}${member.name.name};`);
|
|
@@ -147,6 +147,17 @@ class DeclarationPrinter {
|
|
|
147
147
|
}
|
|
148
148
|
case 'ConstructorDeclaration': {
|
|
149
149
|
const modifiers = this.modifiers(member.visibility, false);
|
|
150
|
+
// The parameters that are properties are declared as fields, as TypeScript writes them.
|
|
151
|
+
member.params.forEach((param, i) => {
|
|
152
|
+
const { property } = param;
|
|
153
|
+
const type = info.ctor?.params[i];
|
|
154
|
+
if (!property)
|
|
155
|
+
return;
|
|
156
|
+
const field = `${this.modifiers(property.visibility, false, property.readonly)}${param.name.name}`;
|
|
157
|
+
lines.push(property.visibility === 'private' || !type
|
|
158
|
+
? `${field};`
|
|
159
|
+
: `${field}: ${tsType(type)};`);
|
|
160
|
+
});
|
|
150
161
|
if (info.ctor) {
|
|
151
162
|
lines.push(`${modifiers}constructor${parameters(member.params, info.ctor)};`);
|
|
152
163
|
}
|
|
@@ -154,8 +165,11 @@ class DeclarationPrinter {
|
|
|
154
165
|
}
|
|
155
166
|
case 'MethodDeclaration': {
|
|
156
167
|
const found = (member.isStatic ? info.statics : info.members).get(member.name.name);
|
|
157
|
-
const modifiers = this.modifiers(member.visibility, member.isStatic)
|
|
158
|
-
|
|
168
|
+
const modifiers = this.modifiers(member.visibility, member.isStatic) +
|
|
169
|
+
(member.abstract ? 'abstract ' : '');
|
|
170
|
+
if (member.accessor)
|
|
171
|
+
lines.push(accessor(member, modifiers, found?.type));
|
|
172
|
+
else if (member.visibility === 'private')
|
|
159
173
|
lines.push(`${modifiers}${member.name.name}();`);
|
|
160
174
|
else if (found?.type.kind === 'function') {
|
|
161
175
|
lines.push(`${modifiers}${member.name.name}${this.signature(member.params, found.type)};`);
|
|
@@ -164,10 +178,11 @@ class DeclarationPrinter {
|
|
|
164
178
|
}
|
|
165
179
|
}
|
|
166
180
|
}
|
|
167
|
-
this.lines.push(`${exported}declare class ${jsName(node.name.name)}${this.typeParams(info.typeParams)}${heritage} {`, ...lines.map((line) => ` ${line}`), '}');
|
|
181
|
+
this.lines.push(`${exported}declare ${node.abstract ? 'abstract ' : ''}class ${jsName(node.name.name)}${this.typeParams(info.typeParams)}${heritage} {`, ...lines.map((line) => ` ${line}`), '}');
|
|
168
182
|
}
|
|
169
|
-
modifiers(visibility, isStatic) {
|
|
170
|
-
return `${visibility === 'public' ? '' : `${visibility} `}${isStatic ? 'static ' : ''}
|
|
183
|
+
modifiers(visibility, isStatic, readonly) {
|
|
184
|
+
return (`${visibility === 'public' ? '' : `${visibility} `}${isStatic ? 'static ' : ''}` +
|
|
185
|
+
(readonly ? 'readonly ' : ''));
|
|
171
186
|
}
|
|
172
187
|
/** `<T, U extends Shape>` */
|
|
173
188
|
typeParams(params) {
|
|
@@ -191,6 +206,17 @@ function parameters(params, type) {
|
|
|
191
206
|
});
|
|
192
207
|
return `(${list.join(', ')})`;
|
|
193
208
|
}
|
|
209
|
+
/** `get area(): number;` or `set area(v: number);`; a private one, as TypeScript writes it, untyped. */
|
|
210
|
+
function accessor(node, modifiers, type) {
|
|
211
|
+
const head = `${modifiers}${node.accessor} ${node.name.name}`;
|
|
212
|
+
const param = jsName(node.params[0]?.name.name ?? 'value');
|
|
213
|
+
if (node.visibility === 'private' || !type) {
|
|
214
|
+
return node.accessor === 'get' ? `${head}();` : `${head}(${param});`;
|
|
215
|
+
}
|
|
216
|
+
return node.accessor === 'get'
|
|
217
|
+
? `${head}(): ${tsType(type)};`
|
|
218
|
+
: `${head}(${param}: ${tsType(type)});`;
|
|
219
|
+
}
|
|
194
220
|
/** `Base` or `events.EventEmitter` in `extends`; other expressions cannot be written in types. */
|
|
195
221
|
function expressionName(node) {
|
|
196
222
|
if (node.kind === 'Identifier')
|
package/dist/decorator-copy.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export type CopyListener = (copy: ast.Node, original: ast.Node) => void;
|
|
|
5
5
|
export declare function originOf(node: ast.Node): ast.Node;
|
|
6
6
|
/**
|
|
7
7
|
* Renames of the names that are not values: tags of components, `<Icon />`, and decorators,
|
|
8
|
-
*
|
|
8
|
+
* `@visible.shown`. Code of another module refers to those of its own module.
|
|
9
9
|
*/
|
|
10
10
|
export interface OtherNames {
|
|
11
11
|
tags?: ReadonlyMap<string, string>;
|
package/dist/decorator-copy.js
CHANGED
|
@@ -47,7 +47,10 @@ export function renamer(renames, copied, other = {}) {
|
|
|
47
47
|
const generic = (node, hidden) => {
|
|
48
48
|
const result = {};
|
|
49
49
|
for (const [key, value] of Object.entries(node)) {
|
|
50
|
-
|
|
50
|
+
// Labels are not values: `outer: for` and `break outer` keep their names.
|
|
51
|
+
if (key === 'label')
|
|
52
|
+
result[key] = value;
|
|
53
|
+
else if (Array.isArray(value)) {
|
|
51
54
|
result[key] = value.map((item) => (isNode(item) ? copy(item, hidden) : item));
|
|
52
55
|
}
|
|
53
56
|
else {
|
|
@@ -106,7 +109,7 @@ export function renamer(renames, copied, other = {}) {
|
|
|
106
109
|
return done({
|
|
107
110
|
...node,
|
|
108
111
|
params: node.params.map((param) => copy(param, inner)),
|
|
109
|
-
body: copy(node.body, inner),
|
|
112
|
+
body: node.body && copy(node.body, inner),
|
|
110
113
|
}, node);
|
|
111
114
|
}
|
|
112
115
|
case 'FieldDeclaration':
|
|
@@ -140,6 +143,7 @@ export function renamer(renames, copied, other = {}) {
|
|
|
140
143
|
return done({
|
|
141
144
|
...node,
|
|
142
145
|
iterable: copy(node.iterable, hidden),
|
|
146
|
+
...(node.withKey ? { withKey: copy(node.withKey, scoped(names, hidden)) } : {}),
|
|
143
147
|
body: copy(node.body, scoped(names, hidden)),
|
|
144
148
|
}, node);
|
|
145
149
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type * as ast from './ast.ts';
|
|
2
|
+
import type { DecoratorSource } from './decorators.ts';
|
|
3
|
+
/** The JS name of a member or a parameter of a decorator, in the components it is applied to. */
|
|
4
|
+
export declare function decoratedName(decorator: string, member: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* The public members that a decorator gives the components it is applied to: its own and those of
|
|
7
|
+
* the decorators it includes, each with whether it changes (state and derived values do).
|
|
8
|
+
*/
|
|
9
|
+
export declare function publicMembers(decorator: ast.DecoratorDeclaration, decorators: ReadonlyMap<string, DecoratorSource>, seen?: ReadonlySet<ast.DecoratorDeclaration>): Map<string, boolean>;
|
|
10
|
+
/**
|
|
11
|
+
* `@shop.count` of a member that `shop` gets from the `cart` it includes: a variable of `shop`
|
|
12
|
+
* that is that of `cart`, `derived` when it changes, so that what reads it is updated.
|
|
13
|
+
*/
|
|
14
|
+
export declare function aliases(included: DecoratorSource, use: ast.DecoratorUse, prefix: string, decorators: ReadonlyMap<string, DecoratorSource>, prefixes: ReadonlyMap<string, string> | undefined): ast.VariableDeclaration[];
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// The names of the members of decorators in the components they are applied to, and the members
|
|
2
|
+
// that a decorator gives with those of the decorators it includes.
|
|
3
|
+
/** The JS name of a member or a parameter of a decorator, in the components it is applied to. */
|
|
4
|
+
export function decoratedName(decorator, member) {
|
|
5
|
+
return `$$${decorator}$${member}`;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The public members that a decorator gives the components it is applied to: its own and those of
|
|
9
|
+
* the decorators it includes, each with whether it changes (state and derived values do).
|
|
10
|
+
*/
|
|
11
|
+
export function publicMembers(decorator, decorators, seen = new Set()) {
|
|
12
|
+
const members = new Map();
|
|
13
|
+
const inner = new Set([...seen, decorator]);
|
|
14
|
+
for (const use of decorator.includes) {
|
|
15
|
+
const included = decorators.get(use.name.name);
|
|
16
|
+
if (!included || inner.has(included.node))
|
|
17
|
+
continue;
|
|
18
|
+
for (const [name, changes] of publicMembers(included.node, decorators, inner)) {
|
|
19
|
+
members.set(name, changes);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
for (const statement of decorator.body.body) {
|
|
23
|
+
if (statement.kind === 'FuncDeclaration' && statement.isPublic) {
|
|
24
|
+
members.set(statement.name.name, false);
|
|
25
|
+
}
|
|
26
|
+
else if (statement.kind === 'VariableDeclaration' && statement.isPublic) {
|
|
27
|
+
const changes = statement.keyword === 'state' || statement.keyword === 'derived';
|
|
28
|
+
for (const name of statement.names)
|
|
29
|
+
members.set(name.name, changes);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return members;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* `@shop.count` of a member that `shop` gets from the `cart` it includes: a variable of `shop`
|
|
36
|
+
* that is that of `cart`, `derived` when it changes, so that what reads it is updated.
|
|
37
|
+
*/
|
|
38
|
+
export function aliases(included, use, prefix, decorators, prefixes) {
|
|
39
|
+
const from = prefixes?.get(included.node.name.name) ?? included.node.name.name;
|
|
40
|
+
return [...publicMembers(included.node, decorators)].map(([member, changes]) => ({
|
|
41
|
+
kind: 'VariableDeclaration',
|
|
42
|
+
exported: false,
|
|
43
|
+
isPublic: false,
|
|
44
|
+
keyword: changes ? 'derived' : 'const',
|
|
45
|
+
names: [
|
|
46
|
+
{ kind: 'Identifier', name: decoratedName(prefix, member), start: use.start, end: use.end },
|
|
47
|
+
],
|
|
48
|
+
type: null,
|
|
49
|
+
values: [
|
|
50
|
+
{ kind: 'Identifier', name: decoratedName(from, member), start: use.start, end: use.end },
|
|
51
|
+
],
|
|
52
|
+
body: null,
|
|
53
|
+
start: use.start,
|
|
54
|
+
end: use.end,
|
|
55
|
+
}));
|
|
56
|
+
}
|
package/dist/decorators.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type * as ast from './ast.ts';
|
|
2
2
|
import { type CopyListener } from './decorator-copy.ts';
|
|
3
|
-
|
|
4
|
-
export declare function decoratedName(decorator: string, member: string): string;
|
|
3
|
+
export { decoratedName, publicMembers } from './decorator-names.ts';
|
|
5
4
|
/**
|
|
6
5
|
* Whether a declaration of an applied component gets an argument of a decorator. When the
|
|
7
6
|
* argument reads the component's properties, the declaration is a `state` that the properties
|
|
@@ -45,7 +44,7 @@ export declare function moduleNamesOf(decorator: ast.DecoratorDeclaration, progr
|
|
|
45
44
|
* The component with its decorators applied. Its body first declares the arguments of each
|
|
46
45
|
* decorator and runs its body, from the top decorator down, then runs the component's own body.
|
|
47
46
|
* The names of a decorator get its prefix, `$$visible$shown`, so they clash neither with each other
|
|
48
|
-
* nor with the component's names, and
|
|
47
|
+
* nor with the component's names, and `@visible.shown` reads that variable. The `mount` of
|
|
49
48
|
* the decorators runs after the component's own, from the inside out, so it goes before every
|
|
50
49
|
* `return` of the component's body.
|
|
51
50
|
*
|
package/dist/decorators.js
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { renamer } from "./decorator-copy.js";
|
|
2
|
+
import { aliases, decoratedName } from "./decorator-names.js";
|
|
2
3
|
import { declaredIn, freeNames, mentionsName, topLevelNames } from "./names.js";
|
|
3
4
|
import { containsReturn } from "./recursion.js";
|
|
4
5
|
import { forEachChild } from "./walk.js";
|
|
5
6
|
// Applying decorators: a component with decorators becomes one component whose body runs the
|
|
6
7
|
// bodies of its decorators first. The checker uses it to see what the inlined code uses, the
|
|
7
8
|
// generator to write it.
|
|
8
|
-
|
|
9
|
-
export function decoratedName(decorator, member) {
|
|
10
|
-
return `$$${decorator}$${member}`;
|
|
11
|
-
}
|
|
9
|
+
export { decoratedName, publicMembers } from "./decorator-names.js";
|
|
12
10
|
const argumentDeclarations = new WeakSet();
|
|
13
11
|
const wrappedContents = new WeakSet();
|
|
14
12
|
/**
|
|
@@ -69,7 +67,7 @@ export function moduleNamesOf(decorator, program) {
|
|
|
69
67
|
* The component with its decorators applied. Its body first declares the arguments of each
|
|
70
68
|
* decorator and runs its body, from the top decorator down, then runs the component's own body.
|
|
71
69
|
* The names of a decorator get its prefix, `$$visible$shown`, so they clash neither with each other
|
|
72
|
-
* nor with the component's names, and
|
|
70
|
+
* nor with the component's names, and `@visible.shown` reads that variable. The `mount` of
|
|
73
71
|
* the decorators runs after the component's own, from the inside out, so it goes before every
|
|
74
72
|
* `return` of the component's body.
|
|
75
73
|
*
|
|
@@ -83,37 +81,55 @@ export function moduleNamesOf(decorator, program) {
|
|
|
83
81
|
export function decorate(component, decorators, copied, prefixes) {
|
|
84
82
|
if (component.decorators.length === 0)
|
|
85
83
|
return component;
|
|
86
|
-
|
|
84
|
+
// Arguments that read the properties, or such arguments of a decorator that includes another,
|
|
85
|
+
// are state: they change with them.
|
|
86
|
+
const reactive = new Set(component.params.map((param) => param.name.name));
|
|
87
87
|
const setup = [];
|
|
88
88
|
const mounts = [];
|
|
89
89
|
const wrappers = [];
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
continue;
|
|
90
|
+
// `argument` copies an argument into the component: one of the component stays as it is, one of
|
|
91
|
+
// a decorator it includes is that decorator's code.
|
|
92
|
+
const apply = (source, args, argument, applying) => {
|
|
94
93
|
const decorator = source.node;
|
|
94
|
+
// A decorator that includes itself, through others too, is reported by the checker.
|
|
95
|
+
const inner = new Set([...applying, decorator]);
|
|
95
96
|
const prefix = prefixes?.get(decorator.name.name) ?? decorator.name.name;
|
|
96
97
|
const names = [...decoratorNames(decorator), ...source.moduleNames];
|
|
97
98
|
const renames = membersOf(prefix, names);
|
|
98
99
|
const copy = renamer(renames, copied, { decorators: prefixes, tags: source.tags });
|
|
99
100
|
decorator.params.forEach((param, i) => {
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
const given = args[i];
|
|
102
|
+
// A default value is the decorator's code.
|
|
103
|
+
const value = given
|
|
104
|
+
? argument(given)
|
|
105
|
+
: param.defaultValue && copy(param.defaultValue, new Set());
|
|
106
|
+
const name = renames.get(param.name.name);
|
|
107
|
+
const changes = value !== null && value !== undefined && mentionsName(value, reactive);
|
|
102
108
|
const declaration = {
|
|
103
109
|
kind: 'VariableDeclaration',
|
|
104
110
|
exported: false,
|
|
105
111
|
isPublic: false,
|
|
106
|
-
keyword:
|
|
107
|
-
names: [{ ...param.name, name
|
|
112
|
+
keyword: changes ? 'state' : 'const',
|
|
113
|
+
names: [{ ...param.name, name }],
|
|
108
114
|
type: param.type,
|
|
109
115
|
values: value ? [value] : [],
|
|
116
|
+
body: null,
|
|
110
117
|
start: param.start,
|
|
111
118
|
end: param.end,
|
|
112
119
|
};
|
|
120
|
+
if (changes)
|
|
121
|
+
reactive.add(name);
|
|
113
122
|
argumentDeclarations.add(declaration);
|
|
114
123
|
copied?.(declaration, param);
|
|
115
124
|
setup.push(declaration);
|
|
116
125
|
});
|
|
126
|
+
for (const use of decorator.includes) {
|
|
127
|
+
const included = decorators.get(use.name.name);
|
|
128
|
+
if (!included || inner.has(included.node))
|
|
129
|
+
continue;
|
|
130
|
+
apply(included, use.arguments, (value) => copy(value, new Set()), inner);
|
|
131
|
+
setup.push(...aliases(included, use, prefix, decorators, prefixes));
|
|
132
|
+
}
|
|
117
133
|
const wrapper = wrapperOf(decorator);
|
|
118
134
|
const own = [];
|
|
119
135
|
for (const statement of decorator.body.body) {
|
|
@@ -128,6 +144,11 @@ export function decorate(component, decorators, copied, prefixes) {
|
|
|
128
144
|
mounts.push(own);
|
|
129
145
|
if (wrapper)
|
|
130
146
|
wrappers.push(applyWrapper(source, wrapper, copied, prefix, prefixes));
|
|
147
|
+
};
|
|
148
|
+
for (const use of component.decorators) {
|
|
149
|
+
const source = decorators.get(use.name.name);
|
|
150
|
+
if (source)
|
|
151
|
+
apply(source, use.arguments, (value) => value, new Set());
|
|
131
152
|
}
|
|
132
153
|
const inside = mounts.reverse().flat();
|
|
133
154
|
const chain = wrappers.reverse();
|
|
@@ -186,6 +207,7 @@ function wrapped(node, chain) {
|
|
|
186
207
|
names: [{ ...wrapper.content }],
|
|
187
208
|
type: wrapper.type,
|
|
188
209
|
values: [value],
|
|
210
|
+
body: null,
|
|
189
211
|
start: node.start,
|
|
190
212
|
end: node.end,
|
|
191
213
|
};
|
package/dist/goroutines.d.ts
CHANGED
|
@@ -34,4 +34,4 @@ export declare function reach(program: ast.Program, names: Iterable<string>): Re
|
|
|
34
34
|
* The program of the worker module: the imports and the declarations that the functions `targets`
|
|
35
35
|
* reach, unexported, since the worker module is only loaded by the worker.
|
|
36
36
|
*/
|
|
37
|
-
export declare function workerProgram(program: ast.Program, targets: readonly string[]): ast.Program;
|
|
37
|
+
export declare function workerProgram(program: ast.Program, targets: readonly string[], dataClasses?: Iterable<string>): ast.Program;
|
package/dist/goroutines.js
CHANGED
|
@@ -165,9 +165,10 @@ export function reach(program, names) {
|
|
|
165
165
|
* The program of the worker module: the imports and the declarations that the functions `targets`
|
|
166
166
|
* reach, unexported, since the worker module is only loaded by the worker.
|
|
167
167
|
*/
|
|
168
|
-
export function workerProgram(program, targets) {
|
|
168
|
+
export function workerProgram(program, targets, dataClasses = []) {
|
|
169
169
|
const lifted = { ...program, body: [...program.body, ...literalFunctions(program)] };
|
|
170
|
-
|
|
170
|
+
// The data classes come too, so that their instances get their class here (runtime/classes.js).
|
|
171
|
+
const { statements, imports } = reach(lifted, [...targets, ...dataClasses]);
|
|
171
172
|
const body = [];
|
|
172
173
|
for (const [statement, names] of imports) {
|
|
173
174
|
body.push({
|
|
@@ -229,8 +230,8 @@ function usedNames(statement) {
|
|
|
229
230
|
if (member.value)
|
|
230
231
|
add(freeNames({ params: [], body: block([expression(member.value)]) }));
|
|
231
232
|
}
|
|
232
|
-
else {
|
|
233
|
-
add(freeNames(member));
|
|
233
|
+
else if (member.body) {
|
|
234
|
+
add(freeNames({ params: member.params, body: member.body }));
|
|
234
235
|
}
|
|
235
236
|
}
|
|
236
237
|
return names;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type CompileResult } from './compile.ts';
|
|
2
2
|
import { type CompletionList } from './completion.ts';
|
|
3
|
+
export { importFixes, type ImportFix } from './auto-import.ts';
|
|
3
4
|
export type { CompileResult } from './compile.ts';
|
|
4
|
-
export type { Completion, CompletionList } from './completion.ts';
|
|
5
|
+
export type { Completion, CompletionList, TextEdit } from './completion.ts';
|
|
5
6
|
export type { Diagnostic } from './diagnostics.ts';
|
|
6
7
|
export { formatDiagnostic } from './diagnostics.ts';
|
|
7
8
|
export { SourceFile } from './source.ts';
|
|
@@ -19,6 +20,8 @@ export interface CompileOptions {
|
|
|
19
20
|
declarations?: boolean;
|
|
20
21
|
/** Where the worker module of `go` is, relative to the module; see workerUrl() in compile.ts. */
|
|
21
22
|
workerUrl?: string;
|
|
23
|
+
/** A module that a worker thread of Node imports first, to load `.rk` files (vite.ts). */
|
|
24
|
+
nodeLoader?: string;
|
|
22
25
|
/** Markup and components; by default as the package.json of the file says (src/config.ts). */
|
|
23
26
|
markup?: boolean;
|
|
24
27
|
/** Import the runtime from "rooklang/runtime", the default, or put it into the module. */
|
|
@@ -27,7 +30,8 @@ export interface CompileOptions {
|
|
|
27
30
|
export declare function compile(source: string, options?: CompileOptions): CompileResult;
|
|
28
31
|
/**
|
|
29
32
|
* What can be written at `offset` in a module, for editors: names, members, types, tags and
|
|
30
|
-
* attributes
|
|
33
|
+
* attributes, and after them the names that other modules of the package export, with the imports
|
|
34
|
+
* they need. The imports are read from disk, like those of `compile`.
|
|
31
35
|
*/
|
|
32
36
|
export declare function complete(source: string, offset: number, options?: {
|
|
33
37
|
filename?: string;
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { importCompletions } from "./auto-import.js";
|
|
1
2
|
import { compileModule, workerUrl, } from "./compile.js";
|
|
2
3
|
import { completeModule } from "./completion.js";
|
|
3
4
|
import { markupFor } from "./config.js";
|
|
4
5
|
import { loadModuleExports } from "./modules.js";
|
|
5
6
|
import { readFileSync } from 'node:fs';
|
|
6
|
-
import { dirname, join, resolve } from 'node:path';
|
|
7
|
+
import { basename, dirname, join, resolve } from 'node:path';
|
|
7
8
|
import { importDeclarations, libraryFor } from "./typescript/importer.js";
|
|
9
|
+
export { importFixes } from "./auto-import.js";
|
|
8
10
|
export { formatDiagnostic } from "./diagnostics.js";
|
|
9
11
|
export { SourceFile } from "./source.js";
|
|
10
12
|
export function compile(source, options = {}) {
|
|
@@ -16,20 +18,27 @@ export function compile(source, options = {}) {
|
|
|
16
18
|
markup,
|
|
17
19
|
rewriteImports,
|
|
18
20
|
workerUrl: options.workerUrl ?? workerUrl(filename ?? 'main.rk', rewriteImports),
|
|
21
|
+
nodeLoader: options.nodeLoader,
|
|
19
22
|
typeCheck: options.typeCheck ?? true,
|
|
20
23
|
declarations: options.declarations ?? false,
|
|
21
24
|
runtime: options.runtime,
|
|
25
|
+
sourceName: filename === undefined ? undefined : basename(filename),
|
|
22
26
|
});
|
|
23
27
|
}
|
|
24
28
|
/**
|
|
25
29
|
* What can be written at `offset` in a module, for editors: names, members, types, tags and
|
|
26
|
-
* attributes
|
|
30
|
+
* attributes, and after them the names that other modules of the package export, with the imports
|
|
31
|
+
* they need. The imports are read from disk, like those of `compile`.
|
|
27
32
|
*/
|
|
28
33
|
export function complete(source, offset, options = {}) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
const { filename } = options;
|
|
35
|
+
const list = completeModule(source, offset, {
|
|
36
|
+
...filesOf(filename, true, options.markup),
|
|
37
|
+
markup: options.markup ?? markupFor(filename),
|
|
32
38
|
});
|
|
39
|
+
if (filename === undefined)
|
|
40
|
+
return list;
|
|
41
|
+
return { ...list, items: [...list.items, ...importCompletions(source, filename, list)] };
|
|
33
42
|
}
|
|
34
43
|
/** Reading what a module imports: other modules, declarations, CSS modules and the library. */
|
|
35
44
|
function filesOf(filename, typeCheck, markup) {
|
|
@@ -27,6 +27,7 @@ export interface ModulePackages {
|
|
|
27
27
|
* recursive or a web component cannot be inlined, and neither can one that reaches components or
|
|
28
28
|
* decorators the module imports: those would bring the names of a third module. Nor can code that
|
|
29
29
|
* uses a component of the module as a value, which is the function in the module, or that assigns
|
|
30
|
-
* a variable of the module: another module could only read it.
|
|
30
|
+
* a variable of the module: another module could only read it. Nor can code that reads state of
|
|
31
|
+
* the module, `state items` at its top level: it listens to the changes there.
|
|
31
32
|
*/
|
|
32
33
|
export declare function inlinePackages(program: ast.Program): ModulePackages;
|
package/dist/inline-packages.js
CHANGED
|
@@ -7,7 +7,8 @@ import { forEachChild } from "./walk.js";
|
|
|
7
7
|
* recursive or a web component cannot be inlined, and neither can one that reaches components or
|
|
8
8
|
* decorators the module imports: those would bring the names of a third module. Nor can code that
|
|
9
9
|
* uses a component of the module as a value, which is the function in the module, or that assigns
|
|
10
|
-
* a variable of the module: another module could only read it.
|
|
10
|
+
* a variable of the module: another module could only read it. Nor can code that reads state of
|
|
11
|
+
* the module, `state items` at its top level: it listens to the changes there.
|
|
11
12
|
*/
|
|
12
13
|
export function inlinePackages(program) {
|
|
13
14
|
const components = new Map();
|
|
@@ -30,9 +31,13 @@ export function inlinePackages(program) {
|
|
|
30
31
|
};
|
|
31
32
|
const topLevel = topLevelNames(program);
|
|
32
33
|
const usesComponentValues = (node) => componentValues(node, (name) => components.has(name)).length > 0;
|
|
33
|
-
const
|
|
34
|
+
const states = new Set(program.body.flatMap((statement) => statement.kind === 'VariableDeclaration' && statement.keyword === 'state'
|
|
35
|
+
? statement.names.map((name) => name.name)
|
|
36
|
+
: []));
|
|
37
|
+
// It assigns a variable of the module or reads its state, which only the module can do.
|
|
38
|
+
const needsItsModule = (node) => {
|
|
34
39
|
const assigned = assignedNames(node);
|
|
35
|
-
return [...freeNames(node)].some((name) => topLevel.has(name) && assigned.has(name));
|
|
40
|
+
return [...freeNames(node)].some((name) => topLevel.has(name) && (assigned.has(name) || states.has(name)));
|
|
36
41
|
};
|
|
37
42
|
/** The package of a component, or of the tags in the code of a decorator. */
|
|
38
43
|
const build = (root, tags) => {
|
|
@@ -69,7 +74,7 @@ export function inlinePackages(program) {
|
|
|
69
74
|
found.components.set(current, component);
|
|
70
75
|
if (usesComponentValues(expanded.get(current)))
|
|
71
76
|
return false;
|
|
72
|
-
if (
|
|
77
|
+
if (needsItsModule(expanded.get(current)))
|
|
73
78
|
return false;
|
|
74
79
|
for (const use of component.decorators) {
|
|
75
80
|
const source = sources.get(use.name.name);
|
package/dist/lexer/base.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ export declare abstract class LexerBase {
|
|
|
10
10
|
constructor(text: string);
|
|
11
11
|
/** Skips whitespace and comments; returns whether a line break was skipped. */
|
|
12
12
|
protected skipTrivia(): boolean;
|
|
13
|
+
/** After a value `/` divides; elsewhere it starts a regular expression, as in JS. */
|
|
14
|
+
protected lastEndsValue(): boolean;
|
|
13
15
|
protected lastEndsStatement(): boolean;
|
|
14
16
|
/**
|
|
15
17
|
* Unlike Go, a line starting with `.` / `?.` continues a method chain, and a line starting with
|
package/dist/lexer/base.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ENDS_STATEMENT, isDigit } from "./tables.js";
|
|
1
|
+
import { ENDS_STATEMENT, ENDS_VALUE, isDigit } from "./tables.js";
|
|
2
2
|
// The lexer is a chain of layers: base → literals → markup → style → Lexer (lexer.ts). This layer
|
|
3
3
|
// keeps the position and the modes (code, markup tags, markup content, CSS), skips spaces and
|
|
4
4
|
// comments, and inserts semicolons at the ends of lines.
|
|
@@ -48,6 +48,11 @@ export class LexerBase {
|
|
|
48
48
|
}
|
|
49
49
|
return sawNewline;
|
|
50
50
|
}
|
|
51
|
+
/** After a value `/` divides; elsewhere it starts a regular expression, as in JS. */
|
|
52
|
+
lastEndsValue() {
|
|
53
|
+
const last = this.tokens.at(-1);
|
|
54
|
+
return last !== undefined && ENDS_VALUE.has(last.kind);
|
|
55
|
+
}
|
|
51
56
|
lastEndsStatement() {
|
|
52
57
|
const last = this.tokens.at(-1);
|
|
53
58
|
return last !== undefined && ENDS_STATEMENT.has(last.kind);
|
package/dist/lexer/lexer.js
CHANGED
|
@@ -71,6 +71,9 @@ class Lexer extends StyleLexer {
|
|
|
71
71
|
this.push('}', start, start + 1);
|
|
72
72
|
this.modes.pop();
|
|
73
73
|
}
|
|
74
|
+
else if (c === '/' && !this.lastEndsValue()) {
|
|
75
|
+
this.scanRegExp(start);
|
|
76
|
+
}
|
|
74
77
|
else if (c === '<' && this.startsElement()) {
|
|
75
78
|
this.push('JsxTagOpen', start, start + 1);
|
|
76
79
|
this.modes.push({ kind: 'tag', start });
|
package/dist/lexer/literals.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { LexerBase } from './base.ts';
|
|
2
2
|
import { type CharTest } from './tables.ts';
|
|
3
3
|
export declare abstract class LiteralLexer extends LexerBase {
|
|
4
|
+
/**
|
|
5
|
+
* `/ab+c/gi`: the pattern goes up to a `/` that is not escaped or inside `[...]`, on one line,
|
|
6
|
+
* as in JS. JS checks the pattern when it loads the module, so an invalid one is an error here.
|
|
7
|
+
*/
|
|
8
|
+
protected scanRegExp(start: number): void;
|
|
4
9
|
protected scanNumber(start: number): void;
|
|
5
10
|
/** Consumes digits and `_` separators starting at `pos`; returns the end offset. */
|
|
6
11
|
protected scanDigits(pos: number, isValid: CharTest): number;
|
package/dist/lexer/literals.js
CHANGED
|
@@ -1,7 +1,57 @@
|
|
|
1
1
|
import { LexerBase } from "./base.js";
|
|
2
2
|
import { IDENTIFIER, SIMPLE_ESCAPES, isDigit, isHexDigit, isOctalDigit, isBinaryDigit, } from "./tables.js";
|
|
3
|
-
// Numbers, strings, template strings and escapes.
|
|
3
|
+
// Numbers, strings, template strings, regular expressions and escapes.
|
|
4
|
+
/** The flags of a regular expression, each at most once. */
|
|
5
|
+
const FLAGS = /^(?!.*(.).*\1)[dgimsuvy]*$/;
|
|
4
6
|
export class LiteralLexer extends LexerBase {
|
|
7
|
+
/**
|
|
8
|
+
* `/ab+c/gi`: the pattern goes up to a `/` that is not escaped or inside `[...]`, on one line,
|
|
9
|
+
* as in JS. JS checks the pattern when it loads the module, so an invalid one is an error here.
|
|
10
|
+
*/
|
|
11
|
+
scanRegExp(start) {
|
|
12
|
+
const t = this.text;
|
|
13
|
+
let pos = start + 1;
|
|
14
|
+
let inClass = false;
|
|
15
|
+
while (pos < t.length && t[pos] !== '\n' && (inClass || t[pos] !== '/')) {
|
|
16
|
+
if (t[pos] === '\\' && t[pos + 1] !== '\n')
|
|
17
|
+
pos++;
|
|
18
|
+
else if (t[pos] === '[')
|
|
19
|
+
inClass = true;
|
|
20
|
+
else if (t[pos] === ']')
|
|
21
|
+
inClass = false;
|
|
22
|
+
pos++;
|
|
23
|
+
}
|
|
24
|
+
const pattern = t.slice(start + 1, pos);
|
|
25
|
+
if (t[pos] !== '/') {
|
|
26
|
+
this.error('unterminated regular expression: end it with "/"', start, pos);
|
|
27
|
+
this.tokens.push({
|
|
28
|
+
kind: 'RegExp',
|
|
29
|
+
text: t.slice(start, pos),
|
|
30
|
+
value: pattern,
|
|
31
|
+
start,
|
|
32
|
+
end: pos,
|
|
33
|
+
});
|
|
34
|
+
this.pos = pos;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
IDENTIFIER.lastIndex = pos + 1;
|
|
38
|
+
const flags = IDENTIFIER.exec(t)?.[0] ?? '';
|
|
39
|
+
const end = pos + 1 + flags.length;
|
|
40
|
+
this.tokens.push({ kind: 'RegExp', text: t.slice(start, end), value: pattern, start, end });
|
|
41
|
+
this.pos = end;
|
|
42
|
+
if (!FLAGS.test(flags) || (flags.includes('u') && flags.includes('v'))) {
|
|
43
|
+
this.error(`invalid flags "${flags}" of a regular expression: each of d, g, i, m, s, u, v and y goes once, and not u with v`, pos + 1, end);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
new RegExp(pattern, flags);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
// "Invalid regular expression: /(/: Unterminated group" → "unterminated group".
|
|
51
|
+
const reason = error.message.replace(/^.*: /, '');
|
|
52
|
+
this.error(`invalid regular expression: ${reason.charAt(0).toLowerCase()}${reason.slice(1)}`, start, end);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
5
55
|
scanNumber(start) {
|
|
6
56
|
const t = this.text;
|
|
7
57
|
let pos = start;
|
package/dist/lexer/markup.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { LiteralLexer } from "./literals.js";
|
|
2
|
-
import {
|
|
2
|
+
import { JSX_NAME, decodeEntities } from "./tables.js";
|
|
3
3
|
// Markup: where an element starts, tags with their attributes, and text content.
|
|
4
4
|
export class MarkupLexer extends LiteralLexer {
|
|
5
5
|
/** `<` starts markup where a value is expected and is "less than" after a value. */
|
|
6
6
|
startsElement() {
|
|
7
|
-
|
|
8
|
-
if (last && ENDS_VALUE.has(last.kind))
|
|
7
|
+
if (this.lastEndsValue())
|
|
9
8
|
return false;
|
|
10
9
|
// `chan<number>(10)` makes a channel: its `<` opens the type of the values.
|
|
11
|
-
if (
|
|
10
|
+
if (this.tokens.at(-1)?.kind === 'chan')
|
|
12
11
|
return false;
|
|
13
12
|
const next = this.text[this.pos + 1];
|
|
14
13
|
return next === '>' || (next !== undefined && /^[\p{ID_Start}$_]$/u.test(next));
|
package/dist/lexer/tables.js
CHANGED
|
@@ -8,6 +8,7 @@ export const ENDS_STATEMENT = new Set([
|
|
|
8
8
|
'Number',
|
|
9
9
|
'BigInt',
|
|
10
10
|
'String',
|
|
11
|
+
'RegExp',
|
|
11
12
|
'Template',
|
|
12
13
|
'TemplateTail',
|
|
13
14
|
'true',
|
|
@@ -34,6 +35,7 @@ export const ENDS_VALUE = new Set([
|
|
|
34
35
|
'Number',
|
|
35
36
|
'BigInt',
|
|
36
37
|
'String',
|
|
38
|
+
'RegExp',
|
|
37
39
|
'Template',
|
|
38
40
|
'TemplateTail',
|
|
39
41
|
'true',
|
package/dist/lexer/token.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const KEYWORDS: readonly ["func", "comp", "go", "chan", "return", "let", "const", "type", "interface", "class", "extends", "new", "this", "super", "if", "else", "for", "in", "break", "continue", "switch", "case", "default", "defer", "try", "catch", "finally", "throw", "import", "export", "null", "true", "false", "typeof", "instanceof", "async", "await"
|
|
1
|
+
export declare const KEYWORDS: readonly ["func", "comp", "go", "chan", "return", "let", "const", "type", "interface", "class", "extends", "new", "this", "super", "if", "else", "for", "in", "break", "continue", "switch", "case", "default", "defer", "try", "catch", "finally", "throw", "import", "export", "null", "true", "false", "typeof", "instanceof", "async", "await"];
|
|
2
2
|
export declare const PUNCTUATORS: readonly ["{", "}", "(", ")", "[", "]", ";", ",", ":", ".", "...", "?", "?.", "??", "=>", "=", "+=", "-=", "*=", "/=", "%=", "**=", "&=", "|=", "^=", "<<=", ">>=", ">>>=", "&&=", "||=", "??=", "==", "!=", "<", "<-", ">", "<=", ">=", "+", "-", "*", "/", "%", "**", "++", "--", "&", "|", "^", "~", "<<", ">>", ">>>", "&&", "||", "!", "@"];
|
|
3
3
|
export type Keyword = (typeof KEYWORDS)[number];
|
|
4
4
|
export type Punctuator = (typeof PUNCTUATORS)[number];
|
|
@@ -7,9 +7,10 @@ export type Punctuator = (typeof PUNCTUATORS)[number];
|
|
|
7
7
|
* substitutions: `a${x}b${y}c` becomes TemplateHead("a") x TemplateMiddle("b") y TemplateTail("c"),
|
|
8
8
|
* and a template without substitutions is a single Template token. In markup, JsxText is the text
|
|
9
9
|
* between tags and JsxString an attribute value in quotes; both have HTML entities decoded. CssText is
|
|
10
|
-
* the raw text of a `style { ... }` block between the values from code.
|
|
10
|
+
* the raw text of a `style { ... }` block between the values from code. RegExp is `/ab+c/g`, whose
|
|
11
|
+
* value is the pattern as it is written, without the slashes and the flags.
|
|
11
12
|
*/
|
|
12
|
-
export type StringKind = 'String' | 'Template' | 'TemplateHead' | 'TemplateMiddle' | 'TemplateTail' | 'JsxText' | 'JsxString' | 'CssText';
|
|
13
|
+
export type StringKind = 'String' | 'Template' | 'TemplateHead' | 'TemplateMiddle' | 'TemplateTail' | 'JsxText' | 'JsxString' | 'CssText' | 'RegExp';
|
|
13
14
|
/**
|
|
14
15
|
* Tokens of markup such as `<a href="/">text</a>`: JsxTagOpen `<`, JsxCloseTagOpen `</`, JsxName
|
|
15
16
|
* (tag and attribute names, which may contain `-` and `:`), JsxTagEnd `>` and JsxSelfClose `/>`.
|