Skip to content

Commit

Permalink
support annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
HcySunYang committed Oct 1, 2018
1 parent 2b6f02d commit edf9a8d
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 14 deletions.
16 changes: 16 additions & 0 deletions __fixtures__/commentProps.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template>
<div></div>
</template>

<script>
export default {
props: {
// a string
/**
* For input form
* and something
*/
a: String
}
}
</script>
2 changes: 1 addition & 1 deletion __fixtures__/objectProps.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default {
d: 'null',
e: {
type: Function,
default: function() {}
default () {}
}
}
}
Expand Down
28 changes: 28 additions & 0 deletions __fixtures__/propFieldComment.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<template>
<div></div>
</template>

<script>
const noop = () => {}
export default {
props: {
a: {
type: Function,
// An empty function
default: noop
},
b: {
type: Number,
default: 1,
// Must be a number greater than 0
validator (value) {
return value > 0
}
},
c: {
// 'TOP' | 'LEFT'
type: String
}
}
}
</script>
16 changes: 15 additions & 1 deletion src/__test__/__snapshots__/index.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Get comments as a description 1`] = `
Array [
"a string",
"For input form
and something",
]
`;

exports[`Gets a description of the default value and a description of the validator 1`] = `
Array [
"'TOP' | 'LEFT'",
]
`;

exports[`The validator function should be used as a string representation 1`] = `
"function () {
return true;
}"
`;

exports[`When the \`type\` definition contains \`Function\`, you should get a string representation of the \`default\` function. 1`] = `"function () {}"`;
exports[`When the \`type\` definition contains \`Function\`, you should get a string representation of the \`default\` function. 1`] = `""`;
55 changes: 45 additions & 10 deletions src/__test__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,31 @@ test('Ability to correctly handle props that is an array of string', () => {
vuese(ast, options)
})

const ast = getAST('objectProps.vue')
const ast1 = getAST('objectProps.vue')
test('Is a prop using a shorthand type', () => {
const options: ParserOptions = {
onProp: (propsRes?: PropsResult[]) => {
expect((propsRes as PropsResult[])[0]).toEqual({
name: 'a',
type: 'String'
type: 'String',
describe: []
})
}
}
vuese(ast, options)
vuese(ast1, options)
})

test('`prop` defined using a type array', () => {
const options: ParserOptions = {
onProp: (propsRes?: PropsResult[]) => {
expect((propsRes as PropsResult[])[1]).toEqual({
name: 'b',
type: ['Number', 'String']
type: ['Number', 'String'],
describe: []
})
}
}
vuese(ast, options)
vuese(ast1, options)
})

test('Execute the default function and get the default value correctly', () => {
Expand All @@ -49,7 +51,7 @@ test('Execute the default function and get the default value correctly', () => {
})
}
}
vuese(ast, options)
vuese(ast1, options)
})

test('Get the `required` value correctly', () => {
Expand All @@ -59,7 +61,7 @@ test('Get the `required` value correctly', () => {
expect(propRes.required).toBe(true)
}
}
vuese(ast, options)
vuese(ast1, options)
})

test('The validator function should be used as a string representation', () => {
Expand All @@ -69,19 +71,20 @@ test('The validator function should be used as a string representation', () => {
expect(propRes.validator).toMatchSnapshot()
}
}
vuese(ast, options)
vuese(ast1, options)
})

test('The `prop` that does not satisfy the `prop` writing specification should be treated as no type', () => {
const options: ParserOptions = {
onProp: (propsRes?: PropsResult[]) => {
expect((propsRes as PropsResult[])[3]).toEqual({
name: 'd',
type: null
type: null,
describe: []
})
}
}
vuese(ast, options)
vuese(ast1, options)
})

test('When the `type` definition contains `Function`, you should get a string representation of the `default` function.', () => {
Expand All @@ -92,5 +95,37 @@ test('When the `type` definition contains `Function`, you should get a string re
expect(propRes.default).toMatchSnapshot()
}
}
vuese(ast1, options)
})

test('Get comments as a description', () => {
const ast = getAST('commentProps.vue')
const options: ParserOptions = {
onProp: (propsRes?: PropsResult[]) => {
const propRes = (propsRes as PropsResult[])[0]
expect((propRes.describe as []).length).toBe(2)
expect(propRes.describe).toMatchSnapshot()
}
}
vuese(ast, options)
})

