Skip to content

Commit

Permalink
fix: allow generating SourceFiles for files matched by a user-provide…
Browse files Browse the repository at this point in the history
…d 'exclude' glob. Closes #65
  • Loading branch information
wessberg committed Jan 5, 2020
1 parent 78e5fc7 commit c54c1e6
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 21 deletions.
1 change: 1 addition & 0 deletions src/plugin/typescript-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ export default function typescriptRollupPlugin(pluginInputOptions: Partial<Types
watchChange(id: string): void {
host.delete(id);
resolveCache.delete(id);
host.clearCaches();
},

/**
Expand Down
12 changes: 6 additions & 6 deletions src/service/compiler-host/compiler-host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ export class CompilerHost extends ModuleResolutionHost implements TS.CompilerHos
this.addDefaultFileNames();
}

isSupportedFileName(fileName: string): boolean {
return this.options.filter(fileName) && this.getSupportedExtensions().has(getExtension(fileName));
isSupportedFileName(fileName: string, ignoreFilter: boolean = false): boolean {
return (ignoreFilter || this.options.filter(fileName)) && this.getSupportedExtensions().has(getExtension(fileName));
}

getDiagnostics(fileName?: string): readonly TS.Diagnostic[] {
Expand Down Expand Up @@ -287,7 +287,7 @@ export class CompilerHost extends ModuleResolutionHost implements TS.CompilerHos
return this.sourceFiles.get(absoluteFileName);
}

if (!this.isSupportedFileName(absoluteFileName)) return undefined;
if (!this.isSupportedFileName(absoluteFileName, true)) return undefined;

let file = this.get(absoluteFileName);

Expand Down Expand Up @@ -390,9 +390,9 @@ export class CompilerHost extends ModuleResolutionHost implements TS.CompilerHos
*/
readDirectory(
path: string,
extensions?: ReadonlyArray<string>,
exclude?: ReadonlyArray<string>,
include?: ReadonlyArray<string>,
extensions: readonly string[],
exclude: readonly string[] | undefined,
include: readonly string[],
depth?: number
): string[] {
return this.getFileSystem()
Expand Down
47 changes: 40 additions & 7 deletions src/service/module-resolution-host/module-resolution-host.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import {TS} from "../../type/ts";
import {ModuleResolutionHostOptions} from "./module-resolution-host-options";
import {nativeNormalize, normalize} from "../../util/path/path-util";
import {dirname, nativeNormalize, normalize} from "../../util/path/path-util";
import {FileSystem} from "../../util/file-system/file-system";
import {SupportedExtensions} from "../../util/get-supported-extensions/get-supported-extensions";
import {VirtualFile, VirtualFileInput} from "./virtual-file";

export class ModuleResolutionHost implements TS.ModuleSpecifierResolutionHost {
private readonly directoryExistsCache: Map<string, boolean> = new Map();
private readonly fileExistsCache: Map<string, boolean> = new Map();
private currentFileNames: Set<string> | undefined;
private currentDirectories: Set<string> | undefined;
constructor(protected readonly options: ModuleResolutionHostOptions, protected readonly files: Map<string, VirtualFile> = new Map()) {}

add(fileInput: VirtualFileInput | VirtualFile): VirtualFile {
Expand All @@ -14,9 +18,18 @@ export class ModuleResolutionHost implements TS.ModuleSpecifierResolutionHost {
transformedText: "transformedText" in fileInput && fileInput.transformedText != null ? fileInput.transformedText : fileInput.text
};
this.files.set(file.fileName, file);
this.fileExistsCache.delete(file.fileName);
this.directoryExistsCache.delete(dirname(file.fileName));
this.currentFileNames = undefined;
this.currentDirectories = undefined;
return file;
}

clearCaches(): void {
this.directoryExistsCache.clear();
this.fileExistsCache.clear();
}

delete(fileName: string): boolean {
return this.files.delete(fileName);
}
Expand All @@ -30,7 +43,19 @@ export class ModuleResolutionHost implements TS.ModuleSpecifierResolutionHost {
}

getFileNames(): Set<string> {
return new Set(this.files.keys());
if (this.currentFileNames == null) {
this.currentFileNames = new Set(this.files.keys());
}

return this.currentFileNames;
}

getFileNameDirectories(): Set<string> {
if (this.currentDirectories == null) {
this.currentDirectories = new Set([...this.getFileNames()].map(fileName => dirname(fileName)));
}

return this.currentDirectories;
}

getRollupFileNames(): Set<string> {
Expand Down Expand Up @@ -65,11 +90,13 @@ export class ModuleResolutionHost implements TS.ModuleSpecifierResolutionHost {
* Returns true if the given file exists
*/
fileExists(fileName: string): boolean {
// Check if the file exists cached
if (this.files.has(fileName)) return true;
if (this.fileExistsCache.has(fileName)) {
return this.fileExistsCache.get(fileName)!;
}

// Otherwise, check if it exists on disk
return this.getFileSystem().fileExists(nativeNormalize(fileName));
const exists = this.files.has(fileName) || this.getFileSystem().fileExists(nativeNormalize(fileName));
this.fileExistsCache.set(fileName, exists);
return exists;
}

/**
Expand All @@ -88,7 +115,13 @@ export class ModuleResolutionHost implements TS.ModuleSpecifierResolutionHost {
* Returns true if the given directory exists
*/
directoryExists(directoryName: string): boolean {
return this.getFileSystem().directoryExists(nativeNormalize(directoryName));
if (this.directoryExistsCache.has(directoryName)) {
return this.directoryExistsCache.get(directoryName)!;
}

const result = this.getFileNameDirectories().has(directoryName) || this.getFileSystem().directoryExists(nativeNormalize(directoryName));
this.directoryExistsCache.set(directoryName, result);
return result;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/util/chunk/normalize-chunk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export function normalizeChunk(
}
}

const visitableModules = chunk.modules.filter(module => host.isSupportedFileName(module));
const visitableModules = chunk.modules.filter(module => host.isSupportedFileName(module, true));
let entryModules = chunk.isEntry ? [visitableModules.slice(-1)[0]] : [...visitableModules].reverse();

return {
Expand Down
12 changes: 6 additions & 6 deletions src/util/file-system/file-system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ export interface FileSystem {
useCaseSensitiveFileNames: boolean;
fileExists(path: string): boolean;
readFile(path: string, encoding?: string): string | undefined;
ensureDirectory(path: string): string;
readDirectory(
path: string,
extensions?: ReadonlyArray<string>,
exclude?: ReadonlyArray<string>,
include?: ReadonlyArray<string>,
rootDir: string,
extensions: readonly string[],
excludes: readonly string[] | undefined,
includes: readonly string[],
depth?: number
): string[];
): readonly string[];
ensureDirectory(path: string): string;
realpath(path: string): string;
getDirectories(path: string): string[];
directoryExists(path: string): boolean;
Expand Down
36 changes: 36 additions & 0 deletions test/exclude.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import test from "ava";
import {formatCode} from "./util/format-code";
import {generateRollupBundle} from "./setup/setup-rollup";
// tslint:disable:no-duplicate-string

test("Is still capable of resolving SourceFiles when needed for when a file path is matched by the 'exclude' glob. #1", async t => {
const bundle = await generateRollupBundle(
[
{
entry: true,
fileName: "index.ts",
text: `\
export function foo (arg: Buffer): Buffer {
return arg;
}
`
}
],
{
debug: false,
exclude: ["node_modules/**/*.*"]
}
);
const {
declarations: [file]
} = bundle;

t.deepEqual(
formatCode(file.code),
formatCode(`\
/// <reference types="node" />
declare function foo(arg: Buffer): Buffer;
export { foo };
`)
);
});
40 changes: 40 additions & 0 deletions test/global-definition.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import test from "ava";
import {formatCode} from "./util/format-code";
import {generateRollupBundle} from "./setup/setup-rollup";
// tslint:disable:no-duplicate-string

test("Detects d.ts files when matched by a ParsedCommandLine. #1", async t => {
const bundle = await generateRollupBundle(
[
{
entry: true,
fileName: "index.ts",
text: `\
export const foo = globalFunc();
`
},
{
entry: false,
fileName: "typings/typings.d.ts",
text: `\
declare function globalFunc(): string;
`
}
],
{
debug: false,
exclude: ["node_modules/**/*.*"]
}
);
const {
declarations: [file]
} = bundle;

t.deepEqual(
formatCode(file.code),
formatCode(`\
declare const foo: string;
export {foo};
`)
);
});
16 changes: 15 additions & 1 deletion test/setup/setup-rollup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export interface GenerateRollupBundleOptions {
transpileOnly: boolean;
debug: TypescriptPluginOptions["debug"];
hook: Partial<HookRecord>;
exclude: TypescriptPluginOptions["exclude"];
transpiler: TypescriptPluginOptions["transpiler"];
transformers: TypescriptPluginOptions["transformers"];
}
Expand All @@ -51,6 +52,7 @@ export async function generateRollupBundle(
{
rollupOptions = {},
transformers,
exclude = [],
transpiler = "typescript",
tsconfig = {},
format = "esm",
Expand Down Expand Up @@ -150,7 +152,7 @@ export async function generateRollupBundle(
transpileOnly,
debug,
typescript,
exclude: ["dist/**/*.*"],
exclude: [...exclude, "dist/**/*.*"],
tsconfig: {
target: "esnext",
declaration: true,
Expand Down Expand Up @@ -184,6 +186,18 @@ export async function generateRollupBundle(
},
realpath(path: string): string {
return nativeNormalize(path);
},
readDirectory(
rootDir: string,
extensions: readonly string[],
excludes: readonly string[] | undefined,
includes: readonly string[],
depth?: number
): readonly string[] {
const nativeNormalizedRootDir = nativeNormalize(rootDir);
const realResult = typescript.sys.readDirectory(rootDir, extensions, excludes, includes, depth);
const virtualFiles = files.filter(file => file.fileName.includes(nativeNormalizedRootDir)).map(file => file.fileName);
return [...new Set([...realResult, ...virtualFiles])];
}
}
}),
Expand Down

0 comments on commit c54c1e6

Please sign in to comment.