Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 58 additions & 2 deletions src/cli/tsconfig.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -41,17 +41,73 @@ 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<string>();
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<string>,
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 { 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) {
Object.assign(
options,
getExtendedTstlOptions(extendedConfigFile, newConfigRoot, cycleCache, system)
);
}
} else {
Object.assign(options, getExtendedTstlOptions(parsedConfig.extends, newConfigRoot, cycleCache, system));
}
}

if (parsedConfig.tstl) {
Object.assign(options, parsedConfig.tstl);
}
}

return options;
}

export function createConfigFileUpdater(
optionsToExtend: CompilerOptions
): (options: ts.CompilerOptions) => ts.Diagnostic[] {
Expand Down
24 changes: 23 additions & 1 deletion test/cli/tsconfig.spec.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -91,3 +91,25 @@ 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" });
});

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" });
});
});
6 changes: 6 additions & 0 deletions test/cli/tsconfig/tsconfig-cycle1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": "./tsconfig-cycle2.json",
"tstl": {
"luaTarget": "5.4"
}
}
6 changes: 6 additions & 0 deletions test/cli/tsconfig/tsconfig-cycle2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": "./tsconfig-cycle1.json",
"tstl": {
"luaTarget": "5.3"
}
}
6 changes: 6 additions & 0 deletions test/cli/tsconfig/tsconfig.base.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"tstl": {
"noHeader": true,
"luaTarget": "jit"
}
}
6 changes: 6 additions & 0 deletions test/cli/tsconfig/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": "./tsconfig.base.json",
"tstl": {
"luaTarget": "5.3"
}
}
6 changes: 6 additions & 0 deletions test/cli/tsconfig/tsconfig.multi-extends.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": ["./tsconfig.json", "./tsconfig2.json"],
"tstl": {
"sourceMapTraceback": true
}
}
8 changes: 8 additions & 0 deletions test/cli/tsconfig/tsconfig.with-comments.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "./tsconfig.base.json",
"tstl": {
// Can handle comments
/* also of this kind */
"luaTarget": "5.3"
}
}
5 changes: 5 additions & 0 deletions test/cli/tsconfig/tsconfig2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"tstl": {
"luaTarget": "5.4"
}
}