- Removed orphaned __trace2.js (unnecessary escape error) - Fixed empty block statement in config-migrations.test.js busy-wait - Fixed empty block statement in metrics.test.js busy-wait - Auto-fixed 5 fixable warnings via eslint --fix - Remaining 547 warnings (require-await, no-unused-vars) are non-blocking code quality - 0 errors, 1633 tests pass
181 lines
6.9 KiB
JavaScript
181 lines
6.9 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Refactor helper: rewrites require('./xxx') / require('../xxx') paths in
|
|
* dashcaddy-api to point to the new src/<subdir>/xxx.js locations.
|
|
*
|
|
* Algorithm:
|
|
* 1. For each require() call with a relative spec:
|
|
* 2. If the resolved file exists, leave it alone.
|
|
* 3. If the resolved file does NOT exist, the bare name of the spec
|
|
* (or the directory name 'dns-providers') might be one of the
|
|
* modules that was moved out of the repo root. In that case, rewrite
|
|
* the spec to the correct relative path to the new location.
|
|
* 4. Otherwise leave alone.
|
|
*/
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const REPO = process.cwd();
|
|
|
|
// Map: bare module name (no extension) -> new repo-relative path (no extension)
|
|
const NEW_LOCATIONS = {
|
|
'auth-manager': 'src/managers/auth-manager',
|
|
'credential-manager': 'src/managers/credential-manager',
|
|
'license-manager': 'src/managers/license-manager',
|
|
'port-lock-manager': 'src/managers/port-lock-manager',
|
|
'state-manager': 'src/managers/state-manager',
|
|
'notification-manager': 'src/managers/notification-manager',
|
|
'resource-monitor': 'src/managers/resource-monitor',
|
|
'config-drift-detector': 'src/managers/config-drift-detector',
|
|
'auto-restart-manager': 'src/managers/auto-restart-manager',
|
|
'update-manager': 'src/managers/update-manager',
|
|
'dependency-manager': 'src/managers/dependency-manager',
|
|
'csrf-protection': 'src/security/csrf-protection',
|
|
'crypto-utils': 'src/security/crypto-utils',
|
|
'docker-security': 'src/security/docker-security',
|
|
'input-validator': 'src/security/input-validator',
|
|
'keychain-manager': 'src/security/keychain-manager',
|
|
'log-digest': 'src/security/log-digest',
|
|
'audit-logger': 'src/security/audit-logger',
|
|
'docker-maintenance': 'src/docker/docker-maintenance',
|
|
'app-templates': 'src/docker/app-templates',
|
|
'self-updater': 'src/docker/self-updater',
|
|
'dns-propagation': 'src/dns/dns-propagation',
|
|
'recipe-templates': 'src/recipes/recipe-templates',
|
|
'bundled-workflows': 'src/recipes/bundled-workflows',
|
|
'health-checker': 'src/monitoring/health-checker',
|
|
'metrics': 'src/monitoring/metrics',
|
|
'ssl-monitor': 'src/monitoring/ssl-monitor',
|
|
'backup-manager': 'src/utilities/backup-manager',
|
|
'error-handler': 'src/utilities/error-handler',
|
|
'errors': 'src/utilities/errors',
|
|
'fs-helpers': 'src/utilities/fs-helpers',
|
|
'pagination': 'src/utilities/pagination',
|
|
'url-resolver': 'src/utilities/url-resolver',
|
|
'config-schema': 'src/utilities/config-schema',
|
|
'constants': 'src/utilities/constants',
|
|
'middleware': 'src/utilities/middleware',
|
|
'startup-validator': 'src/utilities/startup-validator',
|
|
'cache-config': 'src/utilities/cache-config',
|
|
};
|
|
|
|
const SKIP_DIRS = new Set(['node_modules', '.git']);
|
|
const SKIP_FILE_PATTERNS = [/\/scripts\/refactor-requires\.js$/];
|
|
|
|
function* walk(dir) {
|
|
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
if (SKIP_DIRS.has(entry.name)) continue;
|
|
const full = path.join(dir, entry.name);
|
|
if (entry.isDirectory()) {
|
|
yield* walk(full);
|
|
} else if (entry.name.endsWith('.js')) {
|
|
yield full;
|
|
}
|
|
}
|
|
}
|
|
|
|
function toRelativeFromFile(filePath, targetRel) {
|
|
const fromDir = path.dirname(filePath);
|
|
const targetAbs = path.resolve(REPO, targetRel);
|
|
let rel = path.relative(fromDir, targetAbs);
|
|
if (!rel.startsWith('.')) rel = './' + rel;
|
|
return rel.split(path.sep).join('/');
|
|
}
|
|
|
|
function fileExistsWithJsOrIndex(p) {
|
|
// exists if p is a file, or p is a dir with index.js
|
|
try {
|
|
if (fs.existsSync(p) && fs.statSync(p).isFile()) return true;
|
|
} catch (_) {}
|
|
try {
|
|
if (fs.existsSync(p + '.js') && fs.statSync(p + '.js').isFile()) return true;
|
|
} catch (_) {}
|
|
try {
|
|
if (
|
|
fs.existsSync(p) &&
|
|
fs.statSync(p).isDirectory() &&
|
|
fs.existsSync(path.join(p, 'index.js'))
|
|
)
|
|
{return true;}
|
|
} catch (_) {}
|
|
return false;
|
|
}
|
|
|
|
function refactor(filePath) {
|
|
const relFile = path.relative(REPO, filePath);
|
|
if (SKIP_FILE_PATTERNS.some((re) => re.test(relFile))) return false;
|
|
|
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
let changed = false;
|
|
|
|
const requireRe = /require\(\s*(['"])([^'"]+)\1\s*\)/g;
|
|
const newContent = content.replace(requireRe, (full, quote, spec) => {
|
|
if (!spec.startsWith('.')) return full; // package require, leave alone
|
|
const fromDir = path.dirname(filePath);
|
|
const resolvedBase = path.resolve(fromDir, spec);
|
|
// If the resolved file exists, the require is correct as-is.
|
|
if (fileExistsWithJsOrIndex(resolvedBase)) {
|
|
// But — check for the special case: require to <REPO>/dns-providers/x
|
|
// which after move becomes <REPO>/src/dns/dns-providers/x — wait,
|
|
// that doesn't exist anymore. The dir was moved.
|
|
const dnsProvidersOld = path.resolve(REPO, 'dns-providers');
|
|
if (
|
|
resolvedBase === dnsProvidersOld ||
|
|
resolvedBase.startsWith(dnsProvidersOld + path.sep)
|
|
) {
|
|
const subPath = resolvedBase === dnsProvidersOld ? '' : resolvedBase.slice(dnsProvidersOld.length + 1);
|
|
const newResolved = path.resolve(REPO, 'src/dns/dns-providers', subPath);
|
|
let rel = path.relative(fromDir, newResolved);
|
|
if (!rel.startsWith('.')) rel = './' + rel;
|
|
const newSpec = rel.split(path.sep).join('/');
|
|
changed = true;
|
|
return `require(${quote}${newSpec}${quote})`;
|
|
}
|
|
return full;
|
|
}
|
|
// The file does not exist. Check if the bare name is a moved module.
|
|
const bare = path.basename(resolvedBase);
|
|
if (bare in NEW_LOCATIONS) {
|
|
const target = NEW_LOCATIONS[bare];
|
|
const newSpec = toRelativeFromFile(filePath, target);
|
|
changed = true;
|
|
return `require(${quote}${newSpec}${quote})`;
|
|
}
|
|
// Bare not in map. Check for the special case: the spec points into
|
|
// the OLD dns-providers dir (now src/dns/dns-providers). E.g. spec
|
|
// could be '../dns-providers/registry' or './dns-providers/registry'
|
|
// from somewhere else.
|
|
if (spec.includes('dns-providers')) {
|
|
const dnsProvidersOld = path.resolve(REPO, 'dns-providers');
|
|
if (
|
|
resolvedBase === dnsProvidersOld ||
|
|
resolvedBase.startsWith(dnsProvidersOld + path.sep)
|
|
) {
|
|
const subPath =
|
|
resolvedBase === dnsProvidersOld ? '' : resolvedBase.slice(dnsProvidersOld.length + 1);
|
|
const newResolved = path.resolve(REPO, 'src/dns/dns-providers', subPath);
|
|
let rel = path.relative(fromDir, newResolved);
|
|
if (!rel.startsWith('.')) rel = './' + rel;
|
|
const newSpec = rel.split(path.sep).join('/');
|
|
changed = true;
|
|
return `require(${quote}${newSpec}${quote})`;
|
|
}
|
|
}
|
|
return full;
|
|
});
|
|
|
|
if (changed) {
|
|
fs.writeFileSync(filePath, newContent);
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
let count = 0;
|
|
for (const file of walk(REPO)) {
|
|
if (refactor(file)) {
|
|
count += 1;
|
|
console.log('rewrote', path.relative(REPO, file));
|
|
}
|
|
}
|
|
console.log(`\nDone: rewrote ${count} file(s).`);
|