docs: document root guard scripts

This commit is contained in:
Peter Steinberger
2026-06-04 23:30:59 -04:00
parent 74f3baebb7
commit 978fdd7d2a
10 changed files with 121 additions and 0 deletions

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env node
// Runs knip unused-file detection and compares results to the allowlist.
import { spawn } from "node:child_process";
import { fileURLToPath } from "node:url";
import {
@@ -8,9 +9,21 @@ import {
import { createPnpmRunnerSpawnSpec } from "./pnpm-runner.mjs";
const KNIP_VERSION = "6.8.0";
/**
* Timeout for the unused-file knip child process.
*/
export const KNIP_TIMEOUT_MS = 10 * 60 * 1000;
/**
* Grace period before force-killing a timed-out knip child process.
*/
export const KNIP_KILL_GRACE_MS = 5_000;
/**
* Heartbeat interval used while knip runs without output.
*/
export const KNIP_HEARTBEAT_MS = 60_000;
/**
* Maximum buffered knip output retained for diagnostics.
*/
export const KNIP_MAX_BUFFER_BYTES = 16 * 1024 * 1024;
const KNIP_ARGS = [
"--config",
@@ -37,6 +50,9 @@ function isLikelyRepoFilePath(value) {
return /^(apps|docs|extensions|packages|scripts|src|test|ui)\//u.test(normalizeRepoPath(value));
}
/**
* Parses compact knip output into unused file paths.
*/
export function parseKnipCompactUnusedFiles(output) {
const files = [];
let inUnusedFilesSection = false;
@@ -68,6 +84,9 @@ export function parseKnipCompactUnusedFiles(output) {
return uniqueSorted(files);
}
/**
* Compares detected unused files against the checked-in allowlist.
*/
export function compareUnusedFilesToAllowlist(
actualFiles,
allowlistFiles,
@@ -90,6 +109,9 @@ export function compareUnusedFilesToAllowlist(
};
}
/**
* Formats unused-file allowlist drift for CLI output.
*/
export function formatUnusedFileComparison(comparison) {
const lines = [];
if (!comparison.allowlistIsSorted) {
@@ -132,6 +154,9 @@ function signalProcessTree(child, signal) {
}
}
/**
* Runs knip and returns parsed unused-file results.
*/
export async function runKnipUnusedFiles(params = {}) {
const run = params.spawnCommand ?? spawn;
const timeoutMs = params.timeoutMs ?? KNIP_TIMEOUT_MS;
@@ -284,6 +309,9 @@ export async function runKnipUnusedFiles(params = {}) {
});
});
}
/**
* Checks detected unused files against the current allowlist.
*/
export function checkUnusedFiles(
output,
allowlistFiles = KNIP_UNUSED_FILE_ALLOWLIST,

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env node
// Audits patched dependency pins for exact versions and drift.
import { execFileSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
@@ -106,10 +107,16 @@ function collectWorkspaceViolations(cwd) {
return violations;
}
/**
* Collects dependency pin violations for the current workspace.
*/
export function collectDependencyPinViolations(cwd = process.cwd()) {
return [...collectPackageJsonViolations(cwd), ...collectWorkspaceViolations(cwd)];
}
/**
* Builds the full dependency pin audit payload.
*/
export function collectDependencyPinAudit(cwd = process.cwd()) {
const packageJsonFiles = listTrackedPackageJsonFiles(cwd);
let packageSpecCount = 0;
@@ -128,6 +135,9 @@ export function collectDependencyPinAudit(cwd = process.cwd()) {
};
}
/**
* Runs the dependency pin check.
*/
export async function main() {
const audit = collectDependencyPinAudit();
const { violations } = audit;

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env node
// Scans source files for usage of deprecated API markers.
import fs from "node:fs";
import path from "node:path";
import { collectDeprecatedInternalConfigApiViolations } from "./lib/deprecated-config-api-guard.mjs";

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env node
// Checks deprecated JSDoc blocks for required migration details.
import fs from "node:fs";
import { createRequire } from "node:module";
import path from "node:path";

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env node
// Validates docs i18n glossary terms against configured usage rules.
import { execFileSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env node
// Validates docs MDX files for syntax and repository-specific conventions.
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
@@ -91,6 +92,9 @@ function parsePositiveIntegerArg(raw, label) {
return value;
}
/**
* Parses docs MDX check arguments.
*/
export function parseArgs(argv) {
const roots = [];
let jsonOut = "";

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env node
// Runs duplicate-code detection with repo-specific excludes.
import { spawnSync } from "node:child_process";
import path from "node:path";
import { fileURLToPath } from "node:url";

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env node
// Advises on ineffective or suspicious dynamic import patterns.
import { promises as fs } from "node:fs";
import path from "node:path";
import ts from "typescript";
@@ -90,6 +91,9 @@ function isIgnoredTestHelperPath(filePath) {
);
}
/**
* Finds dynamic import advisories in a single source file.
*/
export function findDynamicImportAdvisories(content, fileName = "source.ts") {
const sourceFile = ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest, true);
const staticRuntimeImports = new Map();
@@ -171,6 +175,9 @@ export function findDynamicImportAdvisories(content, fileName = "source.ts") {
return advisories;
}
/**
* Collects dynamic import advisories across configured source roots.
*/
export async function collectDynamicImportAdvisories(options = {}) {
const roots = options.roots ?? defaultRoots;
const files = await collectTypeScriptFilesFromRoots(roots, {
@@ -195,6 +202,9 @@ export async function collectDynamicImportAdvisories(options = {}) {
return advisories;
}
/**
* Runs the dynamic import advisory check.
*/
export async function main(argv = process.argv.slice(2)) {
const fail = argv.includes("--fail");
const json = argv.includes("--json");

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env node
// Verifies extension packages compile through their package-local TypeScript boundary.
import { spawn, spawnSync } from "node:child_process";
import {
existsSync,
@@ -49,6 +50,9 @@ function parseMode(argv) {
return mode;
}
/**
* Resolves the compile worker count from CLI/env/default settings.
*/
export function resolveCompileConcurrency(
env = process.env,
availableParallelism = os.availableParallelism(),
@@ -98,6 +102,9 @@ function createStepOutputCapture() {
return { text: "", truncatedChars: 0 };
}
/**
* Appends child-process output while preserving only the diagnostic tail.
*/
export function appendBoundedStepOutput(buffer, chunk, maxChars = STEP_OUTPUT_MAX_CHARS) {
const nextText = buffer.text + String(chunk);
if (nextText.length <= maxChars) {
@@ -114,6 +121,9 @@ function formatCapturedStepOutput(buffer) {
return `[output truncated ${buffer.truncatedChars} chars; showing tail]\n${buffer.text}`;
}
/**
* Formats the successful boundary compile summary.
*/
export function formatBoundaryCheckSuccessSummary(params = {}) {
const lines = ["extension package boundary check passed"];
if (params.mode) {
@@ -143,6 +153,9 @@ export function formatBoundaryCheckSuccessSummary(params = {}) {
return `${lines.join("\n")}\n`;
}
/**
* Formats skipped compile progress for fresh extension canaries.
*/
export function formatSkippedCompileProgress(params = {}) {
const skippedCount = params.skippedCount ?? 0;
const totalCount = params.totalCount ?? 0;
@@ -157,6 +170,9 @@ export function formatSkippedCompileProgress(params = {}) {
return `skipped ${skippedCount} fresh plugin compiles\n`;
}
/**
* Formats slow extension compile diagnostics.
*/
export function formatSlowCompileSummary(params = {}) {
const compileTimings = Array.isArray(params.compileTimings) ? params.compileTimings : [];
if (compileTimings.length === 0) {
@@ -174,6 +190,9 @@ export function formatSlowCompileSummary(params = {}) {
return `${lines.join("\n")}\n`;
}
/**
* Formats a failed boundary-check child process step.
*/
export function formatStepFailure(label, params = {}) {
const stdoutSection = summarizeOutputSection("stdout", params.stdout ?? "");
const stderrSection = summarizeOutputSection("stderr", params.stderr ?? "");
@@ -285,6 +304,9 @@ function collectOldestMtime(paths) {
return Number.isFinite(oldestMtimeMs) ? oldestMtimeMs : null;
}
/**
* Checks whether an extension boundary compile canary is still fresh.
*/
export function isBoundaryCompileFresh(extensionId, params = {}) {
const rootDir = params.rootDir ?? repoRoot;
const extensionRoot = resolve(rootDir, "extensions", extensionId);
@@ -363,6 +385,9 @@ function abortSiblingSteps(abortController) {
}
}
/**
* Runs one node-based boundary check step with timeout and output capture.
*/
export function runNodeStepAsync(label, args, timeoutMs, params = {}) {
const abortController = params.abortController;
const killProcess = params.killProcess ?? process.kill.bind(process);
@@ -540,6 +565,9 @@ export function runNodeStepAsync(label, args, timeoutMs, params = {}) {
});
}
/**
* Runs boundary check steps with bounded concurrency.
*/
export async function runNodeStepsWithConcurrency(steps, concurrency) {
const abortController = new AbortController();
let firstFailure = null;
@@ -571,6 +599,9 @@ export async function runNodeStepsWithConcurrency(steps, concurrency) {
}
}
/**
* Resolves canary artifact paths for an extension boundary compile.
*/
export function resolveCanaryArtifactPaths(extensionId, rootDir = repoRoot) {
const extensionRoot = resolve(rootDir, "extensions", extensionId);
return {
@@ -580,18 +611,27 @@ export function resolveCanaryArtifactPaths(extensionId, rootDir = repoRoot) {
};
}
/**
* Removes canary artifacts for one extension.
*/
export function cleanupCanaryArtifacts(extensionId, rootDir = repoRoot) {
const { canaryPath, tsconfigPath } = resolveCanaryArtifactPaths(extensionId, rootDir);
rmSync(canaryPath, { force: true });
rmSync(tsconfigPath, { force: true });
}
/**
* Removes canary artifacts for multiple extensions.
*/
export function cleanupCanaryArtifactsForExtensions(extensionIds, rootDir = repoRoot) {
for (const extensionId of extensionIds) {
cleanupCanaryArtifacts(extensionId, rootDir);
}
}
/**
* Installs signal/exit cleanup for extension canary artifacts.
*/
export function installCanaryArtifactCleanup(extensionIds, params = {}) {
const rootDir = params.rootDir ?? repoRoot;
const processObject = params.processObject ?? process;
@@ -612,6 +652,9 @@ function resolveBoundaryTsStampPath(extensionId, rootDir = repoRoot) {
return resolve(rootDir, "extensions", extensionId, "dist", ".boundary-tsc.stamp");
}
/**
* Resolves the local lock path for extension boundary checks.
*/
export function resolveBoundaryCheckLockPath(rootDir = repoRoot) {
return resolve(rootDir, "dist", ".extension-package-boundary.lock");
}
@@ -649,6 +692,9 @@ function removeStaleBoundaryCheckLock(lockPath) {
return true;
}
/**
* Acquires the single-process lock for extension boundary checks.
*/
export function acquireBoundaryCheckLock(params = {}) {
const rootDir = params.rootDir ?? repoRoot;
const processObject = params.processObject ?? process;
@@ -848,6 +894,9 @@ async function runCanaryCheck(extensionIds) {
};
}
/**
* Runs the extension package TypeScript boundary check.
*/
export async function main(argv = process.argv.slice(2)) {
const startedAt = Date.now();
const mode = parseMode(argv);

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env node
// Inventories extension imports to enforce plugin SDK boundary rules.
import { promises as fs } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
@@ -225,6 +226,9 @@ function collectEntriesByModeFromModuleReferences(filePath, references) {
return entriesByMode;
}
/**
* Collects the current extension plugin SDK boundary inventory.
*/
export async function collectExtensionPluginSdkBoundaryInventory(mode) {
if (!MODES.has(mode)) {
throw new Error(`Unknown mode: ${mode}`);
@@ -253,6 +257,9 @@ export async function collectExtensionPluginSdkBoundaryInventory(mode) {
return inventoryByMode[mode];
}
/**
* Reads the checked-in expected boundary inventory.
*/
export async function readExpectedInventory(mode) {
try {
return JSON.parse(await fs.readFile(baselinePathByMode[mode], "utf8"));
@@ -270,6 +277,9 @@ export async function readExpectedInventory(mode) {
}
}
/**
* Diffs expected and actual boundary inventory entries.
*/
export function diffInventory(expected, actual) {
return diffInventoryEntries(expected, actual, compareEntries);
}
@@ -294,6 +304,9 @@ function formatInventoryHuman(mode, inventory) {
return lines.join("\n");
}
/**
* Runs the boundary inventory check with CLI-style inputs and outputs.
*/
export async function runExtensionPluginSdkBoundaryCheck(argv, io) {
const args = argv ?? process.argv.slice(2);
const streams = io ?? { stdout: process.stdout, stderr: process.stderr };
@@ -343,6 +356,9 @@ export async function runExtensionPluginSdkBoundaryCheck(argv, io) {
return 1;
}
/**
* Entrypoint wrapper for the extension plugin SDK boundary check.
*/
export async function main(argv, io) {
const exitCode = await runExtensionPluginSdkBoundaryCheck(argv, io);
if (!io) {