@tsrx/core 0.0.13 → 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 +280 -23
- package/src/transform/jsx/helpers.js +17 -0
- package/src/transform/jsx/index.js +540 -349
- package/src/transform/lazy.js +185 -13
- package/src/transform/segments.js +117 -7
- package/src/utils/ast.js +61 -0
- package/types/index.d.ts +17 -0
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') {
|
|
@@ -767,6 +853,10 @@ export function convert_source_map_to_mappings(
|
|
|
767
853
|
const node_fn = /** @type (typeof node) & AST.NodeWithLocation */ (node);
|
|
768
854
|
const is_component = node_fn.metadata?.is_component;
|
|
769
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
|
+
);
|
|
770
860
|
let start_col = node_fn.loc.start.column;
|
|
771
861
|
let start = node_fn.start;
|
|
772
862
|
const async_keyword = 'async';
|
|
@@ -782,7 +872,7 @@ export function convert_source_map_to_mappings(
|
|
|
782
872
|
mapping.lengths = [source_func_keyword.length];
|
|
783
873
|
mapping.generatedOffsets = [generated_keyword_start];
|
|
784
874
|
mapping.generatedLengths = ['function'.length];
|
|
785
|
-
mapping.data.customData.hover =
|
|
875
|
+
if (function_hover) mapping.data.customData.hover = function_hover;
|
|
786
876
|
mappings.push(mapping);
|
|
787
877
|
} else {
|
|
788
878
|
if (node_fn.async) {
|
|
@@ -814,7 +904,7 @@ export function convert_source_map_to_mappings(
|
|
|
814
904
|
column: start_col + source_func_keyword.length,
|
|
815
905
|
},
|
|
816
906
|
},
|
|
817
|
-
metadata:
|
|
907
|
+
metadata: function_hover ? { hover: function_hover } : {},
|
|
818
908
|
});
|
|
819
909
|
}
|
|
820
910
|
}
|
|
@@ -826,11 +916,24 @@ export function convert_source_map_to_mappings(
|
|
|
826
916
|
/** @type {AST.FunctionDeclaration | AST.FunctionExpression} */ (node).id &&
|
|
827
917
|
!is_method
|
|
828
918
|
) {
|
|
829
|
-
|
|
830
|
-
/** @type {AST.
|
|
831
|
-
|
|
832
|
-
|
|
919
|
+
const id = /** @type {AST.Identifier} */ (
|
|
920
|
+
/** @type {AST.FunctionDeclaration | AST.FunctionExpression} */ (node).id
|
|
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,
|
|
833
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
|
+
}
|
|
834
937
|
}
|
|
835
938
|
|
|
836
939
|
if (node.typeParameters) {
|
|
@@ -839,6 +942,13 @@ export function convert_source_map_to_mappings(
|
|
|
839
942
|
|
|
840
943
|
if (node.params) {
|
|
841
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
|
+
}
|
|
842
952
|
visit(param);
|
|
843
953
|
if (param.typeAnnotation) {
|
|
844
954
|
visit(param.typeAnnotation);
|
|
@@ -2067,7 +2177,7 @@ export function convert_source_map_to_mappings(
|
|
|
2067
2177
|
token.loc.start.column,
|
|
2068
2178
|
src_line_offsets,
|
|
2069
2179
|
);
|
|
2070
|
-
const source_length = source_text.length;
|
|
2180
|
+
const source_length = token.sourceLength ?? source_text.length;
|
|
2071
2181
|
const gen_length = gen_text.length;
|
|
2072
2182
|
let gen_line_col;
|
|
2073
2183
|
try {
|
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
|
/**
|