Skip to content

Commit

Permalink
Remove tsconfig dependency and add support for tsconfig extends
Browse files Browse the repository at this point in the history
  • Loading branch information
Jontem authored Nov 18, 2017
1 parent 4373939 commit dc0acda
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 30 deletions.
25 changes: 15 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
{
"name": "tsconfig-paths",
"version": "2.3.0",
"description":
"Load node modules according to tsconfig paths, in run-time or via API.",
"description": "Load node modules according to tsconfig paths, in run-time or via API.",
"main": "lib/index.js",
"author": "Jonas Kello",
"license": "MIT",
"repository": "https://github.com/dividab/tsconfig-paths",
"devDependencies": {
"@types/chai": "^3.4.34",
"@types/deepmerge": "^1.3.2",
"@types/mocha": "^2.2.35",
"@types/node": "^6.0.54",
"@types/strip-bom": "^3.0.0",
"@types/strip-json-comments": "^0.0.30",
"chai": "^3.5.0",
"codecov": "^2.1.0",
"husky": "^0.14.3",
Expand All @@ -24,26 +26,29 @@
},
"scripts": {
"start": "cd src && ts-node index.ts",
"start:example:node":
"yarn tsc && cd example/node && ts-node -r ../register.js main.ts",
"start:example:node": "yarn tsc && cd example/node && ts-node -r ../register.js main.ts",
"start:example:api": "cd example/api && ts-node main.ts",
"tsc": "tsc -P src",
"tsc:tests": "tsc -P tests",
"test:unit": "mocha --compilers ts:ts-node/register \"tests/**/*.ts\"",
"test":
"nyc --include src/**/*.ts -e '.ts' -r html -r lcov -r text yarn test:unit",
"report-coverage":
"nyc report --reporter=text-lcov > coverage.lcov && codecov",
"test": "nyc --include src/**/*.ts -e '.ts' -r html -r lcov -r text yarn test:unit",
"report-coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov",
"build": "rm -rf lib && tsc -P src",
"precommit": "lint-staged",
"publish:major": "yarn run build && node scripts/publish.js major",
"publish:minor": "yarn run build && node scripts/publish.js minor",
"publish:patch": "yarn run build && node scripts/publish.js patch"
},
"lint-staged": {
"*.ts": ["tslint", "prettier --write", "git add"]
"*.ts": [
"tslint",
"prettier --write",
"git add"
]
},
"dependencies": {
"tsconfig": "^5.0.3"
"deepmerge": "^2.0.1",
"strip-bom": "^3.0.0",
"strip-json-comments": "^2.0.1"
}
}
86 changes: 81 additions & 5 deletions src/tsconfig-loader.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import * as Tsconfig from "tsconfig";
import * as path from "path";
import * as fs from "fs";
import * as deepmerge from "deepmerge";
import * as StripJsonComments from "strip-json-comments";
import StripBom = require("strip-bom");

