tsconfig-paths
Advanced tools
Comparing version
@@ -10,2 +10,26 @@ # Change Log | ||
## [4.2.0] - 2023-03-29 | ||
### Added | ||
- Add support for tsconfig extends as array of strings. #. See PR [#245](https://github.com/dividab/tsconfig-paths/pull/245). Thanks to [@DanielSidhion](https://github.com/DanielSidhion) for this PR! | ||
## [3.14.2] - 2023-02-25 | ||
### Fixed | ||
- bump JSON5 from v1.0.1 to v1.0.2 in tsconfig-paths v3.14.1 to fix CVE-2022-46175 #234. See PR [#234](https://github.com/dividab/tsconfig-paths/pull/234). Thanks to [@mihaiplesa](https://github.com/mihaiplesa) for this PR! | ||
## [4.1.2] - 2023-01-02 | ||
### Fixed | ||
- Bump JSON5 dependency to 2.2.2 to fix CVE-2022-46175. See PR [#232](https://github.com/dividab/tsconfig-paths/pull/232). Thanks to [@oparisblue](https://github.com/oparisblue) for this PR! | ||
## [4.1.1] - 2022-11-30 | ||
### Fixed | ||
- Skip stat call / throwing an exception when source files don't exist. See PR [#225](https://github.com/dividab/tsconfig-paths/pull/225). Thanks to [@robstolarz](https://github.com/robstolarz) for this PR! | ||
## [4.1.0] - 2022-08-06 | ||
@@ -12,0 +36,0 @@ |
@@ -138,3 +138,3 @@ "use strict"; | ||
describe("loadConfig", function () { | ||
it("It should load a config", function () { | ||
it("should load a config", function () { | ||
var config = { compilerOptions: { baseUrl: "hej" } }; | ||
@@ -144,3 +144,3 @@ var res = (0, tsconfig_loader_1.loadTsconfig)("/root/dir1/tsconfig.json", function (path) { return path === "/root/dir1/tsconfig.json"; }, function (_) { return JSON.stringify(config); }); | ||
}); | ||
it("It should load a config with comments", function () { | ||
it("should load a config with comments", function () { | ||
var config = { compilerOptions: { baseUrl: "hej" } }; | ||
@@ -150,3 +150,3 @@ var res = (0, tsconfig_loader_1.loadTsconfig)("/root/dir1/tsconfig.json", function (path) { return path === "/root/dir1/tsconfig.json"; }, function (_) { return "{\n // my comment\n \"compilerOptions\": { \n \"baseUrl\": \"hej\"\n }\n }"; }); | ||
}); | ||
it("It should load a config with trailing commas", function () { | ||
it("should load a config with trailing commas", function () { | ||
var config = { compilerOptions: { baseUrl: "hej" } }; | ||
@@ -156,3 +156,3 @@ var res = (0, tsconfig_loader_1.loadTsconfig)("/root/dir1/tsconfig.json", function (path) { return path === "/root/dir1/tsconfig.json"; }, function (_) { return "{\n \"compilerOptions\": { \n \"baseUrl\": \"hej\",\n },\n }"; }); | ||
}); | ||
it("It should throw an error including the file path when encountering invalid JSON5", function () { | ||
it("should throw an error including the file path when encountering invalid JSON5", function () { | ||
expect(function () { | ||
@@ -162,3 +162,3 @@ return (0, tsconfig_loader_1.loadTsconfig)("/root/dir1/tsconfig.json", function (path) { return path === "/root/dir1/tsconfig.json"; }, function (_) { return "{\n \"compilerOptions\": {\n }"; }); | ||
}); | ||
it("It should load a config with extends and overwrite all options", function () { | ||
it("should load a config with string extends and overwrite all options", function () { | ||
var firstConfig = { | ||
@@ -195,3 +195,3 @@ extends: "../base-config.json", | ||
}); | ||
it("It should load a config with extends from node_modules and overwrite all options", function () { | ||
it("should load a config with string extends from node_modules and overwrite all options", function () { | ||
var firstConfig = { | ||
@@ -228,3 +228,3 @@ extends: "my-package/base-config.json", | ||
}); | ||
it("Should use baseUrl relative to location of extended tsconfig", function () { | ||
it("should use baseUrl relative to location of extended tsconfig", function () { | ||
var firstConfig = { compilerOptions: { baseUrl: "." } }; | ||
@@ -257,3 +257,80 @@ var firstConfigPath = (0, path_1.join)("/root", "first-config.json"); | ||
}); | ||
it("should load a config with array extends and overwrite all options", function () { | ||
var baseConfig1 = { | ||
compilerOptions: { baseUrl: ".", paths: { foo: ["bar"] } }, | ||
}; | ||
var baseConfig1Path = (0, path_1.join)("/root", "base-config-1.json"); | ||
var baseConfig2 = { compilerOptions: { baseUrl: "." } }; | ||
var baseConfig2Path = (0, path_1.join)("/root", "dir1", "base-config-2.json"); | ||
var baseConfig3 = { | ||
compilerOptions: { baseUrl: ".", paths: { foo: ["bar2"] } }, | ||
}; | ||
var baseConfig3Path = (0, path_1.join)("/root", "dir1", "dir2", "base-config-3.json"); | ||
var actualConfig = { | ||
extends: [ | ||
"./base-config-1.json", | ||
"./dir1/base-config-2.json", | ||
"./dir1/dir2/base-config-3.json", | ||
], | ||
}; | ||
var actualConfigPath = (0, path_1.join)("/root", "tsconfig.json"); | ||
var res = (0, tsconfig_loader_1.loadTsconfig)((0, path_1.join)("/root", "tsconfig.json"), function (path) { | ||
return [ | ||
baseConfig1Path, | ||
baseConfig2Path, | ||
baseConfig3Path, | ||
actualConfigPath, | ||
].indexOf(path) >= 0; | ||
}, function (path) { | ||
if (path === baseConfig1Path) { | ||
return JSON.stringify(baseConfig1); | ||
} | ||
if (path === baseConfig2Path) { | ||
return JSON.stringify(baseConfig2); | ||
} | ||
if (path === baseConfig3Path) { | ||
return JSON.stringify(baseConfig3); | ||
} | ||
if (path === actualConfigPath) { | ||
return JSON.stringify(actualConfig); | ||
} | ||
return ""; | ||
}); | ||
expect(res).toEqual({ | ||
extends: [ | ||
"./base-config-1.json", | ||
"./dir1/base-config-2.json", | ||
"./dir1/dir2/base-config-3.json", | ||
], | ||
compilerOptions: { | ||
baseUrl: (0, path_1.join)("dir1", "dir2"), | ||
paths: { foo: ["bar2"] }, | ||
}, | ||
}); | ||
}); | ||
it("should load a config with array extends without .json extension", function () { | ||
var baseConfig = { | ||
compilerOptions: { baseUrl: ".", paths: { foo: ["bar"] } }, | ||
}; | ||
var baseConfigPath = (0, path_1.join)("/root", "base-config-1.json"); | ||
var actualConfig = { extends: ["./base-config-1"] }; | ||
var actualConfigPath = (0, path_1.join)("/root", "tsconfig.json"); | ||
var res = (0, tsconfig_loader_1.loadTsconfig)((0, path_1.join)("/root", "tsconfig.json"), function (path) { return [baseConfigPath, actualConfigPath].indexOf(path) >= 0; }, function (path) { | ||
if (path === baseConfigPath) { | ||
return JSON.stringify(baseConfig); | ||
} | ||
if (path === actualConfigPath) { | ||
return JSON.stringify(actualConfig); | ||
} | ||
return ""; | ||
}); | ||
expect(res).toEqual({ | ||
extends: ["./base-config-1"], | ||
compilerOptions: { | ||
baseUrl: ".", | ||
paths: { foo: ["bar"] }, | ||
}, | ||
}); | ||
}); | ||
}); | ||
//# sourceMappingURL=tsconfig-loader.test.js.map |
@@ -6,2 +6,6 @@ "use strict"; | ||
function fileExistsSync(path) { | ||
// If the file doesn't exist, avoid throwing an exception over the native barrier for every miss | ||
if (!fs.existsSync(path)) { | ||
return false; | ||
} | ||
try { | ||
@@ -8,0 +12,0 @@ var stats = fs.statSync(path); |
@@ -5,3 +5,3 @@ /** | ||
export interface Tsconfig { | ||
extends?: string; | ||
extends?: string | string[]; | ||
compilerOptions?: { | ||
@@ -8,0 +8,0 @@ baseUrl?: string; |
@@ -101,21 +101,12 @@ "use strict"; | ||
if (extendedConfig) { | ||
if (typeof extendedConfig === "string" && | ||
extendedConfig.indexOf(".json") === -1) { | ||
extendedConfig += ".json"; | ||
var base = void 0; | ||
if (Array.isArray(extendedConfig)) { | ||
base = extendedConfig.reduce(function (currBase, extendedConfigElement) { | ||
return mergeTsconfigs(currBase, loadTsconfigFromExtends(configFilePath, extendedConfigElement, existsSync, readFileSync)); | ||
}, {}); | ||
} | ||
var currentDir = path.dirname(configFilePath); | ||
var extendedConfigPath = path.join(currentDir, extendedConfig); | ||
if (extendedConfig.indexOf("/") !== -1 && | ||
extendedConfig.indexOf(".") !== -1 && | ||
!existsSync(extendedConfigPath)) { | ||
extendedConfigPath = path.join(currentDir, "node_modules", extendedConfig); | ||
else { | ||
base = loadTsconfigFromExtends(configFilePath, extendedConfig, existsSync, readFileSync); | ||
} | ||
var base = loadTsconfig(extendedConfigPath, existsSync, readFileSync) || {}; | ||
// baseUrl should be interpreted as relative to the base tsconfig, | ||
// but we need to update it so it is relative to the original tsconfig being loaded | ||
if (base.compilerOptions && base.compilerOptions.baseUrl) { | ||
var extendsDir = path.dirname(extendedConfig); | ||
base.compilerOptions.baseUrl = path.join(extendsDir, base.compilerOptions.baseUrl); | ||
} | ||
return __assign(__assign(__assign({}, base), config), { compilerOptions: __assign(__assign({}, base.compilerOptions), config.compilerOptions) }); | ||
return mergeTsconfigs(base, config); | ||
} | ||
@@ -125,2 +116,35 @@ return config; | ||
exports.loadTsconfig = loadTsconfig; | ||
/** | ||
* Intended to be called only from loadTsconfig. | ||
* Parameters don't have defaults because they should use the same as loadTsconfig. | ||
*/ | ||
function loadTsconfigFromExtends(configFilePath, extendedConfigValue, | ||
// eslint-disable-next-line no-shadow | ||
existsSync, readFileSync) { | ||
var _a; | ||
if (typeof extendedConfigValue === "string" && | ||
extendedConfigValue.indexOf(".json") === -1) { | ||
extendedConfigValue += ".json"; | ||
} | ||
var currentDir = path.dirname(configFilePath); | ||
var extendedConfigPath = path.join(currentDir, extendedConfigValue); | ||
if (extendedConfigValue.indexOf("/") !== -1 && | ||
extendedConfigValue.indexOf(".") !== -1 && | ||
!existsSync(extendedConfigPath)) { | ||
extendedConfigPath = path.join(currentDir, "node_modules", extendedConfigValue); | ||
} | ||
var config = loadTsconfig(extendedConfigPath, existsSync, readFileSync) || {}; | ||
// baseUrl should be interpreted as relative to extendedConfigPath, | ||
// but we need to update it so it is relative to the original tsconfig being loaded | ||
if ((_a = config.compilerOptions) === null || _a === void 0 ? void 0 : _a.baseUrl) { | ||
var extendsDir = path.dirname(extendedConfigValue); | ||
config.compilerOptions.baseUrl = path.join(extendsDir, config.compilerOptions.baseUrl); | ||
} | ||
return config; | ||
} | ||
function mergeTsconfigs(base, config) { | ||
base = base || {}; | ||
config = config || {}; | ||
return __assign(__assign(__assign({}, base), config), { compilerOptions: __assign(__assign({}, base.compilerOptions), config.compilerOptions) }); | ||
} | ||
//# sourceMappingURL=tsconfig-loader.js.map |
{ | ||
"name": "tsconfig-paths", | ||
"version": "4.1.0", | ||
"version": "4.2.0", | ||
"description": "Load node modules according to tsconfig paths, in run-time or via API.", | ||
@@ -44,3 +44,3 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"json5": "^2.2.1", | ||
"json5": "^2.2.2", | ||
"minimist": "^1.2.6", | ||
@@ -47,0 +47,0 @@ "strip-bom": "^3.0.0" |
@@ -171,3 +171,3 @@ import { | ||
describe("loadConfig", () => { | ||
it("It should load a config", () => { | ||
it("should load a config", () => { | ||
const config = { compilerOptions: { baseUrl: "hej" } }; | ||
@@ -182,3 +182,3 @@ const res = loadTsconfig( | ||
it("It should load a config with comments", () => { | ||
it("should load a config with comments", () => { | ||
const config = { compilerOptions: { baseUrl: "hej" } }; | ||
@@ -198,3 +198,3 @@ const res = loadTsconfig( | ||
it("It should load a config with trailing commas", () => { | ||
it("should load a config with trailing commas", () => { | ||
const config = { compilerOptions: { baseUrl: "hej" } }; | ||
@@ -213,3 +213,3 @@ const res = loadTsconfig( | ||
it("It should throw an error including the file path when encountering invalid JSON5", () => { | ||
it("should throw an error including the file path when encountering invalid JSON5", () => { | ||
expect(() => | ||
@@ -228,3 +228,3 @@ loadTsconfig( | ||
it("It should load a config with extends and overwrite all options", () => { | ||
it("should load a config with string extends and overwrite all options", () => { | ||
const firstConfig = { | ||
@@ -267,3 +267,3 @@ extends: "../base-config.json", | ||
it("It should load a config with extends from node_modules and overwrite all options", () => { | ||
it("should load a config with string extends from node_modules and overwrite all options", () => { | ||
const firstConfig = { | ||
@@ -312,3 +312,3 @@ extends: "my-package/base-config.json", | ||
it("Should use baseUrl relative to location of extended tsconfig", () => { | ||
it("should use baseUrl relative to location of extended tsconfig", () => { | ||
const firstConfig = { compilerOptions: { baseUrl: "." } }; | ||
@@ -345,2 +345,92 @@ const firstConfigPath = join("/root", "first-config.json"); | ||
}); | ||
it("should load a config with array extends and overwrite all options", () => { | ||
const baseConfig1 = { | ||
compilerOptions: { baseUrl: ".", paths: { foo: ["bar"] } }, | ||
}; | ||
const baseConfig1Path = join("/root", "base-config-1.json"); | ||
const baseConfig2 = { compilerOptions: { baseUrl: "." } }; | ||
const baseConfig2Path = join("/root", "dir1", "base-config-2.json"); | ||
const baseConfig3 = { | ||
compilerOptions: { baseUrl: ".", paths: { foo: ["bar2"] } }, | ||
}; | ||
const baseConfig3Path = join("/root", "dir1", "dir2", "base-config-3.json"); | ||
const actualConfig = { | ||
extends: [ | ||
"./base-config-1.json", | ||
"./dir1/base-config-2.json", | ||
"./dir1/dir2/base-config-3.json", | ||
], | ||
}; | ||
const actualConfigPath = join("/root", "tsconfig.json"); | ||
const res = loadTsconfig( | ||
join("/root", "tsconfig.json"), | ||
(path) => | ||
[ | ||
baseConfig1Path, | ||
baseConfig2Path, | ||
baseConfig3Path, | ||
actualConfigPath, | ||
].indexOf(path) >= 0, | ||
(path) => { | ||
if (path === baseConfig1Path) { | ||
return JSON.stringify(baseConfig1); | ||
} | ||
if (path === baseConfig2Path) { | ||
return JSON.stringify(baseConfig2); | ||
} | ||
if (path === baseConfig3Path) { | ||
return JSON.stringify(baseConfig3); | ||
} | ||
if (path === actualConfigPath) { | ||
return JSON.stringify(actualConfig); | ||
} | ||
return ""; | ||
} | ||
); | ||
expect(res).toEqual({ | ||
extends: [ | ||
"./base-config-1.json", | ||
"./dir1/base-config-2.json", | ||
"./dir1/dir2/base-config-3.json", | ||
], | ||
compilerOptions: { | ||
baseUrl: join("dir1", "dir2"), | ||
paths: { foo: ["bar2"] }, | ||
}, | ||
}); | ||
}); | ||
it("should load a config with array extends without .json extension", () => { | ||
const baseConfig = { | ||
compilerOptions: { baseUrl: ".", paths: { foo: ["bar"] } }, | ||
}; | ||
const baseConfigPath = join("/root", "base-config-1.json"); | ||
const actualConfig = { extends: ["./base-config-1"] }; | ||
const actualConfigPath = join("/root", "tsconfig.json"); | ||
const res = loadTsconfig( | ||
join("/root", "tsconfig.json"), | ||
(path) => [baseConfigPath, actualConfigPath].indexOf(path) >= 0, | ||
(path) => { | ||
if (path === baseConfigPath) { | ||
return JSON.stringify(baseConfig); | ||
} | ||
if (path === actualConfigPath) { | ||
return JSON.stringify(actualConfig); | ||
} | ||
return ""; | ||
} | ||
); | ||
expect(res).toEqual({ | ||
extends: ["./base-config-1"], | ||
compilerOptions: { | ||
baseUrl: ".", | ||
paths: { foo: ["bar"] }, | ||
}, | ||
}); | ||
}); | ||
}); |
@@ -36,2 +36,6 @@ import * as fs from "fs"; | ||
export function fileExistsSync(path: string): boolean { | ||
// If the file doesn't exist, avoid throwing an exception over the native barrier for every miss | ||
if (!fs.existsSync(path)) { | ||
return false; | ||
} | ||
try { | ||
@@ -38,0 +42,0 @@ const stats = fs.statSync(path); |
@@ -12,3 +12,3 @@ import * as path from "path"; | ||
export interface Tsconfig { | ||
extends?: string; | ||
extends?: string | string[]; | ||
compilerOptions?: { | ||
@@ -135,48 +135,97 @@ baseUrl?: string; | ||
} | ||
let extendedConfig = config.extends; | ||
if (extendedConfig) { | ||
let base: Tsconfig; | ||
if (extendedConfig) { | ||
if ( | ||
typeof extendedConfig === "string" && | ||
extendedConfig.indexOf(".json") === -1 | ||
) { | ||
extendedConfig += ".json"; | ||
} | ||
const currentDir = path.dirname(configFilePath); | ||
let extendedConfigPath = path.join(currentDir, extendedConfig); | ||
if ( | ||
extendedConfig.indexOf("/") !== -1 && | ||
extendedConfig.indexOf(".") !== -1 && | ||
!existsSync(extendedConfigPath) | ||
) { | ||
extendedConfigPath = path.join( | ||
currentDir, | ||
"node_modules", | ||
extendedConfig | ||
if (Array.isArray(extendedConfig)) { | ||
base = extendedConfig.reduce( | ||
(currBase, extendedConfigElement) => | ||
mergeTsconfigs( | ||
currBase, | ||
loadTsconfigFromExtends( | ||
configFilePath, | ||
extendedConfigElement, | ||
existsSync, | ||
readFileSync | ||
) | ||
), | ||
{} | ||
); | ||
} else { | ||
base = loadTsconfigFromExtends( | ||
configFilePath, | ||
extendedConfig, | ||
existsSync, | ||
readFileSync | ||
); | ||
} | ||
const base = | ||
loadTsconfig(extendedConfigPath, existsSync, readFileSync) || {}; | ||
return mergeTsconfigs(base, config); | ||
} | ||
return config; | ||
} | ||
// baseUrl should be interpreted as relative to the base tsconfig, | ||
// but we need to update it so it is relative to the original tsconfig being loaded | ||
if (base.compilerOptions && base.compilerOptions.baseUrl) { | ||
const extendsDir = path.dirname(extendedConfig); | ||
base.compilerOptions.baseUrl = path.join( | ||
extendsDir, | ||
base.compilerOptions.baseUrl | ||
); | ||
} | ||
/** | ||
* Intended to be called only from loadTsconfig. | ||
* Parameters don't have defaults because they should use the same as loadTsconfig. | ||
*/ | ||
function loadTsconfigFromExtends( | ||
configFilePath: string, | ||
extendedConfigValue: string, | ||
// eslint-disable-next-line no-shadow | ||
existsSync: (path: string) => boolean, | ||
readFileSync: (filename: string) => string | ||
): Tsconfig { | ||
if ( | ||
typeof extendedConfigValue === "string" && | ||
extendedConfigValue.indexOf(".json") === -1 | ||
) { | ||
extendedConfigValue += ".json"; | ||
} | ||
const currentDir = path.dirname(configFilePath); | ||
let extendedConfigPath = path.join(currentDir, extendedConfigValue); | ||
if ( | ||
extendedConfigValue.indexOf("/") !== -1 && | ||
extendedConfigValue.indexOf(".") !== -1 && | ||
!existsSync(extendedConfigPath) | ||
) { | ||
extendedConfigPath = path.join( | ||
currentDir, | ||
"node_modules", | ||
extendedConfigValue | ||
); | ||
} | ||
return { | ||
...base, | ||
...config, | ||
compilerOptions: { | ||
...base.compilerOptions, | ||
...config.compilerOptions, | ||
}, | ||
}; | ||
const config = | ||
loadTsconfig(extendedConfigPath, existsSync, readFileSync) || {}; | ||
// baseUrl should be interpreted as relative to extendedConfigPath, | ||
// but we need to update it so it is relative to the original tsconfig being loaded | ||
if (config.compilerOptions?.baseUrl) { | ||
const extendsDir = path.dirname(extendedConfigValue); | ||
config.compilerOptions.baseUrl = path.join( | ||
extendsDir, | ||
config.compilerOptions.baseUrl | ||
); | ||
} | ||
return config; | ||
} | ||
function mergeTsconfigs( | ||
base: Tsconfig | undefined, | ||
config: Tsconfig | undefined | ||
): Tsconfig { | ||
base = base || {}; | ||
config = config || {}; | ||
return { | ||
...base, | ||
...config, | ||
compilerOptions: { | ||
...base.compilerOptions, | ||
...config.compilerOptions, | ||
}, | ||
}; | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
216221
6.06%3818
6.62%Updated