ripple 0.2.138 → 0.2.140

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/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Ripple is an elegant TypeScript UI framework",
4
4
  "license": "MIT",
5
5
  "author": "Dominic Gannaway",
6
- "version": "0.2.138",
6
+ "version": "0.2.140",
7
7
  "type": "module",
8
8
  "module": "src/runtime/index-client.js",
9
9
  "main": "src/runtime/index-client.js",
@@ -81,6 +81,6 @@
81
81
  "typescript": "^5.9.2"
82
82
  },
83
83
  "peerDependencies": {
84
- "ripple": "0.2.138"
84
+ "ripple": "0.2.140"
85
85
  }
86
86
  }
@@ -12,7 +12,7 @@ import { convert_source_map_to_mappings } from './phases/3-transform/segments.js
12
12
  * @returns {Program}
13
13
  */
14
14
  export function parse(source) {
15
- return parse_module(source);
15
+ return parse_module(source);
16
16
  }
17
17
 
18
18
  /**
@@ -23,13 +23,13 @@ export function parse(source) {
23
23
  * @returns {object}
24
24
  */
25
25
  export function compile(source, filename, options = {}) {
26
- const ast = parse_module(source);
27
- const analysis = analyze(ast, filename, options);
28
- const result = options.mode === 'server'
29
- ? transform_server(filename, source, analysis)
30
- : transform_client(filename, source, analysis, false);
26
+ const ast = parse_module(source);
27
+ const analysis = analyze(ast, filename, options);
28
+ const result = options.mode === 'server'
29
+ ? transform_server(filename, source, analysis)
30
+ : transform_client(filename, source, analysis, false);
31
31
 
32
- return result;
32
+ return result;
33
33
  }
34
34
 
35
35
  /** @import { PostProcessingChanges, LineOffsets } from './phases/3-transform/client/index.js' */
@@ -41,17 +41,17 @@ export function compile(source, filename, options = {}) {
41
41
  * @returns {object} Volar mappings object
42
42
  */
43
43
  export function compile_to_volar_mappings(source, filename) {
44
- const ast = parse_module(source);
45
- const analysis = analyze(ast, filename, {});
46
- const transformed = transform_client(filename, source, analysis, true);
44
+ const ast = parse_module(source);
45
+ const analysis = analyze(ast, filename, { to_ts: true });
46
+ const transformed = transform_client(filename, source, analysis, true);
47
47
 
48
- // Create volar mappings with esrap source map for accurate positioning
49
- return convert_source_map_to_mappings(
50
- transformed.ast,
51
- source,
52
- transformed.js.code,
53
- transformed.js.map,
54
- /** @type {PostProcessingChanges} */ (transformed.js.post_processing_changes),
55
- /** @type {LineOffsets} */ (transformed.js.line_offsets)
56
- );
48
+ // Create volar mappings with esrap source map for accurate positioning
49
+ return convert_source_map_to_mappings(
50
+ transformed.ast,
51
+ source,
52
+ transformed.js.code,
53
+ transformed.js.map,
54
+ /** @type {PostProcessingChanges} */(transformed.js.post_processing_changes),
55
+ /** @type {LineOffsets} */(transformed.js.line_offsets)
56
+ );
57
57
  }
@@ -987,6 +987,7 @@ function RipplePlugin(config) {
987
987
  this.finishNode(id, 'Identifier');
988
988
  node.name = id;
989
989
  node.value = id;
990
+ node.shorthand = true; // Mark as shorthand since name and value are the same
990
991
  this.next();
991
992
  this.expect(tt.braceR);
992
993
  return this.finishNode(node, 'Attribute');
@@ -436,9 +436,13 @@ const visitors = {
436
436
  const pattern = node.left.declarations[0].id;
437
437
  const paths = extract_paths(pattern);
438
438
  const scope = state.scopes.get(node);
439
- const pattern_id = b.id(scope.generate('pattern'));
440
-
441
- node.left.declarations[0].id = pattern_id;
439
+ let pattern_id;
440
+ if (state.to_ts) {
441
+ pattern_id = pattern;
442
+ } else {
443
+ pattern_id = b.id(scope.generate('pattern'));
444
+ node.left.declarations[0].id = pattern_id;
445
+ }
442
446
 
443
447
  for (const path of paths) {
444
448
  const name = path.node.name;
@@ -544,10 +548,10 @@ const visitors = {
544
548
  }
545
549
  },
546
550
  /**
547
- *
548
- * @param {any} node
549
- * @param {any} context
550
- * @returns
551
+ *
552
+ * @param {any} node
553
+ * @param {any} context
554
+ * @returns
551
555
  */
552
556
  TryStatement(node, context) {
553
557
  if (!is_inside_component(context)) {
@@ -808,9 +812,9 @@ const visitors = {
808
812
  },
809
813
 
810
814
  /**
811
- *
812
- * @param {any} node
813
- * @param {any} context
815
+ *
816
+ * @param {any} node
817
+ * @param {any} context
814
818
  */
815
819
  AwaitExpression(node, context) {
816
820
  if (is_inside_component(context)) {
@@ -862,6 +866,7 @@ export function analyze(ast, filename, options = {}) {
862
866
  analysis,
863
867
  inside_head: false,
864
868
  inside_server_block: options.mode === 'server',
869
+ to_ts: options.to_ts ?? false,
865
870
  },
866
871
  visitors,
867
872
  );
@@ -190,9 +190,17 @@ const visitors = {
190
190
  const binding = context.state.scope.get(node.name);
191
191
  if (binding?.metadata?.is_dynamic_component) {
192
192
  // Capitalize the identifier for TypeScript
193
- const capitalizedName = node.name.charAt(0).toUpperCase() + node.name.slice(1);
194
- const capitalizedNode = { ...node, name: capitalizedName };
195
- return b.member(capitalizedNode, b.literal('#v'), true);
193
+ const capitalized_name = node.name.charAt(0).toUpperCase() + node.name.slice(1);
194
+ const capitalized_node = {
195
+ ...node,
196
+ name: capitalized_name,
197
+ metadata: {
198
+ ...node.metadata,
199
+ original_name: node.name,
200
+ is_capitalized: true,
201
+ }
202
+ };
203
+ return b.member(capitalized_node, b.literal('#v'), true);
196
204
  }
197
205
  return b.member(node, b.literal('#v'), true);
198
206
  }
@@ -525,13 +533,74 @@ const visitors = {
525
533
 
526
534
  VariableDeclarator(node, context) {
527
535
  // In TypeScript mode, capitalize identifiers that are used as dynamic components
528
- if (context.state.to_ts && node.id.type === 'Identifier') {
529
- const binding = context.state.scope.get(node.id.name);
530
- if (binding?.metadata?.is_dynamic_component) {
531
- const capitalizedName = node.id.name.charAt(0).toUpperCase() + node.id.name.slice(1);
536
+ if (context.state.to_ts) {
537
+ /**
538
+ * Recursively capitalize identifiers in patterns (ArrayPattern, ObjectPattern)
539
+ * @param {any} pattern - The pattern node to process
540
+ * @returns {any} The transformed pattern
541
+ */
542
+ const capitalize_pattern = (pattern) => {
543
+ if (pattern.type === 'Identifier') {
544
+ const binding = context.state.scope.get(pattern.name);
545
+ if (binding?.metadata?.is_dynamic_component) {
546
+ const capitalized_name = pattern.name.charAt(0).toUpperCase() + pattern.name.slice(1);
547
+ // Add metadata to track the original name for Volar mappings
548
+ return {
549
+ ...pattern,
550
+ name: capitalized_name,
551
+ metadata: {
552
+ ...pattern.metadata,
553
+ original_name: pattern.name,
554
+ is_capitalized: true,
555
+ }
556
+ };
557
+ }
558
+ return pattern;
559
+ } else if (pattern.type === 'ArrayPattern') {
560
+ return {
561
+ ...pattern,
562
+ elements: pattern.elements.map((element) =>
563
+ element ? capitalize_pattern(element) : element
564
+ ),
565
+ };
566
+ } else if (pattern.type === 'ObjectPattern') {
567
+ return {
568
+ ...pattern,
569
+ properties: pattern.properties.map((prop) => {
570
+ if (prop.type === 'Property') {
571
+ return {
572
+ ...prop,
573
+ value: capitalize_pattern(prop.value),
574
+ };
575
+ } else if (prop.type === 'RestElement') {
576
+ return {
577
+ ...prop,
578
+ argument: capitalize_pattern(prop.argument),
579
+ };
580
+ }
581
+ return prop;
582
+ }),
583
+ };
584
+ } else if (pattern.type === 'RestElement') {
585
+ return {
586
+ ...pattern,
587
+ argument: capitalize_pattern(pattern.argument),
588
+ };
589
+ } else if (pattern.type === 'AssignmentPattern') {
590
+ return {
591
+ ...pattern,
592
+ left: capitalize_pattern(pattern.left),
593
+ right: context.visit(pattern.right),
594
+ };
595
+ }
596
+ return pattern;
597
+ };
598
+
599
+ const transformed_id = capitalize_pattern(node.id);
600
+ if (transformed_id !== node.id) {
532
601
  return {
533
602
  ...node,
534
- id: { ...node.id, name: capitalizedName },
603
+ id: transformed_id,
535
604
  init: node.init ? context.visit(node.init) : null,
536
605
  };
537
606
  }
@@ -1244,7 +1313,6 @@ const visitors = {
1244
1313
  /** @type {Expression} */ (context.visit(left)),
1245
1314
  /** @type {Expression} */ (context.visit(right)),
1246
1315
  ),
1247
- b.id('__block'),
1248
1316
  );
1249
1317
  }
1250
1318
 
@@ -1265,7 +1333,6 @@ const visitors = {
1265
1333
  ),
1266
1334
  /** @type {Expression} */ (context.visit(right)),
1267
1335
  ),
1268
- b.id('__block'),
1269
1336
  );
1270
1337
  }
1271
1338
 
@@ -1291,7 +1358,6 @@ const visitors = {
1291
1358
  node.prefix ? '_$_.update_pre_property' : '_$_.update_property',
1292
1359
  context.visit(argument.object, { ...context.state, metadata: { tracking: false } }),
1293
1360
  argument.computed ? context.visit(argument.property) : b.literal(argument.property.name),
1294
- b.id('__block'),
1295
1361
  node.operator === '--' ? b.literal(-1) : undefined,
1296
1362
  );
1297
1363
  }
@@ -1300,7 +1366,6 @@ const visitors = {
1300
1366
  return b.call(
1301
1367
  node.prefix ? '_$_.update_pre' : '_$_.update',
1302
1368
  context.visit(argument, { ...context.state, metadata: { tracking: null } }),
1303
- b.id('__block'),
1304
1369
  node.operator === '--' ? b.literal(-1) : undefined,
1305
1370
  );
1306
1371
  }
@@ -1309,7 +1374,6 @@ const visitors = {
1309
1374
  return b.call(
1310
1375
  node.prefix ? '_$_.update_pre' : '_$_.update',
1311
1376
  context.visit(argument.argument, { ...context.state, metadata: { tracking: null } }),
1312
- b.id('__block'),
1313
1377
  node.operator === '--' ? b.literal(-1) : undefined,
1314
1378
  );
1315
1379
  }
@@ -1740,7 +1804,10 @@ function transform_ts_child(node, context) {
1740
1804
  }
1741
1805
  jsx_name.loc = attr.name.loc || name.loc;
1742
1806
 
1743
- return b.jsx_attribute(jsx_name, b.jsx_expression_container(value));
1807
+ const jsx_attr = b.jsx_attribute(jsx_name, b.jsx_expression_container(value));
1808
+ // Preserve shorthand flag from parser (set for {identifier} syntax)
1809
+ jsx_attr.shorthand = attr.shorthand ?? false;
1810
+ return jsx_attr;
1744
1811
  } else if (attr.type === 'SpreadAttribute') {
1745
1812
  const metadata = { await: false };
1746
1813
  const argument = visit(attr.argument, { ...state, metadata });
@@ -1783,31 +1850,75 @@ function transform_ts_child(node, context) {
1783
1850
  closing_type = node.selfClosing ? undefined : type_expression;
1784
1851
  } else {
1785
1852
  opening_type = b.jsx_id(type_expression);
1786
- // Use node.id.loc if available, otherwise create a loc based on the element's position
1787
- opening_type.loc = node.id.loc || {
1788
- start: {
1789
- line: node.loc.start.line,
1790
- column: node.loc.start.column + 2, // After "<@"
1791
- },
1792
- end: {
1793
- line: node.loc.start.line,
1794
- column: node.loc.start.column + 2 + type_expression.length,
1795
- },
1796
- };
1797
-
1798
- if (!node.selfClosing) {
1799
- closing_type = b.jsx_id(type_expression);
1800
- closing_type.loc = {
1853
+ // For tracked identifiers (dynamic components), adjust the loc to skip the '@' prefix
1854
+ // and add metadata for mapping
1855
+ if (node.id.tracked && node.id.loc) {
1856
+ // The original identifier loc includes the '@', so we need to skip it
1857
+ opening_type.loc = {
1858
+ start: {
1859
+ line: node.id.loc.start.line,
1860
+ column: node.id.loc.start.column + 1, // Skip '@'
1861
+ },
1862
+ end: node.id.loc.end,
1863
+ };
1864
+ // Add metadata if this was capitalized
1865
+ if (node.metadata?.ts_name && node.metadata?.original_name) {
1866
+ opening_type.metadata = {
1867
+ original_name: node.metadata.original_name,
1868
+ is_capitalized: true,
1869
+ };
1870
+ }
1871
+ } else {
1872
+ // Use node.id.loc if available, otherwise create a loc based on the element's position
1873
+ opening_type.loc = node.id.loc || {
1801
1874
  start: {
1802
- line: node.loc.end.line,
1803
- column: node.loc.end.column - type_expression.length - 1,
1875
+ line: node.loc.start.line,
1876
+ column: node.loc.start.column + 2, // After "<@"
1804
1877
  },
1805
1878
  end: {
1806
- line: node.loc.end.line,
1807
- column: node.loc.end.column - 1,
1879
+ line: node.loc.start.line,
1880
+ column: node.loc.start.column + 2 + type_expression.length,
1808
1881
  },
1809
1882
  };
1810
1883
  }
1884
+
1885
+ if (!node.selfClosing) {
1886
+ closing_type = b.jsx_id(type_expression);
1887
+ // For tracked identifiers, also adjust closing tag location
1888
+ if (node.id.tracked && node.id.loc) {
1889
+ // Calculate position relative to closing tag
1890
+ // Format: </@identifier>
1891
+ const closing_tag_start = node.loc.end.column - type_expression.length - 3; // </@
1892
+ closing_type.loc = {
1893
+ start: {
1894
+ line: node.loc.end.line,
1895
+ column: closing_tag_start + 3, // Skip '</@'
1896
+ },
1897
+ end: {
1898
+ line: node.loc.end.line,
1899
+ column: closing_tag_start + 3 + (node.metadata?.original_name?.length || type_expression.length),
1900
+ },
1901
+ };
1902
+ // Add metadata if this was capitalized
1903
+ if (node.metadata?.ts_name && node.metadata?.original_name) {
1904
+ closing_type.metadata = {
1905
+ original_name: node.metadata.original_name,
1906
+ is_capitalized: true,
1907
+ };
1908
+ }
1909
+ } else {
1910
+ closing_type.loc = {
1911
+ start: {
1912
+ line: node.loc.end.line,
1913
+ column: node.loc.end.column - type_expression.length - 1,
1914
+ },
1915
+ end: {
1916
+ line: node.loc.end.line,
1917
+ column: node.loc.end.column - 1,
1918
+ },
1919
+ };
1920
+ }
1921
+ }
1811
1922
  }
1812
1923
 
1813
1924
  const jsxElement = b.jsx_element(
@@ -2396,12 +2507,13 @@ export function transform_client(filename, source, analysis, to_ts) {
2396
2507
 
2397
2508
  const language_handler = to_ts ? create_tsx_with_typescript_support() : tsx();
2398
2509
 
2399
- const js = /** @type {ReturnType<typeof print> & { post_processing_changes?: PostProcessingChanges, line_offsets?: number[] }} */ (
2400
- print(program, language_handler, {
2401
- sourceMapContent: source,
2402
- sourceMapSource: path.basename(filename),
2403
- })
2404
- );
2510
+ const js =
2511
+ /** @type {ReturnType<typeof print> & { post_processing_changes?: PostProcessingChanges, line_offsets?: number[] }} */ (
2512
+ print(program, language_handler, {
2513
+ sourceMapContent: source,
2514
+ sourceMapSource: path.basename(filename),
2515
+ })
2516
+ );
2405
2517
 
2406
2518
  // Post-process TypeScript output to remove 'declare' from function overload signatures
2407
2519
  // Function overload signatures in regular .ts files should not have 'declare' keyword
@@ -2427,7 +2539,10 @@ export function transform_client(filename, source, analysis, to_ts) {
2427
2539
  */
2428
2540
  const offset_to_line = (offset) => {
2429
2541
  for (let i = 0; i < line_offsets.length; i++) {
2430
- if (offset >= line_offsets[i] && (i === line_offsets.length - 1 || offset < line_offsets[i + 1])) {
2542
+ if (
2543
+ offset >= line_offsets[i] &&
2544
+ (i === line_offsets.length - 1 || offset < line_offsets[i + 1])
2545
+ ) {
2431
2546
  return i + 1;
2432
2547
  }
2433
2548
  }
@@ -2440,22 +2555,25 @@ export function transform_client(filename, source, analysis, to_ts) {
2440
2555
  // Remove 'export declare function' -> 'export function' (for overloads only, not implementations)
2441
2556
  // Match: export declare function name(...): type;
2442
2557
  // Don't match: export declare function name(...): type { (has body)
2443
- js.code = js.code.replace(/^(export\s+)declare\s+(function\s+\w+[^{\n]*;)$/gm, (match, p1, p2, offset) => {
2444
- const replacement = p1 + p2;
2445
- const line = offset_to_line(offset);
2446
- const delta = replacement.length - match.length; // negative (removing 'declare ')
2447
-
2448
- // Track first change offset and total delta per line
2449
- if (!line_deltas.has(line)) {
2450
- line_deltas.set(line, { offset, delta });
2451
- } else {
2452
- // Additional change on same line - accumulate delta
2453
- // @ts-ignore
2454
- line_deltas.get(line).delta += delta;
2455
- }
2558
+ js.code = js.code.replace(
2559
+ /^(export\s+)declare\s+(function\s+\w+[^{\n]*;)$/gm,
2560
+ (match, p1, p2, offset) => {
2561
+ const replacement = p1 + p2;
2562
+ const line = offset_to_line(offset);
2563
+ const delta = replacement.length - match.length; // negative (removing 'declare ')
2564
+
2565
+ // Track first change offset and total delta per line
2566
+ if (!line_deltas.has(line)) {
2567
+ line_deltas.set(line, { offset, delta });
2568
+ } else {
2569
+ // Additional change on same line - accumulate delta
2570
+ // @ts-ignore
2571
+ line_deltas.get(line).delta += delta;
2572
+ }
2456
2573
 
2457
- return replacement;
2458
- });
2574
+ return replacement;
2575
+ },
2576
+ );
2459
2577
 
2460
2578
  post_processing_changes = line_deltas;
2461
2579
  }
@@ -70,26 +70,6 @@ export function convert_source_map_to_mappings(ast, source, generated_code, esra
70
70
  return line_offsets[line - 1] + column;
71
71
  };
72
72
 
73
- // Map to track capitalized names: original name -> capitalized name
74
- /** @type {Map<string, string>} */
75
- const capitalized_names = new Map();
76
- // Reverse map: capitalized name -> original name
77
- /** @type {Map<string, string>} */
78
- const reverse_capitalized_names = new Map();
79
-
80
- // Pre-walk to collect capitalized names from JSXElement nodes (transformed AST)
81
- // These are identifiers that are used as dynamic components/elements
82
- walk(ast, null, {
83
- _(node, { next }) {
84
- // Check JSXElement nodes with metadata (preserved from Element nodes)
85
- if (node.type === 'JSXElement' && node.metadata?.ts_name && node.metadata?.original_name) {
86
- capitalized_names.set(node.metadata.original_name, node.metadata.ts_name);
87
- reverse_capitalized_names.set(node.metadata.ts_name, node.metadata.original_name);
88
- }
89
- next();
90
- }
91
- });
92
-
93
73
  const adjusted_source_map = build_source_to_generated_map(
94
74
  esrap_source_map,
95
75
  post_processing_changes,
@@ -110,51 +90,30 @@ export function convert_source_map_to_mappings(ast, source, generated_code, esra
110
90
  walk(ast, null, {
111
91
  _(node, { visit }) {
112
92
  // Collect key node types: Identifiers, Literals, and JSX Elements
113
- // Skip nodes without .loc (synthesized during transformation, not in original source)
114
- if (node.type === 'Identifier' && node.name) {
115
- if (node.loc) {
93
+ if (node.type === 'Identifier') {
94
+ // Only create mappings for identifiers with location info (from source)
95
+ // Synthesized identifiers (created by builders) don't have .loc and are skipped
96
+ if (node.name && node.loc) {
116
97
  // Check if this identifier has tracked_shorthand metadata (e.g., TrackedMap -> #Map)
117
98
  if (node.metadata?.tracked_shorthand) {
118
99
  tokens.push({ source: node.metadata.tracked_shorthand, generated: node.name, loc: node.loc });
100
+ } else if (node.metadata?.is_capitalized) {
101
+ // This identifier was capitalized during transformation
102
+ // Map the original lowercase name to the capitalized generated name
103
+ tokens.push({ source: node.metadata.original_name, generated: node.name, loc: node.loc });
119
104
  } else {
120
- // Check if this identifier was capitalized (reverse lookup)
121
- const original_name = reverse_capitalized_names.get(node.name);
122
- if (original_name) {
123
- // This is a capitalized name in generated code, map to lowercase in source
124
- tokens.push({ source: original_name, generated: node.name, loc: node.loc });
125
- } else {
126
- // Check if this identifier should be capitalized (forward lookup)
127
- const cap_name = capitalized_names.get(node.name);
128
- if (cap_name) {
129
- tokens.push({ source: node.name, generated: cap_name, loc: node.loc });
130
- } else {
131
- // Check if this identifier should be capitalized (forward lookup)
132
- const cap_name = capitalized_names.get(node.name);
133
- if (cap_name) {
134
- tokens.push({ source: node.name, generated: cap_name, loc: node.loc });
135
- } else {
136
- // Store token with .loc for accurate positioning
137
- tokens.push({ source: node.name, generated: node.name, loc: node.loc });
138
- }
139
- }
140
- }
105
+ // No transformation - source and generated names are the same
106
+ tokens.push({ source: node.name, generated: node.name, loc: node.loc });
141
107
  }
142
108
  }
143
109
  return; // Leaf node, don't traverse further
144
- } else if (node.type === 'JSXIdentifier' && node.name) {
145
- if (node.loc) {
146
- // Check if this was capitalized (reverse lookup)
147
- const originalName = reverse_capitalized_names.get(node.name);
148
- if (originalName) {
149
- tokens.push({ source: originalName, generated: node.name, loc: node.loc });
110
+ } else if (node.type === 'JSXIdentifier') {
111
+ // JSXIdentifiers can also be capitalized (for dynamic components)
112
+ if (node.loc && node.name) {
113
+ if (node.metadata?.is_capitalized) {
114
+ tokens.push({ source: node.metadata.original_name, generated: node.name, loc: node.loc });
150
115
  } else {
151
- // Check if this should be capitalized (forward lookup)
152
- const capitalizedName = capitalized_names.get(node.name);
153
- if (capitalizedName) {
154
- tokens.push({ source: node.name, generated: capitalizedName, loc: node.loc });
155
- } else {
156
- tokens.push({ source: node.name, generated: node.name, loc: node.loc });
157
- }
116
+ tokens.push({ source: node.name, generated: node.name, loc: node.loc });
158
117
  }
159
118
  }
160
119
  return; // Leaf node, don't traverse further
@@ -242,11 +201,18 @@ export function convert_source_map_to_mappings(ast, source, generated_code, esra
242
201
  return;
243
202
  } else if (node.type === 'JSXAttribute') {
244
203
  // Visit name and value in source order
245
- if (node.name) {
246
- visit(node.name);
247
- }
248
- if (node.value) {
249
- visit(node.value);
204
+ // For shorthand attributes ({ count }), key and value are the same node, only visit once
205
+ if (node.shorthand) {
206
+ if (node.value) {
207
+ visit(node.value);
208
+ }
209
+ } else {
210
+ if (node.name) {
211
+ visit(node.name);
212
+ }
213
+ if (node.value) {
214
+ visit(node.value);
215
+ }
250
216
  }
251
217
  return;
252
218
  } else if (node.type === 'JSXSpreadAttribute') {
@@ -282,19 +248,10 @@ export function convert_source_map_to_mappings(ast, source, generated_code, esra
282
248
  // 3. Push closing tag name (not visited by AST walker)
283
249
  if (!node.openingElement?.selfClosing && node.closingElement?.name?.type === 'JSXIdentifier') {
284
250
  const closingNameNode = node.closingElement.name;
285
- const closingName = closingNameNode.name;
286
- // Check if this was capitalized (reverse lookup)
287
- const originalName = reverse_capitalized_names.get(closingName);
288
- if (originalName) {
289
- tokens.push({ source: originalName, generated: closingName, loc: closingNameNode.loc });
251
+ if (closingNameNode.metadata?.is_capitalized) {
252
+ tokens.push({ source: closingNameNode.metadata.original_name, generated: closingNameNode.name, loc: closingNameNode.loc });
290
253
  } else {
291
- // Check if this should be capitalized (forward lookup)
292
- const capitalizedName = capitalized_names.get(closingName);
293
- if (capitalizedName) {
294
- tokens.push({ source: closingName, generated: capitalizedName, loc: closingNameNode.loc });
295
- } else {
296
- tokens.push({ source: closingName, generated: closingName, loc: closingNameNode.loc });
297
- }
254
+ tokens.push({ source: closingNameNode.name, generated: closingNameNode.name, loc: closingNameNode.loc });
298
255
  }
299
256
  }
300
257
 
@@ -175,7 +175,7 @@ export function bindValue(maybe_tracked) {
175
175
  value = selected_option && get_option_value(selected_option);
176
176
  }
177
177
 
178
- set(tracked, value, block);
178
+ set(tracked, value);
179
179
  });
180
180
 
181
181
  effect(() => {
@@ -189,7 +189,7 @@ export function bindValue(maybe_tracked) {
189
189
  var selected_option = select.querySelector(':checked');
190
190
  if (selected_option !== null) {
191
191
  value = get_option_value(selected_option);
192
- set(tracked, value, block);
192
+ set(tracked, value);
193
193
  }
194
194
  }
195
195
 
@@ -202,7 +202,7 @@ export function bindValue(maybe_tracked) {
202
202
  /** @type {any} */
203
203
  var value = input.value;
204
204
  value = is_numberlike_input(input) ? to_number(value) : value;
205
- set(tracked, value, block);
205
+ set(tracked, value);
206
206
 
207
207
  await tick();
208
208
 
@@ -254,7 +254,7 @@ export function bindChecked(maybe_tracked) {
254
254
 
255
255
  return (input) => {
256
256
  const clear_event = on(input, 'change', () => {
257
- set(tracked, input.checked, block);
257
+ set(tracked, input.checked);
258
258
  });
259
259
 
260
260
  return clear_event;
@@ -277,11 +277,11 @@ function bind_element_size(maybe_tracked, type) {
277
277
 
278
278
  return (/** @type {HTMLElement} */ element) => {
279
279
  var unsubscribe = resize_observer_border_box.observe(element, () =>
280
- set(tracked, element[type], block),
280
+ set(tracked, element[type]),
281
281
  );
282
282
 
283
283
  effect(() => {
284
- untrack(() => set(tracked, element[type], block));
284
+ untrack(() => set(tracked, element[type]));
285
285
  return unsubscribe;
286
286
  });
287
287
  };
@@ -342,7 +342,7 @@ function bind_element_rect(maybe_tracked, type) {
342
342
  return (/** @type {HTMLElement} */ element) => {
343
343
  var unsubscribe = observer.observe(
344
344
  element,
345
- /** @param {any} entry */ (entry) => set(tracked, entry[type], block),
345
+ /** @param {any} entry */ (entry) => set(tracked, entry[type]),
346
346
  );
347
347
 
348
348
  effect(() => unsubscribe);
@@ -398,7 +398,7 @@ export function bind_content_editable(maybe_tracked, property) {
398
398
 
399
399
  return (element) => {
400
400
  const clear_event = on(element, 'input', () => {
401
- set(tracked, element[property], block);
401
+ set(tracked, element[property]);
402
402
  });
403
403
 
404
404
  render(() => {
@@ -408,7 +408,7 @@ export function bind_content_editable(maybe_tracked, property) {
408
408
  if (value == null) {
409
409
  // @ts-ignore
410
410
  var non_null_value = element[property];
411
- set(tracked, non_null_value, block);
411
+ set(tracked, non_null_value);
412
412
  } else {
413
413
  // @ts-ignore
414
414
  element[property] = value + '';
@@ -186,7 +186,7 @@ function reconcile_fast_clear(anchor, block, array) {
186
186
  * @returns {void}
187
187
  */
188
188
  function update_index(block, index) {
189
- set(block.s.i, index, block);
189
+ set(block.s.i, index);
190
190
  }
191
191
 
192
192
  /**
@@ -195,7 +195,7 @@ function update_index(block, index) {
195
195
  * @returns {void}
196
196
  */
197
197
  function update_value(block, value) {
198
- set(block.s.v, value, block);
198
+ set(block.s.v, value);
199
199
  }
200
200
 
201
201
  /**
@@ -345,6 +345,9 @@ export function track(v, get, set, b) {
345
345
  if (is_tracked_object(v)) {
346
346
  return v;
347
347
  }
348
+ if (b === null) {
349
+ throw new TypeError('track() requires a valid component context');
350
+ }
348
351
 
349
352
  if (typeof v === 'function') {
350
353
  return derived(v, b, get, set);
@@ -440,7 +443,7 @@ function is_tracking_dirty(tracking) {
440
443
  var tracked = tracking.t;
441
444
 
442
445
  if ((tracked.f & DERIVED) !== 0) {
443
- update_derived(/** @type {Derived} **/(tracked));
446
+ update_derived(/** @type {Derived} **/ (tracked));
444
447
  }
445
448
 
446
449
  if (tracked.c > tracking.c) {
@@ -500,7 +503,7 @@ export function async_computed(fn, block) {
500
503
  }
501
504
 
502
505
  promise.then((v) => {
503
- if (parent && is_destroyed(/** @type {Block} */(parent))) {
506
+ if (parent && is_destroyed(/** @type {Block} */ (parent))) {
504
507
  return;
505
508
  }
506
509
  if (promise === current && t.__v !== v) {
@@ -509,7 +512,7 @@ export function async_computed(fn, block) {
509
512
  if (t.__v === UNINITIALIZED) {
510
513
  t.__v = v;
511
514
  } else {
512
- set(t, v, block);
515
+ set(t, v);
513
516
  }
514
517
  }
515
518
 
@@ -774,7 +777,7 @@ export function get(tracked) {
774
777
  }
775
778
 
776
779
  return (tracked.f & DERIVED) !== 0
777
- ? get_derived(/** @type {Derived} */(tracked))
780
+ ? get_derived(/** @type {Derived} */ (tracked))
778
781
  : get_tracked(tracked);
779
782
  }
780
783
 
@@ -803,15 +806,14 @@ export function get_tracked(tracked) {
803
806
  * @param {any} value
804
807
  */
805
808
  export function public_set(tracked, value) {
806
- set(tracked, value, safe_scope());
809
+ set(tracked, value);
807
810
  }
808
811
 
809
812
  /**
810
813
  * @param {Derived | Tracked} tracked
811
814
  * @param {any} value
812
- * @param {Block} block
813
815
  */
814
- export function set(tracked, value, block) {
816
+ export function set(tracked, value) {
815
817
  if (!is_mutating_allowed) {
816
818
  throw new Error(
817
819
  'Assignments or updates to tracked values are not allowed during computed "track(() => ...)" evaluation',
@@ -823,7 +825,7 @@ export function set(tracked, value, block) {
823
825
  if (value !== old_value) {
824
826
  var tracked_block = tracked.b;
825
827
 
826
- if ((block.f & CONTAINS_TEARDOWN) !== 0) {
828
+ if ((tracked_block.f & CONTAINS_TEARDOWN) !== 0) {
827
829
  if (teardown) {
828
830
  old_values.set(tracked, value);
829
831
  } else {
@@ -991,85 +993,78 @@ export function get_property(obj, property, chain = false) {
991
993
  * @param {any} obj
992
994
  * @param {string | number | symbol} property
993
995
  * @param {any} value
994
- * @param {Block} block
995
996
  * @returns {void}
996
997
  */
997
- export function set_property(obj, property, value, block) {
998
+ export function set_property(obj, property, value) {
998
999
  var tracked = obj[property];
999
- set(tracked, value, block);
1000
+ set(tracked, value);
1000
1001
  }
1001
1002
 
1002
1003
  /**
1003
1004
  * @param {Tracked} tracked
1004
- * @param {Block} block
1005
1005
  * @param {number} [d]
1006
1006
  * @returns {number}
1007
1007
  */
1008
- export function update(tracked, block, d = 1) {
1008
+ export function update(tracked, d = 1) {
1009
1009
  var value = get(tracked);
1010
1010
  var result = d === 1 ? value++ : value--;
1011
- set(tracked, value, block);
1011
+ set(tracked, value);
1012
1012
  return result;
1013
1013
  }
1014
1014
 
1015
1015
  /**
1016
1016
  * @param {Tracked} tracked
1017
- * @param {Block} block
1018
1017
  * @returns {void}
1019
1018
  */
1020
- export function increment(tracked, block) {
1021
- set(tracked, tracked.__v + 1, block);
1019
+ export function increment(tracked) {
1020
+ set(tracked, tracked.__v + 1);
1022
1021
  }
1023
1022
 
1024
1023
  /**
1025
1024
  * @param {Tracked} tracked
1026
- * @param {Block} block
1027
1025
  * @returns {void}
1028
1026
  */
1029
- export function decrement(tracked, block) {
1030
- set(tracked, tracked.__v - 1, block);
1027
+ export function decrement(tracked) {
1028
+ set(tracked, tracked.__v - 1);
1031
1029
  }
1032
1030
 
1033
1031
  /**
1034
1032
  * @param {Tracked} tracked
1035
- * @param {Block} block
1036
1033
  * @param {number} [d]
1037
1034
  * @returns {number}
1038
1035
  */
1039
- export function update_pre(tracked, block, d = 1) {
1036
+ export function update_pre(tracked, d = 1) {
1040
1037
  var value = get(tracked);
1041
1038
  var new_value = d === 1 ? ++value : --value;
1042
- set(tracked, new_value, block);
1039
+ set(tracked, new_value);
1043
1040
  return new_value;
1044
1041
  }
1045
1042
 
1046
1043
  /**
1047
1044
  * @param {any} obj
1048
1045
  * @param {string | number | symbol} property
1049
- * @param {Block} block
1050
1046
  * @param {number} [d=1]
1051
1047
  * @returns {number}
1052
1048
  */
1053
- export function update_property(obj, property, block, d = 1) {
1049
+ export function update_property(obj, property, d = 1) {
1054
1050
  var tracked = obj[property];
1055
1051
  var value = get(tracked);
1056
1052
  var new_value = d === 1 ? value++ : value--;
1057
- set(tracked, value, block);
1053
+ set(tracked, value);
1058
1054
  return new_value;
1059
1055
  }
1060
1056
 
1061
1057
  /**
1062
1058
  * @param {any} obj
1063
1059
  * @param {string | number | symbol} property
1064
- * @param {Block} block
1065
1060
  * @param {number} [d=1]
1066
1061
  * @returns {number}
1067
1062
  */
1068
- export function update_pre_property(obj, property, block, d = 1) {
1063
+ export function update_pre_property(obj, property, d = 1) {
1069
1064
  var tracked = obj[property];
1070
1065
  var value = get(tracked);
1071
1066
  var new_value = d === 1 ? ++value : --value;
1072
- set(tracked, new_value, block);
1067
+ set(tracked, new_value);
1073
1068
  return new_value;
1074
1069
  }
1075
1070
 
@@ -1093,7 +1088,7 @@ export function with_scope(block, fn) {
1093
1088
  * @returns {Block | null}
1094
1089
  */
1095
1090
  export function scope() {
1096
- return active_scope;
1091
+ return active_scope || active_block;
1097
1092
  }
1098
1093
 
1099
1094
  /**
@@ -1206,7 +1201,7 @@ export async function maybe_tracked(v) {
1206
1201
  } else {
1207
1202
  value = await async_computed(async () => {
1208
1203
  return await get_tracked(v);
1209
- }, /** @type {Block} */(active_block));
1204
+ }, /** @type {Block} */ (active_block));
1210
1205
  }
1211
1206
  } else {
1212
1207
  value = await v;
@@ -714,6 +714,7 @@ export function jsx_attribute(name, value = null) {
714
714
  type: 'JSXAttribute',
715
715
  name,
716
716
  value,
717
+ shorthand: false,
717
718
  };
718
719
  }
719
720
 
@@ -39,11 +39,15 @@ describe('basic client > get/set functions', () => {
39
39
  let count = track(0);
40
40
 
41
41
  <p>{get(count)}</p>
42
- <button onClick={() => {
43
- @count++;
44
- @count++;
45
- @count++;
46
- }}>{'increment'}</button>
42
+ <button
43
+ onClick={() => {
44
+ @count++;
45
+ @count++;
46
+ @count++;
47
+ }}
48
+ >
49
+ {'increment'}
50
+ </button>
47
51
  }
48
52
 
49
53
  render(Test);
@@ -83,11 +87,15 @@ describe('basic client > get/set functions', () => {
83
87
  let count = track(0);
84
88
 
85
89
  <p>{get(count)}</p>
86
- <button onClick={() => {
87
- set(count, 5);
88
- set(count, 15);
89
- set(count, 25);
90
- }}>{'set multiple times'}</button>
90
+ <button
91
+ onClick={() => {
92
+ set(count, 5);
93
+ set(count, 15);
94
+ set(count, 25);
95
+ }}
96
+ >
97
+ {'set multiple times'}
98
+ </button>
91
99
  }
92
100
 
93
101
  render(Test);
@@ -133,11 +141,15 @@ describe('basic client > get/set functions', () => {
133
141
  let count = track(0);
134
142
 
135
143
  <p>{get(count)}</p>
136
- <button onClick={() => {
137
- set(count, get(count) + 5);
138
- set(count, get(count) + 15);
139
- set(count, get(count) + 25);
140
- }}>{'add multiple times'}</button>
144
+ <button
145
+ onClick={() => {
146
+ set(count, get(count) + 5);
147
+ set(count, get(count) + 15);
148
+ set(count, get(count) + 25);
149
+ }}
150
+ >
151
+ {'add multiple times'}
152
+ </button>
141
153
  }
142
154
 
143
155
  render(Test);
@@ -158,11 +170,11 @@ describe('basic client > get/set functions', () => {
158
170
  expect(p.textContent).toBe('90');
159
171
  });
160
172
 
161
- function store() {
162
- return track(0);
163
- }
164
-
165
173
  it('gets value declared outside Ripple component', () => {
174
+ function store() {
175
+ return track(0);
176
+ }
177
+
166
178
  component Test() {
167
179
  let count = store();
168
180
  <p>{get(count)}</p>
@@ -175,6 +187,10 @@ describe('basic client > get/set functions', () => {
175
187
  });
176
188
 
177
189
  it('sets value declared outside Ripple component', () => {
190
+ function store() {
191
+ return track(0);
192
+ }
193
+
178
194
  component Test() {
179
195
  let count = store();
180
196
 
@@ -257,35 +273,7 @@ describe('basic client > get/set functions', () => {
257
273
  expect(p.textContent).toBe('2');
258
274
  });
259
275
 
260
- it("get isn't reactive when declared outside Ripple context", () => {
261
- let count = store();
262
-
263
- component Test() {
264
- <p>{get(count)}</p>
265
- <button onClick={() => { set(count, get(count) + 1) }}>{'increment'}</button>
266
- }
267
-
268
- expect(get(count)).toBe(0);
269
-
270
- render(Test);
271
-
272
- const p = container.querySelector('p');
273
- expect(p.textContent).toBe('0');
274
- expect(get(count)).toBe(0);
275
-
276
- const button = container.querySelector('button');
277
- button.click();
278
- flushSync();
279
-
280
- expect(p.textContent).toBe('0');
281
- expect(get(count)).toBe(1);
282
- });
283
-
284
- it('throws on trying to set a value outside Ripple component', () => {
285
- let count = store();
286
-
287
- expect(get(count)).toBe(0);
288
- expect(() => set(count, 1)).toThrow();
289
- expect(get(count)).toBe(0);
276
+ it('throws on trying to create tracked Ripple component', () => {
277
+ expect(() => track(0)).toThrow();
290
278
  });
291
279
  });
@@ -4,9 +4,9 @@ exports[`compiler > assignments > compiles tracked values in effect with assignm
4
4
 
5
5
  exports[`compiler > assignments > compiles tracked values in effect with update expressions 1`] = `
6
6
  "_$_.with_scope(__block, () => untrack(() => {
7
- state.preIncrement = _$_.update_pre(count, __block);
8
- state.postIncrement = _$_.update(count, __block);
9
- state.preDecrement = _$_.update_pre(count, __block, -1);
10
- state.postDecrement = _$_.update(count, __block, -1);
7
+ state.preIncrement = _$_.update_pre(count);
8
+ state.postIncrement = _$_.update(count);
9
+ state.preDecrement = _$_.update_pre(count, -1);
10
+ state.postDecrement = _$_.update(count, -1);
11
11
  }));"
12
12
  `;