ripple 0.2.183 → 0.2.185

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.
@@ -13,6 +13,9 @@
13
13
  import type * as acorn from 'acorn';
14
14
  import type * as AST from 'estree';
15
15
  import type * as ESTreeJSX from 'estree-jsx';
16
+ import type * as ESRap from 'esrap';
17
+ import type * as SourceMap from '@jridgewell/sourcemap-codec';
18
+ import type * as RippleCompiler from '#compiler';
16
19
 
17
20
  type ForInit = boolean | 'await';
18
21
 
@@ -33,7 +36,34 @@ declare module 'acorn' {
33
36
  }
34
37
  }
35
38
 
39
+ declare module 'esrap' {
40
+ export function print<V extends RippleCompiler.Visitors<AST.Node, any>>(
41
+ ast: AST.Node,
42
+ visitors: V,
43
+ options?: ESRap.PrintOptions,
44
+ ): { code: string; map: SourceMap.SourceMapMappings };
45
+ }
46
+
47
+ declare module 'esrap/languages/tsx' {
48
+ export default function tsx<V extends RippleCompiler.Visitors<AST.Node, any>>(
49
+ options: Parse.ESRapTSOptions,
50
+ ): V;
51
+ }
52
+
53
+ declare module 'zimmerframe' {
54
+ export function walk(
55
+ node: AST.Node,
56
+ state: any,
57
+ visitors: RippleCompiler.Visitors<AST.Node, any>,
58
+ ): AST.Node;
59
+ }
60
+
36
61
  export namespace Parse {
62
+ export interface ESRapTSOptions {
63
+ quotes?: 'double' | 'single';
64
+ comments?: AST.Comment[];
65
+ }
66
+
37
67
  /**
38
68
  * Destructuring errors object used during expression parsing
39
69
  * See: https://github.com/acornjs/acorn/blob/main/acorn/src/parseutil.js
@@ -65,6 +95,85 @@ export namespace Parse {
65
95
  BIND_OUTSIDE: 5;
66
96
  }
67
97
 
98
+ /**
99
+ * Branch ID for tracking disjunction structure in regular expressions
100
+ * Used to determine whether a duplicate capture group name is allowed
101
+ * because it is in a separate branch.
102
+ */
103
+ export interface BranchID {
104
+ /** Parent disjunction branch */
105
+ parent: BranchID | null;
106
+ /** Identifies this set of sibling branches */
107
+ base: BranchID;
108
+ /** Check if this branch is separated from another branch */
109
+ separatedFrom(alt: BranchID): boolean;
110
+ /** Create a sibling branch */
111
+ sibling(): BranchID;
112
+ }
113
+
114
+ /**
115
+ * Regular expression validation state
116
+ * Used by the parser to validate regular expression literals
117
+ * See: https://github.com/acornjs/acorn/blob/main/acorn/src/regexp.js
118
+ */
119
+ export interface RegExpValidationState {
120
+ /** Reference to the parser instance */
121
+ parser: Parser;
122
+ /** Valid flags for the current ECMAScript version */
123
+ validFlags: string;
124
+ /** Unicode properties data for the current ECMAScript version */
125
+ unicodeProperties: any;
126
+ /** Source pattern string of the regular expression */
127
+ source: string;
128
+ /** Flags string of the regular expression */
129
+ flags: string;
130
+ /** Start position of the regular expression in the source */
131
+ start: number;
132
+ /** Whether unicode flag (u) is enabled */
133
+ switchU: boolean;
134
+ /** Whether unicode sets flag (v) is enabled (ES2024+) */
135
+ switchV: boolean;
136
+ /** Whether named capture groups are enabled */
137
+ switchN: boolean;
138
+ /** Current position in the pattern */
139
+ pos: number;
140
+ /** Last integer value parsed */
141
+ lastIntValue: number;
142
+ /** Last string value parsed */
143
+ lastStringValue: string;
144
+ /** Whether the last assertion can be quantified */
145
+ lastAssertionIsQuantifiable: boolean;
146
+ /** Number of capturing parentheses */
147
+ numCapturingParens: number;
148
+ /** Maximum back reference number */
149
+ maxBackReference: number;
150
+ /** Map of group names to their information */
151
+ groupNames: Record<string, BranchID[]>;
152
+ /** Array of back reference names */
153
+ backReferenceNames: string[];
154
+ /** Current branch ID for tracking disjunction structure */
155
+ branchID: BranchID | null;
156
+
157
+ /** Reset state for a new pattern */
158
+ reset(start: number, pattern: string, flags: string): void;
159
+ /** Raise a validation error */
160
+ raise(message: string): void;
161
+ /** Get code point at position i (handles surrogate pairs if unicode mode) */
162
+ at(i: number, forceU?: boolean): number;
163
+ /** Get next index after position i (handles surrogate pairs if unicode mode) */
164
+ nextIndex(i: number, forceU?: boolean): number;
165
+ /** Get code point at current position */
166
+ current(forceU?: boolean): number;
167
+ /** Get code point at next position */
168
+ lookahead(forceU?: boolean): number;
169
+ /** Advance position to next character */
170
+ advance(forceU?: boolean): void;
171
+ /** Try to eat a specific character */
172
+ eat(ch: number, forceU?: boolean): boolean;
173
+ /** Try to eat a sequence of characters */
174
+ eatChars(chs: number[], forceU?: boolean): boolean;
175
+ }
176
+
68
177
  export interface Options extends Omit<acorn.Options, 'onComment' | 'ecmaVersion'> {
69
178
  rippleOptions: {
70
179
  loose: boolean;
@@ -297,6 +406,15 @@ export namespace Parse {
297
406
  tokContexts: AcornTypeScriptTokContexts;
298
407
  }
299
408
 
409
+ interface Scope {
410
+ flags: number;
411
+ var: string[];
412
+ lexical: string[];
413
+ functions: string[];
414
+ }
415
+
416
+ type Exports = Record<string, boolean>;
417
+
300
418
  /**
301
419
  * Extended Parser instance with internal properties
302
420
  *
@@ -360,7 +478,7 @@ export namespace Parse {
360
478
  /** Current scope flags stack */
361
479
  scopeStack: Array<{ flags: number; var: string[]; lexical: string[]; functions: string[] }>;
362
480
  /** Regular expression validation state */
363
- regexpState?: any;
481
+ regexpState: RegExpValidationState | null;
364
482
  /** Whether we can use await keyword */
365
483
  canAwait: boolean;
366
484
  /** Position of await keyword (0 if not in async context) */
@@ -376,7 +494,7 @@ export namespace Parse {
376
494
  /** Potential arrow in for-await position */
377
495
  potentialArrowInForAwait: boolean;
378
496
  /** Private name stack for class private fields validation */
379
- privateNameStack: Array<{ declared: Record<string, any>; used: Array<AST.Node> }>;
497
+ privateNameStack: Array<{ declared: Record<string, string>; used: Array<AST.Node> }>;
380
498
  /** Undefined exports for module validation */
381
499
  undefinedExports: Record<string, AST.Node>;
382
500
 
@@ -646,16 +764,16 @@ export namespace Parse {
646
764
  declareName(name: string, bindingType: BindingType[keyof BindingType], pos: number): void;
647
765
 
648
766
  /** Get current scope */
649
- currentScope(): { flags: number; var: string[]; lexical: string[]; functions: string[] };
767
+ currentScope(): Scope;
650
768
 
651
769
  /** Get current variable scope (for var declarations) */
652
- currentVarScope(): { flags: number; var: string[]; lexical: string[]; functions: string[] };
770
+ currentVarScope(): Scope;
653
771
 
654
772
  /** Get current "this" scope */
655
- currentThisScope(): { flags: number; var: string[]; lexical: string[]; functions: string[] };
773
+ currentThisScope(): Scope;
656
774
 
657
775
  /** Check if treating functions as var in current scope */
658
- treatFunctionsAsVarInScope(scope: any): boolean;
776
+ treatFunctionsAsVarInScope(scope: Scope): boolean;
659
777
 
660
778
  // ============================================================
661
779
  // Context Management
@@ -1262,7 +1380,7 @@ export namespace Parse {
1262
1380
  parseClassSuper(node: AST.Node): void;
1263
1381
 
1264
1382
  /** Enter class body scope */
1265
- enterClassBody(): Record<string, any>;
1383
+ enterClassBody(): Record<string, string>;
1266
1384
 
1267
1385
  /** Exit class body scope */
1268
1386
  exitClassBody(): void;
@@ -1325,11 +1443,11 @@ export namespace Parse {
1325
1443
  /** Parse export declaration */
1326
1444
  parseExport(
1327
1445
  node: AST.Node,
1328
- exports?: any,
1446
+ exports?: Exports,
1329
1447
  ): AST.ExportNamedDeclaration | AST.ExportDefaultDeclaration | AST.ExportAllDeclaration;
1330
1448
 
1331
1449
  /** Parse export specifiers */
1332
- parseExportSpecifiers(exports?: any): AST.ExportSpecifier[];
1450
+ parseExportSpecifiers(exports?: Exports): AST.ExportSpecifier[];
1333
1451
 
1334
1452
  /** Parse export default declaration */
1335
1453
  parseExportDefaultDeclaration(): AST.Declaration | AST.Expression | AST.Component;
@@ -2,10 +2,12 @@
2
2
 
3
3
  import { DERIVED, TRACKED, UNINITIALIZED } from './internal/client/constants.js';
4
4
  import { is_tracked_object } from './internal/client/utils.js';
5
- import { active_component } from './internal/server/index.js';
5
+ import { active_component, get, set, untrack } from './internal/server/index.js';
6
6
 
7
7
  export { Context } from './internal/server/context.js';
8
8
 
9
+ export { get, set, untrack };
10
+
9
11
  export function effect() {
10
12
  // NO-OP
11
13
  }
@@ -13,31 +15,6 @@ export function effect() {
13
15
  var empty_get_set = { get: undefined, set: undefined };
14
16
 
15
17
  /**
16
- * @param {Derived | Tracked} tracked
17
- * @returns {any}
18
- */
19
- export function get(tracked) {
20
- if (!is_tracked_object(tracked)) {
21
- return tracked;
22
- }
23
-
24
- var g = tracked.a.get;
25
-
26
- return g ? g(tracked.v) : tracked.v;
27
- }
28
-
29
- /**
30
- * @param {Tracked} tracked
31
- * @param {any} value
32
- */
33
- export function set(tracked, value) {
34
- var s = tracked.a.set;
35
-
36
- tracked.v = s ? s(value, tracked.v) : value;
37
- }
38
-
39
- /**
40
- *
41
18
  * @param {any} v
42
19
  * @param {Function} [get]
43
20
  * @param {Function} [set]
@@ -53,7 +30,9 @@ export function track(v, get, set) {
53
30
  if (typeof v === 'function') {
54
31
  return {
55
32
  a: get || set ? { get, set } : empty_get_set,
33
+ c: 0,
56
34
  co: active_component,
35
+ d: null,
57
36
  f: TRACKED | DERIVED,
58
37
  fn: v,
59
38
  v: UNINITIALIZED,
@@ -62,6 +41,8 @@ export function track(v, get, set) {
62
41
 
63
42
  return {
64
43
  a: get || set ? { get, set } : empty_get_set,
44
+ c: 0,
45
+ d: null,
65
46
  f: TRACKED,
66
47
  v,
67
48
  };
@@ -91,5 +72,7 @@ export function MediaQuery(query, matches = false) {
91
72
  * @param {any} _
92
73
  */
93
74
  export function createSubscriber(_) {
94
- return () => { /* NO-OP */ };
75
+ return () => {
76
+ /* NO-OP */
77
+ };
95
78
  }
@@ -48,7 +48,7 @@ export function first_child(node) {
48
48
  export function child_frag(node) {
49
49
  var child = /** @type {Text} */ (first_child(node));
50
50
 
51
- if (child.nodeType === 8 && child.data === '') {
51
+ if (child.nodeType === Node.COMMENT_NODE && child.data === '') {
52
52
  return next_sibling(child);
53
53
  }
54
54
  return child;
@@ -429,7 +429,7 @@ export function track_split(v, l, b) {
429
429
  }
430
430
 
431
431
  /**
432
- * @param {Tracked} tracked
432
+ * @param {Tracked | Derived} tracked
433
433
  * @returns {Dependency}
434
434
  */
435
435
  function create_dependency(tracked) {
@@ -512,10 +512,10 @@ export function async_computed(fn, block) {
512
512
 
513
513
  var restore = capture();
514
514
  /** @type {(() => void) | undefined} */
515
- var unuspend;
515
+ var unsuspend;
516
516
 
517
517
  if (deferred === null) {
518
- unuspend = suspend();
518
+ unsuspend = suspend();
519
519
  } else {
520
520
  for (var i = 0; i < deferred.length; i++) {
521
521
  var tracked = deferred[i];
@@ -538,7 +538,7 @@ export function async_computed(fn, block) {
538
538
  }
539
539
 
540
540
  if (deferred === null) {
541
- unuspend?.();
541
+ unsuspend?.();
542
542
  } else if (promise === current) {
543
543
  for (var i = 0; i < deferred.length; i++) {
544
544
  var tracked = deferred[i];
@@ -586,16 +586,16 @@ function capture_deferred(fn) {
586
586
  var value = fn();
587
587
  /** @type {Tracked[] | null} */
588
588
  var deferred = null;
589
- var depedency = active_dependency;
589
+ var dependency = active_dependency;
590
590
 
591
- while (depedency !== null) {
592
- var tracked = depedency.t;
591
+ while (dependency !== null) {
592
+ var tracked = dependency.t;
593
593
  if ((tracked.f & DEFERRED) !== 0) {
594
594
  deferred ??= [];
595
595
  deferred.push(tracked);
596
596
  break;
597
597
  }
598
- depedency = depedency.n;
598
+ dependency = dependency.n;
599
599
  }
600
600
 
601
601
  return [value, deferred];
@@ -19,7 +19,7 @@ export type Dependency = {
19
19
 
20
20
  export type Tracked<V = any> = {
21
21
  DO_NOT_ACCESS_THIS_OBJECT_DIRECTLY?: true;
22
- a: { get?: Function, set?: Function };
22
+ a: { get?: Function; set?: Function };
23
23
  b: Block;
24
24
  c: number;
25
25
  f: number;
@@ -28,12 +28,12 @@ export type Tracked<V = any> = {
28
28
 
29
29
  export type Derived = {
30
30
  DO_NOT_ACCESS_THIS_OBJECT_DIRECTLY?: true;
31
- a: { get?: Function, set?: Function };
31
+ a: { get?: Function; set?: Function };
32
32
  b: Block;
33
33
  blocks: null | Block[];
34
34
  c: number;
35
35
  co: null | Component;
36
- d: null;
36
+ d: null | Dependency;
37
37
  f: number;
38
38
  fn: Function;
39
39
  __v: any;
@@ -58,8 +58,8 @@ export type CompatApi = {
58
58
  createRoot: () => void;
59
59
  createComponent: (node: any, children_fn: () => any) => void;
60
60
  jsx: (type: any, props: any) => any;
61
- }
61
+ };
62
62
 
63
63
  export type CompatOptions = {
64
64
  [key: string]: CompatApi;
65
- }
65
+ };
@@ -1,18 +1,160 @@
1
+ /**
2
+ @import { Component, Dependency, Derived, Tracked } from '#server';
3
+ @import { render, renderToStream, SSRComponent } from 'ripple/server';
4
+ */
5
+
1
6
  import { Readable } from 'stream';
2
- /** @import { Component, Derived } from '#server' */
3
- /** @import { render, renderToStream, SSRComponent } from 'ripple/server'*/
4
7
  import { DERIVED, UNINITIALIZED } from '../client/constants.js';
5
8
  import { is_tracked_object } from '../client/utils.js';
6
9
  import { escape } from '../../../utils/escaping.js';
7
10
  import { is_boolean_attribute } from '../../../compiler/utils.js';
8
11
  import { clsx } from 'clsx';
12
+ import { normalize_css_property_name } from '../../../utils/normalize_css_property_name.js';
9
13
 
10
14
  export { escape };
11
15
  export { register_component_css as register_css } from './css-registry.js';
12
16
 
13
- /** @type {Component | null} */
17
+ /** @type {null | Component} */
14
18
  export let active_component = null;
15
19
 
20
+ /** @type {number} */
21
+ let clock = 0;
22
+
23
+ /** @type {null | Dependency} */
24
+ let active_dependency = null;
25
+
26
+ export let tracking = false;
27
+
28
+ /**
29
+ * @returns {number}
30
+ */
31
+ function increment_clock() {
32
+ return ++clock;
33
+ }
34
+
35
+ /**
36
+ * @param {Tracked | Derived} tracked
37
+ * @returns {Dependency}
38
+ */
39
+ function create_dependency(tracked) {
40
+ return {
41
+ c: tracked.c,
42
+ t: tracked,
43
+ n: null,
44
+ };
45
+ }
46
+
47
+ /**
48
+ * @param {Tracked | Derived} tracked
49
+ */
50
+ function register_dependency(tracked) {
51
+ var dependency = active_dependency;
52
+
53
+ if (dependency === null) {
54
+ dependency = create_dependency(tracked);
55
+ active_dependency = dependency;
56
+ } else {
57
+ var current = dependency;
58
+
59
+ while (current !== null) {
60
+ if (current.t === tracked) {
61
+ current.c = tracked.c;
62
+ return;
63
+ }
64
+ var next = current.n;
65
+ if (next === null) {
66
+ break;
67
+ }
68
+ current = next;
69
+ }
70
+
71
+ dependency = create_dependency(tracked);
72
+ current.n = dependency;
73
+ }
74
+ }
75
+
76
+ /**
77
+ * @param {Dependency | null} tracking
78
+ */
79
+ function is_tracking_dirty(tracking) {
80
+ if (tracking === null) {
81
+ return false;
82
+ }
83
+ while (tracking !== null) {
84
+ var tracked = tracking.t;
85
+
86
+ if ((tracked.f & DERIVED) !== 0) {
87
+ update_derived(/** @type {Derived} **/ (tracked));
88
+ }
89
+
90
+ if (tracked.c > tracking.c) {
91
+ return true;
92
+ }
93
+ tracking = tracking.n;
94
+ }
95
+
96
+ return false;
97
+ }
98
+
99
+ /**
100
+ * @template T
101
+ * @param {() => T} fn
102
+ * @returns {T}
103
+ */
104
+ export function untrack(fn) {
105
+ var previous_tracking = tracking;
106
+ var previous_dependency = active_dependency;
107
+ tracking = false;
108
+ active_dependency = null;
109
+ try {
110
+ return fn();
111
+ } finally {
112
+ tracking = previous_tracking;
113
+ active_dependency = previous_dependency;
114
+ }
115
+ }
116
+
117
+ /**
118
+ * @param {Derived} computed
119
+ */
120
+ function update_derived(computed) {
121
+ var value = computed.v;
122
+
123
+ if (value === UNINITIALIZED || is_tracking_dirty(computed.d)) {
124
+ value = run_derived(computed);
125
+
126
+ if (value !== computed.v) {
127
+ computed.v = value;
128
+ computed.c = increment_clock();
129
+ }
130
+ }
131
+ }
132
+
133
+ /**
134
+ * @param {Derived} computed
135
+ */
136
+ function run_derived(computed) {
137
+ var previous_tracking = tracking;
138
+ var previous_dependency = active_dependency;
139
+ var previous_component = active_component;
140
+
141
+ try {
142
+ active_component = computed.co;
143
+ tracking = true;
144
+ active_dependency = null;
145
+
146
+ var value = computed.fn();
147
+
148
+ computed.d = active_dependency;
149
+
150
+ return value;
151
+ } finally {
152
+ tracking = previous_tracking;
153
+ active_dependency = previous_dependency;
154
+ active_component = previous_component;
155
+ }
156
+ }
157
+
16
158
  /**
17
159
  * `<div translate={false}>` should be rendered as `<div translate="no">` and _not_
18
160
  * `<div translate="false">`, which is equivalent to `<div translate="yes">`. There
@@ -141,7 +283,7 @@ export function push_component() {
141
283
  */
142
284
  export function pop_component() {
143
285
  var component = /** @type {Component} */ (active_component);
144
- active_component = component;
286
+ active_component = component.p;
145
287
  }
146
288
 
147
289
  /**
@@ -161,30 +303,119 @@ export function aborted() {
161
303
  }
162
304
 
163
305
  /**
164
- * @param {Derived} tracked
306
+ * @param {any} tracked
165
307
  * @returns {any}
166
308
  */
167
- function get_derived(tracked) {
168
- let v = tracked.v;
309
+ export function get(tracked) {
310
+ if (!is_tracked_object(tracked)) {
311
+ return tracked;
312
+ }
313
+
314
+ if ((tracked.f & DERIVED) !== 0) {
315
+ update_derived(/** @type {Derived} **/ (tracked));
316
+ if (tracking) {
317
+ register_dependency(tracked);
318
+ }
319
+ } else if (tracking) {
320
+ register_dependency(tracked);
321
+ }
322
+
323
+ var g = tracked.a.get;
324
+ return g ? g(tracked.v) : tracked.v;
325
+ }
326
+
327
+ /**
328
+ * @param {Derived | Tracked} tracked
329
+ * @param {any} value
330
+ */
331
+ export function set(tracked, value) {
332
+ var old_value = tracked.v;
169
333
 
170
- if (v === UNINITIALIZED) {
171
- v = tracked.fn();
172
- tracked.v = v;
334
+ if (value !== old_value) {
335
+ var s = tracked.a.set;
336
+ tracked.v = s ? s(value, tracked.v) : value;
337
+ tracked.c = increment_clock();
173
338
  }
174
- return v;
175
339
  }
176
340
 
177
341
  /**
178
- * @param {any} tracked
342
+ * @param {Tracked} tracked
343
+ * @param {number} [d]
344
+ * @returns {number}
345
+ */
346
+ export function update(tracked, d = 1) {
347
+ var value = get(tracked);
348
+ var result = d === 1 ? value++ : value--;
349
+ set(tracked, value);
350
+ return result;
351
+ }
352
+
353
+ /**
354
+ * @param {Tracked} tracked
355
+ * @param {number} [d]
356
+ * @returns {number}
357
+ */
358
+ export function update_pre(tracked, d = 1) {
359
+ var value = get(tracked);
360
+ var new_value = d === 1 ? ++value : --value;
361
+ set(tracked, new_value);
362
+ return new_value;
363
+ }
364
+
365
+ /**
366
+ * @param {any} obj
367
+ * @param {string | number | symbol} property
368
+ * @param {any} value
369
+ * @returns {void}
370
+ */
371
+ export function set_property(obj, property, value) {
372
+ var tracked = obj[property];
373
+ set(tracked, value);
374
+ }
375
+
376
+ /**
377
+ * @param {any} obj
378
+ * @param {string | number | symbol} property
379
+ * @param {boolean} [chain=false]
179
380
  * @returns {any}
180
381
  */
181
- export function get(tracked) {
182
- // reflect back the value if it's not boxed
183
- if (!is_tracked_object(tracked)) {
382
+ export function get_property(obj, property, chain = false) {
383
+ if (chain && obj == null) {
384
+ return undefined;
385
+ }
386
+ var tracked = obj[property];
387
+ if (tracked == null) {
184
388
  return tracked;
185
389
  }
390
+ return get(tracked);
391
+ }
186
392
 
187
- return (tracked.f & DERIVED) !== 0 ? get_derived(/** @type {Derived} */ (tracked)) : tracked.v;
393
+ /**
394
+ * @param {any} obj
395
+ * @param {string | number | symbol} property
396
+ * @param {number} [d=1]
397
+ * @returns {number}
398
+ */
399
+ export function update_property(obj, property, d = 1) {
400
+ var tracked = obj[property];
401
+ var value = get(tracked);
402
+ var new_value = d === 1 ? value++ : value--;
403
+ set(tracked, value);
404
+ return new_value;
405
+ }
406
+
407
+ /**
408
+ * @param {any} obj
409
+ * @param {string | number | symbol} property
410
+ * @param {number} [d=1]
411
+ * @returns {number}
412
+ */
413
+ export function update_pre_property(obj, property, d = 1) {
414
+ var tracked = obj[property];
415
+ var value = get(tracked);
416
+ var new_value = d === 1 ? ++value : --value;
417
+ set(tracked, new_value);
418
+ return new_value;
188
419
  }
189
420
 
190
421
  /**
@@ -200,11 +431,31 @@ export function attr(name, value, is_boolean = false) {
200
431
  }
201
432
  if (value == null || (!value && is_boolean)) return '';
202
433
  const normalized = (name in replacements && replacements[name].get(value)) || value;
203
- const value_to_escape = name === 'class' ? clsx(normalized) : normalized;
434
+ let value_to_escape = name === 'class' ? clsx(normalized) : normalized;
435
+ value_to_escape =
436
+ name === 'style'
437
+ ? typeof value !== 'string'
438
+ ? get_styles(value)
439
+ : String(normalized).trim()
440
+ : value_to_escape;
204
441
  const assignment = is_boolean ? '' : `="${escape(value_to_escape, true)}"`;
205
442
  return ` ${name}${assignment}`;
206
443
  }
207
444
 
445
+ /**
446
+ * @param {Record<string, string | number>} styles
447
+ * @returns {string}
448
+ */
449
+ function get_styles(styles) {
450
+ var result = '';
451
+ for (const key in styles) {
452
+ const css_prop = normalize_css_property_name(key);
453
+ const value = String(styles[key]).trim();
454
+ result += `${css_prop}: ${value}; `;
455
+ }
456
+ return result.trim();
457
+ }
458
+
208
459
  /**
209
460
  * @param {Record<string, any>} attrs
210
461
  * @param {string | undefined} css_hash