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
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ChannelChecker, typeName } from "./channels.js";
|
|
2
|
+
import { isUntyped } from "./helpers.js";
|
|
3
|
+
import { isNullable, typeToString } from "./types.js";
|
|
4
|
+
// Signals and cancellation as channels (runtime/signals.js): `signal("SIGTERM")` gets the signals
|
|
5
|
+
// of the process, `done(request.signal)` the reason of an AbortSignal, and `abortSignal(stop)` is an
|
|
6
|
+
// AbortSignal that aborts when the channel gets a value or is closed. Their types are in
|
|
7
|
+
// builtins.ts; the names that signal() takes, the AbortSignal that done() takes and the type that
|
|
8
|
+
// abortSignal() gives, from the library if it has one, are here.
|
|
9
|
+
const SIGNAL = /^SIG[A-Z0-9]+$/;
|
|
10
|
+
export class SignalChecker extends ChannelChecker {
|
|
11
|
+
checkCall(node, callee, expected = null) {
|
|
12
|
+
const result = super.checkCall(node, callee, expected);
|
|
13
|
+
const { callee: name } = node;
|
|
14
|
+
if (name.kind !== 'Identifier' ||
|
|
15
|
+
this.lookupValue(name.name) !== this.globals.values.get(name.name)) {
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
switch (name.name) {
|
|
19
|
+
case 'signal':
|
|
20
|
+
this.checkSignalNames(node);
|
|
21
|
+
return result;
|
|
22
|
+
case 'done': {
|
|
23
|
+
const [argument] = node.arguments;
|
|
24
|
+
const type = argument && argument.kind !== 'SpreadElement' && this.checkedTypes.get(argument);
|
|
25
|
+
if (argument && type && !isUntyped(type) && typeName(type) !== 'AbortSignal') {
|
|
26
|
+
this.error(`done() takes an AbortSignal, such as request.signal, not ${typeToString(type)}${isNullable(type) ? ': check it for null first' : ''}`, argument);
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
// An AbortSignal of the library, for `fetch(url, { signal: abortSignal(stop) })`.
|
|
31
|
+
case 'abortSignal':
|
|
32
|
+
return this.options.library?.type('AbortSignal') ?? result;
|
|
33
|
+
default:
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** `signal("SIGINT", "SIGTERM")`: at least one name, and the names are those of signals. */
|
|
38
|
+
checkSignalNames(node) {
|
|
39
|
+
if (node.arguments.length === 0) {
|
|
40
|
+
this.error('signal() takes the signals to listen to, e.g. signal("SIGINT", "SIGTERM")', node);
|
|
41
|
+
}
|
|
42
|
+
for (const argument of node.arguments) {
|
|
43
|
+
if (argument.kind === 'StringLiteral' && !SIGNAL.test(argument.value)) {
|
|
44
|
+
this.error(`"${argument.value}" is not the name of a signal: they start with SIG, e.g. signal("SIGINT", "SIGTERM")`, argument);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -12,10 +12,11 @@ export declare abstract class StatementChecker extends AssignmentChecker {
|
|
|
12
12
|
*/
|
|
13
13
|
protected checkEffect(node: ast.EffectStatement): void;
|
|
14
14
|
/**
|
|
15
|
-
* `mount
|
|
16
|
-
*
|
|
15
|
+
* `mount { ... }`: a function that runs once the markup is in the document, like a handler. It
|
|
16
|
+
* cleans up with `defer`, as an effect does, so it returns nothing.
|
|
17
17
|
*/
|
|
18
18
|
protected checkMount(node: ast.MountStatement): void;
|
|
19
|
+
private checkDeferring;
|
|
19
20
|
/**
|
|
20
21
|
* `delete scores[name]` removes a key of an object used as a map, `{ [string]: T }`, or a field
|
|
21
22
|
* that may be missing, of type `?T`; values of type `any` are not checked.
|
|
@@ -30,4 +31,6 @@ export declare abstract class StatementChecker extends AssignmentChecker {
|
|
|
30
31
|
private linkError;
|
|
31
32
|
/** The types of the variables of a declaration: the written one, or those of their values. */
|
|
32
33
|
private initializerTypes;
|
|
34
|
+
/** `derived total number { ... }`: the block runs like the body of a closure and returns the value. */
|
|
35
|
+
private derivedBlockType;
|
|
33
36
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { guardedByError } from "./error-results.js";
|
|
2
2
|
import { AssignmentChecker } from "./assignments.js";
|
|
3
|
+
import { placeOf } from "./context.js";
|
|
4
|
+
import { isTerminating } from "./flow.js";
|
|
3
5
|
import { isUntyped, isNumeric, ownStatements } from "./helpers.js";
|
|
4
6
|
import { func, hasZeroValue, isNullable, nonNull, nullable, typeToString, UNKNOWN, } from "./types.js";
|
|
5
|
-
// Statements: declarations of variables, blocks, `mount
|
|
7
|
+
// Statements: declarations of variables, blocks, `mount`, `effect`. Assignments and `return`
|
|
6
8
|
// are in assignments.ts.
|
|
7
9
|
export class StatementChecker extends AssignmentChecker {
|
|
8
10
|
checkStatement(node) {
|
|
@@ -92,30 +94,22 @@ export class StatementChecker extends AssignmentChecker {
|
|
|
92
94
|
* a handler. It cleans up with `defer`, so it returns nothing.
|
|
93
95
|
*/
|
|
94
96
|
checkEffect(node) {
|
|
95
|
-
|
|
96
|
-
if (statement.kind === 'ReturnStatement' && statement.values.length > 0) {
|
|
97
|
-
this.error('an effect returns nothing; clean up with defer, e.g. defer clearInterval(timer)', statement.values[0]);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
this.checkFunction([], func([], []), null, node.body, { closure: true });
|
|
97
|
+
this.checkDeferring(node.body, 'an effect');
|
|
101
98
|
}
|
|
102
99
|
/**
|
|
103
|
-
* `mount
|
|
104
|
-
*
|
|
100
|
+
* `mount { ... }`: a function that runs once the markup is in the document, like a handler. It
|
|
101
|
+
* cleans up with `defer`, as an effect does, so it returns nothing.
|
|
105
102
|
*/
|
|
106
103
|
checkMount(node) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
(result.kind === 'function' && result.required === 0));
|
|
115
|
-
if (!cleans) {
|
|
116
|
-
const returned = results.length === 1 ? typeToString(results[0]) : `${results.length} values`;
|
|
117
|
-
this.error(`mount() returns the function that cleans up, e.g. return () => clearInterval(timer), not ${returned}`, { start: node.start, end: node.start + 'mount'.length });
|
|
104
|
+
this.checkDeferring(node.body, 'mount');
|
|
105
|
+
}
|
|
106
|
+
checkDeferring(body, what) {
|
|
107
|
+
for (const statement of ownStatements(body)) {
|
|
108
|
+
if (statement.kind === 'ReturnStatement' && statement.values.length > 0) {
|
|
109
|
+
this.error(`${what} returns nothing; clean up with defer, e.g. defer clearInterval(timer)`, statement.values[0]);
|
|
110
|
+
}
|
|
118
111
|
}
|
|
112
|
+
this.checkFunction([], func([], []), null, body, { closure: true });
|
|
119
113
|
}
|
|
120
114
|
/**
|
|
121
115
|
* `delete scores[name]` removes a key of an object used as a map, `{ [string]: T }`, or a field
|
|
@@ -133,6 +127,8 @@ export class StatementChecker extends AssignmentChecker {
|
|
|
133
127
|
: null;
|
|
134
128
|
if (target.kind === 'IndexExpression')
|
|
135
129
|
this.checkValue(target.index);
|
|
130
|
+
// `delete user.boss` makes the field null again.
|
|
131
|
+
this.forget(target);
|
|
136
132
|
if (isUntyped(object))
|
|
137
133
|
return;
|
|
138
134
|
if (object.kind === 'array') {
|
|
@@ -180,7 +176,7 @@ export class StatementChecker extends AssignmentChecker {
|
|
|
180
176
|
binding.type = type;
|
|
181
177
|
const value = values.length === names.length ? values[i] : undefined;
|
|
182
178
|
if (value && isNullable(type) && !isNullable(this.typeOfChecked(value))) {
|
|
183
|
-
this.flow.set(binding, nonNull(type));
|
|
179
|
+
this.flow.set(placeOf(binding), nonNull(type));
|
|
184
180
|
}
|
|
185
181
|
});
|
|
186
182
|
if (node.keyword === 'const' && !declared)
|
|
@@ -207,7 +203,10 @@ export class StatementChecker extends AssignmentChecker {
|
|
|
207
203
|
initializerTypes(node, declared) {
|
|
208
204
|
const { names, values } = node;
|
|
209
205
|
let types;
|
|
210
|
-
if (
|
|
206
|
+
if (node.body) {
|
|
207
|
+
types = [this.derivedBlockType(names[0].name, node.body.body, declared)];
|
|
208
|
+
}
|
|
209
|
+
else if (values.length === 0) {
|
|
211
210
|
if (declared && !hasZeroValue(declared) && declared.kind !== 'unknown') {
|
|
212
211
|
const type = typeToString(declared);
|
|
213
212
|
this.error(`${type} has no zero value: give "${names[0].name}" a value or make it nullable with ${typeToString(nullable(declared))}`, node.type ?? node);
|
|
@@ -228,4 +227,34 @@ export class StatementChecker extends AssignmentChecker {
|
|
|
228
227
|
}
|
|
229
228
|
return types;
|
|
230
229
|
}
|
|
230
|
+
/** `derived total number { ... }`: the block runs like the body of a closure and returns the value. */
|
|
231
|
+
derivedBlockType(name, body, declared) {
|
|
232
|
+
const ends = isTerminating(body);
|
|
233
|
+
if (!ends) {
|
|
234
|
+
this.error(`derived "${name}" must return its value at the end of the block, e.g. return total`, {
|
|
235
|
+
start: body.end - 1,
|
|
236
|
+
end: body.end,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
const saved = this.derivedBlock;
|
|
240
|
+
const results = declared ? [declared] : null;
|
|
241
|
+
this.derivedBlock = name;
|
|
242
|
+
try {
|
|
243
|
+
const types = this.checkFunction([], func([], results ?? []), results, body, {
|
|
244
|
+
closure: true,
|
|
245
|
+
});
|
|
246
|
+
if (types.length === 1)
|
|
247
|
+
return types[0];
|
|
248
|
+
// A block that does not end with a return is reported above.
|
|
249
|
+
if (ends) {
|
|
250
|
+
this.error(types.length === 0
|
|
251
|
+
? `derived "${name}" returns no value: return it, e.g. return total`
|
|
252
|
+
: `derived "${name}" is one value, but its block returns ${types.length}`, body);
|
|
253
|
+
}
|
|
254
|
+
return UNKNOWN;
|
|
255
|
+
}
|
|
256
|
+
finally {
|
|
257
|
+
this.derivedBlock = saved;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
231
260
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type * as ast from '../ast.ts';
|
|
2
|
+
import { type Narrowing, type Place } from './context.ts';
|
|
3
|
+
import { ControlFlowChecker } from './control-flow.ts';
|
|
4
|
+
import { type LiteralType, type Member, type Type } from './types.ts';
|
|
5
|
+
type Value = LiteralType['value'];
|
|
6
|
+
export declare abstract class TaggedUnionChecker extends ControlFlowChecker {
|
|
7
|
+
/** The paths among the checked member expressions, with the types of their fields. */
|
|
8
|
+
private readonly paths;
|
|
9
|
+
/** The types of the fields of the paths, before narrowing: what their tags are found in. */
|
|
10
|
+
private readonly declared;
|
|
11
|
+
protected isTagOf(place: Place, field: string): boolean;
|
|
12
|
+
protected narrowable(node: ast.Expression): {
|
|
13
|
+
place: Place;
|
|
14
|
+
type: Type;
|
|
15
|
+
} | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* The type of `object.field` read by `node`, which is `type` unless the expression is a path
|
|
18
|
+
* narrowed here. Getters and methods are not paths: they may give another value each time.
|
|
19
|
+
*/
|
|
20
|
+
protected pathType(node: ast.MemberExpression, object: Type, type: Type): Type;
|
|
21
|
+
/** The field `name` of an object or a class instance, unless it is a method or an accessor. */
|
|
22
|
+
protected dataField(type: Type, name: string): Member | undefined;
|
|
23
|
+
/** The values of the tag `name` in each member of a union; `null` when `name` is not a tag. */
|
|
24
|
+
protected tagValues(members: readonly Type[], name: string): Value[][] | null;
|
|
25
|
+
/** `d.kind == "courier"` narrows `d` too: the members with this tag, or the others. */
|
|
26
|
+
protected narrow(node: ast.Expression, assumeTrue: boolean): Narrowing;
|
|
27
|
+
/** `switch d.kind`: in a case the members with its tags, in `default` those of no case. */
|
|
28
|
+
protected narrowCase(node: ast.SwitchStatement, switchCase: ast.SwitchCase): Narrowing;
|
|
29
|
+
private narrowTag;
|
|
30
|
+
/**
|
|
31
|
+
* `{ kind: "pickup", shop: "Main st." }` where one of several objects is expected: the member
|
|
32
|
+
* that a tag of the literal chooses, or `null` when no tag chooses one. A tag of no member is
|
|
33
|
+
* reported, and the literal then gets `UNKNOWN`, so that it is not reported again.
|
|
34
|
+
*/
|
|
35
|
+
protected taggedMember(node: ast.ObjectLiteral, objects: readonly Type[], union: Type): Type | null;
|
|
36
|
+
}
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { placeOf } from "./context.js";
|
|
2
|
+
import { ControlFlowChecker } from "./control-flow.js";
|
|
3
|
+
import { literalValue, narrowByTag } from "./flow.js";
|
|
4
|
+
import { findClassMember, memberTypeOf, nonNull, typeToString, unionMembers, UNKNOWN, } from "./types.js";
|
|
5
|
+
export class TaggedUnionChecker extends ControlFlowChecker {
|
|
6
|
+
/** The paths among the checked member expressions, with the types of their fields. */
|
|
7
|
+
paths = new WeakMap();
|
|
8
|
+
/** The types of the fields of the paths, before narrowing: what their tags are found in. */
|
|
9
|
+
declared = new WeakMap();
|
|
10
|
+
isTagOf(place, field) {
|
|
11
|
+
const type = place.path === '' ? place.binding.type : this.declared.get(place);
|
|
12
|
+
return type != null && this.tagValues(unionMembers(nonNull(type)), field) !== null;
|
|
13
|
+
}
|
|
14
|
+
narrowable(node) {
|
|
15
|
+
if (node.kind === 'Identifier') {
|
|
16
|
+
const binding = this.narrowableBinding(node);
|
|
17
|
+
if (!binding?.type)
|
|
18
|
+
return undefined;
|
|
19
|
+
const place = placeOf(binding);
|
|
20
|
+
return { place, type: this.flow.get(place) ?? binding.type };
|
|
21
|
+
}
|
|
22
|
+
const path = node.kind === 'MemberExpression' ? this.paths.get(node) : undefined;
|
|
23
|
+
return path && { place: path.place, type: this.flow.get(path.place) ?? path.type };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The type of `object.field` read by `node`, which is `type` unless the expression is a path
|
|
27
|
+
* narrowed here. Getters and methods are not paths: they may give another value each time.
|
|
28
|
+
*/
|
|
29
|
+
pathType(node, object, type) {
|
|
30
|
+
const parent = node.optional ? undefined : this.narrowable(node.object)?.place;
|
|
31
|
+
const { name } = node.property;
|
|
32
|
+
if (!parent || !unionMembers(object).every((member) => this.dataField(member, name))) {
|
|
33
|
+
this.paths.delete(node);
|
|
34
|
+
return type;
|
|
35
|
+
}
|
|
36
|
+
const place = placeOf(parent.binding, parent.path === '' ? name : `${parent.path}.${name}`);
|
|
37
|
+
this.paths.set(node, { place, type });
|
|
38
|
+
this.declared.set(place, type);
|
|
39
|
+
return this.flow.get(place) ?? type;
|
|
40
|
+
}
|
|
41
|
+
/** The field `name` of an object or a class instance, unless it is a method or an accessor. */
|
|
42
|
+
dataField(type, name) {
|
|
43
|
+
let member;
|
|
44
|
+
if (type.kind === 'object') {
|
|
45
|
+
member = type.members.get(name);
|
|
46
|
+
}
|
|
47
|
+
else if (type.kind === 'class') {
|
|
48
|
+
this.ensureClassResolved(type.info);
|
|
49
|
+
member = findClassMember(type.info, name, false);
|
|
50
|
+
if (member && type.args)
|
|
51
|
+
member = { ...member, type: memberTypeOf(type, member) };
|
|
52
|
+
}
|
|
53
|
+
return member && !member.method && member.accessor === undefined ? member : undefined;
|
|
54
|
+
}
|
|
55
|
+
/** The values of the tag `name` in each member of a union; `null` when `name` is not a tag. */
|
|
56
|
+
tagValues(members, name) {
|
|
57
|
+
if (members.length < 2)
|
|
58
|
+
return null;
|
|
59
|
+
const tags = [];
|
|
60
|
+
for (const member of members) {
|
|
61
|
+
const field = this.dataField(member, name);
|
|
62
|
+
const types = field ? unionMembers(field.type) : [];
|
|
63
|
+
if (!types.every((type) => type.kind === 'literal'))
|
|
64
|
+
return null;
|
|
65
|
+
if (types.length === 0)
|
|
66
|
+
return null;
|
|
67
|
+
tags.push(types.map((type) => type.value));
|
|
68
|
+
}
|
|
69
|
+
return tags;
|
|
70
|
+
}
|
|
71
|
+
/** `d.kind == "courier"` narrows `d` too: the members with this tag, or the others. */
|
|
72
|
+
narrow(node, assumeTrue) {
|
|
73
|
+
const narrowing = super.narrow(node, assumeTrue);
|
|
74
|
+
if (node.kind !== 'BinaryExpression')
|
|
75
|
+
return narrowing;
|
|
76
|
+
if (node.operator !== '==' && node.operator !== '!=')
|
|
77
|
+
return narrowing;
|
|
78
|
+
const right = literalValue(node.right);
|
|
79
|
+
const value = right ?? literalValue(node.left);
|
|
80
|
+
if (value === undefined)
|
|
81
|
+
return narrowing;
|
|
82
|
+
const target = right !== undefined ? node.left : node.right;
|
|
83
|
+
const equal = (node.operator === '==') === assumeTrue;
|
|
84
|
+
return [...narrowing, ...this.narrowTag(target, [value], equal)];
|
|
85
|
+
}
|
|
86
|
+
/** `switch d.kind`: in a case the members with its tags, in `default` those of no case. */
|
|
87
|
+
narrowCase(node, switchCase) {
|
|
88
|
+
const narrowing = super.narrowCase(node, switchCase);
|
|
89
|
+
if (!node.discriminant)
|
|
90
|
+
return narrowing;
|
|
91
|
+
const isDefault = switchCase.tests.length === 0;
|
|
92
|
+
const tests = isDefault ? node.cases.flatMap((each) => each.tests) : switchCase.tests;
|
|
93
|
+
const values = tests.map(literalValue);
|
|
94
|
+
if (!isDefault && values.includes(undefined))
|
|
95
|
+
return narrowing;
|
|
96
|
+
const known = values.filter((value) => value !== undefined);
|
|
97
|
+
return [...narrowing, ...this.narrowTag(node.discriminant, known, !isDefault)];
|
|
98
|
+
}
|
|
99
|
+
narrowTag(target, values, equal) {
|
|
100
|
+
if (target.kind !== 'MemberExpression' || target.optional)
|
|
101
|
+
return [];
|
|
102
|
+
const owner = this.narrowable(target.object);
|
|
103
|
+
const tags = owner && this.tagValues(unionMembers(nonNull(owner.type)), target.property.name);
|
|
104
|
+
return owner && tags ? [[owner.place, narrowByTag(owner.type, tags, values, equal)]] : [];
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* `{ kind: "pickup", shop: "Main st." }` where one of several objects is expected: the member
|
|
108
|
+
* that a tag of the literal chooses, or `null` when no tag chooses one. A tag of no member is
|
|
109
|
+
* reported, and the literal then gets `UNKNOWN`, so that it is not reported again.
|
|
110
|
+
*/
|
|
111
|
+
taggedMember(node, objects, union) {
|
|
112
|
+
for (const property of node.properties) {
|
|
113
|
+
if (property.kind === 'SpreadElement')
|
|
114
|
+
continue;
|
|
115
|
+
const name = property.key.kind === 'Identifier' ? property.key.name : property.key.value;
|
|
116
|
+
const value = literalValue(property.value);
|
|
117
|
+
const tags = value === undefined ? null : this.tagValues(objects, name);
|
|
118
|
+
if (value === undefined || !tags)
|
|
119
|
+
continue;
|
|
120
|
+
const chosen = objects.filter((_, i) => tags[i].includes(value));
|
|
121
|
+
if (chosen.length === 1)
|
|
122
|
+
return chosen[0];
|
|
123
|
+
if (chosen.length > 1)
|
|
124
|
+
continue;
|
|
125
|
+
const known = [...new Set(tags.flat())].map((each) => JSON.stringify(each));
|
|
126
|
+
const choices = known.length > 1 ? `${known.slice(0, -1).join(', ')} or ${known.at(-1)}` : known[0];
|
|
127
|
+
this.error(`${JSON.stringify(value)} is not a kind of ${typeToString(union)}: write ${choices}`, property.value);
|
|
128
|
+
return UNKNOWN;
|
|
129
|
+
}
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { QueueChecker } from "./queues.js";
|
|
2
|
+
import { notBroadcast } from "./transfer.js";
|
|
3
|
+
import { STRING, topicOf } from "./types.js";
|
|
4
|
+
// Topics: `topic<T>(name)` makes one, and its values go to the other tabs of the site as copies,
|
|
5
|
+
// so they must be data without channels. `t <- v` sends (channels.ts), `<-t` receives
|
|
6
|
+
// (operators.ts) and `for v in t` receives them until it is closed (loops.ts).
|
|
7
|
+
export class TopicChecker extends QueueChecker {
|
|
8
|
+
checkTopic(node) {
|
|
9
|
+
const element = this.resolveType(node.element);
|
|
10
|
+
const reason = notBroadcast(element);
|
|
11
|
+
if (reason !== null) {
|
|
12
|
+
this.error(`the values of a topic go to other tabs as copies: ${reason}`, node.element);
|
|
13
|
+
}
|
|
14
|
+
this.expectAssignable(this.checkValue(node.name, STRING), STRING, node.name);
|
|
15
|
+
return topicOf(element);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -2,4 +2,6 @@ import { type Type } from './types.ts';
|
|
|
2
2
|
/** Buffers and their views: copied whole, or moved by `transfer(x)` (channels.ts). */
|
|
3
3
|
export declare const BUFFERS: readonly string[];
|
|
4
4
|
/** Why a value of the type cannot be copied to a worker, or null if it can. */
|
|
5
|
-
export declare function notCopied(type: Type, seen?: Set<Type
|
|
5
|
+
export declare function notCopied(type: Type, seen?: Set<Type>, tab?: boolean): string | null;
|
|
6
|
+
/** Why a value of the type cannot go to another tab through a topic, or null if it can. */
|
|
7
|
+
export declare function notBroadcast(type: Type): string | null;
|
package/dist/checker/transfer.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isQueue, memberNames, queueElement, typeToString } from "./types.js";
|
|
2
2
|
// What can go to a worker and back: a worker gets a copy of each value (the structured clone of
|
|
3
|
-
// postMessage), and a copy has the data of a value but not its methods.
|
|
3
|
+
// postMessage), and a copy has the data of a value but not its methods. What goes to another tab
|
|
4
|
+
// through a topic is a copy as well, and it cannot hold a channel.
|
|
4
5
|
/** Buffers and their views: copied whole, or moved by `transfer(x)` (channels.ts). */
|
|
5
6
|
export const BUFFERS = [
|
|
6
7
|
'ArrayBuffer',
|
|
@@ -23,6 +24,8 @@ const COPIED = new Set([
|
|
|
23
24
|
'chan',
|
|
24
25
|
'chan<-',
|
|
25
26
|
'<-chan',
|
|
27
|
+
// A topic is copied as its name, and the other thread listens to it on its own.
|
|
28
|
+
'topic',
|
|
26
29
|
'Map',
|
|
27
30
|
'Set',
|
|
28
31
|
'Date',
|
|
@@ -35,13 +38,13 @@ const COPIED = new Set([
|
|
|
35
38
|
...BUFFERS,
|
|
36
39
|
]);
|
|
37
40
|
/** Why a value of the type cannot be copied to a worker, or null if it can. */
|
|
38
|
-
export function notCopied(type, seen = new Set()) {
|
|
41
|
+
export function notCopied(type, seen = new Set(), tab = false) {
|
|
39
42
|
if (seen.has(type))
|
|
40
43
|
return null;
|
|
41
44
|
seen.add(type);
|
|
42
45
|
const inner = (types) => {
|
|
43
46
|
for (const each of types) {
|
|
44
|
-
const reason = notCopied(each, seen);
|
|
47
|
+
const reason = notCopied(each, seen, tab);
|
|
45
48
|
if (reason !== null)
|
|
46
49
|
return reason;
|
|
47
50
|
}
|
|
@@ -61,15 +64,28 @@ export function notCopied(type, seen = new Set()) {
|
|
|
61
64
|
return 'a component cannot be copied';
|
|
62
65
|
case 'classValue':
|
|
63
66
|
return `the class ${type.info.name} cannot be copied`;
|
|
67
|
+
// A data class goes with its class (runtime/classes.js), but not to another tab, which may not
|
|
68
|
+
// have it.
|
|
64
69
|
case 'class':
|
|
65
|
-
|
|
66
|
-
|
|
70
|
+
if (type.info.name === 'Error')
|
|
71
|
+
return null;
|
|
72
|
+
if (type.info.data === true) {
|
|
73
|
+
return tab
|
|
74
|
+
? `${typeToString(type)} cannot go to another tab, which may not have its class: send an object of an interface`
|
|
75
|
+
: inner(type.args ?? []);
|
|
76
|
+
}
|
|
77
|
+
return type.info.data === false && !tab
|
|
78
|
+
? `a copy of ${typeToString(type)} would lose its class and methods: mark it to keep them, e.g. data class ${type.info.name}`
|
|
67
79
|
: `a copy of ${typeToString(type)} would lose its class and methods`;
|
|
68
80
|
case 'object': {
|
|
69
81
|
// A queue goes as its values, and the other thread makes a queue of them (src/runtime/threads.js).
|
|
70
82
|
if (isQueue(type))
|
|
71
83
|
return inner([queueElement(type)]);
|
|
72
84
|
const name = type.instanceOf?.template.name ?? type.name;
|
|
85
|
+
// The id of a channel means something only to the workers of the tab that made it.
|
|
86
|
+
if (tab && (name === 'chan' || name === 'chan<-' || name === '<-chan')) {
|
|
87
|
+
return `${typeToString(type)} cannot go to another tab: a channel works only within one`;
|
|
88
|
+
}
|
|
73
89
|
if (name !== null && COPIED.has(name))
|
|
74
90
|
return inner(type.instanceOf?.args ?? []);
|
|
75
91
|
if (type.call || type.construct)
|
|
@@ -84,3 +100,7 @@ export function notCopied(type, seen = new Set()) {
|
|
|
84
100
|
return null;
|
|
85
101
|
}
|
|
86
102
|
}
|
|
103
|
+
/** Why a value of the type cannot go to another tab through a topic, or null if it can. */
|
|
104
|
+
export function notBroadcast(type) {
|
|
105
|
+
return notCopied(type, new Set(), true);
|
|
106
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { DecodeChecker } from "./decode.js";
|
|
2
|
+
import { isErrorType } from "./error-results.js";
|
|
3
|
+
import { ERROR } from "./types.js";
|
|
4
|
+
// `try expr`: an exception in the expression, or a rejected Promise that an `await` in it waits
|
|
5
|
+
// for, becomes an error, as if the expression returned it (codegen/try.ts): `try JSON.parse(text)`
|
|
6
|
+
// gives `(any, error)`, `try save()` of a function without results gives the error alone, and of
|
|
7
|
+
// `(User, error)` the exception is one more way to get that error.
|
|
8
|
+
export class TryChecker extends DecodeChecker {
|
|
9
|
+
checkTryExpression(node) {
|
|
10
|
+
const type = this.checkExpression(node.argument, null);
|
|
11
|
+
if (type.kind === 'void' || isErrorType(type))
|
|
12
|
+
return ERROR;
|
|
13
|
+
if (type.kind !== 'tuple')
|
|
14
|
+
return { kind: 'tuple', types: [type, ERROR] };
|
|
15
|
+
return isErrorType(type.types.at(-1))
|
|
16
|
+
? type
|
|
17
|
+
: { kind: 'tuple', types: [...type.types, ERROR] };
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ArrayType, type ClassInfo, type FunctionType, type LiteralType, type Member, type Type, type TypeParam } from './model.ts';
|
|
2
|
-
export declare function arrayOf(element: Type): ArrayType;
|
|
2
|
+
export declare function arrayOf(element: Type, positions?: Type[]): ArrayType;
|
|
3
3
|
export declare function nullable(type: Type): Type;
|
|
4
4
|
export declare function literal(value: string | number | boolean): LiteralType;
|
|
5
5
|
/** The type that a literal belongs to: `"all"` → `string`. */
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { BOOL, NEVER, NULL, NUMBER, STRING, } from "./model.js";
|
|
2
2
|
import { typesEqual } from "./relations.js";
|
|
3
3
|
// Making types: arrays, nullable types, literals, unions, functions, members, classes.
|
|
4
|
-
export function arrayOf(element) {
|
|
5
|
-
return { kind: 'array', element };
|
|
4
|
+
export function arrayOf(element, positions) {
|
|
5
|
+
return positions ? { kind: 'array', element, positions } : { kind: 'array', element };
|
|
6
6
|
}
|
|
7
7
|
export function nullable(type) {
|
|
8
8
|
switch (type.kind) {
|
|
@@ -43,7 +43,7 @@ export function instantiate(template, args) {
|
|
|
43
43
|
}
|
|
44
44
|
// The indexes and the values of a loop, substituted when first used: the template of a
|
|
45
45
|
// `.d.ts` may get them after its instances.
|
|
46
|
-
for (const key of ['index', 'numberIndex', 'iterates']) {
|
|
46
|
+
for (const key of ['index', 'numberIndex', 'iterates', 'asyncIterates']) {
|
|
47
47
|
let substituted;
|
|
48
48
|
Object.defineProperty(instance, key, {
|
|
49
49
|
enumerable: true,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type ObjectType, type Type } from './model.ts';
|
|
2
|
+
/** The values that `for` gives of a type it goes over at once, or null. */
|
|
3
|
+
export declare function iteratedBy(type: Type): Type | null;
|
|
4
|
+
/**
|
|
5
|
+
* Whether `source` fits `Iterable<T>` or another interface that `for` goes over: its values must
|
|
6
|
+
* fit. An array or a string, which have no members here, fits one whose members may be left out;
|
|
7
|
+
* an object goes on to the check of its members (null).
|
|
8
|
+
*/
|
|
9
|
+
export declare function iterableAssignable(source: Type, target: ObjectType, assuming: [Type, Type][]): boolean | null;
|
|
10
|
+
/** `{ [string]: T }` accepts an object whose own index and fields are all `T`. */
|
|
11
|
+
export declare function indexAssignable(source: Type, index: Type, assuming: [Type, Type][]): boolean;
|
|
12
|
+
/** `ArrayLike<T>` from a `.d.ts` accepts an array, a string or a typed array of `T`. */
|
|
13
|
+
export declare function numberIndexAssignable(source: Type, index: Type, assuming: [Type, Type][]): boolean;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { isNullable } from "./constructors.js";
|
|
2
|
+
import { memberNames } from "./lazy.js";
|
|
3
|
+
import { STRING } from "./model.js";
|
|
4
|
+
import { assignable } from "./relations.js";
|
|
5
|
+
// What types from a `.d.ts` that are gone over or indexed accept: `Iterable<T>` takes what `for`
|
|
6
|
+
// goes over with values that fit, an array or a Set; `{ [string]: T }` an object of fields of `T`;
|
|
7
|
+
// `ArrayLike<T>` an array, a string or a typed array.
|
|
8
|
+
/** The values that `for` gives of a type it goes over at once, or null. */
|
|
9
|
+
export function iteratedBy(type) {
|
|
10
|
+
if (type.kind === 'array')
|
|
11
|
+
return type.element;
|
|
12
|
+
if (type.kind === 'string')
|
|
13
|
+
return STRING;
|
|
14
|
+
return type.kind === 'object' ? (type.iterates ?? null) : null;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Whether `source` fits `Iterable<T>` or another interface that `for` goes over: its values must
|
|
18
|
+
* fit. An array or a string, which have no members here, fits one whose members may be left out;
|
|
19
|
+
* an object goes on to the check of its members (null).
|
|
20
|
+
*/
|
|
21
|
+
export function iterableAssignable(source, target, assuming) {
|
|
22
|
+
const values = iteratedBy(source);
|
|
23
|
+
if (values === null || !assignable(values, target.iterates, assuming))
|
|
24
|
+
return values === null ? null : false;
|
|
25
|
+
if (source.kind === 'object')
|
|
26
|
+
return null;
|
|
27
|
+
return [...memberNames(target.members)].every((name) => {
|
|
28
|
+
const member = target.members.get(name);
|
|
29
|
+
return !member || (!member.method && isNullable(member.type));
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/** `{ [string]: T }` accepts an object whose own index and fields are all `T`. */
|
|
33
|
+
export function indexAssignable(source, index, assuming) {
|
|
34
|
+
if (source.kind !== 'object')
|
|
35
|
+
return false;
|
|
36
|
+
if (source.index && !assignable(source.index, index, assuming))
|
|
37
|
+
return false;
|
|
38
|
+
return [...memberNames(source.members)].every((name) => {
|
|
39
|
+
const member = source.members.get(name);
|
|
40
|
+
return !member || member.method || assignable(member.type, index, assuming);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/** `ArrayLike<T>` from a `.d.ts` accepts an array, a string or a typed array of `T`. */
|
|
44
|
+
export function numberIndexAssignable(source, index, assuming) {
|
|
45
|
+
if (source.kind === 'array')
|
|
46
|
+
return assignable(source.element, index, assuming);
|
|
47
|
+
if (source.kind === 'string')
|
|
48
|
+
return assignable(source, index, assuming);
|
|
49
|
+
return (source.kind === 'object' &&
|
|
50
|
+
source.numberIndex !== undefined &&
|
|
51
|
+
assignable(source.numberIndex, index, assuming));
|
|
52
|
+
}
|
|
@@ -22,6 +22,11 @@ export declare const UNKNOWN: SimpleType;
|
|
|
22
22
|
export interface ArrayType {
|
|
23
23
|
kind: 'array';
|
|
24
24
|
element: Type;
|
|
25
|
+
/**
|
|
26
|
+
* The types by position of a tuple of a `.d.ts`, `[K, V]`, or of an array literal: only for
|
|
27
|
+
* inferring type parameters, since the array may change. `element` is the union of them.
|
|
28
|
+
*/
|
|
29
|
+
positions?: Type[];
|
|
25
30
|
}
|
|
26
31
|
/** `?T`; the inner type itself is never nullable. */
|
|
27
32
|
export interface NullableType {
|
|
@@ -66,6 +71,15 @@ export interface Member {
|
|
|
66
71
|
visibility: Visibility;
|
|
67
72
|
/** The class that declares the member, for visibility checks. */
|
|
68
73
|
owner: ClassInfo | null;
|
|
74
|
+
/** `readonly id string`: only its value and the constructor of its class assign it. */
|
|
75
|
+
readonly?: true;
|
|
76
|
+
/**
|
|
77
|
+
* A getter, a setter or both, as in `get area() number`: the member is a value of its type, which
|
|
78
|
+
* a getter alone cannot be assigned and a setter alone cannot be read.
|
|
79
|
+
*/
|
|
80
|
+
accessor?: 'get' | 'set' | 'both';
|
|
81
|
+
/** `abstract area() number`: a subclass that is not abstract implements it. */
|
|
82
|
+
abstract?: true;
|
|
69
83
|
}
|
|
70
84
|
/** Interfaces, object type literals and the types of object literals. */
|
|
71
85
|
export interface ObjectType {
|
|
@@ -82,6 +96,8 @@ export interface ObjectType {
|
|
|
82
96
|
numberIndex?: Type;
|
|
83
97
|
/** What `for v in x` gives: the values of `[Symbol.iterator]()` in a `.d.ts`. */
|
|
84
98
|
iterates?: Type;
|
|
99
|
+
/** What `for v in x` waits for: the values of `[Symbol.asyncIterator]()`, as of a Node stream. */
|
|
100
|
+
asyncIterates?: Type;
|
|
85
101
|
/** A generic interface, `interface Box<T>`: its members use these parameters. */
|
|
86
102
|
typeParams?: TypeParam[];
|
|
87
103
|
/** `Box<number>`: the generic interface and the type arguments it was made from. */
|
|
@@ -105,6 +121,15 @@ export interface ClassInfo {
|
|
|
105
121
|
/** Type arguments for a generic base class: the defaults of a class from a `.d.ts`. */
|
|
106
122
|
superArgs?: Type[];
|
|
107
123
|
ctorVisibility: Visibility;
|
|
124
|
+
/** `abstract class Shape`: `new` makes only instances of its subclasses. */
|
|
125
|
+
abstract?: boolean;
|
|
126
|
+
/**
|
|
127
|
+
* `data class Point`: its fields are data, and its instances go to other threads with their
|
|
128
|
+
* class. False for the other classes of Rook; not set for those of a `.d.ts`.
|
|
129
|
+
*/
|
|
130
|
+
data?: boolean;
|
|
131
|
+
/** What `for v in x` waits for: the values of `[Symbol.asyncIterator]()` in a `.d.ts`. */
|
|
132
|
+
asyncIterates?: Type;
|
|
108
133
|
instance: ClassType;
|
|
109
134
|
value: ClassValueType;
|
|
110
135
|
}
|