Merge pull request #27844 from Microsoft/includeJson
Allow files to be included by `*.json` pattern in include of tsconfig
This commit is contained in:
commit
99b271853a
|
@ -2509,11 +2509,16 @@ namespace ts {
|
|||
// via wildcard, and to handle extension priority.
|
||||
const wildcardFileMap = createMap<string>();
|
||||
|
||||
// Wildcard paths of json files (provided via the "includes" array in tsconfig.json) are stored in a
|
||||
// file map with a possibly case insensitive key. We use this map to store paths matched
|
||||
// via wildcard of *.json kind
|
||||
const wildCardJsonFileMap = createMap<string>();
|
||||
const { filesSpecs, validatedIncludeSpecs, validatedExcludeSpecs, wildcardDirectories } = spec;
|
||||
|
||||
// Rather than requery this for each file and filespec, we query the supported extensions
|
||||
// once and store it on the expansion context.
|
||||
const supportedExtensions = getSupportedExtensions(options, extraFileExtensions);
|
||||
const supportedExtensionsWithJsonIfResolveJsonModule = getSuppoertedExtensionsWithJsonIfResolveJsonModule(options, supportedExtensions);
|
||||
|
||||
// Literal files are always included verbatim. An "include" or "exclude" specification cannot
|
||||
// remove a literal file.
|
||||
|
@ -2524,8 +2529,25 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
let jsonOnlyIncludeRegexes: ReadonlyArray<RegExp> | undefined;
|
||||
if (validatedIncludeSpecs && validatedIncludeSpecs.length > 0) {
|
||||
for (const file of host.readDirectory(basePath, supportedExtensions, validatedExcludeSpecs, validatedIncludeSpecs, /*depth*/ undefined)) {
|
||||
for (const file of host.readDirectory(basePath, supportedExtensionsWithJsonIfResolveJsonModule, validatedExcludeSpecs, validatedIncludeSpecs, /*depth*/ undefined)) {
|
||||
if (fileExtensionIs(file, Extension.Json)) {
|
||||
// Valid only if *.json specified
|
||||
if (!jsonOnlyIncludeRegexes) {
|
||||
const includes = validatedIncludeSpecs.filter(s => endsWith(s, Extension.Json));
|
||||
const includeFilePatterns = map(getRegularExpressionsForWildcards(includes, basePath, "files"), pattern => `^${pattern}$`);
|
||||
jsonOnlyIncludeRegexes = includeFilePatterns ? includeFilePatterns.map(pattern => getRegexFromPattern(pattern, host.useCaseSensitiveFileNames)) : emptyArray;
|
||||
}
|
||||
const includeIndex = findIndex(jsonOnlyIncludeRegexes, re => re.test(file));
|
||||
if (includeIndex !== -1) {
|
||||
const key = keyMapper(file);
|
||||
if (!literalFileMap.has(key) && !wildCardJsonFileMap.has(key)) {
|
||||
wildCardJsonFileMap.set(key, file);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// If we have already included a literal or wildcard path with a
|
||||
// higher priority extension, we should skip this file.
|
||||
//
|
||||
|
@ -2553,7 +2575,7 @@ namespace ts {
|
|||
const wildcardFiles = arrayFrom(wildcardFileMap.values());
|
||||
|
||||
return {
|
||||
fileNames: literalFiles.concat(wildcardFiles),
|
||||
fileNames: literalFiles.concat(wildcardFiles, arrayFrom(wildCardJsonFileMap.values())),
|
||||
wildcardDirectories,
|
||||
spec
|
||||
};
|
||||
|
|
|
@ -610,7 +610,7 @@ namespace ts {
|
|||
const programDiagnostics = createDiagnosticCollection();
|
||||
const currentDirectory = host.getCurrentDirectory();
|
||||
const supportedExtensions = getSupportedExtensions(options);
|
||||
const supportedExtensionsWithJsonIfResolveJsonModule = options.resolveJsonModule ? [...supportedExtensions, Extension.Json] : undefined;
|
||||
const supportedExtensionsWithJsonIfResolveJsonModule = getSuppoertedExtensionsWithJsonIfResolveJsonModule(options, supportedExtensions);
|
||||
|
||||
// Map storing if there is emit blocking diagnostics for given input
|
||||
const hasEmitBlockingDiagnostics = createMap<boolean>();
|
||||
|
@ -1965,7 +1965,7 @@ namespace ts {
|
|||
refFile?: SourceFile): SourceFile | undefined {
|
||||
|
||||
if (hasExtension(fileName)) {
|
||||
if (!options.allowNonTsExtensions && !forEach(supportedExtensionsWithJsonIfResolveJsonModule || supportedExtensions, extension => fileExtensionIs(host.getCanonicalFileName(fileName), extension))) {
|
||||
if (!options.allowNonTsExtensions && !forEach(supportedExtensionsWithJsonIfResolveJsonModule, extension => fileExtensionIs(host.getCanonicalFileName(fileName), extension))) {
|
||||
if (fail) fail(Diagnostics.File_0_has_unsupported_extension_The_only_supported_extensions_are_1, fileName, "'" + supportedExtensions.join("', '") + "'");
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -7738,7 +7738,7 @@ namespace ts {
|
|||
return `^(${pattern})${terminator}`;
|
||||
}
|
||||
|
||||
function getRegularExpressionsForWildcards(specs: ReadonlyArray<string> | undefined, basePath: string, usage: "files" | "directories" | "exclude"): string[] | undefined {
|
||||
export function getRegularExpressionsForWildcards(specs: ReadonlyArray<string> | undefined, basePath: string, usage: "files" | "directories" | "exclude"): string[] | undefined {
|
||||
if (specs === undefined || specs.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -8003,11 +8003,13 @@ namespace ts {
|
|||
* List of supported extensions in order of file resolution precedence.
|
||||
*/
|
||||
export const supportedTSExtensions: ReadonlyArray<Extension> = [Extension.Ts, Extension.Tsx, Extension.Dts];
|
||||
export const supportedTSExtensionsWithJson: ReadonlyArray<Extension> = [Extension.Ts, Extension.Tsx, Extension.Dts, Extension.Json];
|
||||
/** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */
|
||||
export const supportedTSExtensionsForExtractExtension: ReadonlyArray<Extension> = [Extension.Dts, Extension.Ts, Extension.Tsx];
|
||||
export const supportedJSExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx];
|
||||
export const supportedJSAndJsonExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx, Extension.Json];
|
||||
const allSupportedExtensions: ReadonlyArray<Extension> = [...supportedTSExtensions, ...supportedJSExtensions];
|
||||
const allSupportedExtensionsWithJson: ReadonlyArray<Extension> = [...supportedTSExtensions, ...supportedJSExtensions, Extension.Json];
|
||||
|
||||
export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: ReadonlyArray<FileExtensionInfo>): ReadonlyArray<string> {
|
||||
const needJsExtensions = options && options.allowJs;
|
||||
|
@ -8024,6 +8026,13 @@ namespace ts {
|
|||
return deduplicate<string>(extensions, equateStringsCaseSensitive, compareStringsCaseSensitive);
|
||||
}
|
||||
|
||||
export function getSuppoertedExtensionsWithJsonIfResolveJsonModule(options: CompilerOptions | undefined, supportedExtensions: ReadonlyArray<string>): ReadonlyArray<string> {
|
||||
if (!options || !options.resolveJsonModule) { return supportedExtensions; }
|
||||
if (supportedExtensions === allSupportedExtensions) { return allSupportedExtensionsWithJson; }
|
||||
if (supportedExtensions === supportedTSExtensions) { return supportedTSExtensionsWithJson; }
|
||||
return [...supportedExtensions, Extension.Json];
|
||||
}
|
||||
|
||||
function isJSLike(scriptKind: ScriptKind | undefined): boolean {
|
||||
return scriptKind === ScriptKind.JS || scriptKind === ScriptKind.JSX;
|
||||
}
|
||||
|
@ -8043,7 +8052,8 @@ namespace ts {
|
|||
export function isSupportedSourceFileName(fileName: string, compilerOptions?: CompilerOptions, extraFileExtensions?: ReadonlyArray<FileExtensionInfo>) {
|
||||
if (!fileName) { return false; }
|
||||
|
||||
for (const extension of getSupportedExtensions(compilerOptions, extraFileExtensions)) {
|
||||
const supportedExtensions = getSupportedExtensions(compilerOptions, extraFileExtensions);
|
||||
for (const extension of getSuppoertedExtensionsWithJsonIfResolveJsonModule(compilerOptions, supportedExtensions)) {
|
||||
if (fileExtensionIs(fileName, extension)) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -276,6 +276,10 @@ export class cNew {}`);
|
|||
|
||||
function verifyProjectWithResolveJsonModule(configFile: string, ...expectedDiagnosticMessages: DiagnosticMessage[]) {
|
||||
const fs = projFs.shadow();
|
||||
verifyProjectWithResolveJsonModuleWithFs(fs, configFile, allExpectedOutputs, ...expectedDiagnosticMessages);
|
||||
}
|
||||
|
||||
function verifyProjectWithResolveJsonModuleWithFs(fs: vfs.FileSystem, configFile: string, allExpectedOutputs: ReadonlyArray<string>, ...expectedDiagnosticMessages: DiagnosticMessage[]) {
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, [configFile], { dry: false, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
|
@ -292,6 +296,21 @@ export class cNew {}`);
|
|||
verifyProjectWithResolveJsonModule("/src/tests/tsconfig_withInclude.json", Diagnostics.File_0_is_not_in_project_file_list_Projects_must_list_all_files_or_use_an_include_pattern);
|
||||
});
|
||||
|
||||
it("with resolveJsonModule and include of *.json along with other include", () => {
|
||||
verifyProjectWithResolveJsonModule("/src/tests/tsconfig_withIncludeOfJson.json");
|
||||
});
|
||||
|
||||
it("with resolveJsonModule and include of *.json along with other include and file name matches ts file", () => {
|
||||
const fs = projFs.shadow();
|
||||
fs.rimrafSync("/src/tests/src/hello.json");
|
||||
fs.writeFileSync("/src/tests/src/index.json", JSON.stringify({ hello: "world" }));
|
||||
fs.writeFileSync("/src/tests/src/index.ts", `import hello from "./index.json"
|
||||
|
||||
export default hello.hello`);
|
||||
const allExpectedOutputs = ["/src/tests/dist/src/index.js", "/src/tests/dist/src/index.d.ts", "/src/tests/dist/src/index.json"];
|
||||
verifyProjectWithResolveJsonModuleWithFs(fs, "/src/tests/tsconfig_withIncludeOfJson.json", allExpectedOutputs);
|
||||
});
|
||||
|
||||
it("with resolveJsonModule and files containing json file", () => {
|
||||
verifyProjectWithResolveJsonModule("/src/tests/tsconfig_withFiles.json");
|
||||
});
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"target": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"module": "commonjs",
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"outDir": "dist",
|
||||
"skipDefaultLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*", "src/**/*.json"
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue