Last active
May 20, 2024 10:36
-
-
Save jeremyben/4de4fdc40175d0f76892209e00ece98f to your computer and use it in GitHub Desktop.
Typescript programmatic build with tsconfig.json (run with `ts-node -T`)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as path from 'path' | |
import ts from 'typescript' | |
function build( | |
override: { | |
compilerOptions?: ts.CompilerOptions | |
include?: string[] | |
exclude?: string[] | |
files?: string[] | |
extends?: string | |
} = {}, | |
currentDir = process.cwd() | |
) { | |
const configFile = ts.findConfigFile(currentDir, ts.sys.fileExists, 'tsconfig.json') | |
if (!configFile) throw Error('tsconfig.json not found') | |
const { config } = ts.readConfigFile(configFile, ts.sys.readFile) | |
config.compilerOptions = Object.assign({}, config.compilerOptions, override.compilerOptions) | |
if (override.include) config.include = override.include | |
if (override.exclude) config.exclude = override.exclude | |
if (override.files) config.files = override.files | |
if (override.extends) config.files = override.extends | |
const { options, fileNames, errors } = ts.parseJsonConfigFileContent(config, ts.sys, currentDir) | |
const program = ts.createProgram({ options, rootNames: fileNames, configFileParsingDiagnostics: errors }) | |
const { diagnostics, emitSkipped } = program.emit() | |
const allDiagnostics = ts.getPreEmitDiagnostics(program).concat(diagnostics, errors) | |
if (allDiagnostics.length) { | |
const formatHost: ts.FormatDiagnosticsHost = { | |
getCanonicalFileName: (path) => path, | |
getCurrentDirectory: ts.sys.getCurrentDirectory, | |
getNewLine: () => ts.sys.newLine, | |
} | |
const message = ts.formatDiagnostics(allDiagnostics, formatHost) | |
console.warn(message) | |
} | |
if (emitSkipped) process.exit(1) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { exec, ExecOptions } from 'child_process' | |
import { join } from 'path' | |
function build(flags: string[] = [], directory = process.cwd()) { | |
const tsc = join(__dirname, 'node_modules', 'typescript', 'lib', 'tsc.js') | |
const tsConfig = join(directory, 'tsconfig.json') | |
const cmd = encodeArgs(process.execPath, tsc, '--project', tsConfig, ...flags).join(' ') | |
return execAsync(cmd, { inherit: true }) | |
function execAsync(cmd: string, opts: ExecOptions & { inherit?: boolean } = {}): Promise<string> { | |
return new Promise((resolve, reject) => { | |
const child = exec(cmd, opts, (error, stdout, stderr) => { | |
if (error) reject({ ...error, stdout, stderr }) | |
else resolve(stdout) | |
}) | |
if (opts.inherit) { | |
child.stdout.pipe(process.stdout) | |
child.stderr.pipe(process.stderr) | |
} | |
}) | |
} | |
function encodeArgs(...args: string[]) { | |
// Taken from https://github.com/xxorax/node-shell-escape/blob/master/shell-escape.js | |
// However, we needed to use double quotes because that's the norm in more platforms | |
if (!args) return args | |
return args.map((arg) => { | |
if (/[^\w/:=-]/.test(arg)) { | |
arg = `"${arg.replace(/"/g, '"\\"')}"` | |
arg = arg.replace(/^(?:"")+/g, '').replace(/\\"""/g, '\\"') | |
} | |
return arg | |
}) | |
} | |
} |
Check out my project https://github.com/jeremyben/tsc-prog 😉
const formatHost = {
getCanonicalFileName: path => path,
getNewLine: () => ts.sys.newLine,
getCurrentDirectory: () => root,
};
const message = ts.formatDiagnosticsWithColorAndContext(
allDiagnostics,
formatHost
);
This usage is better.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
great job !