@velarscript/web 0.28.1 → 0.29.1
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/dist/analysis/component-guidance.d.ts +52 -0
- package/dist/analysis/component-guidance.d.ts.map +1 -0
- package/dist/analysis/component-guidance.js +103 -0
- package/dist/analysis/component-guidance.js.map +1 -0
- package/dist/analysis/look-values.d.ts +30 -0
- package/dist/analysis/look-values.d.ts.map +1 -0
- package/dist/analysis/look-values.js +61 -0
- package/dist/analysis/look-values.js.map +1 -0
- package/dist/analysis/public-config.d.ts +44 -0
- package/dist/analysis/public-config.d.ts.map +1 -0
- package/dist/analysis/public-config.js +133 -0
- package/dist/analysis/public-config.js.map +1 -0
- package/dist/analysis/watch-cycles.d.ts +176 -0
- package/dist/analysis/watch-cycles.d.ts.map +1 -0
- package/dist/analysis/watch-cycles.js +300 -0
- package/dist/analysis/watch-cycles.js.map +1 -0
- package/dist/analyzer.d.ts +45 -0
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +134 -214
- package/dist/analyzer.js.map +1 -1
- package/dist/browser-host-runtime.d.ts +23 -0
- package/dist/browser-host-runtime.d.ts.map +1 -0
- package/dist/browser-host-runtime.js +29 -0
- package/dist/browser-host-runtime.js.map +1 -0
- package/dist/compiler.d.ts +1 -1
- package/dist/compiler.js +6 -6
- package/dist/compiler.js.map +1 -1
- package/dist/emitter.js +25 -5
- package/dist/emitter.js.map +1 -1
- package/dist/lexer.js +89 -16
- package/dist/lexer.js.map +1 -1
- package/dist/look.d.ts +1 -1
- package/dist/look.d.ts.map +1 -1
- package/dist/look.js +5 -3
- package/dist/look.js.map +1 -1
- package/dist/parser.d.ts +2 -0
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +23 -25
- package/dist/parser.js.map +1 -1
- package/dist/runtime-foundation.d.ts.map +1 -1
- package/dist/runtime-foundation.js +5 -5
- package/dist/runtime-foundation.js.map +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +12 -11
- package/dist/runtime.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -1
- package/dist/visual-blocks.d.ts +28 -0
- package/dist/visual-blocks.d.ts.map +1 -0
- package/dist/visual-blocks.js +23 -0
- package/dist/visual-blocks.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a component's refusals say — the JSX element a call was reaching for,
|
|
3
|
+
* the contract a `ref` needs, and the four "how many of this section" rules a
|
|
4
|
+
* body earns once its statements are read.
|
|
5
|
+
*
|
|
6
|
+
* D115 §三: these are sentence-building questions about a component's shape,
|
|
7
|
+
* and none of them needs the analyzer's walk state, so they read as free
|
|
8
|
+
* functions in their own module rather than as methods in the middle of it.
|
|
9
|
+
*/
|
|
10
|
+
import { type Diagnostic, type Span } from "@velarscript/compiler";
|
|
11
|
+
import { type Expression, type ValueType } from "@velarscript/compiler/extension";
|
|
12
|
+
import { type WebComponentType } from "../types.ts";
|
|
13
|
+
/**
|
|
14
|
+
* D114 0.29.0 JX-I1: calling a component is one mistake, and a named argument
|
|
15
|
+
* is how it is spelled rather than a second one. The named form therefore
|
|
16
|
+
* extends the same sentence with the element the author meant — and only that
|
|
17
|
+
* sentence, so `Card("a")` and `Card(title="a")` each report once.
|
|
18
|
+
*/
|
|
19
|
+
export declare function componentCallRefusal(name: string | null, arguments_: readonly Expression[], argumentNames: readonly (string | null)[] | undefined, sourceText: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* D114 0.29.0 LC-I2: two different mistakes used to share one sentence. A
|
|
22
|
+
* component declared without `exposes` really does expose no Handle. A
|
|
23
|
+
* one-argument `Component<Props>` contract is a different failure: the
|
|
24
|
+
* constructor behind it may expose a Handle exactly as its author intended, and
|
|
25
|
+
* what withholds `ref` is the contract's missing second type argument (§14). So
|
|
26
|
+
* the contract is answered with the contract it needs, spelling the Handle the
|
|
27
|
+
* ref binding already declares when it declares one.
|
|
28
|
+
*/
|
|
29
|
+
export declare function componentRefHandleRefusal(tag: string, component: WebComponentType, stored: ValueType): string;
|
|
30
|
+
export interface ComponentSectionCounts {
|
|
31
|
+
readonly renders: number;
|
|
32
|
+
readonly mounted: number;
|
|
33
|
+
readonly cleanup: number;
|
|
34
|
+
readonly exposes: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* D114 0.29.0 JX-I2: VEL5008 names the two ways out, because it is the only
|
|
38
|
+
* message this shape earns now — a `return` inside a `match` arm or an `if` is
|
|
39
|
+
* where the count usually goes wrong, and the author who reads "exactly one"
|
|
40
|
+
* has branches already written that he needs told what to do with.
|
|
41
|
+
*/
|
|
42
|
+
export declare function componentSectionCountDiagnostics(name: string, counts: ComponentSectionCounts, declarationSpan: Span, handleTypeSpan: Span | null): readonly Diagnostic[];
|
|
43
|
+
/**
|
|
44
|
+
* D114 0.29.0 ST-D1: a `resource` publishes four reactive fields, and the
|
|
45
|
+
* surface carrying them is not one of them — the handle is built once and never
|
|
46
|
+
* replaced, so `watch profile:` compiled clean and never ran. The sentence
|
|
47
|
+
* VEL5064 already had names the answer ("or a resource field"); what was
|
|
48
|
+
* missing was this shape's place in the criterion, so the fields are spelled
|
|
49
|
+
* out here.
|
|
50
|
+
*/
|
|
51
|
+
export declare function watchedResourceSurfaceRefusal(name: string): string;
|
|
52
|
+
//# sourceMappingURL=component-guidance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component-guidance.d.ts","sourceRoot":"","sources":["../../src/analysis/component-guidance.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,IAAI,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,EAA+B,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAC/G,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIpD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,UAAU,EAAE,SAAS,UAAU,EAAE,EACjC,aAAa,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,GAAG,SAAS,EACrD,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AA4BD;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,GAAG,MAAM,CAO7G;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAC9C,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,sBAAsB,EAC9B,eAAe,EAAE,IAAI,EACrB,cAAc,EAAE,IAAI,GAAG,IAAI,GAC1B,SAAS,UAAU,EAAE,CAiBvB;AAED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIlE"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a component's refusals say — the JSX element a call was reaching for,
|
|
3
|
+
* the contract a `ref` needs, and the four "how many of this section" rules a
|
|
4
|
+
* body earns once its statements are read.
|
|
5
|
+
*
|
|
6
|
+
* D115 §三: these are sentence-building questions about a component's shape,
|
|
7
|
+
* and none of them needs the analyzer's walk state, so they read as free
|
|
8
|
+
* functions in their own module rather than as methods in the middle of it.
|
|
9
|
+
*/
|
|
10
|
+
import {} from "@velarscript/compiler";
|
|
11
|
+
import { describeType, isInvalidType } from "@velarscript/compiler/extension";
|
|
12
|
+
import {} from "../types.js";
|
|
13
|
+
const diagnostic = (code, message, sourceSpan) => ({ code, message, span: sourceSpan });
|
|
14
|
+
/**
|
|
15
|
+
* D114 0.29.0 JX-I1: calling a component is one mistake, and a named argument
|
|
16
|
+
* is how it is spelled rather than a second one. The named form therefore
|
|
17
|
+
* extends the same sentence with the element the author meant — and only that
|
|
18
|
+
* sentence, so `Card("a")` and `Card(title="a")` each report once.
|
|
19
|
+
*/
|
|
20
|
+
export function componentCallRefusal(name, arguments_, argumentNames, sourceText) {
|
|
21
|
+
const subject = name ? `Render component '${name}' with JSX` : "Render a Component value with JSX";
|
|
22
|
+
if (!argumentNames?.some((argument) => argument !== null))
|
|
23
|
+
return subject;
|
|
24
|
+
const element = componentElementSpelling(name, arguments_, argumentNames, sourceText);
|
|
25
|
+
return `${subject}${element === null ? "" : ` — write '${element}'`}; components take JSX props rather than named call arguments`;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The JSX element a named-argument component call was reaching for, or null
|
|
29
|
+
* when the call does not spell one: an unnamed `Component` value has no tag to
|
|
30
|
+
* write, and a positional argument has no prop name. A string literal keeps
|
|
31
|
+
* JSX's quoted attribute form; every other value takes the braces JSX requires,
|
|
32
|
+
* and both are sliced from the author's own source so the answer is the line he
|
|
33
|
+
* can paste back.
|
|
34
|
+
*/
|
|
35
|
+
function componentElementSpelling(name, arguments_, argumentNames, sourceText) {
|
|
36
|
+
if (name === null || arguments_.length === 0)
|
|
37
|
+
return null;
|
|
38
|
+
const attributes = [];
|
|
39
|
+
for (const [index, argument] of arguments_.entries()) {
|
|
40
|
+
const propName = argumentNames[index] ?? null;
|
|
41
|
+
const written = sourceText.slice(argument.span.start, argument.span.end);
|
|
42
|
+
if (propName === null || written === "" || /[\n\r]/u.test(written))
|
|
43
|
+
return null;
|
|
44
|
+
const literal = argument.kind === "LiteralExpression" && typeof argument.value === "string";
|
|
45
|
+
attributes.push(`${propName}=${literal ? written : `{${written}}`}`);
|
|
46
|
+
}
|
|
47
|
+
return `<${name} ${attributes.join(" ")} />`;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* D114 0.29.0 LC-I2: two different mistakes used to share one sentence. A
|
|
51
|
+
* component declared without `exposes` really does expose no Handle. A
|
|
52
|
+
* one-argument `Component<Props>` contract is a different failure: the
|
|
53
|
+
* constructor behind it may expose a Handle exactly as its author intended, and
|
|
54
|
+
* what withholds `ref` is the contract's missing second type argument (§14). So
|
|
55
|
+
* the contract is answered with the contract it needs, spelling the Handle the
|
|
56
|
+
* ref binding already declares when it declares one.
|
|
57
|
+
*/
|
|
58
|
+
export function componentRefHandleRefusal(tag, component, stored) {
|
|
59
|
+
if (component.role !== "contract")
|
|
60
|
+
return `Component '${tag}' does not expose a Handle`;
|
|
61
|
+
const known = stored.kind !== "null" && stored.kind !== "unknown" && stored.kind !== "any" && !isInvalidType(stored);
|
|
62
|
+
const handleType = known ? stored : { kind: "named", name: "Handle" };
|
|
63
|
+
const widened = describeType({ ...component, arguments: [handleType] });
|
|
64
|
+
return `The contract on '${tag}' names no Handle, so it does not authorise a component ref — the authority is the contract's second type argument,`
|
|
65
|
+
+ ` not the component behind it; declare the contract as '${widened}'`;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* D114 0.29.0 JX-I2: VEL5008 names the two ways out, because it is the only
|
|
69
|
+
* message this shape earns now — a `return` inside a `match` arm or an `if` is
|
|
70
|
+
* where the count usually goes wrong, and the author who reads "exactly one"
|
|
71
|
+
* has branches already written that he needs told what to do with.
|
|
72
|
+
*/
|
|
73
|
+
export function componentSectionCountDiagnostics(name, counts, declarationSpan, handleTypeSpan) {
|
|
74
|
+
const reports = [];
|
|
75
|
+
if (counts.renders !== 1) {
|
|
76
|
+
reports.push(diagnostic("VEL5008", `Component '${name}' must have exactly one top-level return: assign the branches to a binding — 'let node: WebNode = <span />' written in each arm — and return it once,`
|
|
77
|
+
+ " or move the branching into a 'def' that returns WebNode and return its call", declarationSpan));
|
|
78
|
+
}
|
|
79
|
+
if (counts.mounted > 1)
|
|
80
|
+
reports.push(diagnostic("VEL5009", `Component '${name}' has more than one '@mounted' block`, declarationSpan));
|
|
81
|
+
if (counts.cleanup > 1)
|
|
82
|
+
reports.push(diagnostic("VEL5010", `Component '${name}' has more than one '@cleanup' block`, declarationSpan));
|
|
83
|
+
if (counts.exposes > 1)
|
|
84
|
+
reports.push(diagnostic("VEL5056", `Component '${name}' has more than one expose declaration`, declarationSpan));
|
|
85
|
+
if (handleTypeSpan && counts.exposes === 0) {
|
|
86
|
+
reports.push(diagnostic("VEL5056", `Component '${name}' declares an exposed Handle but does not provide an expose value`, handleTypeSpan));
|
|
87
|
+
}
|
|
88
|
+
return reports;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* D114 0.29.0 ST-D1: a `resource` publishes four reactive fields, and the
|
|
92
|
+
* surface carrying them is not one of them — the handle is built once and never
|
|
93
|
+
* replaced, so `watch profile:` compiled clean and never ran. The sentence
|
|
94
|
+
* VEL5064 already had names the answer ("or a resource field"); what was
|
|
95
|
+
* missing was this shape's place in the criterion, so the fields are spelled
|
|
96
|
+
* out here.
|
|
97
|
+
*/
|
|
98
|
+
export function watchedResourceSurfaceRefusal(name) {
|
|
99
|
+
return `This watch subject never changes, so its body can never run — '${name}' is the resource itself rather than one of the fields it publishes;`
|
|
100
|
+
+ " watch a 'state', a 'computed', a prop, or a resource field, or move these statements to where they should run:"
|
|
101
|
+
+ ` 'watch ${name}.value:' for the loaded value, 'watch ${name}.loading:' for the load's progress, or the input the load reads`;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=component-guidance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component-guidance.js","sourceRoot":"","sources":["../../src/analysis/component-guidance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How the visual unit types combine — the rule `+` reads, and the rule the
|
|
3
|
+
* length-percentage builders read.
|
|
4
|
+
*
|
|
5
|
+
* D115 §三: one question about types, asked in two places, so it is written
|
|
6
|
+
* once here rather than twice in the middle of the Web analyzer.
|
|
7
|
+
*/
|
|
8
|
+
import { type Expression, type ValueType } from "@velarscript/compiler/extension";
|
|
9
|
+
export declare function isLookNumericType(type: ValueType): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* The type two visual operands add up to: the same kind on both sides keeps it,
|
|
12
|
+
* and a length beside a percentage widens to the type that carries both.
|
|
13
|
+
*/
|
|
14
|
+
export declare function lookAdditiveType(left: ValueType, right: ValueType, sameIdentity: boolean): ValueType | null;
|
|
15
|
+
/**
|
|
16
|
+
* D114 0.29.0 LK-C3: `min`, `max` and `clamp` publish the widest of the three
|
|
17
|
+
* length-percentage types, because a slot takes either. A call whose slots are
|
|
18
|
+
* all one kind is still that kind, and the fold is the one `+` already makes.
|
|
19
|
+
* Without it, `clamp(16px, 3vw, 24px)` — the tour's own line, and a legal
|
|
20
|
+
* `lineHeight` — would have started answering `LengthPercentage` and stopped
|
|
21
|
+
* assigning.
|
|
22
|
+
*
|
|
23
|
+
* `inferSlot` both infers a slot and remembers the answer, because the call's
|
|
24
|
+
* own analysis reads each argument again straight afterwards and must not
|
|
25
|
+
* report the argument's diagnostics a second time.
|
|
26
|
+
*/
|
|
27
|
+
export declare function foldedLengthPercentage(expression: Extract<Expression, {
|
|
28
|
+
kind: "CallExpression";
|
|
29
|
+
}>, builderOf: (name: string) => string | undefined, inferSlot: (argument: Expression) => ValueType, join: (left: ValueType, right: ValueType) => ValueType | null): ValueType | null;
|
|
30
|
+
//# sourceMappingURL=look-values.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"look-values.d.ts","sourceRoot":"","sources":["../../src/analysis/look-values.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAMlF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAE1D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAO3G;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC,EAC3D,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,EAC/C,SAAS,EAAE,CAAC,QAAQ,EAAE,UAAU,KAAK,SAAS,EAC9C,IAAI,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,KAAK,SAAS,GAAG,IAAI,GAC5D,SAAS,GAAG,IAAI,CAclB"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How the visual unit types combine — the rule `+` reads, and the rule the
|
|
3
|
+
* length-percentage builders read.
|
|
4
|
+
*
|
|
5
|
+
* D115 §三: one question about types, asked in two places, so it is written
|
|
6
|
+
* once here rather than twice in the middle of the Web analyzer.
|
|
7
|
+
*/
|
|
8
|
+
import {} from "@velarscript/compiler/extension";
|
|
9
|
+
import { LOOK_BUILDER_SIGNATURES, LOOK_NUMERIC_TYPE_NAMES } from "../look.js";
|
|
10
|
+
const lookLengthPercentage = { kind: "named", name: "LengthPercentage" };
|
|
11
|
+
const lengthPercentageNames = new Set(["Length", "Percentage", "LengthPercentage"]);
|
|
12
|
+
export function isLookNumericType(type) {
|
|
13
|
+
return type.kind === "named" && LOOK_NUMERIC_TYPE_NAMES.has(type.name);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The type two visual operands add up to: the same kind on both sides keeps it,
|
|
17
|
+
* and a length beside a percentage widens to the type that carries both.
|
|
18
|
+
*/
|
|
19
|
+
export function lookAdditiveType(left, right, sameIdentity) {
|
|
20
|
+
if (!isLookNumericType(left) || !isLookNumericType(right))
|
|
21
|
+
return null;
|
|
22
|
+
if (sameIdentity)
|
|
23
|
+
return left;
|
|
24
|
+
return left.kind === "named" && right.kind === "named"
|
|
25
|
+
&& lengthPercentageNames.has(left.name) && lengthPercentageNames.has(right.name)
|
|
26
|
+
? lookLengthPercentage
|
|
27
|
+
: null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* D114 0.29.0 LK-C3: `min`, `max` and `clamp` publish the widest of the three
|
|
31
|
+
* length-percentage types, because a slot takes either. A call whose slots are
|
|
32
|
+
* all one kind is still that kind, and the fold is the one `+` already makes.
|
|
33
|
+
* Without it, `clamp(16px, 3vw, 24px)` — the tour's own line, and a legal
|
|
34
|
+
* `lineHeight` — would have started answering `LengthPercentage` and stopped
|
|
35
|
+
* assigning.
|
|
36
|
+
*
|
|
37
|
+
* `inferSlot` both infers a slot and remembers the answer, because the call's
|
|
38
|
+
* own analysis reads each argument again straight afterwards and must not
|
|
39
|
+
* report the argument's diagnostics a second time.
|
|
40
|
+
*/
|
|
41
|
+
export function foldedLengthPercentage(expression, builderOf, inferSlot, join) {
|
|
42
|
+
if (expression.callee.kind !== "IdentifierExpression")
|
|
43
|
+
return null;
|
|
44
|
+
const builder = builderOf(expression.callee.name);
|
|
45
|
+
const signature = builder === undefined ? undefined : LOOK_BUILDER_SIGNATURES.get(builder);
|
|
46
|
+
if (!signature || signature.result !== "length-percentage")
|
|
47
|
+
return null;
|
|
48
|
+
if (expression.arguments.length !== signature.parameters.length)
|
|
49
|
+
return null;
|
|
50
|
+
let folded = null;
|
|
51
|
+
for (const argument of expression.arguments) {
|
|
52
|
+
const slot = inferSlot(argument);
|
|
53
|
+
if (!isLookNumericType(slot))
|
|
54
|
+
return null;
|
|
55
|
+
folded = folded === null ? slot : join(folded, slot);
|
|
56
|
+
if (folded === null)
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
return folded;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=look-values.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"look-values.js","sourceRoot":"","sources":["../../src/analysis/look-values.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAmC,MAAM,iCAAiC,CAAC;AAClF,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE9E,MAAM,oBAAoB,GAAc,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC;AACpF,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,YAAY,EAAE,kBAAkB,CAAC,CAAC,CAAC;AAEpF,MAAM,UAAU,iBAAiB,CAAC,IAAe;IAC/C,OAAO,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,uBAAuB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAe,EAAE,KAAgB,EAAE,YAAqB;IACvF,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvE,IAAI,YAAY;QAAE,OAAO,IAAI,CAAC;IAC9B,OAAO,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;WACjD,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,qBAAqB,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;QAChF,CAAC,CAAC,oBAAoB;QACtB,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,sBAAsB,CACpC,UAA2D,EAC3D,SAA+C,EAC/C,SAA8C,EAC9C,IAA6D;IAE7D,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,KAAK,sBAAsB;QAAE,OAAO,IAAI,CAAC;IACnE,MAAM,OAAO,GAAG,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,uBAAuB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC3F,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,mBAAmB;QAAE,OAAO,IAAI,CAAC;IACxE,IAAI,UAAU,CAAC,SAAS,CAAC,MAAM,KAAK,SAAS,CAAC,UAAU,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAC7E,IAAI,MAAM,GAAqB,IAAI,CAAC;IACpC,KAAK,MAAM,QAAQ,IAAI,UAAU,CAAC,SAAS,EAAE,CAAC;QAC5C,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;QACjC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1C,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACrD,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;IACnC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* D114 0.29.0 LC-D1: `publicConfig(Type)` proved against the manifest that
|
|
3
|
+
* feeds it.
|
|
4
|
+
*
|
|
5
|
+
* A `velar/config` value is a *build input* — the same run reads `velar.json`
|
|
6
|
+
* and compiles the module, and web-api says the value is "baked into the
|
|
7
|
+
* content-hashed application entry at build time" — so a manifest that does not
|
|
8
|
+
* satisfy the declared type is provable before anything runs. It used to be
|
|
9
|
+
* provable nowhere: `check` and `build` were both silent, and the failure then
|
|
10
|
+
* arrived during module evaluation, ahead of `velar/app`'s error chain, so not
|
|
11
|
+
* even the compiler-owned fatal state could render. What the author got was a
|
|
12
|
+
* blank page and one uncaught host error.
|
|
13
|
+
*
|
|
14
|
+
* Runtime validation stays: a manifest a build baked in can be hand-edited
|
|
15
|
+
* afterwards. This only moves the answer to where the mistake is.
|
|
16
|
+
*
|
|
17
|
+
* D115 §三: its own module under `web/analysis/`, because the walk is a
|
|
18
|
+
* question about a JSON value and a type and needs nothing else from the
|
|
19
|
+
* analyzer than those two.
|
|
20
|
+
*/
|
|
21
|
+
import { type Diagnostic } from "@velarscript/compiler";
|
|
22
|
+
import { type Expression, type Program, type ValueType } from "@velarscript/compiler/extension";
|
|
23
|
+
/** What the walk asks of the analyzer that hosts it, and nothing more. */
|
|
24
|
+
export interface PublicConfigTypeHost {
|
|
25
|
+
expandAliases(type: ValueType): ValueType;
|
|
26
|
+
fieldsOf(identity: string): ReadonlyMap<string, ValueType> | null;
|
|
27
|
+
describeType(type: ValueType): string;
|
|
28
|
+
}
|
|
29
|
+
/** Local names bound to `publicConfig` from `velar/config`, including aliased imports. */
|
|
30
|
+
export declare function collectPublicConfigNames(program: Program): ReadonlySet<string>;
|
|
31
|
+
/**
|
|
32
|
+
* The manifest's `web.publicConfig`, or null when this compile read no project
|
|
33
|
+
* manifest. Null is not "empty": an empty section is a claim the compile may
|
|
34
|
+
* check, and no manifest is no claim at all.
|
|
35
|
+
*/
|
|
36
|
+
export declare function declaredPublicConfig(webProject: unknown): Readonly<Record<string, unknown>> | null;
|
|
37
|
+
/**
|
|
38
|
+
* The VEL5080 one `publicConfig(Type)` call earns, or null when this call makes
|
|
39
|
+
* no build-time claim or the manifest satisfies the type it names.
|
|
40
|
+
*/
|
|
41
|
+
export declare function publicConfigDiagnostic(expression: Extract<Expression, {
|
|
42
|
+
kind: "CallExpression";
|
|
43
|
+
}>, declared: ValueType, names: ReadonlySet<string>, manifest: Readonly<Record<string, unknown>> | null, host: PublicConfigTypeHost): Diagnostic | null;
|
|
44
|
+
//# sourceMappingURL=public-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-config.d.ts","sourceRoot":"","sources":["../../src/analysis/public-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAiB,KAAK,UAAU,EAAE,KAAK,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAE/G,0EAA0E;AAC1E,MAAM,WAAW,oBAAoB;IACnC,aAAa,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,IAAI,CAAC;IAClE,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;CACvC;AAED,0FAA0F;AAC1F,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,CAS9E;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,CAMlG;AAYD;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC,EAC3D,QAAQ,EAAE,SAAS,EACnB,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,EAC1B,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,EAClD,IAAI,EAAE,oBAAoB,GACzB,UAAU,GAAG,IAAI,CAcnB"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* D114 0.29.0 LC-D1: `publicConfig(Type)` proved against the manifest that
|
|
3
|
+
* feeds it.
|
|
4
|
+
*
|
|
5
|
+
* A `velar/config` value is a *build input* — the same run reads `velar.json`
|
|
6
|
+
* and compiles the module, and web-api says the value is "baked into the
|
|
7
|
+
* content-hashed application entry at build time" — so a manifest that does not
|
|
8
|
+
* satisfy the declared type is provable before anything runs. It used to be
|
|
9
|
+
* provable nowhere: `check` and `build` were both silent, and the failure then
|
|
10
|
+
* arrived during module evaluation, ahead of `velar/app`'s error chain, so not
|
|
11
|
+
* even the compiler-owned fatal state could render. What the author got was a
|
|
12
|
+
* blank page and one uncaught host error.
|
|
13
|
+
*
|
|
14
|
+
* Runtime validation stays: a manifest a build baked in can be hand-edited
|
|
15
|
+
* afterwards. This only moves the answer to where the mistake is.
|
|
16
|
+
*
|
|
17
|
+
* D115 §三: its own module under `web/analysis/`, because the walk is a
|
|
18
|
+
* question about a JSON value and a type and needs nothing else from the
|
|
19
|
+
* analyzer than those two.
|
|
20
|
+
*/
|
|
21
|
+
import {} from "@velarscript/compiler";
|
|
22
|
+
import { isInvalidType } from "@velarscript/compiler/extension";
|
|
23
|
+
/** Local names bound to `publicConfig` from `velar/config`, including aliased imports. */
|
|
24
|
+
export function collectPublicConfigNames(program) {
|
|
25
|
+
const names = new Set();
|
|
26
|
+
for (const statement of program.body) {
|
|
27
|
+
if (statement.kind !== "ImportDeclaration" || statement.source !== "velar/config" || statement.javascript)
|
|
28
|
+
continue;
|
|
29
|
+
for (const specifier of statement.specifiers) {
|
|
30
|
+
if (!specifier.namespace && specifier.imported === "publicConfig")
|
|
31
|
+
names.add(specifier.local);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return names;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The manifest's `web.publicConfig`, or null when this compile read no project
|
|
38
|
+
* manifest. Null is not "empty": an empty section is a claim the compile may
|
|
39
|
+
* check, and no manifest is no claim at all.
|
|
40
|
+
*/
|
|
41
|
+
export function declaredPublicConfig(webProject) {
|
|
42
|
+
if (webProject === undefined || webProject === null || typeof webProject !== "object")
|
|
43
|
+
return null;
|
|
44
|
+
const declared = webProject.publicConfig;
|
|
45
|
+
return declared && typeof declared === "object" && !Array.isArray(declared)
|
|
46
|
+
? declared
|
|
47
|
+
: {};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The name a `publicConfig(Type)` argument writes, or null when the argument is
|
|
51
|
+
* not a written type name. A computed or qualified runtime type carries no
|
|
52
|
+
* spelling for the diagnostic to quote and no claim the compile can hold to, so
|
|
53
|
+
* the build-time proof exists only where the type is written out at the call.
|
|
54
|
+
*/
|
|
55
|
+
function runtimeTypeArgumentName(argument) {
|
|
56
|
+
return argument?.kind === "IdentifierExpression" ? argument.name : null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The VEL5080 one `publicConfig(Type)` call earns, or null when this call makes
|
|
60
|
+
* no build-time claim or the manifest satisfies the type it names.
|
|
61
|
+
*/
|
|
62
|
+
export function publicConfigDiagnostic(expression, declared, names, manifest, host) {
|
|
63
|
+
if (manifest === null || expression.arguments.length !== 1)
|
|
64
|
+
return null;
|
|
65
|
+
if (expression.callee.kind !== "IdentifierExpression" || !names.has(expression.callee.name))
|
|
66
|
+
return null;
|
|
67
|
+
const typeName = runtimeTypeArgumentName(expression.arguments[0]);
|
|
68
|
+
if (typeName === null || declared.kind === "unknown" || declared.kind === "any" || isInvalidType(declared))
|
|
69
|
+
return null;
|
|
70
|
+
const reason = publicConfigMismatch(host, declared, manifest, "");
|
|
71
|
+
if (reason === null)
|
|
72
|
+
return null;
|
|
73
|
+
return {
|
|
74
|
+
code: "VEL5080",
|
|
75
|
+
message: `Value does not match ${typeName} — ${reason}.`
|
|
76
|
+
+ " 'publicConfig' reads the manifest's 'web.publicConfig', which this build bakes into the application entry,"
|
|
77
|
+
+ " so the value is already known here: add the field to 'web.publicConfig' in velar.json, or widen the declared type",
|
|
78
|
+
span: expression.span,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The first reason the manifest value fails the declared type, in the sentence
|
|
83
|
+
* the runtime validator uses, or null when nothing is provably wrong. Only a
|
|
84
|
+
* refusal that is certainly right is reported: a type this walk cannot decide —
|
|
85
|
+
* a class, a capability, a generic parameter — answers null rather than
|
|
86
|
+
* guessing, and the runtime keeps that case.
|
|
87
|
+
*/
|
|
88
|
+
function publicConfigMismatch(host, type, value, path) {
|
|
89
|
+
const expanded = host.expandAliases(type);
|
|
90
|
+
if (expanded.kind === "optional") {
|
|
91
|
+
return value === null || value === undefined ? null : publicConfigMismatch(host, expanded.inner, value, path);
|
|
92
|
+
}
|
|
93
|
+
if (value === undefined)
|
|
94
|
+
return path === "" ? "the value is missing" : `field '${path}' is missing`;
|
|
95
|
+
const fields = expanded.kind === "object"
|
|
96
|
+
? expanded.fields
|
|
97
|
+
: expanded.kind === "named" ? host.fieldsOf(expanded.identity ?? expanded.name) : null;
|
|
98
|
+
if (fields)
|
|
99
|
+
return recordMismatch(host, fields, expanded, value, path);
|
|
100
|
+
if (expanded.kind === "list") {
|
|
101
|
+
if (!Array.isArray(value))
|
|
102
|
+
return typeMismatch(host, expanded, path);
|
|
103
|
+
for (const [index, item] of value.entries()) {
|
|
104
|
+
const reason = publicConfigMismatch(host, expanded.element, item, `${path}[${index}]`);
|
|
105
|
+
if (reason !== null)
|
|
106
|
+
return reason;
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
const matches = expanded.kind === "string" ? typeof value === "string"
|
|
111
|
+
: expanded.kind === "number" ? typeof value === "number"
|
|
112
|
+
: expanded.kind === "bool" ? typeof value === "boolean"
|
|
113
|
+
: expanded.kind === "null" ? value === null
|
|
114
|
+
: null;
|
|
115
|
+
return matches === false ? typeMismatch(host, expanded, path) : null;
|
|
116
|
+
}
|
|
117
|
+
function recordMismatch(host, fields, expanded, value, path) {
|
|
118
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
119
|
+
return typeMismatch(host, expanded, path);
|
|
120
|
+
const record = value;
|
|
121
|
+
for (const [field, fieldType] of fields) {
|
|
122
|
+
const reason = publicConfigMismatch(host, fieldType, Object.hasOwn(record, field) ? record[field] : undefined, path ? `${path}.${field}` : field);
|
|
123
|
+
if (reason !== null)
|
|
124
|
+
return reason;
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
function typeMismatch(host, type, path) {
|
|
129
|
+
return path === ""
|
|
130
|
+
? `the value does not match ${host.describeType(type)}`
|
|
131
|
+
: `field '${path}' does not match ${host.describeType(type)}`;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=public-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-config.js","sourceRoot":"","sources":["../../src/analysis/public-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* D114 W: the reactive places a watch is about — the subject it watches, the
|
|
3
|
+
* places a body statement writes, and the one-hop `action`/`async def` writers
|
|
4
|
+
* of this module. Everything here is a question about *paths and statements*;
|
|
5
|
+
* nothing needs a type, which is why it reads as free functions and why, under
|
|
6
|
+
* D115 §三's `web/analysis/`, it is its own module rather than 280 lines in the
|
|
7
|
+
* middle of the Web analyzer.
|
|
8
|
+
*
|
|
9
|
+
* What a path *means* — whether the type at a depth is a collection, which of
|
|
10
|
+
* its calls mutate — stays with the analyzer and arrives as `ReactiveSubjectWrite`.
|
|
11
|
+
*/
|
|
12
|
+
import { type Span } from "@velarscript/compiler";
|
|
13
|
+
import { type Expression, type Program, type Statement, type ValueType } from "@velarscript/compiler/extension";
|
|
14
|
+
/**
|
|
15
|
+
* D114 W: one step a reactive path takes below its root — a named field, or an
|
|
16
|
+
* element under a key that names the same element on two evaluations. The steps
|
|
17
|
+
* are kept beside the rendered text because two questions are asked of a path:
|
|
18
|
+
* "is this the same place" answers on the text, and "is this place inside that
|
|
19
|
+
* one" has to walk, both to compare step by step and to descend the subject's
|
|
20
|
+
* type to the value the write lands on.
|
|
21
|
+
*/
|
|
22
|
+
export type ReactivePathStep = {
|
|
23
|
+
readonly kind: "field";
|
|
24
|
+
readonly name: string;
|
|
25
|
+
} | {
|
|
26
|
+
readonly kind: "index";
|
|
27
|
+
readonly key: string;
|
|
28
|
+
};
|
|
29
|
+
export interface ReactivePath {
|
|
30
|
+
readonly root: string;
|
|
31
|
+
readonly steps: readonly ReactivePathStep[];
|
|
32
|
+
/** The place as one comparable key, e.g. `items[0].done`. */
|
|
33
|
+
readonly text: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* D114 W: a reactive place written as one comparable key, so "the write and the
|
|
37
|
+
* subject name the same place" is one string equality.
|
|
38
|
+
*
|
|
39
|
+
* It is deliberately narrower than `renderWatchSubject`, which reconstructs any
|
|
40
|
+
* expression for a message. A key has to *decide*, so only the parts that name
|
|
41
|
+
* the same place on two evaluations are allowed into one: names, fields, and an
|
|
42
|
+
* index that is either a literal or another such path. `items[next()]` renders
|
|
43
|
+
* perfectly well and answers a different element every call, so it has no key
|
|
44
|
+
* and the shapes below stay silent on it — which is the right answer for a
|
|
45
|
+
* refusal that has to be right every time.
|
|
46
|
+
*/
|
|
47
|
+
export declare function reactivePathOf(expression: Expression): ReactivePath | null;
|
|
48
|
+
/**
|
|
49
|
+
* D114 0.28.0 H-D1: the steps a written place takes *below* the watch subject,
|
|
50
|
+
* `[]` when the write is the subject itself, and null when it is neither. §15
|
|
51
|
+
* says a watch fires on a deep change of its subject, so a write of a part of
|
|
52
|
+
* the subject is the same ring as a write of the subject — and a sibling
|
|
53
|
+
* (`watch form.name:` writing `form.email`) or a different root is not.
|
|
54
|
+
*/
|
|
55
|
+
export declare function reactiveStepsBelow(subject: ReactivePath, written: ReactivePath): readonly ReactivePathStep[] | null;
|
|
56
|
+
/**
|
|
57
|
+
* D114 W: the calls that mutate the value at one place, or null where the place
|
|
58
|
+
* holds no collection. One reading of the compiler's own roster, asked of the
|
|
59
|
+
* subject and of any place below it alike, so a deep mutating call and a direct
|
|
60
|
+
* one can never disagree about which methods write.
|
|
61
|
+
*/
|
|
62
|
+
export declare function collectionMutators(place: ValueType): ReadonlySet<string> | null;
|
|
63
|
+
/** The root name a reactive path starts from, which is the binding it resolves through. */
|
|
64
|
+
export declare function reactivePathRoot(expression: Expression): string | null;
|
|
65
|
+
/**
|
|
66
|
+
* D114 W: whether a body statement introduces its own binding of `name`. From
|
|
67
|
+
* that statement on, the spelling names something else, and a write through it
|
|
68
|
+
* is not a write of the watched place. The scan stops there rather than
|
|
69
|
+
* guessing which of the two a later line meant.
|
|
70
|
+
*/
|
|
71
|
+
export declare function statementBindsName(statement: Statement, name: string): boolean;
|
|
72
|
+
/**
|
|
73
|
+
* D114 W: the call a body statement makes when the statement is nothing but
|
|
74
|
+
* that call. `detach` is included because it is how a synchronous watch body
|
|
75
|
+
* starts asynchronous work — the tour and four charter fences spell the reload
|
|
76
|
+
* that way — so a refusal that only saw the bare call would miss the shape it
|
|
77
|
+
* exists for. Everything else (a call inside an `if`, an argument, an assigned
|
|
78
|
+
* result) is not a plain top-level call and is not offered here.
|
|
79
|
+
*/
|
|
80
|
+
export declare function topLevelCall(statement: Statement): Extract<Expression, {
|
|
81
|
+
readonly kind: "CallExpression";
|
|
82
|
+
}> | null;
|
|
83
|
+
/**
|
|
84
|
+
* D114 W: the reactive place one plain body statement writes, and how. An
|
|
85
|
+
* assignment or a compound assignment names its target and no method; a call
|
|
86
|
+
* names its receiver and the method called on it, and the caller decides
|
|
87
|
+
* whether that method mutates — the roster depends on the kind of value at the
|
|
88
|
+
* receiver, which only the caller holds a type for.
|
|
89
|
+
*/
|
|
90
|
+
export interface ReactiveWriteCandidate {
|
|
91
|
+
readonly place: ReactivePath;
|
|
92
|
+
/** The method called on `place`, or null when the statement is an assignment. */
|
|
93
|
+
readonly method: string | null;
|
|
94
|
+
}
|
|
95
|
+
export declare function reactiveWriteCandidate(statement: Statement): ReactiveWriteCandidate | null;
|
|
96
|
+
/**
|
|
97
|
+
* D114 W: whether one plain body statement writes the watched place — the
|
|
98
|
+
* subject itself, or any place below it. An assignment or a compound
|
|
99
|
+
* assignment to it is one; so is a call of a mutating collection method on it,
|
|
100
|
+
* because a watch on a collection fires on its deep mutation and `mutators`
|
|
101
|
+
* answers the compiler's own roster of the calls that mutate whatever sits at
|
|
102
|
+
* that depth.
|
|
103
|
+
*
|
|
104
|
+
* D114 0.28.0 H-D1's other half: `watch form: rename()` where `rename` writes
|
|
105
|
+
* `form.name` is the same ring as `watch form: form.name = …`, which F1 already
|
|
106
|
+
* refuses. The subject and the writer question read one comparison —
|
|
107
|
+
* `reactiveStepsBelow` — so a deep write cannot be a cycle at one of them and
|
|
108
|
+
* not at the other.
|
|
109
|
+
*/
|
|
110
|
+
export declare function reactiveWriteOf(statement: Statement, subject: ReactivePath, writes: ReactiveSubjectWrite): ReactivePath | null;
|
|
111
|
+
/**
|
|
112
|
+
* Whether a write `steps` below the watched subject, made the given way, is a
|
|
113
|
+
* write of the subject. Only the analyzer can answer it — the roster of
|
|
114
|
+
* mutating calls depends on the type at that depth — so both the body scan and
|
|
115
|
+
* the one-hop writer scan are handed the same closure rather than each deciding
|
|
116
|
+
* what counts as a write.
|
|
117
|
+
*/
|
|
118
|
+
export type ReactiveSubjectWrite = (steps: readonly ReactivePathStep[], method: string | null) => boolean;
|
|
119
|
+
/**
|
|
120
|
+
* D114 W A2(b): whether an `action` or `async def` writes `path` at its own top
|
|
121
|
+
* level, unconditionally. One hop: what the callee itself calls is not
|
|
122
|
+
* followed. A parameter of the callee's own that is spelled like the path's
|
|
123
|
+
* root, or a binding it declares before the write, means the write is not of
|
|
124
|
+
* the watched place and the answer is no.
|
|
125
|
+
*/
|
|
126
|
+
export declare function writerWritesPath(writer: ReactiveWriterDeclaration, subject: ReactivePath, writes: ReactiveSubjectWrite): ReactivePath | null;
|
|
127
|
+
/**
|
|
128
|
+
* D114 W A2(b): the `action` and `async def` declarations of one module, by
|
|
129
|
+
* name. A name declared twice — or once as an ordinary `def` — answers `null`,
|
|
130
|
+
* because the refusal must know exactly which body a call reaches and two
|
|
131
|
+
* candidates mean it does not.
|
|
132
|
+
*
|
|
133
|
+
* The walk is `collectModuleFunctions`'s: module body, component bodies, and
|
|
134
|
+
* the bodies of the functions themselves, so a nested declaration of a name
|
|
135
|
+
* makes that name ambiguous here rather than silently resolving to the outer
|
|
136
|
+
* one.
|
|
137
|
+
*/
|
|
138
|
+
export interface ReactiveWriterDeclaration {
|
|
139
|
+
readonly spelling: "action" | "async def";
|
|
140
|
+
readonly parameters: readonly string[];
|
|
141
|
+
readonly body: readonly Statement[];
|
|
142
|
+
}
|
|
143
|
+
export declare function collectReactiveWriters(program: Program): ReadonlyMap<string, ReactiveWriterDeclaration | null>;
|
|
144
|
+
/**
|
|
145
|
+
* D114 0.28.0 H-D1: the VEL5077 message one plain body statement earns, or null
|
|
146
|
+
* when it earns none.
|
|
147
|
+
*
|
|
148
|
+
* §15 says a watch fires on a *deep* change of its subject, so `watch form:
|
|
149
|
+
* form.name = …` and `watch items: items[0].done = …` are the same ring
|
|
150
|
+
* `items.append(…)` already is — decided at the top of the body, with no
|
|
151
|
+
* condition to end it — and were silent until the runtime's 100-round cap
|
|
152
|
+
* stopped them. The rule is therefore stated on the path rather than on the
|
|
153
|
+
* spelling: a write whose place is the subject, or any place below it, in an
|
|
154
|
+
* assignment, a compound assignment, or a mutating call.
|
|
155
|
+
*
|
|
156
|
+
* Every existing exclusion stands, because each is answered somewhere else: a
|
|
157
|
+
* conditional or nested write is not a plain body statement, a rebinding stops
|
|
158
|
+
* the scan in `rejectWatchCycle`, and a sibling path (`watch form.name:` writing
|
|
159
|
+
* `form.email`) or a different root fails the step comparison here.
|
|
160
|
+
*/
|
|
161
|
+
export declare function watchSelfWrite(subject: Expression, place: ReactivePath, statement: Statement, writes: ReactiveSubjectWrite, position?: string): string | null;
|
|
162
|
+
/**
|
|
163
|
+
* D114 0.29.0 ST-D2: `finally` is the one nested block a body cannot get out of.
|
|
164
|
+
* §15 refuses a body whose top level *unconditionally* writes its own subject,
|
|
165
|
+
* and "nested" had been standing in for "conditional" — but a `for` body may run
|
|
166
|
+
* zero times, a `try` body may be cut short by a throw and a `match` arm is
|
|
167
|
+
* chosen by data, while every path through a `try` at the body's top level
|
|
168
|
+
* passes through its `finally`. So the write there is proved the same way a
|
|
169
|
+
* top-level write is, and only there: a `try` inside an `if` is a conditional
|
|
170
|
+
* again and stays the runtime cap's (ST-U1).
|
|
171
|
+
*/
|
|
172
|
+
export declare function finallySelfWrite(subject: Expression, place: ReactivePath, statement: Statement, writes: ReactiveSubjectWrite, root: string): {
|
|
173
|
+
readonly message: string;
|
|
174
|
+
readonly span: Span;
|
|
175
|
+
} | null;
|
|
176
|
+
//# sourceMappingURL=watch-cycles.d.ts.map
|