Skip to content

Commit a66c06b

Browse files
authored
Merge pull request #4 from jaredmcateer/propkeys
2 parents 233338c + 4422795 commit a66c06b

File tree

7 files changed

+576
-549
lines changed

7 files changed

+576
-549
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ The files to be converted must meet the criteria below:
2929
- Object
3030
- [x] `name`
3131
- [x] `props`
32+
- [x] `PropType<...>`
3233
- [x] `data`
3334
- [ ] `computed`
3435
- [ ] `methods`

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

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ASTConverter, ASTResultKind, ASTTransform, ASTResultToObject, ReferenceKind } from '../types'
2-
import type ts from 'typescript'
2+
import ts from 'typescript'
33
import { copySyntheticComments } from '../../utils'
44

55
const propDecoratorName = 'Prop'
@@ -10,24 +10,48 @@ export const convertProp: ASTConverter<ts.PropertyDeclaration> = (node, options)
1010
}
1111
const decorator = node.decorators.find((el) => (el.expression as ts.CallExpression).expression.getText() === propDecoratorName)
1212
if (decorator) {
13+
const propType = 'PropType'
1314
const tsModule = options.typescript
15+
const type = node.type?.kind
1416
const decoratorArguments = (decorator.expression as ts.CallExpression).arguments
15-
if (decoratorArguments.length > 0) {
17+
const hasKnowableType = type !== undefined && type !== ts.SyntaxKind.AnyKeyword && type !== ts.SyntaxKind.UndefinedKeyword && type !== ts.SyntaxKind.UnknownKeyword
18+
let addedPropKey = false
19+
20+
if (decoratorArguments.length > 0 || hasKnowableType) {
1621
const propName = node.name.getText()
17-
const propArguments = decoratorArguments[0]
22+
const propArguments = decoratorArguments[0] as ts.ObjectLiteralExpression
23+
const props = propArguments.properties
24+
.reduce((accumulator, property) => {
25+
if (property.kind === ts.SyntaxKind.PropertyAssignment) {
26+
if (node.type && property.name.getText() === 'type') {
27+
const typeReference = ts.createTypeReferenceNode(propType, [node.type])
28+
property.initializer = tsModule.createAsExpression(property.initializer, typeReference)
29+
addedPropKey = true
30+
}
31+
32+
accumulator.push(property)
33+
}
34+
35+
return accumulator
36+
}, [] as ts.ObjectLiteralElementLike[])
37+
38+
const args = tsModule.createObjectLiteral(props)
1839

1940
return {
2041
tag: 'Prop',
21-
kind: ASTResultKind.OBJECT,
22-
imports: [],
42+
kind: ASTResultKind.COMPOSITION,
43+
imports: addedPropKey ? [{
44+
named: [propType],
45+
external: (options.compatible) ? '@vue/composition-api' : 'vue'
46+
}] : [],
2347
reference: ReferenceKind.PROPS,
2448
attributes: [propName],
2549
nodes: [
2650
copySyntheticComments(
2751
tsModule,
2852
tsModule.createPropertyAssignment(
2953
tsModule.createIdentifier(propName),
30-
propArguments
54+
args
3155
),
3256
node
3357
)
@@ -38,18 +62,20 @@ export const convertProp: ASTConverter<ts.PropertyDeclaration> = (node, options)
3862

3963
return false
4064
}
65+
4166
export const mergeProps: ASTTransform = (astResults, options) => {
4267
const tsModule = options.typescript
4368
const propTags = ['Prop', 'Model']
4469

4570
const propASTResults = astResults.filter((el) => propTags.includes(el.tag))
4671
const otherASTResults = astResults.filter((el) => !propTags.includes(el.tag))
4772
const modelASTResult = astResults.find((el) => el.tag === 'Model')
73+
const imports = propASTResults.find(el => el.imports.length > 0)?.imports || []
4874

4975
const mergeASTResult: ASTResultToObject = {
5076
tag: 'Prop',
5177
kind: ASTResultKind.OBJECT,
52-
imports: [],
78+
imports,
5379
reference: ReferenceKind.PROPS,
5480
attributes: propASTResults.map((el) => el.attributes).reduce((array, el) => array.concat(el), []),
5581
nodes: [

tests/__snapshots__/testTSFile.spec.ts.snap

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
exports[`testTSFile compatible 1`] = `
44
"import {
55
computed,
6+
PropType,
67
reactive,
78
toRefs,
89
ref,
@@ -27,7 +28,9 @@ export default defineComponent({
2728
/**
2829
* My foo
2930
*/
30-
foo: { type: Number, default: false }
31+
foo: { type: Boolean, default: false },
32+
bar: { type: Number as PropType<number>, default: 1 },
33+
foobar: { type: Object as PropType<CustomType> }
3134
},
3235
name: 'oao',
3336
setup(props, context) {
@@ -156,6 +159,7 @@ exports[`testTSFile compatible and ts config file: stderr 1`] = `""`;
156159
exports[`testTSFile compatible and ts config file: stdout 1`] = `
157160
"import {
158161
computed,
162+
PropType,
159163
reactive,
160164
toRefs,
161165
ref,
@@ -180,7 +184,9 @@ export default defineComponent({
180184
/**
181185
* My foo
182186
*/
183-
foo: { type: Number, default: false }
187+
foo: { type: Boolean, default: false },
188+
bar: { type: Number as PropType<number>, default: 1 },
189+
foobar: { type: Object as PropType<CustomType> }
184190
},
185191
name: 'oao',
186192
setup(props, ctx) {
@@ -308,6 +314,7 @@ export default defineComponent({
308314
exports[`testTSFile no compatible 1`] = `
309315
"import {
310316
computed,
317+
PropType,
311318
reactive,
312319
toRefs,
313320
ref,
@@ -331,7 +338,9 @@ export default {
331338
/**
332339
* My foo
333340
*/
334-
foo: { type: Number, default: false }
341+
foo: { type: Boolean, default: false },
342+
bar: { type: Number as PropType<number>, default: 1 },
343+
foobar: { type: Object as PropType<CustomType> }
335344
},
336345
name: 'oao',
337346
setup(props, context) {

tests/__snapshots__/testVueFile.spec.ts.snap

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ exports[`testVueFile compatible 1`] = `
44
"import MyComponent from 'my-component.vue'
55
import {
66
computed,
7+
PropType,
78
reactive,
89
toRefs,
910
ref,
@@ -32,7 +33,9 @@ export default defineComponent({
3233
/**
3334
* My foo
3435
*/
35-
foo: { type: Boolean, default: false }
36+
foo: { type: Boolean, default: false },
37+
bar: { type: Number as PropType<number>, default: 1 },
38+
foobar: { type: Object as PropType<CustomType> }
3639
},
3740
name: 'oao',
3841
setup(props, context) {
@@ -131,6 +134,7 @@ exports[`testVueFile no compatible 1`] = `
131134
"import MyComponent from 'my-component.vue'
132135
import {
133136
computed,
137+
PropType,
134138
reactive,
135139
toRefs,
136140
ref,
@@ -158,7 +162,9 @@ export default {
158162
/**
159163
* My foo
160164
*/
161-
foo: { type: Boolean, default: false }
165+
foo: { type: Boolean, default: false },
166+
bar: { type: Number as PropType<number>, default: 1 },
167+
foobar: { type: Object as PropType<CustomType> }
162168
},
163169
name: 'oao',
164170
setup(props, context) {

tests/fixture/Input.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ export default class BasicPropertyClass extends Vue {
2222
/**
2323
* My foo
2424
*/
25-
@Prop({ type: Number, default: false }) foo!: number
25+
@Prop({ type: Boolean, default: false }) foo!
26+
@Prop({ type: Number, default: 1 }) bar: number
27+
@Prop({ type: Object }) foobar: CustomType
2628

2729
$refs!: {
2830
myDiv: HTMLDivElement

tests/fixture/Input.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ export default class BasicPropertyClass extends Vue {
3030
/**
3131
* My foo
3232
*/
33-
@Prop({ type: Boolean, default: false }) foo: any
33+
@Prop({ type: Boolean, default: false }) foo!
34+
@Prop({ type: Number, default: 1 }) bar: number
35+
@Prop({ type: Object }) foobar: CustomType
3436
3537
@Provide() foa = 'foo'
3638
@Provide('bar') baz = 'bar'

0 commit comments

Comments
 (0)