Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | import { readFileSync, existsSync } from 'fs';
import path from 'path';
import { globSync } from 'glob';
import { getRepoRoot, getLernaJson, getConfig } from './config.js';
let cachedPackages = null;
export function discoverPackages() {
if (cachedPackages) return cachedPackages;
const root = getRepoRoot();
const lerna = getLernaJson();
if (!lerna || !lerna.packages) {
throw new Error('lerna.json not found or missing "packages" field');
}
// Discovery sources: lerna.json's `packages` globs plus any `additionalPackages`
// configured in package-release.config.json. The latter lets the release CLI
// manage published Tier-2 packages that live OUTSIDE lerna's package list
// (e.g. `design-tokens`, which is intentionally kept out of lerna.json so
// SFCI's `lerna-publish` step never touches it) — so `detect-bumps`, `tag`,
// `github`, and `changelog` still see them. Tier classification is unaffected:
// classifyTier() reads `release-cycle-aligned-packages`, so an additional
// package that isn't in that list stays Tier 2.
const config = getConfig();
const patterns = [...lerna.packages, ...(config.additionalPackages || [])];
const pkgs = [];
const seenPaths = new Set();
for (const pattern of patterns) {
const pkgJsonPath = path.join(root, pattern, 'package.json');
const matches = globSync(pkgJsonPath);
if (matches.length === 0 && existsSync(pkgJsonPath)) {
matches.push(pkgJsonPath);
}
for (const match of matches) {
if (seenPaths.has(match)) continue; // de-dupe across the two sources
seenPaths.add(match);
const manifest = JSON.parse(readFileSync(match, 'utf8'));
const pkgDir = path.dirname(match);
pkgs.push({
name: manifest.name,
version: manifest.version,
private: manifest.private === true,
path: pkgDir,
relativePath: path.relative(root, pkgDir),
manifestPath: match,
});
}
}
cachedPackages = pkgs;
return pkgs;
}
export function resolvePackage(nameOrPath) {
const pkgs = discoverPackages();
const normalized = nameOrPath.replace(/\/$/, '');
const byName = pkgs.find((p) => p.name === normalized);
if (byName) return byName;
const byShortName = pkgs.find((p) => {
const shortName = p.name.split('/').pop();
return shortName === normalized;
});
if (byShortName) return byShortName;
const byPath = pkgs.find(
(p) => p.relativePath === normalized || p.path === normalized,
);
if (byPath) return byPath;
return null;
}
export function resolvePackages(nameOrPathList) {
const resolved = [];
for (const item of nameOrPathList) {
const pkg = resolvePackage(item);
if (!pkg) {
throw new Error(
`Package "${item}" not found in lerna.json packages. ` +
`Available packages: ${discoverPackages().map((p) => p.name).join(', ')}`,
);
}
resolved.push(pkg);
}
return resolved;
}
|