Skip to content

Commit

Permalink
fix: support multiple entry points again
Browse files Browse the repository at this point in the history
  • Loading branch information
aleclarson committed Jun 6, 2019
1 parent 1e0e0f7 commit d282499
Showing 1 changed file with 66 additions and 26 deletions.
92 changes: 66 additions & 26 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as ts from "typescript";
import * as path from "path";
import { PluginImpl, SourceDescription, InputOptions } from "rollup";
import { PluginImpl, SourceDescription } from "rollup";
import { Transformer } from "./Transformer";
import { NamespaceFixer } from "./NamespaceFixer";

Expand Down Expand Up @@ -31,13 +31,10 @@ function getCompilerOptions(input: string): ts.CompilerOptions {
return options;
};

const createProgram = ({ input }: InputOptions) => {
if (typeof input !== "string") {
throw new TypeError('"input" option must be a string');
}
input = path.resolve(input);
const createProgram = (main: string) => {
main = path.resolve(main);
const compilerOptions: ts.CompilerOptions = {
...getCompilerOptions(input),
...getCompilerOptions(main),
// Ensure ".d.ts" modules are generated
declaration: true,
// Skip ".js" generation
Expand All @@ -52,7 +49,7 @@ const createProgram = ({ input }: InputOptions) => {
preserveSymlinks: true,
};
const host = ts.createCompilerHost(compilerOptions, true);
return ts.createProgram([input], compilerOptions, host);
return ts.createProgram([main], compilerOptions, host);
};

// Parse a TypeScript module into an ESTree program.
Expand All @@ -75,12 +72,48 @@ const transformFile = (input: ts.SourceFile): SourceDescription => {
};

const plugin: PluginImpl<{}> = () => {
let program: ts.Program;
// There exists one Program object per entry point,
// except when all entry points are ".d.ts" modules.
const programs = new Map<string, ts.Program>();
const getModule = (fileName: string) => {
let source: ts.SourceFile | null = null;
let program: ts.Program | null = null;
if (programs.size) {
// Rollup doesn't tell you the entry point of each module in the bundle,
// so we need to ask every TypeScript program for the given filename.
for (program of programs.values()) {
source = program.getSourceFile(fileName) || null;
if (source) break;
}
}
// Create any `ts.SourceFile` objects on-demand for ".d.ts" modules,
// but only when there are zero ".ts" entry points.
else if (fileName.endsWith(dts)) {
const code = ts.sys.readFile(fileName, "utf8");
if (code)
source = ts.createSourceFile(
fileName,
code,
ts.ScriptTarget.Latest,
true, // setParentNodes
);
}
return { source, program };
};

return {
name: "dts",

options(options) {
program = createProgram(options);
let { input } = options;
if (!Array.isArray(input)) {
input = !input ? [] : typeof input === "string" ? [input] : Object.values(input);
}
input.forEach(main => {
if (!main.endsWith(dts)) {
programs.set(main, createProgram(main));
}
});
return {
...options,
treeshake: {
Expand Down Expand Up @@ -109,26 +142,33 @@ const plugin: PluginImpl<{}> = () => {
if (!tsx.test(id)) {
return null;
}
const source = program.getSourceFile(id);
if (!source) {
return null;
}
if (id.endsWith(dts)) {
return transformFile(source);
const { source } = getModule(id);
return source ? transformFile(source) : null;
}
const ambientId = id.replace(tsx, dts);
const ambientDefs = program.getSourceFile(ambientId);
if (ambientDefs) {
return transformFile(ambientDefs);
// Always try ".d.ts" before ".tsx?"
const declarationId = id.replace(tsx, dts);
let module = getModule(declarationId);
if (module.source) {
return transformFile(module.source);
}
// Generate in-memory ".d.ts" modules from ".tsx?" modules!
module = getModule(id);
if (!module.source || !module.program) {
return null;
}
// Transform ".ts" modules into ".d.ts" in-memory!
let generated!: SourceDescription;
const { emitSkipped, diagnostics } = program.emit(
source,
(_, code) => {
const ambientDefs = ts.createSourceFile(ambientId, code, ts.ScriptTarget.Latest, true);
generated = transformFile(ambientDefs);
},
const { emitSkipped, diagnostics } = module.program.emit(
module.source,
(_, declarationText) =>
(generated = transformFile(
ts.createSourceFile(
declarationId,
declarationText,
ts.ScriptTarget.Latest,
true, // setParentNodes
),
)),
undefined, // cancellationToken
true, // emitOnlyDtsFiles
);
Expand Down

0 comments on commit d282499

Please sign in to comment.