ferrovue 0.9.0 → 0.10.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 +36 -22
- package/dist/args.js +1 -1
- package/dist/attrs.d.ts +2 -0
- package/dist/attrs.js +12 -4
- package/dist/blocks.d.ts +32 -0
- package/dist/blocks.js +476 -0
- package/dist/calls.js +12 -3
- package/dist/children.js +10 -3
- package/dist/cli.js +2 -6
- package/dist/client-render.d.ts +4 -3
- package/dist/client-render.js +17 -4
- package/dist/client.d.ts +12 -0
- package/dist/client.js +28 -24
- package/dist/compiler.d.ts +14 -4
- package/dist/compiler.js +184 -35
- package/dist/component.js +9 -3
- package/dist/conformance.d.ts +1 -1
- package/dist/constants.d.ts +26 -3
- package/dist/constants.js +176 -20
- package/dist/context.d.ts +15 -1
- package/dist/context.js +8 -2
- package/dist/diagnostics.d.ts +11 -1
- package/dist/diagnostics.js +33 -4
- package/dist/dynamic.js +7 -2
- package/dist/editor.d.ts +2 -2
- package/dist/editor.js +14 -9
- package/dist/emitter.d.ts +1 -0
- package/dist/emitter.js +12 -0
- package/dist/errors.d.ts +422 -7
- package/dist/errors.js +1399 -335
- package/dist/expr.d.ts +11 -0
- package/dist/expr.js +140 -33
- package/dist/fixture.d.ts +4 -1
- package/dist/fixture.js +10 -3
- package/dist/functions.d.ts +14 -0
- package/dist/functions.js +172 -0
- package/dist/hydration.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/inputs.d.ts +2 -2
- package/dist/inputs.js +1 -1
- package/dist/lists.d.ts +5 -1
- package/dist/lists.js +173 -29
- package/dist/loads.d.ts +27 -0
- package/dist/loads.js +81 -0
- package/dist/loops.js +10 -3
- package/dist/model.d.ts +50 -3
- package/dist/model.js +162 -6
- package/dist/narrowing.d.ts +8 -0
- package/dist/narrowing.js +28 -4
- package/dist/page-json.d.ts +1 -0
- package/dist/page-json.js +14 -0
- package/dist/plugin.d.ts +2 -1
- package/dist/plugins/client-only.js +1 -1
- package/dist/plugins/head.js +2 -1
- package/dist/plugins/index.js +2 -1
- package/dist/plugins/loaders.d.ts +35 -0
- package/dist/plugins/loaders.js +349 -0
- package/dist/plugins/provide.js +5 -4
- package/dist/plugins/router-link.js +2 -2
- package/dist/plugins/stores.js +7 -7
- package/dist/plugins/twins.js +1 -1
- package/dist/resolve.d.ts +32 -0
- package/dist/resolve.js +246 -0
- package/dist/rust.d.ts +1 -1
- package/dist/rust.js +22 -4
- package/dist/schema.d.ts +1 -1
- package/dist/script.d.ts +1 -1
- package/dist/script.js +64 -54
- package/dist/settle.js +8 -0
- package/dist/template.js +162 -137
- package/dist/typescript.d.ts +0 -1
- package/dist/typescript.js +14 -22
- package/dist/vite.js +3 -3
- package/dist/volar.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,13 +18,6 @@ HTML with no JavaScript runtime, and the browser hydrates that HTML with the sam
|
|
|
18
18
|
- **Exact or refused.** What ferrovue cannot reproduce exactly is a compile error that names the
|
|
19
19
|
file, line and construct. A component that compiles renders as Vue renders it.
|
|
20
20
|
|
|
21
|
-
ferrovue is at 0.8, before 1.0: a minor release may change the configuration, the generated code or
|
|
22
|
-
the crates' API. The [CHANGELOG](https://github.com/Kinsmir/ferrovue/blob/main/CHANGELOG.md) says
|
|
23
|
-
what changed, and the guide's upgrade pages
|
|
24
|
-
([0.8 to 0.9](https://docs.rs/ferrovue/latest/ferrovue/guide/upgrading_to_0_9/index.html),
|
|
25
|
-
[0.7 to 0.8](https://docs.rs/ferrovue/latest/ferrovue/guide/upgrading_to_0_8/index.html)) say how
|
|
26
|
-
to move a project.
|
|
27
|
-
|
|
28
21
|
```text
|
|
29
22
|
Button.vue ──(ferrovue compiler, Node)──▶ button.rs ──(your Rust server)──▶ HTML ──▶ Vue hydrates it
|
|
30
23
|
```
|
|
@@ -114,9 +107,10 @@ pnpm ferrovue --watch # regenerates when components or configs change
|
|
|
114
107
|
```
|
|
115
108
|
|
|
116
109
|
`-c, --config <path>` reads another configuration file. `--watch` regenerates on a change to what a
|
|
117
|
-
run reads (the configuration, the components, stores, locale messages, pages or routes file,
|
|
118
|
-
|
|
119
|
-
does the same in its dev server and before a build
|
|
110
|
+
run reads (the configuration, the components, stores, locale messages, pages or routes file, the
|
|
111
|
+
`.ts` files components import types from, and the tsconfig files their aliases come from). A Vite
|
|
112
|
+
project can use the plugin instead, which does the same in its dev server and before a build, and
|
|
113
|
+
also resolves imports through the build's `resolve.alias`:
|
|
120
114
|
|
|
121
115
|
```ts
|
|
122
116
|
// vite.config.ts
|
|
@@ -131,7 +125,9 @@ by default).
|
|
|
131
125
|
|
|
132
126
|
Every error carries a stable code, as `error[FV1805]: components/Card.vue:4:17: …`, documented in
|
|
133
127
|
the [`error_codes`](https://docs.rs/ferrovue/latest/ferrovue/guide/error_codes/index.html) guide.
|
|
134
|
-
|
|
128
|
+
A run reports every error it finds, each with a `= help:` line where the way around it is short,
|
|
129
|
+
then a line that counts them, and writes nothing while any remains. `--format json` writes the same
|
|
130
|
+
errors as JSON with the exit status unchanged; the
|
|
135
131
|
[quick start](https://docs.rs/ferrovue/latest/ferrovue/guide/quick_start/index.html#editor-and-ci-diagnostics)
|
|
136
132
|
has a VS Code problem matcher that puts them in the Problems panel.
|
|
137
133
|
|
|
@@ -222,17 +218,20 @@ ferrovue compiles `<script setup lang="ts">` components, and components with no
|
|
|
222
218
|
| Area | Supported |
|
|
223
219
|
|---|---|
|
|
224
220
|
| Prop types | `string`, `number` (integers, `i64`, written and computed as JavaScript does, exact within ±2⁵³), `Float` from `ferrovue/types` (fractions, `f64`), `boolean`, string-literal unions (`"sm" \| "md"`), `T \| undefined`, `T \| null` (an `Option` written as `null`), arrays (`T[]`, `Array<T>`, `readonly T[]`), interfaces and object type aliases (recursive ones too), dictionaries (`Record<string, T>`, `{ [key: string]: T }`, `ferrovue::Record` in Rust, which keeps JavaScript's order of keys), another component's exported `Props`, `TrustedHtml`, `InlineHtml`, `Date` (a component's own prop, optional or nullable too: `ferrovue::JsDate`, or `chrono::DateTime<Utc>` with the `chrono` feature) |
|
|
225
|
-
| Shared types | Interfaces and type aliases imported from `.ts` files (generated once, into `types.rs`), from a store's file, or from another component's `.vue` file; objects of a shared type can be passed between components. A TypeScript `enum` whose members are literals is the type of its values: a string, or a number |
|
|
226
|
-
| Constants | Constants imported from `.ts` files and `enum`s (imported, or declared in the component), evaluated when the component is compiled: strings, numbers, booleans, `null`, lists of them, objects of them read field by field (`LABELS.save`, `Tone.Loud`, `Rank[5]`), and lists of objects of them, which become a `const` in `types.rs` (`{ value, label }` items get a type named after the constant, `OptionsItem`, unless the constant is typed with an interface: `OPTIONS: Option[]`; a field that is `null` in some items is `T | null`). See the crate's [`props`](https://docs.rs/ferrovue/latest/ferrovue/guide/props/index.html#constants) guide |
|
|
221
|
+
| Shared types | Interfaces and type aliases imported from `.ts` files (generated once, into `types.rs`; imported by a relative path or through an alias the project declares, in its tsconfig.json's `compilerOptions.paths` or, with the Vite plugin, Vite's `resolve.alias`: `@/lib/format`), from a store's file, or from another component's `.vue` file; objects of a shared type can be passed between components. A TypeScript `enum` whose members are literals is the type of its values: a string, or a number |
|
|
222
|
+
| Constants | Constants imported from `.ts` files, object constants declared in `<script setup>`, and `enum`s (imported, or declared in the component), evaluated when the component is compiled: strings, numbers, booleans, `null`, lists of them, objects of them read field by field (`LABELS.save`, `Tone.Loud`, `Rank[5]`), and lists of objects of them, which become a `const` in `types.rs` (`{ value, label }` items get a type named after the constant, `OptionsItem`, unless the constant is typed with an interface: `OPTIONS: Option[]`; a field that is `null` in some items is `T | null`); lookup tables: an object constant (`as const`, `Record<Size, T>` or untyped, keys computed from enum members too) read by a key whose type is a union of string or integer literals or an `enum` (a prop, a `computed`, a `v-for` item's field, a `?:` of literals), compiled to a `match` over the members, read on by field (`THEME[tone].fg`) in text, attributes, `:class` and `:style`, with `undefined` for a member the object lacks (`ICONS[kind] ?? "none"`, `ICONS[kind]?.label`, `v-if="ICONS[kind]"`). See the crate's [`props`](https://docs.rs/ferrovue/latest/ferrovue/guide/props/index.html#constants) guide |
|
|
227
223
|
| Props | `withDefaults`, destructured props with defaults (`const { size = "md" } = defineProps<…>()`), the props object (`const props = defineProps<…>()`, then `props.label` in the template or in script code), optional booleans (Vue casts an absent one to `false`), `defineModel` (named, required, with defaults), components with no props. A generic component (`<script setup generic="T extends Item">`) renders each type parameter as its constraint, which is all the template can rely on |
|
|
228
|
-
| Setup | `ref`/`shallowRef`, `computed` (an expression or a
|
|
224
|
+
| Setup | `ref`/`shallowRef`, `computed` (an expression, or a body of statements: see Statements; one that may throw, through `.repeat()`, `.padStart()`, a date, `$t` or a helper, is evaluated where the render first reads it, once, as Vue does), refs that start empty, typed by their type argument (`ref<Row[]>([])`, `ref<Row>()`, `ref<string \| undefined>(undefined)`), plain `const`/`let`, `.value` in script code, helpers with Rust twins, functions (see Functions), a plain `<script>` block beside setup. Lifecycle hooks, `watch` (not `immediate`), `defineEmits`, `defineSlots`, `defineOptions`, `defineExpose` and template refs (`ref(null)`, `useTemplateRef`) are client-only, as is a function only an event handler calls. The template may name them only from event handlers, which the server drops |
|
|
225
|
+
| Statements | in a `computed`'s body and in a list method's callback (`.map()`, `.filter()`, `.find()`, `.some()`, `.reduce()`, a `.toSorted()` comparator and the others): `const`, and `let` never assigned again, of any value the template may compute, destructured too (`const { name, posts: count } = author`); `if` / `else if` / `else` and early `return`, narrowing what follows as TypeScript narrows it (`if (!user) return ""; return user.name`, `if (!a \|\| !a.title) return "-"`); `switch` over a string or a number, with stacked `case`s, `default` and `break`. Each `const` is evaluated once, where JavaScript evaluates it, and only on the path that reaches it. Loops, assignments, `try`, `throw`, `var` and a path that ends without `return` are refused. See the crate's [`script_logic`](https://docs.rs/ferrovue/latest/ferrovue/guide/script_logic/index.html) guide |
|
|
226
|
+
| Functions | functions the template or a `computed` calls: declared in `<script setup>` (`function f(a: T): R { … }`, `const f = (a: T) => …`) or exported from a `.ts` file the component imports, whose bodies hold what a `computed`'s may (see Statements) and read props, refs, `computed`s, constants and other such functions (a `.ts` file's own constants, functions and imports); parameters by name, optional (`x?: T`), with defaults (`x = 1`, also after an earlier parameter: ``plural = `${word}s` ``) and as object patterns. Each call is translated where it is written, its arguments evaluated once and in order, with the types they have there, so one function serves an integer and a `Float`. A function imported from a `.ts` file needs no `helpers` entry. Recursion, `...rest`, `async` and generators are refused. See the crate's [`script_logic`](https://docs.rs/ferrovue/latest/ferrovue/guide/script_logic/index.html#functions) guide |
|
|
227
|
+
| Loaders | A top-level `await` in `<script setup>` of a loader declared with `defineLoader`, whose arguments are strings, numbers and booleans and whose result is any type a prop may have: the compiler writes a `Loaders` trait the Rust app implements, and the render stops where Vue's would until the result is in, starting siblings' loaders together. The results travel in the page for the client to hydrate from, inside a `<Suspense>` `mountPage` adds. See the crate's [`loaders`](https://docs.rs/ferrovue/latest/ferrovue/guide/loaders/index.html) guide |
|
|
229
228
|
| Provide and inject | `provide` and `inject` resolved through the component tree, slot content seeing the providers of the component that renders it, as Vue does: keys that are string literals or `InjectionKey` symbols exported from `.ts` files; values that are props, refs, `computed`s, constants or objects of them (an interface's fields, `reactive()` unwrapping refs); defaults, factory defaults (`inject(k, () => …, true)`), object defaults built as the key's interface (`inject(k, { size: "md" })`), and keys holding functions, which only event handlers may call. A page rendered from Rust passes the generated `Provides`, empty or holding what the client app gives `app.provide`. See the crate's [`provide_inject`](https://docs.rs/ferrovue/latest/ferrovue/guide/provide_inject/index.html) guide |
|
|
230
|
-
| Text | `{{ }}` of strings, integers and booleans; `+`, `-`, `*`, `/`, `%`, with integers and fractions as JavaScript computes them; `<`, `>`, `<=`, `>=` (between numbers, or between strings by UTF-16 code unit), `===`, `!==`; unary `-`, `!`; `??`, `\|\|`, `&&`,
|
|
229
|
+
| Text | `{{ }}` of strings, integers and booleans; `+`, `-`, `*`, `/`, `%`, with integers and fractions as JavaScript computes them; `<`, `>`, `<=`, `>=` (between numbers, or between strings by UTF-16 code unit), `===`, `!==`; unary `-`, `!`; `??`, `\|\|`, `&&`, `?:` (whose branches may differ in type where the value is only written out: in `{{ }}`, a string-valued attribute and a template literal, each branch is written as JavaScript writes it, `{{ n > 0 ? n : "none" }}`); template literals and `String()` of strings, numbers, booleans, values that may be absent (`undefined` or `null`, as JavaScript writes them) and lists (their items joined by `,`); `typeof`; optional chaining `a?.b`, `a?.[i]` and chains that go on past it (`a?.b.c`, `s?.trim().length`, `list?.at(-1)?.name`), with every property and method the value has when present, `undefined` as a whole once `a` is absent; `.length`; `.toString()`, `.toFixed()`, `.toPrecision()` and `.toExponential()` (with no argument or a literal one), `Math.max`/`min` (of a spread list too, `Math.max(...xs)`)/`abs`/`round`/`floor`/`ceil`/`trunc`/`sqrt`/`sign`, the constants of `Math` and `Number`, `**` and `Math.pow()` of an integer and a whole exponent known when compiling, exact within ±2⁵³; `Number()`, `parseInt()` (no radix, 10 or 16), `parseFloat()`; `Number.isNaN()`, `Number.isFinite()`, `Number.isInteger()` and `Number.isSafeInteger()` of a number, present or optional, and `isNaN()` and `isFinite()` of a present number; `JSON.stringify()` of strings, numbers, booleans and lists of those; `encodeURIComponent()` and `encodeURI()`; array literals |
|
|
231
230
|
| Strings | `.trim()`, `.trimStart()`, `.trimEnd()`, `.trimLeft()`, `.trimRight()`, `.toUpperCase()`, `.toLowerCase()`, `.includes()`, `.startsWith()`, `.endsWith()`, `.indexOf()` and `.lastIndexOf()`, with a position or without, `.slice()`, `.substring()`, `.substr()`, `.at()`, `.charAt()`, `.charCodeAt()`, `.codePointAt()`, `.concat()`, `.split()` with a limit or without, `.replace()` and `.replaceAll()` with string patterns (`$&`, `` $` ``, `$'`, `$$` read as JavaScript reads them), `.padStart()`, `.padEnd()`, `.repeat()`; indices and lengths count UTF-16 code units, as JavaScript's do (see the crate's [`strings`](https://docs.rs/ferrovue/latest/ferrovue/guide/strings/index.html) guide) |
|
|
232
231
|
| Dates | `new Date(s)` and `Date.parse(s)` of an ISO string (a date alone, or a date and time with a `Z` or an offset, as ECMAScript's date time string format specifies), `new Date(ms)`, `Date.UTC(…)` of one to seven parts, `.toISOString()`, `.toUTCString()`, `.toJSON()`, `JSON.stringify()`, `.getTime()`, `.valueOf()` and the `.getUTC…()` methods, and `<`, `<=`, `>` and `>=` between two dates, invalid dates included, as JavaScript computes them, a date's validity tested with `Number.isNaN(d.getTime())`, and dates chosen with `?:`, `??` and `||` (a date is always truthy, an invalid one too), of a date built in the template or of a `Date` prop, which an island's `data-props` carries as its ISO string and the client turns back into a `Date` before hydrating, and which may be handed to a child's `Date` prop. Prices and formatted dates are written in Rust and passed as strings, or filled into a `$t` message. See the crate's [`dates_and_prices`](https://docs.rs/ferrovue/latest/ferrovue/guide/dates_and_prices/index.html) guide |
|
|
233
232
|
| Conditions | `v-if` / `v-else-if` / `v-else`, `?:`, `&&` and `||`, with optional and nullable values narrowed as TypeScript narrows them: `v-if="user"`, `user !== undefined`, `user !== null`, `user != null`, `typeof user !== "undefined"`, and `!user`, `user === undefined` or `user === null` for the `v-else` |
|
|
234
|
-
| Lists | `v-for` over arrays (of strings, numbers, objects or child props), array literals and number ranges (`n in 5`); with an index; with destructured items (`{ id, name } in rows`); nested; on `<template>`. `.includes()` (a number looked for in a list of numbers whether either is a `number` or a `Float`, as JavaScript compares them), `.join()`, and `.filter()`, `.map()`, `.some()`, `.every()`, `.find()`, `.findIndex()`, `.findLast()`, `.findLastIndex()` with an arrow function of the item (a name, or destructured) and its index, whose body is an expression, narrowing inside as outside, or with `Boolean`; `.filter(Boolean)` of a list or an array literal whose items may be `null` or `undefined`, which keeps the ones present and truthy as a list of the values (`[name, title, city].filter(Boolean).join(" · ")`); `Boolean(x)`; `.slice()`; an item by its index, `list[i]` with an integer `i` and `list.at(i)` (from the end when negative), `undefined` outside the list and narrowed as other optional values are (`v-if="rows[0]"`); `.indexOf()` and `.lastIndexOf()` of a string, number or boolean, compared with `===` (`NaN` found nowhere, `-0` found as `0`); `.concat()` of lists of one item type (numbers whether `number` or `Float`); `.reduce()` and `.reduceRight()` with an initial value, into a string, a number or a boolean; `.toReversed()`, and `.toSorted()` by `String(x)` as JavaScript sorts without a comparator (`[10, 9, 1]` to `[1, 10, 9]`) or by a comparator `(a, b) => a - b`, `a.k - b.k` of integers or `?:` over `<` and `>` of integers or strings, stable as JavaScript's; `[...list].sort(…)` and `[...list].reverse()`; spread in array literals (`[...a, x, ...b]`) of one item type; chained and nested; a computed list read by `v-for`, `.join()`, `.length`, `.includes()`, kept by `computed`, or handed to a child |
|
|
235
|
-
| Dictionaries | `v-for="(value, key, index) in r"` over a `Record<string, T>`, and `([key, value], index) in Object.entries(r)`, in JavaScript's order: keys that are array indices first, in numeric order, then the others as the props give them; `Object.keys(r)`, `Object.values(r)`, `Object.entries(r).
|
|
233
|
+
| Lists | `v-for` over arrays (of strings, numbers, objects or child props), array literals and number ranges (`n in 5`); with an index; with destructured items (`{ id, name } in rows`); nested; on `<template>`. `.includes()` (a number looked for in a list of numbers whether either is a `number` or a `Float`, as JavaScript compares them), `.join()`, and `.filter()`, `.map()`, `.some()`, `.every()`, `.find()`, `.findIndex()`, `.findLast()`, `.findLastIndex()` with an arrow function of the item (a name, or destructured) and its index, whose body is an expression or a body of statements (see Statements), narrowing inside as outside, or with `Boolean`; `.filter(Boolean)` of a list or an array literal whose items may be `null` or `undefined`, which keeps the ones present and truthy as a list of the values (`[name, title, city].filter(Boolean).join(" · ")`); `Boolean(x)`; `.slice()`; an item by its index, `list[i]` with an integer `i` and `list.at(i)` (from the end when negative), `undefined` outside the list and narrowed as other optional values are (`v-if="rows[0]"`); `.indexOf()` and `.lastIndexOf()` of a string, number or boolean, compared with `===` (`NaN` found nowhere, `-0` found as `0`); `.concat()` of lists of one item type (numbers whether `number` or `Float`); `.reduce()` and `.reduceRight()` with an initial value, into a string, a number or a boolean; `.toReversed()`, and `.toSorted()` by `String(x)` as JavaScript sorts without a comparator (`[10, 9, 1]` to `[1, 10, 9]`) or by a comparator `(a, b) => a - b`, `a.k - b.k` of integers or `?:` over `<` and `>` of integers or strings, stable as JavaScript's; `[...list].sort(…)` and `[...list].reverse()`; spread in array literals (`[...a, x, ...b]`) of one item type; `.flat()` of lists of lists, to a literal depth or `Infinity`, and `.flatMap()` with an arrow function that gives a list (flattened one level) or a value (kept as `.map()` keeps it); chained and nested; a computed list read by `v-for`, `.join()`, `.length`, `.includes()`, kept by `computed`, or handed to a child |
|
|
234
|
+
| Dictionaries | `v-for="(value, key, index) in r"` over a `Record<string, T>`, and `([key, value], index) in Object.entries(r)`, in JavaScript's order: keys that are array indices first, in numeric order, then the others as the props give them; `Object.keys(r)`, `Object.values(r)` (of a record of lists too, which `.flat()` joins), and `Object.entries(r)` read by the list methods, whose arrow functions destructure each pair (`([key, value]) => …`, `([, value]) => …`, `([key, { id }]) => …`) or read its parts (`pair[0]`, `pair[1]`), and walked by `v-for="[key, value] in Object.entries(r).filter(…)"`, kept by `computed` and sorted by a comparator of either part; handed to a child |
|
|
236
235
|
| Attributes | static and bound attributes, boolean attributes, `:hidden`, `data-*` and `aria-*`, `v-bind` objects |
|
|
237
236
|
| `class` | strings, arrays, objects (`{ active: on }`, computed keys), `cond && "x"`, `cond ? "x" : null`, merged with a static `class` |
|
|
238
237
|
| `style` | objects (camelCase or kebab-case keys, `--custom` properties), arrays of objects, strings, merged with a static `style`, and `v-show`; later values override earlier ones as in Vue. A global `<style>` block is allowed |
|
|
@@ -273,8 +272,9 @@ The crate's guide, `ferrovue::guide` on docs.rs, covers each topic in depth:
|
|
|
273
272
|
`<style scoped>` ids that match `@vitejs/plugin-vue`, `v-bind()` in `<style>`, CSS modules
|
|
274
273
|
- [Routing](https://docs.rs/ferrovue/latest/ferrovue/guide/routing/index.html),
|
|
275
274
|
[translating with vue-i18n](https://docs.rs/ferrovue/latest/ferrovue/guide/i18n/index.html),
|
|
276
|
-
[Pinia](https://docs.rs/ferrovue/latest/ferrovue/guide/pinia/index.html)
|
|
277
|
-
[provide and inject](https://docs.rs/ferrovue/latest/ferrovue/guide/provide_inject/index.html)
|
|
275
|
+
[Pinia](https://docs.rs/ferrovue/latest/ferrovue/guide/pinia/index.html),
|
|
276
|
+
[provide and inject](https://docs.rs/ferrovue/latest/ferrovue/guide/provide_inject/index.html) and
|
|
277
|
+
[loaders](https://docs.rs/ferrovue/latest/ferrovue/guide/loaders/index.html)
|
|
278
278
|
- [Teleports](https://docs.rs/ferrovue/latest/ferrovue/guide/teleports/index.html) and
|
|
279
279
|
[the page head](https://docs.rs/ferrovue/latest/ferrovue/guide/head/index.html) (`useHead`,
|
|
280
280
|
`useSeoMeta`)
|
|
@@ -294,7 +294,12 @@ The crate's guide, `ferrovue::guide` on docs.rs, covers each topic in depth:
|
|
|
294
294
|
- [Errors and limits](https://docs.rs/ferrovue/latest/ferrovue/guide/errors_and_limits/index.html),
|
|
295
295
|
with helpers, `<ClientOnly>` and Rust twins, and every
|
|
296
296
|
[error code](https://docs.rs/ferrovue/latest/ferrovue/guide/error_codes/index.html)
|
|
297
|
-
-
|
|
297
|
+
- [Porting an existing app](https://docs.rs/ferrovue/latest/ferrovue/guide/porting/index.html)
|
|
298
|
+
from a Node server that renders with Vue, and the
|
|
299
|
+
[support policy](https://docs.rs/ferrovue/latest/ferrovue/guide/support/index.html): supported
|
|
300
|
+
versions, fixes, deprecations and where to report a problem
|
|
301
|
+
- Upgrading a project [from 0.9 to 0.10](https://docs.rs/ferrovue/latest/ferrovue/guide/upgrading_to_0_10/index.html),
|
|
302
|
+
[from 0.8 to 0.9](https://docs.rs/ferrovue/latest/ferrovue/guide/upgrading_to_0_9/index.html)
|
|
298
303
|
and [from 0.7 to 0.8](https://docs.rs/ferrovue/latest/ferrovue/guide/upgrading_to_0_8/index.html)
|
|
299
304
|
|
|
300
305
|
[`examples/fullstack`](https://github.com/Kinsmir/ferrovue/blob/main/examples/fullstack/README.md)
|
|
@@ -354,10 +359,19 @@ the fixtures from it. A weekly CI job re-records them from the newest patch each
|
|
|
354
359
|
hydrates the committed HTML with it, so a patch that changes what Vue writes or hydrates is caught
|
|
355
360
|
before it reaches you; a ferrovue patch follows when one does.
|
|
356
361
|
|
|
362
|
+
### Upgrading
|
|
363
|
+
|
|
364
|
+
Until 1.0, versions are 0.MINOR.PATCH: raising MINOR (0.9.2 to 0.10.0) may change the
|
|
365
|
+
configuration, the generated code and the crates' API, and raising PATCH (0.10.0 to 0.10.1) breaks
|
|
366
|
+
none of them. The npm package and the crates share one version, so upgrade them together and
|
|
367
|
+
generate your components again. The
|
|
368
|
+
[CHANGELOG](https://github.com/Kinsmir/ferrovue/blob/main/CHANGELOG.md) lists what each release
|
|
369
|
+
changes, and the [guides](#guides) have an upgrade page for each MINOR release.
|
|
370
|
+
|
|
357
371
|
### Deprecations
|
|
358
372
|
|
|
359
|
-
What ferrovue stops supporting is deprecated for at least one minor release
|
|
360
|
-
major release. A deprecated crate item carries `#[deprecated]`; a deprecated configuration key warns
|
|
373
|
+
What ferrovue stops supporting is deprecated for at least one minor release before it is removed:
|
|
374
|
+
in a later minor release before 1.0, and only in a major release from 1.0. A deprecated crate item carries `#[deprecated]`; a deprecated configuration key warns
|
|
361
375
|
with `warning[FV1117]` and a command-line option with `warning[FV1118]`, naming the replacement, and the JSON Schema marks a deprecated key for editors.
|
|
362
376
|
Each release's CHANGELOG lists what it deprecates under "Deprecated".
|
|
363
377
|
|
package/dist/args.js
CHANGED
|
@@ -60,7 +60,7 @@ export function parseArgs(argv, flags = FLAGS, commands = COMMANDS) {
|
|
|
60
60
|
return { error: `option '${name}' takes no value` };
|
|
61
61
|
}
|
|
62
62
|
if (flag.deprecated) {
|
|
63
|
-
args.warnings.push(new GenError("FV1118", `'${name}' is deprecated since ${flag.deprecated.since}, and goes in
|
|
63
|
+
args.warnings.push(new GenError("FV1118", `'${name}' is deprecated since ${flag.deprecated.since}, and goes in a later minor release: use ${flag.deprecated.use}`));
|
|
64
64
|
}
|
|
65
65
|
args.options.set(longName(flag), value);
|
|
66
66
|
args.spelt.set(longName(flag), name);
|
package/dist/attrs.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ 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
7
|
export declare function keepsAttrCase(tag: string): boolean;
|
|
8
|
+
/** The value bound to the attribute \`key\`, shown as text unless the attribute is a boolean one. */
|
|
9
|
+
export declare function attrShown(s: Scope, key: string, n: N, tag?: string | null): Val;
|
|
8
10
|
export declare function renderDynamicAttr(s: Scope, e: Emitter, key: string, v: Val, n: N, tag?: string | null): void;
|
|
9
11
|
export declare const IGNORED_PROPS: Set<string>;
|
|
10
12
|
export declare function directiveProps(s: Scope, n: N): boolean;
|
package/dist/attrs.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { escapeHtml, hyphenate, isBooleanAttr, isSSRSafeAttrName, isSVGTag, propsToAttrMap } from "@vue/shared";
|
|
2
2
|
import { fail, nothing, GenError, rustStr } from "./model.js";
|
|
3
3
|
import { CONFIG_FILE, ctx } from "./context.js";
|
|
4
|
-
import { describeTy, expr } from "./expr.js";
|
|
4
|
+
import { describeTy, expr, shown } from "./expr.js";
|
|
5
5
|
import { known, truthy } from "./narrowing.js";
|
|
6
6
|
import { asCow, isTemporary, unquote } from "./strings.js";
|
|
7
7
|
import { atom, bare, condition, receiver, strArg } from "./parens.js";
|
|
@@ -78,8 +78,16 @@ export function renderAttr(s, e, key, v, n) {
|
|
|
78
78
|
export function keepsAttrCase(tag) {
|
|
79
79
|
return tag.indexOf("-") > 0 || isSVGTag(tag);
|
|
80
80
|
}
|
|
81
|
+
function attrName(key, tag) {
|
|
82
|
+
return tag !== null && keepsAttrCase(tag) ? key : (propsToAttrMap[key] ?? key.toLowerCase());
|
|
83
|
+
}
|
|
84
|
+
/** The value bound to the attribute \`key\`, shown as text unless the attribute is a boolean one. */
|
|
85
|
+
export function attrShown(s, key, n, tag = null) {
|
|
86
|
+
const name = attrName(key, tag);
|
|
87
|
+
return isBooleanAttr(name) || name === "hidden" ? expr(s, n) : shown(s, n, "attr");
|
|
88
|
+
}
|
|
81
89
|
export function renderDynamicAttr(s, e, key, v, n, tag = null) {
|
|
82
|
-
const name =
|
|
90
|
+
const name = attrName(key, tag);
|
|
83
91
|
if (!isSSRSafeAttrName(name))
|
|
84
92
|
fail(s.comp, "FV0404", `unsafe attribute name \`${name}\``, n);
|
|
85
93
|
renderable(s, key, v, n);
|
|
@@ -259,7 +267,7 @@ function objectAttrs(s, e, n, merged) {
|
|
|
259
267
|
e.lit(`"`);
|
|
260
268
|
}
|
|
261
269
|
else {
|
|
262
|
-
renderDynamicAttr(s, e, key,
|
|
270
|
+
renderDynamicAttr(s, e, key, attrShown(s, key, p.value), p);
|
|
263
271
|
}
|
|
264
272
|
}
|
|
265
273
|
}
|
|
@@ -318,7 +326,7 @@ export function attrOf(s, key, n, side) {
|
|
|
318
326
|
return styleAttr(s, n);
|
|
319
327
|
if (n.type === "NullLiteral")
|
|
320
328
|
return "fv::Attr::Undefined";
|
|
321
|
-
return valueAttr(s,
|
|
329
|
+
return valueAttr(s, attrShown(s, key, n), n);
|
|
322
330
|
}
|
|
323
331
|
export function valueAttr(s, v, n) {
|
|
324
332
|
switch (v.ty.k) {
|
package/dist/blocks.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type Component, type N, type Scope, type Val } from "./model.ts";
|
|
2
|
+
/** Runtime calls that panic where JavaScript throws, or user code that may. */
|
|
3
|
+
export declare const PANICS: RegExp;
|
|
4
|
+
export declare function panicky(code: string): boolean;
|
|
5
|
+
/** How a value is held in a Rust `let`: what the `let` is given, how the name reads back, and
|
|
6
|
+
* whether the `let` owns what a read borrows (a `String`, a `Cow`, a `Vec`). */
|
|
7
|
+
export declare function bindingOf(v: Val): {
|
|
8
|
+
init: string;
|
|
9
|
+
read: (at: string) => Val;
|
|
10
|
+
owned: boolean;
|
|
11
|
+
};
|
|
12
|
+
/** How many times a body's statements may be translated again after an `if` or a `case` that
|
|
13
|
+
* falls off its end: each such path continues with the statements after it, translated on its own,
|
|
14
|
+
* so sequential `switch`es of `break`ing cases multiply them. */
|
|
15
|
+
export declare const PATH_BUDGET = 4096;
|
|
16
|
+
/** The expression a function's body computes: the expression of an arrow function, or a block of
|
|
17
|
+
* statements in the subset ferrovue translates, written as one expression. */
|
|
18
|
+
export declare function bodyExpr(comp: Component, fn: N): N;
|
|
19
|
+
/** `p` (a name, or an object or array pattern of names) bound to `value` around `body`. */
|
|
20
|
+
export declare function destructured(comp: Component, p: N, value: N, body: N): N;
|
|
21
|
+
/** `fn` with an expression for its body, where it is an arrow or function expression with a block. */
|
|
22
|
+
export declare function expressionBodied(comp: Component, fn: N): N;
|
|
23
|
+
/** `const name = init` around `body`: the value `body` computes with `name` bound once, as a Rust
|
|
24
|
+
* `let` in a block that hands out nothing borrowed from it. */
|
|
25
|
+
export declare function letIn(s: Scope, n: N): Val;
|
|
26
|
+
/** `v` bound once to `name` for `body`, which is given the scope that reads it. */
|
|
27
|
+
export declare function bound(s: Scope, local: string, v: Val, then: (inner: Scope) => Val): Val;
|
|
28
|
+
/** Whether a desugared `if` whose test is `a && b` or `a || b` should be split, so that a side
|
|
29
|
+
* that narrows a value narrows what follows it, as TypeScript narrows it. */
|
|
30
|
+
export declare function splits(s: Scope, test: N): boolean;
|
|
31
|
+
/** `a && b ? x : y` as `a ? (b ? x : y) : y`, and `a || b ? x : y` as `a ? x : (b ? x : y)`. */
|
|
32
|
+
export declare function split(n: N): N;
|