@tsrx/vue 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 +7 -2
- package/src/index.js +19 -4
- package/src/merge-refs.js +1 -0
- package/src/transform.js +61 -77
- package/types/error-boundary.d.ts +11 -0
- package/types/merge-refs.d.ts +1 -0
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Vue compiler built on @tsrx/core",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Dominic Gannaway",
|
|
6
|
-
"version": "0.0.
|
|
6
|
+
"version": "0.0.14",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"publishConfig": {
|
|
9
9
|
"access": "public"
|
|
@@ -19,13 +19,18 @@
|
|
|
19
19
|
"default": "./src/index.js"
|
|
20
20
|
},
|
|
21
21
|
"./error-boundary": {
|
|
22
|
+
"types": "./types/error-boundary.d.ts",
|
|
22
23
|
"default": "./src/error-boundary.js"
|
|
24
|
+
},
|
|
25
|
+
"./merge-refs": {
|
|
26
|
+
"types": "./types/merge-refs.d.ts",
|
|
27
|
+
"default": "./src/merge-refs.js"
|
|
23
28
|
}
|
|
24
29
|
},
|
|
25
30
|
"dependencies": {
|
|
26
31
|
"esrap": "^2.1.0",
|
|
27
32
|
"zimmerframe": "^1.1.2",
|
|
28
|
-
"@tsrx/core": "0.0.
|
|
33
|
+
"@tsrx/core": "0.0.19"
|
|
29
34
|
},
|
|
30
35
|
"peerDependencies": {
|
|
31
36
|
"vue": ">=3.5",
|
package/src/index.js
CHANGED
|
@@ -26,9 +26,19 @@ export function parse(source, filename, options) {
|
|
|
26
26
|
*/
|
|
27
27
|
export function compile(source, filename, options) {
|
|
28
28
|
const errors = /** @type {CompileError[]} */ ([]);
|
|
29
|
+
const comments = /** @type {AST.CommentWithLocation[]} */ ([]);
|
|
29
30
|
const collect = !!options?.loose;
|
|
30
|
-
const ast = parseModule(
|
|
31
|
-
|
|
31
|
+
const ast = parseModule(
|
|
32
|
+
source,
|
|
33
|
+
filename,
|
|
34
|
+
collect ? { loose: true, errors, comments } : undefined,
|
|
35
|
+
);
|
|
36
|
+
const { ast: _ast, ...result } = transform(
|
|
37
|
+
ast,
|
|
38
|
+
source,
|
|
39
|
+
filename,
|
|
40
|
+
collect ? { loose: true, errors, comments } : undefined,
|
|
41
|
+
);
|
|
32
42
|
return { ...result, errors };
|
|
33
43
|
}
|
|
34
44
|
|
|
@@ -42,8 +52,13 @@ export function compile(source, filename, options) {
|
|
|
42
52
|
*/
|
|
43
53
|
export function compile_to_volar_mappings(source, filename, options) {
|
|
44
54
|
const errors = /** @type {import('@tsrx/core/types').CompileError[]} */ ([]);
|
|
45
|
-
const
|
|
46
|
-
const
|
|
55
|
+
const comments = /** @type {AST.CommentWithLocation[]} */ ([]);
|
|
56
|
+
const ast = parseModule(source, filename, { ...options, errors, comments });
|
|
57
|
+
const transformed = transform(ast, source, filename, {
|
|
58
|
+
loose: true,
|
|
59
|
+
errors,
|
|
60
|
+
comments,
|
|
61
|
+
});
|
|
47
62
|
const result = createVolarMappingsResult({
|
|
48
63
|
ast: transformed.ast,
|
|
49
64
|
ast_from_source: ast,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { mergeRefs } from '@tsrx/core/runtime/merge-refs';
|
package/src/transform.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
clone_identifier,
|
|
7
7
|
componentToFunctionDeclaration,
|
|
8
8
|
createJsxTransform,
|
|
9
|
-
|
|
9
|
+
error,
|
|
10
10
|
identifier_to_jsx_name,
|
|
11
11
|
setLocation,
|
|
12
12
|
} from '@tsrx/core';
|
|
@@ -25,10 +25,12 @@ const vue_platform = {
|
|
|
25
25
|
imports: {
|
|
26
26
|
suspense: 'vue',
|
|
27
27
|
errorBoundary: '@tsrx/vue/error-boundary',
|
|
28
|
+
mergeRefs: '@tsrx/vue/merge-refs',
|
|
28
29
|
},
|
|
29
30
|
jsx: {
|
|
30
31
|
rewriteClassAttr: false,
|
|
31
32
|
acceptedTsxKinds: ['vue'],
|
|
33
|
+
multiRefStrategy: 'merge-refs',
|
|
32
34
|
},
|
|
33
35
|
validation: {
|
|
34
36
|
requireUseServerForAwait: true,
|
|
@@ -66,13 +68,22 @@ const vue_platform = {
|
|
|
66
68
|
metadata: { path: [] },
|
|
67
69
|
};
|
|
68
70
|
},
|
|
69
|
-
transformElementChildren(node, walked_children, raw_children, attributes) {
|
|
70
|
-
return rewrite_host_text_or_html_children(
|
|
71
|
+
transformElementChildren(node, walked_children, raw_children, attributes, ctx) {
|
|
72
|
+
return rewrite_host_text_or_html_children(
|
|
73
|
+
node,
|
|
74
|
+
walked_children,
|
|
75
|
+
raw_children,
|
|
76
|
+
attributes,
|
|
77
|
+
ctx,
|
|
78
|
+
);
|
|
71
79
|
},
|
|
72
|
-
validateComponentAwait(await_expression) {
|
|
73
|
-
|
|
74
|
-
await_expression,
|
|
80
|
+
validateComponentAwait(await_expression, _component, ctx) {
|
|
81
|
+
error(
|
|
75
82
|
'`await` is not yet supported in Vue TSRX components.',
|
|
83
|
+
ctx?.filename ?? null,
|
|
84
|
+
await_expression,
|
|
85
|
+
ctx?.errors,
|
|
86
|
+
ctx?.comments,
|
|
76
87
|
);
|
|
77
88
|
},
|
|
78
89
|
componentToFunction(component, ctx, helper_state) {
|
|
@@ -404,77 +415,33 @@ function is_vue_setup_call(call_expression) {
|
|
|
404
415
|
}
|
|
405
416
|
|
|
406
417
|
/**
|
|
418
|
+
* Reject `{ref expr}` on composite (component-like) elements: Vue component
|
|
419
|
+
* refs resolve to the component instance, not the rendered DOM node, so
|
|
420
|
+
* Ripple-style component refs don't have a meaningful DOM target. Multi-ref
|
|
421
|
+
* merging itself is handled by the shared `merge_duplicate_refs` pass via
|
|
422
|
+
* the platform's `multiRefStrategy: 'merge-refs'` config.
|
|
423
|
+
*
|
|
407
424
|
* @param {any[]} attrs
|
|
408
425
|
* @param {any} element
|
|
409
426
|
* @param {any} transform_context
|
|
410
427
|
* @returns {any[]}
|
|
411
428
|
*/
|
|
412
429
|
function preprocess_ref_attributes(attrs, element, transform_context) {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
const ref_attrs = [];
|
|
417
|
-
|
|
430
|
+
if (!is_component_like_element(element)) {
|
|
431
|
+
return attrs;
|
|
432
|
+
}
|
|
418
433
|
for (const attr of attrs) {
|
|
419
|
-
if (
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
434
|
+
if (attr?.type === 'RefAttribute') {
|
|
435
|
+
error(
|
|
436
|
+
'`{ref ...}` on the Vue target is only supported on host elements. Vue component refs resolve to component instances rather than the rendered DOM node, so Ripple-style component refs are not supported here.',
|
|
437
|
+
transform_context?.filename ?? null,
|
|
438
|
+
attr,
|
|
439
|
+
transform_context?.errors,
|
|
440
|
+
transform_context?.comments,
|
|
441
|
+
);
|
|
423
442
|
}
|
|
424
|
-
result.push(attr);
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
if (ref_attrs.length > 0 && is_component_like_element(element)) {
|
|
428
|
-
throw create_compile_error(
|
|
429
|
-
ref_attrs[0],
|
|
430
|
-
'`{ref ...}` on the Vue target is only supported on host elements. Vue component refs resolve to component instances rather than the rendered DOM node, so Ripple-style component refs are not supported here.',
|
|
431
|
-
);
|
|
432
443
|
}
|
|
433
|
-
|
|
434
|
-
if (ref_attrs.length === 1) {
|
|
435
|
-
result.push(ref_attrs[0]);
|
|
436
|
-
} else if (ref_attrs.length > 1) {
|
|
437
|
-
result.push({
|
|
438
|
-
type: 'RefAttribute',
|
|
439
|
-
argument: create_combined_ref_callback(ref_attrs),
|
|
440
|
-
loc: ref_attrs[0].loc,
|
|
441
|
-
metadata: { path: [] },
|
|
442
|
-
});
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
return result;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
/**
|
|
449
|
-
* @param {any[]} ref_attrs
|
|
450
|
-
* @returns {any}
|
|
451
|
-
*/
|
|
452
|
-
function create_combined_ref_callback(ref_attrs) {
|
|
453
|
-
const node_id = builders.id('node');
|
|
454
|
-
|
|
455
|
-
return {
|
|
456
|
-
type: 'ArrowFunctionExpression',
|
|
457
|
-
params: [node_id],
|
|
458
|
-
body: {
|
|
459
|
-
type: 'BlockStatement',
|
|
460
|
-
body: ref_attrs.map((attr) => ({
|
|
461
|
-
type: 'ExpressionStatement',
|
|
462
|
-
expression: {
|
|
463
|
-
type: 'CallExpression',
|
|
464
|
-
callee: attr.argument,
|
|
465
|
-
arguments: [clone_identifier(node_id)],
|
|
466
|
-
optional: false,
|
|
467
|
-
metadata: { path: [] },
|
|
468
|
-
},
|
|
469
|
-
metadata: { path: [] },
|
|
470
|
-
})),
|
|
471
|
-
metadata: { path: [] },
|
|
472
|
-
},
|
|
473
|
-
expression: false,
|
|
474
|
-
async: false,
|
|
475
|
-
generator: false,
|
|
476
|
-
metadata: { path: [] },
|
|
477
|
-
};
|
|
444
|
+
return attrs;
|
|
478
445
|
}
|
|
479
446
|
|
|
480
447
|
/**
|
|
@@ -482,9 +449,16 @@ function create_combined_ref_callback(ref_attrs) {
|
|
|
482
449
|
* @param {any[]} walked_children
|
|
483
450
|
* @param {any[]} raw_children
|
|
484
451
|
* @param {any[]} attributes
|
|
452
|
+
* @param {any} [transform_context]
|
|
485
453
|
* @returns {{ children: any[]; selfClosing?: boolean } | null}
|
|
486
454
|
*/
|
|
487
|
-
function rewrite_host_text_or_html_children(
|
|
455
|
+
function rewrite_host_text_or_html_children(
|
|
456
|
+
node,
|
|
457
|
+
walked_children,
|
|
458
|
+
raw_children,
|
|
459
|
+
attributes,
|
|
460
|
+
transform_context,
|
|
461
|
+
) {
|
|
488
462
|
const source_children = raw_children || walked_children;
|
|
489
463
|
const is_composite = is_component_like_element(node);
|
|
490
464
|
const html_children = source_children.filter((child) => child?.type === 'Html');
|
|
@@ -496,9 +470,12 @@ function rewrite_host_text_or_html_children(node, walked_children, raw_children,
|
|
|
496
470
|
has_dom_content_attribute(attributes, 'innerHTML') ||
|
|
497
471
|
has_dom_content_attribute(attributes, 'textContent')
|
|
498
472
|
) {
|
|
499
|
-
|
|
500
|
-
html_children[0],
|
|
473
|
+
error(
|
|
501
474
|
'`{html ...}` on the Vue target is only supported as the sole child of a host element. Use `innerHTML={...}` as an element attribute when you need the explicit prop form.',
|
|
475
|
+
transform_context?.filename ?? null,
|
|
476
|
+
html_children[0],
|
|
477
|
+
transform_context?.errors,
|
|
478
|
+
transform_context?.comments,
|
|
502
479
|
);
|
|
503
480
|
}
|
|
504
481
|
|
|
@@ -652,15 +629,20 @@ function inject_vue_imports(program, transform_context) {
|
|
|
652
629
|
if (transform_context.needs_error_boundary) {
|
|
653
630
|
ensure_named_import(program, '@tsrx/vue/error-boundary', 'TsrxErrorBoundary');
|
|
654
631
|
}
|
|
632
|
+
|
|
633
|
+
if (transform_context.needs_merge_refs) {
|
|
634
|
+
ensure_named_import(program, '@tsrx/vue/merge-refs', 'mergeRefs', '__mergeRefs');
|
|
635
|
+
}
|
|
655
636
|
}
|
|
656
637
|
|
|
657
638
|
/**
|
|
658
639
|
* @param {import('estree').Program} program
|
|
659
640
|
* @param {string} source
|
|
660
641
|
* @param {string} name
|
|
642
|
+
* @param {string} [local]
|
|
661
643
|
* @returns {void}
|
|
662
644
|
*/
|
|
663
|
-
function ensure_named_import(program, source, name) {
|
|
645
|
+
function ensure_named_import(program, source, name, local = name) {
|
|
664
646
|
for (const statement of program.body) {
|
|
665
647
|
if (statement.type !== 'ImportDeclaration' || statement.source?.value !== source) {
|
|
666
648
|
continue;
|
|
@@ -670,28 +652,30 @@ function ensure_named_import(program, source, name) {
|
|
|
670
652
|
(/** @type {any} */ specifier) =>
|
|
671
653
|
specifier.type === 'ImportSpecifier' &&
|
|
672
654
|
specifier.imported?.type === 'Identifier' &&
|
|
673
|
-
specifier.imported.name === name
|
|
655
|
+
specifier.imported.name === name &&
|
|
656
|
+
specifier.local?.name === local,
|
|
674
657
|
);
|
|
675
658
|
|
|
676
659
|
if (!has_specifier) {
|
|
677
|
-
statement.specifiers.push(create_import_specifier(name));
|
|
660
|
+
statement.specifiers.push(create_import_specifier(name, local));
|
|
678
661
|
}
|
|
679
662
|
|
|
680
663
|
return;
|
|
681
664
|
}
|
|
682
665
|
|
|
683
|
-
program.body.unshift(create_import_declaration(source, [create_import_specifier(name)]));
|
|
666
|
+
program.body.unshift(create_import_declaration(source, [create_import_specifier(name, local)]));
|
|
684
667
|
}
|
|
685
668
|
|
|
686
669
|
/**
|
|
687
670
|
* @param {string} name
|
|
671
|
+
* @param {string} [local]
|
|
688
672
|
* @returns {any}
|
|
689
673
|
*/
|
|
690
|
-
function create_import_specifier(name) {
|
|
674
|
+
function create_import_specifier(name, local = name) {
|
|
691
675
|
return {
|
|
692
676
|
type: 'ImportSpecifier',
|
|
693
677
|
imported: builders.id(name),
|
|
694
|
-
local: builders.id(
|
|
678
|
+
local: builders.id(local),
|
|
695
679
|
importKind: 'value',
|
|
696
680
|
metadata: { path: [] },
|
|
697
681
|
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface TsrxErrorBoundaryProps {
|
|
2
|
+
content: () => any;
|
|
3
|
+
fallback: (error: unknown, reset: () => void) => any;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface TsrxErrorBoundaryComponent {
|
|
7
|
+
(props: TsrxErrorBoundaryProps): any;
|
|
8
|
+
__setup(): void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const TsrxErrorBoundary: TsrxErrorBoundaryComponent;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { mergeRefs } from '@tsrx/core/runtime/merge-refs';
|