Skip to content

Commit

Permalink
Expose ts.matchFiles as public API (microsoft#13793)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret committed Jan 5, 2018
1 parent 4eb633e commit 024f2a2
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 64 deletions.
128 changes: 64 additions & 64 deletions src/compiler/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,70 @@ namespace ts {
// Update: We also consider a path like `C:\foo.ts` "relative" because we do not search for it in `node_modules` or treat it as an ambient module.
return pathIsRelative(moduleName) || isRootedDiskPath(moduleName);
}

export interface FileSystemEntries {
readonly files: ReadonlyArray<string>;
readonly directories: ReadonlyArray<string>;
}

export function matchFiles(path: string, extensions: ReadonlyArray<string>, excludes: ReadonlyArray<string>, includes: ReadonlyArray<string>, useCaseSensitiveFileNames: boolean, currentDirectory: string, depth: number | undefined, getFileSystemEntries: (path: string) => FileSystemEntries): string[] {
path = normalizePath(path);
currentDirectory = normalizePath(currentDirectory);

const comparer = useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive;
const patterns = getFileMatcherPatterns(path, excludes, includes, useCaseSensitiveFileNames, currentDirectory);

const regexFlag = useCaseSensitiveFileNames ? "" : "i";
const includeFileRegexes = patterns.includeFilePatterns && patterns.includeFilePatterns.map(pattern => new RegExp(pattern, regexFlag));
const includeDirectoryRegex = patterns.includeDirectoryPattern && new RegExp(patterns.includeDirectoryPattern, regexFlag);
const excludeRegex = patterns.excludePattern && new RegExp(patterns.excludePattern, regexFlag);

// Associate an array of results with each include regex. This keeps results in order of the "include" order.
// If there are no "includes", then just put everything in results[0].
const results: string[][] = includeFileRegexes ? includeFileRegexes.map(() => []) : [[]];

for (const basePath of patterns.basePaths) {
visitDirectory(basePath, combinePaths(currentDirectory, basePath), depth);
}

return flatten<string>(results);

function visitDirectory(path: string, absolutePath: string, depth: number | undefined) {
const { files, directories } = getFileSystemEntries(path);

for (const current of sort(files, comparer)) {
const name = combinePaths(path, current);
const absoluteName = combinePaths(absolutePath, current);
if (extensions && !fileExtensionIsOneOf(name, extensions)) continue;
if (excludeRegex && excludeRegex.test(absoluteName)) continue;
if (!includeFileRegexes) {
results[0].push(name);
}
else {
const includeIndex = findIndex(includeFileRegexes, re => re.test(absoluteName));
if (includeIndex !== -1) {
results[includeIndex].push(name);
}
}
}

if (depth !== undefined) {
depth--;
if (depth === 0) {
return;
}
}

for (const current of sort(directories, comparer)) {
const name = combinePaths(path, current);
const absoluteName = combinePaths(absolutePath, current);
if ((!includeDirectoryRegex || includeDirectoryRegex.test(absoluteName)) &&
(!excludeRegex || !excludeRegex.test(absoluteName))) {
visitDirectory(name, absoluteName, depth);
}
}
}
}
}

/* @internal */
Expand Down Expand Up @@ -2454,11 +2518,6 @@ namespace ts {
return match === "*" ? singleAsteriskRegexFragment : match === "?" ? "[^/]" : "\\" + match;
}

export interface FileSystemEntries {
readonly files: ReadonlyArray<string>;
readonly directories: ReadonlyArray<string>;
}

export interface FileMatcherPatterns {
/** One pattern for each "include" spec. */
includeFilePatterns: ReadonlyArray<string>;
Expand All @@ -2483,65 +2542,6 @@ namespace ts {
};
}

