From 8802df8d2cab41d157e93da1dd42bac39a53ac46 Mon Sep 17 00:00:00 2001 From: Sacha STAFYNIAK Date: Sun, 31 Jul 2022 04:06:55 +0200 Subject: [PATCH] add schema extraction option + resolve inline objects + js file resolution (#1656) Co-authored-by: johnsoncodehk --- packages/vue-component-meta/src/index.ts | 317 +++++++++++------- packages/vue-component-meta/src/types.ts | 50 +++ .../vue-component-meta/tests/index.spec.ts | 135 +++++--- packages/vue-test-workspace/tsconfig.json | 1 + .../empty-component/component.vue | 7 + .../reference-type-props/component-js.vue | 12 + .../reference-type-props/my-props.ts | 8 +- .../vue-component-meta/tsconfig.json | 3 +- 8 files changed, 376 insertions(+), 157 deletions(-) create mode 100644 packages/vue-component-meta/src/types.ts create mode 100644 packages/vue-test-workspace/vue-component-meta/empty-component/component.vue create mode 100644 packages/vue-test-workspace/vue-component-meta/reference-type-props/component-js.vue diff --git a/packages/vue-component-meta/src/index.ts b/packages/vue-component-meta/src/index.ts index 156f42d10..c133997f8 100644 --- a/packages/vue-component-meta/src/index.ts +++ b/packages/vue-component-meta/src/index.ts @@ -1,97 +1,29 @@ import * as vue from '@volar/vue-language-core'; import * as ts from 'typescript/lib/tsserverlibrary'; -export type PropertyMeta = { - name: string; - default?: string; - description: string; - required: boolean; - type: string; - tags: { name: string, text?: string; }[]; - schema: PropertyMetaSchema; +import type { + MetaCheckerOptions, + ComponentMeta, + EventMeta, + ExposeMeta, + MetaCheckerSchemaOptions, + PropertyMeta, + PropertyMetaSchema, + SlotMeta +} from './types'; + +export type { + MetaCheckerOptions, + ComponentMeta, + EventMeta, + ExposeMeta, + MetaCheckerSchemaOptions, + PropertyMeta, + PropertyMetaSchema, + SlotMeta }; -export type PropertyMetaSchema = string - | { kind: 'enum', type: string, schema: PropertyMetaSchema[]; } - | { kind: 'array', type: string, schema: PropertyMetaSchema[]; } - | { kind: 'event', type: string, schema: PropertyMetaSchema[]; } - | { kind: 'object', type: string, schema: Record; }; - -function createSchemaResolvers(typeChecker: ts.TypeChecker, symbolNode: ts.Expression) { - function reducer(acc: any, cur: any) { - acc[cur.name] = cur; - return acc; - } - function resolveSymbolSchema(prop: ts.Symbol): PropertyMeta { - const subtype = typeChecker.getTypeOfSymbolAtLocation(prop, symbolNode!); - typeChecker.getDefaultFromTypeParameter(subtype); - - return { - name: prop.getEscapedName().toString(), - description: ts.displayPartsToString(prop.getDocumentationComment(typeChecker)), - tags: prop.getJsDocTags(typeChecker).map(tag => ({ - name: tag.name, - text: tag.text?.map(part => part.text).join(''), - })), - required: !Boolean((prop.declarations?.[0] as ts.ParameterDeclaration)?.questionToken ?? false), - type: typeChecker.typeToString(subtype), - schema: resolveSchema(subtype), - }; - } - function resolveCallbackSchema(signature: ts.Signature): PropertyMetaSchema { - return { - kind: 'event', - type: typeChecker.signatureToString(signature), - schema: typeChecker.getTypeArguments(typeChecker.getTypeOfSymbolAtLocation(signature.parameters[0], symbolNode) as ts.TypeReference).map(resolveSchema) - }; - } - function resolveEventSchema(subtype: ts.Type): PropertyMetaSchema { - return (subtype.getCallSignatures().length === 1) - ? resolveCallbackSchema(subtype.getCallSignatures()[0]) - : typeChecker.typeToString(subtype); - } - function resolveNestedSchema(subtype: ts.Type): PropertyMetaSchema { - // !!(subtype.flags & ts.TypeFlags.Object) - return (subtype.isClassOrInterface() || subtype.isIntersection()) - ? { - kind: 'object', - type: typeChecker.typeToString(subtype), - schema: subtype.getProperties().map(resolveSymbolSchema).reduce(reducer, {}) - } - : resolveEventSchema(subtype); - } - function resolveArraySchema(subtype: ts.Type): PropertyMetaSchema { - // @ts-ignore - typescript internal, isArrayLikeType exists - return typeChecker.isArrayLikeType(subtype) - ? { - kind: 'array', - type: typeChecker.typeToString(subtype), - schema: typeChecker.getTypeArguments(subtype as ts.TypeReference).map(resolveSchema) - } - : resolveNestedSchema(subtype); - } - function resolveSchema(subtype: ts.Type): PropertyMetaSchema { - return subtype.isUnion() - ? { - kind: 'enum', - type: typeChecker.typeToString(subtype), - schema: subtype.types.map(resolveArraySchema) - } - : resolveArraySchema(subtype); - } - - return { - resolveSymbolSchema, - resolveCallbackSchema, - resolveEventSchema, - resolveNestedSchema, - resolveArraySchema, - resolveSchema, - }; -} - -export function createComponentMetaChecker(tsconfigPath: string) { - +export function createComponentMetaChecker(tsconfigPath: string, checkerOptions: MetaCheckerOptions = {}) { const parsedCommandLine = vue.tsShared.createParsedCommandLine(ts, { useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames, readDirectory: (path, extensions, exclude, include, depth) => { @@ -142,7 +74,26 @@ export function createComponentMetaChecker(tsconfigPath: string) { getVueCompilationSettings: () => parsedCommandLine.vueOptions, }; const core = vue.createLanguageContext(host); - const tsLs = ts.createLanguageService(core.typescriptLanguageServiceHost); + const proxyApis: Partial = checkerOptions.forceUseTs ? { + getScriptKind: (fileName) => { + if (fileName.endsWith('.vue.js')) { + return ts.ScriptKind.TS; + } + if (fileName.endsWith('.vue.jsx')) { + return ts.ScriptKind.TSX; + } + return core.typescriptLanguageServiceHost.getScriptKind!(fileName); + }, + } : {}; + const proxyHost = new Proxy(core.typescriptLanguageServiceHost, { + get(target, propKey: keyof ts.LanguageServiceHost) { + if (propKey in proxyApis) { + return proxyApis[propKey]; + } + return target[propKey]; + } + }); + const tsLs = ts.createLanguageService(proxyHost); const program = tsLs.getProgram()!; const typeChecker = program.getTypeChecker(); @@ -185,7 +136,7 @@ export function createComponentMetaChecker(tsconfigPath: string) { return _getExports(componentPath).exports.map(e => e.getName()); } - function getComponentMeta(componentPath: string, exportName = 'default') { + function getComponentMeta(componentPath: string, exportName = 'default'): ComponentMeta { const { symbolNode, exports } = _getExports(componentPath); const _export = exports.find((property) => property.getName() === exportName); @@ -196,6 +147,12 @@ export function createComponentMetaChecker(tsconfigPath: string) { const componentType = typeChecker.getTypeOfSymbolAtLocation(_export, symbolNode!); const symbolProperties = componentType.getProperties() ?? []; + const { + resolveNestedProperties, + resolveEventSignature, + resolveExposedProperties, + resolveSlotProperties, + } = createSchemaResolvers(typeChecker, symbolNode!, checkerOptions.schema); return { props: getProps(), @@ -207,14 +164,16 @@ export function createComponentMetaChecker(tsconfigPath: string) { function getProps() { const $props = symbolProperties.find(prop => prop.escapedName === '$props'); + const propEventRegex = /^(on[A-Z])/; let result: PropertyMeta[] = []; if ($props) { const type = typeChecker.getTypeOfSymbolAtLocation($props, symbolNode!); const properties = type.getApparentProperties(); - const { resolveSymbolSchema } = createSchemaResolvers(typeChecker, symbolNode!); - result = properties.map(resolveSymbolSchema); + result = properties + .map(resolveNestedProperties) + .filter((prop) => !prop.name.match(propEventRegex)); } // fill defaults @@ -239,14 +198,8 @@ export function createComponentMetaChecker(tsconfigPath: string) { if ($emit) { const type = typeChecker.getTypeOfSymbolAtLocation($emit, symbolNode!); const calls = type.getCallSignatures(); - const { resolveSchema } = createSchemaResolvers(typeChecker, symbolNode!); - - return calls.map(call => ({ - name: (typeChecker.getTypeOfSymbolAtLocation(call.parameters[0], symbolNode!) as ts.StringLiteralType).value, - type: typeChecker.typeToString(typeChecker.getTypeOfSymbolAtLocation(call.parameters[1], symbolNode!)), - signature: typeChecker.signatureToString(call), - schema: typeChecker.getTypeArguments(typeChecker.getTypeOfSymbolAtLocation(call.parameters[1], symbolNode!) as ts.TypeReference).map(resolveSchema), - })); + + return calls.map(resolveEventSignature).filter(event => event.name); } return []; @@ -260,29 +213,21 @@ export function createComponentMetaChecker(tsconfigPath: string) { if ($slots) { const type = typeChecker.getTypeOfSymbolAtLocation($slots, symbolNode!); const properties = type.getProperties(); - return properties.map(prop => ({ - name: prop.getName(), - type: typeChecker.typeToString(typeChecker.getTypeOfSymbolAtLocation(typeChecker.getTypeOfSymbolAtLocation(prop, symbolNode!).getCallSignatures()[0].parameters[0], symbolNode!)), - description: ts.displayPartsToString(prop.getDocumentationComment(typeChecker)), - })); + + return properties.map(resolveSlotProperties); } return []; } function getExposed() { - const exposed = symbolProperties.filter(prop => // only exposed props will have a syntheticOrigin Boolean((prop as any).syntheticOrigin) ); if (exposed.length) { - return exposed.map(expose => ({ - name: expose.getName(), - type: typeChecker.typeToString(typeChecker.getTypeOfSymbolAtLocation(expose, symbolNode!)), - description: ts.displayPartsToString(expose.getDocumentationComment(typeChecker)), - })); + return exposed.map(resolveExposedProperties); } return []; @@ -328,6 +273,154 @@ export function createComponentMetaChecker(tsconfigPath: string) { } } +function createSchemaResolvers(typeChecker: ts.TypeChecker, symbolNode: ts.Expression, options: MetaCheckerSchemaOptions = {}) { + const ignore = options.ignore ?? []; + const enabled = options.enabled ?? false; + + function shouldIgnore(subtype: ts.Type) { + const type = typeChecker.typeToString(subtype); + if (type === 'any') { + return true; + } + + if (ignore.length === 0) { + return false; + } + + return ignore.includes(type); + } + + function reducer(acc: any, cur: any) { + acc[cur.name] = cur; + return acc; + } + + function resolveNestedProperties(prop: ts.Symbol): PropertyMeta { + const subtype = typeChecker.getTypeOfSymbolAtLocation(prop, symbolNode!); + const schema = enabled ? resolveSchema(subtype) : undefined; + + return { + name: prop.getEscapedName().toString(), + description: ts.displayPartsToString(prop.getDocumentationComment(typeChecker)), + tags: prop.getJsDocTags(typeChecker).map(tag => ({ + name: tag.name, + text: tag.text?.map(part => part.text).join(''), + })), + required: !Boolean((prop.declarations?.[0] as ts.ParameterDeclaration)?.questionToken ?? false), + type: typeChecker.typeToString(subtype), + schema, + }; + } + function resolveSlotProperties(prop: ts.Symbol): SlotMeta { + const subtype = typeChecker.getTypeOfSymbolAtLocation(typeChecker.getTypeOfSymbolAtLocation(prop, symbolNode!).getCallSignatures()[0].parameters[0], symbolNode!); + const schema = enabled ? resolveSchema(subtype) : undefined; + + return { + name: prop.getName(), + type: typeChecker.typeToString(subtype), + description: ts.displayPartsToString(prop.getDocumentationComment(typeChecker)), + schema, + }; + } + function resolveExposedProperties(expose: ts.Symbol): ExposeMeta { + const subtype = typeChecker.getTypeOfSymbolAtLocation(expose, symbolNode!); + const schema = enabled ? resolveSchema(subtype) : undefined; + + return { + name: expose.getName(), + type: typeChecker.typeToString(subtype), + description: ts.displayPartsToString(expose.getDocumentationComment(typeChecker)), + schema, + }; + } + function resolveEventSignature(call: ts.Signature): EventMeta { + const subtype = typeChecker.getTypeOfSymbolAtLocation(call.parameters[1], symbolNode!); + const schema = enabled + ? typeChecker.getTypeArguments(subtype as ts.TypeReference).map(resolveSchema) + : undefined; + + return { + name: (typeChecker.getTypeOfSymbolAtLocation(call.parameters[0], symbolNode!) as ts.StringLiteralType).value, + type: typeChecker.typeToString(subtype), + signature: typeChecker.signatureToString(call), + schema, + }; + } + + function resolveCallbackSchema(signature: ts.Signature): PropertyMetaSchema { + const schema = enabled && signature.parameters.length > 0 + ? typeChecker + .getTypeArguments(typeChecker.getTypeOfSymbolAtLocation(signature.parameters[0], symbolNode) as ts.TypeReference) + .map(resolveSchema) + : undefined; + + return { + kind: 'event', + type: typeChecker.signatureToString(signature), + schema, + }; + } + function resolveEventSchema(subtype: ts.Type): PropertyMetaSchema { + return (subtype.getCallSignatures().length === 1) + ? resolveCallbackSchema(subtype.getCallSignatures()[0]) + : typeChecker.typeToString(subtype); + } + function resolveNestedSchema(subtype: ts.Type): PropertyMetaSchema { + if ( + subtype.getCallSignatures().length === 0 && + (subtype.isClassOrInterface() || subtype.isIntersection() || (subtype as ts.ObjectType).objectFlags & ts.ObjectFlags.Anonymous) + ) { + if (shouldIgnore(subtype)) { + return typeChecker.typeToString(subtype); + } + + return { + kind: 'object', + type: typeChecker.typeToString(subtype), + schema: subtype.getProperties().map(resolveNestedProperties).reduce(reducer, {}) + }; + } + return resolveEventSchema(subtype); + } + function resolveArraySchema(subtype: ts.Type): PropertyMetaSchema { + // @ts-ignore - typescript internal, isArrayLikeType exists + if (typeChecker.isArrayLikeType(subtype)) { + if (shouldIgnore(subtype)) { + return typeChecker.typeToString(subtype); + } + + return { + kind: 'array', + type: typeChecker.typeToString(subtype), + schema: typeChecker.getTypeArguments(subtype as ts.TypeReference).map(resolveSchema) + }; + } + + return resolveNestedSchema(subtype); + } + function resolveSchema(subtype: ts.Type): PropertyMetaSchema { + return subtype.isUnion() + ? { + kind: 'enum', + type: typeChecker.typeToString(subtype), + schema: subtype.types.map(resolveArraySchema) + } + : resolveArraySchema(subtype); + } + + return { + resolveNestedProperties, + resolveSlotProperties, + resolveEventSignature, + resolveExposedProperties, + resolveCallbackSchema, + resolveEventSchema, + resolveNestedSchema, + resolveArraySchema, + resolveSchema, + }; +} + function readCmponentDefaultProps(fileText: string) { const vueSourceFile = vue.createSourceFile('/tmp.vue', fileText, {}, {}, ts); diff --git a/packages/vue-component-meta/src/types.ts b/packages/vue-component-meta/src/types.ts new file mode 100644 index 000000000..d37d0cea3 --- /dev/null +++ b/packages/vue-component-meta/src/types.ts @@ -0,0 +1,50 @@ + + +export interface ComponentMeta { + props: PropertyMeta[]; + events: EventMeta[]; + slots: SlotMeta[]; + exposed: ExposeMeta[]; +} +export interface PropertyMeta { + name: string; + default?: string; + description: string; + required: boolean; + type: string; + tags: { name: string, text?: string; }[]; + schema?: PropertyMetaSchema; +}; +export interface EventMeta { + name: string; + type: string; + signature: string; + schema?: PropertyMetaSchema[]; +} +export interface SlotMeta { + name: string; + type: string; + description: string; + schema?: PropertyMetaSchema; +} +export interface ExposeMeta { + name: string; + description: string; + type: string; + schema?: PropertyMetaSchema; +} + +export type PropertyMetaSchema = string + | { kind: 'enum', type: string, schema?: PropertyMetaSchema[]; } + | { kind: 'array', type: string, schema?: PropertyMetaSchema[]; } + | { kind: 'event', type: string, schema?: PropertyMetaSchema[]; } + | { kind: 'object', type: string, schema?: Record; }; + +export interface MetaCheckerSchemaOptions { + enabled?: boolean; + ignore?: string[]; +} +export interface MetaCheckerOptions { + schema?: MetaCheckerSchemaOptions; + forceUseTs?: boolean; +} diff --git a/packages/vue-component-meta/tests/index.spec.ts b/packages/vue-component-meta/tests/index.spec.ts index bfd9c35ab..850847171 100644 --- a/packages/vue-component-meta/tests/index.spec.ts +++ b/packages/vue-component-meta/tests/index.spec.ts @@ -1,11 +1,19 @@ import * as path from 'path'; import { describe, expect, test } from 'vitest'; -import * as metaChecker from '..'; +import { createComponentMetaChecker } from '..'; describe(`vue-component-meta`, () => { const tsconfigPath = path.resolve(__dirname, '../../vue-test-workspace/vue-component-meta/tsconfig.json'); - const checker = metaChecker.createComponentMetaChecker(tsconfigPath); + const checker = createComponentMetaChecker(tsconfigPath, { + forceUseTs: true, + }); + const checker_schema = createComponentMetaChecker(tsconfigPath, { + schema: { + enabled: true, + ignore: ['MyIgnoredNestedProps'], + } + }); test('global-props', () => { @@ -16,21 +24,29 @@ describe(`vue-component-meta`, () => { 'ref', 'ref_for', 'ref_key', - 'onVnodeBeforeMount', - 'onVnodeMounted', - 'onVnodeBeforeUpdate', - 'onVnodeUpdated', - 'onVnodeBeforeUnmount', - 'onVnodeUnmounted', 'class', 'style', ]); }); - test('reference-type-props', () => { + test('empty-component', () => { + const componentPath = path.resolve(__dirname, '../../vue-test-workspace/vue-component-meta/empty-component/component.vue'); + const meta = checker.getComponentMeta(componentPath); + const globalPropNames = checker.getGlobalPropNames(); + + meta.props = meta.props.filter(prop => !globalPropNames.includes(prop.name)); + expect(meta).toEqual({ + props: [], + events: [], + slots: [], + exposed: [], + }); + }); + + test('reference-type-props', () => { const componentPath = path.resolve(__dirname, '../../vue-test-workspace/vue-component-meta/reference-type-props/component.vue'); - const meta = checker.getComponentMeta(componentPath); + const meta = checker_schema.getComponentMeta(componentPath); const foo = meta.props.find(prop => prop.name === 'foo'); const bar = meta.props.find(prop => prop.name === 'bar'); @@ -44,7 +60,7 @@ describe(`vue-component-meta`, () => { const arrayOptional = meta.props.find(prop => prop.name === 'arrayOptional'); const enumValue = meta.props.find(prop => prop.name === 'enumValue'); const literalFromContext = meta.props.find(prop => prop.name === 'literalFromContext'); - const literal = meta.props.find(prop => prop.name === 'literal'); + const inlined = meta.props.find(prop => prop.name === 'inlined'); // const onEvent = meta.props.find(prop => prop.name === 'onEvent'); expect(foo).toBeDefined(); @@ -162,11 +178,11 @@ describe(`vue-component-meta`, () => { expect(nestedOptional).toBeDefined(); expect(nestedOptional?.required).toBeFalsy(); - expect(nestedOptional?.type).toEqual('MyNestedProps | undefined'); + expect(nestedOptional?.type).toEqual('MyNestedProps | MyIgnoredNestedProps | undefined'); expect(nestedOptional?.description).toEqual('optional nested object'); expect(nestedOptional?.schema).toEqual({ kind: 'enum', - type: 'MyNestedProps | undefined', + type: 'MyNestedProps | MyIgnoredNestedProps | undefined', schema: [ 'undefined', { @@ -182,7 +198,8 @@ describe(`vue-component-meta`, () => { schema: 'string' } } - } + }, + 'MyIgnoredNestedProps', ] }); @@ -253,25 +270,22 @@ describe(`vue-component-meta`, () => { schema: ['MyEnum.Small', 'MyEnum.Medium', 'MyEnum.Large'] }); - expect(literal).toBeDefined(); - expect(literal?.required).toBeTruthy(); - expect(literal?.type).toEqual('{ foo: string; }'); - - // todo: this should be resolved to a type alias - // expect(literal?.schema).toEqual({ - // kind: 'object', - // type: '{ foo: string; }', - // schema: { - // foo: { - // name: 'foo', - // description: '', - // tags: [], - // required: true, - // type: 'string', - // schema: 'string' - // } - // } - // }) + expect(inlined).toBeDefined(); + expect(inlined?.required).toBeTruthy(); + expect(inlined?.schema).toEqual({ + kind: 'object', + type: '{ foo: string; }', + schema: { + foo: { + name: 'foo', + description: '', + tags: [], + required: true, + type: 'string', + schema: 'string' + } + } + }); expect(literalFromContext).toBeDefined(); expect(literalFromContext?.required).toBeTruthy(); @@ -313,10 +327,18 @@ describe(`vue-component-meta`, () => { // }); }); - test('reference-type-events', () => { + test('reference-type-props-js', () => { + const componentPath = path.resolve(__dirname, '../../vue-test-workspace/vue-component-meta/reference-type-props/component-js.vue'); + const meta = checker.getComponentMeta(componentPath); + const foo = meta.props.find(prop => prop.name === 'foo'); + expect(foo).toBeDefined(); + expect(foo?.required).toBeTruthy(); + }); + + test('reference-type-events', () => { const componentPath = path.resolve(__dirname, '../../vue-test-workspace/vue-component-meta/reference-type-events/component.vue'); - const meta = checker.getComponentMeta(componentPath); + const meta = checker_schema.getComponentMeta(componentPath); const onFoo = meta.events.find(event => event.name === 'foo'); const onBar = meta.events.find(event => event.name === 'bar'); @@ -331,7 +353,20 @@ describe(`vue-component-meta`, () => { type: '{ foo: string; } | undefined', schema: [ 'undefined', - '{ foo: string; }' // todo: this should be resolved to a type alias + { + kind: 'object', + type: '{ foo: string; }', + schema: { + foo: { + name: 'foo', + description: '', + tags: [], + required: true, + type: 'string', + schema: 'string' + } + } + } ], } ]); @@ -340,7 +375,28 @@ describe(`vue-component-meta`, () => { expect(onBar?.type).toEqual('[value: { arg1: number; arg2?: any; }]'); expect(onBar?.signature).toEqual('(event: "bar", value: { arg1: number; arg2?: any; }): void'); expect(onBar?.schema).toEqual([ - '{ arg1: number; arg2?: any; }' // todo: this should be resolved to a type alias + { + kind: 'object', + type: '{ arg1: number; arg2?: any; }', + schema: { + arg1: { + name: 'arg1', + description: '', + tags: [], + required: true, + type: 'number', + schema: 'number' + }, + arg2: { + name: 'arg2', + description: '', + tags: [], + required: false, + type: 'any', + schema: 'any' + }, + } + } ]); expect(onBaz).toBeDefined(); @@ -350,7 +406,6 @@ describe(`vue-component-meta`, () => { }); test('template-slots', () => { - const componentPath = path.resolve(__dirname, '../../vue-test-workspace/vue-component-meta/template-slots/component.vue'); const meta = checker.getComponentMeta(componentPath); @@ -373,7 +428,6 @@ describe(`vue-component-meta`, () => { }); test('class-slots', () => { - const componentPath = path.resolve(__dirname, '../../vue-test-workspace/vue-component-meta/class-slots/component.vue'); const meta = checker.getComponentMeta(componentPath); @@ -391,7 +445,6 @@ describe(`vue-component-meta`, () => { }); test('exposed', () => { - const componentPath = path.resolve(__dirname, '../../vue-test-workspace/vue-component-meta/reference-type-exposed/component.vue'); const meta = checker.getComponentMeta(componentPath); @@ -405,7 +458,6 @@ describe(`vue-component-meta`, () => { }); test('ts-component', () => { - const componentPath = path.resolve(__dirname, '../../vue-test-workspace/vue-component-meta/ts-component/component.ts'); const meta = checker.getComponentMeta(componentPath); @@ -425,7 +477,6 @@ describe(`vue-component-meta`, () => { }); test('ts-named-exports', () => { - const componentPath = path.resolve(__dirname, '../../vue-test-workspace/vue-component-meta/ts-named-export/component.ts'); const exportNames = checker.getExportNames(componentPath); const Foo = checker.getComponentMeta(componentPath, 'Foo'); diff --git a/packages/vue-test-workspace/tsconfig.json b/packages/vue-test-workspace/tsconfig.json index f401addb1..208c9aa74 100644 --- a/packages/vue-test-workspace/tsconfig.json +++ b/packages/vue-test-workspace/tsconfig.json @@ -9,6 +9,7 @@ "noUnusedLocals": true, "noUnusedParameters": true, "skipLibCheck": true, + "allowJs": true, "jsx": "preserve", "baseUrl": ".", "paths": { diff --git a/packages/vue-test-workspace/vue-component-meta/empty-component/component.vue b/packages/vue-test-workspace/vue-component-meta/empty-component/component.vue new file mode 100644 index 000000000..622b5c0a7 --- /dev/null +++ b/packages/vue-test-workspace/vue-component-meta/empty-component/component.vue @@ -0,0 +1,7 @@ + + + diff --git a/packages/vue-test-workspace/vue-component-meta/reference-type-props/component-js.vue b/packages/vue-test-workspace/vue-component-meta/reference-type-props/component-js.vue new file mode 100644 index 000000000..e808e05f2 --- /dev/null +++ b/packages/vue-test-workspace/vue-component-meta/reference-type-props/component-js.vue @@ -0,0 +1,12 @@ + diff --git a/packages/vue-test-workspace/vue-component-meta/reference-type-props/my-props.ts b/packages/vue-test-workspace/vue-component-meta/reference-type-props/my-props.ts index 0b77e324c..53bf591c8 100644 --- a/packages/vue-test-workspace/vue-component-meta/reference-type-props/my-props.ts +++ b/packages/vue-test-workspace/vue-component-meta/reference-type-props/my-props.ts @@ -5,6 +5,10 @@ export interface MyNestedProps { nestedProp: string; } +export interface MyIgnoredNestedProps { + nestedProp: string; +} + enum MyEnum { Small, Medium, @@ -69,7 +73,7 @@ export interface MyProps { /** * optional nested object */ - nestedOptional?: MyNestedProps, + nestedOptional?: MyNestedProps | MyIgnoredNestedProps, /** * required array object */ @@ -86,5 +90,5 @@ export interface MyProps { * literal type alias that require context */ literalFromContext: MyCategories, - literal: { foo: string }, + inlined: { foo: string }, } diff --git a/packages/vue-test-workspace/vue-component-meta/tsconfig.json b/packages/vue-test-workspace/vue-component-meta/tsconfig.json index e1b85270d..2a8d3bfd3 100644 --- a/packages/vue-test-workspace/vue-component-meta/tsconfig.json +++ b/packages/vue-test-workspace/vue-component-meta/tsconfig.json @@ -2,5 +2,6 @@ "extends": "../tsconfig.json", "include": [ "**/*", - ] + ], + "allowJs": true, } \ No newline at end of file