Merge pull request '[E00-S01-T11] apps/packages/extensions separated' (#378) from feature/164 into main
CI / Frozen lockfile install (push) Successful in 52s

This commit was merged in pull request #378.
This commit is contained in:
2026-08-28 22:50:38 +00:00
+190
View File
@@ -0,0 +1,190 @@
/**
* Workspace layout test — locks in the [E00-S01-T11] apps/packages/extensions
* separation for the workspace.
*
* Acceptance criteria covered (each test fails without the committed layout):
* - "apps, packages and extensions are separated in the workspace layout" →
* the repo root contains exactly the three top-level package group
* directories apps/, packages/, extensions/; every workspace package.json
* lives exactly one level below one of them (never at the root, never in
* another directory, never nested deeper); `pnpm-workspace.yaml` declares
* one glob per group and `dependency-boundaries.json` maps the same three
* groups to the same three directories.
* - "each package sits in the correct top-level directory" → the bootstrap
* packages are found where their group says: `@personal-blog/server` in
* apps/, `@personal-blog/core` in packages/, `@personal-blog/example-
* extension` in extensions/; the discovered workspace package set is
* exactly the expected one, and every discovered package has a lockfile
* importer (layout ↔ lockfile parity).
*
* Run: `node --test tests/workspace-layout.test.mjs`
* (node:test — built into Node >= 18; no dependencies, lockfile untouched.)
*/
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync, readdirSync, statSync } from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const read = (relPath) => readFileSync(path.join(REPO_ROOT, relPath), 'utf8');
/** The three top-level package group directories of the separated layout. */
const TOP_LEVEL_GROUPS = ['apps', 'packages', 'extensions'];
/** Expected bootstrap packages: package name -> top-level directory it must sit in. */
const EXPECTED_PACKAGES = {
'@personal-blog/server': 'apps/server',
'@personal-blog/core': 'packages/core',
'@personal-blog/example-extension': 'extensions/example',
};
/** Directories never scanned as package sources. */
const IGNORED_DIRS = new Set(['node_modules', 'dist', 'coverage', '.git', '.pnpm-store']);
// ---------------------------------------------------------------------------
// Layout helpers
// ---------------------------------------------------------------------------
function isDirectory(p) {
try {
return statSync(p).isDirectory();
} catch {
return false;
}
}
/**
* Recursively collects every package.json path under a directory, as a
* repo-root-relative posix path (the root workspace manifest itself is
* included as "package.json").
*/
function collectPackageJsonPaths(dir) {
const results = [];
for (const entry of readdirSync(dir, { withFileTypes: true })) {
if (entry.isDirectory()) {
if (!IGNORED_DIRS.has(entry.name)) {
results.push(...collectPackageJsonPaths(path.join(dir, entry.name)));
}
} else if (entry.name === 'package.json') {
results.push(path.relative(REPO_ROOT, path.join(dir, entry.name)).split(path.sep).join('/'));
}
}
return results;
}
/**
* Validates the placement of a repo-root-relative package.json path. A
* workspace package must be exactly `<group>/<name>/package.json` under one of
* the three top-level groups; the root workspace manifest ("package.json") is
* the one allowed exception. Returns an error message, or null when the
* placement is correct.
*/
function placementError(relPath) {
if (relPath === 'package.json') return null; // workspace root manifest, not a package
const parts = relPath.split('/');
if (parts.length !== 3 || parts[2] !== 'package.json') {
return `"${relPath}" must be <group>/<name>/package.json (exactly one level below a top-level group directory)`;
}
if (!TOP_LEVEL_GROUPS.includes(parts[0])) {
return `"${relPath}" must sit under apps/, packages/ or extensions/ (got "${parts[0]}")`;
}
return null;
}
// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------
test('the workspace root contains exactly the three separated top-level group directories', () => {
for (const group of TOP_LEVEL_GROUPS) {
assert.ok(
isDirectory(path.join(REPO_ROOT, group)),
`top-level directory "${group}/" must exist (apps/packages/extensions separated)`,
);
}
});
test('every workspace package.json sits exactly one level below its top-level group directory', () => {
const manifests = collectPackageJsonPaths(REPO_ROOT);
const packageManifests = manifests.filter((rel) => rel !== 'package.json');
assert.ok(packageManifests.length > 0, 'the workspace must contain at least one package manifest');
for (const rel of packageManifests) {
const error = placementError(rel);
assert.equal(error, null, error);
}
});
test('each expected package sits in the correct top-level directory', () => {
for (const [name, dir] of Object.entries(EXPECTED_PACKAGES)) {
const manifest = JSON.parse(read(path.join(dir, 'package.json')));
assert.equal(
manifest.name,
name,
`"${dir}/package.json" must declare name "${name}" (each package sits in its correct top-level directory)`,
);
}
});
test('the discovered workspace package set is exactly the expected bootstrap set', () => {
const manifests = collectPackageJsonPaths(REPO_ROOT).filter((rel) => rel !== 'package.json');
const discoveredDirs = new Set(manifests.map((rel) => rel.replace(/\/package\.json$/, '')));
assert.deepEqual(discoveredDirs, new Set(Object.values(EXPECTED_PACKAGES)));
});
test('pnpm-workspace.yaml declares one group glob per top-level group directory', () => {
const workspace = read('pnpm-workspace.yaml');
const packagesSection = workspace.slice(workspace.indexOf('packages:'));
const globs = [...packagesSection.matchAll(/^\s*-\s*'([^']+)'\s*$/gm)].map((m) => m[1]);
assert.deepEqual(
globs,
TOP_LEVEL_GROUPS.map((g) => `${g}/*`),
'pnpm-workspace.yaml must declare exactly apps/*, packages/* and extensions/*',
);
});
test('dependency-boundaries.json maps the three groups to the same top-level directories', () => {
const rule = JSON.parse(read('dependency-boundaries.json'));
for (const group of TOP_LEVEL_GROUPS) {
assert.equal(
rule.groups?.[group]?.path,
`${group}/`,
`dependency-boundaries.json must map group "${group}" to path "${group}/"`,
);
}
});
test('every discovered workspace package has a lockfile importer (layout ↔ lockfile parity)', () => {
const lockfile = read('pnpm-lock.yaml');
const manifests = collectPackageJsonPaths(REPO_ROOT).filter((rel) => rel !== 'package.json');
for (const rel of manifests) {
const importer = rel.replace(/\/package\.json$/, '');
assert.ok(
lockfile.includes(` ${importer}:`),
`pnpm-lock.yaml must contain an importer for "${importer}" (every package in the layout must be a workspace member)`,
);
}
});
test('the placement validation flags mis-placed packages (non-vacuous probe)', () => {
const valid = [
'apps/server/package.json',
'packages/core/package.json',
'extensions/example/package.json',
'package.json', // workspace root manifest
];
for (const rel of valid) {
assert.equal(placementError(rel), null, `"${rel}" must be a valid placement`);
}
const invalid = [
'lib/shared/package.json', // no top-level group at all
'apps/package.json', // manifest directly in a group dir (no package name level)
'packages/a/b/package.json', // nested deeper than one level
'docs/package.json', // outside the three groups
];
for (const rel of invalid) {
assert.notEqual(placementError(rel), null, `"${rel}" must be flagged as mis-placed`);
}
});