From 496042cf7952a9931c73095dda9a8543668c1b7a Mon Sep 17 00:00:00 2001 From: yoyo930021 Date: Fri, 7 Jun 2019 23:45:28 +0800 Subject: [PATCH 01/14] Add support analyzing vue-class-component and vue-property-decorator --- server/src/modes/script/childComponents.ts | 52 +-- server/src/modes/script/componentInfo.ts | 362 +++++++++++++++------ 2 files changed, 296 insertions(+), 118 deletions(-) diff --git a/server/src/modes/script/childComponents.ts b/server/src/modes/script/childComponents.ts index 99a7fa7c80..026293d275 100644 --- a/server/src/modes/script/childComponents.ts +++ b/server/src/modes/script/childComponents.ts @@ -1,5 +1,5 @@ import * as ts from 'typescript'; -import { getLastChild, buildDocumentation, getDefaultExportObjectLiteralExpr } from './componentInfo'; +import { getLastChild, buildDocumentation, getDefaultExportNode } from './componentInfo'; import { T_TypeScript } from '../../services/dependencyService'; interface InternalChildComponent { @@ -10,7 +10,7 @@ interface InternalChildComponent { start: number; end: number; }; - defaultExportExpr?: ts.Node; + defaultExportNode?: ts.Node; } export function getChildComponents( @@ -19,7 +19,15 @@ export function getChildComponents( checker: ts.TypeChecker, tagCasing = 'kebab' ): InternalChildComponent[] | undefined { - const componentsSymbol = checker.getPropertyOfType(defaultExportType, 'components'); + let type = defaultExportType; + if (defaultExportType.isClass()) { + // get decorator argument type when class + type = checker.getTypeAtLocation( + (defaultExportType.symbol.declarations[0].decorators![0].expression as ts.CallExpression).arguments[0] + ); + } + + const componentsSymbol = checker.getPropertyOfType(type, 'components'); if (!componentsSymbol || !componentsSymbol.valueDeclaration) { return undefined; } @@ -56,27 +64,25 @@ export function getChildComponents( } if (objectLiteralSymbol.flags & tsModule.SymbolFlags.Alias) { - const definitionObjectLiteralSymbol = checker.getAliasedSymbol(objectLiteralSymbol); - if (definitionObjectLiteralSymbol.valueDeclaration) { - const defaultExportExpr = getDefaultExportObjectLiteralExpr( - tsModule, - definitionObjectLiteralSymbol.valueDeclaration.getSourceFile() - ); - if (!defaultExportExpr) { - return; - } - - result.push({ - name: componentName, - documentation: buildDocumentation(tsModule, definitionObjectLiteralSymbol, checker), - definition: { - path: definitionObjectLiteralSymbol.valueDeclaration.getSourceFile().fileName, - start: defaultExportExpr.getStart(undefined, true), - end: defaultExportExpr.getEnd() - }, - defaultExportExpr - }); + const definitionSymbol = checker.getAliasedSymbol(objectLiteralSymbol); + const sourceFile = definitionSymbol.valueDeclaration.getSourceFile() + const defaultExportNode = getDefaultExportNode( + tsModule, + sourceFile + ); + if (!defaultExportNode) { + return; } + result.push({ + name: componentName, + documentation: buildDocumentation(tsModule, definitionSymbol, checker), + definition: { + path: sourceFile.fileName, + start: defaultExportNode.getStart(sourceFile, true), + end: defaultExportNode.getEnd() + }, + defaultExportNode + }); } }); diff --git a/server/src/modes/script/componentInfo.ts b/server/src/modes/script/componentInfo.ts index 78cdb7e9b3..a3b39707a6 100644 --- a/server/src/modes/script/componentInfo.ts +++ b/server/src/modes/script/componentInfo.ts @@ -28,14 +28,14 @@ export function getComponentInfo( const checker = program.getTypeChecker(); - const defaultExportExpr = getDefaultExportObjectLiteralExpr(tsModule, sourceFile); - if (!defaultExportExpr) { + const defaultExportNode = getDefaultExportNode(tsModule, sourceFile); + if (!defaultExportNode) { return undefined; } - const vueFileInfo = analyzeDefaultExportExpr(tsModule, defaultExportExpr, checker); + const vueFileInfo = analyzeDefaultExportExpr(tsModule, defaultExportNode, checker); - const defaultExportType = checker.getTypeAtLocation(defaultExportExpr); + const defaultExportType = checker.getTypeAtLocation(defaultExportNode); const internalChildComponents = getChildComponents( tsModule, defaultExportType, @@ -50,7 +50,7 @@ export function getComponentInfo( name: c.name, documentation: c.documentation, definition: c.definition, - info: c.defaultExportExpr ? analyzeDefaultExportExpr(tsModule, c.defaultExportExpr, checker) : undefined + info: c.defaultExportNode ? analyzeDefaultExportExpr(tsModule, c.defaultExportNode, checker) : undefined }); }); vueFileInfo.componentInfo.childComponents = childComponents; @@ -61,10 +61,10 @@ export function getComponentInfo( export function analyzeDefaultExportExpr( tsModule: T_TypeScript, - defaultExportExpr: ts.Node, + defaultExport: ts.Node, checker: ts.TypeChecker ): VueFileInfo { - const defaultExportType = checker.getTypeAtLocation(defaultExportExpr); + const defaultExportType = checker.getTypeAtLocation(defaultExport); const props = getProps(tsModule, defaultExportType, checker); const data = getData(tsModule, defaultExportType, checker); @@ -81,66 +81,104 @@ export function analyzeDefaultExportExpr( }; } -export function getDefaultExportObjectLiteralExpr( +export function getDefaultExportNode( tsModule: T_TypeScript, sourceFile: ts.SourceFile -): ts.Expression | undefined { - const exportStmts = sourceFile.statements.filter(st => st.kind === tsModule.SyntaxKind.ExportAssignment); +): ts.Node | undefined { + const exportStmts = sourceFile.statements.filter(st => + st.kind === tsModule.SyntaxKind.ExportAssignment || + st.kind === tsModule.SyntaxKind.ClassDeclaration + ); if (exportStmts.length === 0) { return undefined; } - const exportExpr = (exportStmts[0] as ts.ExportAssignment).expression; + const exportNode = (exportStmts[0].kind === tsModule.SyntaxKind.ExportAssignment) ? + (exportStmts[0] as ts.ExportAssignment).expression : (exportStmts[0] as ts.ClassDeclaration); - return getObjectLiteralExprFromExportExpr(tsModule, exportExpr); + return getNodeFromExportNode(tsModule, exportNode); } function getProps(tsModule: T_TypeScript, defaultExportType: ts.Type, checker: ts.TypeChecker): PropInfo[] | undefined { - const propsSymbol = checker.getPropertyOfType(defaultExportType, 'props'); - if (!propsSymbol || !propsSymbol.valueDeclaration) { - return undefined; + const result: PropInfo[] = []; + if (defaultExportType.isClass()) { + result.push.apply(result, getClassProps(defaultExportType) || []); + + const decoratorArgumentType = checker.getTypeAtLocation( + (defaultExportType.symbol.declarations[0].decorators![0].expression as ts.CallExpression).arguments[0] + ); + result.push.apply(result, getObjectProps(decoratorArgumentType) || []); + } else { + result.push.apply(result, getObjectProps(defaultExportType) || []); } - const propsDeclaration = getLastChild(propsSymbol.valueDeclaration); - if (!propsDeclaration) { - return undefined; + function getClassProps (type: ts.Type) { + const propsSymbols = type.getProperties() + .filter((property) => + property.valueDeclaration.kind === tsModule.SyntaxKind.PropertyDeclaration && + property.declarations[0].decorators && + property.declarations[0].decorators.some((decorator) => + (decorator.expression as ts.CallExpression).expression.getText() === 'Prop' || + (decorator.expression as ts.CallExpression).expression.getText() === 'Model' + ) + ); + if (propsSymbols.length === 0) { return undefined; } + + return propsSymbols.map((prop) => { + return { + name: prop.name, + documentation: buildDocumentation(tsModule, prop, checker) + }; + }); } - /** - * Plain array props like `props: ['foo', 'bar']` - */ - if (propsDeclaration.kind === tsModule.SyntaxKind.ArrayLiteralExpression) { - return (propsDeclaration as ts.ArrayLiteralExpression).elements - .filter(expr => expr.kind === tsModule.SyntaxKind.StringLiteral) - .map(expr => { + function getObjectProps (type: ts.Type) { + const propsSymbol = checker.getPropertyOfType(type, 'props'); + if (!propsSymbol || !propsSymbol.valueDeclaration) { + return undefined; + } + + const propsDeclaration = getLastChild(propsSymbol.valueDeclaration); + if (!propsDeclaration) { + return undefined; + } + + /** + * Plain array props like `props: ['foo', 'bar']` + */ + if (propsDeclaration.kind === tsModule.SyntaxKind.ArrayLiteralExpression) { + return (propsDeclaration as ts.ArrayLiteralExpression).elements + .filter(expr => expr.kind === tsModule.SyntaxKind.StringLiteral) + .map(expr => { + return { + name: (expr as ts.StringLiteral).text + }; + }); + } + + /** + * Object literal props like + * ``` + * { + * props: { + * foo: { type: Boolean, default: true }, + * bar: { type: String, default: 'bar' } + * } + * } + * ``` + */ + if (propsDeclaration.kind === tsModule.SyntaxKind.ObjectLiteralExpression) { + const propsType = checker.getTypeOfSymbolAtLocation(propsSymbol, propsDeclaration); + + return checker.getPropertiesOfType(propsType).map(s => { return { - name: (expr as ts.StringLiteral).text + name: s.name, + documentation: buildDocumentation(tsModule, s, checker) }; }); + } } - /** - * Object literal props like - * ``` - * { - * props: { - * foo: { type: Boolean, default: true }, - * bar: { type: String, default: 'bar' } - * } - * } - * ``` - */ - if (propsDeclaration.kind === tsModule.SyntaxKind.ObjectLiteralExpression) { - const propsType = checker.getTypeOfSymbolAtLocation(propsSymbol, propsDeclaration); - - return checker.getPropertiesOfType(propsType).map(s => { - return { - name: s.name, - documentation: buildDocumentation(tsModule, s, checker) - }; - }); - } - - return undefined; + return result.length === 0 ? undefined : result; } /** @@ -157,23 +195,64 @@ function getProps(tsModule: T_TypeScript, defaultExportType: ts.Type, checker: t * ``` */ function getData(tsModule: T_TypeScript, defaultExportType: ts.Type, checker: ts.TypeChecker): DataInfo[] | undefined { - const dataSymbol = checker.getPropertyOfType(defaultExportType, 'data'); - if (!dataSymbol || !dataSymbol.valueDeclaration) { - return undefined; + const result: DataInfo[] = []; + if (defaultExportType.isClass()) { + result.push.apply(result, getClassData(defaultExportType) || []); + + const decoratorArgumentType = checker.getTypeAtLocation( + (defaultExportType.symbol.declarations[0].decorators![0].expression as ts.CallExpression).arguments[0] + ); + result.push.apply(result, getObjectData(decoratorArgumentType) || []); + } else { + result.push.apply(result, getObjectData(defaultExportType) || []); } - const dataType = checker.getTypeOfSymbolAtLocation(dataSymbol, dataSymbol.valueDeclaration); - const dataSignatures = dataType.getCallSignatures(); - if (dataSignatures.length === 0) { - return undefined; + function getClassData (type: ts.Type) { + const dataSymbols = type.getProperties() + .filter((property) => + property.valueDeclaration.kind === tsModule.SyntaxKind.PropertyDeclaration && ( + property.declarations[0].decorators === undefined || ( + property.declarations[0].decorators && + !property.declarations[0].decorators.some((decorator) => + (decorator.expression as ts.CallExpression).expression.getText() === 'Prop' || + (decorator.expression as ts.CallExpression).expression.getText() === 'Model' || + (decorator.expression as ts.CallExpression).expression.getText() === 'Inject' + ) + ) + ) && + !property.name.startsWith('_') && !property.name.startsWith('$') + ); + if (dataSymbols.length === 0) { return undefined; } + + return dataSymbols.map((data) => { + return { + name: data.name, + documentation: buildDocumentation(tsModule, data, checker) + }; + }); } - const dataReturnTypeProperties = checker.getReturnTypeOfSignature(dataSignatures[0]); - return dataReturnTypeProperties.getProperties().map(s => { - return { - name: s.name, - documentation: buildDocumentation(tsModule, s, checker) - }; - }); + + function getObjectData (type: ts.Type) { + const dataSymbol = checker.getPropertyOfType(type, 'data'); + if (!dataSymbol || !dataSymbol.valueDeclaration) { + return undefined; + } + + const dataType = checker.getTypeOfSymbolAtLocation(dataSymbol, dataSymbol.valueDeclaration); + const dataSignatures = dataType.getCallSignatures(); + if (dataSignatures.length === 0) { + return undefined; + } + const dataReturnTypeProperties = checker.getReturnTypeOfSignature(dataSignatures[0]); + return dataReturnTypeProperties.getProperties().map(s => { + return { + name: s.name, + documentation: buildDocumentation(tsModule, s, checker) + }; + }); + } + + return result.length === 0 ? undefined : result; } function getComputed( @@ -181,28 +260,83 @@ function getComputed( defaultExportType: ts.Type, checker: ts.TypeChecker ): ComputedInfo[] | undefined { - const computedSymbol = checker.getPropertyOfType(defaultExportType, 'computed'); - if (!computedSymbol || !computedSymbol.valueDeclaration) { - return undefined; + const result: ComputedInfo[] = []; + if (defaultExportType.isClass()) { + result.push.apply(result, getClassComputed(defaultExportType) || []); + + const decoratorArgumentType = checker.getTypeAtLocation( + (defaultExportType.symbol.declarations[0].decorators![0].expression as ts.CallExpression).arguments[0] + ); + result.push.apply(result, getObjectComputed(decoratorArgumentType) || []); + } else { + result.push.apply(result, getObjectComputed(defaultExportType) || []); } - const computedDeclaration = getLastChild(computedSymbol.valueDeclaration); - if (!computedDeclaration) { - return undefined; - } - - if (computedDeclaration.kind === tsModule.SyntaxKind.ObjectLiteralExpression) { - const computedType = checker.getTypeOfSymbolAtLocation(computedSymbol, computedDeclaration); - - return checker.getPropertiesOfType(computedType).map(s => { + function getClassComputed (type: ts.Type) { + const getAccessorSymbols = type.getProperties() + .filter((property) => + property.valueDeclaration.kind === tsModule.SyntaxKind.GetAccessor + ); + const setAccessorSymbols = defaultExportType.getProperties() + .filter((property) => + property.valueDeclaration.kind === tsModule.SyntaxKind.SetAccessor + ); + if (getAccessorSymbols.length === 0) { return undefined; } + + return getAccessorSymbols.map((computed) => { + const setComputed = setAccessorSymbols.find((setAccessor) => setAccessor.name === computed.name); return { - name: s.name, - documentation: buildDocumentation(tsModule, s, checker) + name: computed.name, + documentation: buildDocumentation(tsModule, computed, checker) + + ((setComputed !== undefined) ? buildDocumentation(tsModule, setComputed, checker) : '') }; }); } - return undefined; + function getObjectComputed (type: ts.Type) { + const computedSymbol = checker.getPropertyOfType(type, 'computed'); + if (!computedSymbol || !computedSymbol.valueDeclaration) { + return undefined; + } + + const computedDeclaration = getLastChild(computedSymbol.valueDeclaration); + if (!computedDeclaration) { + return undefined; + } + + if (computedDeclaration.kind === tsModule.SyntaxKind.ObjectLiteralExpression) { + const computedType = checker.getTypeOfSymbolAtLocation(computedSymbol, computedDeclaration); + + return checker.getPropertiesOfType(computedType).map(s => { + return { + name: s.name, + documentation: buildDocumentation(tsModule, s, checker) + }; + }); + } + } + + return result.length === 0 ? undefined : result; +} + +function isInternalHook (methodName: string) { + const $internalHooks = [ + 'data', + 'beforeCreate', + 'created', + 'beforeMount', + 'mounted', + 'beforeDestroy', + 'destroyed', + 'beforeUpdate', + 'updated', + 'activated', + 'deactivated', + 'render', + 'errorCaptured', // 2.5 + 'serverPrefetch' // 2.6 + ]; + return $internalHooks.includes(methodName); } function getMethods( @@ -210,40 +344,78 @@ function getMethods( defaultExportType: ts.Type, checker: ts.TypeChecker ): MethodInfo[] | undefined { - const methodsSymbol = checker.getPropertyOfType(defaultExportType, 'methods'); - if (!methodsSymbol || !methodsSymbol.valueDeclaration) { - return undefined; + const result: MethodInfo[] = []; + if (defaultExportType.isClass()) { + result.push.apply(result, getClassMethods(defaultExportType) || []); + + const decoratorArgumentType = checker.getTypeAtLocation( + (defaultExportType.symbol.declarations[0].decorators![0].expression as ts.CallExpression).arguments[0] + ); + result.push.apply(result, getObjectMethods(decoratorArgumentType) || []); + } else { + result.push.apply(result, getObjectMethods(defaultExportType) || []); } - const methodsDeclaration = getLastChild(methodsSymbol.valueDeclaration); - if (!methodsDeclaration) { - return undefined; - } - - if (methodsDeclaration.kind === tsModule.SyntaxKind.ObjectLiteralExpression) { - const methodsType = checker.getTypeOfSymbolAtLocation(methodsSymbol, methodsDeclaration); - - return checker.getPropertiesOfType(methodsType).map(s => { + function getClassMethods (type: ts.Type) { + const methodSymbols = type.getProperties() + .filter((property) => + property.valueDeclaration.kind === tsModule.SyntaxKind.MethodDeclaration && ( + property.declarations[0].decorators === undefined || ( + property.declarations[0].decorators && + !property.declarations[0].decorators.some((decorator) => + (decorator.expression as ts.CallExpression).expression.getText() === 'Watch' + ) + ) + ) && !isInternalHook(property.name) + ); + if (methodSymbols.length === 0) { return undefined; } + + return methodSymbols.map((method) => { return { - name: s.name, - documentation: buildDocumentation(tsModule, s, checker) + name: method.name, + documentation: buildDocumentation(tsModule, method, checker) }; }); } - return undefined; + function getObjectMethods (type: ts.Type) { + const methodsSymbol = checker.getPropertyOfType(type, 'methods'); + if (!methodsSymbol || !methodsSymbol.valueDeclaration) { + return undefined; + } + + const methodsDeclaration = getLastChild(methodsSymbol.valueDeclaration); + if (!methodsDeclaration) { + return undefined; + } + + if (methodsDeclaration.kind === tsModule.SyntaxKind.ObjectLiteralExpression) { + const methodsType = checker.getTypeOfSymbolAtLocation(methodsSymbol, methodsDeclaration); + + return checker.getPropertiesOfType(methodsType).map(s => { + return { + name: s.name, + documentation: buildDocumentation(tsModule, s, checker) + }; + }); + } + } + + return result.length === 0 ? undefined : result; } -export function getObjectLiteralExprFromExportExpr( +function getNodeFromExportNode( tsModule: T_TypeScript, exportExpr: ts.Node -): ts.Expression | undefined { +): ts.Node | undefined { switch (exportExpr.kind) { case tsModule.SyntaxKind.CallExpression: // Vue.extend or synthetic __vueEditorBridge return (exportExpr as ts.CallExpression).arguments[0]; case tsModule.SyntaxKind.ObjectLiteralExpression: return exportExpr as ts.ObjectLiteralExpression; + case tsModule.SyntaxKind.ClassDeclaration: + return exportExpr as ts.ClassDeclaration; } return undefined; } From 91d7b2dafd296f3035a766bf5cc470f7ff11c889 Mon Sep 17 00:00:00 2001 From: yoyo930021 Date: Sat, 8 Jun 2019 23:26:53 +0800 Subject: [PATCH 02/14] Fix @Component no argument error --- server/src/modes/script/childComponents.ts | 15 +++++-- server/src/modes/script/componentInfo.ts | 50 +++++++++++++++------- 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/server/src/modes/script/childComponents.ts b/server/src/modes/script/childComponents.ts index 026293d275..2089c659ab 100644 --- a/server/src/modes/script/childComponents.ts +++ b/server/src/modes/script/childComponents.ts @@ -1,5 +1,10 @@ import * as ts from 'typescript'; -import { getLastChild, buildDocumentation, getDefaultExportNode } from './componentInfo'; +import { + getLastChild, + buildDocumentation, + getDefaultExportNode, + getClassDecoratorArgumentType +} from './componentInfo'; import { T_TypeScript } from '../../services/dependencyService'; interface InternalChildComponent { @@ -22,9 +27,11 @@ export function getChildComponents( let type = defaultExportType; if (defaultExportType.isClass()) { // get decorator argument type when class - type = checker.getTypeAtLocation( - (defaultExportType.symbol.declarations[0].decorators![0].expression as ts.CallExpression).arguments[0] - ); + const classDecoratorArgumentType = getClassDecoratorArgumentType(tsModule, defaultExportType, checker); + if (!classDecoratorArgumentType) { + return undefined; + } + type = classDecoratorArgumentType; } const componentsSymbol = checker.getPropertyOfType(type, 'components'); diff --git a/server/src/modes/script/componentInfo.ts b/server/src/modes/script/componentInfo.ts index a3b39707a6..4ebec4a620 100644 --- a/server/src/modes/script/componentInfo.ts +++ b/server/src/modes/script/componentInfo.ts @@ -103,10 +103,10 @@ function getProps(tsModule: T_TypeScript, defaultExportType: ts.Type, checker: t if (defaultExportType.isClass()) { result.push.apply(result, getClassProps(defaultExportType) || []); - const decoratorArgumentType = checker.getTypeAtLocation( - (defaultExportType.symbol.declarations[0].decorators![0].expression as ts.CallExpression).arguments[0] - ); - result.push.apply(result, getObjectProps(decoratorArgumentType) || []); + const decoratorArgumentType = getClassDecoratorArgumentType(tsModule, defaultExportType, checker); + if (decoratorArgumentType) { + result.push.apply(result, getObjectProps(decoratorArgumentType) || []); + } } else { result.push.apply(result, getObjectProps(defaultExportType) || []); } @@ -199,10 +199,10 @@ function getData(tsModule: T_TypeScript, defaultExportType: ts.Type, checker: ts if (defaultExportType.isClass()) { result.push.apply(result, getClassData(defaultExportType) || []); - const decoratorArgumentType = checker.getTypeAtLocation( - (defaultExportType.symbol.declarations[0].decorators![0].expression as ts.CallExpression).arguments[0] - ); - result.push.apply(result, getObjectData(decoratorArgumentType) || []); + const decoratorArgumentType = getClassDecoratorArgumentType(tsModule, defaultExportType, checker); + if (decoratorArgumentType) { + result.push.apply(result, getObjectData(decoratorArgumentType) || []); + } } else { result.push.apply(result, getObjectData(defaultExportType) || []); } @@ -264,10 +264,10 @@ function getComputed( if (defaultExportType.isClass()) { result.push.apply(result, getClassComputed(defaultExportType) || []); - const decoratorArgumentType = checker.getTypeAtLocation( - (defaultExportType.symbol.declarations[0].decorators![0].expression as ts.CallExpression).arguments[0] - ); - result.push.apply(result, getObjectComputed(decoratorArgumentType) || []); + const decoratorArgumentType = getClassDecoratorArgumentType(tsModule, defaultExportType, checker); + if (decoratorArgumentType) { + result.push.apply(result, getObjectComputed(decoratorArgumentType) || []); + } } else { result.push.apply(result, getObjectComputed(defaultExportType) || []); } @@ -348,10 +348,10 @@ function getMethods( if (defaultExportType.isClass()) { result.push.apply(result, getClassMethods(defaultExportType) || []); - const decoratorArgumentType = checker.getTypeAtLocation( - (defaultExportType.symbol.declarations[0].decorators![0].expression as ts.CallExpression).arguments[0] - ); - result.push.apply(result, getObjectMethods(decoratorArgumentType) || []); + const decoratorArgumentType = getClassDecoratorArgumentType(tsModule, defaultExportType, checker); + if (decoratorArgumentType) { + result.push.apply(result, getObjectMethods(decoratorArgumentType) || []); + } } else { result.push.apply(result, getObjectMethods(defaultExportType) || []); } @@ -429,6 +429,24 @@ export function getLastChild(d: ts.Declaration) { return children[children.length - 1]; } +export function getClassDecoratorArgumentType( + tsModule: T_TypeScript, + type: ts.Type, + checker: ts.TypeChecker +) { + const decorators = type.symbol.declarations[0].decorators; + if (!decorators || decorators.length === 0) { + return undefined; + } + + const decoratorArguments = (decorators[0].expression as ts.CallExpression).arguments; + if (!decoratorArguments || decoratorArguments.length === 0) { + return undefined; + } + + return checker.getTypeAtLocation(decoratorArguments[0]); +} + export function buildDocumentation(tsModule: T_TypeScript, s: ts.Symbol, checker: ts.TypeChecker) { let documentation = s .getDocumentationComment(checker) From 5c3fd03e3fce9cad65d6463823d19dc09f8d38cf Mon Sep 17 00:00:00 2001 From: yoyo930021 Date: Sun, 23 Jun 2019 22:15:35 +0800 Subject: [PATCH 03/14] Add integration tests for analyzing vue-class-component --- test/interpolation/completion/class.test.ts | 116 ++++++++++++++++++ .../interpolation/completion/property.test.ts | 110 +++++++++++++++++ .../fixture/completion/BasicClass.vue | 45 +++++++ .../fixture/completion/BasicPropertyClass.vue | 40 ++++++ .../fixture/completion/ParentClass.vue | 48 ++++++++ .../completion/ParentPropertyClass.vue | 44 +++++++ test/interpolation/fixture/package.json | 1 + test/interpolation/fixture/yarn.lock | 13 ++ 8 files changed, 417 insertions(+) create mode 100644 test/interpolation/completion/class.test.ts create mode 100644 test/interpolation/completion/property.test.ts create mode 100644 test/interpolation/fixture/completion/BasicClass.vue create mode 100644 test/interpolation/fixture/completion/BasicPropertyClass.vue create mode 100644 test/interpolation/fixture/completion/ParentClass.vue create mode 100644 test/interpolation/fixture/completion/ParentPropertyClass.vue diff --git a/test/interpolation/completion/class.test.ts b/test/interpolation/completion/class.test.ts new file mode 100644 index 0000000000..7037b06f16 --- /dev/null +++ b/test/interpolation/completion/class.test.ts @@ -0,0 +1,116 @@ +import { activateLS, showFile, sleep, FILE_LOAD_SLEEP_TIME } from '../../lsp/helper'; +import { position, getDocUri } from '../util'; +import { testCompletion, testNoSuchCompletion } from './helper'; +import { CompletionItem, CompletionItemKind, MarkdownString } from 'vscode'; + +describe('Should autocomplete interpolation for