@lenne.tech/cli
Version:
lenne.Tech CLI: lt
120 lines (119 loc) • 5.14 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.apiNeedsPortPatch = apiNeedsPortPatch;
exports.appNeedsPortPatch = appNeedsPortPatch;
exports.deriveDbName = deriveDbName;
exports.deriveTestDbName = deriveTestDbName;
exports.deriveTicketDbName = deriveTicketDbName;
exports.resolveLayout = resolveLayout;
const fs_1 = require("fs");
const path_1 = require("path");
const workspace_integration_1 = require("./workspace-integration");
/**
* Detect whether the API project still has the legacy hardcoded `port: 3000`.
* Returns the file path if a patch is needed, null otherwise.
*/
function apiNeedsPortPatch(apiDir) {
const file = (0, path_1.join)(apiDir, 'src', 'config.env.ts');
if (!(0, fs_1.existsSync)(file))
return null;
const content = (0, fs_1.readFileSync)(file, 'utf8');
return /port:\s*3000\s*,/.test(content) ? file : null;
}
/**
* Detect whether the App project still has hardcoded `port: 3001` or a
* hardcoded vite-proxy `target: 'http://localhost:3000'`. Returns an
* array of file paths that need patching.
*/
function appNeedsPortPatch(appDir) {
const candidates = [(0, path_1.join)(appDir, 'nuxt.config.ts'), (0, path_1.join)(appDir, 'playwright.config.ts')];
return candidates.filter((file) => {
if (!(0, fs_1.existsSync)(file))
return false;
const c = (0, fs_1.readFileSync)(file, 'utf8');
return (/port:\s*3001\s*,/.test(c) ||
/target:\s*'http:\/\/localhost:3000'/.test(c) ||
/baseURL:\s*'http:\/\/localhost:3001'/.test(c) ||
/url:\s*'http:\/\/localhost:3001'/.test(c) ||
/host:\s*'http:\/\/localhost:3001'/.test(c) ||
// Unguarded Playwright `webServer` (no LT_DEV_ACTIVE guard) — patch it so
// `lt dev test`'s isolated stack is reused instead of a stray server.
(/webServer:\s*[[{]/.test(c) && !/webServer:\s*process\.env\.LT_DEV_ACTIVE/.test(c)));
});
}
/** Read `dbName` from the API config (defaults to `<slug>-local`). */
function deriveDbName(apiDir, slug) {
if (apiDir) {
const cfg = (0, path_1.join)(apiDir, 'src', 'config.env.ts');
if ((0, fs_1.existsSync)(cfg)) {
const content = (0, fs_1.readFileSync)(cfg, 'utf8');
const match = content.match(/dbName:\s*['"`]([^'"`]+)['"`]/);
if (match)
return match[1];
}
}
return `${slug}-local`;
}
/**
* Derive the dedicated database name for the `lt dev test` stack from the
* project's dev DB name. Distinct from both `<…>-local` (developer DB) and
* the API unit-test DB (`<…>-e2e`), so Playwright E2E never touches developer
* or API-test data.
*
* svl-sports-system-local → svl-sports-system-test
*
* Uses the `-test` suffix so it passes test-helper guards that only permit
* local/test databases (name ending in `-local` | `-ci` | `-e2e` | `-test`).
*/
function deriveTestDbName(devDbName) {
const base = devDbName.replace(/-(local|dev)$/i, '');
return `${base}-test`;
}
/**
* Derive the per-TICKET database name from the project's dev DB name, so each
* ticket worktree reads/writes its OWN database and tickets never collide.
*
* svl-sports-system-local + "2200" → svl-sports-system-2200
*
* The ticket's isolated `lt dev test` stack then derives its test DB from this
* via {@link deriveTestDbName} → `svl-sports-system-2200-test`.
*/
function deriveTicketDbName(devDbName, ticketId) {
const base = devDbName.replace(/-(local|dev)$/i, '');
return `${base}-${ticketId}`;
}
/**
* Resolve layout starting from `cwd`. Walks up to find a workspace if
* cwd is inside `projects/api/` or `projects/app/`.
*/
function resolveLayout(cwd, filesystem) {
const subContext = (0, workspace_integration_1.detectSubProjectContext)(cwd, filesystem);
if (subContext)
return monorepoLayout(subContext.workspaceRoot);
const layout = (0, workspace_integration_1.detectWorkspaceLayout)(cwd, filesystem);
if (layout.hasWorkspace)
return monorepoLayout(layout.workspaceDir);
const workspaceRoot = (0, workspace_integration_1.findWorkspaceRoot)(cwd, filesystem);
if (workspaceRoot)
return monorepoLayout(workspaceRoot);
// Standalone project — figure out if it's API or App.
const isApi = (0, fs_1.existsSync)((0, path_1.join)(cwd, 'src', 'config.env.ts')) || (0, fs_1.existsSync)((0, path_1.join)(cwd, 'nest-cli.json'));
const isApp = (0, fs_1.existsSync)((0, path_1.join)(cwd, 'nuxt.config.ts'));
return {
apiDir: isApi ? cwd : null,
appDir: isApp ? cwd : null,
root: cwd,
workspace: false,
};
}
/** Build the layout for an lt-monorepo workspace root. */
function monorepoLayout(workspaceRoot) {
const apiDir = (0, path_1.join)(workspaceRoot, 'projects', 'api');
const appDir = (0, path_1.join)(workspaceRoot, 'projects', 'app');
return {
apiDir: (0, fs_1.existsSync)(apiDir) ? apiDir : null,
appDir: (0, fs_1.existsSync)(appDir) ? appDir : null,
root: workspaceRoot,
workspace: true,
};
}