Skip to content

Commit 45ab3d5

Browse files
committed
refactor(component-meta): remove parseScriptRanges need
1 parent bb235b6 commit 45ab3d5

File tree

6 files changed

+151
-184
lines changed

6 files changed

+151
-184
lines changed

packages/component-meta/lib/base.ts

Lines changed: 74 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ function baseCreate(
110110
let fileNamesSet = new Set(fileNames.map(path => path.replace(windowsPathReg, '/')));
111111
let projectVersion = 0;
112112

113-
const scriptRangesCache = new WeakMap<ts.SourceFile, core.ScriptRanges>();
114113
const projectHost: TypeScriptProjectHost = {
115114
getCurrentDirectory: () => rootPath,
116115
getProjectVersion: () => projectVersion.toString(),
@@ -206,35 +205,29 @@ function baseCreate(
206205
},
207206
};
208207

209-
function getExportNames(componentPath: string) {
210-
const program = tsLs.getProgram()!;
211-
const sourceFile = program.getSourceFile(componentPath);
212-
if (sourceFile) {
213-
const scriptRanges = getScriptRanges(sourceFile);
214-
return Object.keys(scriptRanges.exports);
215-
}
216-
}
217-
218-
function getComponentMeta(componentPath: string, exportName = 'default'): ComponentMeta {
208+
function getProgramAndFile(componentPath: string) {
219209
let program = tsLs.getProgram()!;
220210
let sourceFile = program.getSourceFile(componentPath);
221211
if (!sourceFile) {
222212
fileNamesSet.add(componentPath);
223213
projectVersion++;
224214
program = tsLs.getProgram()!;
225-
sourceFile = program.getSourceFile(componentPath);
226-
if (!sourceFile) {
227-
throw `Could not find component file: ${componentPath}`;
228-
}
215+
sourceFile = program.getSourceFile(componentPath)!;
229216
}
217+
return [program, sourceFile] as const;
218+
}
230219

231-
const scriptRanges = getScriptRanges(sourceFile);
232-
const component = scriptRanges.exports[exportName];
233-
if (!component) {
234-
throw `Could not find export ${exportName}`;
235-
}
220+
function getExportNames(componentPath: string) {
221+
const [program, sourceFile] = getProgramAndFile(componentPath);
222+
return getExports(program, sourceFile).map(e => e.getName());
223+
}
236224

237-
const symbolNode = component.expression.node;
225+
function getComponentMeta(componentPath: string, exportName = 'default'): ComponentMeta {
226+
const [program, sourceFile] = getProgramAndFile(componentPath);
227+
const symbolNode = getExport(ts, program, sourceFile, exportName)!;
228+
if (!symbolNode) {
229+
throw new Error(`Export '${exportName}' not found in '${componentPath}'.`);
230+
}
238231
const typeChecker = program.getTypeChecker();
239232

240233
let name: string | undefined;
@@ -387,32 +380,55 @@ function baseCreate(
387380
}
388381

389382
function getName() {
390-
const sourceFile = program.getSourceFile(componentPath);
391-
if (sourceFile) {
392-
const scriptRanges = getScriptRanges(sourceFile);
393-
const name = scriptRanges?.exports[exportName]?.options?.name;
394-
if (name && ts.isStringLiteral(name.node)) {
395-
return name.node.text;
396-
}
383+
let decl = getExport(ts, program, sourceFile, exportName);
384+
if (!decl) {
385+
return;
386+
}
387+
388+
// const __VLS_export = ...
389+
const text = sourceFile.text.slice(decl.pos, decl.end);
390+
if (text.includes(core.names._export)) {
391+
ts.forEachChild(sourceFile, child2 => {
392+
if (ts.isVariableStatement(child2)) {
393+
for (const { name, initializer } of child2.declarationList.declarations) {
394+
if (name.getText() === core.names._export && initializer) {
395+
decl = initializer;
396+
}
397+
}
398+
}
399+
});
397400
}
401+
402+
return core.parseOptionsFromExtression(ts, decl, sourceFile)?.name?.node.text;
398403
}
399404

400405
function getDescription() {
401-
const sourceFile = program.getSourceFile(componentPath);
402-
if (sourceFile) {
403-
const scriptRanges = getScriptRanges(sourceFile);
404-
return readComponentDescription(ts, scriptRanges, exportName, typeChecker);
406+
const decl = getExport(ts, program, sourceFile, exportName);
407+
if (!decl) {
408+
return;
405409
}
406-
}
407-
}
408410

409-
function getScriptRanges(sourceFile: ts.SourceFile) {
410-
let scriptRanges = scriptRangesCache.get(sourceFile);
411-
if (!scriptRanges) {
412-
scriptRanges = core.parseScriptRanges(ts, sourceFile, vueOptions);
413-
scriptRangesCache.set(sourceFile, scriptRanges);
411+
// Try to get JSDoc comments from the node using TypeScript API
412+
const jsDocComments = ts.getJSDocCommentsAndTags(decl);
413+
for (const jsDoc of jsDocComments) {
414+
if (ts.isJSDoc(jsDoc) && jsDoc.comment) {
415+
// Handle both string and array of comment parts
416+
if (typeof jsDoc.comment === 'string') {
417+
return jsDoc.comment;
418+
}
419+
else if (Array.isArray(jsDoc.comment)) {
420+
return jsDoc.comment.map(part => (part as any).text || '').join('');
421+
}
422+
}
423+
}
424+
425+
// Fallback to symbol documentation
426+
const symbol = typeChecker.getSymbolAtLocation(decl);
427+
if (symbol) {
428+
const description = ts.displayPartsToString(symbol.getDocumentationComment(typeChecker));
429+
return description || undefined;
430+
}
414431
}
415-
return scriptRanges;
416432
}
417433

418434
function getVirtualCode(fileName: string) {
@@ -867,34 +883,27 @@ function resolveDefaultOptionExpression(
867883
return _default;
868884
}
869885

870-
function readComponentDescription(
886+
function getExport(
871887
ts: typeof import('typescript'),
872-
scriptRanges: core.ScriptRanges,
888+
program: ts.Program,
889+
sourceFile: ts.SourceFile,
873890
exportName: string,
874-
typeChecker: ts.TypeChecker,
875-
): string | undefined {
876-
const _export = scriptRanges.exports[exportName];
877-
878-
if (_export) {
879-
// Try to get JSDoc comments from the node using TypeScript API
880-
const jsDocComments = ts.getJSDocCommentsAndTags(_export.node);
881-
for (const jsDoc of jsDocComments) {
882-
if (ts.isJSDoc(jsDoc) && jsDoc.comment) {
883-
// Handle both string and array of comment parts
884-
if (typeof jsDoc.comment === 'string') {
885-
return jsDoc.comment;
886-
}
887-
else if (Array.isArray(jsDoc.comment)) {
888-
return jsDoc.comment.map(part => (part as any).text || '').join('');
889-
}
890-
}
891+
) {
892+
const exports = getExports(program, sourceFile);
893+
const symbol = exports.find(e => e.getName() === exportName);
894+
if (symbol?.valueDeclaration) {
895+
const decl = symbol.valueDeclaration;
896+
if (ts.isExportAssignment(decl)) {
897+
return decl.expression;
891898
}
892-
893-
// Fallback to symbol documentation
894-
const symbol = typeChecker.getSymbolAtLocation(_export.node);
895-
if (symbol) {
896-
const description = ts.displayPartsToString(symbol.getDocumentationComment(typeChecker));
897-
return description || undefined;
899+
if (ts.isVariableDeclaration(decl)) {
900+
return decl.initializer;
898901
}
899902
}
900903
}
904+
905+
function getExports(program: ts.Program, sourceFile: ts.SourceFile) {
906+
const typeChecker = program.getTypeChecker();
907+
const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
908+
return moduleSymbol ? typeChecker.getExportsOfModule(moduleSymbol) : [];
909+
}

packages/language-core/lib/codegen/script/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ function* generateWorker(
7171

7272
// <script>
7373
let selfType: string | undefined;
74-
const exportDefault = scriptRanges.exports.default;
74+
const { exportDefault } = scriptRanges;
7575
if (exportDefault) {
7676
yield* generateScriptWithExportDefault(
7777
ctx,
@@ -154,7 +154,7 @@ function* generateWorker(
154154
}
155155
// only <script>
156156
else if (script && scriptRanges) {
157-
const exportDefault = scriptRanges.exports.default;
157+
const { exportDefault } = scriptRanges;
158158
if (exportDefault) {
159159
yield* generateScriptWithExportDefault(
160160
ctx,
@@ -182,12 +182,12 @@ function* generateScriptWithExportDefault(
182182
ctx: ScriptCodegenContext,
183183
script: NonNullable<Sfc['script']>,
184184
scriptRanges: ScriptRanges,
185-
exportDefault: NonNullable<ScriptRanges['exports'][string]>,
185+
exportDefault: NonNullable<ScriptRanges['exportDefault']>,
186186
vueCompilerOptions: VueCompilerOptions,
187187
varName: string,
188188
templateGenerator?: Generator<Code>,
189189
): Generator<Code> {
190-
const componentOptions = scriptRanges.exports.default?.options;
190+
const componentOptions = scriptRanges.exportDefault?.options;
191191
const { expression, isObjectLiteral } = componentOptions ?? exportDefault;
192192

193193
let wrapLeft: string | undefined;

packages/language-core/lib/codegen/script/template.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ function* generateTemplateComponents(
8888
if (ctx.generatedTypes.has(names.SetupExposed)) {
8989
types.push(names.SetupExposed);
9090
}
91-
if (script && scriptRanges?.exports.default?.options?.components) {
92-
const { components } = scriptRanges.exports.default.options;
91+
if (script && scriptRanges?.exportDefault?.options?.components) {
92+
const { components } = scriptRanges.exportDefault.options;
9393
yield `const __VLS_componentsOption = `;
9494
yield* generateSfcBlockSection(
9595
script,
@@ -124,8 +124,8 @@ function* generateTemplateDirectives(
124124
if (ctx.generatedTypes.has(names.SetupExposed)) {
125125
types.push(names.SetupExposed);
126126
}
127-
if (script && scriptRanges?.exports.default?.options?.directives) {
128-
const { directives } = scriptRanges.exports.default.options;
127+
if (script && scriptRanges?.exportDefault?.options?.directives) {
128+
const { directives } = scriptRanges.exportDefault.options;
129129
yield `const __VLS_directivesOption = `;
130130
yield* generateSfcBlockSection(
131131
script,

0 commit comments

Comments
 (0)