test('Gets a description of the default value and a description of the validator', () => {
const ast = getAST('propFieldComment.vue')
const options: ParserOptions = {
onProp: (propsRes?: PropsResult[]) => {
let propRes = (propsRes as PropsResult[])[0]
expect((propRes.defaultDesc as string[]).length).toBe(1)
expect(propRes.defaultDesc).toEqual(['An empty function'])

propRes = (propsRes as PropsResult[])[1]
expect((propRes.validatorDesc as string[]).length).toBe(1)
expect(propRes.validatorDesc).toEqual(['Must be a number greater than 0'])

propRes = (propsRes as PropsResult[])[2]
expect((propRes.typeDesc as string[]).length).toBe(1)
expect(propRes.typeDesc).toMatchSnapshot()
}
}
vuese(ast, options)
})
18 changes: 18 additions & 0 deletions src/comments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { isCommentLine, isCommentBlock } from './helpers'

const commentRE = /\n\s*\*\s*/g

export function getComments(path: any): string[] {
const commentNodes: [] | undefined = path.node.leadingComments
if (!commentNodes || !commentNodes.length) return []
return (commentNodes as []).map((node: any) => {
if (isCommentLine(node)) {
return node.value.trim()
} else if (isCommentBlock(node)) {
return node.value
.replace(commentRE, '\n')
.replace(/^\*/, '')
.trim()
}
})
}
1 change: 1 addition & 0 deletions src/declarations.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
declare module 'vue-template-compiler'
declare module '@babel/traverse'
declare module '@babel/generator'
declare module 'strip-ansi'
11 changes: 10 additions & 1 deletion src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,18 @@ import * as fs from 'fs'
* 1. It is a default export
* 2. others...
*/
export function isVueComponent(node: object): boolean {
export function isVueComponent(node: any): boolean {
return bt.isExportDefaultDeclaration(node)
}

export function isCommentLine(node: any): boolean {
return node.type === 'CommentLine'
}

export function isCommentBlock(node: any): boolean {
return node.type === 'CommentBlock'
}

export function runFunction(fnCode: string): any {
const { code: genCode } = generate(fnCode)
const code = `return (${genCode})()`
Expand Down Expand Up @@ -58,6 +66,7 @@ export function normalizeProps(props: string[]): PropsResult[] {
const josnCache: [] = []
export function writeFileSync(str: any, keep?: boolean) {
const filePath = __dirname + '/a.txt'
if (!fs.existsSync(filePath)) return
const preContent = fs.readFileSync(filePath)
const content = JSON.stringify(
str,
Expand Down
26 changes: 25 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import traverse from '@babel/traverse'
import generate from '@babel/generator'
import * as bt from '@babel/types'
import { getComments } from './comments'
import {
getValueFromGenerate,
isPropsOption,
Expand All @@ -15,9 +16,13 @@ type PropType = string | string[] | null
export interface PropsResult {
type: PropType
name: string
typeDesc?: string[]
required?: boolean
default?: string
defaultDesc?: string[]
validator?: string
validatorDesc?: string[]
describe?: string[]
}

const mainTraveres = {
Expand All @@ -41,8 +46,10 @@ const mainTraveres = {
const vPath = propPath.get('value')
const result: PropsResult = {
name,
type: null
type: null,
describe: getComments(propPath)
}

if (isAllowPropsType(vPath.node)) {
result.type = getTypeByPath(vPath)
} else if (bt.isObjectExpression(vPath.node)) {
Expand Down Expand Up @@ -72,6 +79,11 @@ const mainTraveres = {
result.type = getTypeByPath(
typeNode[0].$$selfPath.get('value')
)
// Get descriptions of the type
const typeDesc: string[] = getComments(typeNode[0].$$selfPath)
if (typeDesc.length > 0) {
result.typeDesc = typeDesc
}
}

otherNodes.forEach((node: any) => {
Expand All @@ -85,12 +97,24 @@ const mainTraveres = {
} else {
result.default = generate(node.value).code
}

// Get descriptions of the default value
const defaultDesc: string[] = getComments(node.$$selfPath)
if (defaultDesc.length > 0) {
result.defaultDesc = defaultDesc
}
} else if (n === 'required') {
if (bt.isBooleanLiteral(node.value)) {
result.required = node.value.value
}
} else if (n === 'validator') {
result.validator = generate(node.value).code

// Get descriptions of the validator
const validatorDesc: string[] = getComments(node.$$selfPath)
if (validatorDesc.length > 0) {
result.validatorDesc = validatorDesc
}
}
})
}
Expand Down

0 comments on commit edf9a8d

Please sign in to comment.