Skip to content

Commit 5882e44

Browse files
committed
feat: Improved support for global files
Lift requirement of only one global file per project If a value is declared in more than one global file entry point, this will result in it being included in both... which isn't great, but seems to produce mostly reasonable results. Resolves #1424
1 parent 56158e2 commit 5882e44

File tree

2 files changed

+48
-55
lines changed

2 files changed

+48
-55
lines changed

src/lib/converter/context.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,12 @@ export class Context {
160160

161161
createDeclarationReflection(
162162
kind: ReflectionKind,
163-
symbol: ts.Symbol,
164-
name = getHumanName(symbol.name)
163+
symbol: ts.Symbol | undefined,
164+
name = getHumanName(symbol?.name ?? "unknown")
165165
) {
166166
const reflection = new DeclarationReflection(name, kind, this.scope);
167167
this.addChild(reflection);
168-
if (this.converter.isExternal(symbol)) {
168+
if (symbol && this.converter.isExternal(symbol)) {
169169
reflection.setFlag(ReflectionFlag.External);
170170
}
171171
this.registerReflection(reflection, symbol);
@@ -175,7 +175,7 @@ export class Context {
175175
this,
176176
reflection,
177177
// FIXME this isn't good enough.
178-
this.converter.getNodesForSymbol(symbol, kind)[0]
178+
symbol && this.converter.getNodesForSymbol(symbol, kind)[0]
179179
);
180180

181181
return reflection;

src/lib/converter/converter.ts

Lines changed: 44 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,7 @@ import * as assert from "assert";
44
import { resolve } from "path";
55

66
import { Application } from "../application";
7-
import {
8-
Type,
9-
ProjectReflection,
10-
ReflectionKind,
11-
ContainerReflection,
12-
DeclarationReflection,
13-
} from "../models/index";
7+
import { Type, ProjectReflection, ReflectionKind } from "../models/index";
148
import { Context } from "./context";
159
import { ConverterComponent } from "./components";
1610
import { Component, ChildableComponent } from "../utils/component";
@@ -249,34 +243,40 @@ export class Converter extends ChildableComponent<
249243
*/
250244
private compile(entryPoints: readonly string[], context: Context) {
251245
const baseDir = getCommonDirectory(entryPoints);
252-
const entries: [string, ts.SourceFile, ts.Program][] = [];
253-
254-
entryLoop: for (const entry of entryPoints.map(normalizePath)) {
246+
const entries: {
247+
file: string;
248+
sourceFile: ts.SourceFile;
249+
program: ts.Program;
250+
context?: Context;
251+
}[] = [];
252+
253+
entryLoop: for (const file of entryPoints.map(normalizePath)) {
255254
for (const program of context.programs) {
256-
const sourceFile = program.getSourceFile(entry);
255+
const sourceFile = program.getSourceFile(file);
257256
if (sourceFile) {
258-
entries.push([entry, sourceFile, program]);
257+
entries.push({ file, sourceFile, program });
259258
continue entryLoop;
260259
}
261260
}
262261
this.application.logger.warn(
263-
`Unable to locate entry point: ${entry}`
262+
`Unable to locate entry point: ${file}`
264263
);
265264
}
266265

267-
for (const [entry, file, program] of entries) {
268-
context.setActiveProgram(program);
269-
this.convertExports(
266+
for (const entry of entries) {
267+
context.setActiveProgram(entry.program);
268+
entry.context = this.convertExports(
270269
context,
271-
file,
270+
entry.sourceFile,
272271
entryPoints,
273-
getModuleName(resolve(entry), baseDir)
272+
getModuleName(resolve(entry.file), baseDir)
274273
);
275274
}
276275

277-
for (const [, file, program] of entries) {
278-
context.setActiveProgram(program);
279-
this.convertReExports(context, file);
276+
for (const { sourceFile, context } of entries) {
277+
// active program is already set on context
278+
assert(context);
279+
this.convertReExports(context, sourceFile);
280280
}
281281

282282
context.setActiveProgram(undefined);
@@ -296,49 +296,28 @@ export class Converter extends ChildableComponent<
296296
// create modules for each entry. Register the project as this module.
297297
context.project.registerReflection(context.project, symbol);
298298
moduleContext = context;
299-
} else if (symbol) {
299+
} else {
300300
const reflection = context.createDeclarationReflection(
301301
ReflectionKind.Module,
302302
symbol,
303303
entryName
304304
);
305305
moduleContext = context.withScope(reflection);
306-
} else {
307-
this.application.logger.warn(
308-
`If specifying a global file as an entry point, only one entry point may be specified. (${node.fileName})`
309-
);
310-
return;
311306
}
312307

313308
for (const exp of getExports(context, node).filter((exp) =>
314-
context
315-
.resolveAliasedSymbol(exp)
316-
.getDeclarations()
317-
?.every((d) => d.getSourceFile() === node.getSourceFile())
309+
isDirectExport(context.resolveAliasedSymbol(exp), node)
318310
)) {
319311
convertSymbol(moduleContext, exp);
320312
}
321-
}
322-
323-
private convertReExports(context: Context, node: ts.SourceFile) {
324-
const symbol = context.checker.getSymbolAtLocation(node) ?? node.symbol;
325-
// Was a global "module"... no re exports.
326-
if (symbol == null) return;
327313

328-
const moduleReflection = context.project.getReflectionFromSymbol(
329-
symbol
330-
);
331-
assert(
332-
moduleReflection instanceof ContainerReflection ||
333-
moduleReflection instanceof DeclarationReflection
334-
);
314+
return moduleContext;
315+
}
335316

336-
const moduleContext = context.withScope(moduleReflection);
337-
for (const exp of getExports(context, node).filter((exp) =>
338-
context
339-
.resolveAliasedSymbol(exp)
340-
.getDeclarations()
341-
?.some((d) => d.getSourceFile() !== node.getSourceFile())
317+
private convertReExports(moduleContext: Context, node: ts.SourceFile) {
318+
for (const exp of getExports(moduleContext, node).filter(
319+
(exp) =>
320+
!isDirectExport(moduleContext.resolveAliasedSymbol(exp), node)
342321
)) {
343322
convertSymbol(moduleContext, exp);
344323
}
@@ -437,10 +416,24 @@ function getExports(
437416
// and lift that up one level
438417
if (
439418
globalSymbols.length === 1 &&
440-
globalSymbols[0].getDeclarations()?.every(ts.isModuleDeclaration)
419+
globalSymbols[0]
420+
.getDeclarations()
421+
?.every(
422+
(declaration) =>
423+
ts.isModuleDeclaration(declaration) &&
424+
ts.isStringLiteral(declaration.name)
425+
)
441426
) {
442427
return context.checker.getExportsOfModule(globalSymbols[0]);
443428
}
444429

445430
return globalSymbols;
446431
}
432+
433+
function isDirectExport(symbol: ts.Symbol, file: ts.SourceFile): boolean {
434+
return (
435+
symbol
436+
.getDeclarations()
437+
?.every((decl) => decl.getSourceFile() === file) ?? false
438+
);
439+
}

0 commit comments

Comments
 (0)