cartodb-4.42/webpack/v4/gearAwareResolver.js
2024-04-06 05:25:13 +00:00

138 lines
3.7 KiB
JavaScript

const { resolve, join, sep } = require('path');
const fs = require('fs');
// Detect existing gears
const gearPaths = [
join(__dirname, '../../gears'),
join(__dirname, '../../private_gears')
]
.filter(gearPath => fs.existsSync(gearPath))
.reduce((gears, gearsDir) => {
fs.readdirSync(gearsDir).forEach((gearName) => { gears[gearName] = resolve(gearsDir, gearName); });
return gears;
}, {})
;
const fileCache = {};
const gearResolved = new Set();
const ROOT_DIR = resolve(__dirname, '../../');
function rootDir (file, opts = {}) {
if (fileCache[file] === undefined || opts.skipCache) {
// Try to find the file in gears
for (let [gearName, gearPath] of Object.entries(gearPaths)) {
let fileGearPath = join(gearPath, file);
let fileExistsAndBoundedToGear =
fs.existsSync(fileGearPath) &&
fs.lstatSync(fileGearPath).isFile() &&
// Check that the file is not from outside the gear path
// PE, using ../..
resolve(fileGearPath).startsWith(gearPath)
;
// Try to look for full folder overriding, preceded by @
if (!fileExistsAndBoundedToGear) {
let pathParts = file.split(sep);
pathParts.some((pathPart, pathPartIdx) => {
fileGearPath = pathParts.slice(0, pathPartIdx).join(sep);
if (fileGearPath) fileGearPath += sep;
fileGearPath +=
'@' + pathPart + sep +
pathParts.slice(pathPartIdx + 1).join(sep)
;
fileGearPath = join(gearPath, fileGearPath);
fileExistsAndBoundedToGear =
fs.existsSync(fileGearPath) &&
fs.lstatSync(fileGearPath).isDirectory() &&
// Check that the file is not from outside the gear path
// PE, using ../..
resolve(fileGearPath).startsWith(gearPath)
;
return fileExistsAndBoundedToGear;
});
}
if (fileExistsAndBoundedToGear) {
fileCache[file] = {
path: fileGearPath,
gear: gearName
};
gearResolved.add(fileCache[file].path);
break;
}
}
// Find the file in project path if not in gear
if (fileCache[file] === undefined) {
fileCache[file] = {
path: resolve(ROOT_DIR, file),
gear: null
};
gearResolved.add(fileCache[file].path);
}
}
file = fileCache[file];
if (!opts.includeGear) {
file = file.path;
}
return file;
}
// See https://github.com/webpack/webpack/blob/8a7597aa6eb2eef66a8f9db3a0c49bcb96022a94/lib/NormalModuleReplacementPlugin.js
// See https://webpack.js.org/plugins/normal-module-replacement-plugin/
class GearResolverPlugin {
_resolve (result, attrName) {
if (!result) return;
if (/^!/.test(result[attrName])) return result;
let path = result[attrName].startsWith('/')
? result[attrName]
: join(result.context, result[attrName])
;
let relPath = result.context
? path.replace(new RegExp('^' + ROOT_DIR + '/?'), '')
: result[attrName]
;
if (gearResolved.has(relPath)) {
return result;
} else {
const file = rootDir(relPath, { includeGear: true });
if (file.gear !== null) { // The file has been overridden by a gear
result[attrName] = file.path;
}
return result;
}
}
apply (compiler) {
compiler.hooks.normalModuleFactory.tap(
'GearResolverPlugin',
nmf => {
nmf.hooks.afterResolve.tap('NormalModuleReplacementPlugin', result => {
if (!result) return;
return this._resolve(result, 'resource');
});
})
;
}
}
module.exports = {
rootDir: rootDir,
GearResolverPlugin: GearResolverPlugin
};