@tsrx/core 0.1.16 → 0.1.17
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/README.md +4 -3
- package/package.json +1 -1
- package/src/analyze/prune.js +13 -28
- package/src/analyze/validation.js +27 -94
- package/src/diagnostics.js +1 -3
- package/src/index.js +18 -28
- package/src/parse/index.js +37 -4
- package/src/plugin.js +182 -644
- package/src/runtime/ref.js +48 -0
- package/src/scope.js +0 -13
- package/src/transform/await.js +1 -1
- package/src/transform/jsx/ast-builders.js +3 -5
- package/src/transform/jsx/helpers.js +1 -2
- package/src/transform/jsx/index.js +1257 -1491
- package/src/transform/lazy.js +6 -6
- package/src/transform/scoping.js +1 -2
- package/src/transform/segments.js +26 -157
- package/src/transform/style-ref.js +235 -0
- package/src/utils/ast.js +15 -23
- package/src/utils/builders.js +0 -18
- package/types/index.d.ts +32 -74
- package/types/jsx-platform.d.ts +20 -28
- package/types/parse.d.ts +2 -15
- package/types/runtime/ref.d.ts +3 -0
package/src/transform/lazy.js
CHANGED
|
@@ -438,14 +438,14 @@ function replace_lazy_in_pattern(pattern, is_top = true) {
|
|
|
438
438
|
|
|
439
439
|
/**
|
|
440
440
|
* Walk the AST and pre-allocate `lazy_id` metadata on every lazy destructuring
|
|
441
|
-
* pattern: function
|
|
442
|
-
* assignment LHS. Walks into non-lazy outer patterns to
|
|
443
|
-
* e.g. `{ pair: &[a, b] }` allocates an id for the inner
|
|
444
|
-
* skips patterns that already have a `lazy_id`.
|
|
441
|
+
* pattern: function params, variable declarator ids, and statement-level
|
|
442
|
+
* assignment LHS. Walks into non-lazy outer patterns to
|
|
443
|
+
* find nested lazy ones, e.g. `{ pair: &[a, b] }` allocates an id for the inner
|
|
444
|
+
* `&[a, b]`. Idempotent: skips patterns that already have a `lazy_id`.
|
|
445
445
|
*
|
|
446
446
|
* Also stamps `metadata.has_lazy_descendants = true` on every function-like
|
|
447
447
|
* node whose subtree contains any lazy pattern, so `apply_lazy_transforms`
|
|
448
|
-
* can take a constant-time
|
|
448
|
+
* can take a constant-time fast path for purely non-lazy functions.
|
|
449
449
|
*
|
|
450
450
|
* @param {any} root
|
|
451
451
|
* @param {LazyContext} context
|
|
@@ -570,7 +570,7 @@ export function apply_lazy_transforms(node, lazy_bindings) {
|
|
|
570
570
|
return node;
|
|
571
571
|
}
|
|
572
572
|
|
|
573
|
-
// Past the
|
|
573
|
+
// Past the fast path: either we have active lazy bindings, lazy
|
|
574
574
|
// params to replace, defaults referencing outer lazy, or the body
|
|
575
575
|
// contains lazy descendants the BlockStatement handler will collect.
|
|
576
576
|
// In every case the body needs to be walked.
|
package/src/transform/scoping.js
CHANGED
|
@@ -89,7 +89,7 @@ function is_composite_jsx_element(node) {
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
/**
|
|
92
|
-
* Recursively walk `Element` nodes within a
|
|
92
|
+
* Recursively walk `Element` nodes within a TSRX fragment and add the hash
|
|
93
93
|
* class name so scope-qualified selectors (e.g. `.foo.hash`) match.
|
|
94
94
|
*
|
|
95
95
|
* @param {any} node
|
|
@@ -106,7 +106,6 @@ export function annotate_with_hash(
|
|
|
106
106
|
) {
|
|
107
107
|
if (!node || typeof node !== 'object') return node;
|
|
108
108
|
if (
|
|
109
|
-
node.type === 'Component' ||
|
|
110
109
|
node.type === 'FunctionDeclaration' ||
|
|
111
110
|
node.type === 'FunctionExpression' ||
|
|
112
111
|
node.type === 'ArrowFunctionExpression'
|
|
@@ -56,7 +56,6 @@ import {
|
|
|
56
56
|
get_mapping_from_node,
|
|
57
57
|
} from '../source-map-utils.js';
|
|
58
58
|
|
|
59
|
-
const LABEL_TO_COMPONENT_REPLACE_REGEX = /(function|\((property|method)\))/;
|
|
60
59
|
const LAZY_PARAM_IDENTIFIER_REGEX = /^__lazy\d+$/;
|
|
61
60
|
|
|
62
61
|
/**
|
|
@@ -67,17 +66,6 @@ function escape_regex(value) {
|
|
|
67
66
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
68
67
|
}
|
|
69
68
|
|
|
70
|
-
/**
|
|
71
|
-
* @param {string} content
|
|
72
|
-
* @returns {string}
|
|
73
|
-
*/
|
|
74
|
-
function replace_label_to_component(content) {
|
|
75
|
-
return content.replace(LABEL_TO_COMPONENT_REPLACE_REGEX, (_, fn, kind) => {
|
|
76
|
-
if (fn === 'function') return 'component';
|
|
77
|
-
return `(component ${kind})`;
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
69
|
/**
|
|
82
70
|
* @param {string} lazy_id
|
|
83
71
|
* @param {(content: string) => string} [base_hover]
|
|
@@ -442,53 +430,12 @@ export function convert_source_map_to_mappings(
|
|
|
442
430
|
}
|
|
443
431
|
}
|
|
444
432
|
|
|
445
|
-
/**
|
|
446
|
-
* @typedef {AST.Property & {value: AST.FunctionExpression, method: true} & {value: {metadata: {is_component: true}}}} PropertyIsComponent
|
|
447
|
-
*/
|
|
448
|
-
|
|
449
|
-
/**
|
|
450
|
-
* Maps `component` to the identifier's location
|
|
451
|
-
* e.g. const obj = { component something() { } }
|
|
452
|
-
* since there is no function keyword in source maps
|
|
453
|
-
* @param {PropertyIsComponent} node
|
|
454
|
-
* @returns {void}
|
|
455
|
-
*/
|
|
456
|
-
function set_component_mapping_to_name(node) {
|
|
457
|
-
if (node.key.loc) {
|
|
458
|
-
/** @type {CodeMapping} */
|
|
459
|
-
let mapping;
|
|
460
|
-
let start = /** @type {AST.NodeWithLocation} */ (node).start;
|
|
461
|
-
let length = 'component'.length;
|
|
462
|
-
|
|
463
|
-
if (node.value.type === 'FunctionExpression' && node.value.id) {
|
|
464
|
-
const id = /** @type {AST.Identifier & AST.NodeWithLocation} */ (node.value.id);
|
|
465
|
-
mapping = get_mapping_from_node(id, src_to_gen_map, gen_line_offsets);
|
|
466
|
-
} else {
|
|
467
|
-
// e.g. key is computed or literal
|
|
468
|
-
mapping = get_mapping_from_node(node.key, src_to_gen_map, gen_line_offsets);
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// overwrite source start and length to point to 'component' keyword
|
|
472
|
-
mapping.sourceOffsets = [start];
|
|
473
|
-
mapping.lengths = [length];
|
|
474
|
-
mapping.data.customData.hover = replace_label_to_component;
|
|
475
|
-
|
|
476
|
-
mappings.push(mapping);
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
|
|
480
433
|
/**
|
|
481
434
|
* @param {AST.Literal} node
|
|
482
|
-
* @param {boolean} [is_component]
|
|
483
435
|
*/
|
|
484
|
-
function handle_literal(node
|
|
436
|
+
function handle_literal(node) {
|
|
485
437
|
if (node.loc) {
|
|
486
438
|
const mapping = get_mapping_from_node(node, src_to_gen_map, gen_line_offsets);
|
|
487
|
-
|
|
488
|
-
if (is_component) {
|
|
489
|
-
mapping.data.customData.hover = replace_label_to_component;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
439
|
mappings.push(mapping);
|
|
493
440
|
}
|
|
494
441
|
}
|
|
@@ -524,15 +471,8 @@ export function convert_source_map_to_mappings(
|
|
|
524
471
|
};
|
|
525
472
|
}
|
|
526
473
|
|
|
527
|
-
if (node.metadata?.is_component) {
|
|
528
|
-
// only if the node has a component as the parent
|
|
529
|
-
token.metadata.hover = replace_label_to_component;
|
|
530
|
-
}
|
|
531
474
|
if (node.metadata?.source_length != null && LAZY_PARAM_IDENTIFIER_REGEX.test(node.name)) {
|
|
532
|
-
token.metadata.hover = create_lazy_param_hover_replacement(
|
|
533
|
-
node.name,
|
|
534
|
-
node.metadata?.lazy_param_is_component ? replace_label_to_component : undefined,
|
|
535
|
-
);
|
|
475
|
+
token.metadata.hover = create_lazy_param_hover_replacement(node.name);
|
|
536
476
|
}
|
|
537
477
|
if ('hover' in (node.metadata || {})) {
|
|
538
478
|
token.metadata.hover = /** @type {any} */ (node.metadata).hover;
|
|
@@ -772,25 +712,6 @@ export function convert_source_map_to_mappings(
|
|
|
772
712
|
visit(node.name);
|
|
773
713
|
}
|
|
774
714
|
|
|
775
|
-
if (
|
|
776
|
-
node.name.type === 'JSXIdentifier' &&
|
|
777
|
-
node.name.metadata?.is_component &&
|
|
778
|
-
node.name.loc
|
|
779
|
-
) {
|
|
780
|
-
const mapping = get_mapping_from_node(
|
|
781
|
-
node.name,
|
|
782
|
-
src_to_gen_map,
|
|
783
|
-
gen_line_offsets,
|
|
784
|
-
mapping_data,
|
|
785
|
-
);
|
|
786
|
-
mapping.sourceOffsets = [
|
|
787
|
-
/** @type {AST.NodeWithLocation} */ (node.name).start - 'component '.length,
|
|
788
|
-
];
|
|
789
|
-
mapping.lengths = ['component'.length];
|
|
790
|
-
|
|
791
|
-
mapping.data.customData.hover = replace_label_to_component;
|
|
792
|
-
mappings.push(mapping);
|
|
793
|
-
}
|
|
794
715
|
if (node.value) {
|
|
795
716
|
visit(node.value);
|
|
796
717
|
}
|
|
@@ -920,69 +841,51 @@ export function convert_source_map_to_mappings(
|
|
|
920
841
|
}
|
|
921
842
|
}
|
|
922
843
|
|
|
923
|
-
// Add function
|
|
844
|
+
// Add the function keyword token.
|
|
924
845
|
if (
|
|
925
846
|
(node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') &&
|
|
926
847
|
!is_method &&
|
|
927
848
|
node.loc
|
|
928
849
|
) {
|
|
929
850
|
const node_fn = /** @type (typeof node) & AST.NodeWithLocation */ (node);
|
|
930
|
-
const is_component = node_fn.metadata?.is_component;
|
|
931
|
-
const source_func_keyword = is_component ? 'component' : 'function';
|
|
932
851
|
const function_hover = create_function_hover_replacement(
|
|
933
852
|
/** @type {AST.Parameter[]} */ (node.params),
|
|
934
|
-
is_component ? replace_label_to_component : undefined,
|
|
935
853
|
);
|
|
936
854
|
let start_col = node_fn.loc.start.column;
|
|
937
855
|
let start = node_fn.start;
|
|
938
856
|
const async_keyword = 'async';
|
|
939
857
|
|
|
940
|
-
if (
|
|
941
|
-
|
|
942
|
-
const generated_id_start = mapping.generatedOffsets[0];
|
|
943
|
-
const generated_keyword_start = find_component_keyword_offset(
|
|
944
|
-
generated_code,
|
|
945
|
-
generated_id_start,
|
|
946
|
-
);
|
|
947
|
-
mapping.sourceOffsets = [start];
|
|
948
|
-
mapping.lengths = [source_func_keyword.length];
|
|
949
|
-
mapping.generatedOffsets = [generated_keyword_start];
|
|
950
|
-
mapping.generatedLengths = ['function'.length];
|
|
951
|
-
if (function_hover) mapping.data.customData.hover = function_hover;
|
|
952
|
-
mappings.push(mapping);
|
|
953
|
-
} else {
|
|
954
|
-
if (node_fn.async) {
|
|
955
|
-
// We explicitly mapped async and function in esrap
|
|
956
|
-
tokens.push({
|
|
957
|
-
source: async_keyword,
|
|
958
|
-
generated: async_keyword,
|
|
959
|
-
loc: {
|
|
960
|
-
start: { line: node_fn.loc.start.line, column: start_col },
|
|
961
|
-
end: {
|
|
962
|
-
line: node_fn.loc.start.line,
|
|
963
|
-
column: start_col + async_keyword.length,
|
|
964
|
-
},
|
|
965
|
-
},
|
|
966
|
-
metadata: {},
|
|
967
|
-
});
|
|
968
|
-
|
|
969
|
-
start_col += async_keyword.length + 1; // +1 for space
|
|
970
|
-
start += async_keyword.length + 1;
|
|
971
|
-
}
|
|
972
|
-
|
|
858
|
+
if (node_fn.async) {
|
|
859
|
+
// We explicitly mapped async and function in esrap
|
|
973
860
|
tokens.push({
|
|
974
|
-
source:
|
|
975
|
-
generated:
|
|
861
|
+
source: async_keyword,
|
|
862
|
+
generated: async_keyword,
|
|
976
863
|
loc: {
|
|
977
864
|
start: { line: node_fn.loc.start.line, column: start_col },
|
|
978
865
|
end: {
|
|
979
866
|
line: node_fn.loc.start.line,
|
|
980
|
-
column: start_col +
|
|
867
|
+
column: start_col + async_keyword.length,
|
|
981
868
|
},
|
|
982
869
|
},
|
|
983
|
-
metadata:
|
|
870
|
+
metadata: {},
|
|
984
871
|
});
|
|
872
|
+
|
|
873
|
+
start_col += async_keyword.length + 1; // +1 for space
|
|
874
|
+
start += async_keyword.length + 1;
|
|
985
875
|
}
|
|
876
|
+
|
|
877
|
+
tokens.push({
|
|
878
|
+
source: 'function',
|
|
879
|
+
generated: 'function',
|
|
880
|
+
loc: {
|
|
881
|
+
start: { line: node_fn.loc.start.line, column: start_col },
|
|
882
|
+
end: {
|
|
883
|
+
line: node_fn.loc.start.line,
|
|
884
|
+
column: start_col + 'function'.length,
|
|
885
|
+
},
|
|
886
|
+
},
|
|
887
|
+
metadata: function_hover ? { hover: function_hover } : {},
|
|
888
|
+
});
|
|
986
889
|
}
|
|
987
890
|
|
|
988
891
|
// Visit in source order: id, params, body
|
|
@@ -997,7 +900,6 @@ export function convert_source_map_to_mappings(
|
|
|
997
900
|
);
|
|
998
901
|
const function_hover = create_function_hover_replacement(
|
|
999
902
|
/** @type {AST.Parameter[]} */ (node.params),
|
|
1000
|
-
node.metadata?.is_component ? replace_label_to_component : undefined,
|
|
1001
903
|
);
|
|
1002
904
|
if (function_hover && id.loc) {
|
|
1003
905
|
tokens.push({
|
|
@@ -1018,13 +920,6 @@ export function convert_source_map_to_mappings(
|
|
|
1018
920
|
|
|
1019
921
|
if (node.params) {
|
|
1020
922
|
for (const param of node.params) {
|
|
1021
|
-
if (
|
|
1022
|
-
param.type === 'Identifier' &&
|
|
1023
|
-
param.metadata?.source_length != null &&
|
|
1024
|
-
LAZY_PARAM_IDENTIFIER_REGEX.test(param.name)
|
|
1025
|
-
) {
|
|
1026
|
-
param.metadata.lazy_param_is_component = node.metadata?.is_component === true;
|
|
1027
|
-
}
|
|
1028
923
|
visit(param);
|
|
1029
924
|
if (param.typeAnnotation) {
|
|
1030
925
|
visit(param.typeAnnotation);
|
|
@@ -1406,19 +1301,8 @@ export function convert_source_map_to_mappings(
|
|
|
1406
1301
|
set_bracket_computed_mapping(node, mappings);
|
|
1407
1302
|
}
|
|
1408
1303
|
|
|
1409
|
-
if (
|
|
1410
|
-
node.value.type === 'FunctionExpression' &&
|
|
1411
|
-
node.method &&
|
|
1412
|
-
node.value.metadata.is_component
|
|
1413
|
-
) {
|
|
1414
|
-
set_component_mapping_to_name(/** @type {PropertyIsComponent} */ (node));
|
|
1415
|
-
}
|
|
1416
|
-
|
|
1417
1304
|
if (node.key.type === 'Literal') {
|
|
1418
|
-
handle_literal(
|
|
1419
|
-
node.key,
|
|
1420
|
-
/** @type {AST.FunctionExpression} */ (node.value).metadata.is_component,
|
|
1421
|
-
);
|
|
1305
|
+
handle_literal(node.key);
|
|
1422
1306
|
} else {
|
|
1423
1307
|
visit(node.key);
|
|
1424
1308
|
}
|
|
@@ -2374,21 +2258,6 @@ export function convert_source_map_to_mappings(
|
|
|
2374
2258
|
};
|
|
2375
2259
|
}
|
|
2376
2260
|
|
|
2377
|
-
/**
|
|
2378
|
-
* @param {string} generated_code
|
|
2379
|
-
* @param {number} generated_id_start
|
|
2380
|
-
* @returns {number}
|
|
2381
|
-
*/
|
|
2382
|
-
function find_component_keyword_offset(generated_code, generated_id_start) {
|
|
2383
|
-
const function_keyword_index = generated_code.lastIndexOf('function', generated_id_start);
|
|
2384
|
-
|
|
2385
|
-
if (function_keyword_index === -1) {
|
|
2386
|
-
return generated_id_start;
|
|
2387
|
-
}
|
|
2388
|
-
|
|
2389
|
-
return function_keyword_index;
|
|
2390
|
-
}
|
|
2391
|
-
|
|
2392
2261
|
/**
|
|
2393
2262
|
* Build a `VolarMappingsResult` from generated code plus source-map metadata.
|
|
2394
2263
|
*
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/** @import * as AST from 'estree' */
|
|
2
|
+
|
|
3
|
+
import * as b from '../utils/builders.js';
|
|
4
|
+
import { clone_expression_node, clone_identifier } from './jsx/ast-builders.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {{
|
|
8
|
+
* allowMutableRefTarget?: boolean;
|
|
9
|
+
* createTempIdentifier?: () => AST.Identifier;
|
|
10
|
+
* visitExpression?: (expression: AST.Expression) => AST.Expression;
|
|
11
|
+
* }} StyleRefOptions
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {any} component
|
|
16
|
+
* @param {any} css
|
|
17
|
+
* @returns {AST.ObjectExpression}
|
|
18
|
+
*/
|
|
19
|
+
export function create_style_class_map(component, css) {
|
|
20
|
+
const hash = css?.hash ?? null;
|
|
21
|
+
const top_scoped_classes = /** @type {Map<string, any>} */ (
|
|
22
|
+
component?.metadata?.topScopedClasses ?? new Map()
|
|
23
|
+
);
|
|
24
|
+
const class_names = [...top_scoped_classes.keys()].sort();
|
|
25
|
+
|
|
26
|
+
return b.object(
|
|
27
|
+
class_names.map((class_name) =>
|
|
28
|
+
b.prop('init', b.literal(class_name), b.literal(hash ? `${hash} ${class_name}` : class_name)),
|
|
29
|
+
),
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {any} node
|
|
35
|
+
* @param {any[]} [refs]
|
|
36
|
+
* @returns {any[]}
|
|
37
|
+
*/
|
|
38
|
+
export function collect_style_ref_attributes(node, refs = []) {
|
|
39
|
+
if (!node || typeof node !== 'object') return refs;
|
|
40
|
+
|
|
41
|
+
if (Array.isArray(node)) {
|
|
42
|
+
for (const child of node) collect_style_ref_attributes(child, refs);
|
|
43
|
+
return refs;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (is_style_element(node)) {
|
|
47
|
+
for (const attr of node.attributes || []) {
|
|
48
|
+
if (is_ref_attribute(attr) && attr.value) {
|
|
49
|
+
refs.push(attr);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return refs;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (is_function_or_class_boundary(node)) {
|
|
56
|
+
return refs;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
for (const key of Object.keys(node)) {
|
|
60
|
+
if (key === 'loc' || key === 'start' || key === 'end' || key === 'metadata' || key === 'css') {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
collect_style_ref_attributes(node[key], refs);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return refs;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @param {any[]} ref_attributes
|
|
71
|
+
* @param {AST.Expression} style_map
|
|
72
|
+
* @param {StyleRefOptions} [options]
|
|
73
|
+
* @returns {AST.Statement[]}
|
|
74
|
+
*/
|
|
75
|
+
export function create_style_ref_setup_statements(ref_attributes, style_map, options = {}) {
|
|
76
|
+
/** @type {AST.Statement[]} */
|
|
77
|
+
const statements = [];
|
|
78
|
+
for (const attr of ref_attributes) {
|
|
79
|
+
const source = get_ref_attribute_expression(attr);
|
|
80
|
+
if (!source) continue;
|
|
81
|
+
statements.push(...create_style_ref_expression_statements(source, style_map, options));
|
|
82
|
+
}
|
|
83
|
+
return statements;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @param {AST.Expression} source
|
|
88
|
+
* @param {AST.Expression} style_map
|
|
89
|
+
* @param {StyleRefOptions} options
|
|
90
|
+
* @returns {AST.Statement[]}
|
|
91
|
+
*/
|
|
92
|
+
function create_style_ref_expression_statements(source, style_map, options) {
|
|
93
|
+
if (source.type === 'ArrayExpression') {
|
|
94
|
+
return source.elements.flatMap((element) => {
|
|
95
|
+
if (!element) return [];
|
|
96
|
+
const expression = element.type === 'SpreadElement' ? element.argument : element;
|
|
97
|
+
return create_style_ref_expression_statements(
|
|
98
|
+
/** @type {AST.Expression} */ (expression),
|
|
99
|
+
style_map,
|
|
100
|
+
options,
|
|
101
|
+
);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (
|
|
106
|
+
options.allowMutableRefTarget !== false &&
|
|
107
|
+
(source.type === 'Identifier' || source.type === 'MemberExpression')
|
|
108
|
+
) {
|
|
109
|
+
const target = clone_expression_node(source, false);
|
|
110
|
+
return [
|
|
111
|
+
b.stmt(
|
|
112
|
+
b.assignment(
|
|
113
|
+
'=',
|
|
114
|
+
/** @type {AST.Pattern} */ (target),
|
|
115
|
+
clone_expression_node(style_map, false),
|
|
116
|
+
),
|
|
117
|
+
),
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (source.type === 'ArrowFunctionExpression' || source.type === 'FunctionExpression') {
|
|
122
|
+
return [
|
|
123
|
+
b.stmt(
|
|
124
|
+
b.call(
|
|
125
|
+
visit_expression(clone_expression_node(source, false), options),
|
|
126
|
+
clone_expression_node(style_map, false),
|
|
127
|
+
),
|
|
128
|
+
),
|
|
129
|
+
];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return create_dynamic_style_ref_statement(source, style_map, options);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @param {AST.Expression} source
|
|
137
|
+
* @param {AST.Expression} style_map
|
|
138
|
+
* @param {StyleRefOptions} options
|
|
139
|
+
* @returns {AST.Statement[]}
|
|
140
|
+
*/
|
|
141
|
+
function create_dynamic_style_ref_statement(source, style_map, options) {
|
|
142
|
+
const ref_id = options.createTempIdentifier?.() ?? b.id('__tsrx_style_ref');
|
|
143
|
+
const ref_read = () => clone_identifier(ref_id);
|
|
144
|
+
const current_write = b.stmt(
|
|
145
|
+
b.assignment('=', b.member(ref_read(), 'current'), clone_expression_node(style_map, false)),
|
|
146
|
+
);
|
|
147
|
+
const value_write = b.stmt(
|
|
148
|
+
b.assignment('=', b.member(ref_read(), 'value'), clone_expression_node(style_map, false)),
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
return [
|
|
152
|
+
b.let(ref_id, visit_expression(clone_expression_node(source, false), options)),
|
|
153
|
+
b.if(
|
|
154
|
+
b.binary('===', b.unary('typeof', ref_read()), b.literal('function')),
|
|
155
|
+
b.block([b.stmt(b.call(ref_read(), clone_expression_node(style_map, false)))]),
|
|
156
|
+
b.if(
|
|
157
|
+
b.logical(
|
|
158
|
+
'&&',
|
|
159
|
+
ref_read(),
|
|
160
|
+
b.binary('===', b.unary('typeof', ref_read()), b.literal('object')),
|
|
161
|
+
),
|
|
162
|
+
b.block([
|
|
163
|
+
b.if(
|
|
164
|
+
b.binary('in', b.literal('current'), ref_read()),
|
|
165
|
+
b.block([current_write]),
|
|
166
|
+
b.if(b.binary('in', b.literal('value'), ref_read()), b.block([value_write]), null),
|
|
167
|
+
),
|
|
168
|
+
]),
|
|
169
|
+
null,
|
|
170
|
+
),
|
|
171
|
+
),
|
|
172
|
+
];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* @param {AST.Expression} expression
|
|
177
|
+
* @param {StyleRefOptions} options
|
|
178
|
+
* @returns {AST.Expression}
|
|
179
|
+
*/
|
|
180
|
+
function visit_expression(expression, options) {
|
|
181
|
+
return options.visitExpression ? options.visitExpression(expression) : expression;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @param {any} attr
|
|
186
|
+
* @returns {AST.Expression | null}
|
|
187
|
+
*/
|
|
188
|
+
function get_ref_attribute_expression(attr) {
|
|
189
|
+
const value = attr.value;
|
|
190
|
+
if (!value) return null;
|
|
191
|
+
if (value.type === 'JSXExpressionContainer') {
|
|
192
|
+
return value.expression.type === 'JSXEmptyExpression' ? null : value.expression;
|
|
193
|
+
}
|
|
194
|
+
return value;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* @param {any} attr
|
|
199
|
+
* @returns {boolean}
|
|
200
|
+
*/
|
|
201
|
+
function is_ref_attribute(attr) {
|
|
202
|
+
return (
|
|
203
|
+
(attr?.type === 'Attribute' && attr.name?.type === 'Identifier' && attr.name.name === 'ref') ||
|
|
204
|
+
(attr?.type === 'JSXAttribute' &&
|
|
205
|
+
attr.name?.type === 'JSXIdentifier' &&
|
|
206
|
+
attr.name.name === 'ref')
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* @param {any} node
|
|
212
|
+
* @returns {boolean}
|
|
213
|
+
*/
|
|
214
|
+
function is_style_element(node) {
|
|
215
|
+
return !!(
|
|
216
|
+
node &&
|
|
217
|
+
node.type === 'Element' &&
|
|
218
|
+
node.id?.type === 'Identifier' &&
|
|
219
|
+
node.id.name === 'style'
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* @param {any} node
|
|
225
|
+
* @returns {boolean}
|
|
226
|
+
*/
|
|
227
|
+
function is_function_or_class_boundary(node) {
|
|
228
|
+
return (
|
|
229
|
+
node?.type === 'FunctionDeclaration' ||
|
|
230
|
+
node?.type === 'FunctionExpression' ||
|
|
231
|
+
node?.type === 'ArrowFunctionExpression' ||
|
|
232
|
+
node?.type === 'ClassDeclaration' ||
|
|
233
|
+
node?.type === 'ClassExpression'
|
|
234
|
+
);
|
|
235
|
+
}
|
package/src/utils/ast.js
CHANGED
|
@@ -37,12 +37,7 @@ export function is_function_node(node) {
|
|
|
37
37
|
* @returns {boolean}
|
|
38
38
|
*/
|
|
39
39
|
export function is_function_or_component_node(node) {
|
|
40
|
-
return (
|
|
41
|
-
node.type === 'FunctionDeclaration' ||
|
|
42
|
-
node.type === 'FunctionExpression' ||
|
|
43
|
-
node.type === 'ArrowFunctionExpression' ||
|
|
44
|
-
node.type === 'Component'
|
|
45
|
-
);
|
|
40
|
+
return is_function_node(node);
|
|
46
41
|
}
|
|
47
42
|
|
|
48
43
|
/**
|
|
@@ -54,32 +49,29 @@ export function is_class_node(node) {
|
|
|
54
49
|
}
|
|
55
50
|
|
|
56
51
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
|
|
60
|
-
export function is_component_node(node) {
|
|
61
|
-
return node.type === 'Component';
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Returns the closest component in an ancestry path. By default, function and
|
|
66
|
-
* class boundaries stop the search so callers only match direct component
|
|
67
|
-
* body/control-flow nodes.
|
|
52
|
+
* Returns the closest native TSRX function in an ancestry path. By default,
|
|
53
|
+
* function and class boundaries stop the search so callers only match direct
|
|
54
|
+
* native TSRX function body/control-flow nodes.
|
|
68
55
|
*
|
|
69
56
|
* @param {AST.Node[]} path
|
|
70
57
|
* @param {boolean} [includes_functions=false]
|
|
71
|
-
* @returns {AST.
|
|
58
|
+
* @returns {AST.Function | undefined}
|
|
72
59
|
*/
|
|
73
60
|
export function get_component_from_path(path, includes_functions = false) {
|
|
74
61
|
for (let i = path.length - 1; i >= 0; i -= 1) {
|
|
75
62
|
const node = path[i];
|
|
76
63
|
|
|
77
|
-
if (
|
|
78
|
-
|
|
64
|
+
if (is_function_node(node)) {
|
|
65
|
+
if (/** @type {any} */ (node).metadata?.native_tsrx_function) {
|
|
66
|
+
return /** @type {AST.Function} */ (node);
|
|
67
|
+
}
|
|
68
|
+
if (!includes_functions) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
79
71
|
}
|
|
80
72
|
|
|
81
|
-
if (
|
|
82
|
-
return
|
|
73
|
+
if (!includes_functions && is_class_node(node)) {
|
|
74
|
+
return;
|
|
83
75
|
}
|
|
84
76
|
}
|
|
85
77
|
}
|
|
@@ -87,7 +79,7 @@ export function get_component_from_path(path, includes_functions = false) {
|
|
|
87
79
|
/**
|
|
88
80
|
* @param {AST.Node[] | { path: AST.Node[] }} context_or_path
|
|
89
81
|
* @param {boolean} [includes_functions=false]
|
|
90
|
-
* @returns {AST.
|
|
82
|
+
* @returns {AST.Function | undefined}
|
|
91
83
|
*/
|
|
92
84
|
export function is_inside_component(context_or_path, includes_functions = false) {
|
|
93
85
|
const path = Array.isArray(context_or_path) ? context_or_path : context_or_path.path;
|
package/src/utils/builders.js
CHANGED
|
@@ -77,24 +77,6 @@ export function arrow(params, body, async = false, type_parameters, loc_info) {
|
|
|
77
77
|
return set_location(node, loc_info);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
/**
|
|
81
|
-
* @param {AST.Identifier} id
|
|
82
|
-
* @param {AST.Pattern[]} params
|
|
83
|
-
* @param {AST.Node[]} body
|
|
84
|
-
* @returns {AST.Component}
|
|
85
|
-
*/
|
|
86
|
-
export function component(id, params, body) {
|
|
87
|
-
return {
|
|
88
|
-
type: 'Component',
|
|
89
|
-
id,
|
|
90
|
-
params,
|
|
91
|
-
body,
|
|
92
|
-
css: null,
|
|
93
|
-
metadata: { path: [] },
|
|
94
|
-
default: false,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
|
|
98
80
|
/**
|
|
99
81
|
* @param {AST.AssignmentOperator} operator
|
|
100
82
|
* @param {AST.Pattern} left
|