export interface TsConfigLoaderResult {
tsConfigPath: string | undefined;
Expand Down Expand Up @@ -26,11 +30,83 @@ export function tsConfigLoader({

function loadSyncDefault(cwd: string, filename?: string): TsConfigLoaderResult {
// Tsconfig.loadSync uses path.resolve. This is why we can use an absolute path as filename
const loadResult = Tsconfig.loadSync(cwd, filename);

const configPath = resolveConfigPath(cwd, filename);

if (!configPath) {
return {
tsConfigPath: undefined,
baseUrl: undefined,
paths: undefined
};
}
const config = loadConfig(configPath);

return {
tsConfigPath: loadResult.path,
baseUrl: loadResult.config.compilerOptions.baseUrl,
paths: loadResult.config.compilerOptions.paths
tsConfigPath: configPath,
baseUrl: config && config.compilerOptions && config.compilerOptions.baseUrl,
paths: config && config.compilerOptions && config.compilerOptions.paths
};
}

export function resolveConfigPath(
cwd: string,
filename?: string
): string | undefined {
if (filename) {
const absolutePath = fs.lstatSync(filename).isDirectory()
? path.resolve(filename, "./tsconfig.json")
: path.resolve(cwd, filename);

return absolutePath;
}

return walkForTsConfig(cwd);
}

export function walkForTsConfig(
directory: string,
existsSync: (path: string) => boolean = fs.existsSync
): string | undefined {
const configPath = path.resolve(directory, "./tsconfig.json");
if (existsSync(configPath)) {
return configPath;
}

const parentDirectory = path.resolve(directory, "../");

This comment has been minimized.

Copy link
@aleclarson

aleclarson Apr 16, 2022

Contributor

Hi @Jontem, do you remember if using path.resolve instead of path.dirname was important here? I think they both do the same thing in this instance, yes?

This comment has been minimized.

Copy link
@Jontem

Jontem Apr 19, 2022

Author Collaborator

Hi, I'm not sure I understand what you mean? path.dirname takes a directory name from a path? In this case we just try to resolve the parent directory path.

This comment has been minimized.

Copy link
@aleclarson

aleclarson Apr 19, 2022

Contributor

Ah okay, I see the difference now. Thank you!


// If we reached the top
if (directory === parentDirectory) {
return undefined;
}

return walkForTsConfig(parentDirectory, existsSync);
}

export function loadConfig(
configFilePath: string,
existsSync: (path: string) => boolean = fs.existsSync,
readFileSync: (filename: string) => string = (filename: string) =>
fs.readFileSync(filename, "utf8")
): { [key: string]: any } | undefined {
if (!existsSync(configFilePath)) {
return undefined;
}

const configString = readFileSync(configFilePath);
const cleanedJson = StripBom(StripJsonComments(configString));
const config = JSON.parse(cleanedJson);

if (config.extends) {
const currentDir = path.dirname(configFilePath);
const base =
loadConfig(
path.resolve(currentDir, config.extends),
existsSync,
readFileSync
) || {};

return deepmerge(base, config);
}
return config;
}
86 changes: 85 additions & 1 deletion tests/tsconfig-loader-tests.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { assert } from "chai";
import { tsConfigLoader } from "../src/tsconfig-loader";
import {
loadConfig,
tsConfigLoader,
walkForTsConfig
} from "../src/tsconfig-loader";

describe("tsconfig-loader", function() {
it("should find tsconfig in cwd", () => {
Expand Down Expand Up @@ -59,3 +63,83 @@ describe("tsconfig-loader", function() {
assert.equal(result.tsConfigPath, "/foo/baz/tsconfig.json");
});
});

describe("walkForTsConfig", function() {
it("should find tsconfig in starting directory", () => {
const res = walkForTsConfig(
"/root/dir1",
path => path === "/root/dir1/tsconfig.json"
);
assert.equal(res, "/root/dir1/tsconfig.json");
});

it("should find tsconfig in parent directory", () => {
const res = walkForTsConfig(
"/root/dir1",
path => path === "/root/tsconfig.json"
);
assert.equal(res, "/root/tsconfig.json");
});

it("should return undefined when reaching the top", () => {
const res = walkForTsConfig("/root/dir1/kalle", () => false);
assert.equal(res, undefined);
});
});

describe("loadConfig", function() {
it("It should load a config", () => {
const config = { kalle: "hej" };
const res = loadConfig(
"/root/dir1/tsconfig.json",
path => path === "/root/dir1/tsconfig.json",
_ => JSON.stringify(config)
);
assert.deepEqual(res, config);
});

it("It should load a config with comments", () => {
const config = { kalle: "hej" };
const res = loadConfig(
"/root/dir1/tsconfig.json",
path => path === "/root/dir1/tsconfig.json",
_ => `{
// my comment
"kalle": "hej"
}`
);
assert.deepEqual(res, config);
});

it("It should load a config with extends", () => {
const firstConfig = { extends: "../base-config.json", kalle: "hej" };
const baseConfig = { compilerOptions: { baseUrl: "." } };
const res = loadConfig(
"/root/dir1/tsconfig.json",
path => {
if (path === "/root/dir1/tsconfig.json") {
return true;
}

if (path === "/root/base-config.json") {
return true;
}

return false;
},
path => {
if (path === "/root/dir1/tsconfig.json") {
return JSON.stringify(firstConfig);
}

if (path === "/root/base-config.json") {
return JSON.stringify(baseConfig);
}

return "";
}
);

assert.deepEqual(res, { ...baseConfig, ...firstConfig });
});
});
31 changes: 17 additions & 14 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
version "3.4.34"
resolved "https://registry.yarnpkg.com/@types/chai/-/chai-3.4.34.tgz#d5335792823bb09cddd5e38c3d211b709183854d"

"@types/deepmerge@^1.3.2":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@types/deepmerge/-/deepmerge-1.3.2.tgz#a87837384624d63e8c3df3ae85693d574ea6b5db"

"@types/mocha@^2.2.35":
version "2.2.35"
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.35.tgz#dd3150b62a6de73368109308515c3aa86f81f1ec"
Expand All @@ -14,6 +18,14 @@
version "6.0.54"
resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.54.tgz#65859962ba988052cbdd5c48881395acfdd46931"

"@types/strip-bom@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/strip-bom/-/strip-bom-3.0.0.tgz#14a8ec3956c2e81edb7520790aecf21c290aebd2"

"@types/strip-json-comments@^0.0.30":
version "0.0.30"
resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1"

align-text@^0.1.1, align-text@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
Expand Down Expand Up @@ -48,10 +60,6 @@ ansi-styles@^3.1.0, ansi-styles@^3.2.0:
dependencies:
color-convert "^1.9.0"

any-promise@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"

app-root-path@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.0.1.tgz#cd62dcf8e4fd5a417efc664d2e5b10653c651b46"
Expand Down Expand Up @@ -455,6 +463,10 @@ deep-eql@^0.1.3:
dependencies:
type-detect "0.1.1"

deepmerge@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.0.1.tgz#25c1c24f110fb914f80001b925264dd77f3f4312"

default-require-extensions@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8"
Expand Down Expand Up @@ -1829,7 +1841,7 @@ strip-indent@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68"

strip-json-comments@^2.0.0:
strip-json-comments@^2.0.0, strip-json-comments@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"

Expand Down Expand Up @@ -1892,15 +1904,6 @@ ts-node@^3.1.0:
v8flags "^2.0.11"
yn "^2.0.0"

tsconfig@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-5.0.3.tgz#5f4278e701800967a8fc383fd19648878f2a6e3a"
dependencies:
any-promise "^1.3.0"
parse-json "^2.2.0"
strip-bom "^2.0.0"
strip-json-comments "^2.0.0"

tsconfig@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-6.0.0.tgz#6b0e8376003d7af1864f8df8f89dd0059ffcd032"
Expand Down

0 comments on commit dc0acda

Please sign in to comment.