Files
manycoretech--aholo-viewer/scripts/package-utils.mjs
T
2026-07-13 13:18:05 +08:00

157 lines
4.5 KiB
JavaScript

import { spawnSync } from 'node:child_process';
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
import { dirname, isAbsolute, relative, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
export const workspaceRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
export function resolvePackageRoot(packageRootArg = process.argv[2]) {
const packageRoot = resolve(process.cwd(), packageRootArg ?? '.');
assertInsideDir(workspaceRoot, packageRoot, 'Package root');
const packageJsonPath = resolve(packageRoot, 'package.json');
if (!existsSync(packageJsonPath)) {
throw new Error(`Package root is missing package.json: ${packageRoot}`);
}
return packageRoot;
}
export function readPackageJson(packageRoot) {
return readJsonFile(resolve(packageRoot, 'package.json'), 'package metadata');
}
export function readJsonFile(filePath, label = 'JSON') {
try {
return JSON.parse(readFileSync(filePath, 'utf8'));
} catch (error) {
throw new Error(`Unable to read ${label} at ${filePath}.`, { cause: error });
}
}
export function resolvePackagePath(packageRoot, value, label) {
if (typeof value !== 'string' || value.trim() === '') {
throw new Error(`Missing ${label}.`);
}
const absolutePath = resolve(packageRoot, value);
assertInsideDir(packageRoot, absolutePath, label);
return absolutePath;
}
export function resolveWorkspacePath(value, label) {
if (typeof value !== 'string' || value.trim() === '') {
throw new Error(`Missing ${label}.`);
}
const absolutePath = resolve(workspaceRoot, value);
assertInsideDir(workspaceRoot, absolutePath, label);
return absolutePath;
}
export function assertInsideDir(parent, child, label) {
if (!isInsideDir(parent, child)) {
throw new Error(`${label} must stay inside ${parent}: ${child}`);
}
}
export function isInsideDir(parent, child) {
const relativePath = relative(resolve(parent), resolve(child));
return relativePath === '' || (!!relativePath && !relativePath.startsWith('..') && !isAbsolute(relativePath));
}
export function formatWorkspacePath(filePath) {
return toPosixPath(relative(workspaceRoot, resolve(filePath)));
}
export function statSafe(filePath) {
try {
return statSync(filePath);
} catch {
return undefined;
}
}
export function listFiles(directory, options = {}) {
if (!existsSync(directory)) {
return [];
}
const files = [];
const skipDirectories = new Set(options.skipDirectories ?? []);
for (const entry of readdirSync(directory, { withFileTypes: true })) {
if (entry.isDirectory() && skipDirectories.has(entry.name)) {
continue;
}
const entryPath = resolve(directory, entry.name);
if (entry.isDirectory()) {
files.push(...listFiles(entryPath, options));
continue;
}
if (entry.isFile()) {
files.push(entryPath);
}
}
return files;
}
export function readWebsiteLocales() {
const localeSourcePath = resolve(workspaceRoot, 'website/src/i18n/locales.ts');
const source = readFileSync(localeSourcePath, 'utf8');
const localeMatches = [...source.matchAll(/code:\s*["']([^"']+)["']/g)].map(match => match[1]);
if (localeMatches.length === 0) {
throw new Error(`Unable to read website locales from ${formatWorkspacePath(localeSourcePath)}.`);
}
return localeMatches;
}
export function getPnpmCommand() {
return process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm';
}
export function runCommand(command, args, options = {}) {
return spawnSync(command, args, {
cwd: options.cwd ?? workspaceRoot,
encoding: options.encoding,
env: options.env ?? process.env,
shell: options.shell ?? false,
stdio: options.stdio ?? 'inherit',
});
}
export function runCommandOrExit(command, args, options = {}) {
const result = runCommand(command, args, options);
if (result.status === 0) {
return result;
}
const cwd = options.cwd ?? workspaceRoot;
const label = options.label ?? `${command} ${args.join(' ')}`;
console.error(`[scripts] Command failed in ${cwd}: ${label}`);
if (result.error) {
console.error(result.error);
}
if (result.stderr) {
console.error(result.stderr);
}
process.exit(result.status ?? 1);
}
export function toPosixPath(value) {
return value.replace(/\\/g, '/');
}