@visulima/tsconfig
Version:
Find and/or parse the tsconfig.json file from a directory path.
471 lines (463 loc) • 19.9 kB
JavaScript
;
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
const fs = require('@visulima/fs');
const error = require('@visulima/fs/error');
const path = require('@visulima/path');
const utils = require('@visulima/path/utils');
const jsoncParser = require('jsonc-parser');
const node_fs = require('node:fs');
const Module = require('node:module');
const resolvePkgMaps = require('resolve-pkg-maps');
const _interopDefaultCompat = e => e && typeof e === 'object' && 'default' in e ? e.default : e;
const Module__default = /*#__PURE__*/_interopDefaultCompat(Module);
var __defProp$1 = Object.defineProperty;
var __name$1 = (target, value) => __defProp$1(target, "name", { value, configurable: true });
const readJsonc$1 = /* @__PURE__ */ __name$1((jsonPath) => jsoncParser.parse(fs.readFileSync(jsonPath, { buffer: false })), "readJsonc");
const getPnpApi = /* @__PURE__ */ __name$1(() => {
const { findPnpApi } = Module__default;
return findPnpApi?.(process.cwd());
}, "getPnpApi");
const resolveFromPackageJsonPath = /* @__PURE__ */ __name$1((packageJsonPath, subpath, ignoreExports, cache) => {
const cacheKey = "resolveFromPackageJsonPath:" + packageJsonPath + ":" + subpath + ":" + (ignoreExports ? "yes" : "no");
if (cache?.has(cacheKey)) {
return cache.get(cacheKey);
}
const packageJson = readJsonc$1(packageJsonPath);
if (!packageJson) {
return void 0;
}
let resolvedPath = subpath || "tsconfig.json";
if (!ignoreExports && packageJson.exports) {
try {
const [resolvedExport] = resolvePkgMaps.resolveExports(packageJson.exports, subpath, ["require", "types"]);
resolvedPath = resolvedExport;
} catch {
return false;
}
} else if (!subpath && packageJson.tsconfig) {
resolvedPath = packageJson.tsconfig;
}
resolvedPath = path.join(packageJsonPath, "..", resolvedPath);
cache?.set(cacheKey, resolvedPath);
return resolvedPath;
}, "resolveFromPackageJsonPath");
const PACKAGE_JSON = "package.json";
const TS_CONFIG_JSON = "tsconfig.json";
const resolveExtendsPath = /* @__PURE__ */ __name$1((requestedPath, directoryPath, cache) => {
let filePath = requestedPath;
if (requestedPath === "..") {
filePath = path.join(filePath, TS_CONFIG_JSON);
}
if (requestedPath.startsWith(".")) {
filePath = path.resolve(directoryPath, filePath);
}
if (path.isAbsolute(filePath)) {
if (fs.isAccessibleSync(filePath)) {
if (node_fs.statSync(filePath).isFile()) {
return filePath;
}
} else if (!filePath.endsWith(".json")) {
const jsonPath = `${filePath}.json`;
if (fs.isAccessibleSync(jsonPath)) {
return jsonPath;
}
}
return void 0;
}
const [orgOrName, ...remaining] = requestedPath.split("/");
const packageName = orgOrName.startsWith("@") ? orgOrName + "/" + remaining.shift() : orgOrName;
const subpath = remaining.join("/");
const pnpApi = getPnpApi();
if (pnpApi) {
const { resolveRequest: resolveWithPnp } = pnpApi;
try {
if (packageName === requestedPath) {
const packageJsonPath2 = resolveWithPnp(path.join(packageName, PACKAGE_JSON), directoryPath);
if (packageJsonPath2) {
const resolvedPath = resolveFromPackageJsonPath(packageJsonPath2, subpath, false, cache);
if (resolvedPath && fs.isAccessibleSync(resolvedPath)) {
return resolvedPath;
}
}
} else {
let resolved;
try {
resolved = resolveWithPnp(requestedPath, directoryPath, { extensions: [".json"] });
} catch {
resolved = resolveWithPnp(path.join(requestedPath, TS_CONFIG_JSON), directoryPath);
}
if (resolved) {
return resolved;
}
}
} catch {
}
}
const packagePath = fs.findUpSync(
(directory) => {
const path$1 = path.join(path.resolve(directory), "node_modules", packageName);
if (fs.isAccessibleSync(path$1)) {
return path.join("node_modules", packageName);
}
return void 0;
},
{
cwd: directoryPath,
type: "directory"
}
);
if (!packagePath || !node_fs.statSync(packagePath).isDirectory()) {
return void 0;
}
const packageJsonPath = path.join(packagePath, PACKAGE_JSON);
if (fs.isAccessibleSync(packageJsonPath)) {
const resolvedPath = resolveFromPackageJsonPath(packageJsonPath, subpath, false, cache);
if (resolvedPath === false) {
return void 0;
}
if (resolvedPath && fs.isAccessibleSync(resolvedPath) && node_fs.statSync(resolvedPath).isFile()) {
return resolvedPath;
}
}
const fullPackagePath = path.join(packagePath, subpath);
const jsonExtension = fullPackagePath.endsWith(".json");
if (!jsonExtension) {
const fullPackagePathWithJson = fullPackagePath + ".json";
if (fs.isAccessibleSync(fullPackagePathWithJson)) {
return fullPackagePathWithJson;
}
}
if (!fs.isAccessibleSync(fullPackagePath)) {
return void 0;
}
if (node_fs.statSync(fullPackagePath).isDirectory()) {
const fullPackageJsonPath = path.join(fullPackagePath, PACKAGE_JSON);
if (fs.isAccessibleSync(fullPackageJsonPath)) {
const resolvedPath = resolveFromPackageJsonPath(fullPackageJsonPath, "", true, cache);
if (resolvedPath && fs.isAccessibleSync(resolvedPath)) {
return resolvedPath;
}
}
const tsconfigPath = path.join(fullPackagePath, TS_CONFIG_JSON);
if (fs.isAccessibleSync(tsconfigPath)) {
return tsconfigPath;
}
} else if (jsonExtension) {
return fullPackagePath;
}
return void 0;
}, "resolveExtendsPath");
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
const readJsonc = /* @__PURE__ */ __name((jsonPath) => jsoncParser.parse(fs.readFileSync(jsonPath, { buffer: false })), "readJsonc");
const normalizePath = /* @__PURE__ */ __name((path$1) => {
const namespacedPath = path.toNamespacedPath(path$1);
return utils.isRelative(namespacedPath) ? namespacedPath : "./" + namespacedPath;
}, "normalizePath");
const filesProperties = ["files", "include", "exclude"];
const resolveExtends = /* @__PURE__ */ __name((resolvedExtendsPath, fromDirectoryPath, circularExtendsTracker, options) => {
if (circularExtendsTracker.has(resolvedExtendsPath)) {
throw new Error(`Circularity detected while resolving configuration: ${resolvedExtendsPath}`);
}
circularExtendsTracker.add(resolvedExtendsPath);
const extendsDirectoryPath = path.dirname(resolvedExtendsPath);
const extendsConfig = internalParseTsConfig(resolvedExtendsPath, options, circularExtendsTracker);
delete extendsConfig.references;
const { compilerOptions } = extendsConfig;
if (compilerOptions) {
const { baseUrl } = compilerOptions;
if (baseUrl && !baseUrl.startsWith(configDirectoryPlaceholder)) {
compilerOptions.baseUrl = path.normalize(path.relative(fromDirectoryPath, path.join(extendsDirectoryPath, baseUrl))) || "./";
}
let { outDir } = compilerOptions;
if (outDir) {
if (!outDir.startsWith(configDirectoryPlaceholder)) {
outDir = path.relative(fromDirectoryPath, path.join(extendsDirectoryPath, outDir));
}
compilerOptions.outDir = normalizePath(outDir.replace(configDirectoryPlaceholder + "/", "")) || "./";
}
}
for (const property of filesProperties) {
const filesList = extendsConfig[property];
if (filesList) {
extendsConfig[property] = filesList.map((file) => {
if (file.startsWith(configDirectoryPlaceholder)) {
return file;
}
if (path.isAbsolute(file)) {
return file;
}
return path.relative(fromDirectoryPath, path.join(extendsDirectoryPath, file));
});
}
}
return extendsConfig;
}, "resolveExtends");
const internalParseTsConfig = /* @__PURE__ */ __name((tsconfigPath, options, circularExtendsTracker = /* @__PURE__ */ new Set()) => {
let config;
try {
config = readJsonc(tsconfigPath) || {};
} catch {
throw new Error(`Cannot resolve tsconfig at path: ${tsconfigPath}`);
}
if (typeof config !== "object") {
throw new SyntaxError(`Failed to parse tsconfig at: ${tsconfigPath}`);
}
const directoryPath = path.dirname(tsconfigPath);
if (config.compilerOptions) {
const { compilerOptions } = config;
if (compilerOptions.paths && !compilerOptions.baseUrl) {
compilerOptions[implicitBaseUrlSymbol] = directoryPath;
}
}
if (config.extends) {
const extendsPathList = Array.isArray(config.extends) ? config.extends : [config.extends];
delete config.extends;
for (const extendsPath of extendsPathList.reverse()) {
const resolvedExtendsPath = resolveExtendsPath(extendsPath, directoryPath);
if (!resolvedExtendsPath) {
throw new error.NotFoundError("No such file or directory, for '" + extendsPath + "' found.");
}
const extendsConfig = resolveExtends(resolvedExtendsPath, directoryPath, new Set(circularExtendsTracker), options);
if (extendsConfig.compilerOptions?.rootDir !== void 0 && !extendsConfig.compilerOptions.rootDir.startsWith(configDirectoryPlaceholder)) {
extendsConfig.compilerOptions.rootDir = path.join(path.dirname(resolvedExtendsPath), extendsConfig.compilerOptions.rootDir);
}
const merged = {
...extendsConfig,
...config,
compilerOptions: {
...extendsConfig.compilerOptions,
...config.compilerOptions
}
};
if (extendsConfig.watchOptions) {
merged.watchOptions = {
...extendsConfig.watchOptions,
...config.watchOptions
};
}
config = merged;
}
}
if (config.compilerOptions) {
const { compilerOptions } = config;
for (const property of ["baseUrl", "rootDir"]) {
const unresolvedPath = compilerOptions[property];
if (unresolvedPath && !unresolvedPath.startsWith(configDirectoryPlaceholder)) {
const resolvedBaseUrl = path.resolve(directoryPath, unresolvedPath);
compilerOptions[property] = normalizePath(path.relative(directoryPath, resolvedBaseUrl));
}
}
for (const outputField of ["outDir", "declarationDir"]) {
let outputPath = compilerOptions[outputField];
if (outputPath) {
if (!Array.isArray(config.exclude)) {
config.exclude = [];
}
let excludePath = outputPath;
if (!path.isAbsolute(excludePath)) {
excludePath = path.join(directoryPath, excludePath);
}
excludePath = excludePath.replace(configDirectoryPlaceholder, "");
if (!config.exclude.includes(excludePath)) {
config.exclude.push(excludePath);
}
if (!outputPath.startsWith(configDirectoryPlaceholder)) {
outputPath = normalizePath(outputPath);
}
compilerOptions[outputField] = outputPath;
}
}
} else {
config.compilerOptions = {};
}
if (config.include) {
config.include = config.include.map((element) => path.normalize(element));
if (config.files) {
delete config.files;
}
} else if (config.files) {
config.files = config.files.map((file) => file.startsWith(configDirectoryPlaceholder) ? file : normalizePath(file));
}
if (config.watchOptions) {
const { watchOptions } = config;
if (watchOptions.excludeDirectories) {
watchOptions.excludeDirectories = watchOptions.excludeDirectories.map((excludePath) => path.resolve(directoryPath, excludePath));
}
}
if (config.compilerOptions?.lib) {
config.compilerOptions.lib = config.compilerOptions.lib.map((library) => library.toLowerCase());
}
if (config.compilerOptions.module) {
config.compilerOptions.module = config.compilerOptions.module.toLowerCase();
}
if (config.compilerOptions.target) {
config.compilerOptions.target = config.compilerOptions.target.toLowerCase();
}
return config;
}, "internalParseTsConfig");
const interpolateConfigDirectory = /* @__PURE__ */ __name((filePath, configDirectory) => {
if (filePath.startsWith(configDirectoryPlaceholder)) {
return path.normalize(path.join(configDirectory, filePath.slice(configDirectoryPlaceholder.length)));
}
return void 0;
}, "interpolateConfigDirectory");
const compilerFieldsWithConfigDirectory = ["outDir", "declarationDir", "outFile", "rootDir", "baseUrl", "tsBuildInfoFile"];
const tsCompatibleWrapper = /* @__PURE__ */ __name((config, options) => {
if (config.compilerOptions === void 0) {
return config;
}
if (["5.4", "5.5", "5.6", "5.7", "5.8", "true"].includes(String(options?.tscCompatible))) {
if (config.compilerOptions.esModuleInterop === void 0 && (config.compilerOptions.module === "node16" || config.compilerOptions.module === "nodenext" || config.compilerOptions.module === "preserve")) {
config.compilerOptions.esModuleInterop = true;
}
if ((config.compilerOptions.esModuleInterop || config.compilerOptions.module === "system" || config.compilerOptions.moduleResolution === "bundler") && config.compilerOptions.allowSyntheticDefaultImports === void 0) {
config.compilerOptions.allowSyntheticDefaultImports = true;
}
if (config?.compilerOptions.moduleDetection === void 0 && config.compilerOptions.module && ["node16", "nodenext"].includes(config.compilerOptions.module)) {
config.compilerOptions.moduleDetection = "force";
}
if (config.compilerOptions.moduleResolution === void 0) {
let moduleResolution = "classic";
if (config.compilerOptions.module !== void 0) {
switch ((config.compilerOptions?.module).toLocaleLowerCase()) {
case "commonjs": {
moduleResolution = "node10";
break;
}
case "node16": {
moduleResolution = "node16";
break;
}
case "nodenext": {
moduleResolution = "nodenext";
break;
}
case "preserve": {
moduleResolution = "bundler";
break;
}
}
}
if (moduleResolution !== "classic") {
config.compilerOptions.moduleResolution = moduleResolution;
}
}
if (["5.7", "5.8", "true"].includes(String(options?.tscCompatible)) && config.compilerOptions.moduleResolution) {
let resolvePackageJson = false;
if (["bundler", "node16", "nodenext"].includes(config.compilerOptions.moduleResolution.toLocaleLowerCase())) {
resolvePackageJson = true;
}
if (config.compilerOptions.resolvePackageJsonExports === void 0 && resolvePackageJson) {
config.compilerOptions.resolvePackageJsonExports = true;
}
if (config.compilerOptions.resolvePackageJsonImports === void 0 && resolvePackageJson) {
config.compilerOptions.resolvePackageJsonImports = true;
}
}
if (config.compilerOptions.target === void 0) {
let target = "es5";
if (config.compilerOptions.module === "node16") {
target = "es2022";
} else if (config.compilerOptions.module === "nodenext") {
target = "esnext";
}
if (target !== "es5") {
config.compilerOptions.target = target;
}
}
if (config.compilerOptions.useDefineForClassFields === void 0 && config.compilerOptions.target && (config.compilerOptions.target.includes("es202") || config.compilerOptions.target === "esnext")) {
config.compilerOptions.useDefineForClassFields = true;
}
}
if (["5.6", "5.7", "5.8", "true"].includes(String(options?.tscCompatible)) && config.compilerOptions.strict && config.compilerOptions.strictBuiltinIteratorReturn === void 0) {
config.compilerOptions.strictBuiltinIteratorReturn = true;
}
if (["5.4", "5.5", "5.6", "5.7", "5.8", "true"].includes(String(options?.tscCompatible))) {
if (config.compilerOptions.strict) {
config.compilerOptions.noImplicitAny = config.compilerOptions.noImplicitAny ?? true;
config.compilerOptions.noImplicitThis = config.compilerOptions.noImplicitThis ?? true;
config.compilerOptions.strictNullChecks = config.compilerOptions.strictNullChecks ?? true;
config.compilerOptions.strictFunctionTypes = config.compilerOptions.strictFunctionTypes ?? true;
config.compilerOptions.strictBindCallApply = config.compilerOptions.strictBindCallApply ?? true;
config.compilerOptions.strictPropertyInitialization = config.compilerOptions.strictPropertyInitialization ?? true;
config.compilerOptions.alwaysStrict = config.compilerOptions.alwaysStrict ?? true;
}
if (config.compilerOptions.useDefineForClassFields === void 0 && config.compilerOptions.target) {
let useDefineForClassFields = false;
if (config.compilerOptions.target.includes("es202") || config.compilerOptions.target === "esnext") {
useDefineForClassFields = true;
}
if (useDefineForClassFields) {
config.compilerOptions.useDefineForClassFields = true;
}
}
if (config.compilerOptions.strict && config.compilerOptions.useUnknownInCatchVariables === void 0) {
config.compilerOptions.useUnknownInCatchVariables = true;
}
if (config.compilerOptions.isolatedModules) {
config.compilerOptions.preserveConstEnums = config.compilerOptions.preserveConstEnums ?? true;
}
}
if (config.compileOnSave === false) {
delete config.compileOnSave;
}
return config;
}, "tsCompatibleWrapper");
const configDirectoryPlaceholder = "${configDir}";
const implicitBaseUrlSymbol = Symbol("implicitBaseUrl");
const readTsConfig = /* @__PURE__ */ __name((tsconfigPath, options) => {
const resolvedTsconfigPath = path.resolve(tsconfigPath);
const config = internalParseTsConfig(resolvedTsconfigPath, options);
const configDirectory = path.dirname(resolvedTsconfigPath);
const { compilerOptions } = config;
if (compilerOptions) {
for (const property of compilerFieldsWithConfigDirectory) {
const value = compilerOptions[property];
if (value) {
const resolvedPath = interpolateConfigDirectory(value, configDirectory);
compilerOptions[property] = resolvedPath ? normalizePath(path.relative(configDirectory, resolvedPath)) : value;
}
}
for (const property of ["rootDirs", "typeRoots"]) {
const value = compilerOptions[property];
if (value) {
compilerOptions[property] = value.map((v) => {
const resolvedPath = interpolateConfigDirectory(v, configDirectory);
return resolvedPath ? normalizePath(path.relative(configDirectory, resolvedPath)) : v;
});
}
}
const { paths } = compilerOptions;
if (paths) {
for (const name of Object.keys(paths)) {
paths[name] = paths[name].map((filePath) => interpolateConfigDirectory(filePath, configDirectory) ?? filePath);
}
}
if (compilerOptions.outDir) {
compilerOptions.outDir = compilerOptions.outDir.replace(configDirectoryPlaceholder, "");
}
}
for (const property of filesProperties) {
const value = config[property];
if (value) {
config[property] = value.map((filePath) => {
const interpolate = interpolateConfigDirectory(filePath, configDirectory);
if (interpolate) {
return interpolate;
}
if (property === "files" && utils.isRelative(filePath)) {
return filePath;
}
if (property === "include" && utils.isRelative(filePath)) {
return path.join(configDirectory, filePath);
}
return path.normalize(filePath);
});
}
}
return tsCompatibleWrapper(config, options);
}, "readTsConfig");
exports.configDirectoryPlaceholder = configDirectoryPlaceholder;
exports.implicitBaseUrlSymbol = implicitBaseUrlSymbol;
exports.readTsConfig = readTsConfig;