@tsrx/vue 0.0.22 → 0.1.0
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 +5 -5
- package/src/index.js +2 -0
- package/src/ref.js +1 -0
- package/src/transform.js +122 -3
- package/types/index.d.ts +2 -0
- package/types/ref.d.ts +1 -0
- package/src/merge-refs.js +0 -1
- package/types/merge-refs.d.ts +0 -1
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.1.0",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"publishConfig": {
|
|
9
9
|
"access": "public"
|
|
@@ -22,16 +22,16 @@
|
|
|
22
22
|
"types": "./types/error-boundary.d.ts",
|
|
23
23
|
"default": "./src/error-boundary.js"
|
|
24
24
|
},
|
|
25
|
-
"./
|
|
26
|
-
"types": "./types/
|
|
27
|
-
"default": "./src/
|
|
25
|
+
"./ref": {
|
|
26
|
+
"types": "./types/ref.d.ts",
|
|
27
|
+
"default": "./src/ref.js"
|
|
28
28
|
}
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"esrap": "^2.1.0",
|
|
32
32
|
"is-reference": "^3.0.3",
|
|
33
33
|
"zimmerframe": "^1.1.2",
|
|
34
|
-
"@tsrx/core": "0.0
|
|
34
|
+
"@tsrx/core": "0.1.0"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"vue": ">=3.5",
|
package/src/index.js
CHANGED
package/src/ref.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@tsrx/core/runtime/ref';
|
package/src/transform.js
CHANGED
|
@@ -6,11 +6,15 @@ import {
|
|
|
6
6
|
builders,
|
|
7
7
|
clone_expression_node,
|
|
8
8
|
clone_identifier,
|
|
9
|
+
CREATE_REF_PROP_INTERNAL_NAME,
|
|
9
10
|
create_generated_identifier,
|
|
10
11
|
componentToFunctionDeclaration,
|
|
11
12
|
createJsxTransform,
|
|
12
13
|
error,
|
|
14
|
+
MERGE_REFS_INTERNAL_NAME,
|
|
15
|
+
NORMALIZE_SPREAD_PROPS_INTERNAL_NAME,
|
|
13
16
|
setLocation,
|
|
17
|
+
toJsxAttribute,
|
|
14
18
|
} from '@tsrx/core';
|
|
15
19
|
|
|
16
20
|
/**
|
|
@@ -27,12 +31,14 @@ const vue_platform = {
|
|
|
27
31
|
imports: {
|
|
28
32
|
suspense: 'vue',
|
|
29
33
|
errorBoundary: '@tsrx/vue/error-boundary',
|
|
30
|
-
mergeRefs: '@tsrx/vue/
|
|
34
|
+
mergeRefs: '@tsrx/vue/ref',
|
|
35
|
+
refProp: '@tsrx/vue/ref',
|
|
31
36
|
},
|
|
32
37
|
jsx: {
|
|
33
38
|
rewriteClassAttr: false,
|
|
34
39
|
acceptedTsxKinds: ['vue'],
|
|
35
40
|
multiRefStrategy: 'merge-refs',
|
|
41
|
+
hostSpreadRefStrategy: 'explicit-ref-attr',
|
|
36
42
|
},
|
|
37
43
|
validation: {
|
|
38
44
|
requireUseServerForAwait: true,
|
|
@@ -58,6 +64,13 @@ const vue_platform = {
|
|
|
58
64
|
preprocessElementAttributes(attrs, ctx, element) {
|
|
59
65
|
return preprocess_ref_attributes(attrs, element, ctx);
|
|
60
66
|
},
|
|
67
|
+
transformElementAttributes(attrs, ctx, element) {
|
|
68
|
+
const result = attrs.map((attr) => toJsxAttribute(attr, ctx));
|
|
69
|
+
if (!ctx.typeOnly || is_component_like_element(element)) {
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
return result.map(mark_type_only_host_ref_attribute);
|
|
73
|
+
},
|
|
61
74
|
renderForOf: (node, loop_params, body_statements, ctx) =>
|
|
62
75
|
render_for_of_as_vapor_for(node, loop_params, body_statements, ctx),
|
|
63
76
|
createErrorBoundaryContent(try_content) {
|
|
@@ -93,6 +106,34 @@ const vue_platform = {
|
|
|
93
106
|
|
|
94
107
|
export const transform = createJsxTransform(vue_platform);
|
|
95
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Vue's `VNodeRef` type is wider than TSRX host refs because it also supports
|
|
111
|
+
* component instances and null teardown values. In editor-only TSX, keep the ref
|
|
112
|
+
* expression unchanged but stop TypeScript verification from reporting that
|
|
113
|
+
* Vue-specific assignability diagnostic on the generated `ref` prop token.
|
|
114
|
+
*
|
|
115
|
+
* @param {any} attr
|
|
116
|
+
* @returns {any}
|
|
117
|
+
*/
|
|
118
|
+
function mark_type_only_host_ref_attribute(attr) {
|
|
119
|
+
if (
|
|
120
|
+
!attr ||
|
|
121
|
+
attr.type !== 'JSXAttribute' ||
|
|
122
|
+
attr.name?.type !== 'JSXIdentifier' ||
|
|
123
|
+
attr.name.name !== 'ref'
|
|
124
|
+
) {
|
|
125
|
+
return attr;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
...attr,
|
|
130
|
+
name: {
|
|
131
|
+
...attr.name,
|
|
132
|
+
metadata: { ...(attr.name.metadata || {}), disable_verification: true },
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
96
137
|
/**
|
|
97
138
|
* @param {any} component
|
|
98
139
|
* @param {any} transform_context
|
|
@@ -817,6 +858,7 @@ function preprocess_ref_attributes(attrs, element, transform_context) {
|
|
|
817
858
|
if (!is_component_like_element(element)) {
|
|
818
859
|
return attrs;
|
|
819
860
|
}
|
|
861
|
+
const result = [];
|
|
820
862
|
for (const attr of attrs) {
|
|
821
863
|
if (attr?.type === 'RefAttribute') {
|
|
822
864
|
error(
|
|
@@ -827,8 +869,72 @@ function preprocess_ref_attributes(attrs, element, transform_context) {
|
|
|
827
869
|
transform_context?.comments,
|
|
828
870
|
);
|
|
829
871
|
}
|
|
872
|
+
if (!transform_context.typeOnly && is_vue_named_ref_attribute(attr)) {
|
|
873
|
+
result.push(create_vue_named_ref_spread(attr));
|
|
874
|
+
continue;
|
|
875
|
+
}
|
|
876
|
+
result.push(attr);
|
|
877
|
+
}
|
|
878
|
+
return result;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
/**
|
|
882
|
+
* Vue's JSX transform treats prop names ending in `ref` as template-ref
|
|
883
|
+
* sugar on components. Keep named TSRX refs as ordinary runtime props by
|
|
884
|
+
* hiding the static prop name behind an object spread before Vue sees the JSX.
|
|
885
|
+
* Type-only virtual TSX skips that spread so Volar can offer completions on
|
|
886
|
+
* the real component prop name.
|
|
887
|
+
*
|
|
888
|
+
* @param {any} attr
|
|
889
|
+
* @returns {boolean}
|
|
890
|
+
*/
|
|
891
|
+
function is_vue_named_ref_attribute(attr) {
|
|
892
|
+
const attr_name = get_vue_attribute_name(attr);
|
|
893
|
+
const value = get_vue_attribute_expression(attr);
|
|
894
|
+
return !!(
|
|
895
|
+
attr_name &&
|
|
896
|
+
attr_name !== 'ref' &&
|
|
897
|
+
(attr?.type === 'Attribute' || attr?.type === 'JSXAttribute') &&
|
|
898
|
+
(value?.type === 'RefExpression' ||
|
|
899
|
+
(value?.type === 'CallExpression' &&
|
|
900
|
+
value.callee?.type === 'Identifier' &&
|
|
901
|
+
value.callee.name === CREATE_REF_PROP_INTERNAL_NAME))
|
|
902
|
+
);
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/**
|
|
906
|
+
* @param {any} attr
|
|
907
|
+
* @returns {any}
|
|
908
|
+
*/
|
|
909
|
+
function create_vue_named_ref_spread(attr) {
|
|
910
|
+
const attr_name = get_vue_attribute_name(attr);
|
|
911
|
+
const value = get_vue_attribute_expression(attr);
|
|
912
|
+
if (attr_name === null) return attr;
|
|
913
|
+
const prop = builders.prop('init', builders.key(attr_name), value, false, false);
|
|
914
|
+
return builders.jsx_spread_attribute(builders.object([prop], attr), attr);
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
/**
|
|
918
|
+
* @param {any} attr
|
|
919
|
+
* @returns {string | null}
|
|
920
|
+
*/
|
|
921
|
+
function get_vue_attribute_name(attr) {
|
|
922
|
+
if (attr?.type === 'Attribute') {
|
|
923
|
+
return typeof attr.name === 'string' ? attr.name : (attr.name?.name ?? null);
|
|
924
|
+
}
|
|
925
|
+
if (attr?.type === 'JSXAttribute') {
|
|
926
|
+
return attr.name?.type === 'JSXIdentifier' ? attr.name.name : null;
|
|
830
927
|
}
|
|
831
|
-
return
|
|
928
|
+
return null;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
/**
|
|
932
|
+
* @param {any} attr
|
|
933
|
+
* @returns {any}
|
|
934
|
+
*/
|
|
935
|
+
function get_vue_attribute_expression(attr) {
|
|
936
|
+
const value = attr?.value;
|
|
937
|
+
return value?.type === 'JSXExpressionContainer' ? value.expression : value;
|
|
832
938
|
}
|
|
833
939
|
|
|
834
940
|
/**
|
|
@@ -1008,7 +1114,20 @@ function inject_vue_imports(program, transform_context) {
|
|
|
1008
1114
|
}
|
|
1009
1115
|
|
|
1010
1116
|
if (transform_context.needs_merge_refs) {
|
|
1011
|
-
ensure_named_import(program, '@tsrx/vue/
|
|
1117
|
+
ensure_named_import(program, '@tsrx/vue/ref', 'mergeRefs', MERGE_REFS_INTERNAL_NAME);
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
if (transform_context.needs_ref_prop) {
|
|
1121
|
+
ensure_named_import(program, '@tsrx/vue/ref', 'create_ref_prop', CREATE_REF_PROP_INTERNAL_NAME);
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
if (transform_context.needs_normalize_spread_props) {
|
|
1125
|
+
ensure_named_import(
|
|
1126
|
+
program,
|
|
1127
|
+
'@tsrx/vue/ref',
|
|
1128
|
+
'normalize_spread_props',
|
|
1129
|
+
NORMALIZE_SPREAD_PROPS_INTERNAL_NAME,
|
|
1130
|
+
);
|
|
1012
1131
|
}
|
|
1013
1132
|
}
|
|
1014
1133
|
|
package/types/index.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import type { CompileFn, ParseOptions, VolarCompileFn } from '@tsrx/core/types';
|
|
|
3
3
|
|
|
4
4
|
export function parse(source: string, filename?: string, options?: ParseOptions): Program;
|
|
5
5
|
|
|
6
|
+
export { isRefProp } from './ref.js';
|
|
7
|
+
|
|
6
8
|
export const compile: CompileFn;
|
|
7
9
|
|
|
8
10
|
export const compile_to_volar_mappings: VolarCompileFn;
|
package/types/ref.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@tsrx/core/runtime/ref';
|
package/src/merge-refs.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { mergeRefs } from '@tsrx/core/runtime/merge-refs';
|
package/types/merge-refs.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { mergeRefs } from '@tsrx/core/runtime/merge-refs';
|