diff --git a/scripts/check-deadcode-unused-files.mjs b/scripts/check-deadcode-unused-files.mjs index cb3fe93c33b8..969b4f6709d6 100644 --- a/scripts/check-deadcode-unused-files.mjs +++ b/scripts/check-deadcode-unused-files.mjs @@ -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, diff --git a/scripts/check-dependency-pins.mjs b/scripts/check-dependency-pins.mjs index daf7c1ed3119..3bcc278d79f8 100644 --- a/scripts/check-dependency-pins.mjs +++ b/scripts/check-dependency-pins.mjs @@ -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; diff --git a/scripts/check-deprecated-api-usage.mjs b/scripts/check-deprecated-api-usage.mjs index 82c758d27d2a..be258f3f2ba6 100644 --- a/scripts/check-deprecated-api-usage.mjs +++ b/scripts/check-deprecated-api-usage.mjs @@ -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"; diff --git a/scripts/check-deprecated-jsdoc.mjs b/scripts/check-deprecated-jsdoc.mjs index 96bd204f7357..c1a7d86e72ec 100644 --- a/scripts/check-deprecated-jsdoc.mjs +++ b/scripts/check-deprecated-jsdoc.mjs @@ -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"; diff --git a/scripts/check-docs-i18n-glossary.mjs b/scripts/check-docs-i18n-glossary.mjs index 96f890bc4ff5..28ae5f0befe3 100644 --- a/scripts/check-docs-i18n-glossary.mjs +++ b/scripts/check-docs-i18n-glossary.mjs @@ -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"; diff --git a/scripts/check-docs-mdx.mjs b/scripts/check-docs-mdx.mjs index e6892c797de0..9015e09dcc8a 100644 --- a/scripts/check-docs-mdx.mjs +++ b/scripts/check-docs-mdx.mjs @@ -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 = ""; diff --git a/scripts/check-duplicates.mjs b/scripts/check-duplicates.mjs index c86418779713..95d255ea4960 100644 --- a/scripts/check-duplicates.mjs +++ b/scripts/check-duplicates.mjs @@ -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"; diff --git a/scripts/check-dynamic-import-warts.mjs b/scripts/check-dynamic-import-warts.mjs index 7a19b700afc8..0a9badfbd8bd 100644 --- a/scripts/check-dynamic-import-warts.mjs +++ b/scripts/check-dynamic-import-warts.mjs @@ -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"); diff --git a/scripts/check-extension-package-tsc-boundary.mjs b/scripts/check-extension-package-tsc-boundary.mjs index 86f844da5172..8928098d7ddb 100644 --- a/scripts/check-extension-package-tsc-boundary.mjs +++ b/scripts/check-extension-package-tsc-boundary.mjs @@ -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); diff --git a/scripts/check-extension-plugin-sdk-boundary.mjs b/scripts/check-extension-plugin-sdk-boundary.mjs index a6372a2a60b8..f6ee00a944f7 100644 --- a/scripts/check-extension-plugin-sdk-boundary.mjs +++ b/scripts/check-extension-plugin-sdk-boundary.mjs @@ -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) {