mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
a04b587993
* chore(gates): derive the contracts export inventory from package.json R11's package-boundaries test pinned every packages/contracts export subpath by hand (~115 entries, compared with deepEqual), so every merge that touched packages/contracts/package.json also had to hand-edit the pin. Replace it with a structural check derived from the manifest itself: every exports target must resolve to an existing, tracked source file, and the number of resolved targets must equal Object.keys(manifest.exports).length. The must-not-resolve negative list (Node resolution enforces the exports map at runtime) is untouched. * chore(gates): restore exact-membership for the contracts export surface assertExportTargetsMatchManifest's two checks (targets resolve to tracked files, count equals manifest.exports keys) both read from the same manifest.exports object, so a subpath added or removed moves both sides together and the equality holds regardless -- the widen/shrink guarantee the deleted ~120-line CONTRACT_EXPORTS pin gave was silently gone (#2297 review). Add scripts/layering/contracts-exports.snapshot.json, an independently committed baseline regenerated by the new generate-contracts-exports-snapshot.ts, and deepEqual the live export specifiers against it. A subpath change now fails until the contributor reruns the generator and reviews the snapshot diff -- "run a script and commit its output" instead of hand-retyping an alphabetized array, so the original maintenance-burden goal holds too. Planted red: widened packages/contracts/package.json#exports with a throwaway "./planted-red-widen" subpath, then separately deleted the "./wait" subpath; `node --test --experimental-strip-types scripts/layering/package-boundaries.test.ts` failed both times on the new deepEqual with the regenerate-and-review message. Reverted before committing.
34 lines
1.6 KiB
TypeScript
34 lines
1.6 KiB
TypeScript
// Regenerates contracts-exports.snapshot.json from packages/contracts/package.json#exports.
|
|
//
|
|
// package-boundaries.test.ts diffs the live manifest's export specifiers against this committed
|
|
// snapshot so widening or shrinking `@agent-device/contracts`'s export surface fails the gate
|
|
// (the property the deleted ~120-line inline CONTRACT_EXPORTS pin used to give). The snapshot is a
|
|
// separate file rather than an inline list so an editor who adds or removes a contracts subpath
|
|
// runs this script and reviews the diff, instead of hand-retyping an alphabetized array.
|
|
//
|
|
// Run after any packages/contracts/package.json#exports change:
|
|
// node --experimental-strip-types scripts/layering/generate-contracts-exports-snapshot.ts
|
|
// then commit the resulting snapshot diff alongside the manifest change.
|
|
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
|
|
const repoRoot = path.resolve(import.meta.dirname, '../..');
|
|
const manifestFile = 'packages/contracts/package.json';
|
|
const snapshotFile = path.join(import.meta.dirname, 'contracts-exports.snapshot.json');
|
|
|
|
const manifest = JSON.parse(fs.readFileSync(path.join(repoRoot, manifestFile), 'utf8')) as {
|
|
name?: string;
|
|
exports?: Record<string, unknown>;
|
|
};
|
|
if (!manifest.name) throw new Error(`${manifestFile} has no "name"`);
|
|
|
|
const specifiers = Object.keys(manifest.exports ?? {})
|
|
.map((subpath) => path.posix.join(manifest.name!, subpath))
|
|
.sort();
|
|
|
|
fs.writeFileSync(snapshotFile, `${JSON.stringify(specifiers, null, 2)}\n`);
|
|
console.log(
|
|
`Wrote ${specifiers.length} export specifiers to ${path.relative(repoRoot, snapshotFile)}`,
|
|
);
|