Skip to content

Commit

Permalink
feat: load tsconfig
Browse files Browse the repository at this point in the history
  • Loading branch information
skarab42 committed Jul 6, 2022
1 parent 7ec0912 commit 0b45180
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 1 deletion.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"up-hooks": "npx simple-git-hooks",
"prepare": "pnpm up-hooks",
"build": "tsup",
"watch": "nodemon ./src/compiler.ts",
"watch": "nodemon ./src/program/index.ts",
"check": "tsc -p tsconfig.check.json",
"format": "prettier . --write --ignore-path .gitignore",
"lint": "eslint . --fix --ext .js,.cjs,.ts --ignore-path .gitignore",
Expand Down
89 changes: 89 additions & 0 deletions src/program/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import path from 'path';
import ts from 'typescript';
import { errorMessage, ErrorCode } from './error';
import { formatDiagnostics } from './diagnostic';
import { getCurrentDirectory, fileExists, readFile } from './util';

export interface Options {
configName?: string;
searchPath?: string;
compilerOptions?: ts.CompilerOptions;
}

export function findConfigFile(options: Options = {}) {
const configName = options.configName ?? 'tsconfig.json';
const searchPath = options.searchPath ?? getCurrentDirectory();
const filePath = ts.findConfigFile(searchPath, fileExists, configName);

// TODO: allow fallback to default config with a warning?
if (!filePath) {
return {
error: errorMessage(ErrorCode.TSCONFIG_FILE_NOT_FOUND, { searchPath, configName }),
};
}

return { filePath };
}

export function readConfigFile(filePath: string) {
try {
const jsonText = readFile(filePath);

if (!jsonText) {
return {
error: errorMessage(ErrorCode.TSCONFIG_FILE_NOT_READABLE, { filePath }),
};
}

return { filePath, jsonText };
} catch (_err) {
return {
error: errorMessage(ErrorCode.TSCONFIG_FILE_NOT_READABLE, { filePath }),
};
}
}

export function parseConfigFile(fileName: string, jsonText: string, compilerOptions?: ts.CompilerOptions) {
const configObject = ts.parseConfigFileTextToJson(fileName, jsonText);

if (configObject.error) {
return { error: new Error(formatDiagnostics([configObject.error])) };
}

const config = ts.parseJsonConfigFileContent(configObject.config, ts.sys, path.dirname(fileName), compilerOptions);

if (config.errors.length > 0) {
return { error: new Error(formatDiagnostics(config.errors)) };
}

return { fileName, config };
}
export function loadConfig(options?: Options) {
try {
const configFile = findConfigFile(options);

if (configFile.error) {
throw configFile.error;
}

const configFileContent = readConfigFile(configFile.filePath);

if (configFileContent.error) {
throw configFileContent.error;
}

const parsedConfig = parseConfigFile(
configFileContent.filePath,
configFileContent.jsonText,
options?.compilerOptions,
);

if (parsedConfig.error) {
throw parsedConfig.error;
}

return { config: parsedConfig };
} catch (error) {
return { error: error as Error };
}
}
12 changes: 12 additions & 0 deletions src/program/diagnostic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import ts from 'typescript';
import { getCurrentDirectory, newLine } from './util';

export const diagnosticsHost: ts.FormatDiagnosticsHost = {
getNewLine: () => newLine,
getCurrentDirectory: () => getCurrentDirectory(),
getCanonicalFileName: (fileName: string) => fileName,
};

export function formatDiagnostics(diagnostics: ts.Diagnostic[]) {
return ts.formatDiagnostics(diagnostics, diagnosticsHost);
}
19 changes: 19 additions & 0 deletions src/program/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export enum ErrorCode {
TSCONFIG_FILE_NOT_FOUND,
TSCONFIG_FILE_NOT_READABLE,
}

export const errorMessages: Record<ErrorCode, string> = {
[ErrorCode.TSCONFIG_FILE_NOT_FOUND]: 'TS config file not found. File name: {configName} - Search path: {searchPath}',
[ErrorCode.TSCONFIG_FILE_NOT_READABLE]: 'TS config file not readable or empty. File path: {filePath}',
};

export function errorMessage(code: ErrorCode, data?: Record<string, unknown>) {
let message = errorMessages[code];

Object.entries(data ?? {}).forEach(([index, value]) => {
message = message.replace(new RegExp(`{${index}}`, 'g'), String(value));
});

return new Error(message);
}
8 changes: 8 additions & 0 deletions src/program/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { loadConfig } from './config';

const config = loadConfig({
configName: 'tsconfig.check.json',
});

// eslint-disable-next-line no-console
console.log(config);
15 changes: 15 additions & 0 deletions src/program/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import ts from 'typescript';

export const newLine = '\n';

export function getCurrentDirectory() {
return ts.sys.getCurrentDirectory();
}

export function fileExists(fileName: string) {
return ts.sys.fileExists(fileName);
}

export function readFile(fileName: string) {
return ts.sys.readFile(fileName);
}

0 comments on commit 0b45180

Please sign in to comment.