ferrovue 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +103 -15
  2. package/dist/attrs.d.ts +8 -42
  3. package/dist/attrs.js +148 -297
  4. package/dist/calls.d.ts +4 -0
  5. package/dist/calls.js +219 -0
  6. package/dist/children.d.ts +9 -0
  7. package/dist/children.js +273 -0
  8. package/dist/classes.d.ts +13 -0
  9. package/dist/classes.js +176 -0
  10. package/dist/cli.js +121 -27
  11. package/dist/client.d.ts +11 -2
  12. package/dist/client.js +45 -9
  13. package/dist/compiler.d.ts +4 -0
  14. package/dist/compiler.js +37 -90
  15. package/dist/component.js +19 -82
  16. package/dist/context.d.ts +6 -68
  17. package/dist/context.js +25 -38
  18. package/dist/diff.d.ts +1 -0
  19. package/dist/diff.js +68 -0
  20. package/dist/emitter.d.ts +0 -8
  21. package/dist/emitter.js +0 -12
  22. package/dist/expr.d.ts +0 -70
  23. package/dist/expr.js +30 -855
  24. package/dist/fallthrough.d.ts +9 -0
  25. package/dist/fallthrough.js +78 -0
  26. package/dist/fixture.d.ts +2 -1
  27. package/dist/fixture.js +37 -22
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.js +1 -0
  30. package/dist/islands.d.ts +6 -0
  31. package/dist/islands.js +5 -0
  32. package/dist/lists.d.ts +0 -11
  33. package/dist/lists.js +4 -39
  34. package/dist/loops.d.ts +3 -0
  35. package/dist/loops.js +164 -0
  36. package/dist/model.d.ts +22 -130
  37. package/dist/model.js +37 -9
  38. package/dist/narrowing.d.ts +19 -0
  39. package/dist/narrowing.js +126 -0
  40. package/dist/numbers.d.ts +8 -0
  41. package/dist/numbers.js +73 -0
  42. package/dist/parens.d.ts +0 -27
  43. package/dist/parens.js +0 -44
  44. package/dist/plugin.d.ts +84 -0
  45. package/dist/plugin.js +26 -0
  46. package/dist/plugins/i18n.d.ts +23 -0
  47. package/dist/{i18n.js → plugins/i18n.js} +76 -19
  48. package/dist/plugins/index.d.ts +2 -0
  49. package/dist/plugins/index.js +8 -0
  50. package/dist/plugins/router-link.d.ts +8 -0
  51. package/dist/{router.js → plugins/router-link.js} +65 -57
  52. package/dist/plugins/router.d.ts +42 -0
  53. package/dist/plugins/router.js +256 -0
  54. package/dist/plugins/scoped.d.ts +12 -0
  55. package/dist/{scoped.js → plugins/scoped.js} +55 -20
  56. package/dist/plugins/shared-types.d.ts +2 -0
  57. package/dist/plugins/shared-types.js +7 -0
  58. package/dist/plugins/stores.d.ts +37 -0
  59. package/dist/plugins/stores.js +377 -0
  60. package/dist/plugins/teleport.d.ts +5 -0
  61. package/dist/plugins/teleport.js +55 -0
  62. package/dist/rust.d.ts +2 -5
  63. package/dist/rust.js +66 -161
  64. package/dist/script.d.ts +0 -6
  65. package/dist/script.js +22 -121
  66. package/dist/slots.d.ts +13 -0
  67. package/dist/slots.js +160 -0
  68. package/dist/strings.d.ts +13 -0
  69. package/dist/strings.js +208 -0
  70. package/dist/styles.d.ts +14 -0
  71. package/dist/styles.js +181 -0
  72. package/dist/template.d.ts +2 -40
  73. package/dist/template.js +40 -691
  74. package/dist/testing.d.ts +1 -0
  75. package/dist/testing.js +1 -8
  76. package/dist/types.d.ts +2 -0
  77. package/dist/typescript.d.ts +0 -13
  78. package/dist/typescript.js +8 -41
  79. package/dist/vite.d.ts +1 -0
  80. package/dist/vite.js +35 -14
  81. package/package.json +11 -2
  82. package/dist/i18n.d.ts +0 -27
  83. package/dist/router.d.ts +0 -17
  84. package/dist/scoped.d.ts +0 -10
  85. package/dist/stores.d.ts +0 -6
  86. package/dist/stores.js +0 -227
