Skip to content

Commit b9f6445

Browse files
authored
Merge pull request #13 from jaredmcateer/prop-types
2 parents e7d3a27 + 74d733a commit b9f6445

File tree

3 files changed

+129
-19
lines changed

3 files changed

+129
-19
lines changed

src/plugins/vue-property-decorator/Prop.ts

Lines changed: 87 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import ts from "typescript";
99
import { TsHelper } from "../../helpers/TsHelper";
1010

1111
const propDecoratorName = "Prop";
12+
let $t: TsHelper;
1213

1314
export const convertProp: ASTConverter<ts.PropertyDeclaration> = (node, options) => {
1415
if (!node.decorators) {
@@ -19,28 +20,30 @@ export const convertProp: ASTConverter<ts.PropertyDeclaration> = (node, options)
1920
);
2021
if (decorator) {
2122
const propType = "PropType";
22-
const $t = new TsHelper(options);
23-
const type = node.type?.kind;
23+
$t = new TsHelper(options);
24+
let type = node.type?.kind;
2425
const decoratorArguments = (decorator.expression as ts.CallExpression).arguments;
2526
const hasKnowableType =
2627
type !== undefined &&
2728
type !== ts.SyntaxKind.AnyKeyword &&
2829
type !== ts.SyntaxKind.UndefinedKeyword &&
2930
type !== ts.SyntaxKind.UnknownKeyword;
30-
let addedPropKey = false;
31+
let addedPropType = false;
32+
let addTodoComplex = false;
33+
34+
let props: ts.ObjectLiteralElementLike[] = [];
35+
const propName = node.name.getText();
3136

3237
if (decoratorArguments.length > 0 || hasKnowableType) {
33-
const propName = node.name.getText();
3438
const propArguments = decoratorArguments[0];
35-
let props: ts.ObjectLiteralElementLike[] = [];
3639
if (propArguments && $t.module.isObjectLiteralExpression(propArguments)) {
3740
props = propArguments.properties.reduce((accumulator, property) => {
3841
if (property.kind === ts.SyntaxKind.PropertyAssignment) {
3942
let initializer: ts.AsExpression = property.initializer as ts.AsExpression;
4043
if (node.type && property.name.getText() === "type") {
4144
const typeReference = $t.factory.createTypeReferenceNode(propType, [node.type]);
4245
initializer = $t.factory.createAsExpression(property.initializer, typeReference);
43-
addedPropKey = true;
46+
addedPropType = true;
4447
}
4548

4649
const newProperty = $t.factory.createPropertyAssignment(property.name, initializer);
@@ -49,26 +52,91 @@ export const convertProp: ASTConverter<ts.PropertyDeclaration> = (node, options)
4952

5053
return accumulator;
5154
}, [] as ts.ObjectLiteralElementLike[]);
52-
}
55+
} else if (node.type && hasKnowableType) {
56+
let primType: string | undefined;
57+
58+
if ($t.module.isLiteralTypeNode(node.type)) {
59+
type = node.type.literal.kind;
60+
}
5361

54-
const args = $t.factory.createObjectLiteralExpression(props);
55-
56-
return {
57-
tag: "Prop",
58-
kind: ASTResultKind.COMPOSITION,
59-
imports: addedPropKey ? $t.namedImports([propType]) : [],
60-
reference: ReferenceKind.PROPS,
61-
attributes: [propName],
62-
nodes: [
63-
$t.copySyntheticComments($t.factory.createPropertyAssignment(propName, args), node),
64-
],
65-
};
62+
switch (type) {
63+
case ts.SyntaxKind.StringLiteral:
64+
addedPropType = true;
65+
primType = "String";
66+
break;
67+
case ts.SyntaxKind.StringKeyword:
68+
primType = "String";
69+
break;
70+
case ts.SyntaxKind.TrueKeyword:
71+
case ts.SyntaxKind.FalseKeyword:
72+
addedPropType = true;
73+
primType = "Boolean";
74+
break;
75+
case ts.SyntaxKind.BooleanKeyword:
76+
primType = "Boolean";
77+
break;
78+
case ts.SyntaxKind.NumericLiteral:
79+
addedPropType = true;
80+
primType = "Number";
81+
break;
82+
case ts.SyntaxKind.NumberKeyword:
83+
primType = "Number";
84+
break;
85+
default:
86+
addTodoComplex = true;
87+
break;
88+
}
89+
90+
if (primType) {
91+
const vueIdentifier = $t.factory.createIdentifier(primType);
92+
const tsIdentifier = addedPropType
93+
? $t.factory.createIdentifier(node.type.getText())
94+
: undefined;
95+
props = [createPropTypeAssignment(vueIdentifier, tsIdentifier)];
96+
}
97+
}
6698
}
99+
const args = $t.factory.createObjectLiteralExpression(props.length > 0 ? props : undefined);
100+
let propAssignment = $t.factory.createPropertyAssignment(propName, args);
101+
propAssignment = addTodoComplex
102+
? $t.addTodoComment(
103+
propAssignment,
104+
`Too complex to determine primitive type: ${node.type!.getText()} `,
105+
true
106+
)
107+
: propAssignment;
108+
109+
return {
110+
tag: "Prop",
111+
kind: ASTResultKind.COMPOSITION,
112+
imports: addedPropType ? $t.namedImports([propType]) : [],
113+
reference: ReferenceKind.PROPS,
114+
attributes: [propName],
115+
nodes: [$t.copySyntheticComments(propAssignment, node)],
116+
};
67117
}
68118

69119
return false;
70120
};
71121

