From ac5c077df36b95085bdf437230dd47aeecc5d96c Mon Sep 17 00:00:00 2001 From: Perryvw Date: Mon, 1 May 2023 21:01:35 +0200 Subject: [PATCH 1/3] Correctly merge tstl options from extended tsconfig --- src/cli/tsconfig.ts | 56 ++++++++++++++++++- test/cli/tsconfig.spec.ts | 19 ++++++- test/cli/tsconfig/tsconfig-cycle1.json | 6 ++ test/cli/tsconfig/tsconfig-cycle2.json | 6 ++ test/cli/tsconfig/tsconfig.base.json | 6 ++ test/cli/tsconfig/tsconfig.json | 6 ++ test/cli/tsconfig/tsconfig.multi-extends.json | 6 ++ test/cli/tsconfig/tsconfig2.json | 5 ++ 8 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 test/cli/tsconfig/tsconfig-cycle1.json create mode 100644 test/cli/tsconfig/tsconfig-cycle2.json create mode 100644 test/cli/tsconfig/tsconfig.base.json create mode 100644 test/cli/tsconfig/tsconfig.json create mode 100644 test/cli/tsconfig/tsconfig.multi-extends.json create mode 100644 test/cli/tsconfig/tsconfig2.json diff --git a/src/cli/tsconfig.ts b/src/cli/tsconfig.ts index bc6fb5ae9..2a483b492 100644 --- a/src/cli/tsconfig.ts +++ b/src/cli/tsconfig.ts @@ -1,6 +1,6 @@ import * as path from "path"; import * as ts from "typescript"; -import { CompilerOptions } from "../CompilerOptions"; +import { CompilerOptions, TypeScriptToLuaOptions } from "../CompilerOptions"; import { normalizeSlashes } from "../utils"; import * as cliDiagnostics from "./diagnostics"; import { ParsedCommandLine, updateParsedConfigFile } from "./parse"; @@ -41,17 +41,69 @@ export function parseConfigFileWithSystem( commandLineOptions?: CompilerOptions, system = ts.sys ): ParsedCommandLine { + const configRootDir = path.dirname(configFileName); const parsedConfigFile = ts.parseJsonSourceFileConfigFileContent( ts.readJsonConfigFile(configFileName, system.readFile), system, - path.dirname(configFileName), + configRootDir, commandLineOptions, configFileName ); + const cycleCache = new Set(); + const extendedTstlOptions = getExtendedTstlOptions(configFileName, configRootDir, cycleCache, system); + + parsedConfigFile.raw.tstl = Object.assign(extendedTstlOptions, parsedConfigFile.raw.tstl ?? {}); + return updateParsedConfigFile(parsedConfigFile); } +function getExtendedTstlOptions( + configFilePath: string, + configRootDir: string, + cycleCache: Set, + system: ts.System +): TypeScriptToLuaOptions { + const absolutePath = path.isAbsolute(configFilePath) ? configFilePath : path.resolve(configRootDir, configFilePath); + const newConfigRoot = path.dirname(absolutePath); + + if (cycleCache.has(absolutePath)) { + return {}; + } + + cycleCache.add(absolutePath); + const fileContent = system.readFile(absolutePath); + const options = {}; + + if (fileContent) { + const parsedConfig = JSON.parse(fileContent) as { + extends?: string | string[]; + tstl?: TypeScriptToLuaOptions; + }; + + if (parsedConfig.extends) { + if (Array.isArray(parsedConfig.extends)) { + for (const extendedConfigFile of parsedConfig.extends) { + Object.assign( + options, + getExtendedTstlOptions(extendedConfigFile, newConfigRoot, cycleCache, system) + ); + } + } else { + Object.assign(options, getExtendedTstlOptions(parsedConfig.extends, newConfigRoot, cycleCache, system)); + } + } else { + return parsedConfig.tstl ?? {}; + } + + if (parsedConfig.tstl) { + Object.assign(options, parsedConfig.tstl); + } + } + + return options; +} + export function createConfigFileUpdater( optionsToExtend: CompilerOptions ): (options: ts.CompilerOptions) => ts.Diagnostic[] { diff --git a/test/cli/tsconfig.spec.ts b/test/cli/tsconfig.spec.ts index 1608ac973..de89cf235 100644 --- a/test/cli/tsconfig.spec.ts +++ b/test/cli/tsconfig.spec.ts @@ -1,7 +1,7 @@ import * as fs from "fs-extra"; import * as os from "os"; import * as path from "path"; -import { locateConfigFile } from "../../src/cli/tsconfig"; +import { locateConfigFile, parseConfigFileWithSystem } from "../../src/cli/tsconfig"; import { normalizeSlashes } from "../../src/utils"; let temp: string; @@ -91,3 +91,20 @@ describe("errors", () => { expect([locate("tsconfig.json", [""])]).toHaveDiagnostics(); }); }); + +describe("tsconfig extends", () => { + test("correctly merges extended tsconfig files", () => { + const parsedConfig = parseConfigFileWithSystem(path.join(__dirname, "tsconfig", "tsconfig.json")); + expect(parsedConfig.options).toMatchObject({ luaTarget: "5.3", noHeader: true }); + }); + + test("can handle multiple extends", () => { + const parsedConfig = parseConfigFileWithSystem(path.join(__dirname, "tsconfig", "tsconfig.multi-extends.json")); + expect(parsedConfig.options).toMatchObject({ luaTarget: "5.4", sourceMapTraceback: true }); + }); + + test("can handle cycles in configs", () => { + const parsedConfig = parseConfigFileWithSystem(path.join(__dirname, "tsconfig", "tsconfig-cycle1.json")); + expect(parsedConfig.options).toMatchObject({ luaTarget: "5.4" }); + }); +}); diff --git a/test/cli/tsconfig/tsconfig-cycle1.json b/test/cli/tsconfig/tsconfig-cycle1.json new file mode 100644 index 000000000..6383b5ccf --- /dev/null +++ b/test/cli/tsconfig/tsconfig-cycle1.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig-cycle2.json", + "tstl": { + "luaTarget": "5.4" + } +} diff --git a/test/cli/tsconfig/tsconfig-cycle2.json b/test/cli/tsconfig/tsconfig-cycle2.json new file mode 100644 index 000000000..14c3edcd1 --- /dev/null +++ b/test/cli/tsconfig/tsconfig-cycle2.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig-cycle1.json", + "tstl": { + "luaTarget": "5.3" + } +} diff --git a/test/cli/tsconfig/tsconfig.base.json b/test/cli/tsconfig/tsconfig.base.json new file mode 100644 index 000000000..6b296a8de --- /dev/null +++ b/test/cli/tsconfig/tsconfig.base.json @@ -0,0 +1,6 @@ +{ + "tstl": { + "noHeader": true, + "luaTarget": "jit" + } +} diff --git a/test/cli/tsconfig/tsconfig.json b/test/cli/tsconfig/tsconfig.json new file mode 100644 index 000000000..7e76044a2 --- /dev/null +++ b/test/cli/tsconfig/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.base.json", + "tstl": { + "luaTarget": "5.3" + } +} diff --git a/test/cli/tsconfig/tsconfig.multi-extends.json b/test/cli/tsconfig/tsconfig.multi-extends.json new file mode 100644 index 000000000..7404a6266 --- /dev/null +++ b/test/cli/tsconfig/tsconfig.multi-extends.json @@ -0,0 +1,6 @@ +{ + "extends": ["./tsconfig.json", "./tsconfig2.json"], + "tstl": { + "sourceMapTraceback": true + } +} diff --git a/test/cli/tsconfig/tsconfig2.json b/test/cli/tsconfig/tsconfig2.json new file mode 100644 index 000000000..9cfef77e0 --- /dev/null +++ b/test/cli/tsconfig/tsconfig2.json @@ -0,0 +1,5 @@ +{ + "tstl": { + "luaTarget": "5.4" + } +} From 1b7eaaf8d1934661329b38b8b62145f238fab0c9 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Mon, 1 May 2023 21:04:09 +0200 Subject: [PATCH 2/3] Remove useless else statement --- src/cli/tsconfig.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/cli/tsconfig.ts b/src/cli/tsconfig.ts index 2a483b492..430470d10 100644 --- a/src/cli/tsconfig.ts +++ b/src/cli/tsconfig.ts @@ -92,8 +92,6 @@ function getExtendedTstlOptions( } else { Object.assign(options, getExtendedTstlOptions(parsedConfig.extends, newConfigRoot, cycleCache, system)); } - } else { - return parsedConfig.tstl ?? {}; } if (parsedConfig.tstl) { From a4161d76e70470fc9536e4d40a663d21b2e9658d Mon Sep 17 00:00:00 2001 From: Perryvw Date: Mon, 1 May 2023 21:19:09 +0200 Subject: [PATCH 3/3] Handle tsconfig files with comments --- src/cli/tsconfig.ts | 12 +++++++++--- test/cli/tsconfig.spec.ts | 5 +++++ test/cli/tsconfig/tsconfig.with-comments.json | 8 ++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 test/cli/tsconfig/tsconfig.with-comments.json diff --git a/src/cli/tsconfig.ts b/src/cli/tsconfig.ts index 430470d10..dd6c4e9aa 100644 --- a/src/cli/tsconfig.ts +++ b/src/cli/tsconfig.ts @@ -76,11 +76,17 @@ function getExtendedTstlOptions( const options = {}; if (fileContent) { - const parsedConfig = JSON.parse(fileContent) as { - extends?: string | string[]; - tstl?: TypeScriptToLuaOptions; + const { config: parsedConfig } = ts.parseConfigFileTextToJson(configFilePath, fileContent) as { + config?: { + extends?: string | string[]; + tstl?: TypeScriptToLuaOptions; + }; }; + if (!parsedConfig) { + return {}; + } + if (parsedConfig.extends) { if (Array.isArray(parsedConfig.extends)) { for (const extendedConfigFile of parsedConfig.extends) { diff --git a/test/cli/tsconfig.spec.ts b/test/cli/tsconfig.spec.ts index de89cf235..b4df23e08 100644 --- a/test/cli/tsconfig.spec.ts +++ b/test/cli/tsconfig.spec.ts @@ -107,4 +107,9 @@ describe("tsconfig extends", () => { const parsedConfig = parseConfigFileWithSystem(path.join(__dirname, "tsconfig", "tsconfig-cycle1.json")); expect(parsedConfig.options).toMatchObject({ luaTarget: "5.4" }); }); + + test("can handle tsconfig files with comments", () => { + const parsedConfig = parseConfigFileWithSystem(path.join(__dirname, "tsconfig", "tsconfig.with-comments.json")); + expect(parsedConfig.options).toMatchObject({ luaTarget: "5.3" }); + }); }); diff --git a/test/cli/tsconfig/tsconfig.with-comments.json b/test/cli/tsconfig/tsconfig.with-comments.json new file mode 100644 index 000000000..9baf9adda --- /dev/null +++ b/test/cli/tsconfig/tsconfig.with-comments.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.base.json", + "tstl": { + // Can handle comments + /* also of this kind */ + "luaTarget": "5.3" + } +}