@adonisjs/require-ts
Version:
In memory typescript compiler
196 lines (195 loc) • 6.15 kB
JavaScript
"use strict";
/*
* @adonisjs/require-ts
*
* (c) Harminder Virk <virk@adonisjs.comharminder@cav.ai>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Config = void 0;
const path_1 = require("path");
const fs_extra_1 = require("fs-extra");
const utils_1 = require("../utils");
const Cache_1 = require("../Cache");
const DiagnosticsReporter_1 = require("../DiagnosticsReporter");
/**
* Exposes the API to parse tsconfig file and cache it until the
* contents of the file are changed.
*/
class Config {
constructor(appRoot, cacheRoot, ts, usesCache = true) {
this.appRoot = appRoot;
this.cacheRoot = cacheRoot;
this.ts = ts;
this.usesCache = usesCache;
/**
* Hard assumption has been made that config file name
* is "tsconfig.json"
*/
this.configFilePath = (0, path_1.join)(this.appRoot, 'tsconfig.json');
/**
* Reference to the cache
*/
this.cache = this.usesCache ? new Cache_1.Cache(this.appRoot, this.cacheRoot) : new Cache_1.FakeCache();
/**
* Dignostic reporter to print program errors
*/
this.diagnosticsReporter = this.ts
? new DiagnosticsReporter_1.DiagnosticsReporter(this.appRoot, this.ts, false)
: undefined;
}
/**
* Returns the raw contents of the config file. We need to read this
* always to generate the hash and then look for the cached config
* file.
*/
getConfigRawContents() {
(0, utils_1.debug)('checking for tsconfig "%s"', this.configFilePath);
try {
return (0, fs_extra_1.readFileSync)(this.configFilePath, 'utf-8');
}
catch (error) {
if (error.code === 'ENOENT') {
throw new Error('"@adonisjs/require-ts" expects the "tsconfig.json" file to exists in the app root');
}
throw error;
}
}
/**
* Parses the ts config using the typescript compiler
*/
parseTsConfig() {
let exception = null;
(0, utils_1.debug)('parse tsconfig file');
if (!this.ts) {
throw new Error('Cannot parse typescript config. Make sure to instantiate Config class with typescript compiler');
}
/**
* Parse config using typescript compiler
*/
const config = this.ts.getParsedCommandLineOfConfigFile(this.configFilePath, {}, {
...this.ts.sys,
useCaseSensitiveFileNames: true,
getCurrentDirectory: () => this.appRoot,
onUnRecoverableConfigFileDiagnostic: (error) => (exception = error),
});
/**
* Return exception as it is
*/
if (exception) {
return {
error: exception,
options: null,
};
}
/**
* Return diagnostic errors if any
*/
if (config.errors && config.errors.length) {
return {
error: config.errors,
options: null,
};
}
/**
* Return compiler options
*/
return {
error: null,
options: config.options,
};
}
/**
* Parses the cached config string as JSON. Errors
* are ignored and hence cache is ignored too
*/
parseConfigAsJson(config) {
if (!config) {
return null;
}
try {
return JSON.parse(config);
}
catch (error) {
return null;
}
}
/**
* Extracts transformers the tsconfig file contents
*/
extractTransformers(rawConfig) {
try {
const transformers = JSON.parse(rawConfig).transformers || {};
return {
before: transformers.before,
after: transformers.after,
afterDeclarations: transformers.afterDeclarations,
};
}
catch (error) { }
}
/**
* Returns the config file from the cache or returns null when there is
* no cache
*/
getCached() {
const rawContents = this.getConfigRawContents();
const cachePath = this.cache.makeCachePath(this.configFilePath, rawContents, '.json');
return {
raw: rawContents,
cachePath,
cached: this.parseConfigAsJson(this.cache.get(cachePath)),
};
}
/**
* Parses config and returns the compiler options
*/
parse() {
if (!this.diagnosticsReporter) {
throw new Error('Cannot parse typescript config. Make sure to instantiate Config class with typescript compiler');
}
/**
* Cache exists and is upto date
*/
const { cached, raw, cachePath } = this.getCached();
if (cached && cached.version === Config.version) {
return {
version: cached.version,
error: null,
options: {
compilerOptions: cached.options.compilerOptions,
transformers: cached.options.transformers,
},
};
}
/**
* Parse the config using the compiler
*/
const config = this.parseTsConfig();
if (config.error) {
this.diagnosticsReporter.report(config.error);
return {
version: Config.version,
options: null,
error: config.error,
};
}
/**
* Write to cache to avoid future parsing
*/
const parsed = {
version: Config.version,
error: null,
options: {
compilerOptions: config.options,
transformers: this.extractTransformers(raw),
},
};
this.cache.set(cachePath, JSON.stringify(parsed));
return parsed;
}
}
exports.Config = Config;
Config.version = 'v1';