@itrocks/compose
Version:
Class compositions via configuration file, enabling mixins addition and module exports replacement
107 lines • 4.79 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.compose = compose;
const class_type_1 = require("@itrocks/class-type");
const class_type_2 = require("@itrocks/class-type");
const uses_1 = require("@itrocks/uses");
const node_path_1 = require("node:path");
const EXCLUDE = 2;
const ORIGINAL = 1;
const REPLACEMENT = 0;
const cache = {};
const replacements = {};
function configPath(baseDir, config) {
return (0, node_path_1.normalize)(require.resolve((config[0] === '/') ? (baseDir + '/' + config) : config));
}
function compose(baseDir, config) {
// initReplacements
for (let [module, configReplacements] of Object.entries(config)) {
let moduleExport;
[module, moduleExport] = module.split(':');
module = configPath(baseDir, module);
moduleExport ??= 'default';
replacements[module] ??= {};
replacements[module][moduleExport] = [];
for (let replacement of Array.isArray(configReplacements) ? configReplacements : [configReplacements]) {
let replacementExport;
[replacement, replacementExport] = replacement.split(':');
replacement = configPath(baseDir, replacement);
replacementExport ??= 'default';
replacements[module][moduleExport].push({ script: replacement, export: replacementExport });
}
}
const Module = require('module');
const superRequire = Module.prototype.require;
Module.prototype.require = function (file) {
// resolve and normalize
if (file[0] === '.') {
file = this.path + ((this.path[this.path.length - 1] === '/') ? file : ('/' + file));
}
file = (0, node_path_1.normalize)(require.resolve(file));
// from cache
if (cache[file]) {
const which = cache[file][EXCLUDE].includes(this.filename)
? ORIGINAL
: REPLACEMENT;
return cache[file][which];
}
// no replacement
let exportEntries = replacements[file];
if (!exportEntries) {
const original = superRequire.call(this, ...arguments);
cache[file] = [original, original, []];
return original;
}
// require original
const module = { __esModule: true };
const original = superRequire.call(this, ...arguments);
const replacementFiles = new Array();
cache[file] = [module, original, replacementFiles];
Object.assign(module, original);
// compose
for (let [moduleExport, replacementEntries] of Object.entries(exportEntries)) {
if (!original[moduleExport]) {
if ((moduleExport === 'default') && !original.default) {
moduleExport = Object.keys(original)[0];
}
else {
throw 'Not found original ' + file + ':' + moduleExport;
}
}
const replacementTypes = replacementEntries.map(entry => {
if (!replacementFiles.includes(entry.script)) {
replacementFiles.push(entry.script);
}
const replacementModule = this.require(entry.script);
if (!replacementModule[entry.export]) {
if ((entry.export === 'default') && !replacementModule.default) {
entry.export = Object.keys(replacementModule)[0];
}
else {
throw 'Not found replacement ' + entry.script + ':' + entry.export;
}
}
return replacementModule[entry.export];
});
const originalType = original[moduleExport];
let replacementType;
for (let replacementTypeIndex = 0; replacementTypeIndex < replacementTypes.length; replacementTypeIndex++) {
if ((0, class_type_2.isAnyFunction)(replacementTypes[replacementTypeIndex])
|| (0, class_type_1.inherits)(replacementTypes[replacementTypeIndex], originalType)) {
replacementType = replacementTypes.splice(replacementTypeIndex, 1)[0];
break;
}
}
const replacementExport = replacementType
? (replacementTypes.length ? (0, uses_1.Uses)(...replacementTypes)(replacementType) : replacementType)
: (0, uses_1.Uses)(...replacementTypes)(originalType);
for (const [name, type] of Object.entries(original)) {
if (type === originalType) {
module[name] = replacementExport;
}
}
}
return module;
};
}
//# sourceMappingURL=compose.js.map