/**
* @file src/core/wrapper.js
* @copyright @spmhome @_2025
* @author Scott Meesseman @spmeesseman
*//** */
const os = require("os");
const WpwBase = require("./base");
const WpwBuild = require("./build");
const { join, sep } = require("path");
const WpwLogger = require("../log/log");
const WpwCache = require("../services/cache");
const { wpwPath, cleanupBuildDone } = require("../utils/utils");
const { printWpwProperties } = require("../utils/print");
const { applyVendorMods } = require("../utils/vendormod");
const { getRcConfig, SpmhSchema } = require("@spmhome/app-utils");
const { WpwBuildBaseConfigKeys, WpwSchemaKeys } = require("../types/constants");
const { getRandomColor, SpmhError, SpmhMessageUtils } = require("@spmhome/log-utils");
const { STATS_JSON_SLUG, CRYPTO_KEY_DEFAULT_128, CRYPTO_KEY_DEFAULT_256 } = require("../utils/constants");
const {
findExPathSync, existsAsync, existsSync, createDirAsync, findFiles, findExPath, isAbsPath, joinPath,
resolvePath, findDotJsonFileUpSync
} = require("@spmhome/cmn-utils");
const {
apply, isArray, pick, merge, asArray, applyIf, pickNot, mergeStrong, mergeIf, isObject, uniq, isString,
safeStringify, pushReturnOne, pluralize, create,
isFunction
} = require("@spmhome/type-utils");
const webpackExports = require("../exports");
/**
* @augments WpwBase
* @implements {IWpwSchema}
*/
class WpwWrapper extends WpwBase
{
/**
* @type {boolean}
*/
autoConfig;
/**
* @type {WebpackRuntimeArgs}
*/
cliWp;
/**
* @type {WpwBuild[]}
*/
builds = [];
/**
* @type {IWpwBuildConfig[]}
*/
buildConfigs = [];
/**
* @private
* @type {WpwBuildLibraryConfig}
*/
_library;
/**
* @type {IWpwSchema}
*/
_config;
/**
* @type {WpwCrypto}
*/
crypto;
/**
* @private
* @type {string}
*/
_x0 = "878bcdd309ff6855";
/**
* @private
* @type {string}
*/
_x1 = "706d23bc2f154886";
/**
* @private
* @type {string}
*/
_x2 = "ae9c1cc6a2272923";
/**
* @type {WpwBuildEnvironmentConfig}
*/
development;
/**
* @type {WpwLogOptions}
*/
log;
/**
* @private
* @type {boolean}
*/
_disposed = false;
/**
* @private
* @type {WpwLogger}
*/
_logger;
/**
* @type {WpwWebpackMode}
*/
mode;
/**
* @type {WpwBuildOptions}
*/
options = {};
/**
* @type {WpwRcPaths}
*/
paths;
/**
* @private
* @type {WpwPackageJson}
*/
_pkgJson;
/**
* @private
* @type {string}
*/
_pkgJsonDir;
/**
* @private
* @type {string}
*/
_pkgJsonPath;
/**
* @type {WpwBuildEnvironmentConfig}
*/
production;
/**
* @type {string}
*/
$schema;
/**
* @type {SpmhSchema}
*/
_schema;
/**
* @type {VersionString}
*/
_schemaVersion;
/**
* @type {IWpwSourceCodeConfig}
*/
source;
/**
* @private
* @type {WpwCache}
*/
_stats;
/**
* @private
* @type {string}
*/
_statsfile;
/**
* @private
* @type {WpwBuildTargetConfig}
*/
_target;
/**
* @description Builds in 'test' mode, i.e. 'none'
* @type {WpwBuildEnvironmentConfig}
*/
test;
/**
* @private
* @type {WpwBuildTypeConfig}
*/
_type;
/**
* @type {WpwGlobalSettings}
*/
settings;
/**
* @private
* @type {WpwRcPaths}
*/
_vpaths;
/**
* @private
* @type {WebpackType}
*/
_wp;
/**
* @param {WpwCmdLineArgs} cli
* @param {WebpackType} wp
*/
constructor(cli, wp)
{
super();
this._wp = wp;
this._cli = merge({}, cli);
this._schema = new SpmhSchema("WpwSchema", this._path_.resolve(wpwPath(), "schema/spmh.wpw.schema.json"));
this._schemaVersion = this._schema.version();
}
get buildCount() { return this.builds.length; }
get cacheDir() { return this.settings.cacheDir; }
get cacheDirGlobal() { return this.global.cacheDir; }
get cli() { return this._cli; }
get isSingleBuild() { return this.builds.length === 1; }
get library() { return this._library; }
/** @private */set library(v) { this._library = this._obj_.merge({}, v); }
get logger() { return this._logger; }
get pkgJson() { return this._pkgJson; }
get pkgJsonFilePath() { return this._pkgJsonPath; }
get schema() { return this._schema; }
get schemaVersion() { return this._schemaVersion; }
get stats() { return this._stats.data; }
get statsfile() { return this._statsfile; }
get target() { return this._target; }
/** @private */set target(v) { this._target = this._obj_.merge({}, v); }
get type() { return this._type; }
/** @private */set type(v) { this._type = this._obj_.merge({}, v); }
get vpaths() { return this._vpaths; }
/** @private */set vpaths(v) { this._vpaths = this._obj_.merge({}, v); }
/**
* Application entry point to a cli / startup
*
* @param {WpwCmdLineArgs} cli
* @param {WebpackType} wp
*/
static async create(cli, wp)
{
const wpw = new WpwWrapper(cli, wp);
await wpw.init.call(wpw);
return wpw;
}
/**
* @returns {Promise<WpwBuild[]>}
*/
async createBuilds()
{
const l = this.logger,
arg = this.cli.build?.split(",").map((b) => b.trim());
l.write("prepare build run", 1);
l.value(" cli --build argument", arg || "none [all]", 2);
await this.createBuildConfigs();
const activeConfigs = this.buildConfigs.filter((b) => !b.disabled && (!arg || arg.includes(b.name)));
if (activeConfigs.length > 0)
{
const vMsg = ` ${activeConfigs.length} active ${pluralize("configuration", activeConfigs.length)}`;
if (l.level >= 3) {
l.value(vMsg, safeStringify(activeConfigs, null, 3), 3, " ");
}
else {
l.value(vMsg, safeStringify(activeConfigs.map((c) => ({ name: c.name }))), 1);
}
this.builds.push(...activeConfigs.map((cfg) => new WpwBuild(this, this._wp, cfg)));
await Promise.all(this.builds.map((b) => b.init(" ")));
if (activeConfigs.find((c) => !!c.options.wait?.enabled || (isArray(c) && !c.includes(c.entry)) ||
isObject(c.entry) && !isArray(c.entry) && !!c.entry.dependOn))
{
const dependConfigs = await this.getDependencyBuilds(" ");
if (dependConfigs.length > 0)
{
const dBuilds = dependConfigs.map((cfg) => new WpwBuild(this, this._wp, cfg));
await Promise.all(dBuilds.map((b) => b.init(" ")));
this.builds.push(...dBuilds);
}
l.write(` created ${this.builds.length} build instances [dependencies::${dependConfigs.length}]`, 1);
}
else {
l.write(` created ${this.builds.length} build instances`, 1);
}
let xPortCt = 0, pluginCt = 0;
l.write(" configure webpack configuration exports for each active build", 1);
this.builds.map((b) => webpackExports(b, " ")).forEach((wpc) => {
pluginCt += wpc.plugins.length; xPortCt += Object.keys(wpc).length;
});
l.values([
[ "active builds", this.builds.length ], [ "webpack configs", xPortCt ], [ "plugin instances", pluginCt ]
], 1, " ", false, "completed webpack exports configuration");
l.success("initialization complete, ready to start webpack multi-compiler", 1);
}
else
{ l.warning(" there are no active builds, dumping full configuration object:");
l.write(safeStringify(this.buildConfigs, null, 3), 1, " ", l.icons.color.warning);
l.write("configuration dump complete");
}
return this.builds;
}
/**
* @private
*/
async createBuildConfigs()
{
/** @type {WpwBuildEnvironmentConfig} */
const modeConfig = this[this.mode] || {},
modeBuildConfigs = asArray(modeConfig.builds),
baseBuildConfigs = asArray(this.builds).splice(0),
emptyConfig = () => /** @type {IWpwBuildConfig} */({}),
modeBaseConfig = this.getBasePropertyConfig(modeConfig),
rootBaseConfig = this.getBasePropertyConfig(this._config),
gDefaults = this._schema.defaults("WpwBuildOptionsGroup"),
eDefaults = this._schema.defaults("WpwBuildOptionsExport"),
pDefaults = this._schema.defaults("WpwBuildOptionsPlugin"),
l = this.logger.write("generate all possible build configurations", 1);
l.value(" has base build configuration(", !!this[this.mode] ,1);
l.value(" has mode build configuration", !!modeConfig.builds , 1);
l.write(` merge ${baseBuildConfigs.length} base-level build configurations`, 2);
for (const config of baseBuildConfigs)
{
l.value(" merge base & base-level build configurations", config.name, 3);
if (config.type && this.type[config.type]) {
merge(config, this.type[config.type]);
}
if (config.target) {
this._arr_.asArray(config.target).filter((t) => !!this.target[t]).forEach((target) => {
merge(config, this.target[target]);
});
}
if (config.library && this.library[config.library]) {
merge(config, this.library[config.library]);
}
this.buildConfigs.push(merge(emptyConfig(), rootBaseConfig, config, modeBaseConfig));
} //
// Process the current environment's confsig. Add all builds defined in the env config that
// aren't defined at root level, and apply the base config and mode config to each. If the
// build "is" defined already at root level, merge in the environment config.
//
l.write(` merge ${modeBuildConfigs.length} build-level mode configurations`, 2);
for (const config of modeBuildConfigs)
{
let buildConfig = this.buildConfigs.find((bc) => bc.name === config.name);
if (!buildConfig) {
buildConfig = pushReturnOne(this.buildConfigs, merge(emptyConfig(), rootBaseConfig, modeBaseConfig));
}
if (buildConfig.type && config.type?.[buildConfig.type]) {
merge(buildConfig, config.type[buildConfig.type]);
}
if (buildConfig.target && config.target) {
this._arr_.asArray(config.target).filter((t) => !!config.target[t]).forEach((target) => {
merge(buildConfig, config.target[target]);
});
}
if (buildConfig.library && config.library?.[buildConfig.library]) {
merge(buildConfig, config.library[buildConfig.library]);
}
l.value(" merge mode-level build configuration", config.name, 3);
merge(buildConfig, config);
} //
// resolve all configured paths to absolute and apply log colors and transformations
//
for (const config of this.buildConfigs)
{
applyIf(config, { mode: this.mode, filter: [], suppress: [] });
config.log.color ||= getRandomColor("wpw");
config.log.colors = applyIf(config.log.colors,
{ buildBracket: config.log.color, buildText: "white", default: "default",
infoIcon: config.log.color, tagBracket: config.log.color
});
mergeIf(config.options, gDefaults, eDefaults, pDefaults);
await this.resolvePaths(this._pkgJsonDir, config.name, config);
}
this.logger.write("completesd generation of all possible build configurations", 1);
}
/**
* @private
* @param {string | number} lPad
*/
async getDependencyBuilds(lPad)
{
let cnt = 0;
const /** @type {WpwBuildConfig[]} */depBuilds = [],
l = this._logger.write("check dependency builds for inclusion in compilation", 1, lPad);
const _addBuild = (/** @type {WpwBuildConfig} */cfg) =>
{ l.write(` add dependency build '${cfg.name}' to compilation`, 1, lPad);
const depBuild = depBuilds[depBuilds.push(cfg) - 1];
if (++cnt && !depBuild.options.wait?.enabled) {
depBuild.options.wait = apply(depBuild.options.wait, { enabled: true });
}
};
const _addOutputPathMsg = (/** @type {SpmhMessage[]} */ msgs, depBuildCfg) =>
{ msgs.push(new SpmhError({
code: SpmhError.Code.INFO_CONFIG_SUGGESTION,
message: "possible issue with build configuration",
suggest: `add rc 'assets/output' config for '${depBuildCfg.name}' for determining dependency build status`
}));};
const _isBuilt = (/** @type {string} */ entry, /** @type {string} */distPath, /** @type {string[]} */ ...ext) =>
{ // return Promise.any([
// existsAsync(resolvePath(distPath, `${f}.${cfgExt}`)), existsAsync(resolvePath(distPath, `${f}.js`)),
// existsAsync(resolvePath(distPath, `${f}.mjs`)), existsAsync(resolvePath(distPath, `${f}.cjs`))
// ]);
return /** @type {Promise<string | null | undefined>}*/(new Promise((ok, fail) =>
{
const f = this._path_.basename(entry).replace(/\.[a-zA-Z0-9]{1,8}$/, ""),
files = uniq([ ...ext.map((e) => `${f}.${e}`), `${f}.js`, `${f}.cjs`, `${f}.mjs` ]);
findExPath(files, distPath).then(ok).catch(fail);
}));
};
//
// process the 'entry.dependOn' config of each active build, & add any applicable dependent
// builds to the 'wait' option items array if not already configured
//
for (const build of this.builds.filter((b) => isObject(b.entry)))
{ for (const entry of Object.entries(build.entry))
{ if (isObject(entry[1]) && entry[1].dependOn)
{
build.options.wait = mergeStrong(build.options.wait || {}, { enabled: true, items: [] });
this._arr_.pushUniq(build.options.wait.items, asArray(entry[1].dependOn)
.map((d) => ({ mode: "event", name: d })));
}
}
}
//
// process the 'wait' option configured for this build, adding any dependent builds to the
// current build process if the dependent build output doesn't already exist
//
for (const build of this.builds.filter((b) => !!b.options.wait?.enabled))
{
if (!asArray(build.options.wait?.items))
{
l.write(` build '${build.name}' has 0 dependencies`, 2, lPad);
continue;
}
l.write(`build '${build.name}' has ${build.options.wait.items.length} dependencies`, 2, lPad);
for (const wCfg of build.options.wait.items)
{
l.write(` check status of dependency build '${wCfg.name}'`, 2, lPad);
const exBuild = this.builds.find((b) => b.name === wCfg.name);
if (exBuild)
{
if (!exBuild.options.wait?.enabled) {
exBuild.options.wait = { enabled: true };
}
l.write(" already in build queue, set wait flag", 2, lPad);
continue;
}
const dCfg = this.buildConfigs.find((b) => b.name === wCfg.name);
if (!dCfg)
{
throw new SpmhError({
code: SpmhError.Code.ERROR_CONFIG_INVALID,
message: `specified build '${wCfg.name}' in 'wait' plugin config does not exist`
});
}
let isBuilt = false;
const depDistPath = dCfg.paths.dist,
depDistIsDup = !!this.buildConfigs.find((b) => b.name !== wCfg.name && b.paths.dist === depDistPath);
l.write(" check dist directory for existing output assets", 2, lPad);
if (!existsSync(depDistPath) || this._cli.clean)
{
l.value(" dist directory of dependency doesn't exist", dCfg.paths.dist, 2, lPad);
_addBuild(dCfg);
continue;
}
if (dCfg.type === "types")
{
const bco = build.tsc.compilerOptions;
l.write(" check 'types' build output", 2, lPad);
if (bco.outFile)
{
isBuilt = await existsAsync(resolvePath(build.paths.base, bco.outFile));
}
if (!isBuilt && bco.declarationDir && bco.declarationDir !== build.paths.dist)
{
isBuilt = await existsAsync(resolvePath(build.paths.base, bco.declarationDir));
}
if (!isBuilt && build.pkgJson.types)
{
isBuilt = await existsAsync(resolvePath(depDistPath, build.pkgJson.types));
}
if (!isBuilt && dCfg.options.types.bundle?.enabled)
{
const outName = dCfg.options.output?.name || dCfg.name;
isBuilt = await Promise.any([
existsAsync(join(depDistPath, outName.replace(/\.d\.ts$/, "") + ".d.ts")),
existsAsync(join(depDistPath, "types.d.ts")),
existsAsync(join(depDistPath, "index.d.ts"))
]);
}
if (!isBuilt)
{
const srcPattern = "**/*.{js,ts,cjs,mjs,cts,mts,jsx,tsx}",
srcCnt = (await findFiles(srcPattern, { cwd: dCfg.paths.src })).length;
isBuilt = [ srcCnt, 1 ].includes((await findFiles("**/*.d.ts", { cwd: depDistPath })).length);
}
}
else if (dCfg.type === "script")
{
l.write(" check 'script' build output", 2, lPad);
let addSuggest = false;
const opts = dCfg.options.script,
paths = asArray(opts.assets?.paths);
isBuilt = (paths.length === 0 || paths.every((p) => findExPathSync([
resolvePath(dCfg.paths.dist, p), resolvePath(dCfg.paths.base, p), resolvePath(build.getRootDistPath(), p)
])));
if (isBuilt)
{
asArray(opts?.items).map((s) => asArray(s.paths?.output)).forEach((paths) =>
{
isBuilt = (paths.length === 0 || paths.every((p) => findExPathSync([
resolvePath(depDistPath, p), resolvePath(dCfg.paths.base, p), resolvePath(build.getRootDistPath(), p)
])));
addSuggest &&= (paths.length === 0);
if (!isBuilt) { return; }
});
}
if (depDistIsDup && addSuggest) { _addOutputPathMsg(build.info, dCfg); }
}
else if (dCfg.type === "schema")
{
l.write(" check 'schema' build output", 2, lPad);
let addSuggest = false;
const opts = dCfg.options.schema,
paths = [ dCfg.options.schema.jsonPath, ...asArray(opts.scripts.assets?.paths) ];
isBuilt = (paths.length === 0 || paths.every((p) => findExPathSync([
resolvePath(depDistPath, p), resolvePath(dCfg.paths.base, p), resolvePath(build.getRootDistPath(), p)
])));
if (opts.scripts && isBuilt)
{
asArray(opts.scripts.items).map((s) => asArray(s.paths?.output)).forEach((paths) =>
{ isBuilt = (paths.length === 0 || paths.every((p) => findExPathSync([
resolvePath(depDistPath, p), resolvePath(dCfg.paths.base, p), resolvePath(build.getRootDistPath(), p)
])));
addSuggest &&= (paths.length === 0);
if (!isBuilt) { return; }
});
}
if (depDistIsDup && addSuggest) { _addOutputPathMsg(build.info, dCfg); }
}
else if (dCfg.type === "resource")
{
l.write(" check resource type output", 2, lPad);
const path = dCfg.options.resource.output,
paths = asArray(dCfg.options.resource.assets?.paths);
isBuilt = (paths.length === 0 || paths.every((p) => findExPathSync([
resolvePath(depDistPath, p), resolvePath(build.getRootDistPath(), p)
]))) && !!findExPathSync([ resolvePath(dCfg.paths.dist, path), resolvePath(build.getRootDistPath(), path) ]);
}
if (!isBuilt && dCfg.entry)
{
l.write(" check existing entry configuration", 2, lPad);
const cfgExt = dCfg.options.output.ext?.replace(/^\./, "") || "js";
if (isString(dCfg.entry))
{
isBuilt = !!await _isBuilt(dCfg.options.output?.name || dCfg.entry, depDistPath, cfgExt);
}
else if (isObject(dCfg.entry))
{
const eKeys = Object.keys(dCfg.entry);
isBuilt = (await Promise.all(eKeys.map((e) => _isBuilt(e, depDistPath, cfgExt)))).every((r) => !!r);
}
}
if (!isBuilt)
{
if (!depDistIsDup) {
isBuilt = existsSync(depDistPath);
}
else { _addOutputPathMsg(build.info, dCfg); }
}
build.options.wait.enabled = !isBuilt;
if (!isBuilt) {
l.write(" all checks complete, dependency build required for this compilation", 2, lPad);
_addBuild(dCfg);
}
}
}
if (cnt > 0) {
l.write(` added ${cnt} required dependency builds to compilation`, 1, lPad);
}
return depBuilds;
}
/**
* @override
*/
dispose()
{
if (!this._disposed)
{ this.builds.splice(0).forEach((b) => b.dispose());
this.disposables.splice(0).forEach((d) => d.dispose());
this._disposed = true;
}
}
/**
* @private
* @param {WpwBuildEnvironmentConfig} config
* @returns {IWpwBuildBaseConfig}
*/
getBasePropertyConfig(config) { return config ? pick(config, ...WpwBuildBaseConfigKeys) : {}; }
/**
* @param {string} nameOrType
* @param {boolean} [isName]
* @returns {WpwBuild | undefined}
*/
getBuild(nameOrType, isName)
{
return this.builds.find((b) => b.name === nameOrType || (!isName && b.type === nameOrType));
}
/**
* @param {string} nameOrType
* @param {boolean} [isName]
* @returns {IWpwBuildConfig | undefined}
*/
getBuildConfig(nameOrType, isName)
{
return this.buildConfigs.find((b) => b.name === nameOrType || (!isName && b.type === nameOrType));
}
/**
* @param {(function(IWpwBuildConfig): boolean)} cb
* @param {any} thisArg
*/
getBuildConfigBy(cb, thisArg) { return this.buildConfigs.find(cb.bind(thisArg || cb)) || {}; }
/**
* @private
* @returns {WebpackMode}
*/
getMode()
{
return this.cli.mode || this.cliWp?.mode || "production";
}
/**
* @param {boolean} [web]
* @returns {IWpwRcPaths}
*/
getRootPathsConfig(web) { return this.getBuildConfig(!web ? "app" : "webapp")?.paths || this._config.paths; }
/**
* @param {boolean} [web]
* @returns {string}
*/
getRootSrcPath(web) { return this.getRootPathsConfig(web).src || this.buildConfigs[0].paths.src || process.cwd(); }
/**
* @param {Error} e
*/
handleInitFailure(e)
{
let m, p = "";
const l = this.logger,
n = l.tag("1", l.color, "white"),
separator = l.sep(1, null, "error", true),
hasMessages = this.builds?.filter((b) => b.hasErrorOrWarning);
l.sep(1, l.icons.color.error, "error", false, true);
l.fail("failed to start", 1, "", true);
l.sep(1, l.icons.color.error, "error", false, true);
if (SpmhMessageUtils.isSpmh(e))
{ const xMsg = e.xMessage.toString();
if ((m = xMsg.match(/^( +)/)) !== null) { p = m[1]; }
e.xMessage.setXMessage(`white(ERROR # ${n} of ${n}:)\n${p}${separator}\n${xMsg}\n${p}${separator}`, true);
l.write(e, undefined, "", l.icons.color.error);
}
else
{ const stack = e.stack.replace(/\n/g, "\n".padEnd(l.preMsgTagLen));
// const stack = e.stack.replace(/\n/g, "\n".padEnd(l.messagePrefix(null, false, true).length));
l.write(e.message, undefined, "", l.icons.color.error);
l.write(stack, undefined, "", l.icons.color.error);
}
l.sep(1, l.icons.color.error, "error", false, true);
if (hasMessages.length > 0)
{ hasMessages.forEach((b) => b.printMessages(true));
l.sep(1, l.icons.color.error, "error", false, true);
}
for (const b of this.builds.filter((b) => isFunction(b.dispose)))
{ l.value(`${b.name} rc configuration dump`, b.config);
try {
cleanupBuildDone(b, l);
} catch {}
}
l.fail("done", 1, "", true);
l.sep(1, l.icons.color.error, "error", false, true);
console.log("", "internal");
}
/**
* @private
*/
async init()
{
try
{ const p = this.initPackageJson(),
n = p.scopedName;
this.mode = this.getMode();
this._config = await getRcConfig("wpwrc", "AP_", /** @type {IWpwSchema} */({}));
this._config.settings ||= {};
this._config.settings.project ||= {};
this._config.crypto ||= { type: "none" };
mergeIf(this._config.settings.project, { name: p.name, slug: n.name || p.name, scope: n.scope || "@", group: "" });
mergeIf(this._config, this._schema.defaults("WpwSchema"));
// this._obj_.cleanPrototype(this._config, ...Object.keys(this._config.library));
this.initialConfig = this._obj_.clone(this._config);
this.initLoggerConfig();
await this.initCacheConfig();
await this.resolvePaths(
this._pkgJsonDir, this._config.settings.project?.name || p.scopedName.name || "wpw", this._config
);
this._config.type ||= create();
this._config.target ||= create();
this._config.library ||= create();
this._config.vpaths ||= create({ base: this._config.paths.dist || "" });
this._arr_.popBy(this._config.builds, (bc) => bc.disabled === true);
this._arr_.popBy(this._config.test?.builds , (bc) => bc.disabled === true);
this._arr_.popBy(this._config.production?.builds , (bc) => bc.disabled === true);
this._arr_.popBy(this._config.development?.builds , (bc) => bc.disabled === true);
this._logger = WpwLogger.getLoggerInst(this._config.log, this._schema.defaults("WpwLogOptions"));
this._logger.start("initialize new build pipeline", 1);
if (this._config.crypto.type !== "none")
{
try
{ if (this._config.crypto.key === "default")
{
if (this._config.crypto.strength === "128-bit")
{
this._config.crypto.key = CRYPTO_KEY_DEFAULT_128.substring(0, 16) + this._x0;
}
else {
this._config.crypto.key = `${CRYPTO_KEY_DEFAULT_256.substring(0, 16)}${this._x1}` +
`${this.crypto.key.substring(32, 48)}${this._x2}`;
}
}
this._stats = new WpwCache({
dir: this.global.cacheDir, slug: STATS_JSON_SLUG, logger: this._logger, crypto: this.crypto
});
if (!this._stats.data.applyVendorMods)
{
this._stats.set({ applyVendorMods: true });
if (await applyVendorMods({ all: true }, this._logger)) {
throw new Error("l2_handled");
}
}
} finally { }// store?.dispose(); }
}
merge(this, this._config);
if (this.cli.help || this.cli.version) {
return this;
}
this._schema.validate(this._config, "WpwSchema", this._logger, "", WpwSchemaKeys);
printWpwProperties(this, undefined, " ");
// this.disposables.push(this._tsc = new WpwTscService({ owner: this }));
await this.createBuilds();
this.disposables.push(this.global.globalEvent, ...this.builds, this._logger);
this._logger.success("completed build pipeline initialization", 1);
return this;
}
catch(e)
{ if (e && !/l[1-9]_handled/i.test(e.message || ""))
{ if (this._logger)
{ this._logger.blank(1, this._logger.icons.color.error);
this.handleInitFailure(e);
} else { console.error(e); }
} throw new Error("l3_handled");
}
}
/**
* @private
*/
async initCacheConfig()
{
this.global.cacheDir = !this._config.settings.cacheDir ?
resolvePath(this._pkgJsonDir, "node_modules/.cache") :
(!isAbsPath(this._config.settings.cacheDir) ?
resolvePath(this._config.settings.cacheDir) : this._config.settings.cacheDir);
this._config.settings.cacheDir = joinPath(this.global.cacheDir, "wpw");
if (!existsSync(this._config.settings.cacheDir)) {
await createDirAsync(this._config.settings.cacheDir);
}
this._statsfile = joinPath(this.global.cacheDir, `.${STATS_JSON_SLUG}`);
}
/**
* @private
*/
initLoggerConfig()
{
mergeIf(this._config.log,
{
envTag1: "spmh", envTag2: "wpw", level: 2, color: "spmh_blue",
prefix: merge(this._config.log.prefix, { tag1: "spmh", tag2: "wpw", tag3: "wrapper" })
});
if (WpwLogger.isSpmhLogLevel(this.cli.loglevel)) {
this._config.log.level = WpwLogger.toWpwLogLevel(this.cli.loglevel);
}
}
/**
* @private
*/
initPackageJson()
{
const pkgJsonFile = findDotJsonFileUpSync("package.json");
this._pkgJsonDir = pkgJsonFile.dir;
this._pkgJsonPath = pkgJsonFile.path;
this._pkgJson = merge({}, pkgJsonFile.data);
return this._pkgJson;
}
/**
* @private
* @param {string} base
* @param {string} name
* @param {Partial<IWpwSchema | IWpwBuildConfig>} config
*/
async resolvePaths(base, name, config)
{
let paths = config.paths; // @ts-ignore
const osTmp = os.tmpdir ? os.tmpdir() : os.tmpDir(),
defTmpDir = join(this._config.settings.cacheDir, name || "default", "temp"),
tempDir = osTmp ? `${osTmp}${sep}@spmhome${sep}${name}`.replace(`@spmhome${sep}@spmhome`, "@spmhome") : defTmpDir;
if (!paths) {
config.paths = apply(paths, {}); paths = config.paths;
}
paths.base = base;
paths.dist = resolvePath(base, paths.dist || "dist");
const ctx = paths.ctx ? resolvePath(base, paths.ctx) : base;
// if(!paths.ctx&&!ctx.endsWith("src")&&(await existsAsync(joinPath(ctx,"src")))){paths.ctx=joinPath(ctx,"src");}
paths.src = resolvePath(paths.ctx && !paths.src ? ctx : (paths.base, paths.src || (!paths.ctx ? "src" : ".")));
paths.ctx = ctx;
paths.temp = paths.temp && paths.temp !== defTmpDir ? paths.temp : tempDir;
if (!(await existsAsync(paths.temp))) { await createDirAsync(paths.temp); }
Object.entries(pickNot(paths, "dist", "temp")).forEach((e) =>
{
if (e[0] !== "src")
{ if (!existsSync(e[1]))
{ throw new SpmhError({
code: SpmhError.Code.ERROR_SCHEMA, message: `build path '${e[0]}'/'${e[1]}' does not exist`
});
}
}
else
{ e[1].split(/;|,|\|/).forEach((p) =>
{ if (!existsSync(p))
{ throw new SpmhError({
code: SpmhError.Code.ERROR_SCHEMA, message: `build path '${e[0]}'/'${p}' does not exist`
});
}
}); } });
return config;
};
/**
* @param {boolean} [keepMaxLine]
* @param {boolean} [toInstance]
* @returns {WpwLogger}
*/
syncLogConfigs(keepMaxLine, toInstance)
{
return /** @type {WpwLogger} */(WpwLogger.syncConfigs(this.logger, keepMaxLine, toInstance));
}
}
module.exports = WpwWrapper;