@typed/content-hash
Version:
Content hash a directory of HTML/JS/CSS files and other static assets
87 lines (73 loc) • 2.59 kB
text/typescript
import { none, Option, some } from 'fp-ts/Option'
import * as fs from 'fs'
import { posix } from 'path'
import { sync as nodeResolve } from 'resolve'
import {
CompilerOptions,
convertCompilerOptionsFromJson,
findConfigFile,
FormatDiagnosticsHost,
formatDiagnosticsWithColorAndContext,
getDefaultCompilerOptions,
parseConfigFileTextToJson,
sys,
} from 'typescript'
export type TsConfig = {
readonly compilerOptions: CompilerOptions
readonly configPath: string
readonly extends?: string | string[]
readonly files?: string[]
readonly include?: string[]
readonly exclude?: string[]
}
export type FindTsConfigOptions = {
readonly directory: string
readonly configFileName?: string
}
export const DEFAULT_TSCONFIG_FILENAME = 'tsconfig.json'
export function findTsConfig({
directory,
configFileName = DEFAULT_TSCONFIG_FILENAME,
}: FindTsConfigOptions): Option<TsConfig> {
const configPath = findConfigFile(directory, sys.fileExists, configFileName)
if (!configPath) {
return none
}
const formatHost: FormatDiagnosticsHost = {
getCanonicalFileName: (path) => posix.resolve(directory, path),
getCurrentDirectory: () => directory,
getNewLine: () => sys.newLine,
}
const baseConfig = parseConfigFile(directory, configPath, formatHost)
if (baseConfig.extends) {
const extensions = Array.isArray(baseConfig.extends) ? baseConfig.extends : [baseConfig.extends]
const extendedConfigPaths = extensions.map((ext) => nodeResolve(ext, { basedir: posix.dirname(configPath) }))
const extendedConfigs = extendedConfigPaths.map((path) => parseConfigFile(directory, path, formatHost))
return some(extendedConfigs.reduceRight(mergeConfigs, baseConfig))
}
return some(baseConfig)
}
function mergeConfigs(base: TsConfig, extension: TsConfig): TsConfig {
return {
...extension,
...base,
compilerOptions: {
...extension.compilerOptions,
...base.compilerOptions,
},
}
}
function parseConfigFile(directory: string, filePath: string, host: FormatDiagnosticsHost): TsConfig {
const fileName = posix.basename(filePath)
const contents = fs.readFileSync(filePath).toString()
const { config } = parseConfigFileTextToJson(filePath, contents)
const { options, errors } = convertCompilerOptionsFromJson(config.compilerOptions, directory, fileName)
if (errors && errors.length > 0) {
throw new Error(formatDiagnosticsWithColorAndContext(errors, host))
}
return {
...config,
compilerOptions: { ...getDefaultCompilerOptions(), ...options },
configPath: filePath,
}
}