Skip to content

Commit 63c6d83

Browse files
committed
Merge branch 'master' into vue.md
2 parents 35d7a10 + 7c64219 commit 63c6d83

26 files changed

+1072
-1057
lines changed

packages/component-meta/lib/checker.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ export function createCheckerBase(
6969
const { languageServiceHost } = createLanguageServiceHost(ts, ts.sys, language, s => s, projectHost);
7070
const tsLs = ts.createLanguageService(languageServiceHost);
7171
const printer = ts.createPrinter(checkerOptions.printer);
72+
const getScriptKind = languageServiceHost.getScriptKind?.bind(languageServiceHost);
7273

73-
if (checkerOptions.forceUseTs) {
74-
const getScriptKind = languageServiceHost.getScriptKind?.bind(languageServiceHost);
74+
if (checkerOptions.forceUseTs ?? true) {
7575
languageServiceHost.getScriptKind = fileName => {
7676
const scriptKind = getScriptKind!(fileName);
7777
if (vueOptions.extensions.some(ext => fileName.endsWith(ext))) {
@@ -95,15 +95,20 @@ export function createCheckerBase(
9595
if (!componentNode) {
9696
throw new Error(`Export '${exportName}' not found in '${sourceFile.fileName}'.`);
9797
}
98+
const checker = program.getTypeChecker();
99+
const componentType = checker.getTypeAtLocation(componentNode);
98100
return getComponentMeta(
99101
ts,
100-
program,
102+
checker,
101103
printer,
102-
vueOptions,
103104
language,
104-
sourceFile,
105105
componentNode,
106-
checkerOptions,
106+
componentType,
107+
checkerOptions.schema ?? false,
108+
{
109+
noDeclarations: checkerOptions.noDeclarations ?? true,
110+
rawType: checkerOptions.rawType ?? false,
111+
},
107112
);
108113
},
109114
updateFile(fileName: string, text: string) {
@@ -150,7 +155,7 @@ export function createCheckerBase(
150155
}
151156
}
152157

153-
function getExport(
158+
export function getExport(
154159
ts: typeof import('typescript'),
155160
program: ts.Program,
156161
sourceFile: ts.SourceFile,

packages/component-meta/lib/componentMeta.ts

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,33 @@ import {
99
} from './helpers';
1010
import { createSchemaResolvers } from './schemaResolvers';
1111
import { getDefaultsFromScriptSetup } from './scriptSetup';
12-
import type { ComponentMeta, MetaCheckerOptions, PropertyMeta } from './types';
13-
14-
const vnodeEventRegex = /^onVnode[A-Z]/;
12+
import type { ComponentMeta, MetaCheckerSchemaOptions, PropertyMeta } from './types';
1513

1614
export function getComponentMeta(
1715
ts: typeof import('typescript'),
18-
program: ts.Program,
16+
typeChecker: ts.TypeChecker,
1917
printer: ts.Printer,
20-
vueOptions: core.VueCompilerOptions,
2118
language: core.Language<string>,
22-
sourceFile: ts.SourceFile,
23-
componentNode: ts.Expression,
24-
checkerOptions: MetaCheckerOptions,
19+
componentNode: ts.Node,
20+
componentType: ts.Type,
21+
options: MetaCheckerSchemaOptions,
22+
deprecatedOptions: { noDeclarations: boolean; rawType: boolean } = { noDeclarations: true, rawType: false },
2523
): ComponentMeta {
26-
const typeChecker = program.getTypeChecker();
24+
const componentSymbol = typeChecker.getSymbolAtLocation(componentNode);
25+
26+
let componentFile = componentNode.getSourceFile();
27+
28+
if (componentSymbol) {
29+
const symbol = componentSymbol.flags & ts.SymbolFlags.Alias
30+
? typeChecker.getAliasedSymbol(componentSymbol)
31+
: componentType.symbol;
32+
const declaration = symbol?.valueDeclaration ?? symbol?.declarations?.[0];
33+
34+
if (declaration) {
35+
componentFile = declaration.getSourceFile();
36+
componentNode = declaration;
37+
}
38+
}
2739

2840
let name: string | undefined;
2941
let description: string | undefined;
@@ -60,11 +72,11 @@ export function getComponentMeta(
6072
return meta;
6173

6274
function getType() {
63-
return inferComponentType(typeChecker, componentNode) ?? 0;
75+
return inferComponentType(componentType) ?? 0;
6476
}
6577

6678
function getProps() {
67-
const propsType = inferComponentProps(typeChecker, componentNode);
79+
const propsType = inferComponentProps(typeChecker, componentType);
6880
if (!propsType) {
6981
return [];
7082
}
@@ -79,36 +91,34 @@ export function getComponentMeta(
7991
.map(prop => {
8092
const {
8193
resolveNestedProperties,
82-
} = createSchemaResolvers(ts, typeChecker, printer, language, componentNode, checkerOptions);
94+
} = createSchemaResolvers(ts, typeChecker, printer, language, options, deprecatedOptions);
8395

8496
return resolveNestedProperties(prop);
8597
})
86-
.filter(prop => !vnodeEventRegex.test(prop.name) && !eventProps.has(prop.name));
98+
.filter((prop): prop is PropertyMeta => !!prop && !eventProps.has(prop.name));
8799

88-
// Merge default props from script setup
89-
const defaults = getDefaultsFromScriptSetup(ts, printer, language, sourceFile.fileName, vueOptions);
100+
const defaults = getDefaultsFromScriptSetup(ts, printer, language, componentFile.fileName);
90101

91-
if (defaults?.size) {
92-
for (const prop of result) {
93-
if (defaults.has(prop.name)) {
94-
prop.default = defaults.get(prop.name);
95-
}
102+
for (const prop of result) {
103+
if (prop.name.match(/^onVnode[A-Z]/)) {
104+
prop.name = 'onVue:' + prop.name['onVnode'.length]?.toLowerCase() + prop.name.slice('onVnode'.length + 1);
96105
}
106+
prop.default ??= defaults?.get(prop.name);
97107
}
98108

99109
return result;
100110
}
101111

102112
function getEvents() {
103-
const emitType = inferComponentEmit(typeChecker, componentNode);
113+
const emitType = inferComponentEmit(typeChecker, componentType);
104114

105115
if (emitType) {
106116
const calls = emitType.getCallSignatures();
107117

108118
return calls.map(call => {
109119
const {
110120
resolveEventSignature,
111-
} = createSchemaResolvers(ts, typeChecker, printer, language, componentNode, checkerOptions);
121+
} = createSchemaResolvers(ts, typeChecker, printer, language, options, deprecatedOptions);
112122

113123
return resolveEventSignature(call);
114124
}).filter(event => event.name);
@@ -118,15 +128,15 @@ export function getComponentMeta(
118128
}
119129

120130
function getSlots() {
121-
const slotsType = inferComponentSlots(typeChecker, componentNode);
131+
const slotsType = inferComponentSlots(typeChecker, componentType);
122132

123133
if (slotsType) {
124134
const properties = slotsType.getProperties();
125135

126136
return properties.map(prop => {
127137
const {
128138
resolveSlotProperties,
129-
} = createSchemaResolvers(ts, typeChecker, printer, language, componentNode, checkerOptions);
139+
} = createSchemaResolvers(ts, typeChecker, printer, language, options, deprecatedOptions);
130140

131141
return resolveSlotProperties(prop);
132142
});
@@ -136,10 +146,10 @@ export function getComponentMeta(
136146
}
137147

138148
function getExposed() {
139-
const exposedType = inferComponentExposed(typeChecker, componentNode);
149+
const exposedType = inferComponentExposed(typeChecker, componentType);
140150

141151
if (exposedType) {
142-
const propsType = inferComponentProps(typeChecker, componentNode);
152+
const propsType = inferComponentProps(typeChecker, componentType);
143153
const propsProperties = propsType?.getProperties() ?? [];
144154
const properties = exposedType.getProperties().filter(prop =>
145155
// only exposed props will have at least one declaration and no valueDeclaration
@@ -154,7 +164,7 @@ export function getComponentMeta(
154164
return properties.map(prop => {
155165
const {
156166
resolveExposedProperties,
157-
} = createSchemaResolvers(ts, typeChecker, printer, language, componentNode, checkerOptions);
167+
} = createSchemaResolvers(ts, typeChecker, printer, language, options, deprecatedOptions);
158168

159169
return resolveExposedProperties(prop);
160170
});
@@ -167,9 +177,9 @@ export function getComponentMeta(
167177
let decl = componentNode;
168178

169179
// const __VLS_export = ...
170-
const text = sourceFile.text.slice(decl.pos, decl.end);
180+
const text = componentFile.text.slice(decl.pos, decl.end);
171181
if (text.includes(core.names._export)) {
172-
ts.forEachChild(sourceFile, child2 => {
182+
ts.forEachChild(componentFile, child2 => {
173183
if (ts.isVariableStatement(child2)) {
174184
for (const { name, initializer } of child2.declarationList.declarations) {
175185
if (name.getText() === core.names._export && initializer) {
@@ -180,7 +190,7 @@ export function getComponentMeta(
180190
});
181191
}
182192

183-
return core.parseOptionsFromExtression(ts, decl, sourceFile)?.name?.node.text;
193+
return core.parseOptionsFromExtression(ts, decl, componentFile)?.name?.node.text;
184194
}
185195

186196
function getDescription() {

packages/component-meta/lib/helpers.ts

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import type * as ts from 'typescript';
22

33
export function inferComponentType(
4-
typeChecker: ts.TypeChecker,
5-
symbolNode: ts.Node,
4+
componentType: ts.Type,
65
) {
7-
const componentType = typeChecker.getTypeAtLocation(symbolNode);
86
const constructSignatures = componentType.getConstructSignatures();
97
const callSignatures = componentType.getCallSignatures();
108

@@ -19,15 +17,14 @@ export function inferComponentType(
1917

2018
export function inferComponentProps(
2119
typeChecker: ts.TypeChecker,
22-
symbolNode: ts.Node,
20+
componentType: ts.Type,
2321
): ts.Type | undefined {
24-
const componentType = typeChecker.getTypeAtLocation(symbolNode);
2522
const constructSignatures = componentType.getConstructSignatures();
2623
const callSignatures = componentType.getCallSignatures();
2724

2825
for (const sig of constructSignatures) {
2926
const retType = sig.getReturnType();
30-
const props = findProperty(typeChecker, symbolNode, retType, '$props');
27+
const props = findProperty(typeChecker, retType, '$props');
3128
if (props) {
3229
return props;
3330
}
@@ -37,23 +34,22 @@ export function inferComponentProps(
3734
if (sig.parameters.length > 0) {
3835
const props = sig.parameters[0];
3936
if (props) {
40-
return typeChecker.getTypeOfSymbolAtLocation(props, symbolNode);
37+
return typeChecker.getTypeOfSymbol(props);
4138
}
4239
}
4340
}
4441
}
4542

4643
export function inferComponentSlots(
4744
typeChecker: ts.TypeChecker,
48-
symbolNode: ts.Node,
45+
componentType: ts.Type,
4946
): ts.Type | undefined {
50-
const componentType = typeChecker.getTypeAtLocation(symbolNode);
5147
const constructSignatures = componentType.getConstructSignatures();
5248
const callSignatures = componentType.getCallSignatures();
5349

5450
for (const sig of constructSignatures) {
5551
const retType = sig.getReturnType();
56-
const slots = findProperty(typeChecker, symbolNode, retType, '$slots');
52+
const slots = findProperty(typeChecker, retType, '$slots');
5753
if (slots) {
5854
return slots;
5955
}
@@ -63,8 +59,8 @@ export function inferComponentSlots(
6359
if (sig.parameters.length > 1) {
6460
const ctxParam = sig.parameters[1];
6561
if (ctxParam) {
66-
const ctxType = typeChecker.getTypeOfSymbolAtLocation(ctxParam, symbolNode);
67-
const slots = findProperty(typeChecker, symbolNode, ctxType, 'slots');
62+
const ctxType = typeChecker.getTypeOfSymbol(ctxParam);
63+
const slots = findProperty(typeChecker, ctxType, 'slots');
6864
if (slots) {
6965
return slots;
7066
}
@@ -75,15 +71,14 @@ export function inferComponentSlots(
7571

7672
export function inferComponentEmit(
7773
typeChecker: ts.TypeChecker,
78-
symbolNode: ts.Node,
74+
componentType: ts.Type,
7975
): ts.Type | undefined {
80-
const componentType = typeChecker.getTypeAtLocation(symbolNode);
8176
const constructSignatures = componentType.getConstructSignatures();
8277
const callSignatures = componentType.getCallSignatures();
8378

8479
for (const sig of constructSignatures) {
8580
const retType = sig.getReturnType();
86-
const emit = findProperty(typeChecker, symbolNode, retType, '$emit');
81+
const emit = findProperty(typeChecker, retType, '$emit');
8782
if (emit) {
8883
return emit;
8984
}
@@ -93,8 +88,8 @@ export function inferComponentEmit(
9388
if (sig.parameters.length > 1) {
9489
const ctxParam = sig.parameters[1];
9590
if (ctxParam) {
96-
const ctxType = typeChecker.getTypeOfSymbolAtLocation(ctxParam, symbolNode);
97-
const emitType = findProperty(typeChecker, symbolNode, ctxType, 'emit');
91+
const ctxType = typeChecker.getTypeOfSymbol(ctxParam);
92+
const emitType = findProperty(typeChecker, ctxType, 'emit');
9893
if (emitType) {
9994
return emitType;
10095
}
@@ -105,9 +100,8 @@ export function inferComponentEmit(
105100

106101
export function inferComponentExposed(
107102
typeChecker: ts.TypeChecker,
108-
symbolNode: ts.Node,
103+
componentType: ts.Type,
109104
): ts.Type | undefined {
110-
const componentType = typeChecker.getTypeAtLocation(symbolNode);
111105
const constructSignatures = componentType.getConstructSignatures();
112106
const callSignatures = componentType.getCallSignatures();
113107

@@ -119,12 +113,12 @@ export function inferComponentExposed(
119113
if (sig.parameters.length > 2) {
120114
const exposeParam = sig.parameters[2];
121115
if (exposeParam) {
122-
const exposeType = typeChecker.getTypeOfSymbolAtLocation(exposeParam, symbolNode);
116+
const exposeType = typeChecker.getTypeOfSymbol(exposeParam);
123117
const callSignatures = exposeType.getCallSignatures();
124118
for (const callSig of callSignatures) {
125119
const params = callSig.getParameters();
126120
if (params.length > 0) {
127-
return typeChecker.getTypeOfSymbolAtLocation(params[0]!, symbolNode);
121+
return typeChecker.getTypeOfSymbol(params[0]!);
128122
}
129123
}
130124
}
@@ -134,17 +128,16 @@ export function inferComponentExposed(
134128

135129
function findProperty(
136130
typeChecker: ts.TypeChecker,
137-
location: ts.Node,
138131
type: ts.Type,
139132
property: string,
140133
): ts.Type | undefined {
141134
const symbol = type.getProperty(property);
142135
if (symbol) {
143-
return typeChecker.getTypeOfSymbolAtLocation(symbol, location);
136+
return typeChecker.getTypeOfSymbol(symbol);
144137
}
145138
if (type.isUnionOrIntersection()) {
146139
for (const sub of type.types) {
147-
const found = findProperty(typeChecker, location, sub, property);
140+
const found = findProperty(typeChecker, sub, property);
148141
if (found) {
149142
return found;
150143
}

0 commit comments

Comments
 (0)