@tsrx/core 0.0.12 → 0.0.14
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/analyze/validation.js +47 -0
- package/src/index.js +11 -1
- package/src/plugin.js +295 -24
- package/src/transform/jsx/helpers.js +25 -1
- package/src/transform/jsx/index.js +666 -425
- package/src/transform/lazy.js +185 -13
- package/src/transform/segments.js +134 -19
- package/src/utils/ast.js +61 -0
- package/types/index.d.ts +17 -0
- package/types/parse.d.ts +1 -1
package/src/transform/lazy.js
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
|
-
* @typedef {{ source_name: string, read: () => any }} LazyBinding
|
|
29
|
+
* @typedef {{ source_name: string, read: (reference?: any) => any }} LazyBinding
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
32
|
/**
|
|
@@ -46,12 +46,169 @@ function generate_lazy_id(context) {
|
|
|
46
46
|
return `__lazy${context.lazy_next_id++}`;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* @param {any} node
|
|
51
|
+
* @param {any} [loc_info]
|
|
52
|
+
* @returns {any}
|
|
53
|
+
*/
|
|
54
|
+
function set_source_location(node, loc_info) {
|
|
55
|
+
if (loc_info?.loc) {
|
|
56
|
+
node.start = loc_info.start;
|
|
57
|
+
node.end = loc_info.end;
|
|
58
|
+
node.loc = loc_info.loc;
|
|
59
|
+
}
|
|
60
|
+
return node;
|
|
61
|
+
}
|
|
62
|
+
|
|
49
63
|
/**
|
|
50
64
|
* @param {string} name
|
|
65
|
+
* @param {any} [loc_info]
|
|
66
|
+
* @param {string} [source_name]
|
|
67
|
+
* @param {number} [source_length]
|
|
51
68
|
* @returns {any}
|
|
52
69
|
*/
|
|
53
|
-
function create_generated_identifier(name) {
|
|
54
|
-
|
|
70
|
+
function create_generated_identifier(name, loc_info, source_name, source_length) {
|
|
71
|
+
const id = /** @type {any} */ ({ type: 'Identifier', name, metadata: { path: [] } });
|
|
72
|
+
if (source_name && source_name !== name) id.metadata.source_name = source_name;
|
|
73
|
+
if (source_length != null) id.metadata.source_length = source_length;
|
|
74
|
+
return set_source_location(id, loc_info);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @param {any} pattern
|
|
79
|
+
* @returns {{ start: number, end: number, loc: any, source_length: number } | null}
|
|
80
|
+
*/
|
|
81
|
+
function get_lazy_pattern_mapping_range(pattern) {
|
|
82
|
+
if (!pattern.loc) return null;
|
|
83
|
+
|
|
84
|
+
const end = pattern.typeAnnotation?.start ?? pattern.end;
|
|
85
|
+
const end_loc = pattern.typeAnnotation?.loc?.start ?? pattern.loc.end;
|
|
86
|
+
return {
|
|
87
|
+
start: pattern.start,
|
|
88
|
+
end,
|
|
89
|
+
loc: {
|
|
90
|
+
start: pattern.loc.start,
|
|
91
|
+
end: end_loc,
|
|
92
|
+
},
|
|
93
|
+
source_length: end - pattern.start,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Synthesize an object-shaped annotation for untyped lazy object params so the
|
|
99
|
+
* virtual TSX can expose prop names to TypeScript completions.
|
|
100
|
+
*
|
|
101
|
+
* @param {any} pattern
|
|
102
|
+
* @returns {any | null}
|
|
103
|
+
*/
|
|
104
|
+
function create_lazy_object_type_annotation(pattern) {
|
|
105
|
+
if (pattern.type !== 'ObjectPattern') return null;
|
|
106
|
+
|
|
107
|
+
const members = [];
|
|
108
|
+
for (const prop of pattern.properties || []) {
|
|
109
|
+
if (prop.type === 'RestElement' || prop.computed) continue;
|
|
110
|
+
|
|
111
|
+
const key = prop.key;
|
|
112
|
+
if (key.type !== 'Identifier' && key.type !== 'Literal') continue;
|
|
113
|
+
|
|
114
|
+
members.push({
|
|
115
|
+
type: 'TSPropertySignature',
|
|
116
|
+
key:
|
|
117
|
+
key.type === 'Identifier'
|
|
118
|
+
? create_generated_identifier(key.name, key)
|
|
119
|
+
: set_source_location({ ...key, metadata: { path: [] } }, key),
|
|
120
|
+
computed: false,
|
|
121
|
+
optional: false,
|
|
122
|
+
readonly: false,
|
|
123
|
+
static: false,
|
|
124
|
+
kind: 'init',
|
|
125
|
+
typeAnnotation: {
|
|
126
|
+
type: 'TSTypeAnnotation',
|
|
127
|
+
typeAnnotation: {
|
|
128
|
+
type: 'TSAnyKeyword',
|
|
129
|
+
metadata: { path: [] },
|
|
130
|
+
},
|
|
131
|
+
metadata: { path: [] },
|
|
132
|
+
},
|
|
133
|
+
metadata: { path: [] },
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (members.length === 0) return null;
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
type: 'TSTypeAnnotation',
|
|
141
|
+
typeAnnotation: {
|
|
142
|
+
type: 'TSTypeLiteral',
|
|
143
|
+
members,
|
|
144
|
+
metadata: { path: [] },
|
|
145
|
+
},
|
|
146
|
+
metadata: { path: [] },
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @param {any} node
|
|
152
|
+
* @returns {string | null}
|
|
153
|
+
*/
|
|
154
|
+
function get_static_property_name(node) {
|
|
155
|
+
if (node.type === 'Identifier') return node.name;
|
|
156
|
+
if (node.type === 'Literal') return String(node.value);
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* @param {any} type_annotation
|
|
162
|
+
* @returns {Map<string, any>}
|
|
163
|
+
*/
|
|
164
|
+
function get_type_property_keys(type_annotation) {
|
|
165
|
+
const keys = new Map();
|
|
166
|
+
const members = type_annotation?.typeAnnotation?.members;
|
|
167
|
+
if (!Array.isArray(members)) return keys;
|
|
168
|
+
|
|
169
|
+
for (const member of members) {
|
|
170
|
+
if (member.type !== 'TSPropertySignature' || !member.key) continue;
|
|
171
|
+
const name = get_static_property_name(member.key);
|
|
172
|
+
if (name != null && !keys.has(name)) keys.set(name, member.key);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return keys;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Store extra mappings from lazy object binding identifiers to generated type
|
|
180
|
+
* property keys. Parser diagnostics for duplicate bindings point at the binding
|
|
181
|
+
* names (`&{ a: value, value }`), while the virtual param only exposes object
|
|
182
|
+
* properties (`__lazy0: { a: ...; value: ... }`).
|
|
183
|
+
*
|
|
184
|
+
* @param {any} lazy_id
|
|
185
|
+
* @param {any} pattern
|
|
186
|
+
*/
|
|
187
|
+
function set_lazy_param_binding_mappings(lazy_id, pattern) {
|
|
188
|
+
if (pattern.type !== 'ObjectPattern') return;
|
|
189
|
+
|
|
190
|
+
const type_keys = get_type_property_keys(lazy_id.typeAnnotation);
|
|
191
|
+
if (type_keys.size === 0) return;
|
|
192
|
+
|
|
193
|
+
const mappings = [];
|
|
194
|
+
for (const prop of pattern.properties || []) {
|
|
195
|
+
if (prop.type === 'RestElement' || prop.computed) continue;
|
|
196
|
+
|
|
197
|
+
const value = prop.value;
|
|
198
|
+
const actual = value.type === 'AssignmentPattern' ? value.left : value;
|
|
199
|
+
if (actual.type !== 'Identifier' || !actual.loc) continue;
|
|
200
|
+
|
|
201
|
+
const key_name = get_static_property_name(prop.key);
|
|
202
|
+
const generated = key_name == null ? null : type_keys.get(key_name);
|
|
203
|
+
if (generated?.loc) {
|
|
204
|
+
generated.metadata = { ...generated.metadata, disable_verification: true };
|
|
205
|
+
mappings.push({ source: actual, generated });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (mappings.length > 0) {
|
|
210
|
+
lazy_id.metadata.lazy_param_binding_mappings = mappings;
|
|
211
|
+
}
|
|
55
212
|
}
|
|
56
213
|
|
|
57
214
|
/**
|
|
@@ -76,12 +233,13 @@ export function collect_lazy_bindings(pattern, source_name, lazy_bindings) {
|
|
|
76
233
|
const computed = prop.computed || key.type !== 'Identifier';
|
|
77
234
|
lazy_bindings.set(actual.name, {
|
|
78
235
|
source_name,
|
|
79
|
-
read: () => ({
|
|
236
|
+
read: (reference) => ({
|
|
80
237
|
type: 'MemberExpression',
|
|
81
238
|
object: create_generated_identifier(source_name),
|
|
82
|
-
property:
|
|
83
|
-
|
|
84
|
-
|
|
239
|
+
property:
|
|
240
|
+
computed || key.type !== 'Identifier'
|
|
241
|
+
? { ...key }
|
|
242
|
+
: create_generated_identifier(key.name, reference, reference?.name),
|
|
85
243
|
computed,
|
|
86
244
|
optional: false,
|
|
87
245
|
metadata: { path: [] },
|
|
@@ -491,7 +649,7 @@ export function apply_lazy_transforms(node, lazy_bindings) {
|
|
|
491
649
|
const binding = /** @type {LazyBinding} */ (lazy_bindings.get(node.left.name));
|
|
492
650
|
return {
|
|
493
651
|
...node,
|
|
494
|
-
left: binding.read(),
|
|
652
|
+
left: binding.read(node.left),
|
|
495
653
|
right: apply_lazy_transforms(node.right, lazy_bindings),
|
|
496
654
|
};
|
|
497
655
|
}
|
|
@@ -502,7 +660,7 @@ export function apply_lazy_transforms(node, lazy_bindings) {
|
|
|
502
660
|
lazy_bindings.has(node.argument.name)
|
|
503
661
|
) {
|
|
504
662
|
const binding = /** @type {LazyBinding} */ (lazy_bindings.get(node.argument.name));
|
|
505
|
-
return { ...node, argument: binding.read() };
|
|
663
|
+
return { ...node, argument: binding.read(node.argument) };
|
|
506
664
|
}
|
|
507
665
|
|
|
508
666
|
// Replace lazy variable declaration patterns with generated identifiers.
|
|
@@ -520,14 +678,14 @@ export function apply_lazy_transforms(node, lazy_bindings) {
|
|
|
520
678
|
if (node.type === 'Property' && node.shorthand && node.value?.type === 'Identifier') {
|
|
521
679
|
const binding = lazy_bindings.get(node.value.name);
|
|
522
680
|
if (binding) {
|
|
523
|
-
return { ...node, shorthand: false, value: binding.read() };
|
|
681
|
+
return { ...node, shorthand: false, value: binding.read(node.value) };
|
|
524
682
|
}
|
|
525
683
|
}
|
|
526
684
|
|
|
527
685
|
// Bare identifier reference.
|
|
528
686
|
if (node.type === 'Identifier' && lazy_bindings.has(node.name)) {
|
|
529
687
|
const binding = /** @type {LazyBinding} */ (lazy_bindings.get(node.name));
|
|
530
|
-
return binding.read();
|
|
688
|
+
return binding.read(node);
|
|
531
689
|
}
|
|
532
690
|
|
|
533
691
|
// JSXIdentifier is a label (component/element name), never a reference.
|
|
@@ -654,8 +812,22 @@ export function replace_lazy_params(params) {
|
|
|
654
812
|
pattern.lazy &&
|
|
655
813
|
pattern.metadata?.lazy_id
|
|
656
814
|
) {
|
|
657
|
-
const
|
|
658
|
-
|
|
815
|
+
const pattern_range = get_lazy_pattern_mapping_range(pattern);
|
|
816
|
+
const lazy_id = pattern_range
|
|
817
|
+
? create_generated_identifier(
|
|
818
|
+
pattern.metadata.lazy_id,
|
|
819
|
+
pattern_range,
|
|
820
|
+
undefined,
|
|
821
|
+
pattern_range.source_length,
|
|
822
|
+
)
|
|
823
|
+
: create_generated_identifier(pattern.metadata.lazy_id);
|
|
824
|
+
if (pattern.typeAnnotation) {
|
|
825
|
+
lazy_id.typeAnnotation = pattern.typeAnnotation;
|
|
826
|
+
} else {
|
|
827
|
+
const type_annotation = create_lazy_object_type_annotation(pattern);
|
|
828
|
+
if (type_annotation) lazy_id.typeAnnotation = type_annotation;
|
|
829
|
+
}
|
|
830
|
+
set_lazy_param_binding_mappings(lazy_id, pattern);
|
|
659
831
|
if (param.type === 'AssignmentPattern') return { ...param, left: lazy_id };
|
|
660
832
|
return lazy_id;
|
|
661
833
|
}
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
loc: AST.SourceLocation;
|
|
28
28
|
metadata: PluginActionOverrides;
|
|
29
29
|
end_loc?: AST.SourceLocation;
|
|
30
|
+
sourceLength?: number;
|
|
30
31
|
mappingData?: Partial<VolarCodeMapping['data']>;
|
|
31
32
|
}} Token;
|
|
32
33
|
@typedef {{
|
|
@@ -55,6 +56,15 @@ import {
|
|
|
55
56
|
} from '../source-map-utils.js';
|
|
56
57
|
|
|
57
58
|
const LABEL_TO_COMPONENT_REPLACE_REGEX = /(function|\((property|method)\))/;
|
|
59
|
+
const LAZY_PARAM_IDENTIFIER_REGEX = /^__lazy\d+$/;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @param {string} value
|
|
63
|
+
* @returns {string}
|
|
64
|
+
*/
|
|
65
|
+
function escape_regex(value) {
|
|
66
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
67
|
+
}
|
|
58
68
|
|
|
59
69
|
/**
|
|
60
70
|
* @param {string} content
|
|
@@ -67,6 +77,51 @@ function replace_label_to_component(content) {
|
|
|
67
77
|
});
|
|
68
78
|
}
|
|
69
79
|
|
|
80
|
+
/**
|
|
81
|
+
* @param {string} lazy_id
|
|
82
|
+
* @param {(content: string) => string} [base_hover]
|
|
83
|
+
* @returns {(content: string) => string}
|
|
84
|
+
*/
|
|
85
|
+
function create_lazy_param_hover_replacement(lazy_id, base_hover) {
|
|
86
|
+
const lazy_param_regex = new RegExp(`\\b${escape_regex(lazy_id)}\\s*:\\s*`, 'g');
|
|
87
|
+
|
|
88
|
+
return (content) => {
|
|
89
|
+
const next = base_hover ? base_hover(content) : content;
|
|
90
|
+
return next.replace(lazy_param_regex, '&');
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {AST.Parameter[] | undefined} params
|
|
96
|
+
* @param {(content: string) => string} [base_hover]
|
|
97
|
+
* @returns {((content: string) => string) | undefined}
|
|
98
|
+
*/
|
|
99
|
+
function create_function_hover_replacement(params, base_hover) {
|
|
100
|
+
const lazy_ids =
|
|
101
|
+
params
|
|
102
|
+
?.filter(
|
|
103
|
+
(param) =>
|
|
104
|
+
param.type === 'Identifier' &&
|
|
105
|
+
param.metadata?.source_length != null &&
|
|
106
|
+
LAZY_PARAM_IDENTIFIER_REGEX.test(param.name),
|
|
107
|
+
)
|
|
108
|
+
.map((param) => /** @type {AST.Identifier} */ (param).name) ?? [];
|
|
109
|
+
|
|
110
|
+
if (lazy_ids.length === 0) return base_hover;
|
|
111
|
+
|
|
112
|
+
const lazy_param_regexes = lazy_ids.map(
|
|
113
|
+
(lazy_id) => new RegExp(`\\b${escape_regex(lazy_id)}\\s*:\\s*`, 'g'),
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
return (content) => {
|
|
117
|
+
let next = base_hover ? base_hover(content) : content;
|
|
118
|
+
for (const regex of lazy_param_regexes) {
|
|
119
|
+
next = next.replace(regex, '&');
|
|
120
|
+
}
|
|
121
|
+
return next;
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
70
125
|
/**
|
|
71
126
|
* @param {string} [hash]
|
|
72
127
|
* @param {string} [fallback]
|
|
@@ -423,6 +478,7 @@ export function convert_source_map_to_mappings(
|
|
|
423
478
|
generated: node.name,
|
|
424
479
|
loc: node.loc,
|
|
425
480
|
metadata: {},
|
|
481
|
+
sourceLength: node.metadata.source_length,
|
|
426
482
|
};
|
|
427
483
|
} else {
|
|
428
484
|
token = {
|
|
@@ -430,6 +486,7 @@ export function convert_source_map_to_mappings(
|
|
|
430
486
|
generated: node.name,
|
|
431
487
|
loc: node.loc,
|
|
432
488
|
metadata: {},
|
|
489
|
+
sourceLength: node.metadata?.source_length,
|
|
433
490
|
};
|
|
434
491
|
}
|
|
435
492
|
|
|
@@ -437,7 +494,36 @@ export function convert_source_map_to_mappings(
|
|
|
437
494
|
// only if the node has a component as the parent
|
|
438
495
|
token.metadata.hover = replace_label_to_component;
|
|
439
496
|
}
|
|
497
|
+
if (node.metadata?.source_length != null && LAZY_PARAM_IDENTIFIER_REGEX.test(node.name)) {
|
|
498
|
+
token.metadata.hover = create_lazy_param_hover_replacement(
|
|
499
|
+
node.name,
|
|
500
|
+
node.metadata?.lazy_param_is_component ? replace_label_to_component : undefined,
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
if (node.metadata?.disable_verification) {
|
|
504
|
+
token.mappingData = { ...mapping_data, verification: false };
|
|
505
|
+
}
|
|
440
506
|
tokens.push(token);
|
|
507
|
+
|
|
508
|
+
if (Array.isArray(node.metadata?.lazy_param_binding_mappings)) {
|
|
509
|
+
for (const binding_mapping of node.metadata.lazy_param_binding_mappings) {
|
|
510
|
+
const source_node = binding_mapping.source;
|
|
511
|
+
const generated_node = binding_mapping.generated;
|
|
512
|
+
if (!source_node?.loc || !generated_node?.loc) continue;
|
|
513
|
+
|
|
514
|
+
const mapping = get_mapping_from_node(
|
|
515
|
+
generated_node,
|
|
516
|
+
src_to_gen_map,
|
|
517
|
+
gen_line_offsets,
|
|
518
|
+
mapping_data_verify_only,
|
|
519
|
+
);
|
|
520
|
+
const source_start = /** @type {number} */ (source_node.start);
|
|
521
|
+
const source_end = /** @type {number} */ (source_node.end);
|
|
522
|
+
mapping.sourceOffsets = [source_start];
|
|
523
|
+
mapping.lengths = [source_end - source_start];
|
|
524
|
+
mappings.push(mapping);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
441
527
|
}
|
|
442
528
|
return; // Leaf node, don't traverse further
|
|
443
529
|
} else if (node.type === 'JSXIdentifier') {
|
|
@@ -761,11 +847,16 @@ export function convert_source_map_to_mappings(
|
|
|
761
847
|
// Add function/component keyword token
|
|
762
848
|
if (
|
|
763
849
|
(node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') &&
|
|
764
|
-
!is_method
|
|
850
|
+
!is_method &&
|
|
851
|
+
node.loc
|
|
765
852
|
) {
|
|
766
853
|
const node_fn = /** @type (typeof node) & AST.NodeWithLocation */ (node);
|
|
767
854
|
const is_component = node_fn.metadata?.is_component;
|
|
768
855
|
const source_func_keyword = is_component ? 'component' : 'function';
|
|
856
|
+
const function_hover = create_function_hover_replacement(
|
|
857
|
+
/** @type {AST.Parameter[]} */ (node.params),
|
|
858
|
+
is_component ? replace_label_to_component : undefined,
|
|
859
|
+
);
|
|
769
860
|
let start_col = node_fn.loc.start.column;
|
|
770
861
|
let start = node_fn.start;
|
|
771
862
|
const async_keyword = 'async';
|
|
@@ -781,7 +872,7 @@ export function convert_source_map_to_mappings(
|
|
|
781
872
|
mapping.lengths = [source_func_keyword.length];
|
|
782
873
|
mapping.generatedOffsets = [generated_keyword_start];
|
|
783
874
|
mapping.generatedLengths = ['function'.length];
|
|
784
|
-
mapping.data.customData.hover =
|
|
875
|
+
if (function_hover) mapping.data.customData.hover = function_hover;
|
|
785
876
|
mappings.push(mapping);
|
|
786
877
|
} else {
|
|
787
878
|
if (node_fn.async) {
|
|
@@ -813,7 +904,7 @@ export function convert_source_map_to_mappings(
|
|
|
813
904
|
column: start_col + source_func_keyword.length,
|
|
814
905
|
},
|
|
815
906
|
},
|
|
816
|
-
metadata:
|
|
907
|
+
metadata: function_hover ? { hover: function_hover } : {},
|
|
817
908
|
});
|
|
818
909
|
}
|
|
819
910
|
}
|
|
@@ -825,11 +916,24 @@ export function convert_source_map_to_mappings(
|
|
|
825
916
|
/** @type {AST.FunctionDeclaration | AST.FunctionExpression} */ (node).id &&
|
|
826
917
|
!is_method
|
|
827
918
|
) {
|
|
828
|
-
|
|
829
|
-
/** @type {AST.
|
|
830
|
-
/** @type {AST.FunctionDeclaration | AST.FunctionExpression} */ (node).id
|
|
831
|
-
),
|
|
919
|
+
const id = /** @type {AST.Identifier} */ (
|
|
920
|
+
/** @type {AST.FunctionDeclaration | AST.FunctionExpression} */ (node).id
|
|
832
921
|
);
|
|
922
|
+
const function_hover = create_function_hover_replacement(
|
|
923
|
+
/** @type {AST.Parameter[]} */ (node.params),
|
|
924
|
+
node.metadata?.is_component ? replace_label_to_component : undefined,
|
|
925
|
+
);
|
|
926
|
+
if (function_hover && id.loc) {
|
|
927
|
+
tokens.push({
|
|
928
|
+
source: id.metadata?.source_name ?? id.name,
|
|
929
|
+
generated: id.name,
|
|
930
|
+
loc: id.loc,
|
|
931
|
+
metadata: { hover: function_hover },
|
|
932
|
+
sourceLength: id.metadata?.source_length,
|
|
933
|
+
});
|
|
934
|
+
} else {
|
|
935
|
+
visit(/** @type {AST.Node} */ (id));
|
|
936
|
+
}
|
|
833
937
|
}
|
|
834
938
|
|
|
835
939
|
if (node.typeParameters) {
|
|
@@ -838,6 +942,13 @@ export function convert_source_map_to_mappings(
|
|
|
838
942
|
|
|
839
943
|
if (node.params) {
|
|
840
944
|
for (const param of node.params) {
|
|
945
|
+
if (
|
|
946
|
+
param.type === 'Identifier' &&
|
|
947
|
+
param.metadata?.source_length != null &&
|
|
948
|
+
LAZY_PARAM_IDENTIFIER_REGEX.test(param.name)
|
|
949
|
+
) {
|
|
950
|
+
param.metadata.lazy_param_is_component = node.metadata?.is_component === true;
|
|
951
|
+
}
|
|
841
952
|
visit(param);
|
|
842
953
|
if (param.typeAnnotation) {
|
|
843
954
|
visit(param.typeAnnotation);
|
|
@@ -2066,7 +2177,7 @@ export function convert_source_map_to_mappings(
|
|
|
2066
2177
|
token.loc.start.column,
|
|
2067
2178
|
src_line_offsets,
|
|
2068
2179
|
);
|
|
2069
|
-
const source_length = source_text.length;
|
|
2180
|
+
const source_length = token.sourceLength ?? source_text.length;
|
|
2070
2181
|
const gen_length = gen_text.length;
|
|
2071
2182
|
let gen_line_col;
|
|
2072
2183
|
try {
|
|
@@ -2250,21 +2361,25 @@ export function create_volar_mappings_result({
|
|
|
2250
2361
|
* @returns {CodeMapping[]}
|
|
2251
2362
|
*/
|
|
2252
2363
|
export function dedupe_mappings(mappings) {
|
|
2253
|
-
|
|
2254
|
-
|
|
2364
|
+
// keep for now more for testing and maybe logging later.
|
|
2365
|
+
// We should not use deduping and instead should be
|
|
2366
|
+
// fixing source map generation or mapping generation
|
|
2367
|
+
return mappings;
|
|
2368
|
+
// const deduped = [];
|
|
2369
|
+
// const seen = new Set();
|
|
2255
2370
|
|
|
2256
|
-
for (const mapping of mappings) {
|
|
2257
|
-
|
|
2371
|
+
// for (const mapping of mappings) {
|
|
2372
|
+
// const key = JSON.stringify(serialize_mapping_value(mapping));
|
|
2258
2373
|
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2374
|
+
// if (seen.has(key)) {
|
|
2375
|
+
// continue;
|
|
2376
|
+
// }
|
|
2262
2377
|
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
}
|
|
2378
|
+
// seen.add(key);
|
|
2379
|
+
// deduped.push(mapping);
|
|
2380
|
+
// }
|
|
2266
2381
|
|
|
2267
|
-
return deduped;
|
|
2382
|
+
// return deduped;
|
|
2268
2383
|
}
|
|
2269
2384
|
|
|
2270
2385
|
/**
|
package/src/utils/ast.js
CHANGED
|
@@ -20,6 +20,67 @@
|
|
|
20
20
|
|
|
21
21
|
import * as b from './builders.js';
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @param {AST.Node} node
|
|
25
|
+
* @returns {boolean}
|
|
26
|
+
*/
|
|
27
|
+
export function is_function_node(node) {
|
|
28
|
+
return (
|
|
29
|
+
node.type === 'FunctionExpression' ||
|
|
30
|
+
node.type === 'ArrowFunctionExpression' ||
|
|
31
|
+
node.type === 'FunctionDeclaration'
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @param {AST.Node} node
|
|
37
|
+
* @returns {boolean}
|
|
38
|
+
*/
|
|
39
|
+
export function is_class_node(node) {
|
|
40
|
+
return node.type === 'ClassExpression' || node.type === 'ClassDeclaration';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param {AST.Node} node
|
|
45
|
+
* @returns {boolean}
|
|
46
|
+
*/
|
|
47
|
+
export function is_component_node(node) {
|
|
48
|
+
return node.type === 'Component';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Returns the closest component in an ancestry path. By default, function and
|
|
53
|
+
* class boundaries stop the search so callers only match direct component
|
|
54
|
+
* body/control-flow nodes.
|
|
55
|
+
*
|
|
56
|
+
* @param {AST.Node[]} path
|
|
57
|
+
* @param {boolean} [includes_functions=false]
|
|
58
|
+
* @returns {AST.Component | undefined}
|
|
59
|
+
*/
|
|
60
|
+
export function get_component_from_path(path, includes_functions = false) {
|
|
61
|
+
for (let i = path.length - 1; i >= 0; i -= 1) {
|
|
62
|
+
const node = path[i];
|
|
63
|
+
|
|
64
|
+
if (!includes_functions && (is_function_node(node) || is_class_node(node))) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (is_component_node(node)) {
|
|
69
|
+
return /** @type {AST.Component} */ (node);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @param {AST.Node[] | { path: AST.Node[] }} context_or_path
|
|
76
|
+
* @param {boolean} [includes_functions=false]
|
|
77
|
+
* @returns {AST.Component | undefined}
|
|
78
|
+
*/
|
|
79
|
+
export function is_inside_component(context_or_path, includes_functions = false) {
|
|
80
|
+
const path = Array.isArray(context_or_path) ? context_or_path : context_or_path.path;
|
|
81
|
+
return get_component_from_path(path, includes_functions);
|
|
82
|
+
}
|
|
83
|
+
|
|
23
84
|
/**
|
|
24
85
|
* Gets the left-most identifier of a member expression or identifier.
|
|
25
86
|
* @param {AST.MemberExpression | AST.Identifier} expression
|
package/types/index.d.ts
CHANGED
|
@@ -37,6 +37,11 @@ export interface CompileOptions {
|
|
|
37
37
|
dev?: boolean;
|
|
38
38
|
hmr?: boolean;
|
|
39
39
|
compat_kinds?: string[];
|
|
40
|
+
/**
|
|
41
|
+
* When true, non-fatal errors are collected on the result's `errors`
|
|
42
|
+
* array instead of being thrown. Defaults to false (strict mode: throws).
|
|
43
|
+
*/
|
|
44
|
+
loose?: boolean;
|
|
40
45
|
}
|
|
41
46
|
|
|
42
47
|
export type NameSpace = 'html' | 'svg' | 'mathml';
|
|
@@ -45,6 +50,7 @@ interface BaseNodeMetaData {
|
|
|
45
50
|
path: AST.Node[];
|
|
46
51
|
has_template?: boolean;
|
|
47
52
|
source_name?: string | '#server' | '#style';
|
|
53
|
+
source_length?: number;
|
|
48
54
|
is_capitalized?: boolean;
|
|
49
55
|
commentContainerId?: number;
|
|
50
56
|
parenthesized?: boolean;
|
|
@@ -56,6 +62,12 @@ interface BaseNodeMetaData {
|
|
|
56
62
|
lone_return?: boolean;
|
|
57
63
|
forceMapping?: boolean;
|
|
58
64
|
lazy_id?: string;
|
|
65
|
+
disable_verification?: boolean;
|
|
66
|
+
lazy_param_is_component?: boolean;
|
|
67
|
+
lazy_param_binding_mappings?: Array<{
|
|
68
|
+
source: AST.Identifier;
|
|
69
|
+
generated: AST.Identifier | AST.Literal;
|
|
70
|
+
}>;
|
|
59
71
|
}
|
|
60
72
|
|
|
61
73
|
interface FunctionMetaData extends BaseNodeMetaData {
|
|
@@ -1558,6 +1570,11 @@ export interface CompileResult {
|
|
|
1558
1570
|
};
|
|
1559
1571
|
/** The generated CSS */
|
|
1560
1572
|
css: string;
|
|
1573
|
+
/**
|
|
1574
|
+
* Non-fatal errors collected during compilation. Populated only when the
|
|
1575
|
+
* caller passes `loose: true`; empty otherwise.
|
|
1576
|
+
*/
|
|
1577
|
+
errors: CompileError[];
|
|
1561
1578
|
}
|
|
1562
1579
|
|
|
1563
1580
|
/**
|
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
|