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
|
@@ -11,6 +11,8 @@ export interface ModuleExports {
|
|
|
11
11
|
decorators?: Map<string, DecoratorInfo>;
|
|
12
12
|
/** `export comp`: components are used as tags, not as values. */
|
|
13
13
|
components?: Map<string, ComponentInfo>;
|
|
14
|
+
/** `export state`: other modules read it, and change it only with the functions of its module. */
|
|
15
|
+
shared?: Set<string>;
|
|
14
16
|
}
|
|
15
17
|
/** What `importModule` found: the module's exports, an error for the import, or nothing (untyped). */
|
|
16
18
|
export type ImportResult = {
|
|
@@ -64,6 +66,8 @@ export interface CheckResult {
|
|
|
64
66
|
declarations: ModuleExports;
|
|
65
67
|
/** Types of checked expressions, for code generation (e.g. how to insert element children). */
|
|
66
68
|
types: WeakMap<ast.Expression, Type>;
|
|
69
|
+
/** The data classes that the module declares or imports, by their names here. */
|
|
70
|
+
dataClasses: Set<string>;
|
|
67
71
|
/** With the `completion` option: what can be written at the cursor, if the check reached it. */
|
|
68
72
|
completion?: CompletionResult;
|
|
69
73
|
}
|
|
@@ -78,6 +82,17 @@ export interface Completion {
|
|
|
78
82
|
kind: 'variable' | 'constant' | 'function' | 'class' | 'component' | 'type' | 'property' | 'method' | 'keyword' | 'tag' | 'attribute';
|
|
79
83
|
/** The type, as Rook writes it. */
|
|
80
84
|
detail?: string;
|
|
85
|
+
/** A name exported by another module of the package: choosing it imports it (auto-import.ts). */
|
|
86
|
+
import?: {
|
|
87
|
+
specifier: string;
|
|
88
|
+
edit: TextEdit;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** A change of the text of a module: what is between the offsets becomes `text`. */
|
|
92
|
+
export interface TextEdit {
|
|
93
|
+
start: number;
|
|
94
|
+
end: number;
|
|
95
|
+
text: string;
|
|
81
96
|
}
|
|
82
97
|
export type BindingKind = 'let' | 'const' | 'state' | 'derived' | 'ref' | 'param' | 'prop' | 'function' | 'class' | 'import' | 'loop' | 'catch' | 'builtin' | 'component';
|
|
83
98
|
export interface Binding {
|
|
@@ -87,6 +102,8 @@ export interface Binding {
|
|
|
87
102
|
type: Type | null;
|
|
88
103
|
/** For components, which exist only at compile time and are used as tags. */
|
|
89
104
|
component?: ComponentInfo;
|
|
105
|
+
/** State of another module, `state items` there, which is read-only here: its module's path. */
|
|
106
|
+
shared?: string;
|
|
90
107
|
/**
|
|
91
108
|
* `const user, err = loadUser(id)` of `(User, error)`: the error has the values that are not null
|
|
92
109
|
* once it is null, and each of them has the error (error-results.ts).
|
|
@@ -100,6 +117,7 @@ export interface ComponentInfo {
|
|
|
100
117
|
props: Map<string, {
|
|
101
118
|
type: Type;
|
|
102
119
|
optional: boolean;
|
|
120
|
+
bind?: true;
|
|
103
121
|
}>;
|
|
104
122
|
/** Names from the module that the component's code uses, computed when first needed. */
|
|
105
123
|
freeNames: Set<string> | null;
|
|
@@ -147,6 +165,8 @@ export interface DecoratorInfo {
|
|
|
147
165
|
} | null;
|
|
148
166
|
/** The decorators after `needs` that exist; they are applied above it. */
|
|
149
167
|
needed: DecoratorInfo[];
|
|
168
|
+
/** The decorators after `includes` that exist: applied with it, above its own body. */
|
|
169
|
+
included: DecoratorInfo[];
|
|
150
170
|
/**
|
|
151
171
|
* For an exported decorator: the names of its module that its code uses, which other modules get
|
|
152
172
|
* through hidden exports, and the types of its expressions, for the code generator there.
|
|
@@ -157,9 +177,15 @@ export interface DecoratorInfo {
|
|
|
157
177
|
inline: InlinePackage | null;
|
|
158
178
|
}
|
|
159
179
|
export interface PublicMember {
|
|
160
|
-
kind: 'state' | 'derived' | 'const' | 'func';
|
|
180
|
+
kind: 'state' | 'derived' | 'const' | 'ref' | 'func';
|
|
161
181
|
type: Type;
|
|
162
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* The decorators applied with those they include, which come before them: `@shop` of
|
|
185
|
+
* `dec shop() includes visible, cart` gives visible, cart, shop. A cycle of includes is reported
|
|
186
|
+
* where the decorators are declared; here it stops.
|
|
187
|
+
*/
|
|
188
|
+
export declare function withIncluded(decorators: readonly DecoratorInfo[], seen?: ReadonlySet<DecoratorInfo>): DecoratorInfo[];
|
|
163
189
|
/** A `type` alias, resolved when first used. */
|
|
164
190
|
export interface AliasEntry {
|
|
165
191
|
kind: 'alias';
|
|
@@ -192,11 +218,21 @@ export interface ClassContext {
|
|
|
192
218
|
isStatic: boolean;
|
|
193
219
|
}
|
|
194
220
|
/**
|
|
195
|
-
*
|
|
196
|
-
*
|
|
221
|
+
* A variable, or a path of data fields from it that is narrowed like one: `order.delivery` is the
|
|
222
|
+
* binding of `order` with the path `"delivery"`. The path of the variable itself is empty.
|
|
223
|
+
*/
|
|
224
|
+
export interface Place {
|
|
225
|
+
binding: Binding;
|
|
226
|
+
path: string;
|
|
227
|
+
}
|
|
228
|
+
/** The same object for the same variable and path, so that it is a key of a `Flow`. */
|
|
229
|
+
export declare function placeOf(binding: Binding, path?: string): Place;
|
|
230
|
+
/**
|
|
231
|
+
* Types of variables and paths narrowed by the code before the current point, e.g. `?User` →
|
|
232
|
+
* `User` after `if user == null { return }`.
|
|
197
233
|
*/
|
|
198
|
-
export type Flow = Map<
|
|
199
|
-
export type Narrowing = [
|
|
234
|
+
export type Flow = Map<Place, Type>;
|
|
235
|
+
export type Narrowing = [Place, Type][];
|
|
200
236
|
export declare const NARROWABLE: ReadonlySet<BindingKind>;
|
|
201
237
|
/** Built-in globals. With a library, the untyped ones and the DOM types come from it instead. */
|
|
202
238
|
export declare function globalScope(library: Library | undefined): Scope;
|
package/dist/checker/context.js
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { GLOBAL_TYPES, GLOBAL_VALUES, LIBRARY_TYPES } from "./builtins.js";
|
|
2
2
|
import {} from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* The decorators applied with those they include, which come before them: `@shop` of
|
|
5
|
+
* `dec shop() includes visible, cart` gives visible, cart, shop. A cycle of includes is reported
|
|
6
|
+
* where the decorators are declared; here it stops.
|
|
7
|
+
*/
|
|
8
|
+
export function withIncluded(decorators, seen = new Set()) {
|
|
9
|
+
return decorators.flatMap((each) => seen.has(each) ? [] : [...withIncluded(each.included, new Set([...seen, each])), each]);
|
|
10
|
+
}
|
|
3
11
|
export class Scope {
|
|
4
12
|
parent;
|
|
5
13
|
values = new Map();
|
|
@@ -8,6 +16,21 @@ export class Scope {
|
|
|
8
16
|
this.parent = parent;
|
|
9
17
|
}
|
|
10
18
|
}
|
|
19
|
+
const places = new WeakMap();
|
|
20
|
+
/** The same object for the same variable and path, so that it is a key of a `Flow`. */
|
|
21
|
+
export function placeOf(binding, path = '') {
|
|
22
|
+
let byPath = places.get(binding);
|
|
23
|
+
if (!byPath) {
|
|
24
|
+
byPath = new Map();
|
|
25
|
+
places.set(binding, byPath);
|
|
26
|
+
}
|
|
27
|
+
let place = byPath.get(path);
|
|
28
|
+
if (!place) {
|
|
29
|
+
place = { binding, path };
|
|
30
|
+
byPath.set(path, place);
|
|
31
|
+
}
|
|
32
|
+
return place;
|
|
33
|
+
}
|
|
11
34
|
export const NARROWABLE = new Set([
|
|
12
35
|
'let',
|
|
13
36
|
'const',
|
|
@@ -1,25 +1,31 @@
|
|
|
1
1
|
import type * as ast from '../ast.ts';
|
|
2
|
-
import { type Binding, type
|
|
2
|
+
import { type Binding, type Narrowing } from './context.ts';
|
|
3
3
|
import { StatementChecker } from './statements.ts';
|
|
4
4
|
export declare abstract class ControlFlowChecker extends StatementChecker {
|
|
5
5
|
protected checkIf(node: ast.IfStatement): void;
|
|
6
6
|
protected checkFor(node: ast.ForStatement): void;
|
|
7
7
|
protected checkSimpleStatement(node: ast.SimpleStatement): void;
|
|
8
|
+
/**
|
|
9
|
+
* `if const v = f(); v > 0 { }`: the variables of the initializer are in a scope of their own,
|
|
10
|
+
* around every branch. Returns whether `check` checked the statement inside it.
|
|
11
|
+
*/
|
|
12
|
+
private checkWithInit;
|
|
8
13
|
protected checkSwitch(node: ast.SwitchStatement): void;
|
|
9
14
|
/**
|
|
10
15
|
* `switch filter { case "all": ... default: ... }`: in a case the discriminant has the literals
|
|
11
16
|
* of its tests, in `default` the literals of no case.
|
|
12
17
|
*/
|
|
13
|
-
protected narrowCase(node: ast.SwitchStatement, switchCase: ast.SwitchCase
|
|
18
|
+
protected narrowCase(node: ast.SwitchStatement, switchCase: ast.SwitchCase): Narrowing;
|
|
14
19
|
protected checkTry(node: ast.TryStatement): void;
|
|
15
20
|
protected checkCondition(node: ast.Expression): void;
|
|
16
|
-
/** Variables whose type is narrowed when `node` evaluates to `assumeTrue`. */
|
|
21
|
+
/** Variables and paths whose type is narrowed when `node` evaluates to `assumeTrue`. */
|
|
17
22
|
protected narrow(node: ast.Expression, assumeTrue: boolean): Narrowing;
|
|
18
23
|
/** `x instanceof Date`: an instance of the class when true, the rest of a union when false. */
|
|
19
24
|
protected narrowInstanceof(left: ast.Expression, right: ast.Expression, assumeTrue: boolean): Narrowing;
|
|
20
25
|
protected nullError(node: ast.Expression): void;
|
|
21
26
|
protected narrowableBinding(node: ast.Expression): Binding | undefined;
|
|
22
|
-
/** An assignment to a variable ends its narrowing. */
|
|
27
|
+
/** An assignment to a variable ends its narrowing; one to a path, that of the paths it changes. */
|
|
23
28
|
protected forget(target: ast.Expression): void;
|
|
24
|
-
|
|
29
|
+
/** Ends the narrowing of what `node` assigns: before a loop, or a statement with several ways. */
|
|
30
|
+
protected dropNarrowing(node: ast.Node): void;
|
|
25
31
|
}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import { assignedNames } from "../names.js";
|
|
2
|
-
import { NARROWABLE } from "./context.js";
|
|
3
|
-
import { narrowByTypeof, literalValue, withoutLiteral, withNarrowing, mergeFlows, leaves, } from "./flow.js";
|
|
1
|
+
import { assignedNames, assignedPaths, pathOf } from "../names.js";
|
|
2
|
+
import { NARROWABLE, placeOf } from "./context.js";
|
|
3
|
+
import { narrowByTypeof, literalValue, withoutLiteral, withNarrowing, mergeFlows, leaves, forgetWritten, withoutAssigned, } from "./flow.js";
|
|
4
4
|
import { instanceTypeOf } from "./helpers.js";
|
|
5
5
|
import { StatementChecker } from "./statements.js";
|
|
6
6
|
import { ANY, BOOL, isAssignable, isComparable, isNullable, isSubclass, literal, nonNull, NULL, typeToString, union, unionMembers, widenLiterals, } from "./types.js";
|
|
7
|
-
// if, for, switch and try, and how conditions narrow the types of variables in the
|
|
7
|
+
// if, for, switch and try, and how conditions narrow the types of variables and paths in the
|
|
8
|
+
// branches.
|
|
8
9
|
export class ControlFlowChecker extends StatementChecker {
|
|
9
10
|
checkIf(node) {
|
|
11
|
+
if (this.checkWithInit(node.init, () => this.checkIf({ ...node, init: null })))
|
|
12
|
+
return;
|
|
10
13
|
this.checkCondition(node.condition);
|
|
11
14
|
const before = this.flow;
|
|
12
15
|
// Both are found from the flow before the `if`, not from the end of a branch.
|
|
@@ -37,8 +40,8 @@ export class ControlFlowChecker extends StatementChecker {
|
|
|
37
40
|
this.withScope(() => {
|
|
38
41
|
if (node.init)
|
|
39
42
|
this.checkSimpleStatement(node.init);
|
|
40
|
-
// Variables assigned in the loop may change between iterations.
|
|
41
|
-
this.dropNarrowing(
|
|
43
|
+
// Variables and paths assigned in the loop may change between iterations.
|
|
44
|
+
this.dropNarrowing(node);
|
|
42
45
|
const entry = this.flow;
|
|
43
46
|
if (node.condition)
|
|
44
47
|
this.checkCondition(node.condition);
|
|
@@ -52,9 +55,24 @@ export class ControlFlowChecker extends StatementChecker {
|
|
|
52
55
|
checkSimpleStatement(node) {
|
|
53
56
|
this.checkStatement(node);
|
|
54
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* `if const v = f(); v > 0 { }`: the variables of the initializer are in a scope of their own,
|
|
60
|
+
* around every branch. Returns whether `check` checked the statement inside it.
|
|
61
|
+
*/
|
|
62
|
+
checkWithInit(init, check) {
|
|
63
|
+
if (init === null)
|
|
64
|
+
return false;
|
|
65
|
+
this.withScope(() => {
|
|
66
|
+
this.checkStatement(init);
|
|
67
|
+
check();
|
|
68
|
+
});
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
55
71
|
checkSwitch(node) {
|
|
72
|
+
if (this.checkWithInit(node.init, () => this.checkSwitch({ ...node, init: null })))
|
|
73
|
+
return;
|
|
56
74
|
const discriminant = node.discriminant ? this.checkValue(node.discriminant) : null;
|
|
57
|
-
this.dropNarrowing(
|
|
75
|
+
this.dropNarrowing(node);
|
|
58
76
|
const entry = this.flow;
|
|
59
77
|
for (const switchCase of node.cases) {
|
|
60
78
|
this.flow = entry;
|
|
@@ -72,7 +90,7 @@ export class ControlFlowChecker extends StatementChecker {
|
|
|
72
90
|
? switchCase.tests.length === 1
|
|
73
91
|
? this.narrow(switchCase.tests[0], true)
|
|
74
92
|
: []
|
|
75
|
-
: this.narrowCase(node, switchCase
|
|
93
|
+
: this.narrowCase(node, switchCase);
|
|
76
94
|
this.flow = withNarrowing(entry, narrowing);
|
|
77
95
|
this.checkBlock(switchCase.body);
|
|
78
96
|
}
|
|
@@ -82,18 +100,18 @@ export class ControlFlowChecker extends StatementChecker {
|
|
|
82
100
|
* `switch filter { case "all": ... default: ... }`: in a case the discriminant has the literals
|
|
83
101
|
* of its tests, in `default` the literals of no case.
|
|
84
102
|
*/
|
|
85
|
-
narrowCase(node, switchCase
|
|
86
|
-
const
|
|
87
|
-
if (!
|
|
103
|
+
narrowCase(node, switchCase) {
|
|
104
|
+
const target = node.discriminant ? this.narrowable(node.discriminant) : undefined;
|
|
105
|
+
if (!target)
|
|
88
106
|
return [];
|
|
89
|
-
const current =
|
|
107
|
+
const { place, type: current } = target;
|
|
90
108
|
if (!unionMembers(nonNull(current)).some((member) => member.kind === 'literal'))
|
|
91
109
|
return [];
|
|
92
110
|
if (switchCase.tests.length > 0) {
|
|
93
111
|
const values = switchCase.tests.map(literalValue);
|
|
94
112
|
if (values.some((value) => value === undefined))
|
|
95
113
|
return [];
|
|
96
|
-
return [[
|
|
114
|
+
return [[place, union(values.map((value) => literal(value)))]];
|
|
97
115
|
}
|
|
98
116
|
let rest = current;
|
|
99
117
|
for (const other of node.cases) {
|
|
@@ -103,10 +121,10 @@ export class ControlFlowChecker extends StatementChecker {
|
|
|
103
121
|
rest = withoutLiteral(rest, value);
|
|
104
122
|
}
|
|
105
123
|
}
|
|
106
|
-
return [[
|
|
124
|
+
return [[place, rest]];
|
|
107
125
|
}
|
|
108
126
|
checkTry(node) {
|
|
109
|
-
this.dropNarrowing(
|
|
127
|
+
this.dropNarrowing(node);
|
|
110
128
|
const entry = this.flow;
|
|
111
129
|
this.flow = new Map(entry);
|
|
112
130
|
this.checkBlock(node.block.body);
|
|
@@ -140,7 +158,7 @@ export class ControlFlowChecker extends StatementChecker {
|
|
|
140
158
|
: '';
|
|
141
159
|
this.error(`condition must be bool, not ${typeToString(type)}${hint}`, node);
|
|
142
160
|
}
|
|
143
|
-
/** Variables whose type is narrowed when `node` evaluates to `assumeTrue`. */
|
|
161
|
+
/** Variables and paths whose type is narrowed when `node` evaluates to `assumeTrue`. */
|
|
144
162
|
narrow(node, assumeTrue) {
|
|
145
163
|
if (node.kind === 'UnaryExpression' && node.operator === '!') {
|
|
146
164
|
return this.narrow(node.argument, !assumeTrue);
|
|
@@ -166,17 +184,21 @@ export class ControlFlowChecker extends StatementChecker {
|
|
|
166
184
|
// `x != null` when true, `x == null` when false: `x` is not null.
|
|
167
185
|
if ((operator === '!=' && assumeTrue) || (operator === '==' && !assumeTrue)) {
|
|
168
186
|
const target = right.kind === 'NullLiteral' ? left : left.kind === 'NullLiteral' ? right : null;
|
|
169
|
-
const
|
|
170
|
-
if (
|
|
171
|
-
return [[
|
|
187
|
+
const found = target ? this.narrowable(target) : undefined;
|
|
188
|
+
if (found)
|
|
189
|
+
return [[found.place, nonNull(found.type)]];
|
|
172
190
|
}
|
|
173
191
|
// `err == null` when true, `err != null` when false: the values returned with `err` are not
|
|
174
192
|
// null (error-results.ts).
|
|
175
193
|
if ((operator === '==' && assumeTrue) || (operator === '!=' && !assumeTrue)) {
|
|
176
194
|
const target = right.kind === 'NullLiteral' ? left : left.kind === 'NullLiteral' ? right : null;
|
|
177
195
|
const guards = target ? this.narrowableBinding(target)?.guards : undefined;
|
|
178
|
-
if (guards)
|
|
179
|
-
return guards.map((value) =>
|
|
196
|
+
if (guards) {
|
|
197
|
+
return guards.map((value) => {
|
|
198
|
+
const place = placeOf(value);
|
|
199
|
+
return [place, nonNull(this.flow.get(place) ?? value.type)];
|
|
200
|
+
});
|
|
201
|
+
}
|
|
180
202
|
}
|
|
181
203
|
if (operator === 'instanceof')
|
|
182
204
|
return this.narrowInstanceof(left, right, assumeTrue);
|
|
@@ -191,41 +213,41 @@ export class ControlFlowChecker extends StatementChecker {
|
|
|
191
213
|
? [right, left]
|
|
192
214
|
: [null, null];
|
|
193
215
|
if (check && tag?.kind === 'StringLiteral') {
|
|
194
|
-
const
|
|
195
|
-
if (!
|
|
216
|
+
const found = this.narrowable(check.argument);
|
|
217
|
+
if (!found)
|
|
196
218
|
return [];
|
|
197
|
-
const type = narrowByTypeof(
|
|
198
|
-
return type ? [[
|
|
219
|
+
const type = narrowByTypeof(found.type, tag.value, equal);
|
|
220
|
+
return type ? [[found.place, type]] : [];
|
|
199
221
|
}
|
|
200
222
|
// `filter == "all"`: narrows a type with literals in it.
|
|
201
223
|
const value = literalValue(right) ?? literalValue(left);
|
|
202
224
|
const target = literalValue(right) !== undefined ? left : right;
|
|
203
|
-
const
|
|
204
|
-
if (value === undefined || !
|
|
225
|
+
const found = value === undefined ? undefined : this.narrowable(target);
|
|
226
|
+
if (value === undefined || !found)
|
|
205
227
|
return [];
|
|
206
|
-
const current =
|
|
228
|
+
const { place, type: current } = found;
|
|
207
229
|
if (!unionMembers(nonNull(current)).some((member) => member.kind === 'literal'))
|
|
208
230
|
return [];
|
|
209
|
-
return [[
|
|
231
|
+
return [[place, equal ? literal(value) : withoutLiteral(current, value)]];
|
|
210
232
|
}
|
|
211
233
|
/** `x instanceof Date`: an instance of the class when true, the rest of a union when false. */
|
|
212
234
|
narrowInstanceof(left, right, assumeTrue) {
|
|
213
|
-
const
|
|
235
|
+
const found = this.narrowable(left);
|
|
214
236
|
const classType = this.typeOfChecked(right);
|
|
215
237
|
const instance = instanceTypeOf(classType);
|
|
216
|
-
if (!
|
|
238
|
+
if (!found || !instance)
|
|
217
239
|
return [];
|
|
218
|
-
const current =
|
|
240
|
+
const { place, type: current } = found;
|
|
219
241
|
const members = unionMembers(nonNull(current));
|
|
220
242
|
if (assumeTrue) {
|
|
221
243
|
const kept = members.filter((member) => isAssignable(member, instance));
|
|
222
|
-
return [[
|
|
244
|
+
return [[place, kept.length > 0 ? union(kept) : instance]];
|
|
223
245
|
}
|
|
224
246
|
// A class keeps what is not its subclass; a DOM interface what is not assignable to it.
|
|
225
247
|
const kept = members.filter((member) => classType.kind === 'classValue'
|
|
226
248
|
? !(member.kind === 'class' && isSubclass(member.info, classType.info))
|
|
227
249
|
: !isAssignable(member, instance));
|
|
228
|
-
return [[
|
|
250
|
+
return [[place, union(isNullable(current) ? [...kept, NULL] : kept)]];
|
|
229
251
|
}
|
|
230
252
|
nullError(node) {
|
|
231
253
|
const name = node.kind === 'Identifier' ? node.name : null;
|
|
@@ -242,13 +264,16 @@ export class ControlFlowChecker extends StatementChecker {
|
|
|
242
264
|
const binding = this.lookupValue(node.name);
|
|
243
265
|
return binding && NARROWABLE.has(binding.kind) ? binding : undefined;
|
|
244
266
|
}
|
|
245
|
-
/** An assignment to a variable ends its narrowing. */
|
|
267
|
+
/** An assignment to a variable ends its narrowing; one to a path, that of the paths it changes. */
|
|
246
268
|
forget(target) {
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
269
|
+
const path = pathOf(target);
|
|
270
|
+
const binding = path ? this.lookupValue(path[0]) : undefined;
|
|
271
|
+
if (path && binding && NARROWABLE.has(binding.kind)) {
|
|
272
|
+
forgetWritten(this.flow, binding, path.slice(1).join('.'), (place, field) => this.isTagOf(place, field));
|
|
273
|
+
}
|
|
250
274
|
}
|
|
251
|
-
|
|
252
|
-
|
|
275
|
+
/** Ends the narrowing of what `node` assigns: before a loop, or a statement with several ways. */
|
|
276
|
+
dropNarrowing(node) {
|
|
277
|
+
this.flow = withoutAssigned(this.flow, assignedNames(node), assignedPaths(node), (place, field) => this.isTagOf(place, field));
|
|
253
278
|
}
|
|
254
279
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type * as ast from '../ast.ts';
|
|
2
|
-
import {
|
|
2
|
+
import { SharedStateChecker } from './shared-state.ts';
|
|
3
3
|
import { type FunctionType, type ObjectType, type Type, type TypeParam } from './types.ts';
|
|
4
|
-
export declare abstract class DeclarationChecker extends
|
|
4
|
+
export declare abstract class DeclarationChecker extends SharedStateChecker {
|
|
5
5
|
/**
|
|
6
6
|
* Declares the names of a statement list first (so functions, classes and types can be used
|
|
7
7
|
* before their declaration), then checks the statements in order. Function and method bodies are
|
|
@@ -3,12 +3,12 @@ import { isIterator } from "../iterators.js";
|
|
|
3
3
|
import { collectValueNames } from "../names.js";
|
|
4
4
|
import { recursiveComponents } from "../recursion.js";
|
|
5
5
|
import { Scope } from "./context.js";
|
|
6
|
-
import {
|
|
6
|
+
import { SharedStateChecker } from "./shared-state.js";
|
|
7
7
|
import { awaited, isPromise, promiseOf } from "./promise.js";
|
|
8
8
|
import { createClass, func, typeToString, UNKNOWN, } from "./types.js";
|
|
9
9
|
// Declarations of a list of statements: imports, types, functions, components, decorators and
|
|
10
10
|
// classes, declared before the statements are checked, so that they can refer to each other.
|
|
11
|
-
export class DeclarationChecker extends
|
|
11
|
+
export class DeclarationChecker extends SharedStateChecker {
|
|
12
12
|
/**
|
|
13
13
|
* Declares the names of a statement list first (so functions, classes and types can be used
|
|
14
14
|
* before their declaration), then checks the statements in order. Function and method bodies are
|
|
@@ -34,6 +34,7 @@ export class DeclarationChecker extends ImportChecker {
|
|
|
34
34
|
break;
|
|
35
35
|
case 'ClassDeclaration': {
|
|
36
36
|
const info = createClass(statement.name.name);
|
|
37
|
+
info.data = statement.data;
|
|
37
38
|
info.typeParams = this.createTypeParams(statement.typeParams);
|
|
38
39
|
this.declareType(statement.name, info.instance);
|
|
39
40
|
this.declareValue(statement.name, 'class', info.value);
|
|
@@ -94,6 +95,7 @@ export class DeclarationChecker extends ImportChecker {
|
|
|
94
95
|
freeNames: null,
|
|
95
96
|
wrapper: null,
|
|
96
97
|
needed: [],
|
|
98
|
+
included: [],
|
|
97
99
|
moduleNames: [],
|
|
98
100
|
expressionTypes: null,
|
|
99
101
|
inline: null,
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type * as ast from '../ast.ts';
|
|
2
|
+
import { TopicChecker } from './topics.ts';
|
|
3
|
+
import { type Type } from './types.ts';
|
|
4
|
+
export declare abstract class DecodeChecker extends TopicChecker {
|
|
5
|
+
protected checkDecode(node: ast.DecodeExpression): Type;
|
|
6
|
+
/** Why decode cannot take a value of the type: it is neither JSON text nor a value from JS. */
|
|
7
|
+
private notDecodable;
|
|
8
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { isUntyped } from "./helpers.js";
|
|
2
|
+
import { TopicChecker } from "./topics.js";
|
|
3
|
+
import { isText, notDecoded } from "./json.js";
|
|
4
|
+
import { ERROR, typedArrayOf, typeToString } from "./types.js";
|
|
5
|
+
// `decode<User>(body)`: the types are erased, so only the compiler knows what a User is. It writes
|
|
6
|
+
// the type into the JS as data (codegen/decode.ts), and the runtime checks JSON text, or a value
|
|
7
|
+
// from JS, against it when the program runs (runtime/decode.js). So the type must be one that JSON
|
|
8
|
+
// can hold (json.ts). The argument is JSON text if it is a string, and a value from JS if it is any.
|
|
9
|
+
export class DecodeChecker extends TopicChecker {
|
|
10
|
+
checkDecode(node) {
|
|
11
|
+
const type = this.resolveType(node.type);
|
|
12
|
+
const reason = notDecoded(type);
|
|
13
|
+
if (reason !== null)
|
|
14
|
+
this.error(`cannot decode ${typeToString(type)}: ${reason}`, node.type);
|
|
15
|
+
const argument = this.checkValue(node.argument);
|
|
16
|
+
if (!isUntyped(argument) && !isText(argument)) {
|
|
17
|
+
this.error(this.notDecodable(argument), node.argument);
|
|
18
|
+
}
|
|
19
|
+
return { kind: 'tuple', types: [type, ERROR] };
|
|
20
|
+
}
|
|
21
|
+
/** Why decode cannot take a value of the type: it is neither JSON text nor a value from JS. */
|
|
22
|
+
notDecodable(type) {
|
|
23
|
+
const prefix = `decode takes JSON text, a string, or a value of type any from JS, not ${typeToString(type)}`;
|
|
24
|
+
if (type.kind === 'nullable' && isText(type.type)) {
|
|
25
|
+
return `${prefix}: the text may be null, so check it first, e.g. "if text != null"`;
|
|
26
|
+
}
|
|
27
|
+
if (type.kind === 'object' && (typedArrayOf(type) === 'Uint8Array' || type.name === 'Buffer')) {
|
|
28
|
+
return `${prefix}: make the text of the bytes first, e.g. decode<User>(string(data))`;
|
|
29
|
+
}
|
|
30
|
+
return `${prefix}; its type is known already`;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -20,6 +20,10 @@ export class DecoratorExportChecker extends DecoratorWrapperChecker {
|
|
|
20
20
|
// Other modules can read the variables of this one, but not assign them.
|
|
21
21
|
const assigned = assignedNames(node.body);
|
|
22
22
|
for (const used of info.moduleNames) {
|
|
23
|
+
if (this.moduleScope.values.get(used)?.kind === 'state') {
|
|
24
|
+
this.error(`@${name} is exported, so its code cannot read "${used}", state of its module, yet: read it in a component of the module and pass it to @${name} as an argument`, node.name);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
23
27
|
if (!assigned.has(used))
|
|
24
28
|
continue;
|
|
25
29
|
this.error(`@${name} is exported, so it cannot change "${used}" of its module: other modules can only read it; change it in a function of the module`, node.name);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { DecoratorInfo } from './context.ts';
|
|
2
|
+
import { DecoratorChecker } from './decorators.ts';
|
|
3
|
+
export declare abstract class DecoratorIncludeChecker extends DecoratorChecker {
|
|
4
|
+
protected resolveDecoratorParams(info: DecoratorInfo): void;
|
|
5
|
+
/** The decorators it includes are checked before it: see orderByNeeds. */
|
|
6
|
+
protected checkDecoratorBody(info: DecoratorInfo): void;
|
|
7
|
+
/** The public members of the decorators it includes become its own; each name comes once. */
|
|
8
|
+
private addIncludedMembers;
|
|
9
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { DecoratorChecker } from "./decorators.js";
|
|
2
|
+
import { UNKNOWN } from "./types.js";
|
|
3
|
+
// Decorators that include others, `dec shop(margin string) includes visible(margin), cart { ... }`:
|
|
4
|
+
// those are applied with it, above its own body, their arguments see its parameters, and their
|
|
5
|
+
// public members are its own for the component, `@shop.count`.
|
|
6
|
+
export class DecoratorIncludeChecker extends DecoratorChecker {
|
|
7
|
+
resolveDecoratorParams(info) {
|
|
8
|
+
super.resolveDecoratorParams(info);
|
|
9
|
+
const { node } = info;
|
|
10
|
+
const current = node.name.name;
|
|
11
|
+
const included = new Set();
|
|
12
|
+
for (const use of node.includes) {
|
|
13
|
+
const name = use.name.name;
|
|
14
|
+
const other = this.decorators.get(name);
|
|
15
|
+
if (name === current)
|
|
16
|
+
this.error(`@${name} cannot include itself`, use.name);
|
|
17
|
+
else if (included.has(name))
|
|
18
|
+
this.error(`@${name} is included twice: name it once`, use.name);
|
|
19
|
+
else if (node.needs.some((need) => need.name === name)) {
|
|
20
|
+
this.error(`@${current} both needs and includes @${name}: includes is enough`, use.name);
|
|
21
|
+
}
|
|
22
|
+
else if (!other)
|
|
23
|
+
this.error(`unknown decorator @${name}`, use.name);
|
|
24
|
+
else
|
|
25
|
+
info.included.push(other);
|
|
26
|
+
included.add(name);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** The decorators it includes are checked before it: see orderByNeeds. */
|
|
30
|
+
checkDecoratorBody(info) {
|
|
31
|
+
super.checkDecoratorBody(info);
|
|
32
|
+
const { node } = info;
|
|
33
|
+
const params = node.params.map((param, i) => [
|
|
34
|
+
param.name,
|
|
35
|
+
info.params[i] ?? UNKNOWN,
|
|
36
|
+
]);
|
|
37
|
+
for (const use of node.includes) {
|
|
38
|
+
const included = this.decorators.get(use.name.name);
|
|
39
|
+
if (included)
|
|
40
|
+
this.checkDecoratorArguments(use, included, params);
|
|
41
|
+
}
|
|
42
|
+
this.addIncludedMembers(info);
|
|
43
|
+
// A module that applies it would need the code of those it includes too.
|
|
44
|
+
if (node.exported && node.includes.length > 0) {
|
|
45
|
+
const names = node.includes.map((use) => `@${use.name.name}`).join(' ');
|
|
46
|
+
this.error(`@${node.name.name} is exported, so it cannot include decorators yet: apply them before it, e.g. ${names} @${node.name.name} comp ...`, node.includes[0]);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** The public members of the decorators it includes become its own; each name comes once. */
|
|
50
|
+
addIncludedMembers(info) {
|
|
51
|
+
const current = info.node.name.name;
|
|
52
|
+
const from = new Map();
|
|
53
|
+
for (const included of info.included) {
|
|
54
|
+
const name = included.node.name.name;
|
|
55
|
+
const use = info.node.includes.find((each) => each.name.name === name);
|
|
56
|
+
for (const [member, found] of included.members) {
|
|
57
|
+
const other = from.get(member);
|
|
58
|
+
if (other !== undefined) {
|
|
59
|
+
this.error(`@${current} gets "${member}" from both @${other} and @${name}: rename one of them`, use);
|
|
60
|
+
}
|
|
61
|
+
else if (info.members.has(member)) {
|
|
62
|
+
this.error(`@${current} declares "${member}", which it also gets from @${name}: rename one of them`, use);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
info.members.set(member, found);
|
|
66
|
+
from.set(member, name);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -1,26 +1,24 @@
|
|
|
1
1
|
import type * as ast from '../ast.ts';
|
|
2
|
-
import type
|
|
3
|
-
import {
|
|
2
|
+
import { type DecoratorInfo, type PublicMember } from './context.ts';
|
|
3
|
+
import { DecoratorIncludeChecker } from './decorator-includes.ts';
|
|
4
4
|
import { type Type } from './types.ts';
|
|
5
|
-
export declare abstract class DecoratorMemberChecker extends
|
|
6
|
-
/** `@visible.show`:
|
|
5
|
+
export declare abstract class DecoratorMemberChecker extends DecoratorIncludeChecker {
|
|
6
|
+
/** `@visible.shown` or `@visible.show`: public state, a constant or a function. */
|
|
7
7
|
protected checkDecoratorMember(node: ast.DecoratorMember): Type;
|
|
8
|
-
/** `get(@visible.shown)`: public state or a constant. */
|
|
9
|
-
protected checkDecoratorGet(node: ast.DecoratorGet): Type;
|
|
10
8
|
/**
|
|
11
9
|
* A public member of a decorator applied to the component being checked, or of one that the
|
|
12
10
|
* decorator being checked needs.
|
|
13
11
|
*/
|
|
14
12
|
protected findDecoratorMember(node: ast.DecoratorMember): PublicMember | null;
|
|
15
|
-
/**
|
|
13
|
+
/** `@cart.count` in `dec cartBadge() needs cart`. */
|
|
16
14
|
protected neededMember(node: ast.DecoratorMember, decorator: ast.DecoratorDeclaration): PublicMember | null;
|
|
17
15
|
protected publicMember(node: ast.DecoratorMember, info: DecoratorInfo): PublicMember | null;
|
|
18
16
|
/**
|
|
19
|
-
* Members of a decorator are read-only outside it:
|
|
20
|
-
*
|
|
17
|
+
* Members of a decorator are read-only outside it: `@cart.count = 0`, `@cart.items[0] = x`.
|
|
18
|
+
* Returns whether `target` is one of them.
|
|
21
19
|
*/
|
|
22
20
|
protected checkDecoratorWrite(target: ast.Expression): boolean;
|
|
23
|
-
/**
|
|
21
|
+
/** `@cart.items.push(x)`: a method that changes the array. */
|
|
24
22
|
protected checkDecoratorMutation(node: ast.CallExpression): void;
|
|
25
23
|
protected readOnlyError(member: ast.DecoratorMember, node: ast.NodeBase): void;
|
|
26
24
|
/** `card.count` without `@`: `card` is not a value, but a decorator may have that name. */
|