Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9335bfd

Browse files
committed
feat(api): support TSMappedType
1 parentd944bb0 commit9335bfd

File tree

5 files changed

+170
-52
lines changed

5 files changed

+170
-52
lines changed

‎.changeset/hot-bugs-ring.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@vue-macros/better-define':minor
3+
'@vue-macros/api':minor
4+
---
5+
6+
support union key (TSMappedType)

‎packages/api/src/ts.ts‎

Lines changed: 98 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import path from 'node:path'
44
import{
55
babelParse,
66
getFileCodeAndLang,
7+
isStaticExpression,
8+
resolveLiteral,
79
resolveObjectKey,
810
}from'@vue-macros/common'
911
import{isDeclaration}from'@babel/types'
@@ -21,6 +23,7 @@ import type {
2123
TSInterfaceBody,
2224
TSInterfaceDeclaration,
2325
TSIntersectionType,
26+
TSMappedType,
2427
TSMethodSignature,
2528
TSModuleBlock,
2629
TSModuleDeclaration,
@@ -30,6 +33,7 @@ import type {
3033
TSTypeAliasDeclaration,
3134
TSTypeElement,
3235
TSTypeLiteral,
36+
UnaryExpression,
3337
}from'@babel/types'
3438

3539
exporttypeTSDeclaration=
@@ -57,7 +61,7 @@ export interface TSProperties {
5761
{
5862
value:TSResolvedType<TSType>|null
5963
optional:boolean
60-
signature:TSResolvedType<TSPropertySignature>
64+
signature:TSResolvedType<TSPropertySignature|TSMappedType>
6165
}
6266
>
6367
}
@@ -100,62 +104,108 @@ export async function resolveTSProperties({
100104
type,
101105
scope,
102106
}:TSResolvedType<
103-
TSInterfaceDeclaration|TSInterfaceBody|TSTypeLiteral|TSIntersectionType
107+
|TSInterfaceDeclaration
108+
|TSInterfaceBody
109+
|TSTypeLiteral
110+
|TSIntersectionType
111+
|TSMappedType
104112
>):Promise<TSProperties>{
105-
if(type.type==='TSInterfaceBody'){
106-
returnresolveTypeElements(scope,type.body)
107-
}elseif(type.type==='TSTypeLiteral'){
108-
returnresolveTypeElements(scope,type.members)
109-
}elseif(type.type==='TSInterfaceDeclaration'){
110-
letproperties=resolveTypeElements(scope,type.body.body)
111-
if(type.extends){
112-
constresolvedExtends=(
113-
awaitPromise.all(
114-
type.extends.map((node)=>
115-
node.expression.type==='Identifier'
116-
?resolveTSReferencedType({
117-
scope,
118-
type:node.expression,
119-
})
120-
:undefined
121-
)
122-
)
123-
)
124-
// eslint-disable-next-line unicorn/no-array-callback-reference
125-
.filter(filterValidExtends)
126-
127-
if(resolvedExtends.length>0){
128-
constext=(
113+
switch(type.type){
114+
case'TSInterfaceBody':
115+
returnresolveTypeElements(scope,type.body)
116+
case'TSTypeLiteral':
117+
returnresolveTypeElements(scope,type.members)
118+
case'TSInterfaceDeclaration':{
119+
letproperties=resolveTypeElements(scope,type.body.body)
120+
if(type.extends){
121+
constresolvedExtends=(
129122
awaitPromise.all(
130-
resolvedExtends.map((resolved)=>resolveTSProperties(resolved))
123+
type.extends.map((node)=>
124+
node.expression.type==='Identifier'
125+
?resolveTSReferencedType({
126+
scope,
127+
type:node.expression,
128+
})
129+
:undefined
130+
)
131131
)
132-
).reduceRight((acc,curr)=>mergeTSProperties(acc,curr))
133-
properties=mergeTSProperties(ext,properties)
132+
)
133+
// eslint-disable-next-line unicorn/no-array-callback-reference
134+
.filter(filterValidExtends)
135+
136+
if(resolvedExtends.length>0){
137+
constext=(
138+
awaitPromise.all(
139+
resolvedExtends.map((resolved)=>resolveTSProperties(resolved))
140+
)
141+
).reduceRight((acc,curr)=>mergeTSProperties(acc,curr))
142+
properties=mergeTSProperties(ext,properties)
143+
}
134144
}
145+
returnproperties
135146
}
136-
returnproperties
137-
}elseif(type.type==='TSIntersectionType'){
138-
letproperties:TSProperties={
139-
callSignatures:[],
140-
constructSignatures:[],
141-
methods:{},
142-
properties:{},
147+
case'TSIntersectionType':{
148+
letproperties:TSProperties={
149+
callSignatures:[],
150+
constructSignatures:[],
151+
methods:{},
152+
properties:{},
153+
}
154+
for(constsubTypeoftype.types){
155+
constresolved=awaitresolveTSReferencedType({
156+
scope,
157+
type:subType,
158+
})
159+
if(!filterValidExtends(resolved))continue
160+
properties=mergeTSProperties(
161+
properties,
162+
awaitresolveTSProperties(resolved)
163+
)
164+
}
165+
returnproperties
143166
}
144-
for(constsubTypeoftype.types){
145-
constresolved=awaitresolveTSReferencedType({
167+
case'TSMappedType':{
168+
constproperties:TSProperties={
169+
callSignatures:[],
170+
constructSignatures:[],
171+
methods:{},
172+
properties:{},
173+
}
174+
if(!type.typeParameter.constraint)returnproperties
175+
176+
constconstraint=awaitresolveTSReferencedType({
177+
type:type.typeParameter.constraint,
146178
scope,
147-
type:subType,
148179
})
149-
if(!filterValidExtends(resolved))continue
150-
properties=mergeTSProperties(
151-
properties,
152-
awaitresolveTSProperties(resolved)
153-
)
180+
if(!constraint?.type)returnproperties
181+
182+
consttypes=
183+
constraint.type.type==='TSUnionType'
184+
?constraint.type.types
185+
:[constraint.type]
186+
187+
for(constsubTypeoftypes){
188+
if(subType.type!=='TSLiteralType')continue
189+
constliteral=subType.literal
190+
if(!isStaticExpression(literal))continue
191+
constkey=resolveLiteral(
192+
literalasExclude<typeofliteral,UnaryExpression>
193+
)
194+
if(!key)continue
195+
properties.properties[String(key)]={
196+
value:type.typeAnnotation
197+
?{ scope,type:type.typeAnnotation}
198+
:null,
199+
optional:type.optional==='+'||type.optional===true,
200+
signature:{ type, scope},
201+
}
202+
}
203+
204+
returnproperties
154205
}
155-
returnproperties
156-
}else{
157-
//@ts-expect-error type is never
158-
thrownewError(`unknown node:${type?.type}`)
206+
default:
207+
//@ts-expect-error type is never
208+
thrownewError(`unknown node:${type?.type}`)
159209
}
160210

161211
functionfilterValidExtends(

‎packages/api/src/vue/props.ts‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import type {
2626
StringLiteral,
2727
TSInterfaceDeclaration,
2828
TSIntersectionType,
29+
TSMappedType,
2930
TSMethodSignature,
3031
TSPropertySignature,
3132
TSType,
@@ -368,9 +369,12 @@ export async function handleTSPropsDefinition({
368369
}
369370
}elseif(
370371
definitionsAst.type!=='TSInterfaceDeclaration'&&
371-
definitionsAst.type!=='TSTypeLiteral'
372+
definitionsAst.type!=='TSTypeLiteral'&&
373+
definitionsAst.type!=='TSMappedType'
372374
)
373-
thrownewSyntaxError(`Cannot resolve TS definition.`)
375+
thrownewSyntaxError(
376+
`Cannot resolve TS definition:${definitionsAst.type}.`
377+
)
374378

375379
constproperties=awaitresolveTSProperties({
376380
scope,
@@ -504,7 +508,7 @@ export interface TSPropsProperty {
504508
type:'property'
505509
value:ASTDefinition<TSResolvedType['type']>|undefined
506510
optional:boolean
507-
signature:ASTDefinition<TSPropertySignature>
511+
signature:ASTDefinition<TSPropertySignature|TSMappedType>
508512

509513
/** Whether added by `addProp` API */
510514
addByAPI:boolean
@@ -521,7 +525,11 @@ export interface TSProps extends PropsBase {
521525

522526
definitions:Record<string|number,TSPropsMethod|TSPropsProperty>
523527
definitionsAst:ASTDefinition<
524-
TSInterfaceDeclaration|TSTypeLiteral|TSIntersectionType|TSUnionType
528+
|TSInterfaceDeclaration
529+
|TSTypeLiteral
530+
|TSIntersectionType
531+
|TSUnionType
532+
|TSMappedType
525533
>
526534

527535
/**

‎packages/better-define/tests/__snapshots__/fixtures.test.ts.snap‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,52 @@ export { unionEmits as default };
590590
"
591591
`;
592592

593+
exports[`fixtures > tests/fixtures/union-props.vue > isProduction = false 1`]=`
594+
"import{defineComponent} from 'vue';
595+
import _export_sfc from '/plugin-vue/export-helper';
596+
597+
var _sfc_main = /* @__PURE__ */ defineComponent({
598+
__name: \\"union-props\\",
599+
props: {
600+
\\"foo\\": { type: [String,Number], required:true },
601+
\\"bar\\": { type: [String,Number], required:true },
602+
\\"optional\\": { type:Boolean, required:false }
603+
},
604+
setup(__props) {
605+
return () => {
606+
};
607+
}
608+
});
609+
610+
var unionProps = /* @__PURE__ */ _export_sfc(_sfc_main, [__FILE__]);
611+
612+
export{unionPropsasdefault};
613+
"
614+
`;
615+
616+
exports[`fixtures > tests/fixtures/union-props.vue > isProduction = true 1`]=`
617+
"import{defineComponent} from 'vue';
618+
import _export_sfc from '/plugin-vue/export-helper';
619+
620+
var _sfc_main = /* @__PURE__ */ defineComponent({
621+
__name: \\"union-props\\",
622+
props: {
623+
\\"foo\\":null,
624+
\\"bar\\":null,
625+
\\"optional\\": { type:Boolean }
626+
},
627+
setup(__props) {
628+
return () => {
629+
};
630+
}
631+
});
632+
633+
var unionProps = /* @__PURE__ */ _export_sfc(_sfc_main, [__FILE__]);
634+
635+
export{unionPropsasdefault};
636+
"
637+
`;
638+
593639
exports[`fixtures > tests/fixtures/unresolved.vue > isProduction = false 1`]=`
594640
"import{defineComponent} from 'vue';
595641
import _export_sfc from '/plugin-vue/export-helper';
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<script setup lang="ts">
2+
typeT='foo'|'bar'
3+
defineProps<
4+
{ [KinT]:string|number }& {
5+
[Kin'optional']?:boolean
6+
}
7+
>()
8+
</script>

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp