6ecb2c366f
Publish snapshot / snapshot (push) Successful in 1m2s
[fix] default parameter run records parameters in session for replay[fix] remove default parameters for several cubes
59 lines
2.1 KiB
JavaScript
59 lines
2.1 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Prints the publishable workspace package directories, dependencies first.
|
|
*
|
|
* `packages/*` in alphabetical order puts `nopy` ahead of the `nopy-cube` it
|
|
* depends on, which leaves a window where the registry holds a package whose
|
|
* dependency does not exist yet. Ordering the publish by the workspace graph
|
|
* closes it. One directory per line, so the caller can `for dir in $(…)`.
|
|
*/
|
|
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
|
|
const PACKAGES_DIR = 'packages';
|
|
const RANGE_FIELDS = ['dependencies', 'peerDependencies', 'optionalDependencies'];
|
|
|
|
const packages = fs
|
|
.readdirSync(PACKAGES_DIR)
|
|
.map((name) => path.join(PACKAGES_DIR, name))
|
|
.filter((dir) => fs.existsSync(path.join(dir, 'package.json')))
|
|
.map((dir) => ({ dir, manifest: JSON.parse(fs.readFileSync(path.join(dir, 'package.json'))) }))
|
|
.filter(({ manifest }) => !manifest.private);
|
|
|
|
const dirByName = new Map(packages.map(({ dir, manifest }) => [manifest.name, dir]));
|
|
|
|
/** The other workspace packages this one links to, by directory. */
|
|
const dependenciesOf = ({ manifest }) =>
|
|
RANGE_FIELDS.flatMap((field) => Object.entries(manifest[field] ?? {}))
|
|
.filter(([, range]) => range.startsWith('workspace:'))
|
|
.map(([name]) => dirByName.get(name))
|
|
.filter((dir) => dir !== undefined);
|
|
|
|
const ordered = [];
|
|
const emitted = new Set();
|
|
const visiting = new Set();
|
|
|
|
const visit = (pkg) => {
|
|
if (emitted.has(pkg.dir)) return;
|
|
if (visiting.has(pkg.dir)) {
|
|
// pnpm rejects a workspace cycle at install time, so reaching this means
|
|
// something stranger than a bad dependency edge.
|
|
throw new Error(`Dependency cycle in the workspace, at ${pkg.dir}`);
|
|
}
|
|
visiting.add(pkg.dir);
|
|
for (const dir of dependenciesOf(pkg)) {
|
|
visit(packages.find((candidate) => candidate.dir === dir));
|
|
}
|
|
visiting.delete(pkg.dir);
|
|
emitted.add(pkg.dir);
|
|
ordered.push(pkg.dir);
|
|
};
|
|
|
|
// Alphabetical among packages the graph does not separate, so the output is
|
|
// stable across runs and platforms.
|
|
for (const pkg of [...packages].sort((a, b) => a.dir.localeCompare(b.dir))) visit(pkg);
|
|
|
|
console.log(ordered.join('\n'));
|