- Updated ESLint configuration to enforce stricter import rules for the @customer-portal/domain package, promoting better import hygiene and preventing deep imports. - Refactored various files across the BFF and portal applications to comply with the new import rules, ensuring that only the appropriate modules are imported from the domain. - Cleaned up unused imports and optimized code structure for improved maintainability and clarity. - Updated documentation to reflect changes in import practices and domain structure.
130 lines
4.4 KiB
JavaScript
130 lines
4.4 KiB
JavaScript
import fs from "node:fs/promises";
|
|
import path from "node:path";
|
|
|
|
const ROOT = process.cwd();
|
|
const TARGET_DIRS = [
|
|
path.join(ROOT, "apps", "bff", "src"),
|
|
path.join(ROOT, "apps", "portal", "src"),
|
|
];
|
|
|
|
const FILE_EXTS = new Set([".ts", ".tsx"]);
|
|
|
|
async function* walk(dir) {
|
|
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
for (const e of entries) {
|
|
const p = path.join(dir, e.name);
|
|
if (e.isDirectory()) {
|
|
if (e.name === "node_modules" || e.name === "dist" || e.name.startsWith(".")) continue;
|
|
yield* walk(p);
|
|
} else if (e.isFile()) {
|
|
if (FILE_EXTS.has(path.extname(e.name))) yield p;
|
|
}
|
|
}
|
|
}
|
|
|
|
function replaceProvidersDeepImports(code) {
|
|
// "@customer-portal/domain/<module>/providers/<anything>" -> ".../<module>/providers"
|
|
return code
|
|
.replaceAll(
|
|
/from\s+"@customer-portal\/domain\/([a-z-]+)\/providers\/[^"]+"/g,
|
|
'from "@customer-portal/domain/$1/providers"'
|
|
)
|
|
.replaceAll(
|
|
/from\s+'@customer-portal\/domain\/([a-z-]+)\/providers\/[^']+'/g,
|
|
"from '@customer-portal/domain/$1/providers'"
|
|
);
|
|
}
|
|
|
|
function replaceCommonProviderTypes(code) {
|
|
// Move provider response wrapper types out of common root -> common/providers
|
|
// Only touches *type-only* imports to avoid moving runtime exports accidentally.
|
|
return code
|
|
.replaceAll(
|
|
/import\s+type\s+\{([^}]*)\}\s+from\s+"@customer-portal\/domain\/common";/g,
|
|
(m, spec) => {
|
|
const s = String(spec);
|
|
const needsMove =
|
|
s.includes("WhmcsResponse") || s.includes("WhmcsErrorResponse") || s.includes("SalesforceResponse");
|
|
if (!needsMove) return m;
|
|
return `import type {${spec}} from "@customer-portal/domain/common/providers";`;
|
|
}
|
|
)
|
|
.replaceAll(
|
|
/import\s+type\s+\{([^}]*)\}\s+from\s+'@customer-portal\/domain\/common';/g,
|
|
(m, spec) => {
|
|
const s = String(spec);
|
|
const needsMove =
|
|
s.includes("WhmcsResponse") || s.includes("WhmcsErrorResponse") || s.includes("SalesforceResponse");
|
|
if (!needsMove) return m;
|
|
return `import type {${spec}} from '@customer-portal/domain/common/providers';`;
|
|
}
|
|
);
|
|
}
|
|
|
|
function replaceProvidersNamespaceImports(code) {
|
|
// import { Providers } from "@customer-portal/domain/<module>";
|
|
// import { Providers as Foo } from "@customer-portal/domain/<module>";
|
|
return code
|
|
.replaceAll(
|
|
/import\s+\{\s*Providers\s*\}\s+from\s+"@customer-portal\/domain\/([a-z-]+)";/g,
|
|
'import * as Providers from "@customer-portal/domain/$1/providers";'
|
|
)
|
|
.replaceAll(
|
|
/import\s+\{\s*Providers\s+as\s+([A-Za-z_$][A-Za-z0-9_$]*)\s*\}\s+from\s+"@customer-portal\/domain\/([a-z-]+)";/g,
|
|
'import * as $1 from "@customer-portal/domain/$2/providers";'
|
|
)
|
|
.replaceAll(
|
|
/import\s+\{\s*Providers\s*\}\s+from\s+'@customer-portal\/domain\/([a-z-]+)';/g,
|
|
"import * as Providers from '@customer-portal/domain/$1/providers';"
|
|
)
|
|
.replaceAll(
|
|
/import\s+\{\s*Providers\s+as\s+([A-Za-z_$][A-Za-z0-9_$]*)\s*\}\s+from\s+'@customer-portal\/domain\/([a-z-]+)';/g,
|
|
"import * as $1 from '@customer-portal/domain/$2/providers';"
|
|
);
|
|
}
|
|
|
|
function replaceToolkitPaginationHelper(code) {
|
|
if (!code.includes("@customer-portal/domain/toolkit/validation/helpers")) return code;
|
|
let next = code;
|
|
|
|
next = next
|
|
.replaceAll(
|
|
/import\s+\{\s*createPaginationSchema\s*\}\s+from\s+"@customer-portal\/domain\/toolkit\/validation\/helpers";/g,
|
|
'import { Validation } from "@customer-portal/domain/toolkit";'
|
|
)
|
|
.replaceAll(
|
|
/import\s+\{\s*createPaginationSchema\s*\}\s+from\s+'@customer-portal\/domain\/toolkit\/validation\/helpers';/g,
|
|
"import { Validation } from '@customer-portal/domain/toolkit';"
|
|
);
|
|
|
|
// Update call sites
|
|
next = next.replaceAll(/\bcreatePaginationSchema\b/g, "Validation.createPaginationSchema");
|
|
|
|
return next;
|
|
}
|
|
|
|
function transform(code) {
|
|
let next = code;
|
|
next = replaceProvidersDeepImports(next);
|
|
next = replaceCommonProviderTypes(next);
|
|
next = replaceProvidersNamespaceImports(next);
|
|
next = replaceToolkitPaginationHelper(next);
|
|
return next;
|
|
}
|
|
|
|
let changedFiles = 0;
|
|
for (const dir of TARGET_DIRS) {
|
|
for await (const file of walk(dir)) {
|
|
const before = await fs.readFile(file, "utf8");
|
|
const after = transform(before);
|
|
if (after !== before) {
|
|
await fs.writeFile(file, after, "utf8");
|
|
changedFiles += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log(`codemod-domain-imports: updated ${changedFiles} file(s)`);
|
|
|
|
|