export function matchFiles(path: string, extensions: ReadonlyArray<string>, excludes: ReadonlyArray<string>, includes: ReadonlyArray<string>, useCaseSensitiveFileNames: boolean, currentDirectory: string, depth: number | undefined, getFileSystemEntries: (path: string) => FileSystemEntries): string[] {
path = normalizePath(path);
currentDirectory = normalizePath(currentDirectory);

const comparer = useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive;
const patterns = getFileMatcherPatterns(path, excludes, includes, useCaseSensitiveFileNames, currentDirectory);

const regexFlag = useCaseSensitiveFileNames ? "" : "i";
const includeFileRegexes = patterns.includeFilePatterns && patterns.includeFilePatterns.map(pattern => new RegExp(pattern, regexFlag));
const includeDirectoryRegex = patterns.includeDirectoryPattern && new RegExp(patterns.includeDirectoryPattern, regexFlag);
const excludeRegex = patterns.excludePattern && new RegExp(patterns.excludePattern, regexFlag);

// Associate an array of results with each include regex. This keeps results in order of the "include" order.
// If there are no "includes", then just put everything in results[0].
const results: string[][] = includeFileRegexes ? includeFileRegexes.map(() => []) : [[]];

for (const basePath of patterns.basePaths) {
visitDirectory(basePath, combinePaths(currentDirectory, basePath), depth);
}

return flatten<string>(results);

function visitDirectory(path: string, absolutePath: string, depth: number | undefined) {
const { files, directories } = getFileSystemEntries(path);

for (const current of sort(files, comparer)) {
const name = combinePaths(path, current);
const absoluteName = combinePaths(absolutePath, current);
if (extensions && !fileExtensionIsOneOf(name, extensions)) continue;
if (excludeRegex && excludeRegex.test(absoluteName)) continue;
if (!includeFileRegexes) {
results[0].push(name);
}
else {
const includeIndex = findIndex(includeFileRegexes, re => re.test(absoluteName));
if (includeIndex !== -1) {
results[includeIndex].push(name);
}
}
}

if (depth !== undefined) {
depth--;
if (depth === 0) {
return;
}
}

for (const current of sort(directories, comparer)) {
const name = combinePaths(path, current);
const absoluteName = combinePaths(absolutePath, current);
if ((!includeDirectoryRegex || includeDirectoryRegex.test(absoluteName)) &&
(!excludeRegex || !excludeRegex.test(absoluteName))) {
visitDirectory(name, absoluteName, depth);
}
}
}
}

/**
* Computes the unique non-wildcard base paths amongst the provided include patterns.
*/
Expand Down
5 changes: 5 additions & 0 deletions tests/baselines/reference/api/tsserverlibrary.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2704,6 +2704,11 @@ declare namespace ts {
}
declare namespace ts {
function isExternalModuleNameRelative(moduleName: string): boolean;
interface FileSystemEntries {
readonly files: ReadonlyArray<string>;
readonly directories: ReadonlyArray<string>;
}
function matchFiles(path: string, extensions: ReadonlyArray<string>, excludes: ReadonlyArray<string>, includes: ReadonlyArray<string>, useCaseSensitiveFileNames: boolean, currentDirectory: string, depth: number | undefined, getFileSystemEntries: (path: string) => FileSystemEntries): string[];
}
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
declare function clearTimeout(handle: any): void;
Expand Down
5 changes: 5 additions & 0 deletions tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2704,6 +2704,11 @@ declare namespace ts {
}
declare namespace ts {
function isExternalModuleNameRelative(moduleName: string): boolean;
interface FileSystemEntries {
readonly files: ReadonlyArray<string>;
readonly directories: ReadonlyArray<string>;
}
function matchFiles(path: string, extensions: ReadonlyArray<string>, excludes: ReadonlyArray<string>, includes: ReadonlyArray<string>, useCaseSensitiveFileNames: boolean, currentDirectory: string, depth: number | undefined, getFileSystemEntries: (path: string) => FileSystemEntries): string[];
}
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
declare function clearTimeout(handle: any): void;
Expand Down

0 comments on commit 024f2a2

Please sign in to comment.