@tsrx/core 0.1.33 → 0.1.34
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 +1 -1
- package/src/source-map-utils.js +11 -0
- package/src/transform/jsx/index.js +78 -22
- package/src/transform/segments.js +22 -1
- package/src/utils/builders.js +6 -3
- package/types/index.d.ts +11 -1
package/package.json
CHANGED
package/src/source-map-utils.js
CHANGED
|
@@ -50,6 +50,17 @@ export const mapping_data_verify_complete = {
|
|
|
50
50
|
completion: true,
|
|
51
51
|
};
|
|
52
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Completion only — no verification/hover/navigation. Used for positions that
|
|
55
|
+
* should surface completions but must not be type-checked, e.g. a `@`-leading text
|
|
56
|
+
* node that is an in-progress template directive (verifying it as code would raise
|
|
57
|
+
* spurious diagnostics).
|
|
58
|
+
* @type {Partial<VolarCodeMapping['data']>}
|
|
59
|
+
*/
|
|
60
|
+
export const mapping_data_completion_only = {
|
|
61
|
+
completion: true,
|
|
62
|
+
};
|
|
63
|
+
|
|
53
64
|
/**
|
|
54
65
|
* Convert byte offset to line/column
|
|
55
66
|
* @param {number} offset
|
|
@@ -1202,7 +1202,9 @@ function build_render_statements(
|
|
|
1202
1202
|
const child = body_nodes[i];
|
|
1203
1203
|
|
|
1204
1204
|
if (is_loop_skip_return_statement(child)) {
|
|
1205
|
-
statements.push(
|
|
1205
|
+
statements.push(
|
|
1206
|
+
create_component_return_statement(render_nodes, child, true, transform_context.typeOnly),
|
|
1207
|
+
);
|
|
1206
1208
|
render_nodes.length = 0;
|
|
1207
1209
|
has_terminal_return = true;
|
|
1208
1210
|
continue;
|
|
@@ -1314,7 +1316,7 @@ function build_render_statements(
|
|
|
1314
1316
|
hoist_static_render_nodes(render_nodes, transform_context);
|
|
1315
1317
|
}
|
|
1316
1318
|
|
|
1317
|
-
let return_arg = build_return_expression(render_nodes);
|
|
1319
|
+
let return_arg = build_return_expression(render_nodes, false, transform_context.typeOnly);
|
|
1318
1320
|
// Keep an authored `<> … </>` render output verbatim instead of collapsing it:
|
|
1319
1321
|
// an empty `<></>` stays `<></>` (not `null`), and a single child stays wrapped
|
|
1320
1322
|
// (not its bare value). The `!== 'JSXFragment'` guard avoids double-wrapping a
|
|
@@ -3142,18 +3144,23 @@ function get_generated_component_metadata_list(node) {
|
|
|
3142
3144
|
* @param {any[]} render_nodes
|
|
3143
3145
|
* @param {any} source_node
|
|
3144
3146
|
* @param {boolean} [map_render_node_locations]
|
|
3147
|
+
* @param {boolean} [type_only]
|
|
3145
3148
|
* @returns {any}
|
|
3146
3149
|
*/
|
|
3147
3150
|
function create_component_return_statement(
|
|
3148
3151
|
render_nodes,
|
|
3149
3152
|
source_node,
|
|
3150
3153
|
map_render_node_locations = true,
|
|
3154
|
+
type_only = false,
|
|
3151
3155
|
) {
|
|
3152
3156
|
const cloned = render_nodes.map((node) =>
|
|
3153
3157
|
map_render_node_locations ? clone_expression_node(node) : clone_expression_node(node, false),
|
|
3154
3158
|
);
|
|
3155
3159
|
|
|
3156
|
-
return set_loc(
|
|
3160
|
+
return set_loc(
|
|
3161
|
+
b.return(build_return_expression(cloned, false, type_only) || create_null_literal()),
|
|
3162
|
+
source_node,
|
|
3163
|
+
);
|
|
3157
3164
|
}
|
|
3158
3165
|
|
|
3159
3166
|
/**
|
|
@@ -3196,7 +3203,11 @@ function get_loop_skip_if_consequent_body(node) {
|
|
|
3196
3203
|
function create_component_loop_skip_if_statement(node, render_nodes, transform_context) {
|
|
3197
3204
|
const consequent_body = /** @type {any[]} */ (get_loop_skip_if_consequent_body(node));
|
|
3198
3205
|
const branch_statements = build_render_statements(consequent_body, true, transform_context);
|
|
3199
|
-
prepend_render_nodes_to_return_statements(
|
|
3206
|
+
prepend_render_nodes_to_return_statements(
|
|
3207
|
+
branch_statements,
|
|
3208
|
+
render_nodes,
|
|
3209
|
+
transform_context.typeOnly,
|
|
3210
|
+
);
|
|
3200
3211
|
|
|
3201
3212
|
const statement = set_loc(
|
|
3202
3213
|
b.if(node.test, set_loc(b.block(branch_statements), node.consequent), null),
|
|
@@ -3212,15 +3223,16 @@ function create_component_loop_skip_if_statement(node, render_nodes, transform_c
|
|
|
3212
3223
|
/**
|
|
3213
3224
|
* @param {any[]} statements
|
|
3214
3225
|
* @param {any[]} render_nodes
|
|
3226
|
+
* @param {boolean} [type_only]
|
|
3215
3227
|
* @returns {void}
|
|
3216
3228
|
*/
|
|
3217
|
-
function prepend_render_nodes_to_return_statements(statements, render_nodes) {
|
|
3229
|
+
function prepend_render_nodes_to_return_statements(statements, render_nodes, type_only = false) {
|
|
3218
3230
|
if (render_nodes.length === 0) {
|
|
3219
3231
|
return;
|
|
3220
3232
|
}
|
|
3221
3233
|
|
|
3222
3234
|
for (const statement of statements) {
|
|
3223
|
-
prepend_render_nodes_to_return_statement(statement, render_nodes, false);
|
|
3235
|
+
prepend_render_nodes_to_return_statement(statement, render_nodes, false, type_only);
|
|
3224
3236
|
}
|
|
3225
3237
|
}
|
|
3226
3238
|
|
|
@@ -3228,9 +3240,15 @@ function prepend_render_nodes_to_return_statements(statements, render_nodes) {
|
|
|
3228
3240
|
* @param {any} node
|
|
3229
3241
|
* @param {any[]} render_nodes
|
|
3230
3242
|
* @param {boolean} inside_nested_function
|
|
3243
|
+
* @param {boolean} [type_only]
|
|
3231
3244
|
* @returns {void}
|
|
3232
3245
|
*/
|
|
3233
|
-
function prepend_render_nodes_to_return_statement(
|
|
3246
|
+
function prepend_render_nodes_to_return_statement(
|
|
3247
|
+
node,
|
|
3248
|
+
render_nodes,
|
|
3249
|
+
inside_nested_function,
|
|
3250
|
+
type_only = false,
|
|
3251
|
+
) {
|
|
3234
3252
|
if (!node || typeof node !== 'object') {
|
|
3235
3253
|
return;
|
|
3236
3254
|
}
|
|
@@ -3244,13 +3262,18 @@ function prepend_render_nodes_to_return_statement(node, render_nodes, inside_nes
|
|
|
3244
3262
|
}
|
|
3245
3263
|
|
|
3246
3264
|
if (!inside_nested_function && node.type === 'ReturnStatement') {
|
|
3247
|
-
node.argument = combine_render_return_argument(render_nodes, node.argument);
|
|
3265
|
+
node.argument = combine_render_return_argument(render_nodes, node.argument, type_only);
|
|
3248
3266
|
return;
|
|
3249
3267
|
}
|
|
3250
3268
|
|
|
3251
3269
|
if (Array.isArray(node)) {
|
|
3252
3270
|
for (const child of node) {
|
|
3253
|
-
prepend_render_nodes_to_return_statement(
|
|
3271
|
+
prepend_render_nodes_to_return_statement(
|
|
3272
|
+
child,
|
|
3273
|
+
render_nodes,
|
|
3274
|
+
inside_nested_function,
|
|
3275
|
+
type_only,
|
|
3276
|
+
);
|
|
3254
3277
|
}
|
|
3255
3278
|
return;
|
|
3256
3279
|
}
|
|
@@ -3259,23 +3282,29 @@ function prepend_render_nodes_to_return_statement(node, render_nodes, inside_nes
|
|
|
3259
3282
|
if (key === 'loc' || key === 'start' || key === 'end' || key === 'metadata') {
|
|
3260
3283
|
continue;
|
|
3261
3284
|
}
|
|
3262
|
-
prepend_render_nodes_to_return_statement(
|
|
3285
|
+
prepend_render_nodes_to_return_statement(
|
|
3286
|
+
node[key],
|
|
3287
|
+
render_nodes,
|
|
3288
|
+
inside_nested_function,
|
|
3289
|
+
type_only,
|
|
3290
|
+
);
|
|
3263
3291
|
}
|
|
3264
3292
|
}
|
|
3265
3293
|
|
|
3266
3294
|
/**
|
|
3267
3295
|
* @param {any[]} render_nodes
|
|
3268
3296
|
* @param {any} return_argument
|
|
3297
|
+
* @param {boolean} [type_only]
|
|
3269
3298
|
* @returns {any}
|
|
3270
3299
|
*/
|
|
3271
|
-
function combine_render_return_argument(render_nodes, return_argument) {
|
|
3300
|
+
function combine_render_return_argument(render_nodes, return_argument, type_only = false) {
|
|
3272
3301
|
const combined = render_nodes.map((node) => clone_expression_node(node, false));
|
|
3273
3302
|
|
|
3274
3303
|
if (return_argument != null && !is_null_literal(return_argument)) {
|
|
3275
3304
|
combined.push(return_argument_to_render_node(return_argument));
|
|
3276
3305
|
}
|
|
3277
3306
|
|
|
3278
|
-
return build_return_expression(combined) || create_null_literal();
|
|
3307
|
+
return build_return_expression(combined, false, type_only) || create_null_literal();
|
|
3279
3308
|
}
|
|
3280
3309
|
|
|
3281
3310
|
/**
|
|
@@ -4284,7 +4313,9 @@ export function wrap_edge_whitespace(nodes) {
|
|
|
4284
4313
|
}
|
|
4285
4314
|
}
|
|
4286
4315
|
if (value !== '') {
|
|
4287
|
-
|
|
4316
|
+
// keep the location as we need it for @ autocomplete
|
|
4317
|
+
// and perhaps other things in the future
|
|
4318
|
+
out.push(b.jsx_text(value, value, node));
|
|
4288
4319
|
}
|
|
4289
4320
|
if (trailing) {
|
|
4290
4321
|
out.push(trailing);
|
|
@@ -4412,7 +4443,9 @@ function tsrx_node_to_jsx_expression(node, transform_context, in_jsx_child = fal
|
|
|
4412
4443
|
const render_nodes = wrap_edge_whitespace(
|
|
4413
4444
|
children.map((/** @type {any} */ child) => to_jsx_child(child, transform_context)),
|
|
4414
4445
|
);
|
|
4415
|
-
expression =
|
|
4446
|
+
expression =
|
|
4447
|
+
build_return_expression(render_nodes, in_jsx_child, transform_context.typeOnly) ||
|
|
4448
|
+
create_null_literal();
|
|
4416
4449
|
} finally {
|
|
4417
4450
|
transform_context.inside_element_child = saved_inside_element_child;
|
|
4418
4451
|
}
|
|
@@ -5605,7 +5638,12 @@ function build_switch_with_lift(switch_node, transform_context) {
|
|
|
5605
5638
|
if (helper) {
|
|
5606
5639
|
return set_loc(
|
|
5607
5640
|
b.switch_case(original_case.test, [
|
|
5608
|
-
create_component_return_statement(
|
|
5641
|
+
create_component_return_statement(
|
|
5642
|
+
[helper.component_element],
|
|
5643
|
+
original_case,
|
|
5644
|
+
true,
|
|
5645
|
+
transform_context.typeOnly,
|
|
5646
|
+
),
|
|
5609
5647
|
]),
|
|
5610
5648
|
original_case,
|
|
5611
5649
|
);
|
|
@@ -5626,7 +5664,14 @@ function build_switch_with_lift(switch_node, transform_context) {
|
|
|
5626
5664
|
|
|
5627
5665
|
for (const child of own_body) {
|
|
5628
5666
|
if (is_loop_skip_return_statement(child)) {
|
|
5629
|
-
case_body.push(
|
|
5667
|
+
case_body.push(
|
|
5668
|
+
create_component_return_statement(
|
|
5669
|
+
render_nodes,
|
|
5670
|
+
child,
|
|
5671
|
+
true,
|
|
5672
|
+
transform_context.typeOnly,
|
|
5673
|
+
),
|
|
5674
|
+
);
|
|
5630
5675
|
has_terminal = true;
|
|
5631
5676
|
break;
|
|
5632
5677
|
}
|
|
@@ -5646,7 +5691,14 @@ function build_switch_with_lift(switch_node, transform_context) {
|
|
|
5646
5691
|
|
|
5647
5692
|
if (!has_terminal) {
|
|
5648
5693
|
if (render_nodes.length > 0) {
|
|
5649
|
-
case_body.push(
|
|
5694
|
+
case_body.push(
|
|
5695
|
+
create_component_return_statement(
|
|
5696
|
+
render_nodes,
|
|
5697
|
+
original_case,
|
|
5698
|
+
true,
|
|
5699
|
+
transform_context.typeOnly,
|
|
5700
|
+
),
|
|
5701
|
+
);
|
|
5650
5702
|
} else if (case_body.length > 0) {
|
|
5651
5703
|
case_body.push(create_null_return_statement());
|
|
5652
5704
|
} else if (has_terminator) {
|
|
@@ -6199,7 +6251,7 @@ function value_has_unmappable_jsx_loc(value) {
|
|
|
6199
6251
|
* @param {boolean} [in_jsx_child]
|
|
6200
6252
|
* @returns {any}
|
|
6201
6253
|
*/
|
|
6202
|
-
export function build_return_expression(render_nodes, in_jsx_child = false) {
|
|
6254
|
+
export function build_return_expression(render_nodes, in_jsx_child = false, type_only = false) {
|
|
6203
6255
|
if (render_nodes.length === 0) return null;
|
|
6204
6256
|
if (render_nodes.length === 1) {
|
|
6205
6257
|
const only = render_nodes[0];
|
|
@@ -6213,11 +6265,15 @@ export function build_return_expression(render_nodes, in_jsx_child = false) {
|
|
|
6213
6265
|
return only.expression;
|
|
6214
6266
|
}
|
|
6215
6267
|
if (only.type === 'JSXText') {
|
|
6216
|
-
|
|
6217
|
-
|
|
6268
|
+
// Keep a single text child faithful to the source (e.g. `<>@</>`) — never
|
|
6269
|
+
// promote it to a `{'text'}` string-literal expression, in either the
|
|
6270
|
+
// type-only editor view or runtime codegen. At runtime we additionally drop a
|
|
6271
|
+
// nullish/whitespace-only child so it renders nothing instead of emitting
|
|
6272
|
+
// empty output.
|
|
6273
|
+
if (!type_only && !in_jsx_child && (only.value ?? '').trim() === '') {
|
|
6274
|
+
return null;
|
|
6218
6275
|
}
|
|
6219
|
-
|
|
6220
|
-
return b.literal(value, JSON.stringify(value), only);
|
|
6276
|
+
return set_loc(b.jsx_fragment([only]), only.loc ? only : undefined);
|
|
6221
6277
|
}
|
|
6222
6278
|
return only;
|
|
6223
6279
|
}
|
|
@@ -53,6 +53,7 @@ import {
|
|
|
53
53
|
mapping_data,
|
|
54
54
|
mapping_data_verify_only,
|
|
55
55
|
mapping_data_verify_complete,
|
|
56
|
+
mapping_data_completion_only,
|
|
56
57
|
build_line_offsets,
|
|
57
58
|
get_mapping_from_node,
|
|
58
59
|
} from '../source-map-utils.js';
|
|
@@ -806,7 +807,27 @@ export function convert_source_map_to_mappings(
|
|
|
806
807
|
}
|
|
807
808
|
return;
|
|
808
809
|
} else if (node.type === 'JSXText') {
|
|
809
|
-
//
|
|
810
|
+
// A text node whose first non-whitespace char is `@` is an in-progress template
|
|
811
|
+
// directive (`@`, `@i`, `@if …`) the parser recovered as text; emit a completion-only
|
|
812
|
+
// mapping so the editor can still offer `@if`/`@for`/`@switch`/`@try` completions there.
|
|
813
|
+
//
|
|
814
|
+
// Use a token (resolved by matching generated CONTENT) rather than get_mapping_from_node.
|
|
815
|
+
// At a control-flow boundary the text node's source start maps to several generated
|
|
816
|
+
// positions — e.g. a preceding `@switch` value-IIFE's `return null; })()` tail AND the
|
|
817
|
+
// text itself — and get_mapping_from_node just takes the first, so its generated length
|
|
818
|
+
// spans the wrong region and the editor can't map a completion's edit back to source
|
|
819
|
+
// (it then drops the item). The token resolves to the position whose generated text
|
|
820
|
+
// matches the node's value, giving a well-formed same-length mapping. Ripple keeps text
|
|
821
|
+
// verbatim in to_ts, so `source` and `generated` are identical. Other text stays unmapped.
|
|
822
|
+
if (node.loc && typeof node.value === 'string' && node.value.trimStart().startsWith('@')) {
|
|
823
|
+
tokens.push({
|
|
824
|
+
source: node.value,
|
|
825
|
+
generated: node.value,
|
|
826
|
+
loc: node.loc,
|
|
827
|
+
metadata: {},
|
|
828
|
+
mappingData: mapping_data_completion_only,
|
|
829
|
+
});
|
|
830
|
+
}
|
|
810
831
|
return;
|
|
811
832
|
} else if (node.type === 'JSXCodeBlock') {
|
|
812
833
|
for (const statement of node.body) {
|
package/src/utils/builders.js
CHANGED
|
@@ -1369,15 +1369,18 @@ export function jsx_spread_attribute(argument, loc_info) {
|
|
|
1369
1369
|
/**
|
|
1370
1370
|
* @param {string} value
|
|
1371
1371
|
* @param {string} raw
|
|
1372
|
+
* @param {AST.NodeWithLocation} [loc_info]
|
|
1372
1373
|
* @returns {ESTreeJSX.JSXText}
|
|
1373
1374
|
*/
|
|
1374
|
-
export function jsx_text(value, raw) {
|
|
1375
|
-
|
|
1375
|
+
export function jsx_text(value, raw, loc_info) {
|
|
1376
|
+
const node = /** @type {ESTreeJSX.JSXText} */ ({
|
|
1376
1377
|
type: 'JSXText',
|
|
1377
1378
|
value,
|
|
1378
1379
|
raw,
|
|
1379
1380
|
metadata: { path: [] },
|
|
1380
|
-
};
|
|
1381
|
+
});
|
|
1382
|
+
|
|
1383
|
+
return set_location(node, loc_info);
|
|
1381
1384
|
}
|
|
1382
1385
|
|
|
1383
1386
|
/**
|
package/types/index.d.ts
CHANGED
|
@@ -1480,6 +1480,13 @@ export interface TransformServerState extends BaseState {
|
|
|
1480
1480
|
dev?: boolean;
|
|
1481
1481
|
return_flags?: Map<AST.ReturnStatement, { name: string; tracked: boolean }>;
|
|
1482
1482
|
template_child?: boolean;
|
|
1483
|
+
/**
|
|
1484
|
+
* True while transforming the direct body of a control-flow branch
|
|
1485
|
+
* (`@if`/`@else`/`@for`/`@switch`/`@try`). A `<>…</>` in this position is
|
|
1486
|
+
* bracketed with hydration block markers so the client's fragment
|
|
1487
|
+
* `expression()` finds a matching boundary during hydration.
|
|
1488
|
+
*/
|
|
1489
|
+
control_flow_branch_body?: boolean;
|
|
1483
1490
|
skip_regular_blocks?: boolean;
|
|
1484
1491
|
in_regular_block?: boolean;
|
|
1485
1492
|
is_tsrx_element?: boolean;
|
|
@@ -1564,7 +1571,10 @@ export type TransformClientContext = Context<AST.Node, TransformClientState>;
|
|
|
1564
1571
|
export type TransformServerContext = Context<AST.Node, TransformServerState>;
|
|
1565
1572
|
export type AnalysisContext = Context<AST.Node, AnalysisState>;
|
|
1566
1573
|
export type CommonContext = TransformClientContext | TransformServerContext | AnalysisContext;
|
|
1567
|
-
export type VisitorClientContext = TransformClientContext & {
|
|
1574
|
+
export type VisitorClientContext = TransformClientContext & {
|
|
1575
|
+
root?: boolean;
|
|
1576
|
+
value_position?: boolean;
|
|
1577
|
+
};
|
|
1568
1578
|
|
|
1569
1579
|
/**
|
|
1570
1580
|
* Delegated event result
|