@tangelo/tangelo-configuration-toolkit
Version:
Tangelo Configuration Toolkit is a command-line toolkit which offers support for developing a Tangelo configuration.
106 lines (87 loc) • 3.63 kB
JavaScript
const fs = require('fs-extra');
const globby = require('globby');
const path = require('path');
const sass = require('sass');
const SaxonJS = require('saxon-js');
const url = require('url');
module.exports = class TclConfig {
static #SEF_FILE_PATH = 'tcl/configToJson.sef.json';
static #JSON_TO_SCSS_FILE_PATH = 'tcl/configJsonToScss';
static #TCL_FILE_NAME = 'project.tcl';
static #TCL_JSON_FILE_NAME = 'tcl-config.json';
static #TCL_CSS_FILE_NAME = 'tcl-styles.css';
static #FONTO_HTML_FILE_NAME = 'index.html';
static #sefFile;
static #jsonToScssFile;
static #transformTclConfigToJson(tclFilePathRel) {
this.#sefFile ??= _modulesTdi.require(this.#SEF_FILE_PATH, {message: false});
const messages = [` Warnings from transformation of ${tclFilePathRel}`];
const transformation = SaxonJS.transform({
stylesheetText: JSON.stringify(this.#sefFile),
sourceFileName: tclFilePathRel,
destination: 'raw',
deliverMessage(messageNode) {
messages.push(messageNode.textContent);
}
});
if (messages[1]) _warn(messages.join('\n '));
return transformation.principalResult ?? _error(`No result from transformation of ${tclFilePathRel}`);
}
static #transformJsonToCss(tclFilePathRel, json, moduleName) {
this.#jsonToScssFile ??= _modulesTdi.require(this.#JSON_TO_SCSS_FILE_PATH, {message: false});
const scss = this.#jsonToScssFile(json.project, moduleName);
const fileUrl = url.pathToFileURL(tclFilePathRel);
return sass.compileString(scss, {url: fileUrl, style: 'compressed'}).css;
}
static #addCssImportToHtml(dir) {
const filepath = path.join(dir, this.#FONTO_HTML_FILE_NAME);
if (fs.existsSync(filepath)) {
const html = fs.readFileSync(filepath).toString();
if (!RegExp(`<link[^>]*${this.#TCL_CSS_FILE_NAME}[^>]*>`).test(html)) {
const newHtml = html.replace(/((\s+<link.*")[^"]+\.css(.*))/, `$1$2${this.#TCL_CSS_FILE_NAME}$3`);
fs.outputFileSync(filepath, newHtml);
}
}
}
static findProjects() {
return globby.sync('config/cmscustom/!(tdi)/!(fonts)').map(p => ({path: p, tcl: fs.existsSync(path.join(p, this.#TCL_FILE_NAME))}));
}
#outputFn;
#doModifyFontoHtml;
#tclFilePathRel;
#tclFileExists;
#resultJson;
#resultCss = {};
constructor(tclFileRelDir, addToStreamFn) {
this.#tclFilePathRel = path.join(tclFileRelDir, TclConfig.#TCL_FILE_NAME);
this.#tclFileExists = fs.existsSync(this.#tclFilePathRel);
this.#outputFn = addToStreamFn ?? fs.outputFileSync;
this.#doModifyFontoHtml = !addToStreamFn;
}
#getJson() {
return this.#resultJson ??= TclConfig.#transformTclConfigToJson(this.#tclFilePathRel);
}
#getCss(moduleName) {
return this.#resultCss[moduleName] ??= TclConfig.#transformJsonToCss(this.#tclFilePathRel, this.#getJson(), moduleName);
}
outputJson(dir) {
if (this.#tclFileExists) {
const filepath = path.join(dir, TclConfig.#TCL_JSON_FILE_NAME);
this.#outputFn(filepath, JSON.stringify(this.#getJson()));
}
return this;
}
outputCss(dir) {
if (this.#tclFileExists) {
const filepath = path.join(dir, TclConfig.#TCL_CSS_FILE_NAME);
const moduleName = dir.includes('xbrl') ? 'XBRL' : 'FONTO';
this.#outputFn(filepath, this.#getCss(moduleName));
this.modifyFontoHtml(dir);
}
return this;
}
modifyFontoHtml(dir) {
if (this.#tclFileExists && this.#doModifyFontoHtml) TclConfig.#addCssImportToHtml(dir);
return this;
}
};