ferrovue 0.4.0 → 0.6.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 +378 -63
- package/dist/attrs.d.ts +3 -2
- package/dist/attrs.js +31 -26
- package/dist/calls.js +17 -15
- package/dist/children.d.ts +11 -4
- package/dist/children.js +110 -44
- package/dist/classes.d.ts +4 -0
- package/dist/classes.js +33 -11
- package/dist/cli.js +31 -5
- package/dist/client.d.ts +44 -6
- package/dist/client.js +182 -18
- package/dist/compiler.d.ts +1 -1
- package/dist/compiler.js +42 -10
- package/dist/component.d.ts +3 -1
- package/dist/component.js +114 -20
- package/dist/conformance.d.ts +64 -0
- package/dist/conformance.js +276 -0
- package/dist/constants.d.ts +42 -0
- package/dist/constants.js +292 -0
- package/dist/context.d.ts +40 -7
- package/dist/context.js +14 -5
- package/dist/diagnostics.d.ts +23 -0
- package/dist/diagnostics.js +30 -0
- package/dist/dynamic.d.ts +18 -0
- package/dist/dynamic.js +576 -0
- package/dist/errors.d.ts +1034 -0
- package/dist/errors.js +425 -0
- package/dist/expr.d.ts +1 -0
- package/dist/expr.js +120 -49
- package/dist/file-routes.d.ts +33 -0
- package/dist/file-routes.js +224 -0
- package/dist/fixture.d.ts +19 -10
- package/dist/fixture.js +23 -12
- package/dist/hydration.d.ts +15 -0
- package/dist/hydration.js +80 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/link-router.d.ts +24 -0
- package/dist/link-router.js +37 -0
- package/dist/lists.d.ts +4 -0
- package/dist/lists.js +32 -23
- package/dist/loops.js +18 -14
- package/dist/model.d.ts +43 -1
- package/dist/model.js +167 -7
- package/dist/narrowing.d.ts +8 -0
- package/dist/narrowing.js +40 -9
- package/dist/numbers.js +3 -2
- package/dist/page-routes.d.ts +9 -0
- package/dist/page-routes.js +10 -0
- package/dist/plugin.d.ts +13 -1
- package/dist/plugin.js +3 -0
- package/dist/plugins/client-only.d.ts +8 -0
- package/dist/plugins/client-only.js +110 -0
- package/dist/plugins/head.d.ts +15 -0
- package/dist/plugins/head.js +385 -0
- package/dist/plugins/i18n.js +14 -14
- package/dist/plugins/index.js +5 -1
- package/dist/plugins/provide.d.ts +44 -0
- package/dist/plugins/provide.js +528 -0
- package/dist/plugins/router-link.js +39 -32
- package/dist/plugins/router.d.ts +4 -1
- package/dist/plugins/router.js +65 -19
- package/dist/plugins/scoped.js +1 -1
- package/dist/plugins/shared-types.js +1 -1
- package/dist/plugins/stores.js +45 -33
- package/dist/plugins/teleport.js +3 -3
- package/dist/plugins/twins.d.ts +10 -0
- package/dist/plugins/twins.js +164 -0
- package/dist/routes.d.ts +13 -0
- package/dist/routes.js +12 -0
- package/dist/rust.js +64 -32
- package/dist/script.d.ts +3 -0
- package/dist/script.js +138 -20
- package/dist/settle.d.ts +8 -0
- package/dist/settle.js +39 -0
- package/dist/slots.js +36 -22
- package/dist/ssr.d.ts +3 -0
- package/dist/ssr.js +29 -0
- package/dist/strings.d.ts +3 -0
- package/dist/strings.js +27 -13
- package/dist/styles.js +13 -13
- package/dist/template.js +102 -21
- package/dist/testing.d.ts +3 -3
- package/dist/testing.js +3 -29
- package/dist/types.d.ts +5 -0
- package/dist/typescript.d.ts +2 -1
- package/dist/typescript.js +52 -21
- package/dist/vhtml.d.ts +4 -0
- package/dist/vhtml.js +63 -0
- package/dist/vite.d.ts +8 -2
- package/dist/vite.js +75 -14
- package/package.json +23 -5
package/dist/attrs.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { type N, type Scope, type Val } from "./model.ts";
|
|
2
2
|
import { Emitter } from "./emitter.ts";
|
|
3
3
|
export declare function display(e: Emitter, v: Val): boolean;
|
|
4
|
-
export declare function interpolate(e: Emitter, v: Val): void;
|
|
4
|
+
export declare function interpolate(s: Scope, e: Emitter, v: Val, n: N): void;
|
|
5
5
|
export declare function attrValue(e: Emitter, v: Val): void;
|
|
6
6
|
export declare function renderAttr(s: Scope, e: Emitter, key: string, v: Val, n: N): void;
|
|
7
|
-
export declare function
|
|
7
|
+
export declare function keepsAttrCase(tag: string): boolean;
|
|
8
|
+
export declare function renderDynamicAttr(s: Scope, e: Emitter, key: string, v: Val, n: N, tag?: string | null): void;
|
|
8
9
|
export declare const IGNORED_PROPS: Set<string>;
|
|
9
10
|
export declare function directiveProps(s: Scope, n: N): boolean;
|
|
10
11
|
export declare function isAttrs(n: N): boolean;
|
package/dist/attrs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { escapeHtml, hyphenate, isBooleanAttr, isSSRSafeAttrName, propsToAttrMap } from "@vue/shared";
|
|
2
|
-
import { fail, GenError, rustStr } from "./model.js";
|
|
1
|
+
import { escapeHtml, hyphenate, isBooleanAttr, isSSRSafeAttrName, isSVGTag, propsToAttrMap } from "@vue/shared";
|
|
2
|
+
import { fail, nothing, GenError, rustStr } from "./model.js";
|
|
3
3
|
import { CONFIG_FILE, ctx } from "./context.js";
|
|
4
4
|
import { describeTy, expr } from "./expr.js";
|
|
5
5
|
import { known, truthy } from "./narrowing.js";
|
|
@@ -30,39 +30,40 @@ export function display(e, v) {
|
|
|
30
30
|
return false;
|
|
31
31
|
return true;
|
|
32
32
|
}
|
|
33
|
-
export function interpolate(e, v) {
|
|
33
|
+
export function interpolate(s, e, v, n) {
|
|
34
34
|
if (display(e, v))
|
|
35
35
|
return;
|
|
36
36
|
switch (v.ty.k) {
|
|
37
37
|
case "undef":
|
|
38
|
+
case "null":
|
|
38
39
|
return;
|
|
39
40
|
case "opt":
|
|
40
41
|
e.open(`if let Some(v) = ${v.code}`);
|
|
41
|
-
interpolate(e, { code: "v", ty: v.ty.of });
|
|
42
|
+
interpolate(s, e, { code: "v", ty: v.ty.of }, n);
|
|
42
43
|
e.close();
|
|
43
44
|
return;
|
|
44
45
|
default:
|
|
45
46
|
if (ctx.plugins.some((p) => p.values?.interpolate?.(e, v)))
|
|
46
47
|
return;
|
|
47
|
-
|
|
48
|
+
fail(s.comp, "FV0401", `\`{{ }}\` of ${describeTy(v.ty)}: only strings, numbers and booleans can be interpolated`, n);
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
export function attrValue(e, v) {
|
|
51
52
|
if (!display(e, v))
|
|
52
|
-
throw new GenError("an attribute value must be a string, a number or a boolean");
|
|
53
|
+
throw new GenError("FV0402", "an attribute value must be a string, a number or a boolean");
|
|
53
54
|
}
|
|
54
55
|
function renderable(s, key, v, n) {
|
|
55
56
|
const ty = v.ty.k === "opt" ? v.ty.of : v.ty;
|
|
56
|
-
if (ty.k === "str" || ty.k === "int" || ty.k === "float" || ty.k === "bool" || ty
|
|
57
|
+
if (ty.k === "str" || ty.k === "int" || ty.k === "float" || ty.k === "bool" || nothing(ty))
|
|
57
58
|
return;
|
|
58
59
|
const own = claim((p) => p.values?.unbindable?.(ty));
|
|
59
60
|
const what = own?.what ?? describeTy(ty);
|
|
60
61
|
const fix = own?.fix ?? (ty.k === "list" ? 'join it into one string, as `.join(",")`' : "bind a string, a number or a boolean");
|
|
61
|
-
fail(s.comp, `\`${key}\` is bound to ${what}: Vue's server renderer leaves the attribute out, and hydration then sets it, changing the page; ${fix}`, n);
|
|
62
|
+
fail(s.comp, "FV0403", `\`${key}\` is bound to ${what}: Vue's server renderer leaves the attribute out, and hydration then sets it, changing the page; ${fix}`, n);
|
|
62
63
|
}
|
|
63
64
|
export function renderAttr(s, e, key, v, n) {
|
|
64
65
|
renderable(s, key, v, n);
|
|
65
|
-
if (v.ty
|
|
66
|
+
if (nothing(v.ty))
|
|
66
67
|
return;
|
|
67
68
|
if (v.ty.k === "opt") {
|
|
68
69
|
e.open(`if let Some(v) = ${v.code}`);
|
|
@@ -74,12 +75,15 @@ export function renderAttr(s, e, key, v, n) {
|
|
|
74
75
|
attrValue(e, v);
|
|
75
76
|
e.lit(`"`);
|
|
76
77
|
}
|
|
77
|
-
export function
|
|
78
|
-
|
|
78
|
+
export function keepsAttrCase(tag) {
|
|
79
|
+
return tag.indexOf("-") > 0 || isSVGTag(tag);
|
|
80
|
+
}
|
|
81
|
+
export function renderDynamicAttr(s, e, key, v, n, tag = null) {
|
|
82
|
+
const name = tag !== null && keepsAttrCase(tag) ? key : (propsToAttrMap[key] ?? key.toLowerCase());
|
|
79
83
|
if (!isSSRSafeAttrName(name))
|
|
80
|
-
fail(s.comp, `unsafe attribute name \`${name}\``, n);
|
|
84
|
+
fail(s.comp, "FV0404", `unsafe attribute name \`${name}\``, n);
|
|
81
85
|
renderable(s, key, v, n);
|
|
82
|
-
if (v.ty
|
|
86
|
+
if (nothing(v.ty))
|
|
83
87
|
return;
|
|
84
88
|
const boolean = (t) => isBooleanAttr(name) || (name === "hidden" && (t.k === "bool" || t.k === "int" || t.k === "float"));
|
|
85
89
|
if (v.ty.k === "opt" && boolean(v.ty.of)) {
|
|
@@ -90,7 +94,7 @@ export function renderDynamicAttr(s, e, key, v, n) {
|
|
|
90
94
|
}
|
|
91
95
|
if (v.ty.k === "opt") {
|
|
92
96
|
e.open(`if let Some(v) = ${v.code}`);
|
|
93
|
-
renderDynamicAttr(s, e, key, { code: "v", ty: v.ty.of }, n);
|
|
97
|
+
renderDynamicAttr(s, e, key, { code: "v", ty: v.ty.of }, n, tag);
|
|
94
98
|
e.close();
|
|
95
99
|
return;
|
|
96
100
|
}
|
|
@@ -140,7 +144,7 @@ export function directiveProps(s, n) {
|
|
|
140
144
|
else if (dir?.type === "Identifier")
|
|
141
145
|
name = s.directives.get(dir.name) ?? null;
|
|
142
146
|
if (name === null || !ctx.clientDirectives.has(name)) {
|
|
143
|
-
fail(s.comp, `custom directive \`v-${name ?? "?"}\` may add attributes on the server; if it has no \`getSSRProps\`, list \`${name ?? "?"}\` in \`clientDirectives\` in ${CONFIG_FILE}`, n);
|
|
147
|
+
fail(s.comp, "FV0405", `custom directive \`v-${name ?? "?"}\` may add attributes on the server; if it has no \`getSSRProps\`, list \`${name ?? "?"}\` in \`clientDirectives\` in ${CONFIG_FILE}`, n);
|
|
144
148
|
}
|
|
145
149
|
return true;
|
|
146
150
|
}
|
|
@@ -151,7 +155,7 @@ export function dollarAttrs(s, n) {
|
|
|
151
155
|
if (!isDollarAttrs(n, s.attrsBindings))
|
|
152
156
|
return false;
|
|
153
157
|
if (s.comp.idsInAttrs) {
|
|
154
|
-
fail(s.comp, `\`$attrs\` in ${s.comp.name}, the root of a component that may be handed scope ids: it would hold them as attributes too`, n);
|
|
158
|
+
fail(s.comp, "FV0406", `\`$attrs\` in ${s.comp.name}, the root of a component that may be handed scope ids: it would hold them as attributes too`, n);
|
|
155
159
|
}
|
|
156
160
|
return true;
|
|
157
161
|
}
|
|
@@ -192,7 +196,7 @@ export function renderAttrs(s, e, n) {
|
|
|
192
196
|
else if (p.type === "ObjectExpression")
|
|
193
197
|
sources.push(`&[${attrEntries(s, p, "own").join(", ")}]`);
|
|
194
198
|
else
|
|
195
|
-
fail(s.comp, "attributes must be an object literal", p);
|
|
199
|
+
fail(s.comp, "FV0407", "attributes must be an object literal", p);
|
|
196
200
|
}
|
|
197
201
|
const ids = idsAt >= 0 && s.attrs !== null ? s.attrs : '""';
|
|
198
202
|
e.stmt(`fv::attrs_into(out, &[${sources.join(", ")}], ${idsAt >= 0 ? idsAt : sources.length}, ${ids});`);
|
|
@@ -223,16 +227,16 @@ function staticAttrs(s, e, n) {
|
|
|
223
227
|
}
|
|
224
228
|
function objectAttrs(s, e, n, merged) {
|
|
225
229
|
if (n.type !== "ObjectExpression")
|
|
226
|
-
fail(s.comp, "attributes must be an object literal", n);
|
|
230
|
+
fail(s.comp, "FV0407", "attributes must be an object literal", n);
|
|
227
231
|
for (const p of n.properties) {
|
|
228
232
|
if (p.type !== "ObjectProperty" || p.computed)
|
|
229
|
-
fail(s.comp, "attribute objects hold plain keys", p);
|
|
233
|
+
fail(s.comp, "FV0408", "attribute objects hold plain keys", p);
|
|
230
234
|
const raw = p.key.type === "Identifier" ? p.key.name : p.key.value;
|
|
231
235
|
if (IGNORED_PROPS.has(raw) || /^on[^a-z]/.test(raw) || raw.startsWith("."))
|
|
232
236
|
continue;
|
|
233
237
|
const key = raw.startsWith("^") ? raw.slice(1) : raw;
|
|
234
238
|
if (key === "className") {
|
|
235
|
-
fail(s.comp, "`className` renders by its own rule in Vue; bind `class`", p);
|
|
239
|
+
fail(s.comp, "FV0409", "`className` renders by its own rule in Vue; bind `class`", p);
|
|
236
240
|
}
|
|
237
241
|
else if (key === "class") {
|
|
238
242
|
const present = merged ? classPresent(s, p.value) : "true";
|
|
@@ -267,16 +271,16 @@ export function mergeProps(s, n) {
|
|
|
267
271
|
if (directiveProps(s, a))
|
|
268
272
|
continue;
|
|
269
273
|
if (a.type !== "ObjectExpression")
|
|
270
|
-
fail(s.comp, "`_mergeProps` of object literals is supported", a);
|
|
274
|
+
fail(s.comp, "FV0410", "`_mergeProps` of object literals is supported", a);
|
|
271
275
|
for (const p of a.properties) {
|
|
272
276
|
if (p.type !== "ObjectProperty" || p.computed)
|
|
273
|
-
fail(s.comp, "attribute objects hold plain keys", p);
|
|
277
|
+
fail(s.comp, "FV0408", "attribute objects hold plain keys", p);
|
|
274
278
|
const key = p.key.type === "Identifier" ? p.key.name : p.key.value;
|
|
275
279
|
const had = merged.get(key);
|
|
276
280
|
if (had && key === "class" && maybeEqual(s, p.value)) {
|
|
277
281
|
const before = literalClass(had.value);
|
|
278
282
|
if (before === null || p.value.type !== "StringLiteral") {
|
|
279
|
-
fail(s.comp, "a class merged with a string that may equal the class before it, which Vue then writes once: bind an array", p);
|
|
283
|
+
fail(s.comp, "FV0411", "a class merged with a string that may equal the class before it, which Vue then writes once: bind an array", p);
|
|
280
284
|
}
|
|
281
285
|
if (before !== p.value.value)
|
|
282
286
|
merged.set(key, { ...p, value: { type: "ArrayExpression", elements: [had.value, p.value], fvMerged: true } });
|
|
@@ -297,7 +301,7 @@ export function attrEntries(s, obj, side) {
|
|
|
297
301
|
const out = [];
|
|
298
302
|
for (const p of obj.properties) {
|
|
299
303
|
if (p.type !== "ObjectProperty" || p.computed)
|
|
300
|
-
fail(s.comp, "attribute objects hold plain keys", p);
|
|
304
|
+
fail(s.comp, "FV0408", "attribute objects hold plain keys", p);
|
|
301
305
|
const key = p.key.type === "Identifier" ? p.key.name : String(p.key.value);
|
|
302
306
|
if (IGNORED_PROPS.has(key) || /^on[^a-z]/.test(key) || key.startsWith("."))
|
|
303
307
|
continue;
|
|
@@ -307,7 +311,7 @@ export function attrEntries(s, obj, side) {
|
|
|
307
311
|
}
|
|
308
312
|
export function attrOf(s, key, n, side) {
|
|
309
313
|
if (key === "className")
|
|
310
|
-
fail(s.comp, "`className` renders by its own rule in Vue; bind `class`", n);
|
|
314
|
+
fail(s.comp, "FV0409", "`className` renders by its own rule in Vue; bind `class`", n);
|
|
311
315
|
if (key === "class")
|
|
312
316
|
return classAttr(s, n, side);
|
|
313
317
|
if (key === "style")
|
|
@@ -327,6 +331,7 @@ export function valueAttr(s, v, n) {
|
|
|
327
331
|
case "bool":
|
|
328
332
|
return `fv::Attr::Bool(${bare(v.code)})`;
|
|
329
333
|
case "undef":
|
|
334
|
+
case "null":
|
|
330
335
|
return "fv::Attr::Undefined";
|
|
331
336
|
case "opt": {
|
|
332
337
|
const of = v.ty.of.k;
|
|
@@ -335,5 +340,5 @@ export function valueAttr(s, v, n) {
|
|
|
335
340
|
return `${atom(v.code)}.map_or(fv::Attr::Undefined, ${make})`;
|
|
336
341
|
}
|
|
337
342
|
}
|
|
338
|
-
return fail(s.comp, "an attribute that may fall through is a string, a number or a boolean", n);
|
|
343
|
+
return fail(s.comp, "FV0412", "an attribute that may fall through is a string, a number or a boolean", n);
|
|
339
344
|
}
|
package/dist/calls.js
CHANGED
|
@@ -20,7 +20,7 @@ export function call(s, n) {
|
|
|
20
20
|
meet(comp, a, b, "`v-model`", n, "equal");
|
|
21
21
|
return boolOf(stringsEqual(a, b));
|
|
22
22
|
}
|
|
23
|
-
return fail(comp, "`v-model` comparison between these types", n);
|
|
23
|
+
return fail(comp, "FV0413", "`v-model` comparison between these types", n);
|
|
24
24
|
}
|
|
25
25
|
case "_ssrIncludeBooleanAttr": {
|
|
26
26
|
const a = expr(s, args[0]);
|
|
@@ -33,7 +33,7 @@ export function call(s, n) {
|
|
|
33
33
|
return boolOf(truthy(a));
|
|
34
34
|
}
|
|
35
35
|
case "_ssrLooseContain":
|
|
36
|
-
return fail(comp, "`v-model` over an array", n);
|
|
36
|
+
return fail(comp, "FV0414", "`v-model` over an array", n);
|
|
37
37
|
}
|
|
38
38
|
const own = claim((p) => p.call?.(s, n));
|
|
39
39
|
if (own)
|
|
@@ -58,21 +58,21 @@ export function call(s, n) {
|
|
|
58
58
|
return a;
|
|
59
59
|
if (a.ty.k === "bool")
|
|
60
60
|
return { code: `i64::from(${bare(a.code)})`, ty: INT };
|
|
61
|
-
return fail(comp, "`Number()` takes a string, a number or a boolean that is present", n);
|
|
61
|
+
return fail(comp, "FV0701", "`Number()` takes a string, a number or a boolean that is present", n);
|
|
62
62
|
}
|
|
63
63
|
if ((callee.name === "parseInt" && (args.length === 1 || args.length === 2)) || (callee.name === "parseFloat" && args.length === 1)) {
|
|
64
64
|
const a = expr(s, args[0]);
|
|
65
65
|
if (a.ty.k !== "str")
|
|
66
|
-
fail(comp, `\`${callee.name}()\` takes a string`, args[0]);
|
|
66
|
+
fail(comp, "FV0702", `\`${callee.name}()\` takes a string`, args[0]);
|
|
67
67
|
if (callee.name === "parseFloat")
|
|
68
68
|
return { code: `fv::js_parse_float(${strArg(a.code)})`, ty: FLOAT };
|
|
69
69
|
const radix = args[1];
|
|
70
70
|
if (radix && !(radix.type === "NumericLiteral" && (radix.value === 10 || radix.value === 16))) {
|
|
71
|
-
fail(comp, "`parseInt()` takes a radix of 10 or 16, written as a literal", radix);
|
|
71
|
+
fail(comp, "FV0703", "`parseInt()` takes a radix of 10 or 16, written as a literal", radix);
|
|
72
72
|
}
|
|
73
73
|
return { code: `fv::js_parse_int(${strArg(a.code)}, ${radix ? radix.value : 0})`, ty: FLOAT };
|
|
74
74
|
}
|
|
75
|
-
return fail(comp, `\`${callee.name}()\` is not available when rendering on the server`, n);
|
|
75
|
+
return fail(comp, "FV0601", `\`${callee.name}()\` is not available when rendering on the server`, n);
|
|
76
76
|
}
|
|
77
77
|
if (callee.type === "MemberExpression" && !callee.computed) {
|
|
78
78
|
const method = callee.property.name;
|
|
@@ -119,7 +119,7 @@ export function call(s, n) {
|
|
|
119
119
|
return { code: `${receiver(asF64(x))}.${method}()`, ty: FLOAT };
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
|
-
return fail(comp, `\`Math.${method}()\` is supported on numbers as \`max\`, \`min\`, \`abs\`, \`round\`, \`floor\`, \`ceil\` and \`trunc\``, n);
|
|
122
|
+
return fail(comp, "FV0704", `\`Math.${method}()\` is supported on numbers as \`max\`, \`min\`, \`abs\`, \`round\`, \`floor\`, \`ceil\` and \`trunc\``, n);
|
|
123
123
|
}
|
|
124
124
|
const target = expr(s, callee.object);
|
|
125
125
|
if (target.ty.k === "str") {
|
|
@@ -145,7 +145,7 @@ export function call(s, n) {
|
|
|
145
145
|
if (isNumber(target.ty) && method === "toFixed" && args.length <= 1) {
|
|
146
146
|
const d = args.length ? args[0] : { type: "NumericLiteral", value: 0 };
|
|
147
147
|
if (d.type !== "NumericLiteral" || !Number.isInteger(d.value) || d.value < 0 || d.value > 100) {
|
|
148
|
-
fail(comp, "`.toFixed()` takes a literal number of digits, from 0 to 100", n);
|
|
148
|
+
fail(comp, "FV0705", "`.toFixed()` takes a literal number of digits, from 0 to 100", n);
|
|
149
149
|
}
|
|
150
150
|
return { code: `&*fv::js_to_fixed(${bare(asF64(target))}, ${d.value})`, ty: STR };
|
|
151
151
|
}
|
|
@@ -162,8 +162,10 @@ export function call(s, n) {
|
|
|
162
162
|
const of = target.ty.of;
|
|
163
163
|
if (method === "includes" && args.length === 1) {
|
|
164
164
|
const v = expr(s, args[0]);
|
|
165
|
+
if (of.k === "int" && v.ty.k === "float")
|
|
166
|
+
return { code: `${atom(target.code)}.iter().any(|v| ${binary("*v as f64", "==", v.code)})`, ty: BOOL };
|
|
165
167
|
if (!sameTy(v.ty, of))
|
|
166
|
-
fail(comp, "`.includes()` looks for a value of the list's own type", args[0]);
|
|
168
|
+
fail(comp, "FV0801", "`.includes()` looks for a value of the list's own type", args[0]);
|
|
167
169
|
if (of.k === "int")
|
|
168
170
|
return { code: `${atom(target.code)}.contains(&${operand(v.code, UNARY)})`, ty: BOOL };
|
|
169
171
|
const test = v.code === '""' ? "v.is_empty()" : binary("&**v", "==", v.code);
|
|
@@ -172,14 +174,14 @@ export function call(s, n) {
|
|
|
172
174
|
if (method === "join" && args.length <= 1) {
|
|
173
175
|
const sep = args.length ? expr(s, args[0]) : { code: '","', ty: STR };
|
|
174
176
|
if (sep.ty.k !== "str")
|
|
175
|
-
fail(comp, "`.join()` takes a string", args[0]);
|
|
177
|
+
fail(comp, "FV0802", "`.join()` takes a string", args[0]);
|
|
176
178
|
const each = of.k === "str" ? `${atom(target.code)}.iter().map(|v| &**v)` : `${atom(target.code)}.iter().map(|v| fv::Js(*v).to_string())`;
|
|
177
179
|
return { code: `&*${each}.collect::<Vec<_>>().join(${strArg(sep.code)})`, ty: STR, ...loneOf(sep) };
|
|
178
180
|
}
|
|
179
181
|
}
|
|
180
|
-
return fail(comp, `\`.${method}()\` is not supported`, n);
|
|
182
|
+
return fail(comp, "FV0602", `\`.${method}()\` is not supported`, n);
|
|
181
183
|
}
|
|
182
|
-
return fail(comp, "this call is not supported", n);
|
|
184
|
+
return fail(comp, "FV0603", "this call is not supported", n);
|
|
183
185
|
}
|
|
184
186
|
export function isObjectCall(n, method) {
|
|
185
187
|
return (n?.type === "CallExpression" && n.callee.type === "MemberExpression" && !n.callee.computed &&
|
|
@@ -187,7 +189,7 @@ export function isObjectCall(n, method) {
|
|
|
187
189
|
}
|
|
188
190
|
function json(s, v, n) {
|
|
189
191
|
if (v.lone)
|
|
190
|
-
fail(s.comp, lonely("`JSON.stringify()`"), n);
|
|
192
|
+
fail(s.comp, "FV0706", lonely("`JSON.stringify()`"), n);
|
|
191
193
|
const one = (code, ty) => {
|
|
192
194
|
switch (ty.k) {
|
|
193
195
|
case "str":
|
|
@@ -199,7 +201,7 @@ function json(s, v, n) {
|
|
|
199
201
|
case "bool":
|
|
200
202
|
return `(if ${condition(code)} { "true" } else { "false" }).to_owned()`;
|
|
201
203
|
default:
|
|
202
|
-
return fail(s.comp, "`JSON.stringify()` of a string, a number, a boolean or a list of those, present", n);
|
|
204
|
+
return fail(s.comp, "FV0707", "`JSON.stringify()` of a string, a number, a boolean or a list of those, present", n);
|
|
203
205
|
}
|
|
204
206
|
};
|
|
205
207
|
if (v.ty.k === "list") {
|
|
@@ -212,7 +214,7 @@ function json(s, v, n) {
|
|
|
212
214
|
export function helperCall(s, name, args, n) {
|
|
213
215
|
const h = ctx.helpers[name];
|
|
214
216
|
if (args.length !== h.params.length)
|
|
215
|
-
fail(s.comp, `\`${name}\` takes ${h.params.length} argument(s)`, n);
|
|
217
|
+
fail(s.comp, "FV1101", `\`${name}\` takes ${h.params.length} argument(s)`, n);
|
|
216
218
|
const code = args.map((a, i) => bare(coerce(s.comp, expr(s, a), h.params[i], a))).join(", ");
|
|
217
219
|
s.helperBytes.n += h.maxLen;
|
|
218
220
|
return { code: `${h.rust}(${code})`, ty: h.ret };
|
package/dist/children.d.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import { type Component, type N, type Scope, type Ty, type Val } from "./model.ts";
|
|
1
|
+
import { type Component, type Field, type N, type Scope, type Ty, type Val } from "./model.ts";
|
|
2
2
|
import { Emitter } from "./emitter.ts";
|
|
3
|
-
|
|
3
|
+
/** A component the project renders with a Rust function of its own, in place of a compiled one. */
|
|
4
|
+
export interface TwinCall {
|
|
5
|
+
comp: Component;
|
|
6
|
+
init(s: Scope, f: Field, node: N | undefined, n: N): string;
|
|
7
|
+
call(s: Scope, e: Emitter, inits: string[], slots: N, attrs: string): void;
|
|
8
|
+
}
|
|
9
|
+
export declare function renderChild(s: Scope, e: Emitter, n: N, twin?: TwinCall): void;
|
|
4
10
|
export declare function array(key: string): boolean;
|
|
5
11
|
export declare function fieldInit(name: string, value: string): string;
|
|
6
12
|
export declare function takesSlots(c: Component): boolean;
|
|
7
|
-
export declare function extraParams(c: Component): string;
|
|
8
|
-
export declare function callChild(s: Scope, e: Emitter, child: Component, propsCode: string, slots: N, attrs: string | null): void;
|
|
13
|
+
export declare function extraParams(c: Component, unread?: (name: string) => boolean): string;
|
|
14
|
+
export declare function callChild(s: Scope, e: Emitter, child: Component, propsCode: string, slots: N, attrs: string | null, later?: boolean): void;
|
|
15
|
+
export declare function callWith(s: Scope, e: Emitter, child: Component, m: string, head: string, slotsTy: string, trailing: string, slots: N, vnode?: boolean): void;
|
|
9
16
|
export declare function ownInto(comp: Component, v: Val, want: Ty, node: N): string;
|