From 6af69ad64eef7eba422cd0f958c156a0d041965f Mon Sep 17 00:00:00 2001 From: CSoellinger Date: Fri, 5 Jan 2018 02:53:35 +0100 Subject: [PATCH 1/3] Remove not necessary filename param from parse method --- README.md | 2 +- src/tsconfig.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ce8629b..6661a08 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ See the [TypeScript docs][tsconfig] for information on setting up `tsconfig.json * **loadSync(cwd: string, path?: string): { path?: string, config: any }** Synchronous `load`. * **readFile(filename: string): Promise** Read a JSON file as `tsconfig.json` (strip BOM, parse JSON and support empty contents). * **readFileSync(filename: string): any** Synchronous `readFile`. -* **parse(contents: string, filename: string): any** Parse file contents as `tsconfig.json` (strip BOM, parse JSON and support empty contents). +* **parse(contents: string): any** Parse file contents as `tsconfig.json` (strip BOM, parse JSON and support empty contents). ## Contributing diff --git a/src/tsconfig.ts b/src/tsconfig.ts index c80d8c1..7845284 100644 --- a/src/tsconfig.ts +++ b/src/tsconfig.ts @@ -164,7 +164,7 @@ export function readFile (filename: string): Promise { } try { - return resolve(parse(contents, filename)) + return resolve(parse(contents)) } catch (err) { return reject(err) } @@ -178,13 +178,13 @@ export function readFile (filename: string): Promise { export function readFileSync (filename: string): any { const contents = fs.readFileSync(filename, 'utf8') - return parse(contents, filename) + return parse(contents) } /** * Parse `tsconfig.json` file. */ -export function parse (contents: string, filename: string) { +export function parse (contents: string) { const data = stripComments(stripBom(contents)) // A tsconfig.json file is permitted to be completely empty. From 28fa0da24bfb33eec1182186a91c9d080e907808 Mon Sep 17 00:00:00 2001 From: CSoellinger Date: Fri, 5 Jan 2018 05:31:01 +0100 Subject: [PATCH 2/3] Extend tsconfig if "extends" property is present --- src/tsconfig.spec.ts | 21 +++++++++++++++ src/tsconfig.ts | 41 +++++++++++++++++++++++++++--- tests/extends/tsconfig-second.json | 14 ++++++++++ tests/extends/tsconfig-third.json | 6 +++++ tests/extends/tsconfig.json | 18 +++++++++++++ 5 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 tests/extends/tsconfig-second.json create mode 100644 tests/extends/tsconfig-third.json create mode 100644 tests/extends/tsconfig.json diff --git a/src/tsconfig.spec.ts b/src/tsconfig.spec.ts index 2444e24..188273c 100644 --- a/src/tsconfig.spec.ts +++ b/src/tsconfig.spec.ts @@ -95,6 +95,27 @@ describe('tsconfig', function () { } }, path: join(TEST_DIR, 'cwd/tsconfig.json') + }, + { + args: [TEST_DIR, 'extends/tsconfig-third.json'], + config: { + compilerOptions: { + module: 'commonjs', + noImplicitAny: true, + outDir: 'dist-third', + removeComments: true, + sourceMap: true, + preserveConstEnums: true, + rootDirs: [ + 'src', + 'test' + ] + }, + files: [ + './src/bar.ts' + ] + }, + path: join(TEST_DIR, 'extends/tsconfig-third.json') } ] diff --git a/src/tsconfig.ts b/src/tsconfig.ts index 7845284..997354c 100644 --- a/src/tsconfig.ts +++ b/src/tsconfig.ts @@ -158,16 +158,28 @@ export function loadSync (cwd: string, filename?: string): LoadResult { */ export function readFile (filename: string): Promise { return new Promise((resolve, reject) => { - fs.readFile(filename, 'utf8', (err, contents) => { + fs.readFile(filename, 'utf8', async (err, contents) => { if (err) { return reject(err) } + let obj try { - return resolve(parse(contents)) + obj = parse(contents) } catch (err) { return reject(err) } + + if (obj.extends !== undefined) { + const filepath = filename.replace(path.basename(filename), '') + const extendsFilename = resolveSync(filepath, obj.extends) as string + const extendsObj = await readFile(extendsFilename) + delete obj.extends + + obj = mergeObjects(extendsObj, obj) + } + + return resolve(obj) }) }) } @@ -177,8 +189,18 @@ export function readFile (filename: string): Promise { */ export function readFileSync (filename: string): any { const contents = fs.readFileSync(filename, 'utf8') + let obj = parse(contents) + + if (obj.extends !== undefined) { + const filepath = filename.replace(path.basename(filename), '') + const extendsFilename = resolveSync(filepath, obj.extends) as string + const extendsObj = readFileSync(extendsFilename) + delete obj.extends + + obj = mergeObjects(extendsObj, obj) + } - return parse(contents) + return obj } /** @@ -230,3 +252,16 @@ function isFile (stats: fs.Stats | void) { function isDirectory (stats: fs.Stats | void) { return stats ? (stats as fs.Stats).isDirectory() : false } + +/** + * Simple object merging + */ +function mergeObjects (target: any, source: any): any { + for (let key of Object.keys(source)) { + if (source[key] instanceof Object) { + Object.assign(source[key], mergeObjects(target[key], source[key])) + } + } + Object.assign(target || {}, source) + return target +} diff --git a/tests/extends/tsconfig-second.json b/tests/extends/tsconfig-second.json new file mode 100644 index 0000000..137140b --- /dev/null +++ b/tests/extends/tsconfig-second.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "dist-second", + "rootDirs": [ + "src", + "test" + ] + }, + "files": [ + "./src/bar.ts" + ] +} + diff --git a/tests/extends/tsconfig-third.json b/tests/extends/tsconfig-third.json new file mode 100644 index 0000000..32ab6dd --- /dev/null +++ b/tests/extends/tsconfig-third.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig-second.json", + "compilerOptions": { + "outDir": "dist-third" + } +} diff --git a/tests/extends/tsconfig.json b/tests/extends/tsconfig.json new file mode 100644 index 0000000..776b061 --- /dev/null +++ b/tests/extends/tsconfig.json @@ -0,0 +1,18 @@ +{ + // Compiler options. + "compilerOptions": { + "module": "commonjs", + "noImplicitAny": true, + "removeComments": true, + "preserveConstEnums": true, + "outDir": "dist", + "sourceMap": true, + "rootDirs": [ + "src" + ] + }, + // These are the files to compile with. + "files": [ + "./src/foo.ts" /* Use `foo.ts` */ + ] +} From 2bf19ab9b785178ff5c4787d6aeea1c0cbc4c956 Mon Sep 17 00:00:00 2001 From: CSoellinger Date: Fri, 5 Jan 2018 06:52:58 +0100 Subject: [PATCH 3/3] Remove async and await from readFile and using now readFileSync for extending. This is needed cause code coverage is collected from the compiled JS files and not from the TS ones. --- src/tsconfig.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tsconfig.ts b/src/tsconfig.ts index 997354c..8b578ad 100644 --- a/src/tsconfig.ts +++ b/src/tsconfig.ts @@ -158,7 +158,7 @@ export function loadSync (cwd: string, filename?: string): LoadResult { */ export function readFile (filename: string): Promise { return new Promise((resolve, reject) => { - fs.readFile(filename, 'utf8', async (err, contents) => { + fs.readFile(filename, 'utf8', (err, contents) => { if (err) { return reject(err) } @@ -173,7 +173,7 @@ export function readFile (filename: string): Promise { if (obj.extends !== undefined) { const filepath = filename.replace(path.basename(filename), '') const extendsFilename = resolveSync(filepath, obj.extends) as string - const extendsObj = await readFile(extendsFilename) + const extendsObj = readFileSync(extendsFilename) delete obj.extends obj = mergeObjects(extendsObj, obj) @@ -262,6 +262,6 @@ function mergeObjects (target: any, source: any): any { Object.assign(source[key], mergeObjects(target[key], source[key])) } } - Object.assign(target || {}, source) + Object.assign(target, source) return target }