@velarscript/web 0.30.1 → 0.32.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 +1 -1
- package/dist/analysis/calls/intrinsics/config.d.ts +10 -0
- package/dist/analysis/calls/intrinsics/config.d.ts.map +1 -0
- package/dist/analysis/calls/intrinsics/config.js +19 -0
- package/dist/analysis/calls/intrinsics/config.js.map +1 -0
- package/dist/analysis/calls/intrinsics/forms.d.ts +10 -0
- package/dist/analysis/calls/intrinsics/forms.d.ts.map +1 -0
- package/dist/analysis/calls/intrinsics/forms.js +38 -0
- package/dist/analysis/calls/intrinsics/forms.js.map +1 -0
- package/dist/analysis/calls/intrinsics/http.d.ts +10 -0
- package/dist/analysis/calls/intrinsics/http.d.ts.map +1 -0
- package/dist/analysis/calls/intrinsics/http.js +37 -0
- package/dist/analysis/calls/intrinsics/http.js.map +1 -0
- package/dist/analysis/calls/intrinsics/reactive.d.ts +10 -0
- package/dist/analysis/calls/intrinsics/reactive.d.ts.map +1 -0
- package/dist/analysis/calls/intrinsics/reactive.js +30 -0
- package/dist/analysis/calls/intrinsics/reactive.js.map +1 -0
- package/dist/analysis/calls/intrinsics/storage.d.ts +12 -0
- package/dist/analysis/calls/intrinsics/storage.d.ts.map +1 -0
- package/dist/analysis/calls/intrinsics/storage.js +86 -0
- package/dist/analysis/calls/intrinsics/storage.js.map +1 -0
- package/dist/analysis/calls/intrinsics/web.d.ts +10 -0
- package/dist/analysis/calls/intrinsics/web.d.ts.map +1 -0
- package/dist/analysis/calls/intrinsics/web.js +100 -0
- package/dist/analysis/calls/intrinsics/web.js.map +1 -0
- package/dist/analysis/calls/intrinsics.d.ts +13 -0
- package/dist/analysis/calls/intrinsics.d.ts.map +1 -0
- package/dist/analysis/calls/intrinsics.js +31 -0
- package/dist/analysis/calls/intrinsics.js.map +1 -0
- package/dist/analysis/components/contracts.d.ts +19 -0
- package/dist/analysis/components/contracts.d.ts.map +1 -0
- package/dist/analysis/components/contracts.js +83 -0
- package/dist/analysis/components/contracts.js.map +1 -0
- package/dist/analysis/components/declaration.d.ts +4 -0
- package/dist/analysis/components/declaration.d.ts.map +1 -0
- package/dist/analysis/components/declaration.js +163 -0
- package/dist/analysis/components/declaration.js.map +1 -0
- package/dist/analysis/components/host.d.ts +61 -0
- package/dist/analysis/components/host.d.ts.map +1 -0
- package/dist/analysis/components/host.js +22 -0
- package/dist/analysis/components/host.js.map +1 -0
- package/dist/analysis/components/lifecycle.d.ts +22 -0
- package/dist/analysis/components/lifecycle.d.ts.map +1 -0
- package/dist/analysis/components/lifecycle.js +33 -0
- package/dist/analysis/components/lifecycle.js.map +1 -0
- package/dist/analysis/components/ownership.d.ts +74 -0
- package/dist/analysis/components/ownership.d.ts.map +1 -0
- package/dist/analysis/components/ownership.js +106 -0
- package/dist/analysis/components/ownership.js.map +1 -0
- package/dist/analysis/declarations.d.ts +99 -0
- package/dist/analysis/declarations.d.ts.map +1 -0
- package/dist/analysis/declarations.js +176 -0
- package/dist/analysis/declarations.js.map +1 -0
- package/dist/analysis/inference.d.ts +67 -0
- package/dist/analysis/inference.d.ts.map +1 -0
- package/dist/analysis/inference.js +236 -0
- package/dist/analysis/inference.js.map +1 -0
- package/dist/analysis/jsx/attributes.d.ts +103 -0
- package/dist/analysis/jsx/attributes.d.ts.map +1 -0
- package/dist/analysis/jsx/attributes.js +601 -0
- package/dist/analysis/jsx/attributes.js.map +1 -0
- package/dist/analysis/jsx/elements.d.ts +17 -0
- package/dist/analysis/jsx/elements.d.ts.map +1 -0
- package/dist/analysis/jsx/elements.js +213 -0
- package/dist/analysis/jsx/elements.js.map +1 -0
- package/dist/analysis/jsx/host.d.ts +61 -0
- package/dist/analysis/jsx/host.d.ts.map +1 -0
- package/dist/analysis/jsx/host.js +15 -0
- package/dist/analysis/jsx/host.js.map +1 -0
- package/dist/analysis/jsx/keys.d.ts +15 -0
- package/dist/analysis/jsx/keys.d.ts.map +1 -0
- package/dist/analysis/jsx/keys.js +67 -0
- package/dist/analysis/jsx/keys.js.map +1 -0
- package/dist/analysis/jsx/security.d.ts +29 -0
- package/dist/analysis/jsx/security.d.ts.map +1 -0
- package/dist/analysis/jsx/security.js +61 -0
- package/dist/analysis/jsx/security.js.map +1 -0
- package/dist/analysis/jsx-detection.d.ts +49 -0
- package/dist/analysis/jsx-detection.d.ts.map +1 -0
- package/dist/analysis/jsx-detection.js +196 -0
- package/dist/analysis/jsx-detection.js.map +1 -0
- package/dist/analysis/keyed-rebuild.d.ts +148 -0
- package/dist/analysis/keyed-rebuild.d.ts.map +1 -0
- package/dist/analysis/keyed-rebuild.js +299 -0
- package/dist/analysis/keyed-rebuild.js.map +1 -0
- package/dist/analysis/keyframes-analysis.d.ts +6 -0
- package/dist/analysis/keyframes-analysis.d.ts.map +1 -0
- package/dist/analysis/keyframes-analysis.js +79 -0
- package/dist/analysis/keyframes-analysis.js.map +1 -0
- package/dist/analysis/look/builders.d.ts +29 -0
- package/dist/analysis/look/builders.d.ts.map +1 -0
- package/dist/analysis/look/builders.js +168 -0
- package/dist/analysis/look/builders.js.map +1 -0
- package/dist/analysis/look/conditions.d.ts +13 -0
- package/dist/analysis/look/conditions.d.ts.map +1 -0
- package/dist/analysis/look/conditions.js +84 -0
- package/dist/analysis/look/conditions.js.map +1 -0
- package/dist/analysis/look/edits.d.ts +25 -0
- package/dist/analysis/look/edits.d.ts.map +1 -0
- package/dist/analysis/look/edits.js +57 -0
- package/dist/analysis/look/edits.js.map +1 -0
- package/dist/analysis/look/entries.d.ts +56 -0
- package/dist/analysis/look/entries.d.ts.map +1 -0
- package/dist/analysis/look/entries.js +223 -0
- package/dist/analysis/look/entries.js.map +1 -0
- package/dist/analysis/look/host.d.ts +47 -0
- package/dist/analysis/look/host.d.ts.map +1 -0
- package/dist/analysis/look/host.js +16 -0
- package/dist/analysis/look/host.js.map +1 -0
- package/dist/analysis/look/tokens.d.ts +75 -0
- package/dist/analysis/look/tokens.d.ts.map +1 -0
- package/dist/analysis/look/tokens.js +151 -0
- package/dist/analysis/look/tokens.js.map +1 -0
- package/dist/analysis/look/values.d.ts +45 -0
- package/dist/analysis/look/values.d.ts.map +1 -0
- package/dist/analysis/look/values.js +148 -0
- package/dist/analysis/look/values.js.map +1 -0
- package/dist/analysis/look-conditions.d.ts +47 -0
- package/dist/analysis/look-conditions.d.ts.map +1 -0
- package/dist/analysis/look-conditions.js +157 -0
- package/dist/analysis/look-conditions.js.map +1 -0
- package/dist/analysis/look-sites.d.ts +54 -0
- package/dist/analysis/look-sites.d.ts.map +1 -0
- package/dist/analysis/look-sites.js +104 -0
- package/dist/analysis/look-sites.js.map +1 -0
- package/dist/analysis/look-vocabulary-guidance.d.ts +76 -0
- package/dist/analysis/look-vocabulary-guidance.d.ts.map +1 -0
- package/dist/analysis/look-vocabulary-guidance.js +338 -0
- package/dist/analysis/look-vocabulary-guidance.js.map +1 -0
- package/dist/analysis/media-conditions.d.ts +33 -0
- package/dist/analysis/media-conditions.d.ts.map +1 -0
- package/dist/analysis/media-conditions.js +92 -0
- package/dist/analysis/media-conditions.js.map +1 -0
- package/dist/analysis/program-passes.d.ts +106 -0
- package/dist/analysis/program-passes.d.ts.map +1 -0
- package/dist/analysis/program-passes.js +149 -0
- package/dist/analysis/program-passes.js.map +1 -0
- package/dist/analysis/reactivity/bindings.d.ts +37 -0
- package/dist/analysis/reactivity/bindings.d.ts.map +1 -0
- package/dist/analysis/reactivity/bindings.js +88 -0
- package/dist/analysis/reactivity/bindings.js.map +1 -0
- package/dist/analysis/reactivity/derived.d.ts +39 -0
- package/dist/analysis/reactivity/derived.d.ts.map +1 -0
- package/dist/analysis/reactivity/derived.js +80 -0
- package/dist/analysis/reactivity/derived.js.map +1 -0
- package/dist/analysis/reactivity/host.d.ts +38 -0
- package/dist/analysis/reactivity/host.d.ts.map +1 -0
- package/dist/analysis/reactivity/host.js +14 -0
- package/dist/analysis/reactivity/host.js.map +1 -0
- package/dist/analysis/reactivity/retired-accessors.d.ts +82 -0
- package/dist/analysis/reactivity/retired-accessors.d.ts.map +1 -0
- package/dist/analysis/reactivity/retired-accessors.js +118 -0
- package/dist/analysis/reactivity/retired-accessors.js.map +1 -0
- package/dist/analysis/renderable.d.ts +47 -0
- package/dist/analysis/renderable.d.ts.map +1 -0
- package/dist/analysis/renderable.js +105 -0
- package/dist/analysis/renderable.js.map +1 -0
- package/dist/analysis/routes.d.ts +64 -0
- package/dist/analysis/routes.d.ts.map +1 -0
- package/dist/analysis/routes.js +182 -0
- package/dist/analysis/routes.js.map +1 -0
- package/dist/analysis/url-attributes.d.ts +12 -0
- package/dist/analysis/url-attributes.d.ts.map +1 -0
- package/dist/analysis/url-attributes.js +48 -0
- package/dist/analysis/url-attributes.js.map +1 -0
- package/dist/analysis/watch-cycles.d.ts +102 -0
- package/dist/analysis/watch-cycles.d.ts.map +1 -1
- package/dist/analysis/watch-cycles.js +240 -1
- package/dist/analysis/watch-cycles.js.map +1 -1
- package/dist/analysis/watch-subject.d.ts +45 -0
- package/dist/analysis/watch-subject.d.ts.map +1 -0
- package/dist/analysis/watch-subject.js +272 -0
- package/dist/analysis/watch-subject.js.map +1 -0
- package/dist/analysis/web-types.d.ts +27 -0
- package/dist/analysis/web-types.d.ts.map +1 -0
- package/dist/analysis/web-types.js +170 -0
- package/dist/analysis/web-types.js.map +1 -0
- package/dist/analyzer.d.ts +18 -617
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +208 -4853
- package/dist/analyzer.js.map +1 -1
- package/dist/compiler.d.ts +20 -0
- package/dist/compiler.d.ts.map +1 -1
- package/dist/compiler.js +29 -864
- package/dist/compiler.js.map +1 -1
- package/dist/documentation.d.ts +28 -0
- package/dist/documentation.d.ts.map +1 -0
- package/dist/documentation.js +67 -0
- package/dist/documentation.js.map +1 -0
- package/dist/editor/completions.d.ts +12 -0
- package/dist/editor/completions.d.ts.map +1 -0
- package/dist/editor/completions.js +6 -0
- package/dist/editor/completions.js.map +1 -0
- package/dist/editor/jsx-completion.d.ts +12 -0
- package/dist/editor/jsx-completion.d.ts.map +1 -0
- package/dist/editor/jsx-completion.js +137 -0
- package/dist/editor/jsx-completion.js.map +1 -0
- package/dist/editor/look-completion.d.ts +29 -0
- package/dist/editor/look-completion.d.ts.map +1 -0
- package/dist/editor/look-completion.js +159 -0
- package/dist/editor/look-completion.js.map +1 -0
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +12 -288
- package/dist/editor.js.map +1 -1
- package/dist/emit/components.d.ts +33 -0
- package/dist/emit/components.d.ts.map +1 -0
- package/dist/emit/components.js +135 -0
- package/dist/emit/components.js.map +1 -0
- package/dist/emit/jsx.d.ts +57 -0
- package/dist/emit/jsx.d.ts.map +1 -0
- package/dist/emit/jsx.js +384 -0
- package/dist/emit/jsx.js.map +1 -0
- package/dist/emit/look-css.d.ts +44 -0
- package/dist/emit/look-css.d.ts.map +1 -0
- package/dist/emit/look-css.js +177 -0
- package/dist/emit/look-css.js.map +1 -0
- package/dist/emit/look.d.ts +39 -0
- package/dist/emit/look.d.ts.map +1 -0
- package/dist/emit/look.js +218 -0
- package/dist/emit/look.js.map +1 -0
- package/dist/emit/runtime-imports.d.ts +40 -0
- package/dist/emit/runtime-imports.d.ts.map +1 -0
- package/dist/emit/runtime-imports.js +184 -0
- package/dist/emit/runtime-imports.js.map +1 -0
- package/dist/emitter.d.ts +15 -68
- package/dist/emitter.d.ts.map +1 -1
- package/dist/emitter.js +79 -1008
- package/dist/emitter.js.map +1 -1
- package/dist/look/animation.d.ts +7 -0
- package/dist/look/animation.d.ts.map +1 -0
- package/dist/look/animation.js +13 -0
- package/dist/look/animation.js.map +1 -0
- package/dist/look/builders.d.ts +35 -0
- package/dist/look/builders.d.ts.map +1 -0
- package/dist/look/builders.js +74 -0
- package/dist/look/builders.js.map +1 -0
- package/dist/look/css-functions.d.ts +28 -0
- package/dist/look/css-functions.d.ts.map +1 -0
- package/dist/look/css-functions.js +54 -0
- package/dist/look/css-functions.js.map +1 -0
- package/dist/look/keyword-sets.d.ts +41 -0
- package/dist/look/keyword-sets.d.ts.map +1 -0
- package/dist/look/keyword-sets.js +117 -0
- package/dist/look/keyword-sets.js.map +1 -0
- package/dist/look/keywords.d.ts +55 -0
- package/dist/look/keywords.d.ts.map +1 -0
- package/dist/look/keywords.js +387 -0
- package/dist/look/keywords.js.map +1 -0
- package/dist/look/media.d.ts +19 -0
- package/dist/look/media.d.ts.map +1 -0
- package/dist/look/media.js +27 -0
- package/dist/look/media.js.map +1 -0
- package/dist/look/naming.d.ts +9 -0
- package/dist/look/naming.d.ts.map +1 -0
- package/dist/look/naming.js +45 -0
- package/dist/look/naming.js.map +1 -0
- package/dist/look/properties.d.ts +16 -0
- package/dist/look/properties.d.ts.map +1 -0
- package/dist/look/properties.js +52 -0
- package/dist/look/properties.js.map +1 -0
- package/dist/look/shorthands.d.ts +25 -0
- package/dist/look/shorthands.d.ts.map +1 -0
- package/dist/look/shorthands.js +130 -0
- package/dist/look/shorthands.js.map +1 -0
- package/dist/look/tokens.d.ts +38 -0
- package/dist/look/tokens.d.ts.map +1 -0
- package/dist/look/tokens.js +59 -0
- package/dist/look/tokens.js.map +1 -0
- package/dist/look/units.d.ts +24 -0
- package/dist/look/units.d.ts.map +1 -0
- package/dist/look/units.js +33 -0
- package/dist/look/units.js.map +1 -0
- package/dist/look.d.ts +32 -227
- package/dist/look.d.ts.map +1 -1
- package/dist/look.js +28 -933
- package/dist/look.js.map +1 -1
- package/dist/module-roster.d.ts +16 -0
- package/dist/module-roster.d.ts.map +1 -0
- package/dist/module-roster.js +28 -0
- package/dist/module-roster.js.map +1 -0
- package/dist/modules/app.d.ts +9 -0
- package/dist/modules/app.d.ts.map +1 -0
- package/dist/modules/app.js +20 -0
- package/dist/modules/app.js.map +1 -0
- package/dist/modules/browser-test.d.ts +9 -0
- package/dist/modules/browser-test.d.ts.map +1 -0
- package/dist/modules/browser-test.js +67 -0
- package/dist/modules/browser-test.js.map +1 -0
- package/dist/modules/browser.d.ts +10 -0
- package/dist/modules/browser.d.ts.map +1 -0
- package/dist/modules/browser.js +89 -0
- package/dist/modules/browser.js.map +1 -0
- package/dist/modules/config.d.ts +9 -0
- package/dist/modules/config.d.ts.map +1 -0
- package/dist/modules/config.js +14 -0
- package/dist/modules/config.js.map +1 -0
- package/dist/modules/files.d.ts +9 -0
- package/dist/modules/files.d.ts.map +1 -0
- package/dist/modules/files.js +16 -0
- package/dist/modules/files.js.map +1 -0
- package/dist/modules/forms.d.ts +9 -0
- package/dist/modules/forms.d.ts.map +1 -0
- package/dist/modules/forms.js +26 -0
- package/dist/modules/forms.js.map +1 -0
- package/dist/modules/http.d.ts +9 -0
- package/dist/modules/http.d.ts.map +1 -0
- package/dist/modules/http.js +127 -0
- package/dist/modules/http.js.map +1 -0
- package/dist/modules/look.d.ts +9 -0
- package/dist/modules/look.d.ts.map +1 -0
- package/dist/modules/look.js +58 -0
- package/dist/modules/look.js.map +1 -0
- package/dist/modules/realtime.d.ts +9 -0
- package/dist/modules/realtime.d.ts.map +1 -0
- package/dist/modules/realtime.js +163 -0
- package/dist/modules/realtime.js.map +1 -0
- package/dist/modules/storage.d.ts +9 -0
- package/dist/modules/storage.d.ts.map +1 -0
- package/dist/modules/storage.js +59 -0
- package/dist/modules/storage.js.map +1 -0
- package/dist/modules/types.d.ts +78 -0
- package/dist/modules/types.d.ts.map +1 -0
- package/dist/modules/types.js +154 -0
- package/dist/modules/types.js.map +1 -0
- package/dist/modules/web.d.ts +9 -0
- package/dist/modules/web.d.ts.map +1 -0
- package/dist/modules/web.js +63 -0
- package/dist/modules/web.js.map +1 -0
- package/dist/modules/websocket.d.ts +11 -0
- package/dist/modules/websocket.d.ts.map +1 -0
- package/dist/modules/websocket.js +75 -0
- package/dist/modules/websocket.js.map +1 -0
- package/dist/parser/expressions/jsx.d.ts +17 -0
- package/dist/parser/expressions/jsx.d.ts.map +1 -0
- package/dist/parser/expressions/jsx.js +43 -0
- package/dist/parser/expressions/jsx.js.map +1 -0
- package/dist/parser/expressions/keyframes.d.ts +15 -0
- package/dist/parser/expressions/keyframes.d.ts.map +1 -0
- package/dist/parser/expressions/keyframes.js +33 -0
- package/dist/parser/expressions/keyframes.js.map +1 -0
- package/dist/parser/expressions/look.d.ts +16 -0
- package/dist/parser/expressions/look.d.ts.map +1 -0
- package/dist/parser/expressions/look.js +37 -0
- package/dist/parser/expressions/look.js.map +1 -0
- package/dist/parser/expressions/visual-block.d.ts +17 -0
- package/dist/parser/expressions/visual-block.d.ts.map +1 -0
- package/dist/parser/expressions/visual-block.js +21 -0
- package/dist/parser/expressions/visual-block.js.map +1 -0
- package/dist/parser/keyframes-source.d.ts +24 -0
- package/dist/parser/keyframes-source.d.ts.map +1 -0
- package/dist/parser/keyframes-source.js +133 -0
- package/dist/parser/keyframes-source.js.map +1 -0
- package/dist/parser/look-source.d.ts +25 -0
- package/dist/parser/look-source.d.ts.map +1 -0
- package/dist/parser/look-source.js +189 -0
- package/dist/parser/look-source.js.map +1 -0
- package/dist/parser/spans.d.ts +24 -0
- package/dist/parser/spans.d.ts.map +1 -0
- package/dist/parser/spans.js +113 -0
- package/dist/parser/spans.js.map +1 -0
- package/dist/parser/statements/components.d.ts +37 -0
- package/dist/parser/statements/components.d.ts.map +1 -0
- package/dist/parser/statements/components.js +185 -0
- package/dist/parser/statements/components.js.map +1 -0
- package/dist/parser/statements/heads.d.ts +38 -0
- package/dist/parser/statements/heads.d.ts.map +1 -0
- package/dist/parser/statements/heads.js +55 -0
- package/dist/parser/statements/heads.js.map +1 -0
- package/dist/parser/statements/imports.d.ts +9 -0
- package/dist/parser/statements/imports.d.ts.map +1 -0
- package/dist/parser/statements/imports.js +31 -0
- package/dist/parser/statements/imports.js.map +1 -0
- package/dist/parser/statements/reactive.d.ts +31 -0
- package/dist/parser/statements/reactive.d.ts.map +1 -0
- package/dist/parser/statements/reactive.js +68 -0
- package/dist/parser/statements/reactive.js.map +1 -0
- package/dist/parser/statements/unsafe-css.d.ts +21 -0
- package/dist/parser/statements/unsafe-css.d.ts.map +1 -0
- package/dist/parser/statements/unsafe-css.js +42 -0
- package/dist/parser/statements/unsafe-css.js.map +1 -0
- package/dist/parser.d.ts +37 -50
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +98 -882
- package/dist/parser.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The retired 'computed(...)' accessor: the intrinsic a call around it is still
|
|
3
|
+
* typed by, and the shape of one declaration held for the migration message.
|
|
4
|
+
*
|
|
5
|
+
* D115 P4 R3a: a frozen table and a record shape, read by the analyzer and by
|
|
6
|
+
* the intrinsic that types the call, so they read as a module.
|
|
7
|
+
*
|
|
8
|
+
* D115 P4 R3c: the migration pass itself joins them — what one declaration
|
|
9
|
+
* records, what one read records, and the one message per site the whole-program
|
|
10
|
+
* report writes — over a `RetiredAccessorHost`.
|
|
11
|
+
*/
|
|
12
|
+
import {} from "@velarscript/compiler";
|
|
13
|
+
import { spanIdentity, unknownType } from "@velarscript/compiler/extension";
|
|
14
|
+
import { isRetiredAccessorName } from "../reactive-names.js";
|
|
15
|
+
import { diagnostic } from "../web-types.js";
|
|
16
|
+
export const RETIRED_ACCESSOR_INTRINSIC = "reactive.retired-accessor";
|
|
17
|
+
const retiredAccessorReaderType = Object.freeze({ kind: "function", parameters: [], requiredParameters: 0, result: unknownType });
|
|
18
|
+
export const RETIRED_ACCESSOR_TYPE = Object.freeze({
|
|
19
|
+
kind: "intrinsic",
|
|
20
|
+
name: RETIRED_ACCESSOR_INTRINSIC,
|
|
21
|
+
parameterNames: ["read"],
|
|
22
|
+
parameters: [retiredAccessorReaderType],
|
|
23
|
+
requiredParameters: 1,
|
|
24
|
+
result: retiredAccessorReaderType,
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* D71 rule 183: `computed(...)` the function — the shape Vue and the signals
|
|
28
|
+
* libraries teach — is not how a derived value is written here; the `computed`
|
|
29
|
+
* declaration is. The declaration is recorded before the core walks the module
|
|
30
|
+
* so its reads can be matched against it — the rewrite that removes the call
|
|
31
|
+
* parentheses is only offered when every read is a plain `x()`.
|
|
32
|
+
*/
|
|
33
|
+
export function recordRetiredAccessorDeclaration(host, statement) {
|
|
34
|
+
const initializer = statement.initializer;
|
|
35
|
+
if (initializer.kind !== "CallExpression" || initializer.callee.kind !== "IdentifierExpression"
|
|
36
|
+
|| !isRetiredAccessorName(initializer.callee.name) || host.lookup(initializer.callee.name) !== null)
|
|
37
|
+
return;
|
|
38
|
+
if (statement.binding !== "const" || statement.pattern.kind !== "NameBindingPattern")
|
|
39
|
+
return;
|
|
40
|
+
const read = initializer.arguments.length === 1 && initializer.argumentNames === undefined
|
|
41
|
+
? initializer.arguments[0] : null;
|
|
42
|
+
// Only the `() => E` shape has a body that becomes the declaration's
|
|
43
|
+
// initializer verbatim. Every other argument — a named function, a partial
|
|
44
|
+
// application — would need the rewriter to invent an expression, so it is
|
|
45
|
+
// left to the author with the call spelled out as its only mechanical answer.
|
|
46
|
+
const body = read?.kind === "ArrowFunctionExpression" && !read.asynchronous && read.parameters.length === 0
|
|
47
|
+
? read.body : null;
|
|
48
|
+
host.retiredAccessorDeclarations.set(spanIdentity(statement.pattern.span), {
|
|
49
|
+
name: statement.pattern.name,
|
|
50
|
+
exported: statement.exported,
|
|
51
|
+
readName: read?.kind === "IdentifierExpression" ? read.name : null,
|
|
52
|
+
declarationSpan: statement.span,
|
|
53
|
+
callSpan: initializer.span,
|
|
54
|
+
bodySpan: body ? body.span : null,
|
|
55
|
+
});
|
|
56
|
+
host.migratedComputedCallees.add(spanIdentity(initializer.callee.span));
|
|
57
|
+
}
|
|
58
|
+
/** Returns true when the name is one of the retired accessor globals this pass owns. */
|
|
59
|
+
export function recordRetiredAccessorRead(host, expression) {
|
|
60
|
+
if (isRetiredAccessorName(expression.name)) {
|
|
61
|
+
if (host.lookup(expression.name) !== null)
|
|
62
|
+
return false;
|
|
63
|
+
if (!host.migratedComputedCallees.has(spanIdentity(expression.span))) {
|
|
64
|
+
host.retiredComputedReferences.set(spanIdentity(expression.span), { name: expression.name, span: expression.span });
|
|
65
|
+
}
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
const binding = host.lookup(expression.name);
|
|
69
|
+
if (!binding)
|
|
70
|
+
return false;
|
|
71
|
+
const key = spanIdentity(binding.span);
|
|
72
|
+
if (!host.retiredAccessorDeclarations.has(key))
|
|
73
|
+
return false;
|
|
74
|
+
const reads = host.retiredAccessorReads.get(key);
|
|
75
|
+
if (reads)
|
|
76
|
+
reads.push(expression.span);
|
|
77
|
+
else
|
|
78
|
+
host.retiredAccessorReads.set(key, [expression.span]);
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* D71 migration: one message per site, and a mechanical rewrite only where
|
|
83
|
+
* the compile can prove the rewrite. Where the
|
|
84
|
+
* accessor is used as a value there is no second spelling left to offer, so
|
|
85
|
+
* that site is told to declare the value and write an ordinary `def` where a
|
|
86
|
+
* callable is what the caller wants — and it gets no edit, because moving a
|
|
87
|
+
* reader out of a value position is the author's decision.
|
|
88
|
+
*/
|
|
89
|
+
export function reportRetiredComputedFunction(host) {
|
|
90
|
+
for (const [key, accessor] of host.retiredAccessorDeclarations) {
|
|
91
|
+
const reads = host.retiredAccessorReads.get(key) ?? [];
|
|
92
|
+
const calls = reads.map((span) => host.plainCallSpans.get(spanIdentity(span)) ?? null);
|
|
93
|
+
const rewritable = accessor.bodySpan !== null && calls.every((call) => call !== null);
|
|
94
|
+
const edits = rewritable
|
|
95
|
+
? [
|
|
96
|
+
{ span: { start: accessor.declarationSpan.start, end: accessor.bodySpan.start }, text: `${accessor.exported ? "export " : ""}computed ${accessor.name} = ` },
|
|
97
|
+
{ span: { start: accessor.bodySpan.end, end: accessor.callSpan.end }, text: "" },
|
|
98
|
+
...reads.map((span, index) => ({ span: { start: span.end, end: calls[index].end }, text: "" })),
|
|
99
|
+
]
|
|
100
|
+
: null;
|
|
101
|
+
const alternative = accessor.bodySpan === null
|
|
102
|
+
? ` Where the argument is a function rather than an expression, write the call — 'computed ${accessor.name} = ${accessor.readName ?? "read"}()'`
|
|
103
|
+
: ` Where the reader itself is passed on rather than read here, declare the value — 'computed ${accessor.name} = ...' — and write an ordinary 'def' where a callable is required`;
|
|
104
|
+
host.diagnostics.push({
|
|
105
|
+
code: "VEL5055",
|
|
106
|
+
message: `A derived value is declared, not called: write 'computed ${accessor.name} = ...' and read '${accessor.name}' bare.${rewritable ? "" : alternative}`,
|
|
107
|
+
span: accessor.declarationSpan,
|
|
108
|
+
...(edits ? { fix: { title: `Declare '${accessor.name}' with computed`, edits } } : {}),
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
// There is no `fix`: the rewrite is a declaration, not a rename, and the
|
|
112
|
+
// declaration form is offered above where the compile can see the whole
|
|
113
|
+
// shape.
|
|
114
|
+
for (const reference of host.retiredComputedReferences.values()) {
|
|
115
|
+
host.diagnostics.push(diagnostic("VEL5055", "'computed' declares a derived value — 'computed name = expression'. There is no function form, and 'computed' already caches", reference.span));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=retired-accessors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retired-accessors.js","sourceRoot":"","sources":["../../../src/analysis/reactivity/retired-accessors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a type may stand for in a JSX position: the six questions asked of a
|
|
3
|
+
* `ValueType` and of nothing else — whether it is a Look, a class list, a
|
|
4
|
+
* renderable child, exactly one text node, an attribute value, or an optional
|
|
5
|
+
* string.
|
|
6
|
+
*
|
|
7
|
+
* D115 P4 R3c. These are pure readings of a type, so the only thing they ask of
|
|
8
|
+
* the analyzer is alias expansion, which arrives as a one-member host rather
|
|
9
|
+
* than as a whole face. The two that answer over the written type — `isLookInput`
|
|
10
|
+
* and `isClassInput` — read no aliases at all and take no host.
|
|
11
|
+
*/
|
|
12
|
+
import { type ValueType } from "@velarscript/compiler/extension";
|
|
13
|
+
/** The whole of what the four alias-reading predicates ask of the analyzer. */
|
|
14
|
+
export interface RenderableHost {
|
|
15
|
+
expandAliases(type: ValueType): ValueType;
|
|
16
|
+
}
|
|
17
|
+
export declare function isLookInput(type: ValueType): boolean;
|
|
18
|
+
export declare function isClassInput(type: ValueType): boolean;
|
|
19
|
+
export declare function isJsxRenderable(host: RenderableHost, type: ValueType): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* F1's qualifying rule, and the whole of it: the types whose rendering is
|
|
22
|
+
* *exactly* one text node.
|
|
23
|
+
*
|
|
24
|
+
* `string` and `number` are the two. `__velarAppend` answers a string with one
|
|
25
|
+
* text node carrying it — the empty string included, which is why `""` is not
|
|
26
|
+
* a special case — and a number with one text node carrying `String(value)`,
|
|
27
|
+
* or refuses a non-finite number. An enum member is text at runtime and is
|
|
28
|
+
* assignable to `string`, so it rides the same branch it always did.
|
|
29
|
+
*
|
|
30
|
+
* Everything else stays on the full dynamic region, and the reason is always
|
|
31
|
+
* the same one: it does not render as *one* node.
|
|
32
|
+
* - `bool` renders **zero** nodes (`__velarAppend` returns on `true`/`false`),
|
|
33
|
+
* so a text node would be an added child where an element previously had
|
|
34
|
+
* none — observable to `:empty`, to `childNodes`, and to anything that
|
|
35
|
+
* walks them.
|
|
36
|
+
* - An optional of either renders zero nodes when null and one when present,
|
|
37
|
+
* so it needs an anchor to come back to.
|
|
38
|
+
* - `WebNode`, lists, unions, `any` and every named type can hold markup or
|
|
39
|
+
* several nodes, which is what the comment pair exists to bracket.
|
|
40
|
+
*
|
|
41
|
+
* Widening this set is a semantic ruling, not an optimisation: it would
|
|
42
|
+
* change the node count of a rendered document.
|
|
43
|
+
*/
|
|
44
|
+
export declare function isScalarTextType(host: RenderableHost, type: ValueType): boolean;
|
|
45
|
+
export declare function isJsxAttributeValue(host: RenderableHost, type: ValueType): boolean;
|
|
46
|
+
export declare function isOptionalString(host: RenderableHost, type: ValueType): boolean;
|
|
47
|
+
//# sourceMappingURL=renderable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderable.d.ts","sourceRoot":"","sources":["../../src/analysis/renderable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAIjE,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,aAAa,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,CAAC;CAC3C;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAOpD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAMrD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAS9E;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAG/E;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAQlF;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAM/E"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a type may stand for in a JSX position: the six questions asked of a
|
|
3
|
+
* `ValueType` and of nothing else — whether it is a Look, a class list, a
|
|
4
|
+
* renderable child, exactly one text node, an attribute value, or an optional
|
|
5
|
+
* string.
|
|
6
|
+
*
|
|
7
|
+
* D115 P4 R3c. These are pure readings of a type, so the only thing they ask of
|
|
8
|
+
* the analyzer is alias expansion, which arrives as a one-member host rather
|
|
9
|
+
* than as a whole face. The two that answer over the written type — `isLookInput`
|
|
10
|
+
* and `isClassInput` — read no aliases at all and take no host.
|
|
11
|
+
*/
|
|
12
|
+
import {} from "@velarscript/compiler/extension";
|
|
13
|
+
import { isWebNodeType } from "../types.js";
|
|
14
|
+
import { textualWebPrimitiveNames } from "./web-types.js";
|
|
15
|
+
export function isLookInput(type) {
|
|
16
|
+
if (type.kind === "any" || type.kind === "null")
|
|
17
|
+
return true;
|
|
18
|
+
if (type.kind === "named")
|
|
19
|
+
return type.name === "Look";
|
|
20
|
+
if (type.kind === "optional")
|
|
21
|
+
return isLookInput(type.inner);
|
|
22
|
+
if (type.kind === "list")
|
|
23
|
+
return isLookInput(type.element);
|
|
24
|
+
if (type.kind === "union")
|
|
25
|
+
return type.members.every((member) => isLookInput(member));
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
export function isClassInput(type) {
|
|
29
|
+
if (type.kind === "any" || type.kind === "null" || type.kind === "string")
|
|
30
|
+
return true;
|
|
31
|
+
if (type.kind === "optional")
|
|
32
|
+
return isClassInput(type.inner);
|
|
33
|
+
if (type.kind === "list")
|
|
34
|
+
return isClassInput(type.element);
|
|
35
|
+
if (type.kind === "union")
|
|
36
|
+
return type.members.every((member) => isClassInput(member));
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
export function isJsxRenderable(host, type) {
|
|
40
|
+
const expanded = host.expandAliases(type);
|
|
41
|
+
if (expanded.kind === "any" || expanded.kind === "null" || expanded.kind === "string" || expanded.kind === "number"
|
|
42
|
+
|| expanded.kind === "bool" || expanded.kind === "enum" || expanded.kind === "enumMember" || isWebNodeType(expanded))
|
|
43
|
+
return true;
|
|
44
|
+
if (expanded.kind === "named")
|
|
45
|
+
return textualWebPrimitiveNames.has(expanded.name);
|
|
46
|
+
if (expanded.kind === "optional")
|
|
47
|
+
return isJsxRenderable(host, expanded.inner);
|
|
48
|
+
if (expanded.kind === "list")
|
|
49
|
+
return isJsxRenderable(host, expanded.element);
|
|
50
|
+
if (expanded.kind === "union")
|
|
51
|
+
return expanded.members.every((member) => isJsxRenderable(host, member));
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* F1's qualifying rule, and the whole of it: the types whose rendering is
|
|
56
|
+
* *exactly* one text node.
|
|
57
|
+
*
|
|
58
|
+
* `string` and `number` are the two. `__velarAppend` answers a string with one
|
|
59
|
+
* text node carrying it — the empty string included, which is why `""` is not
|
|
60
|
+
* a special case — and a number with one text node carrying `String(value)`,
|
|
61
|
+
* or refuses a non-finite number. An enum member is text at runtime and is
|
|
62
|
+
* assignable to `string`, so it rides the same branch it always did.
|
|
63
|
+
*
|
|
64
|
+
* Everything else stays on the full dynamic region, and the reason is always
|
|
65
|
+
* the same one: it does not render as *one* node.
|
|
66
|
+
* - `bool` renders **zero** nodes (`__velarAppend` returns on `true`/`false`),
|
|
67
|
+
* so a text node would be an added child where an element previously had
|
|
68
|
+
* none — observable to `:empty`, to `childNodes`, and to anything that
|
|
69
|
+
* walks them.
|
|
70
|
+
* - An optional of either renders zero nodes when null and one when present,
|
|
71
|
+
* so it needs an anchor to come back to.
|
|
72
|
+
* - `WebNode`, lists, unions, `any` and every named type can hold markup or
|
|
73
|
+
* several nodes, which is what the comment pair exists to bracket.
|
|
74
|
+
*
|
|
75
|
+
* Widening this set is a semantic ruling, not an optimisation: it would
|
|
76
|
+
* change the node count of a rendered document.
|
|
77
|
+
*/
|
|
78
|
+
export function isScalarTextType(host, type) {
|
|
79
|
+
const expanded = host.expandAliases(type);
|
|
80
|
+
return expanded.kind === "string" || expanded.kind === "number";
|
|
81
|
+
}
|
|
82
|
+
export function isJsxAttributeValue(host, type) {
|
|
83
|
+
const expanded = host.expandAliases(type);
|
|
84
|
+
if (expanded.kind === "any" || expanded.kind === "null" || expanded.kind === "string" || expanded.kind === "number"
|
|
85
|
+
|| expanded.kind === "bool" || expanded.kind === "enum" || expanded.kind === "enumMember")
|
|
86
|
+
return true;
|
|
87
|
+
if (expanded.kind === "named")
|
|
88
|
+
return textualWebPrimitiveNames.has(expanded.name);
|
|
89
|
+
if (expanded.kind === "optional")
|
|
90
|
+
return isJsxAttributeValue(host, expanded.inner);
|
|
91
|
+
if (expanded.kind === "union")
|
|
92
|
+
return expanded.members.every((member) => isJsxAttributeValue(host, member));
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
export function isOptionalString(host, type) {
|
|
96
|
+
const expanded = host.expandAliases(type);
|
|
97
|
+
if (expanded.kind === "string" || expanded.kind === "null")
|
|
98
|
+
return true;
|
|
99
|
+
if (expanded.kind === "optional")
|
|
100
|
+
return isOptionalString(host, expanded.inner);
|
|
101
|
+
if (expanded.kind === "union")
|
|
102
|
+
return expanded.members.every((member) => isOptionalString(host, member));
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=renderable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderable.js","sourceRoot":"","sources":["../../src/analysis/renderable.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a route accepts: the component a 'route(path, Component)' may name, the
|
|
3
|
+
* path spellings a router can match, and the two accessibility readings a route
|
|
4
|
+
* component's markup is asked for.
|
|
5
|
+
*
|
|
6
|
+
* D115 P4 R3a: 'web.route' asks these of an intrinsic context and the analyzer
|
|
7
|
+
* asks them of a record of routes, so they read as a module both can call.
|
|
8
|
+
*
|
|
9
|
+
* D115 P4 R3c: the analyzer's own two — the `<Router routes={...}>` list and the
|
|
10
|
+
* component slot inside it — join them here, so the two callers differ only in
|
|
11
|
+
* the environment they arrive with.
|
|
12
|
+
*/
|
|
13
|
+
import { type Diagnostic, type Span } from "@velarscript/compiler";
|
|
14
|
+
import { type CompilerIntrinsicAnalysisContext, type Expression, type ValueType } from "@velarscript/compiler/extension";
|
|
15
|
+
import { type WebJsxElementExpression as JSXElementExpression } from "../ast.ts";
|
|
16
|
+
/**
|
|
17
|
+
* What the analyzer's two route readings ask of the analyzer that hosts them.
|
|
18
|
+
* The intrinsic twins take a `CompilerIntrinsicAnalysisContext` instead: they
|
|
19
|
+
* are called from inside an intrinsic, where that context is what the caller
|
|
20
|
+
* already holds.
|
|
21
|
+
*/
|
|
22
|
+
export interface WebRouteHost {
|
|
23
|
+
readonly diagnostics: Diagnostic[];
|
|
24
|
+
inferExpression(expression: Expression, contextualType?: ValueType): ValueType;
|
|
25
|
+
/**
|
|
26
|
+
* Assignability judged against the analyzer as the type environment. Asking
|
|
27
|
+
* for the answer rather than for the environment keeps `TypeEnvironment` out
|
|
28
|
+
* of this face.
|
|
29
|
+
*/
|
|
30
|
+
isAssignableHere(actual: ValueType, expected: ValueType): boolean;
|
|
31
|
+
typeError(message: string, errorSpan: Span): void;
|
|
32
|
+
}
|
|
33
|
+
export declare function checkRouteComponent(type: ValueType, sourceSpan: Span, subject: string, context: CompilerIntrinsicAnalysisContext): void;
|
|
34
|
+
export declare function checkRoutePath(path: string, sourceSpan: Span, report: (message: string, span: Span) => void): void;
|
|
35
|
+
/**
|
|
36
|
+
* The elements of a `<Router routes={...}>` list literal, one at a time.
|
|
37
|
+
*
|
|
38
|
+
* A route written as `route("/a", Panel)` is checked at that call; the record
|
|
39
|
+
* that call returns — `{path: "/a", component: Panel}` — is a legal spelling
|
|
40
|
+
* of the same value, reaches the same runtime position, and until now was
|
|
41
|
+
* checked by nothing: `{path: "no-leading-slash", component: 5}` compiled
|
|
42
|
+
* clean and handed `5` to the Router as a component. Closing the sink rather
|
|
43
|
+
* than the spelling means asking the same questions wherever a route arrives,
|
|
44
|
+
* so this reports exactly what `route(...)` reports, word for word.
|
|
45
|
+
*
|
|
46
|
+
* The runtime is already the second referee (D90 R19): `routerTable`
|
|
47
|
+
* validates every path and refuses a component that is not callable. Nothing
|
|
48
|
+
* here changes which programs run — it moves a refusal the author would have
|
|
49
|
+
* met at mount to the place the source shows the mistake.
|
|
50
|
+
*
|
|
51
|
+
* The `any` component slot is skipped here rather than inside
|
|
52
|
+
* `checkWebRouteComponent`, which is why that function carries no `any` arm:
|
|
53
|
+
* this loop and the Router `fallback` attribute are its only two callers, and
|
|
54
|
+
* both filter first. An `any` reaches this slot for real — `web.lazy` answers
|
|
55
|
+
* `anyType` from each of its error paths — and it arrives with the author's
|
|
56
|
+
* real message already reported, so a second "received any" would be a
|
|
57
|
+
* cascade. The `route(...)` twin skips it for the same reason.
|
|
58
|
+
*/
|
|
59
|
+
export declare function checkWebRouteRecords(host: WebRouteHost, expression: Expression): void;
|
|
60
|
+
export declare function checkWebRouteComponent(host: WebRouteHost, type: ValueType, sourceSpan: Span, subject: string): void;
|
|
61
|
+
export declare function containsPromise(type: ValueType): boolean;
|
|
62
|
+
export declare function hasAccessibleJsxContent(expression: JSXElementExpression): boolean;
|
|
63
|
+
export declare function hasAccessibleSvgName(expression: JSXElementExpression): boolean;
|
|
64
|
+
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/analysis/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,IAAI,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,EAGL,KAAK,gCAAgC,EACrC,KAAK,UAAU,EACf,KAAK,SAAS,EACf,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,KAAK,uBAAuB,IAAI,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAIjF;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,WAAW,EAAE,UAAU,EAAE,CAAC;IACnC,eAAe,CAAC,UAAU,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC/E;;;;OAIG;IACH,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,GAAG,OAAO,CAAC;IAClE,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;CACnD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,gCAAgC,GAAG,IAAI,CAUvI;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,GAAG,IAAI,CAsBlH;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,GAAG,IAAI,CA2BrF;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAanH;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAQxD;AAGD,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,oBAAoB,GAAG,OAAO,CAMjF;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,oBAAoB,GAAG,OAAO,CAY9E"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a route accepts: the component a 'route(path, Component)' may name, the
|
|
3
|
+
* path spellings a router can match, and the two accessibility readings a route
|
|
4
|
+
* component's markup is asked for.
|
|
5
|
+
*
|
|
6
|
+
* D115 P4 R3a: 'web.route' asks these of an intrinsic context and the analyzer
|
|
7
|
+
* asks them of a record of routes, so they read as a module both can call.
|
|
8
|
+
*
|
|
9
|
+
* D115 P4 R3c: the analyzer's own two — the `<Router routes={...}>` list and the
|
|
10
|
+
* component slot inside it — join them here, so the two callers differ only in
|
|
11
|
+
* the environment they arrive with.
|
|
12
|
+
*/
|
|
13
|
+
import {} from "@velarscript/compiler";
|
|
14
|
+
import { describeType, isInvalidType, } from "@velarscript/compiler/extension";
|
|
15
|
+
import {} from "../ast.js";
|
|
16
|
+
import { isWebComponentType } from "../types.js";
|
|
17
|
+
import { routeContextIdentity } from "./web-types.js";
|
|
18
|
+
export function checkRouteComponent(type, sourceSpan, subject, context) {
|
|
19
|
+
if (isInvalidType(type))
|
|
20
|
+
return;
|
|
21
|
+
if (!isWebComponentType(type)) {
|
|
22
|
+
if (type.kind !== "any")
|
|
23
|
+
context.typeError(`${subject} requires a component, received ${describeType(type)}`, sourceSpan);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const unsupported = [...type.requiredProperties].filter((name) => name !== "route");
|
|
27
|
+
if (unsupported.length > 0)
|
|
28
|
+
context.typeError(`${subject} component cannot require props other than route: ${unsupported.join(", ")}`, sourceSpan);
|
|
29
|
+
const routeProp = type.properties.get("route");
|
|
30
|
+
if (routeProp && !context.isAssignable({ kind: "named", name: "RouteContext", identity: routeContextIdentity }, routeProp))
|
|
31
|
+
context.typeError(`${subject} component's route prop must accept RouteContext, received ${describeType(routeProp)}`, sourceSpan);
|
|
32
|
+
}
|
|
33
|
+
export function checkRoutePath(path, sourceSpan, report) {
|
|
34
|
+
if (!path.startsWith("/"))
|
|
35
|
+
report("A route path must start with '/'", sourceSpan);
|
|
36
|
+
if (path.includes("?") || path.includes("#"))
|
|
37
|
+
report("A route path describes only a pathname; read query and hash from RouteContext", sourceSpan);
|
|
38
|
+
if (path.includes("\\"))
|
|
39
|
+
report("A route path cannot contain a backslash", sourceSpan);
|
|
40
|
+
if (path.length > 1 && path.endsWith("/"))
|
|
41
|
+
report("A route path cannot end with '/'; matching already accepts one trailing slash", sourceSpan);
|
|
42
|
+
const segments = path.split("/").slice(1);
|
|
43
|
+
const parameters = new Set();
|
|
44
|
+
for (const [index, segment] of segments.entries()) {
|
|
45
|
+
if (segment.length === 0 && path !== "/")
|
|
46
|
+
report("A route path cannot contain an empty segment", sourceSpan);
|
|
47
|
+
if (segment === "*") {
|
|
48
|
+
if (index !== segments.length - 1)
|
|
49
|
+
report("A route wildcard must be the final segment", sourceSpan);
|
|
50
|
+
if (parameters.has("wildcard"))
|
|
51
|
+
report("A route parameter named 'wildcard' conflicts with the '*' capture", sourceSpan);
|
|
52
|
+
parameters.add("wildcard");
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (segment.includes("*"))
|
|
56
|
+
report("A route wildcard must occupy its whole final segment", sourceSpan);
|
|
57
|
+
if (!segment.startsWith(":"))
|
|
58
|
+
continue;
|
|
59
|
+
const name = segment.slice(1);
|
|
60
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(name))
|
|
61
|
+
report("A route parameter requires a valid name", sourceSpan);
|
|
62
|
+
else if (parameters.has(name))
|
|
63
|
+
report(`Route parameter '${name}' is repeated`, sourceSpan);
|
|
64
|
+
parameters.add(name);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The elements of a `<Router routes={...}>` list literal, one at a time.
|
|
69
|
+
*
|
|
70
|
+
* A route written as `route("/a", Panel)` is checked at that call; the record
|
|
71
|
+
* that call returns — `{path: "/a", component: Panel}` — is a legal spelling
|
|
72
|
+
* of the same value, reaches the same runtime position, and until now was
|
|
73
|
+
* checked by nothing: `{path: "no-leading-slash", component: 5}` compiled
|
|
74
|
+
* clean and handed `5` to the Router as a component. Closing the sink rather
|
|
75
|
+
* than the spelling means asking the same questions wherever a route arrives,
|
|
76
|
+
* so this reports exactly what `route(...)` reports, word for word.
|
|
77
|
+
*
|
|
78
|
+
* The runtime is already the second referee (D90 R19): `routerTable`
|
|
79
|
+
* validates every path and refuses a component that is not callable. Nothing
|
|
80
|
+
* here changes which programs run — it moves a refusal the author would have
|
|
81
|
+
* met at mount to the place the source shows the mistake.
|
|
82
|
+
*
|
|
83
|
+
* The `any` component slot is skipped here rather than inside
|
|
84
|
+
* `checkWebRouteComponent`, which is why that function carries no `any` arm:
|
|
85
|
+
* this loop and the Router `fallback` attribute are its only two callers, and
|
|
86
|
+
* both filter first. An `any` reaches this slot for real — `web.lazy` answers
|
|
87
|
+
* `anyType` from each of its error paths — and it arrives with the author's
|
|
88
|
+
* real message already reported, so a second "received any" would be a
|
|
89
|
+
* cascade. The `route(...)` twin skips it for the same reason.
|
|
90
|
+
*/
|
|
91
|
+
export function checkWebRouteRecords(host, expression) {
|
|
92
|
+
if (expression.kind !== "ListExpression")
|
|
93
|
+
return;
|
|
94
|
+
for (const element of expression.elements) {
|
|
95
|
+
if (element.kind !== "ObjectExpression")
|
|
96
|
+
continue;
|
|
97
|
+
for (const entry of element.properties) {
|
|
98
|
+
if (entry.kind !== "ObjectProperty")
|
|
99
|
+
continue;
|
|
100
|
+
if (entry.name === "path") {
|
|
101
|
+
const path = entry.value;
|
|
102
|
+
if (path.kind === "LiteralExpression" && typeof path.value === "string") {
|
|
103
|
+
checkRoutePath(path.value, path.span, (message, span) => host.typeError(message, span));
|
|
104
|
+
}
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (entry.name !== "component")
|
|
108
|
+
continue;
|
|
109
|
+
// The attribute has already been inferred as a whole, so every
|
|
110
|
+
// sub-expression here has been reported once. This second pass exists
|
|
111
|
+
// only to read the component slot's type back; anything it says is a
|
|
112
|
+
// repeat of what the author already has, and is dropped. Advisories
|
|
113
|
+
// need no such cursor — `advise` is deduplicated by code and span
|
|
114
|
+
// precisely so a re-analysis cannot raise one twice.
|
|
115
|
+
const reported = host.diagnostics.length;
|
|
116
|
+
const type = host.inferExpression(entry.value);
|
|
117
|
+
host.diagnostics.splice(reported);
|
|
118
|
+
if (type.kind === "any")
|
|
119
|
+
continue;
|
|
120
|
+
checkWebRouteComponent(host, type, entry.value.span, "A route");
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
export function checkWebRouteComponent(host, type, sourceSpan, subject) {
|
|
125
|
+
if (isInvalidType(type))
|
|
126
|
+
return;
|
|
127
|
+
if (!isWebComponentType(type)) {
|
|
128
|
+
// No `any` arm, unlike the `route(...)` twin above: both callers — the
|
|
129
|
+
// Router `fallback` attribute and `checkWebRouteRecords` — already filter
|
|
130
|
+
// `any` out before they call here, so a branch for it could never run.
|
|
131
|
+
host.typeError(`${subject} requires a component, received ${describeType(type)}`, sourceSpan);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const unsupported = [...type.requiredProperties].filter((name) => name !== "route");
|
|
135
|
+
if (unsupported.length > 0)
|
|
136
|
+
host.typeError(`${subject} component cannot require props other than route: ${unsupported.join(", ")}`, sourceSpan);
|
|
137
|
+
const routeProp = type.properties.get("route");
|
|
138
|
+
if (routeProp && !host.isAssignableHere({ kind: "named", name: "RouteContext", identity: routeContextIdentity }, routeProp))
|
|
139
|
+
host.typeError(`${subject} component's route prop must accept RouteContext, received ${describeType(routeProp)}`, sourceSpan);
|
|
140
|
+
}
|
|
141
|
+
export function containsPromise(type) {
|
|
142
|
+
if (type.kind === "promise")
|
|
143
|
+
return true;
|
|
144
|
+
if (type.kind === "optional")
|
|
145
|
+
return containsPromise(type.inner);
|
|
146
|
+
if (type.kind === "list" || type.kind === "set")
|
|
147
|
+
return containsPromise(type.element);
|
|
148
|
+
if (type.kind === "map")
|
|
149
|
+
return containsPromise(type.key) || containsPromise(type.value);
|
|
150
|
+
if (type.kind === "record")
|
|
151
|
+
return containsPromise(type.value);
|
|
152
|
+
if (type.kind === "union")
|
|
153
|
+
return type.members.some(containsPromise);
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
export function hasAccessibleJsxContent(expression) {
|
|
157
|
+
return expression.children.some((child) => {
|
|
158
|
+
if (child.kind === "JSXText")
|
|
159
|
+
return child.value.trim().length > 0;
|
|
160
|
+
if (child.kind === "JSXExpressionChild")
|
|
161
|
+
return true;
|
|
162
|
+
return hasAccessibleJsxContent(child) || child.tag.length > 0;
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
export function hasAccessibleSvgName(expression) {
|
|
166
|
+
const named = expression.attributes.some((attribute) => {
|
|
167
|
+
if (attribute.name !== "aria-label" && attribute.name !== "aria-labelledby")
|
|
168
|
+
return false;
|
|
169
|
+
if (attribute.value === null)
|
|
170
|
+
return false;
|
|
171
|
+
return typeof attribute.value !== "string" || attribute.value.trim().length > 0;
|
|
172
|
+
});
|
|
173
|
+
if (named)
|
|
174
|
+
return true;
|
|
175
|
+
const hidden = expression.attributes.find((attribute) => attribute.name === "aria-hidden");
|
|
176
|
+
if (hidden?.value === "true" || (hidden?.value && typeof hidden.value !== "string"
|
|
177
|
+
&& hidden.value.kind === "LiteralExpression" && hidden.value.value === true))
|
|
178
|
+
return true;
|
|
179
|
+
return expression.children.some((child) => child.kind === "ExtensionExpression:web:jsx"
|
|
180
|
+
&& child.tag === "title" && hasAccessibleJsxContent(child));
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/analysis/routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The URL-scheme rule: which attributes carry a URL, and what a written one is
|
|
3
|
+
* refused for.
|
|
4
|
+
*
|
|
5
|
+
* D115 P4 R3a: one question about one string — asked of a literal `href`, of a
|
|
6
|
+
* JSX attribute value, and of an interpolation's parts — so it is written once
|
|
7
|
+
* here rather than in the middle of the analyzer's JSX pass.
|
|
8
|
+
*/
|
|
9
|
+
export declare const WEB_URL_ATTRIBUTES: Set<string>;
|
|
10
|
+
/** The clause naming why one literal URL is refused, or null when it is fine. */
|
|
11
|
+
export declare function urlSchemeRefusal(value: string): string | null;
|
|
12
|
+
//# sourceMappingURL=url-attributes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-attributes.d.ts","sourceRoot":"","sources":["../../src/analysis/url-attributes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,eAAO,MAAM,kBAAkB,aAAmG,CAAC;AAsBnI,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAU7D"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The URL-scheme rule: which attributes carry a URL, and what a written one is
|
|
3
|
+
* refused for.
|
|
4
|
+
*
|
|
5
|
+
* D115 P4 R3a: one question about one string — asked of a literal `href`, of a
|
|
6
|
+
* JSX attribute value, and of an interpolation's parts — so it is written once
|
|
7
|
+
* here rather than in the middle of the analyzer's JSX pass.
|
|
8
|
+
*/
|
|
9
|
+
// WEB-S2: the attributes whose value the browser resolves as a URL and then
|
|
10
|
+
// navigates, fetches, or submits to. A `javascript:`/`vbscript:` string in one
|
|
11
|
+
// of them is script the page runs, which is the boundary the charter reserves
|
|
12
|
+
// for `unsafe:html` — so the scheme is checked wherever it is written down.
|
|
13
|
+
export const WEB_URL_ATTRIBUTES = new Set(["href", "src", "action", "formaction", "poster", "data", "xlink:href", "ping", "cite"]);
|
|
14
|
+
const WEB_SCRIPT_URL_SCHEMES = new Set(["javascript", "vbscript"]);
|
|
15
|
+
// A `data:` URL is a document the browser builds from the string itself, so it
|
|
16
|
+
// is inert only for the media types that cannot carry script. `image/svg+xml`
|
|
17
|
+
// is deliberately absent: an SVG document runs script.
|
|
18
|
+
const WEB_INERT_DATA_MEDIA_TYPES = new Set([
|
|
19
|
+
"image/png", "image/jpeg", "image/gif", "image/webp", "image/avif", "image/bmp", "image/x-icon",
|
|
20
|
+
"video/mp4", "video/webm", "video/ogg", "audio/mpeg", "audio/ogg", "audio/wav", "audio/webm",
|
|
21
|
+
"font/woff", "font/woff2", "font/ttf", "font/otf", "text/plain", "text/css",
|
|
22
|
+
]);
|
|
23
|
+
/**
|
|
24
|
+
* The scheme a browser reads out of a URL string. Leading and embedded ASCII
|
|
25
|
+
* whitespace and control characters are stripped first, because the URL parser
|
|
26
|
+
* strips them too — `java\tscript:alert(1)` is a `javascript:` URL.
|
|
27
|
+
*/
|
|
28
|
+
function urlAttributeScheme(value) {
|
|
29
|
+
const stripped = value.replace(/[\u0000-\u0020]/gu, "");
|
|
30
|
+
const match = /^([A-Za-z][A-Za-z0-9+.-]*):/u.exec(stripped);
|
|
31
|
+
return match ? { scheme: match[1].toLowerCase(), rest: stripped.slice(match[0].length) } : null;
|
|
32
|
+
}
|
|
33
|
+
/** The clause naming why one literal URL is refused, or null when it is fine. */
|
|
34
|
+
export function urlSchemeRefusal(value) {
|
|
35
|
+
const parsed = urlAttributeScheme(value);
|
|
36
|
+
if (!parsed)
|
|
37
|
+
return null;
|
|
38
|
+
if (WEB_SCRIPT_URL_SCHEMES.has(parsed.scheme)) {
|
|
39
|
+
return `'${parsed.scheme}:' is script, not a location — write an 'on:click' handler for behavior, or a real URL for navigation`;
|
|
40
|
+
}
|
|
41
|
+
if (parsed.scheme !== "data")
|
|
42
|
+
return null;
|
|
43
|
+
const media = (/^([^,;]*)/u.exec(parsed.rest)?.[1] ?? "").toLowerCase();
|
|
44
|
+
if (WEB_INERT_DATA_MEDIA_TYPES.has(media))
|
|
45
|
+
return null;
|
|
46
|
+
return `a 'data:' URL is only accepted for a media type that cannot carry script${media ? `, and '${media}' can` : ""}; the inert types are ${[...WEB_INERT_DATA_MEDIA_TYPES].join(", ")}`;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=url-attributes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-attributes.js","sourceRoot":"","sources":["../../src/analysis/url-attributes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,4EAA4E;AAC5E,+EAA+E;AAC/E,8EAA8E;AAC9E,4EAA4E;AAC5E,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AACnI,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC;AACnE,+EAA+E;AAC/E,8EAA8E;AAC9E,uDAAuD;AACvD,MAAM,0BAA0B,GAAG,IAAI,GAAG,CAAC;IACzC,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc;IAC/F,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY;IAC5F,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU;CAC5E,CAAC,CAAC;AAEH;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,KAAa;IACvC,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,8BAA8B,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5D,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACnG,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,sBAAsB,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9C,OAAO,IAAI,MAAM,CAAC,MAAM,uGAAuG,CAAC;IAClI,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAC1C,MAAM,KAAK,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACxE,IAAI,0BAA0B,CAAC,GAAG,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvD,OAAO,2EAA2E,KAAK,CAAC,CAAC,CAAC,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,yBAAyB,CAAC,GAAG,0BAA0B,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAC7L,CAAC"}
|