122+
function createPropTypeAssignment(
123+
vueTypeIdentifier: ts.Identifier,
124+
tsTypeIdentifier?: ts.Identifier
125+
) {
126+
const typeId = $t.factory.createIdentifier("type");
127+
128+
if (!tsTypeIdentifier) {
129+
return $t.factory.createPropertyAssignment(typeId, vueTypeIdentifier);
130+
}
131+
132+
const tsTypeRef = $t.factory.createTypeReferenceNode(tsTypeIdentifier, undefined);
133+
const propTypeId = $t.factory.createIdentifier("PropType");
134+
const propTypeRef = $t.factory.createTypeReferenceNode(propTypeId, [tsTypeRef]);
135+
const asExpr = $t.factory.createAsExpression(vueTypeIdentifier, propTypeRef);
136+
const propAssignment = $t.factory.createPropertyAssignment(typeId, asExpr);
137+
return propAssignment;
138+
}
139+
72140
export const mergeProps: ASTTransform = (astResults, options) => {
73141
const $t = new TsHelper(options);
74142
const propTags = ["Prop", "Model"];

tests/__snapshots__/testTSFile.spec.ts.snap

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@ export default defineComponent({
3131
foo: { type: Boolean, default: false },
3232
bar: { type: Number as PropType<number>, default: 1 },
3333
foobar: { type: Object as PropType<CustomType> },
34+
noType: {},
35+
stringType: { type: String },
36+
booleanType: { type: Boolean },
37+
numberType: { type: Number },
38+
stringLiteralType: { type: String as PropType<\\"foo\\"> },
39+
numericLiteral: { type: Number as PropType<2> },
40+
booleanLiteral: { type: Boolean as PropType<true> },
41+
/* TODO: Too complex to determine primitive type: true | \\"false\\" */ complexType:
42+
{},
43+
/* TODO: Too complex to determine primitive type: string[] */ complexType2:
44+
{},
3445
},
3546
name: \\"oao\\",
3647
setup(props, context) {
@@ -247,6 +258,17 @@ export default defineComponent({
247258
foo: { type: Boolean, default: false },
248259
bar: { type: Number as PropType<number>, default: 1 },
249260
foobar: { type: Object as PropType<CustomType> },
261+
noType: {},
262+
stringType: { type: String },
263+
booleanType: { type: Boolean },
264+
numberType: { type: Number },
265+
stringLiteralType: { type: String as PropType<\\"foo\\"> },
266+
numericLiteral: { type: Number as PropType<2> },
267+
booleanLiteral: { type: Boolean as PropType<true> },
268+
/* TODO: Too complex to determine primitive type: true | \\"false\\" */ complexType:
269+
{},
270+
/* TODO: Too complex to determine primitive type: string[] */ complexType2:
271+
{},
250272
},
251273
name: \\"oao\\",
252274
setup(props, ctx) {
@@ -462,6 +484,17 @@ export default defineComponent({
462484
foo: { type: Boolean, default: false },
463485
bar: { type: Number as PropType<number>, default: 1 },
464486
foobar: { type: Object as PropType<CustomType> },
487+
noType: {},
488+
stringType: { type: String },
489+
booleanType: { type: Boolean },
490+
numberType: { type: Number },
491+
stringLiteralType: { type: String as PropType<\\"foo\\"> },
492+
numericLiteral: { type: Number as PropType<2> },
493+
booleanLiteral: { type: Boolean as PropType<true> },
494+
/* TODO: Too complex to determine primitive type: true | \\"false\\" */ complexType:
495+
{},
496+
/* TODO: Too complex to determine primitive type: string[] */ complexType2:
497+
{},
465498
},
466499
name: \\"oao\\",
467500
setup(props, context) {

tests/fixture/Input.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ export default class BasicPropertyClass extends Vue {
2626
@Prop({ type: Boolean, default: false }) foo!;
2727
@Prop({ type: Number, default: 1 }) bar: number;
2828
@Prop({ type: Object }) foobar: CustomType;
29+
@Prop() noType: any;
30+
@Prop() stringType: string;
31+
@Prop() booleanType: boolean;
32+
@Prop() numberType: number;
33+
@Prop() stringLiteralType: "foo";
34+
@Prop() numericLiteral: 2;
35+
@Prop() booleanLiteral: true;
36+
@Prop() complexType: true | "false";
37+
@Prop() complexType2: string[];
2938

3039
@Action() actA;
3140
@Action("namespace/actD") actD;

0 commit comments

Comments
 (0)