@tsrx/core 0.0.11 → 0.0.13

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": "Core compiler infrastructure for TSRX syntax",
4
4
  "license": "MIT",
5
5
  "author": "Dominic Gannaway",
6
- "version": "0.0.11",
6
+ "version": "0.0.13",
7
7
  "type": "module",
8
8
  "repository": {
9
9
  "type": "git",
package/src/plugin.js CHANGED
@@ -1059,9 +1059,23 @@ export function TSRXPlugin(config) {
1059
1059
  * @type {Parse.Parser['jsx_parseAttribute']}
1060
1060
  */
1061
1061
  jsx_parseAttribute() {
1062
- let node = /** @type {AST.TSRXAttribute | ESTreeJSX.JSXAttribute} */ (this.startNode());
1062
+ let node =
1063
+ /** @type {AST.TSRXAttribute | ESTreeJSX.JSXAttribute | ESTreeJSX.JSXSpreadAttribute} */ (
1064
+ this.startNode()
1065
+ );
1063
1066
 
1064
1067
  if (this.eat(tt.braceL)) {
1068
+ const inside_tsx = this.#path.findLast((n) => n.type === 'TsxCompat' || n.type === 'Tsx');
1069
+ if (inside_tsx) {
1070
+ if (this.type === tt.ellipsis) {
1071
+ this.expect(tt.ellipsis);
1072
+ /** @type {ESTreeJSX.JSXSpreadAttribute} */ (node).argument = this.parseMaybeAssign();
1073
+ this.expect(tt.braceR);
1074
+ return this.finishNode(node, 'JSXSpreadAttribute');
1075
+ }
1076
+ this.unexpected();
1077
+ }
1078
+
1065
1079
  if (this.value === 'ref') {
1066
1080
  this.next();
1067
1081
  if (this.type === tt.braceR) {
@@ -99,7 +99,14 @@ export function tsx_with_ts_locations() {
99
99
  };
100
100
 
101
101
  /** @type {Record<string, (node: any, context: any) => void>} */
102
- const wrappers = {};
102
+ const wrappers = {
103
+ ArrayPattern: (node, context) => {
104
+ base.ArrayPattern(node, context);
105
+ if (node.typeAnnotation) {
106
+ context.visit(node.typeAnnotation);
107
+ }
108
+ },
109
+ };
103
110
  for (const type of [
104
111
  // JS nodes whose esrap printer emits no location marker, causing
105
112
  // segments.js get_mapping_from_node() to throw when it asks for the
@@ -111,6 +118,7 @@ export function tsx_with_ts_locations() {
111
118
  'ReturnStatement',
112
119
  'ForStatement',
113
120
  'ForInStatement',
121
+ 'ForOfStatement',
114
122
  'TemplateLiteral',
115
123
  'AwaitExpression',
116
124
  'TaggedTemplateExpression',
@@ -805,8 +805,8 @@ function create_helper_props_pattern(bindings) {
805
805
  * @returns {AST.Property}
806
806
  */
807
807
  function create_helper_props_property(binding) {
808
- const key = clone_identifier(binding);
809
- const value = clone_identifier(binding);
808
+ const key = create_generated_identifier(binding.name);
809
+ const value = create_generated_identifier(binding.name);
810
810
 
811
811
  return /** @type {any} */ ({
812
812
  type: 'Property',
@@ -824,38 +824,46 @@ function create_helper_props_property(binding) {
824
824
  * @param {AST.Identifier} helper_id
825
825
  * @param {AST.Identifier[]} bindings
826
826
  * @param {any} source_node
827
+ * @param {{
828
+ * mapWrapper?: boolean,
829
+ * mapBindingNames?: boolean,
830
+ * mapBindingValues?: boolean,
831
+ * }} [mapping]
827
832
  * @returns {ESTreeJSX.JSXElement}
828
833
  */
829
- function create_helper_component_element(helper_id, bindings, source_node) {
834
+ function create_helper_component_element(helper_id, bindings, source_node, mapping = {}) {
835
+ const { mapWrapper = true, mapBindingNames = true, mapBindingValues = true } = mapping;
830
836
  const attributes = bindings.map(
831
837
  (binding) =>
832
838
  /** @type {any} */ ({
833
839
  type: 'JSXAttribute',
834
- name: identifier_to_jsx_name(clone_identifier(binding)),
835
- value: to_jsx_expression_container(clone_identifier(binding), binding),
840
+ name: identifier_to_jsx_name(
841
+ mapBindingNames ? clone_identifier(binding) : create_generated_identifier(binding.name),
842
+ ),
843
+ value: to_jsx_expression_container(
844
+ mapBindingValues ? clone_identifier(binding) : create_generated_identifier(binding.name),
845
+ binding,
846
+ ),
836
847
  metadata: { path: [] },
837
848
  }),
838
849
  );
839
850
 
840
- return set_loc(
841
- /** @type {any} */ ({
842
- type: 'JSXElement',
843
- openingElement: set_loc(
844
- {
845
- type: 'JSXOpeningElement',
846
- name: identifier_to_jsx_name(clone_identifier(helper_id)),
847
- attributes,
848
- selfClosing: true,
849
- metadata: { path: [] },
850
- },
851
- source_node,
852
- ),
853
- closingElement: null,
854
- children: [],
855
- metadata: { path: [] },
856
- }),
857
- source_node,
858
- );
851
+ const openingElement = {
852
+ type: 'JSXOpeningElement',
853
+ name: identifier_to_jsx_name(clone_identifier(helper_id)),
854
+ attributes,
855
+ selfClosing: true,
856
+ metadata: { path: [] },
857
+ };
858
+ const element = /** @type {any} */ ({
859
+ type: 'JSXElement',
860
+ openingElement: mapWrapper ? set_loc(openingElement, source_node) : openingElement,
861
+ closingElement: null,
862
+ children: [],
863
+ metadata: { path: [] },
864
+ });
865
+
866
+ return mapWrapper ? set_loc(element, source_node) : element;
859
867
  }
860
868
 
861
869
  /**
@@ -1117,12 +1125,23 @@ function is_lone_return_if_statement(node) {
1117
1125
  /**
1118
1126
  * @param {any[]} render_nodes
1119
1127
  * @param {any} source_node
1128
+ * @param {boolean} [map_render_node_locations]
1120
1129
  * @returns {any}
1121
1130
  */
1122
- function create_component_return_statement(render_nodes, source_node) {
1131
+ function create_component_return_statement(
1132
+ render_nodes,
1133
+ source_node,
1134
+ map_render_node_locations = true,
1135
+ ) {
1123
1136
  return /** @type {any} */ ({
1124
1137
  type: 'ReturnStatement',
1125
- argument: build_return_expression(render_nodes.slice()) || {
1138
+ argument: build_return_expression(
1139
+ render_nodes.map((node) =>
1140
+ map_render_node_locations
1141
+ ? clone_expression_node(node)
1142
+ : clone_expression_node_without_locations(node),
1143
+ ),
1144
+ ) || {
1126
1145
  type: 'Literal',
1127
1146
  value: null,
1128
1147
  raw: 'null',
@@ -1148,7 +1167,7 @@ function create_component_lone_return_if_statement(node, render_nodes) {
1148
1167
  consequent: set_loc(
1149
1168
  /** @type {any} */ ({
1150
1169
  type: 'BlockStatement',
1151
- body: [create_component_return_statement(render_nodes, consequent_body[0])],
1170
+ body: [create_component_return_statement(render_nodes, consequent_body[0], false)],
1152
1171
  metadata: { path: [] },
1153
1172
  }),
1154
1173
  node.consequent,
@@ -1160,6 +1179,30 @@ function create_component_lone_return_if_statement(node, render_nodes) {
1160
1179
  );
1161
1180
  }
1162
1181
 
1182
+ /**
1183
+ * @param {any} node
1184
+ * @returns {any}
1185
+ */
1186
+ function clone_expression_node_without_locations(node) {
1187
+ if (!node || typeof node !== 'object') return node;
1188
+ if (Array.isArray(node)) return node.map(clone_expression_node_without_locations);
1189
+
1190
+ const clone = { ...node };
1191
+ delete clone.loc;
1192
+ delete clone.start;
1193
+ delete clone.end;
1194
+
1195
+ for (const key of Object.keys(clone)) {
1196
+ if (key === 'metadata') {
1197
+ clone.metadata = clone.metadata ? { ...clone.metadata } : { path: [] };
1198
+ continue;
1199
+ }
1200
+ clone[key] = clone_expression_node_without_locations(clone[key]);
1201
+ }
1202
+
1203
+ return clone;
1204
+ }
1205
+
1163
1206
  const TEMPLATE_FRAGMENT_ERROR =
1164
1207
  'JSX fragment syntax is not needed in TSRX templates. TSRX renders in immediate mode, so everything is already a fragment. Use `<>...</>` only within <tsx>...</tsx>.';
1165
1208
 
@@ -1349,9 +1392,8 @@ function statement_body_to_jsx_child(body_nodes, transform_context) {
1349
1392
  */
1350
1393
  function hook_safe_statement_body_to_jsx_child(body_nodes, transform_context) {
1351
1394
  const source_node = get_body_source_node(body_nodes);
1352
- const helper_id = set_loc(
1353
- create_generated_identifier(create_local_statement_component_name(transform_context)),
1354
- source_node,
1395
+ const helper_id = create_generated_identifier(
1396
+ create_local_statement_component_name(transform_context),
1355
1397
  );
1356
1398
  const helper_bindings = Array.from(transform_context.available_bindings.values());
1357
1399
 
@@ -1359,26 +1401,23 @@ function hook_safe_statement_body_to_jsx_child(body_nodes, transform_context) {
1359
1401
  const saved_bindings = transform_context.available_bindings;
1360
1402
  transform_context.available_bindings = new Map(saved_bindings);
1361
1403
 
1362
- const helper_fn = set_loc(
1363
- /** @type {any} */ ({
1364
- type: 'FunctionDeclaration',
1365
- id: helper_id,
1366
- params: helper_bindings.length > 0 ? [create_helper_props_pattern(helper_bindings)] : [],
1367
- body: {
1368
- type: 'BlockStatement',
1369
- body: build_render_statements(body_nodes, true, transform_context),
1370
- metadata: { path: [] },
1371
- },
1372
- async: false,
1373
- generator: false,
1374
- metadata: {
1375
- path: [],
1376
- is_component: true,
1377
- is_method: false,
1378
- },
1379
- }),
1380
- source_node,
1381
- );
1404
+ const helper_fn = /** @type {any} */ ({
1405
+ type: 'FunctionDeclaration',
1406
+ id: helper_id,
1407
+ params: helper_bindings.length > 0 ? [create_helper_props_pattern(helper_bindings)] : [],
1408
+ body: {
1409
+ type: 'BlockStatement',
1410
+ body: build_render_statements(body_nodes, true, transform_context),
1411
+ metadata: { path: [] },
1412
+ },
1413
+ async: false,
1414
+ generator: false,
1415
+ metadata: {
1416
+ path: [],
1417
+ is_component: true,
1418
+ is_method: false,
1419
+ },
1420
+ });
1382
1421
 
1383
1422
  // Restore bindings
1384
1423
  transform_context.available_bindings = saved_bindings;
@@ -1388,7 +1427,13 @@ function hook_safe_statement_body_to_jsx_child(body_nodes, transform_context) {
1388
1427
  transform_context.helper_state.helpers.push(helper_fn);
1389
1428
 
1390
1429
  return to_jsx_expression_container(
1391
- /** @type {any} */ (create_helper_component_element(helper_id, helper_bindings, source_node)),
1430
+ /** @type {any} */ (
1431
+ create_helper_component_element(helper_id, helper_bindings, source_node, {
1432
+ mapWrapper: false,
1433
+ mapBindingNames: false,
1434
+ mapBindingValues: false,
1435
+ })
1436
+ ),
1392
1437
  source_node,
1393
1438
  );
1394
1439
  }
@@ -1405,7 +1450,11 @@ function hook_safe_statement_body_to_jsx_child(body_nodes, transform_context) {
1405
1450
  helper_fn,
1406
1451
  {
1407
1452
  type: 'ReturnStatement',
1408
- argument: create_helper_component_element(helper_id, helper_bindings, source_node),
1453
+ argument: create_helper_component_element(helper_id, helper_bindings, source_node, {
1454
+ mapWrapper: false,
1455
+ mapBindingNames: false,
1456
+ mapBindingValues: false,
1457
+ }),
1409
1458
  metadata: { path: [] },
1410
1459
  },
1411
1460
  ],
@@ -1448,9 +1497,8 @@ function create_local_statement_component_name(transform_context) {
1448
1497
  */
1449
1498
  function hook_safe_render_statements(body_nodes, key_expression, transform_context) {
1450
1499
  const source_node = get_body_source_node(body_nodes);
1451
- const helper_id = set_loc(
1452
- create_generated_identifier(create_local_statement_component_name(transform_context)),
1453
- source_node,
1500
+ const helper_id = create_generated_identifier(
1501
+ create_local_statement_component_name(transform_context),
1454
1502
  );
1455
1503
  const helper_bindings = Array.from(transform_context.available_bindings.values());
1456
1504
 
@@ -1458,26 +1506,23 @@ function hook_safe_render_statements(body_nodes, key_expression, transform_conte
1458
1506
  const saved_bindings = transform_context.available_bindings;
1459
1507
  transform_context.available_bindings = new Map(saved_bindings);
1460
1508
 
1461
- const helper_fn = set_loc(
1462
- /** @type {any} */ ({
1463
- type: 'FunctionDeclaration',
1464
- id: helper_id,
1465
- params: helper_bindings.length > 0 ? [create_helper_props_pattern(helper_bindings)] : [],
1466
- body: {
1467
- type: 'BlockStatement',
1468
- body: build_render_statements(body_nodes, true, transform_context),
1469
- metadata: { path: [] },
1470
- },
1471
- async: false,
1472
- generator: false,
1473
- metadata: {
1474
- path: [],
1475
- is_component: true,
1476
- is_method: false,
1477
- },
1478
- }),
1479
- source_node,
1480
- );
1509
+ const helper_fn = /** @type {any} */ ({
1510
+ type: 'FunctionDeclaration',
1511
+ id: helper_id,
1512
+ params: helper_bindings.length > 0 ? [create_helper_props_pattern(helper_bindings)] : [],
1513
+ body: {
1514
+ type: 'BlockStatement',
1515
+ body: build_render_statements(body_nodes, true, transform_context),
1516
+ metadata: { path: [] },
1517
+ },
1518
+ async: false,
1519
+ generator: false,
1520
+ metadata: {
1521
+ path: [],
1522
+ is_component: true,
1523
+ is_method: false,
1524
+ },
1525
+ });
1481
1526
 
1482
1527
  // Restore bindings
1483
1528
  transform_context.available_bindings = saved_bindings;
@@ -1491,6 +1536,11 @@ function hook_safe_render_statements(body_nodes, key_expression, transform_conte
1491
1536
  helper_id,
1492
1537
  helper_bindings,
1493
1538
  source_node,
1539
+ {
1540
+ mapWrapper: false,
1541
+ mapBindingNames: false,
1542
+ mapBindingValues: false,
1543
+ },
1494
1544
  );
1495
1545
 
1496
1546
  if (key_expression) {
@@ -761,7 +761,8 @@ export function convert_source_map_to_mappings(
761
761
  // Add function/component keyword token
762
762
  if (
763
763
  (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') &&
764
- !is_method
764
+ !is_method &&
765
+ node.loc
765
766
  ) {
766
767
  const node_fn = /** @type (typeof node) & AST.NodeWithLocation */ (node);
767
768
  const is_component = node_fn.metadata?.is_component;
@@ -2250,21 +2251,25 @@ export function create_volar_mappings_result({
2250
2251
  * @returns {CodeMapping[]}
2251
2252
  */
2252
2253
  export function dedupe_mappings(mappings) {
2253
- const deduped = [];
2254
- const seen = new Set();
2254
+ // keep for now more for testing and maybe logging later.
2255
+ // We should not use deduping and instead should be
2256
+ // fixing source map generation or mapping generation
2257
+ return mappings;
2258
+ // const deduped = [];
2259
+ // const seen = new Set();
2255
2260
 
2256
- for (const mapping of mappings) {
2257
- const key = JSON.stringify(serialize_mapping_value(mapping));
2261
+ // for (const mapping of mappings) {
2262
+ // const key = JSON.stringify(serialize_mapping_value(mapping));
2258
2263
 
2259
- if (seen.has(key)) {
2260
- continue;
2261
- }
2264
+ // if (seen.has(key)) {
2265
+ // continue;
2266
+ // }
2262
2267
 
2263
- seen.add(key);
2264
- deduped.push(mapping);
2265
- }
2268
+ // seen.add(key);
2269
+ // deduped.push(mapping);
2270
+ // }
2266
2271
 
2267
- return deduped;
2272
+ // return deduped;
2268
2273
  }
2269
2274
 
2270
2275
  /**
package/types/parse.d.ts CHANGED
@@ -1639,7 +1639,7 @@ export namespace Parse {
1639
1639
  * Parse JSX attribute (name="value" or {spread})
1640
1640
  * @returns JSXAttribute or JSXSpreadAttribute
1641
1641
  */
1642
- jsx_parseAttribute(): AST.TSRXAttribute | ESTreeJSX.JSXAttribute;
1642
+ jsx_parseAttribute(): AST.TSRXAttribute | ESTreeJSX.JSXAttribute | ESTreeJSX.JSXSpreadAttribute;
1643
1643
 
1644
1644
  /**
1645
1645
  * Parse JSX opening element at position