From 453f669bf90aaf4d9e9cf9421d8142f08e7044cd Mon Sep 17 00:00:00 2001 From: David Sherret Date: Thu, 4 Jan 2018 21:25:02 -0500 Subject: [PATCH 1/2] Expose ts.matchFiles as public API (#13793) --- src/compiler/core.ts | 128 +++++++++++++++++++++---------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index eb0696a1869e1..8d26c9ac043ab 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -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; + readonly directories: ReadonlyArray; + } + + export function matchFiles(path: string, extensions: ReadonlyArray, excludes: ReadonlyArray, includes: ReadonlyArray, 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(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 */ @@ -2454,11 +2518,6 @@ namespace ts { return match === "*" ? singleAsteriskRegexFragment : match === "?" ? "[^/]" : "\\" + match; } - export interface FileSystemEntries { - readonly files: ReadonlyArray; - readonly directories: ReadonlyArray; - } - export interface FileMatcherPatterns { /** One pattern for each "include" spec. */ includeFilePatterns: ReadonlyArray; @@ -2483,65 +2542,6 @@ namespace ts { }; } - export function matchFiles(path: string, extensions: ReadonlyArray, excludes: ReadonlyArray, includes: ReadonlyArray, 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(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. */ From 09494becc4d8911b842639c656b1fb554727aa3c Mon Sep 17 00:00:00 2001 From: David Sherret Date: Thu, 4 Jan 2018 22:17:31 -0500 Subject: [PATCH 2/2] Update declaration files for ts.matchFiles (#13793) --- tests/baselines/reference/api/tsserverlibrary.d.ts | 5 +++++ tests/baselines/reference/api/typescript.d.ts | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 6d7a69d350f20..c7f7d936d1239 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2704,6 +2704,11 @@ declare namespace ts { } declare namespace ts { function isExternalModuleNameRelative(moduleName: string): boolean; + interface FileSystemEntries { + readonly files: ReadonlyArray; + readonly directories: ReadonlyArray; + } + function matchFiles(path: string, extensions: ReadonlyArray, excludes: ReadonlyArray, includes: ReadonlyArray, 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; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 4e9f13be2cee3..eb340deab0794 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2704,6 +2704,11 @@ declare namespace ts { } declare namespace ts { function isExternalModuleNameRelative(moduleName: string): boolean; + interface FileSystemEntries { + readonly files: ReadonlyArray; + readonly directories: ReadonlyArray; + } + function matchFiles(path: string, extensions: ReadonlyArray, excludes: ReadonlyArray, includes: ReadonlyArray, 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;