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/README.md CHANGED
@@ -26,7 +26,7 @@ The project has two halves:
26
26
  | | What it is | Published as |
27
27
  |---|---|---|
28
28
  | `packages/ferrovue` | The compiler and the `ferrovue` command (TypeScript, runs on Node) | npm: [`ferrovue`](https://www.npmjs.com/package/ferrovue) |
29
- | `crates/ferrovue` | The runtime the generated Rust calls: escaping, slots, islands, `<RouterLink>` matching | crates.io: [`ferrovue`](https://crates.io/crates/ferrovue) ([API docs](https://docs.rs/ferrovue)) |
29
+ | `crates/ferrovue` | The runtime the generated Rust calls: escaping, slots, islands, `<RouterLink>` matching. The router, vue-i18n and the escaping and number primitives they share are crates of their own (`crates/ferrovue-router`, `ferrovue-i18n`, `ferrovue-core`), which `ferrovue` re-exports | crates.io: [`ferrovue`](https://crates.io/crates/ferrovue) ([API docs](https://docs.rs/ferrovue)) |
30
30
 
31
31
  ## Quick start
32
32
 
@@ -82,8 +82,11 @@ defineProps<{ name: string; unread: number; note?: string }>();
82
82
  ### 4. Generate and render
83
83
 
84
84
  ```sh
85
+ npx ferrovue init # a starter ferrovue.config.json and components/Hello.vue
85
86
  npx ferrovue # writes src/generated/{greeting.rs, mod.rs}
86
87
  npx ferrovue --check # in CI: exits 1 if the committed modules are stale
88
+ npx ferrovue --check --diff # …and shows what differs, as `diff -u` does
89
+ npx ferrovue --watch # regenerates when components or configs change
87
90
  ```
88
91
 
89
92
  ```rust
@@ -115,9 +118,28 @@ With `routes` configured, the generated `route_table::router()` builds the route
115
118
  each request's location with `router.at(path)` and pass the result to the components that take a
116
119
  route.
117
120
 
121
+ The router and vue-i18n are features of the crate, `router` and `i18n`, both on by default. An
122
+ application with neither routes nor translations can leave them out, and build neither
123
+ `ferrovue-router` nor `ferrovue-i18n`: `ferrovue = { version = "0.4", default-features = false }`.
124
+
118
125
  With the `maud` feature, `ferrovue::Html` implements `maud::Render`, so `(greeting::html(&props))` can go
119
126
  straight into a `maud::html!` page.
120
127
 
128
+ With the `axum` feature, `Html` is an `IntoResponse`, and with `actix-web` a `Responder`: a handler
129
+ responds with the component, as `text/html; charset=utf-8`. `into_html(props)` and
130
+ `into_island(props)` take the props by value, so a handler that builds them returns the page:
131
+
132
+ ```rust
133
+ async fn hello(Path(name): Path<String>) -> impl IntoResponse {
134
+ greeting::into_html(greeting::Props::new(name, 0))
135
+ }
136
+ ```
137
+
138
+ With the `dioxus` feature, a component goes into a Dioxus 0.7 page (`dioxus-ssr` or fullstack):
139
+ `{greeting::island(&props)}` in `rsx!` is the island element itself, with exactly the markup Vue
140
+ hydrates inside it. See `examples/dioxus` and the crate guide's
141
+ [Dioxus page](crates/ferrovue/docs/guide/dioxus.md).
142
+
121
143
  ## What a component may use
122
144
 
123
145
  ferrovue compiles `<script setup lang="ts">` components. Props are declared by type, with
@@ -138,11 +160,12 @@ ferrovue compiles `<script setup lang="ts">` components. Props are declared by t
138
160
  | `class` | strings, arrays, objects (`{ active: on }`, computed keys), `cond && "x"`, `cond ? "x" : null`, merged with a static `class` |
139
161
  | `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 |
140
162
  | Scoped styles | `<style scoped>`: the id on every element, on child components' roots (a root that is itself a component, fragments, recursion and `inheritAttrs: false` as Vue renders them) and, from a component with `:slotted()` rules, on the slot content it is given, forwarded slots included; inside `<Transition>`, `<KeepAlive>`, `<Teleport>` and `v-if`; on `<RouterLink>` and what it holds, as vue-router renders them |
141
- | Components | imported child components, `v-bind` of a child's own `Props`, `v-model` on a child's `defineModel`, recursion |
163
+ | Components | imported child components, `v-bind` of a child's own `Props`, `v-model` on a child's `defineModel`, recursion; props named in `kebab-case` or `camelCase` |
164
+ | Fallthrough attributes | what a parent passes a child beyond its props (static and bound attributes, `class`, `style`, `data-*`, `aria-*`, booleans, `undefined`): onto its single root, merged with the root's own class and style and replacing its other attributes where they stand, as Vue's `mergeProps` merges them; none for two roots; on through a root that is a component, or a `<RouterLink>`; with `inheritAttrs: false`, onto the elements or components that bind `v-bind="$attrs"` or a `useAttrs()` binding, before or after their own; beside scope ids. Listeners are dropped, as Vue's server drops them. See the crate's [`generated_code`](https://docs.rs/ferrovue/latest/ferrovue/guide/generated_code/index.html#fallthrough-attributes) guide |
142
165
  | Slots | default and named slots, fallbacks, `$slots.name` tests, scoped slots (`<slot :item="x">` and `#item="{ item }"` or `v-slot="props"`), whose props a parent can hand to its own children |
143
166
  | Forms | `v-model` on text inputs, checkboxes, radios, `<select>` and `<textarea>` (renders the initial state) |
144
167
  | Built-ins | `<Transition>`, `<TransitionGroup>`, `<KeepAlive>`, `<Suspense>` (synchronous content), `<Teleport>` (to any target, nested, disabled: see below), `v-text`, `v-once`, `v-pre`, `v-memo`, custom directives listed in `clientDirectives` |
145
- | Vue Router | `<RouterLink>` (resolved by name or imported) with a string `to` or `{ name, params, query, hash }` / `{ path, query, hash }`, `active-class`, `exact-active-class`, `aria-current-value`, `replace`; vue-router's own encoding and active-link matching, nested routes included (a parent link is active on its children's pages, exact only on its own); a history base. `useRoute()` and `$route`: `path`, `fullPath`, `hash`, `name`, `params`, and `query` (a value written once, without `=`, or repeated, exactly as vue-router parses it). `<RouterView>`, at the top and in nested route components: each takes the page it shows as a slot |
168
+ | Vue Router | `<RouterLink>` (resolved by name or imported) with a string `to` or `{ name, params, query, hash }` / `{ path, query, hash }`, `active-class`, `exact-active-class`, `aria-current-value`, `replace`; vue-router's own encoding and active-link matching, nested routes included (a parent link is active on its children's pages, exact only on its own); a history base. `useRoute()` and `$route`: `path`, `fullPath`, `hash`, `name`, `params`, and `query` (a value written once, without `=`, or repeated, exactly as vue-router parses it; `typeof route.query.q === "string"` narrows one to a single string). `<RouterView>`, at the top and in nested route components: each takes the page it shows as a slot |
146
169
  | Pinia | option stores with a typed `state`, and setup stores (`defineStore(id, () => { … })`) whose returned refs are typed by `ref<T>()` or their initial literal; read through `useX()` or `storeToRefs`, in the template or in `computed`; getters that are an expression of the state, and a setup store's computeds, which may read each other |
147
170
  | vue-i18n | `$t` and `useI18n()`'s `t` and `locale`: named and list values, plurals by vue-i18n's rule, literals, linked messages with `upper`/`lower`/`capitalize`, nested and flat keys, fallback locales, a missing key shown as itself. Messages are parsed at build time by vue-i18n's own compiler |
148
171
  | `v-html` | only on a `TrustedHtml` prop (`import type { TrustedHtml } from "ferrovue/types"`) |
@@ -171,7 +194,18 @@ Refused at compile time, each with an error that names the construct:
171
194
  - two strings that may each hold half of a surrogate pair compared, searched or joined (see
172
195
  [Strings](#strings))
173
196
  - `null`
197
+ - an attribute (`class` and `style` aside) bound to a value that may be neither a string, a number
198
+ nor a boolean: a list, an object, or a `route.query` value, which is an array when its key is
199
+ repeated. Vue's server renderer leaves the attribute out and hydration then sets it, silently;
200
+ join a list (`.join(",")`), or narrow a query value with `typeof route.query.q === "string"`
174
201
  - any method call without a Rust twin
202
+ - a value read from `$attrs` or `useAttrs()` (`$attrs.title`), which has no type; an attribute a
203
+ component is passed that would reach a prop of the component (or `<RouterLink>`) its root passes it
204
+ on to; `$attrs` in a component that is the root of one that may be handed scope ids, where it would
205
+ hold them; an attribute named by a number, or bound to a `$route.query` value; a class merged by
206
+ `v-bind` with a string that may equal the class before it, which Vue would write once; attributes
207
+ passed to a component whose root is a `<Transition>` or `<KeepAlive>` around a `v-if`, which Vue's
208
+ server drops but its client keeps
175
209
 
176
210
  An object prop handed to a child component is cloned. Its strings are `Cow`s, so borrowed ones
177
211
  cost nothing to copy.
@@ -203,7 +237,8 @@ same in development and production, and do not change, nor change the generated
203
237
  component's source does.
204
238
 
205
239
  A component a parent may hand ids to has a `render_scoped(…, attrs)` beside `render`, which
206
- generated parents call. A component whose outlets pass a slot scope id (`:slotted()`) takes slot
240
+ generated parents call (for one a parent also passes attributes to, `attrs` is an `fv::Attrs`
241
+ holding them and the ids). A component whose outlets pass a slot scope id (`:slotted()`) takes slot
207
242
  content that is given it: `Slot::slotted` for a slot, a third `&str` parameter for a scoped slot's
208
243
  closure. `render`, and content from Rust, need none of it: markup written from Rust carries no ids.
209
244
 
@@ -217,7 +252,7 @@ gives the ids that other component inherits.
217
252
  String methods count as JavaScript counts: in UTF-16 code units, so `"🦀".length` is 2 and
218
253
  `"🦀 crab".slice(3)` is `"crab"`. Strings are ordered by code unit too, which puts every character
219
254
  from U+E000 to U+FFFF after one beyond U+FFFF. Each runtime routine is held to vectors recorded from
220
- JavaScript (`crates/ferrovue/tests/vectors/`).
255
+ JavaScript (`crates/*/tests/vectors/`).
221
256
 
222
257
  A JavaScript string can hold half of a surrogate pair — `"🦀".slice(0, 1)`, `.charAt(1)`,
223
258
  `.split("")` — and a Rust string cannot. ferrovue writes U+FFFD in its place, which is exactly what
@@ -286,6 +321,37 @@ let row = |out: &mut String, p: &data_list::RowSlotProps<'_>| {
286
321
  data_list::render(&mut page, &props, data_list::Slots { row: Some(&row), ..Default::default() });
287
322
  ```
288
323
 
324
+ ### Hydrating islands
325
+
326
+ `mountIslands` from `ferrovue` hydrates every `data-island` element on the page with the
327
+ component of that name, from the props the server wrote. With the Vite plugin, `ferrovue/islands`
328
+ gives it every island there is, so nothing has to be listed by hand:
329
+
330
+ ```ts
331
+ import { hydrateState, mountIslands } from "ferrovue";
332
+ import islands from "ferrovue/islands"; // written by `ferrovue()` from `ferrovue/vite`
333
+
334
+ hydrateState(pinia);
335
+ await mountIslands(islands, { pinia, router }); // one Pinia and one router for every island
336
+ ```
337
+
338
+ The islands are exactly the components that have an `island()`: those that render from their props
339
+ alone, as the compiler finds while it generates them. That is the only set the server can write
340
+ `data-island` for, so it needs no folder convention or list to keep in step, and making a component
341
+ an island is a matter of the server calling its `island()`. Each is keyed by its `NAME`, the file
342
+ name without `.vue`, which is what `data-island` carries.
343
+
344
+ Each entry is a lazy `import()`, so the bundler gives every island a chunk of its own and a page
345
+ fetches the code of the islands it holds and no more. `mountIslands` takes such loaders and
346
+ components alike, so a hand-written island can join them: `mountIslands({ ...islands, Chart })`.
347
+ An island whose name is not among them is left as the server rendered it, with a warning naming it
348
+ (`onError` to handle it otherwise), as is one whose component fails to load.
349
+
350
+ An island's `<style>` goes into its chunk too, and Vite links it only once the island's script has
351
+ loaded, after the server's markup is on screen. Link those stylesheets from the page up front: a
352
+ server reading Vite's manifest takes the `css` of the entry's `dynamicImports` as well as its own
353
+ (`examples/fullstack/src/assets.rs`).
354
+
289
355
  ### Hydrating Pinia state
290
356
 
291
357
  ```rust
@@ -293,7 +359,7 @@ ferrovue::state_script_into(&mut page, "__pinia", &stores); // a <script type=
293
359
  ```
294
360
 
295
361
  ```ts
296
- import { hydrateState } from "ferrovue/client";
362
+ import { hydrateState } from "ferrovue";
297
363
  hydrateState(pinia); // before app.mount(): every store starts from what the server rendered
298
364
  ```
299
365
 
@@ -301,7 +367,12 @@ hydrateState(pinia); // before app.mount(): every store starts from what the ser
301
367
 
302
368
  `ferrovue::hole()` is a slot whose content you write later. Render a layout with holes,
303
369
  `split_holes` the output, and stream the pieces with each hole's content between them, in whatever
304
- order the content is ready.
370
+ order the content is ready. With the `axum` or `actix-web` feature, `ferrovue::HtmlStream` is that
371
+ streamed response, from the render and a future for each hole's content:
372
+
373
+ ```rust
374
+ let body = ferrovue::HtmlStream::new(page).hole(async move { reviews_of(&id).await });
375
+ ```
305
376
 
306
377
  ## Performance
307
378
 
@@ -361,21 +432,37 @@ ferrovue version.
361
432
  ## Repository layout
362
433
 
363
434
  ```text
364
- crates/ferrovue/ the Rust runtime crate
365
- src/ runtime (escaping, JS numbers, router, i18n, teleports) + unit tests
435
+ crates/ferrovue/ the Rust runtime crate, which generated code calls
436
+ src/ a module per part (`Html`, slots, class and style, the state script,
437
+ strings, teleports, fallthrough attributes), each module's unit tests
438
+ beside it in <module>/tests.rs; lib.rs re-exports them all, and the
439
+ three crates below
366
440
  tests/conformance/ components, fixtures, recorded HTML, generated Rust
367
- tests/vectors/ vectors recorded from JavaScript, vue-router and vue-i18n
441
+ tests/vectors/ vectors recorded from JavaScript and Vue
368
442
  tests/properties.rs property-based tests of the runtime
369
443
  benches/ criterion benchmarks of generated renderers (see Performance)
444
+ crates/ferrovue-core/ escaping and JavaScript's numbers, which the other crates share
445
+ tests/vectors/ vectors recorded from escapeHtml, String(n), Math and toFixed
446
+ crates/ferrovue-router/ vue-router's matching and links (the `router` feature)
447
+ tests/vectors/ vectors recorded from vue-router
448
+ crates/ferrovue-i18n/ vue-i18n's t() (the `i18n` feature)
370
449
  packages/ferrovue/ the compiler (npm package)
371
- src/compiler.ts the API: `generate`, `write`
372
- src/script.ts, template.ts, expr.ts, attrs.ts
373
- <script setup>, the compiled template, expressions, class/style
374
- src/router.ts, stores.ts, i18n.ts
375
- vue-router, Pinia and vue-i18n
450
+ src/index.ts `ferrovue`: the browser API, `mountIslands`, `hydrateState` and the types
451
+ src/compiler.ts `ferrovue/compiler`: `generate`, `write`
452
+ src/component.ts, script.ts, typescript.ts
453
+ a `.vue` file read, <script setup>, TypeScript types
454
+ src/template.ts, children.ts, slots.ts, loops.ts
455
+ the compiled template: statements, child components, slots, v-for
456
+ src/expr.ts, strings.ts, numbers.ts, narrowing.ts, calls.ts, lists.ts
457
+ expressions: operators, strings, numbers, narrowing, calls, lists
458
+ src/attrs.ts, classes.ts, styles.ts, fallthrough.ts
459
+ attributes, class and style, attributes a parent passes on
460
+ src/plugin.ts the plugin interface (see CONTRIBUTING.md)
461
+ src/plugins/ vue-router, Pinia, vue-i18n, scoped styles, <Teleport>, shared types
376
462
  src/rust.ts, emitter.ts the Rust source written out
377
463
  src/cli.ts, vite.ts the `ferrovue` command and the Vite plugin
378
464
  src/client.ts browser-side helpers: `mountIslands`, `hydrateState`
465
+ src/islands.ts `ferrovue/islands`, which the Vite plugin writes: every island, loaded lazily
379
466
  src/testing.ts utilities for a project's own conformance suite
380
467
  src/types.ts `ferrovue/types`: `TrustedHtml`, `Float`
381
468
  test/ compiler, CLI, router, vector, island, Vite and conformance tests
@@ -384,6 +471,7 @@ packages/ferrovue/ the compiler (npm package)
384
471
  fuzz/ the randomised differential tester (`pnpm fuzz`)
385
472
  examples/greeting/ the smallest setup: one component rendered from Rust
386
473
  examples/fullstack/ axum + Vite: islands, Pinia state, routes and streaming
474
+ examples/dioxus/ a Dioxus page, rendered with dioxus-ssr, with an island in it
387
475
  scripts/release.ts the release version bump (see RELEASING.md)
388
476
  ```
389
477
 
package/dist/attrs.d.ts CHANGED
@@ -1,51 +1,17 @@
1
1
  import { type N, type Scope, type Val } from "./model.ts";
2
2
  import { Emitter } from "./emitter.ts";
3
- /** `toDisplayString`, escaped. */
3
+ export declare function display(e: Emitter, v: Val): boolean;
4
4
  export declare function interpolate(e: Emitter, v: Val): void;
5
- /** The value half of `key="value"`, escaped. */
6
5
  export declare function attrValue(e: Emitter, v: Val): void;
7
- /** `ssrRenderAttr(key, value)`: absent for null/undefined, `key="value"` for anything else. */
8
- export declare function renderAttr(e: Emitter, key: string, v: Val): void;
9
- /** `ssrRenderDynamicAttr(key, value)`: as `renderAttr`, but a boolean attribute is present or
10
- * absent, and an empty string renders the name alone. */
6
+ export declare function renderAttr(s: Scope, e: Emitter, key: string, v: Val, n: N): void;
11
7
  export declare function renderDynamicAttr(s: Scope, e: Emitter, key: string, v: Val, n: N): void;
12
- /** One item of a class list once it is flattened: literal text, known now, or a Rust `&str`
13
- * expression evaluated at run time — empty when the item contributes nothing. */
14
- export type ClassItem = {
15
- lit: string;
16
- } | {
17
- code: string;
18
- };
19
- /** `normalizeClass`'s view of a class binding, flattened: a string, an array of items, an object
20
- * of `name: condition`, `cond && "name"`, `cond ? "a" : null`. Every item is trimmed and the empty
21
- * ones dropped before they are joined with one space, which is what `class_into` does too, so an
22
- * object's keys become items of their own. */
23
- export declare function classItems(s: Scope, n: N): ClassItem[];
24
- /** `ssrRenderClass(value)`: normalised, then escaped. `after` says a class was already written. */
25
- export declare function renderClass(s: Scope, e: Emitter, n: N, after?: boolean): void;
26
8
  export declare const IGNORED_PROPS: Set<string>;
27
- /** `ssrGetDirectiveProps(_ctx, dir)`: a custom directive's server props, which are none for a
28
- * directive the configuration declares client-only. `false` when `n` is not such a call. */
29
9
  export declare function directiveProps(s: Scope, n: N): boolean;
30
- /** `ssrRenderAttrs(obj)`, key by key in the object's order, and the inherited scope ids where the
31
- * root's `_attrs` is merged in. */
10
+ export declare function isAttrs(n: N): boolean;
11
+ export declare function dollarAttrs(s: Scope, n: N): boolean;
12
+ export declare function mergedParts(n: N): N[];
32
13
  export declare function renderAttrs(s: Scope, e: Emitter, n: N): void;
33
- /** `mergeProps(a, _attrs, b, …)` as one object literal, without `_attrs`: it holds only scope ids,
34
- * which the caller writes after the rest. Of the rest, `class` and `style` values are merged as an
35
- * array, and any other key keeps the place it first had with the last value given. */
36
14
  export declare function mergeProps(s: Scope, n: N): N;
37
- /** One object of a style binding, and the run-time condition under which it is part of it. */
38
- export interface StyleItem {
39
- cond: string | null;
40
- entries: {
41
- key: string;
42
- css: string;
43
- value: N;
44
- }[];
45
- }
46
- /** The objects a style binding merges, in order: an object literal, a static `style` the compiler
47
- * parsed, `v-show`'s `cond ? null : { display: "none" }`, and arrays of those. */
48
- export declare function styleItems(s: Scope, n: N, when: string | null): StyleItem[];
49
- /** `ssrRenderStyle(value)`: a string as it is, or the objects merged — each property where it first
50
- * appears, with the last value given — and written `name:value;`, all escaped. */
51
- export declare function renderStyle(s: Scope, e: Emitter, n: N): void;
15
+ export declare function attrEntries(s: Scope, obj: N, side: "vnode" | "own"): string[];
16
+ export declare function attrOf(s: Scope, key: string, n: N, side: "vnode" | "own"): string;
17
+ export declare function valueAttr(s: Scope, v: Val, n: N): string;