Skip to content

Commit

Permalink
Improve robustness of lib builder.
Browse files Browse the repository at this point in the history
  • Loading branch information
kitsonk authored and ry committed Nov 4, 2018
1 parent 2cf3a89 commit 765f229
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 12 deletions.
73 changes: 63 additions & 10 deletions tools/ts_library_builder/ast_util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,24 @@ export function checkDiagnostics(project: Project, onlyFor?: string[]) {
})
.map(diagnostic => diagnostic.compilerObject);

logDiagnostics(diagnostics);

if (diagnostics.length) {
console.log(
ts.formatDiagnosticsWithColorAndContext(diagnostics, formatDiagnosticHost)
);
process.exit(1);
}
}

function createDeclarationError(
msg: string,
declaration: ImportDeclaration | ExportDeclaration
): Error {
return new Error(
`${msg}\n` +
` In: "${declaration.getSourceFile().getFilePath()}"\n` +
` Text: "${declaration.getText()}"`
);
}

export interface FlattenNamespaceOptions {
customSources?: { [sourceFilePath: string]: string };
debug?: boolean;
Expand Down Expand Up @@ -151,7 +161,12 @@ export function flattenNamespace({
}

sourceFile.getExportDeclarations().forEach(exportDeclaration => {
processSourceFile(exportDeclaration.getModuleSpecifierSourceFileOrThrow());
const exportedSourceFile = exportDeclaration.getModuleSpecifierSourceFile();
if (exportedSourceFile) {
processSourceFile(exportedSourceFile);
} else {
throw createDeclarationError("Missing source file.", exportDeclaration);
}
exportDeclaration.remove();
});

Expand Down Expand Up @@ -254,9 +269,19 @@ export function loadFiles(project: Project, filePaths: string[]) {
}
}

/** Log diagnostics to the console with colour. */
export function logDiagnostics(diagnostics: ts.Diagnostic[]): void {
if (diagnostics.length) {
console.log(
ts.formatDiagnosticsWithColorAndContext(diagnostics, formatDiagnosticHost)
);
}
}

export interface NamespaceSourceFileOptions {
debug?: boolean;
namespace?: string;
namespaces: Set<string>;
rootPath: string;
sourceFileMap: Map<SourceFile, string>;
}
Expand All @@ -267,7 +292,13 @@ export interface NamespaceSourceFileOptions {
*/
export function namespaceSourceFile(
sourceFile: SourceFile,
{ debug, namespace, rootPath, sourceFileMap }: NamespaceSourceFileOptions
{
debug,
namespace,
namespaces,
rootPath,
sourceFileMap
}: NamespaceSourceFileOptions
): string {
if (sourceFileMap.has(sourceFile)) {
return "";
Expand Down Expand Up @@ -300,22 +331,42 @@ export function namespaceSourceFile(

const output = sourceFile
.getImportDeclarations()
.filter(declaration => {
const dsf = declaration.getModuleSpecifierSourceFile();
if (dsf == null) {
try {
const namespaceName = declaration
.getNamespaceImportOrThrow()
.getText();
if (!namespaces.has(namespaceName)) {
throw createDeclarationError(
"Already defined source file under different namespace.",
declaration
);
}
} catch (e) {
throw createDeclarationError(
"Unsupported import clause.",
declaration
);
}
declaration.remove();
}
return dsf;
})
.map(declaration => {
if (
declaration.getNamedImports().length ||
!declaration.getNamespaceImport()
) {
throw new Error(
"Unsupported import clause.\n" +
` In: "${declaration.getSourceFile().getFilePath()}"\n` +
` Text: "${declaration.getText()}"`
);
throw createDeclarationError("Unsupported import clause.", declaration);
}
const text = namespaceSourceFile(
declaration.getModuleSpecifierSourceFileOrThrow(),
{
debug,
namespace: declaration.getNamespaceImportOrThrow().getText(),
namespaces,
rootPath,
sourceFileMap
}
Expand All @@ -328,6 +379,8 @@ export function namespaceSourceFile(
.getExportDeclarations()
.forEach(declaration => declaration.remove());

namespaces.add(namespace);

return `${output}
${globalNamespaceText || ""}
Expand Down
11 changes: 11 additions & 0 deletions tools/ts_library_builder/build_library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
getSourceComment,
loadDtsFiles,
loadFiles,
logDiagnostics,
namespaceSourceFile,
normalizeSlashes
} from "./ast_util";
Expand Down Expand Up @@ -222,6 +223,7 @@ export function mergeGlobal({
// declaration source file into a namespace that exists within the merged
// namespace
const importDeclarations = sourceFile.getImportDeclarations();
const namespaces = new Set<string>();
for (const declaration of importDeclarations) {
const declarationSourceFile = declaration.getModuleSpecifierSourceFile();
if (
Expand All @@ -241,6 +243,7 @@ export function mergeGlobal({
namespaceSourceFile(dtsSourceFile, {
debug,
namespace: declaration.getNamespaceImportOrThrow().getText(),
namespaces,
rootPath: basePath,
sourceFileMap
})
Expand Down Expand Up @@ -308,6 +311,14 @@ export function main({
// emit the project, which will be only the declaration files
const inputEmitResult = inputProject.emitToMemory();

const inputDiagnostics = inputEmitResult
.getDiagnostics()
.map(d => d.compilerObject);
logDiagnostics(inputDiagnostics);
if (inputDiagnostics.length) {
process.exit(1);
}

// the declaration project will be the target for the emitted files from
// the input project, these will be used to transfer information over to
// the final library file
Expand Down
15 changes: 13 additions & 2 deletions tools/ts_library_builder/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,10 @@ test(function buildLibraryMerge() {
});

assert(targetSourceFile.getNamespace("moduleC") != null);
assertEqual(targetSourceFile.getNamespaces().length, 1);
assert(targetSourceFile.getNamespace("moduleD") != null);
assert(targetSourceFile.getNamespace("moduleE") != null);
assert(targetSourceFile.getNamespace("moduleF") != null);
assertEqual(targetSourceFile.getNamespaces().length, 4);
assert(targetSourceFile.getInterface("FooBar") != null);
assertEqual(targetSourceFile.getInterfaces().length, 1);
const variableDeclarations = targetSourceFile.getVariableDeclarations();
Expand All @@ -138,7 +141,15 @@ test(function buildLibraryMerge() {
variableDeclarations[2].getType().getText(),
`typeof moduleC.qat`
);
assertEqual(variableDeclarations.length, 3);
assertEqual(
variableDeclarations[3].getType().getText(),
`typeof moduleE.process`
);
assertEqual(
variableDeclarations[4].getType().getText(),
`typeof moduleD.reprocess`
);
assertEqual(variableDeclarations.length, 5);
});

// TODO author unit tests for `ast_util.ts`
4 changes: 4 additions & 0 deletions tools/ts_library_builder/testdata/globals.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import * as moduleC from "./moduleC";
import * as moduleD from "./moduleD";
import * as moduleE from "./moduleE";

// tslint:disable-next-line:no-any
const foobarbaz: any = {};
foobarbaz.bar = new moduleC.Bar();
foobarbaz.qat = moduleC.qat;
foobarbaz.process = moduleE.process;
foobarbaz.reprocess = moduleD.reprocess;
5 changes: 5 additions & 0 deletions tools/ts_library_builder/testdata/moduleD.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as moduleF from "./moduleF";

export function reprocess(value: typeof moduleF.key) {
console.log(value);
}
5 changes: 5 additions & 0 deletions tools/ts_library_builder/testdata/moduleE.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as moduleF from "./moduleF";

export function process(value: typeof moduleF.key) {
console.log(value);
}
1 change: 1 addition & 0 deletions tools/ts_library_builder/testdata/moduleF.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const key = "value";

0 comments on commit 765f229

Please sign in to comment.