package/dist/stores.js DELETED
@@ -1,227 +0,0 @@
1
- /* Pinia option stores: their state, its types, and their getters. */
2
- import { parse as parseJs } from "@babel/parser";
3
- import { readdirSync, readFileSync } from "node:fs";
4
- import { basename, dirname, join, relative, resolve } from "node:path";
5
- import { BOOL, fail, FLOAT, INT, opt, sameTy, snake, STR, tagAst, UNDEF } from "./model.js";
6
- import { ctx } from "./context.js";
7
- import { markStore, structOf, tyOfTs, typesImports } from "./typescript.js";
8
- import { patternNames, setupStatement } from "./script.js";
9
- /** The store module an import names, resolved and without its extension, when it is one. */
10
- export function storeImport(comp, from) {
11
- if (!from.startsWith(".") || ctx.stores.size === 0)
12
- return null;
13
- const target = resolve(ctx.rootDir, dirname(comp.file), from).replace(/\.ts$/, "");
14
- return [...ctx.stores.values()].some((s) => s.module === target) ? target : null;
15
- }
16
- /** Every store in the configured directory, and the interfaces their files declare. */
17
- export function readStores(root, dir) {
18
- ctx.stores = new Map();
19
- ctx.storeStructs = new Map();
20
- ctx.storeFiles = new Map();
21
- const files = readdirSync(join(root, dir)).filter((f) => f.endsWith(".ts") && !f.endsWith(".test.ts")).toSorted();
22
- for (const f of files) {
23
- const path = join(root, dir, f);
24
- const comp = storeHome(relative(root, path));
25
- comp.source = readFileSync(path, "utf8");
26
- const ast = parseJs(comp.source, { sourceType: "module", plugins: ["typescript"] }).program.body;
27
- tagAst(ast, "source");
28
- typesImports(comp, ast);
29
- const decls = ast.map((st) => (st.type === "ExportNamedDeclaration" ? st.declaration : st)).filter(Boolean);
30
- const interfaces = decls.filter((d) => d.type === "TSInterfaceDeclaration");
31
- for (const d of interfaces) {
32
- if (ctx.storeStructs.has(d.id.name))
33
- fail(comp, `\`${d.id.name}\` is declared by another store too`, d);
34
- ctx.storeStructs.set(d.id.name, { name: d.id.name, fields: [] });
35
- ctx.storeFiles.set(d.id.name, comp.file);
36
- }
37
- for (const d of interfaces) {
38
- const st = structOf(comp, d.id.name, d.body.body, ctx.storeStructs);
39
- for (const field of st.fields)
40
- field.ty = markStore(field.ty);
41
- ctx.storeStructs.set(d.id.name, st);
42
- }
43
- for (const d of decls) {
44
- if (d.type !== "VariableDeclaration")
45
- continue;
46
- for (const v of d.declarations) {
47
- const init = v.init;
48
- if (init?.type !== "CallExpression" || init.callee.type !== "Identifier" || init.callee.name !== "defineStore")
49
- continue;
50
- const [id, options] = init.arguments;
51
- if (id?.type !== "StringLiteral")
52
- fail(comp, "a store's id is a string literal", init);
53
- if (options?.type === "ArrowFunctionExpression" || options?.type === "FunctionExpression") {
54
- setupStore(comp, v.id.name, id.value, options, path);
55
- continue;
56
- }
57
- if (options?.type !== "ObjectExpression")
58
- fail(comp, "a store is `defineStore(id, { state, getters, actions })` or `defineStore(id, () => { … })`", init);
59
- const state = options.properties.find((p) => (p.key?.name ?? p.key?.value) === "state");
60
- const fn = state?.value ?? (state?.type === "ObjectMethod" ? state : null);
61
- const ret = fn?.returnType?.typeAnnotation;
62
- if (ret?.type !== "TSTypeReference" || !ctx.storeStructs.has(ret.typeName.name)) {
63
- fail(comp, "a store's `state` declares its return type, an interface in the same file: `state: (): State => ({ … })`", state ?? init);
64
- }
65
- const getters = new Map();
66
- const getterObj = options.properties.find((p) => (p.key?.name ?? p.key?.value) === "getters");
67
- if (getterObj && getterObj.value?.type !== "ObjectExpression")
68
- fail(comp, "a store's `getters` is an object literal", getterObj);
69
- for (const g of getterObj?.value.properties ?? []) {
70
- const getterFn = g.type === "ObjectMethod" ? g : g.value;
71
- const name = g.key?.name ?? g.key?.value;
72
- if (!getterFn || !["ArrowFunctionExpression", "FunctionExpression", "ObjectMethod"].includes(getterFn.type)) {
73
- fail(comp, `getter \`${name}\` is a function of the state`, g);
74
- }
75
- let body = getterFn.body;
76
- if (body.type === "BlockStatement") {
77
- const only = body.body.length === 1 ? body.body[0] : null;
78
- body = only?.type === "ReturnStatement" ? only.argument : null;
79
- }
80
- const param = getterFn.params[0];
81
- // A getter the server cannot translate fails where a component reads it, not here.
82
- getters.set(name, { param: param?.type === "Identifier" ? param.name : null, body, file: comp.file });
83
- }
84
- ctx.stores.set(v.id.name, {
85
- hook: v.id.name,
86
- id: id.value,
87
- field: snake(id.value),
88
- state: ret.typeName.name,
89
- module: path.replace(/\.ts$/, ""),
90
- getters,
91
- });
92
- }
93
- }
94
- }
95
- }
96
- /** A store file, as the thing its types are declared in: what errors name, and where they resolve. */
97
- /** A setup store: \`defineStore(id, () => { …; return { … } })\`. The refs it returns are its state —
98
- * typed by \`ref<T>(…)\`, or by the literal they start from — the computeds it returns its getters,
99
- * and its functions actions, which only the client runs. */
100
- function setupStore(comp, hook, id, fn, path) {
101
- if (fn.body.type !== "BlockStatement")
102
- fail(comp, "a setup store's function returns its state from a block: `() => { …; return { … } }`", fn);
103
- const refs = new Map();
104
- const computeds = new Map();
105
- const others = new Set();
106
- let returned = null;
107
- for (const st of fn.body.body) {
108
- if (st.type === "ReturnStatement") {
109
- returned = st.argument;
110
- continue;
111
- }
112
- if (st.type === "FunctionDeclaration") {
113
- if (st.id)
114
- others.add(st.id.name);
115
- continue;
116
- }
117
- if (st.type === "ExpressionStatement") {
118
- setupStatement(comp, st);
119
- continue;
120
- }
121
- if (st.type !== "VariableDeclaration")
122
- fail(comp, `\`${st.type}\` in a setup store is not supported`, st);
123
- for (const d of st.declarations) {
124
- if (d.id.type !== "Identifier") {
125
- for (const name of patternNames(d.id))
126
- others.add(name);
127
- continue;
128
- }
129
- const init = d.init;
130
- const callee = init?.type === "CallExpression" && init.callee.type === "Identifier" ? init.callee.name : null;
131
- if (callee === "ref" || callee === "shallowRef") {
132
- refs.set(d.id.name, refType(comp, init));
133
- }
134
- else if (callee === "computed") {
135
- const getter = init.arguments[0];
136
- let body = getter?.body;
137
- if (body?.type === "BlockStatement") {
138
- const only = body.body.length === 1 ? body.body[0] : null;
139
- body = only?.type === "ReturnStatement" ? only.argument : null;
140
- }
141
- computeds.set(d.id.name, body);
142
- }
143
- else
144
- others.add(d.id.name);
145
- }
146
- }
147
- if (returned?.type !== "ObjectExpression")
148
- fail(comp, "a setup store returns an object of its state, getters and actions", returned ?? fn);
149
- const state = [];
150
- const getters = new Map();
151
- for (const p of returned.properties) {
152
- if (p.type !== "ObjectProperty" || p.computed || p.value.type !== "Identifier")
153
- fail(comp, "a setup store returns plain names: `{ count, doubled, increment }`", p);
154
- const key = p.key.name ?? p.key.value;
155
- const local = p.value.name;
156
- if (refs.has(local))
157
- state.push({ js: key, rust: snake(key), ty: markStore(refs.get(local)) });
158
- else if (computeds.has(local))
159
- getters.set(key, { param: null, body: computeds.get(local), file: comp.file, setup: true });
160
- else if (!others.has(local))
161
- fail(comp, `\`${local}\` is not declared in the store's function`, p);
162
- }
163
- const name = id.split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("") + "State";
164
- if (ctx.storeStructs.has(name))
165
- fail(comp, `\`${name}\` names this setup store's state; rename the interface`, fn);
166
- ctx.storeStructs.set(name, { name, fields: state });
167
- ctx.storeFiles.set(name, comp.file);
168
- ctx.stores.set(hook, { hook, id, field: snake(id), state: name, module: path.replace(/\.ts$/, ""), getters });
169
- }
170
- /** A setup store ref's type: \`ref<T>(…)\`, or what its initial literal is; optional when it has none. */
171
- function refType(comp, init) {
172
- const typed = init.typeParameters?.params?.[0];
173
- const value = init.arguments[0];
174
- if (typed) {
175
- const ty = tyOfTs(comp, typed, ctx.storeStructs);
176
- return value ? ty : opt(ty);
177
- }
178
- const literal = (n) => {
179
- if (n?.type === "StringLiteral" || (n?.type === "TemplateLiteral" && n.expressions.length === 0))
180
- return STR;
181
- if (n?.type === "NumericLiteral")
182
- return Number.isInteger(n.value) ? INT : FLOAT;
183
- if (n?.type === "UnaryExpression" && n.operator === "-")
184
- return literal(n.argument);
185
- if (n?.type === "BooleanLiteral")
186
- return BOOL;
187
- if (n?.type === "ArrayExpression" && n.elements.length) {
188
- const of = literal(n.elements[0]);
189
- return of && n.elements.every((el) => sameTy(literal(el) ?? UNDEF, of)) ? { k: "list", of } : null;
190
- }
191
- return null;
192
- };
193
- return literal(value) ?? fail(comp, "a setup store's ref declares its type: `ref<string[]>([])`", init);
194
- }
195
- export function storeHome(file) {
196
- return {
197
- name: basename(file),
198
- module: "stores",
199
- file,
200
- props: { name: "Props", fields: [] },
201
- structs: ctx.storeStructs,
202
- trustedName: null,
203
- floatName: null,
204
- childProps: new Map(),
205
- imports: new Set(),
206
- slotNames: [],
207
- routerView: false,
208
- routerLink: false,
209
- readsRoute: false,
210
- usesRoute: false,
211
- readsStores: false,
212
- usesStores: false,
213
- readsI18n: false,
214
- usesI18n: false,
215
- readsTeleports: false,
216
- usesTeleports: false,
217
- models: new Map(),
218
- aliases: new Map(),
219
- importedTypes: new Map(),
220
- slotShapes: new Map(),
221
- scopeId: null,
222
- slotted: false,
223
- inheritAttrs: true,
224
- inherits: false,
225
- passesSlotIds: false,
226
- };
227
- }