@webpieces/nx-webpieces-rules 0.4.919 → 0.4.920

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"graph-impact.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-impact.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Impact mode's data: what one COMPARISON's build looks like, in three shades (plus untouched grey).\n *\n * There are two comparisons, and only two (#1163). Both end at the WORKING TREE, so uncommitted and\n * untracked work counts in either:\n *\n * - BRANCH, \"Changed on this branch\": the fork point (`DiffScope.detectBase` in rules-config:\n * `git merge-base HEAD origin/main`, falling back to `main`) → working tree.\n * - COMMIT, \"Last commit\": `HEAD^` → working tree. To see what another commit changed, check it out\n * (`git checkout <hash>`) and run `pnpm arch:visualize`: nx computes `--affected` against the code\n * that is actually on disk, so nothing here ever jumps to another commit.\n *\n * Which of them exist is decided by `ImpactScopeResolver` from where HEAD is. On `main` (by BRANCH\n * NAME, so a local main with unpushed commits still counts as main) and on a detached HEAD only the\n * last commit exists — the fork point IS HEAD there, so the branch comparison would always be empty.\n * On a feature branch with commits past its fork point both exist, the branch one first. On a FRESH\n * feature branch (fork point = HEAD) only the branch one exists: falling through to \"last commit\"\n * would show main's last PR as if it were the branch's own work.\n *\n * Per comparison:\n * - BUILD INPUT is every transitive dependency of the affected set that is not itself affected:\n * `ci` dependsOn `^build`, so they must exist as build output though their inputs did not change.\n * nx restores them from cache when it has them and compiles them otherwise — which one happens is\n * not knowable here, so nothing claims it. A pure downward walk over the graph's own edges.\n * - AFFECTED is `nx show projects --affected --base=<the comparison's base> --json`, with NO\n * `--head`, so uncommitted and untracked work counts. nx already gets right everything a\n * hand-rolled diff gets wrong: lockfile and package.json changes resolved per project, root/global\n * inputs, namedInputs, implicitDependencies, nested roots and deleted files. This uses its public\n * CLI surface only, never nx internals, and never NX_BASE/NX_HEAD, whose value depends on whoever\n * launched the process.\n * - TOUCHED is the subset of that set which OWNS a changed file, by nx's own file-to-project\n * ownership (the project file map from `createProjectFileMapUsingProjectGraph`, public devkit API)\n * — never a path-prefix guess. The ownership map is computed ONCE and shared by every comparison.\n * A project whose only change is a DELETED file is not in that map (the file is gone), so it shows\n * as affected rather than touched. The changed-file list is `DiffScope.getChangedFiles`, the same\n * base→working-tree diff (with untracked files) every code rule uses.\n *\n * The answer changes per checkout, so it never goes into the committed dependencies.html or\n * dependencies.json (both stay byte-stable). It goes into a SIDECAR,\n * `architecture/.impact/dependencies.impact.js`: a plain script setting one window global,\n * `window.__WP_IMPACT__ = { scans, defaultKind }`, loaded with `<script src>` — the one way a page\n * opened straight from disk (file://) can read a neighbouring file. The directory carries its own\n * `.gitignore` containing `*`, which ignores the directory and everything in it, so a consumer repo\n * needs no gitignore edit and the PR gate's \"build left nothing uncommitted\" check never sees it.\n *\n * `architecture:visualize` scans every comparison that exists. `architecture:generate` refreshes\n * ONLY the branch comparison (`GENERATE_IMPACT_KINDS`) and never scans the last commit; on main or a\n * detached HEAD that leaves nothing to write, so it removes the sidecar and the page says to run\n * `pnpm arch:visualize`.\n *\n * Impact is a convenience. When nx or git cannot answer any comparison, NO sidecar is written (a\n * stale one is removed) and the page disables Impact with a one-line reason. It never fails\n * generation.\n */\n\nimport { spawnSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { createProjectFileMapUsingProjectGraph, createProjectGraphAsync } from '@nx/devkit';\nimport { DiffScope, ChangedFilesOptions } from '@webpieces/rules-config';\nimport type { EnhancedGraph } from './graph-sorter';\nimport { GraphNames } from './graph-names';\nimport { toError } from '../toError';\n\n/** Relative to the architecture/ directory the page lives in; the page's `<script src>`. */\nexport const IMPACT_SIDECAR_DIR = '.impact';\nexport const IMPACT_SIDECAR_FILE = 'dependencies.impact.js';\nexport const IMPACT_SIDECAR_SRC = `${IMPACT_SIDECAR_DIR}/${IMPACT_SIDECAR_FILE}`;\n/** Each nx call is capped; a slow or wedged nx disables that comparison instead of stalling generation. */\nconst NX_TIMEOUT_MS = 15000;\n/** The branch whose name means \"there is no branch comparison here, only the last commit\". */\nconst MAIN_BRANCH = 'main';\n\nexport const NOTHING_CHANGED_ON_BRANCH = 'Nothing changed on this branch yet';\nexport const ROOT_COMMIT_REASON =\n \"HEAD is the repository's first commit; there is no previous commit to compare against\";\nexport const UNCOMMITTED_SUFFIX = ' + uncommitted changes';\n\n/** Which of the two comparisons a scan answers. */\nexport enum ImpactKind {\n /** Fork point → working tree: \"Changed on this branch\". */\n BRANCH = 'branch',\n /** HEAD^ → working tree: \"Last commit\". */\n COMMIT = 'commit',\n}\n\n/** `architecture:visualize` scans every comparison that exists. */\nexport const VISUALIZE_IMPACT_KINDS: readonly ImpactKind[] = [ImpactKind.BRANCH, ImpactKind.COMMIT];\n/** `architecture:generate` refreshes the branch comparison only and never scans the last commit. */\nexport const GENERATE_IMPACT_KINDS: readonly ImpactKind[] = [ImpactKind.BRANCH];\n\n/** One scan as the sidecar carries it; the page reads `window.__WP_IMPACT__.scans`. */\nexport class ImpactReport {\n constructor(\n public readonly kind: ImpactKind,\n /** What the page says this scan compares, e.g. \"Changed on this branch (since abc1234)\". */\n public readonly label: string,\n /** The working tree had uncommitted or untracked changes (they count in the scan). */\n public readonly dirty: boolean,\n public readonly available: boolean,\n /** Why the scan is unavailable; for an available but EMPTY scan, the note the page shows. */\n public readonly reason: string,\n /** The base's short sha ('' when there is none). */\n public readonly base: string,\n /** Affected AND owning a changed file (node ids). */\n public readonly touched: string[],\n /** Affected but owning no changed file (node ids): their ci re-runs. */\n public readonly affected: string[],\n /**\n * Transitive dependencies of the affected set that are NOT affected (node ids). `ci` dependsOn\n * `^build`, so they must exist as build output although their inputs did not change: nx\n * restores them from cache when it has them and compiles them otherwise. Which of the two\n * happens is not knowable here, so the page claims neither.\n */\n public readonly buildInputs: string[],\n public readonly changedFiles: number,\n /**\n * Transitive dependencies of the TOUCHED set that are not touched themselves (node ids): the\n * Filter popover's \"Changed + dependencies\". (\"Changed + dependents\" is touched + affected,\n * which nx already computed as the dependents whose tests re-run.)\n */\n public readonly dependencies: string[],\n /**\n * Changed files no project owns (repo-relative, sorted): workspace-global inputs such as\n * pnpm-lock.yaml. When nothing is touched they are WHY everything is affected, and the\n * legend names them. Empty when nx's file ownership was unavailable — then nothing is known.\n */\n public readonly globalFiles: string[],\n ) {}\n}\n\n/** The sidecar's one global: every scan, and the one the page shows first. */\nexport class ImpactSidecarData {\n constructor(\n public readonly scans: ImpactReport[],\n public readonly defaultKind: ImpactKind,\n ) {}\n}\n\n/** A scan (or a whole plan) that could not produce an answer. */\nexport class ImpactUnavailable {\n constructor(\n public readonly reason: string,\n public readonly label: string = 'Impact',\n ) {}\n}\n\n/** One comparison to scan. `base` is a full sha; null when it does not exist (`reason` says why). */\nexport class ImpactComparison {\n constructor(\n public readonly kind: ImpactKind,\n public readonly base: string | null,\n public readonly label: string,\n public readonly dirty: boolean,\n public readonly reason: string,\n ) {}\n}\n\n/** The comparisons that exist where HEAD is, and which one the page shows first. */\nexport class ImpactPlan {\n constructor(\n public readonly comparisons: ImpactComparison[],\n public readonly defaultKind: ImpactKind,\n ) {}\n}\n\n/** The few git facts the resolver needs. Injected so specs never spawn git. */\nexport class ImpactGit {\n /** The checked-out branch's short name; null on a detached HEAD (or without git). */\n branch(root: string): string | null {\n return this.run(root, ['symbolic-ref', '--short', '-q', 'HEAD']);\n }\n\n /** The full sha `ref` names; null when it does not resolve (e.g. `HEAD^` on the first commit). */\n sha(root: string, ref: string): string | null {\n return this.run(root, ['rev-parse', '--verify', '-q', `${ref}^{commit}`]);\n }\n\n /** `git status --porcelain` is non-empty: uncommitted or untracked work. */\n dirty(root: string): boolean {\n return (this.run(root, ['status', '--porcelain']) ?? '') !== '';\n }\n\n /** HEAD's subject line ('' when unknown). */\n subject(root: string): string {\n return this.run(root, ['log', '-1', '--format=%s', 'HEAD']) ?? '';\n }\n\n /** Trimmed stdout, or null on any failure. */\n private run(root: string, args: string[]): string | null {\n const result = spawnSync('git', args, { cwd: root, encoding: 'utf8', stdio: 'pipe' });\n if (result.error !== undefined || result.status !== 0) return null;\n return result.stdout.trim();\n }\n}\n\n/**\n * Decides which comparisons exist from where HEAD is (#1163):\n *\n * | where | comparisons | default |\n * |---|---|---|\n * | `main` (by branch NAME) | last commit | last commit |\n * | detached HEAD | last commit | last commit |\n * | feature branch with commits past the fork point | branch, last commit | branch |\n * | fresh feature branch (fork point = HEAD) | branch | branch |\n *\n * HEAD with no parent leaves the last commit unavailable, with `ROOT_COMMIT_REASON`.\n */\nexport class ImpactScopeResolver {\n constructor(\n private readonly git: ImpactGit = new ImpactGit(),\n private readonly diffScope: DiffScope = new DiffScope(),\n ) {}\n\n resolve(root: string): ImpactPlan | ImpactUnavailable {\n const head = this.git.sha(root, 'HEAD');\n if (head === null) return new ImpactUnavailable('git cannot resolve HEAD (not a git checkout, or git is unavailable)');\n const branch = this.git.branch(root);\n const dirty = this.git.dirty(root);\n const commit = this.lastCommit(root, dirty);\n // On main the decision is the branch NAME, never merge-base: unpushed commits still mean \"last commit\".\n if (branch === null || branch === MAIN_BRANCH) return new ImpactPlan([commit], ImpactKind.COMMIT);\n const fork = this.diffScope.detectBase(root);\n if (fork === null) {\n const reason = 'no fork point: neither origin/main nor main resolves';\n return new ImpactPlan(\n [new ImpactComparison(ImpactKind.BRANCH, null, 'Changed on this branch', dirty, reason)],\n ImpactKind.BRANCH,\n );\n }\n const onBranch = new ImpactComparison(\n ImpactKind.BRANCH,\n fork,\n `Changed on this branch (since ${this.short(fork)})${dirty ? UNCOMMITTED_SUFFIX : ''}`,\n dirty,\n '',\n );\n // A fresh branch has no commit of its own: \"last commit\" would be main's last PR, not its work.\n if (this.sameCommit(fork, head)) return new ImpactPlan([onBranch], ImpactKind.BRANCH);\n return new ImpactPlan([onBranch, commit], ImpactKind.BRANCH);\n }\n\n private lastCommit(root: string, dirty: boolean): ImpactComparison {\n const parent = this.git.sha(root, 'HEAD^');\n if (parent === null) return new ImpactComparison(ImpactKind.COMMIT, null, 'Last commit', dirty, ROOT_COMMIT_REASON);\n const subject = this.git.subject(root);\n const label =\n `Changed since ${this.short(parent)}${subject === '' ? '' : ` — ${subject}`}` +\n (dirty ? UNCOMMITTED_SUFFIX : '');\n return new ImpactComparison(ImpactKind.COMMIT, parent, label, dirty, '');\n }\n\n /** detectBase may hand back a full or an abbreviated sha; compare on the shorter of the two. */\n private sameCommit(a: string, b: string): boolean {\n const length = Math.min(a.length, b.length);\n return length > 0 && a.slice(0, length) === b.slice(0, length);\n }\n\n private short(sha: string): string {\n return sha.slice(0, 7);\n }\n}\n\n/** Runs the workspace's own nx CLI. Injected so specs never spawn nx. */\nexport class NxCli {\n /** stdout, or null when nx cannot be found, exits non-zero or exceeds the timeout. */\n run(workspaceRoot: string, args: string[], timeoutMs: number): string | null {\n const bin = this.binary(workspaceRoot);\n if (bin === null) return null;\n const result = spawnSync(process.execPath, [bin, ...args], {\n cwd: workspaceRoot,\n encoding: 'utf8',\n timeout: timeoutMs,\n stdio: 'pipe',\n maxBuffer: 16 * 1024 * 1024,\n });\n if (result.error !== undefined || result.status !== 0) return null;\n return result.stdout;\n }\n\n /** Resolved the way node would from the workspace, so a linked worktree finds its main tree's nx. */\n private binary(workspaceRoot: string): string | null {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- a workspace without nx resolves nothing; that is an answer, not an error\n try {\n return require.resolve('nx/bin/nx.js', { paths: [workspaceRoot] });\n } catch (err: unknown) {\n const error = toError(err);\n void error; // no nx installed here — Impact is simply unavailable\n return null;\n }\n }\n}\n\n/** nx's own file → project ownership, from the public devkit file map. Injected for specs. */\nexport class ProjectFileOwners {\n async owners(): Promise<Map<string, string>> {\n const fileMap = await createProjectFileMapUsingProjectGraph(await createProjectGraphAsync());\n const owners = new Map<string, string>();\n for (const project of Object.keys(fileMap)) {\n for (const data of fileMap[project]) owners.set(data.file, project);\n }\n return owners;\n }\n}\n\n/**\n * nx's ownership map, computed at most ONCE however many comparisons ask for it. Failing is not\n * fatal: the set then shows in one shade, all \"affected\".\n */\nexport class SharedOwners {\n private pending: Promise<Map<string, string>> | null = null;\n\n constructor(private readonly ownership: ProjectFileOwners) {}\n\n get(): Promise<Map<string, string>> {\n if (this.pending === null) this.pending = this.load();\n return this.pending;\n }\n\n private async load(): Promise<Map<string, string>> {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- the second shade is optional\n try {\n return await this.ownership.owners();\n } catch (err: unknown) {\n const error = toError(err);\n console.warn(`⚠️ Impact: nx file ownership unavailable (${error.message}); showing one shade`);\n return new Map<string, string>();\n }\n }\n}\n\n/** The sets one scan found; an empty one is still an answer. */\nclass ImpactSets {\n constructor(\n public readonly touched: string[] = [],\n public readonly affected: string[] = [],\n public readonly buildInputs: string[] = [],\n public readonly dependencies: string[] = [],\n public readonly globalFiles: string[] = [],\n ) {}\n}\n\nexport class NxImpactScanner {\n private readonly names = new GraphNames();\n\n constructor(\n private readonly diffScope: DiffScope = new DiffScope(),\n private readonly nx: NxCli = new NxCli(),\n private readonly ownership: ProjectFileOwners = new ProjectFileOwners(),\n ) {}\n\n /** Every comparison, in order, sharing one ownership map. */\n async scanAll(\n workspaceRoot: string,\n graph: EnhancedGraph,\n comparisons: ImpactComparison[],\n ): Promise<(ImpactReport | ImpactUnavailable)[]> {\n const owners = new SharedOwners(this.ownership);\n const results: (ImpactReport | ImpactUnavailable)[] = [];\n for (const comparison of comparisons) results.push(await this.scan(workspaceRoot, graph, comparison, owners));\n return results;\n }\n\n /** One comparison: nx affected from ITS base, with NO `--head`, so uncommitted work counts. */\n async scan(\n workspaceRoot: string,\n graph: EnhancedGraph,\n comparison: ImpactComparison,\n owners: SharedOwners = new SharedOwners(this.ownership),\n ): Promise<ImpactReport | ImpactUnavailable> {\n const base = comparison.base;\n if (base === null) return this.report(comparison, false, comparison.reason, '', 0, new ImpactSets());\n const json = this.nx.run(workspaceRoot, ['show', 'projects', '--affected', `--base=${base}`, '--json'], NX_TIMEOUT_MS);\n if (json === null)\n return new ImpactUnavailable(`nx show projects --affected failed or took over ${NX_TIMEOUT_MS / 1000}s`, comparison.label);\n const affectedSet = this.parse(json, graph);\n if (affectedSet === null)\n return new ImpactUnavailable('nx show projects --affected printed something other than a JSON list', comparison.label);\n const options = new ChangedFilesOptions();\n options.tsOnly = false;\n options.includeDeletions = true;\n const files = this.diffScope.getChangedFiles(workspaceRoot, base, undefined, options);\n const short = base.slice(0, 7);\n if (affectedSet.length === 0)\n return this.report(comparison, true, this.emptyNote(comparison, files.length, short), short, files.length, new ImpactSets());\n const map = await owners.get();\n const touched = this.touched(affectedSet, files, map);\n const rest = affectedSet.filter((project: string): boolean => !touched.includes(project));\n const sets = new ImpactSets(\n this.ids(touched),\n this.ids(rest),\n this.ids(this.buildInputs(affectedSet, graph)),\n this.ids(this.buildInputs(touched, graph)),\n this.globalFiles(files, map),\n );\n return this.report(comparison, true, '', short, files.length, sets);\n }\n\n /**\n * An empty scan is still an ANSWER (available, zero sets): a fresh branch with a clean tree has\n * simply changed nothing yet, and the page says so instead of disabling Impact.\n */\n emptyNote(comparison: ImpactComparison, changedFiles: number, short: string): string {\n if (changedFiles === 0 && comparison.kind === ImpactKind.BRANCH) return NOTHING_CHANGED_ON_BRANCH;\n if (changedFiles === 0) return `Nothing changed since ${short}`;\n return `Nothing affected since ${short}`;\n }\n\n /** Changed files no project owns; none are claimed when ownership itself was unavailable. */\n globalFiles(files: string[], owners: Map<string, string>): string[] {\n if (owners.size === 0) return [];\n return files.filter((file: string): boolean => !owners.has(file)).sort();\n }\n\n /**\n * Every transitive dependency of `roots` that is not itself one of them: a pure downward walk over\n * the graph's own dependsOn edges, no nx call. Of the affected set these are the build inputs; of\n * the touched set, \"Changed + dependencies\".\n */\n buildInputs(roots: string[], graph: EnhancedGraph): string[] {\n const inSet = new Set<string>(roots);\n const seen = new Set<string>(roots);\n const stack = [...roots];\n const inputs: string[] = [];\n while (stack.length > 0) {\n const project = stack.pop() as string;\n for (const dep of graph[project]?.dependsOn ?? []) {\n if (seen.has(dep)) continue;\n seen.add(dep);\n stack.push(dep);\n if (!inSet.has(dep) && graph[dep] !== undefined) inputs.push(dep);\n }\n }\n return inputs.sort();\n }\n\n /** Affected projects that own one of the changed files, by nx's own ownership. */\n touched(affected: string[], files: string[], owners: Map<string, string>): string[] {\n const owning = new Set<string>();\n for (const file of files) {\n const owner = owners.get(file);\n if (owner !== undefined) owning.add(owner);\n }\n return affected.filter((project: string): boolean => owning.has(project));\n }\n\n /** The JSON list, narrowed to projects the graph draws; null when it is not a list of names. */\n parse(json: string, graph: EnhancedGraph): string[] | null {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- untrusted CLI output; anything unparseable is reported as a reason\n try {\n // webpieces-disable no-any-unknown -- CLI JSON is untrusted until narrowed below\n const parsed: unknown = JSON.parse(json);\n if (!Array.isArray(parsed)) return null;\n return parsed\n .filter((name: unknown): name is string => typeof name === 'string' && graph[name] !== undefined)\n .sort();\n } catch (err: unknown) {\n const error = toError(err);\n void error; // not JSON — the caller reports it\n return null;\n }\n }\n\n private report(\n comparison: ImpactComparison,\n available: boolean,\n reason: string,\n base: string,\n changedFiles: number,\n sets: ImpactSets,\n ): ImpactReport {\n return new ImpactReport(\n comparison.kind,\n comparison.label,\n comparison.dirty,\n available,\n reason,\n base,\n sets.touched,\n sets.affected,\n sets.buildInputs,\n changedFiles,\n sets.dependencies,\n sets.globalFiles,\n );\n }\n\n private ids(projects: string[]): string[] {\n return projects.map((project: string): string => this.names.getNodeId(project));\n }\n}\n\n/** Writes (or removes) the sidecar, self-ignored, beside architecture/dependencies.html. */\nexport class ImpactSidecar {\n /** Never throws: a sidecar that cannot be written just leaves Impact disabled on the page. */\n write(architectureDir: string, data: ImpactSidecarData): string | null {\n const dir = path.join(architectureDir, IMPACT_SIDECAR_DIR);\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- impact is optional; a write failure must never fail generation\n try {\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(\n path.join(dir, '.gitignore'),\n '# Written by architecture:generate and architecture:visualize. Per-checkout data: never commit it.\\n*\\n',\n 'utf-8',\n );\n const file = path.join(dir, IMPACT_SIDECAR_FILE);\n fs.writeFileSync(file, this.script(data), 'utf-8');\n return file;\n } catch (err: unknown) {\n const error = toError(err);\n console.warn(`⚠️ Could not write the impact sidecar: ${error.message}`);\n return null;\n }\n }\n\n /** A stale sidecar from an earlier checkout must never be shown as this one's impact. */\n remove(architectureDir: string): void {\n fs.rmSync(path.join(architectureDir, IMPACT_SIDECAR_DIR, IMPACT_SIDECAR_FILE), { force: true });\n }\n\n script(data: ImpactSidecarData): string {\n const json = JSON.stringify(data).replace(/</g, '\\\\u003c');\n return `// Generated by architecture:generate or architecture:visualize for one checkout. Gitignored; do not commit.\\nwindow.__WP_IMPACT__ = ${json};\\n`;\n }\n}\n\n/** The executors' one call: resolve, scan each comparison, write, and report one line per comparison. */\nexport class ImpactRefresh {\n constructor(\n private readonly scanner: NxImpactScanner = new NxImpactScanner(),\n private readonly sidecar: ImpactSidecar = new ImpactSidecar(),\n private readonly resolver: ImpactScopeResolver = new ImpactScopeResolver(),\n ) {}\n\n /**\n * Scans the comparisons in `kinds` that exist here (`VISUALIZE_IMPACT_KINDS` /\n * `GENERATE_IMPACT_KINDS`). Never throws — Impact is optional, generation is not.\n */\n async run(\n architectureDir: string,\n workspaceRoot: string,\n graph: EnhancedGraph,\n kinds: readonly ImpactKind[],\n ): Promise<string> {\n const started = Date.now();\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- impact is optional; any failure becomes a reason, never a failed generation\n try {\n const plan = this.resolver.resolve(workspaceRoot);\n if (plan instanceof ImpactUnavailable) return this.none(architectureDir, plan.reason, started);\n const comparisons = plan.comparisons.filter(\n (comparison: ImpactComparison): boolean => kinds.includes(comparison.kind),\n );\n if (comparisons.length === 0)\n return this.none(\n architectureDir,\n 'no Changed-on-this-branch comparison on main or a detached HEAD; pnpm arch:visualize shows the last commit',\n started,\n );\n const results = await this.scanner.scanAll(workspaceRoot, graph, comparisons);\n const lines = results.map((result: ImpactReport | ImpactUnavailable): string => this.line(result));\n const scans = results.filter(\n (result: ImpactReport | ImpactUnavailable): result is ImpactReport => result instanceof ImpactReport,\n );\n const cost = `${Date.now() - started} ms`;\n if (scans.length === 0) {\n this.sidecar.remove(architectureDir);\n return [...lines, `ℹ️ Impact disabled, no sidecar written (${cost})`].join('\\n');\n }\n const file = this.sidecar.write(architectureDir, new ImpactSidecarData(scans, this.defaultKind(scans, plan.defaultKind)));\n return [...lines, file === null ? `⚠️ Impact sidecar not written (${cost})` : `→ ${file} (${cost})`].join('\\n');\n } catch (err: unknown) {\n const error = toError(err);\n this.sidecar.remove(architectureDir);\n return `⚠️ Impact skipped: ${error.message}`;\n }\n }\n\n /** The plan's default when that scan is available, else the first available one. */\n private defaultKind(scans: ImpactReport[], preferred: ImpactKind): ImpactKind {\n const usable = scans.filter((scan: ImpactReport): boolean => scan.available);\n if (usable.length === 0 || usable.some((scan: ImpactReport): boolean => scan.kind === preferred)) return preferred;\n return usable[0].kind;\n }\n\n private none(architectureDir: string, reason: string, started: number): string {\n this.sidecar.remove(architectureDir);\n return `ℹ️ Impact disabled, no sidecar written: ${reason} (${Date.now() - started} ms)`;\n }\n\n private line(result: ImpactReport | ImpactUnavailable): string {\n if (result instanceof ImpactUnavailable || !result.available)\n return `ℹ️ Impact · ${result.label}: unavailable — ${result.reason}`;\n if (result.reason !== '') return `✅ Impact · ${result.label}: ${result.reason}`;\n return (\n `✅ Impact · ${result.label}: ${result.touched.length} changed · ${result.affected.length} dependents · ` +\n `${result.buildInputs.length} dependencies, from ${result.changedFiles} changed file(s)`\n );\n }\n}\n"]}
1
+ {"version":3,"file":"graph-impact.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-impact.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Impact mode's data: what one COMPARISON's build looks like, and WHY each project is in it.\n *\n * There are two comparisons, and only two (#1163). Both end at the WORKING TREE, so uncommitted and\n * untracked work counts in either:\n *\n * - BRANCH, \"Changed on this branch\": the fork point (`DiffScope.detectBase` in rules-config:\n * `git merge-base HEAD origin/main`, falling back to `main`) → working tree.\n * - COMMIT, \"Last commit\": `HEAD^` → working tree. To see what another commit changed, check it out\n * (`git checkout <hash>`) and run `pnpm arch:visualize`: nx computes `--affected` against the code\n * that is actually on disk, so nothing here ever jumps to another commit.\n *\n * Which of them exist is decided by `ImpactScopeResolver` from where HEAD is. On `main` (by BRANCH\n * NAME, so a local main with unpushed commits still counts as main) and on a detached HEAD only the\n * last commit exists — the fork point IS HEAD there, so the branch comparison would always be empty.\n * On a feature branch with commits past its fork point both exist, the branch one first. On a FRESH\n * feature branch (fork point = HEAD) only the branch one exists: falling through to \"last commit\"\n * would show main's last PR as if it were the branch's own work.\n *\n * Per comparison:\n * - BUILD INPUT is every transitive dependency of the affected set that is not itself affected:\n * `ci` dependsOn `^build`, so they must exist as build output though their inputs did not change.\n * nx restores them from cache when it has them and compiles them otherwise — which one happens is\n * not knowable here, so nothing claims it. A pure downward walk over the graph's own edges.\n * - AFFECTED is `nx show projects --affected --base=<the comparison's base> --json`, with NO\n * `--head`, so uncommitted and untracked work counts. nx already gets right everything a\n * hand-rolled diff gets wrong: lockfile and package.json changes resolved per project, root/global\n * inputs, namedInputs, implicitDependencies, nested roots and deleted files. It never reads\n * NX_BASE/NX_HEAD, whose value depends on whoever launched the process.\n * - WHY each affected project is in it (#1264) — changed, dependent (with the edge path), implicitly\n * touched (with the target, glob and file) or root-file touched — comes from nx's OWN affected\n * locators, run in-process against the workspace's own nx (graph-impact-reasons.ts). They are\n * loaded ONCE and shared by every comparison. The changed-file list is `DiffScope.getChangedFiles`,\n * the same base→working-tree diff (with untracked files) every code rule uses.\n *\n * The answer changes per checkout, so it never goes into the committed dependencies.html or\n * dependencies.json (both stay byte-stable). It goes into a SIDECAR,\n * `architecture/.impact/dependencies.impact.js`: a plain script setting one window global,\n * `window.__WP_IMPACT__ = { scans, defaultKind }`, loaded with `<script src>` — the one way a page\n * opened straight from disk (file://) can read a neighbouring file. The directory carries its own\n * `.gitignore` containing `*`, which ignores the directory and everything in it, so a consumer repo\n * needs no gitignore edit and the PR gate's \"build left nothing uncommitted\" check never sees it.\n *\n * `architecture:visualize` scans every comparison that exists. `architecture:generate` refreshes\n * ONLY the branch comparison (`GENERATE_IMPACT_KINDS`) and never scans the last commit; on main or a\n * detached HEAD that leaves nothing to write, so it removes the sidecar and the page says to run\n * `pnpm arch:visualize`.\n *\n * Impact is a convenience. When nx or git cannot answer any comparison, NO sidecar is written (a\n * stale one is removed) and the page disables Impact with a one-line reason. It never fails\n * generation.\n */\n\nimport { spawnSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { createProjectGraphAsync } from '@nx/devkit';\nimport type { NxJsonConfiguration, ProjectGraph } from '@nx/devkit';\nimport type { FileChange } from 'nx/src/project-graph/file-utils';\nimport type { PackageJson } from 'nx/src/utils/package-json';\nimport { DiffScope, ChangedFilesOptions } from '@webpieces/rules-config';\nimport {\n AffectedClass,\n AffectedClassification,\n AffectedClassifier,\n AffectedInputs,\n AffectedReason,\n WorkspaceNx,\n} from './graph-impact-reasons';\nimport type { EnhancedGraph } from './graph-sorter';\nimport { GraphNames } from './graph-names';\nimport { toError } from '../toError';\n\n/** Relative to the architecture/ directory the page lives in; the page's `<script src>`. */\nexport const IMPACT_SIDECAR_DIR = '.impact';\nexport const IMPACT_SIDECAR_FILE = 'dependencies.impact.js';\nexport const IMPACT_SIDECAR_SRC = `${IMPACT_SIDECAR_DIR}/${IMPACT_SIDECAR_FILE}`;\n/** Each nx call is capped; a slow or wedged nx disables that comparison instead of stalling generation. */\nconst NX_TIMEOUT_MS = 15000;\n/** The branch whose name means \"there is no branch comparison here, only the last commit\". */\nconst MAIN_BRANCH = 'main';\n\nexport const NOTHING_CHANGED_ON_BRANCH = 'Nothing changed on this branch yet';\nexport const ROOT_COMMIT_REASON =\n \"HEAD is the repository's first commit; there is no previous commit to compare against\";\nexport const UNCOMMITTED_SUFFIX = ' + uncommitted changes';\n\n/** Which of the two comparisons a scan answers. */\nexport enum ImpactKind {\n /** Fork point → working tree: \"Changed on this branch\". */\n BRANCH = 'branch',\n /** HEAD^ → working tree: \"Last commit\". */\n COMMIT = 'commit',\n}\n\n/** `architecture:visualize` scans every comparison that exists. */\nexport const VISUALIZE_IMPACT_KINDS: readonly ImpactKind[] = [ImpactKind.BRANCH, ImpactKind.COMMIT];\n/** `architecture:generate` refreshes the branch comparison only and never scans the last commit. */\nexport const GENERATE_IMPACT_KINDS: readonly ImpactKind[] = [ImpactKind.BRANCH];\n\n/** One scan as the sidecar carries it; the page reads `window.__WP_IMPACT__.scans`. */\nexport class ImpactReport {\n constructor(\n public readonly kind: ImpactKind,\n /** What the page says this scan compares, e.g. \"Changed on this branch (since abc1234)\". */\n public readonly label: string,\n /** The working tree had uncommitted or untracked changes (they count in the scan). */\n public readonly dirty: boolean,\n public readonly available: boolean,\n /** Why the scan is unavailable; for an available but EMPTY scan, the note the page shows. */\n public readonly reason: string,\n /** The base's short sha ('' when there is none). */\n public readonly base: string,\n /** Affected AND owning a changed file (node ids): \"changed\". */\n public readonly touched: string[],\n /** Affected through dependency edges from a changed or touched project (node ids). */\n public readonly dependents: string[],\n /** Affected because a `{workspaceRoot}` target input matched a changed file (node ids). */\n public readonly implicit: string[],\n /** Affected by a lockfile, package.json, tsconfig.base.json, nx.json or deleted-config change (node ids). */\n public readonly rootFile: string[],\n /** Affected, and nothing here could say why (node ids). Never shown as a dependent. */\n public readonly unexplained: string[],\n /**\n * Transitive dependencies of the affected set that are NOT affected (node ids). `ci` dependsOn\n * `^build`, so they must exist as build output although their inputs did not change: nx\n * restores them from cache when it has them and compiles them otherwise. Which of the two\n * happens is not knowable here, so the page claims neither.\n */\n public readonly buildInputs: string[],\n public readonly changedFiles: number,\n /**\n * Transitive dependencies of the TOUCHED set that are not touched themselves (node ids): the\n * Filter popover's \"Changed + dependencies\". (\"Changed + dependents\" is every affected project.)\n */\n public readonly dependencies: string[],\n /**\n * Changed files no project owns (repo-relative, sorted): workspace-global inputs such as\n * pnpm-lock.yaml. Empty when nx's locators were unavailable — then nothing is known.\n */\n public readonly globalFiles: string[],\n /** WHY each affected project is in the build (graph-impact-reasons.ts): one per affected node. */\n public readonly reasons: AffectedReason[],\n ) {}\n}\n\n/** The one-line count split, shared by the executor's console line (the page builds the same line). */\nexport class ImpactCounts {\n /** `8 changed · 3 dependents · 22 implicitly touched (runtime-wiring-check inputs) · 47 dependencies`. */\n line(report: ImpactReport): string {\n const parts = [`${report.touched.length} changed`, `${report.dependents.length} dependents`];\n if (report.implicit.length > 0) parts.push(`${report.implicit.length} implicitly touched${this.targets(report)}`);\n if (report.rootFile.length > 0) parts.push(`${report.rootFile.length} root-file touched`);\n if (report.unexplained.length > 0) parts.push(`${report.unexplained.length} unexplained`);\n parts.push(`${report.buildInputs.length} dependencies`);\n return parts.join(' · ');\n }\n\n private targets(report: ImpactReport): string {\n const targets = new Set<string>();\n for (const reason of report.reasons)\n if (reason.kind === AffectedClass.IMPLICIT && reason.target !== '') targets.add(reason.target);\n return targets.size === 0 ? '' : ` (${[...targets].sort().join(', ')} inputs)`;\n }\n}\n\n/** The sidecar's one global: every scan, and the one the page shows first. */\nexport class ImpactSidecarData {\n constructor(\n public readonly scans: ImpactReport[],\n public readonly defaultKind: ImpactKind,\n ) {}\n}\n\n/** A scan (or a whole plan) that could not produce an answer. */\nexport class ImpactUnavailable {\n constructor(\n public readonly reason: string,\n public readonly label: string = 'Impact',\n ) {}\n}\n\n/** One comparison to scan. `base` is a full sha; null when it does not exist (`reason` says why). */\nexport class ImpactComparison {\n constructor(\n public readonly kind: ImpactKind,\n public readonly base: string | null,\n public readonly label: string,\n public readonly dirty: boolean,\n public readonly reason: string,\n ) {}\n}\n\n/** The comparisons that exist where HEAD is, and which one the page shows first. */\nexport class ImpactPlan {\n constructor(\n public readonly comparisons: ImpactComparison[],\n public readonly defaultKind: ImpactKind,\n ) {}\n}\n\n/** The few git facts the resolver needs. Injected so specs never spawn git. */\nexport class ImpactGit {\n /** The checked-out branch's short name; null on a detached HEAD (or without git). */\n branch(root: string): string | null {\n return this.run(root, ['symbolic-ref', '--short', '-q', 'HEAD']);\n }\n\n /** The full sha `ref` names; null when it does not resolve (e.g. `HEAD^` on the first commit). */\n sha(root: string, ref: string): string | null {\n return this.run(root, ['rev-parse', '--verify', '-q', `${ref}^{commit}`]);\n }\n\n /** `git status --porcelain` is non-empty: uncommitted or untracked work. */\n dirty(root: string): boolean {\n return (this.run(root, ['status', '--porcelain']) ?? '') !== '';\n }\n\n /** HEAD's subject line ('' when unknown). */\n subject(root: string): string {\n return this.run(root, ['log', '-1', '--format=%s', 'HEAD']) ?? '';\n }\n\n /** Trimmed stdout, or null on any failure. */\n private run(root: string, args: string[]): string | null {\n const result = spawnSync('git', args, { cwd: root, encoding: 'utf8', stdio: 'pipe' });\n if (result.error !== undefined || result.status !== 0) return null;\n return result.stdout.trim();\n }\n}\n\n/**\n * Decides which comparisons exist from where HEAD is (#1163):\n *\n * | where | comparisons | default |\n * |---|---|---|\n * | `main` (by branch NAME) | last commit | last commit |\n * | detached HEAD | last commit | last commit |\n * | feature branch with commits past the fork point | branch, last commit | branch |\n * | fresh feature branch (fork point = HEAD) | branch | branch |\n *\n * HEAD with no parent leaves the last commit unavailable, with `ROOT_COMMIT_REASON`.\n */\nexport class ImpactScopeResolver {\n constructor(\n private readonly git: ImpactGit = new ImpactGit(),\n private readonly diffScope: DiffScope = new DiffScope(),\n ) {}\n\n resolve(root: string): ImpactPlan | ImpactUnavailable {\n const head = this.git.sha(root, 'HEAD');\n if (head === null) return new ImpactUnavailable('git cannot resolve HEAD (not a git checkout, or git is unavailable)');\n const branch = this.git.branch(root);\n const dirty = this.git.dirty(root);\n const commit = this.lastCommit(root, dirty);\n // On main the decision is the branch NAME, never merge-base: unpushed commits still mean \"last commit\".\n if (branch === null || branch === MAIN_BRANCH) return new ImpactPlan([commit], ImpactKind.COMMIT);\n const fork = this.diffScope.detectBase(root);\n if (fork === null) {\n const reason = 'no fork point: neither origin/main nor main resolves';\n return new ImpactPlan(\n [new ImpactComparison(ImpactKind.BRANCH, null, 'Changed on this branch', dirty, reason)],\n ImpactKind.BRANCH,\n );\n }\n const onBranch = new ImpactComparison(\n ImpactKind.BRANCH,\n fork,\n `Changed on this branch (since ${this.short(fork)})${dirty ? UNCOMMITTED_SUFFIX : ''}`,\n dirty,\n '',\n );\n // A fresh branch has no commit of its own: \"last commit\" would be main's last PR, not its work.\n if (this.sameCommit(fork, head)) return new ImpactPlan([onBranch], ImpactKind.BRANCH);\n return new ImpactPlan([onBranch, commit], ImpactKind.BRANCH);\n }\n\n private lastCommit(root: string, dirty: boolean): ImpactComparison {\n const parent = this.git.sha(root, 'HEAD^');\n if (parent === null) return new ImpactComparison(ImpactKind.COMMIT, null, 'Last commit', dirty, ROOT_COMMIT_REASON);\n const subject = this.git.subject(root);\n const label =\n `Changed since ${this.short(parent)}${subject === '' ? '' : ` — ${subject}`}` +\n (dirty ? UNCOMMITTED_SUFFIX : '');\n return new ImpactComparison(ImpactKind.COMMIT, parent, label, dirty, '');\n }\n\n /** detectBase may hand back a full or an abbreviated sha; compare on the shorter of the two. */\n private sameCommit(a: string, b: string): boolean {\n const length = Math.min(a.length, b.length);\n return length > 0 && a.slice(0, length) === b.slice(0, length);\n }\n\n private short(sha: string): string {\n return sha.slice(0, 7);\n }\n}\n\n/** Runs the workspace's own nx CLI. Injected so specs never spawn nx. */\nexport class NxCli {\n /** stdout, or null when nx cannot be found, exits non-zero or exceeds the timeout. */\n run(workspaceRoot: string, args: string[], timeoutMs: number): string | null {\n const bin = this.binary(workspaceRoot);\n if (bin === null) return null;\n const result = spawnSync(process.execPath, [bin, ...args], {\n cwd: workspaceRoot,\n encoding: 'utf8',\n timeout: timeoutMs,\n stdio: 'pipe',\n maxBuffer: 16 * 1024 * 1024,\n });\n if (result.error !== undefined || result.status !== 0) return null;\n return result.stdout;\n }\n\n /** Resolved the way node would from the workspace, so a linked worktree finds its main tree's nx. */\n private binary(workspaceRoot: string): string | null {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- a workspace without nx resolves nothing; that is an answer, not an error\n try {\n return require.resolve('nx/bin/nx.js', { paths: [workspaceRoot] });\n } catch (err: unknown) {\n const error = toError(err);\n void error; // no nx installed here — Impact is simply unavailable\n return null;\n }\n }\n}\n\n/**\n * The workspace's nx facts every comparison classifies against: its project graph (with npm nodes\n * and every edge), nx.json, package.json, and nx's own affected locators. Subclassed by specs.\n */\nexport class AffectedContext {\n constructor(\n public readonly graph: ProjectGraph,\n public readonly nxJson: NxJsonConfiguration,\n public readonly packageJson: PackageJson,\n public readonly classifier: AffectedClassifier,\n private readonly nx: WorkspaceNx | null,\n ) {}\n\n /** nx's FileChange list for `files`, base → working tree. */\n fileChanges(files: string[], base: string): FileChange[] {\n if (this.nx === null) throw new Error('no workspace nx to read file changes with');\n return this.nx.fileChanges(files, base);\n }\n}\n\n/** Loads the workspace's nx facts. Injected so specs never load the real project graph. */\nexport class AffectedContextLoader {\n async load(workspaceRoot: string): Promise<AffectedContext> {\n const nx = new WorkspaceNx(workspaceRoot);\n return new AffectedContext(\n await createProjectGraphAsync(),\n nx.nxJson(),\n nx.packageJson(),\n new AffectedClassifier(nx.locators()),\n nx,\n );\n }\n}\n\n/**\n * The context, loaded at most ONCE however many comparisons ask for it. Failing is not fatal: every\n * affected project is then \"unexplained\", with this error as its reason — never a dependent.\n */\nexport class SharedContext {\n private pending: Promise<AffectedContext | Error> | null = null;\n\n constructor(\n private readonly loader: AffectedContextLoader,\n private readonly workspaceRoot: string,\n ) {}\n\n get(): Promise<AffectedContext | Error> {\n if (this.pending === null) this.pending = this.load();\n return this.pending;\n }\n\n private async load(): Promise<AffectedContext | Error> {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- the reasons are optional; the affected set still shows\n try {\n return await this.loader.load(this.workspaceRoot);\n } catch (err: unknown) {\n const error = toError(err);\n console.warn(`⚠️ Impact: nx's affected locators unavailable (${error.message}); reasons unknown`);\n return error;\n }\n }\n}\n\nexport class NxImpactScanner {\n private readonly names = new GraphNames();\n\n constructor(\n private readonly diffScope: DiffScope = new DiffScope(),\n private readonly nx: NxCli = new NxCli(),\n private readonly loader: AffectedContextLoader = new AffectedContextLoader(),\n ) {}\n\n /** Every comparison, in order, sharing one nx context. */\n async scanAll(\n workspaceRoot: string,\n graph: EnhancedGraph,\n comparisons: ImpactComparison[],\n ): Promise<(ImpactReport | ImpactUnavailable)[]> {\n const context = new SharedContext(this.loader, workspaceRoot);\n const results: (ImpactReport | ImpactUnavailable)[] = [];\n for (const comparison of comparisons) results.push(await this.scan(workspaceRoot, graph, comparison, context));\n return results;\n }\n\n /** One comparison: nx affected from ITS base, with NO `--head`, so uncommitted work counts. */\n async scan(\n workspaceRoot: string,\n graph: EnhancedGraph,\n comparison: ImpactComparison,\n context: SharedContext = new SharedContext(this.loader, workspaceRoot),\n ): Promise<ImpactReport | ImpactUnavailable> {\n const base = comparison.base;\n if (base === null) return this.empty(comparison, false, comparison.reason, '', 0);\n const json = this.nx.run(workspaceRoot, ['show', 'projects', '--affected', `--base=${base}`, '--json'], NX_TIMEOUT_MS);\n if (json === null)\n return new ImpactUnavailable(`nx show projects --affected failed or took over ${NX_TIMEOUT_MS / 1000}s`, comparison.label);\n const affectedSet = this.parse(json);\n if (affectedSet === null)\n return new ImpactUnavailable('nx show projects --affected printed something other than a JSON list', comparison.label);\n const options = new ChangedFilesOptions();\n options.tsOnly = false;\n options.includeDeletions = true;\n const files = this.diffScope.getChangedFiles(workspaceRoot, base, undefined, options);\n const short = base.slice(0, 7);\n const drawn = affectedSet.filter((project: string): boolean => graph[project] !== undefined);\n if (drawn.length === 0)\n return this.empty(comparison, true, this.emptyNote(comparison, files.length, short), short, files.length);\n const classification = await this.classify(await context.get(), files, base, affectedSet);\n return this.report(comparison, short, files.length, graph, classification);\n }\n\n /** nx's locators' answer; any failure makes every affected project \"unexplained\", with the reason. */\n async classify(\n context: AffectedContext | Error,\n files: string[],\n base: string,\n affected: string[],\n ): Promise<AffectedClassification> {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- the reasons are optional; a locator failure leaves them unknown\n try {\n if (context instanceof Error) throw context;\n const changes = context.fileChanges(files, base);\n return await context.classifier.classify(\n new AffectedInputs(context.graph, context.nxJson, context.packageJson, changes, affected),\n );\n } catch (err: unknown) {\n const error = toError(err);\n const why = `nx's affected locators could not run here (${error.message}), so why nx marked it is unknown`;\n return new AffectedClassification(\n [...affected].sort().map(\n (project: string): AffectedReason =>\n new AffectedReason(project, AffectedClass.UNEXPLAINED, [], [], '', '', why),\n ),\n [],\n );\n }\n }\n\n /**\n * An empty scan is still an ANSWER (available, zero sets): a fresh branch with a clean tree has\n * simply changed nothing yet, and the page says so instead of disabling Impact.\n */\n emptyNote(comparison: ImpactComparison, changedFiles: number, short: string): string {\n if (changedFiles === 0 && comparison.kind === ImpactKind.BRANCH) return NOTHING_CHANGED_ON_BRANCH;\n if (changedFiles === 0) return `Nothing changed since ${short}`;\n return `Nothing affected since ${short}`;\n }\n\n /**\n * Every transitive dependency of `roots` that is not itself one of them: a pure downward walk over\n * the graph's own dependsOn edges, no nx call. Of the affected set these are the build inputs; of\n * the touched set, \"Changed + dependencies\".\n */\n buildInputs(roots: string[], graph: EnhancedGraph): string[] {\n const inSet = new Set<string>(roots);\n const seen = new Set<string>(roots);\n const stack = [...roots];\n const inputs: string[] = [];\n while (stack.length > 0) {\n const project = stack.pop() as string;\n for (const dep of graph[project]?.dependsOn ?? []) {\n if (seen.has(dep)) continue;\n seen.add(dep);\n stack.push(dep);\n if (!inSet.has(dep) && graph[dep] !== undefined) inputs.push(dep);\n }\n }\n return inputs.sort();\n }\n\n /** The JSON list of project names, sorted; null when it is not a list of names. */\n parse(json: string): string[] | null {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- untrusted CLI output; anything unparseable is reported as a reason\n try {\n // webpieces-disable no-any-unknown -- CLI JSON is untrusted until narrowed below\n const parsed: unknown = JSON.parse(json);\n if (!Array.isArray(parsed)) return null;\n return parsed.filter((name: unknown): name is string => typeof name === 'string').sort();\n } catch (err: unknown) {\n const error = toError(err);\n void error; // not JSON — the caller reports it\n return null;\n }\n }\n\n /** The drawn projects only: a reason for a project the page does not draw has nowhere to show. */\n private report(\n comparison: ImpactComparison,\n short: string,\n changedFiles: number,\n graph: EnhancedGraph,\n classification: AffectedClassification,\n ): ImpactReport {\n const drawn = (projects: string[]): string[] =>\n projects.filter((project: string): boolean => graph[project] !== undefined);\n const touched = drawn(classification.of(AffectedClass.CHANGED));\n const affected = drawn(classification.reasons.map((reason: AffectedReason): string => reason.project));\n return new ImpactReport(\n comparison.kind,\n comparison.label,\n comparison.dirty,\n true,\n '',\n short,\n this.ids(touched),\n this.ids(drawn(classification.of(AffectedClass.DEPENDENT))),\n this.ids(drawn(classification.of(AffectedClass.IMPLICIT))),\n this.ids(drawn(classification.of(AffectedClass.ROOT_FILE))),\n this.ids(drawn(classification.of(AffectedClass.UNEXPLAINED))),\n this.ids(this.buildInputs(affected, graph)),\n changedFiles,\n this.ids(this.buildInputs(touched, graph)),\n classification.globalFiles,\n classification.reasons.filter((reason: AffectedReason): boolean => graph[reason.project] !== undefined),\n );\n }\n\n private empty(comparison: ImpactComparison, available: boolean, reason: string, base: string, changedFiles: number): ImpactReport {\n return new ImpactReport(comparison.kind, comparison.label, comparison.dirty, available, reason, base, [], [], [], [], [], [], changedFiles, [], [], []);\n }\n\n private ids(projects: string[]): string[] {\n return projects.map((project: string): string => this.names.getNodeId(project));\n }\n}\n\n/** Writes (or removes) the sidecar, self-ignored, beside architecture/dependencies.html. */\nexport class ImpactSidecar {\n /** Never throws: a sidecar that cannot be written just leaves Impact disabled on the page. */\n write(architectureDir: string, data: ImpactSidecarData): string | null {\n const dir = path.join(architectureDir, IMPACT_SIDECAR_DIR);\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- impact is optional; a write failure must never fail generation\n try {\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(\n path.join(dir, '.gitignore'),\n '# Written by architecture:generate and architecture:visualize. Per-checkout data: never commit it.\\n*\\n',\n 'utf-8',\n );\n const file = path.join(dir, IMPACT_SIDECAR_FILE);\n fs.writeFileSync(file, this.script(data), 'utf-8');\n return file;\n } catch (err: unknown) {\n const error = toError(err);\n console.warn(`⚠️ Could not write the impact sidecar: ${error.message}`);\n return null;\n }\n }\n\n /** A stale sidecar from an earlier checkout must never be shown as this one's impact. */\n remove(architectureDir: string): void {\n fs.rmSync(path.join(architectureDir, IMPACT_SIDECAR_DIR, IMPACT_SIDECAR_FILE), { force: true });\n }\n\n script(data: ImpactSidecarData): string {\n const json = JSON.stringify(data).replace(/</g, '\\\\u003c');\n return `// Generated by architecture:generate or architecture:visualize for one checkout. Gitignored; do not commit.\\nwindow.__WP_IMPACT__ = ${json};\\n`;\n }\n}\n\n/** The executors' one call: resolve, scan each comparison, write, and report one line per comparison. */\nexport class ImpactRefresh {\n constructor(\n private readonly scanner: NxImpactScanner = new NxImpactScanner(),\n private readonly sidecar: ImpactSidecar = new ImpactSidecar(),\n private readonly resolver: ImpactScopeResolver = new ImpactScopeResolver(),\n ) {}\n\n /**\n * Scans the comparisons in `kinds` that exist here (`VISUALIZE_IMPACT_KINDS` /\n * `GENERATE_IMPACT_KINDS`). Never throws — Impact is optional, generation is not.\n */\n async run(\n architectureDir: string,\n workspaceRoot: string,\n graph: EnhancedGraph,\n kinds: readonly ImpactKind[],\n ): Promise<string> {\n const started = Date.now();\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- impact is optional; any failure becomes a reason, never a failed generation\n try {\n const plan = this.resolver.resolve(workspaceRoot);\n if (plan instanceof ImpactUnavailable) return this.none(architectureDir, plan.reason, started);\n const comparisons = plan.comparisons.filter(\n (comparison: ImpactComparison): boolean => kinds.includes(comparison.kind),\n );\n if (comparisons.length === 0)\n return this.none(\n architectureDir,\n 'no Changed-on-this-branch comparison on main or a detached HEAD; pnpm arch:visualize shows the last commit',\n started,\n );\n const results = await this.scanner.scanAll(workspaceRoot, graph, comparisons);\n const lines = results.map((result: ImpactReport | ImpactUnavailable): string => this.line(result));\n const scans = results.filter(\n (result: ImpactReport | ImpactUnavailable): result is ImpactReport => result instanceof ImpactReport,\n );\n const cost = `${Date.now() - started} ms`;\n if (scans.length === 0) {\n this.sidecar.remove(architectureDir);\n return [...lines, `ℹ️ Impact disabled, no sidecar written (${cost})`].join('\\n');\n }\n const file = this.sidecar.write(architectureDir, new ImpactSidecarData(scans, this.defaultKind(scans, plan.defaultKind)));\n return [...lines, file === null ? `⚠️ Impact sidecar not written (${cost})` : `→ ${file} (${cost})`].join('\\n');\n } catch (err: unknown) {\n const error = toError(err);\n this.sidecar.remove(architectureDir);\n return `⚠️ Impact skipped: ${error.message}`;\n }\n }\n\n /** The plan's default when that scan is available, else the first available one. */\n private defaultKind(scans: ImpactReport[], preferred: ImpactKind): ImpactKind {\n const usable = scans.filter((scan: ImpactReport): boolean => scan.available);\n if (usable.length === 0 || usable.some((scan: ImpactReport): boolean => scan.kind === preferred)) return preferred;\n return usable[0].kind;\n }\n\n private none(architectureDir: string, reason: string, started: number): string {\n this.sidecar.remove(architectureDir);\n return `ℹ️ Impact disabled, no sidecar written: ${reason} (${Date.now() - started} ms)`;\n }\n\n private line(result: ImpactReport | ImpactUnavailable): string {\n if (result instanceof ImpactUnavailable || !result.available)\n return `ℹ️ Impact · ${result.label}: unavailable — ${result.reason}`;\n if (result.reason !== '') return `✅ Impact · ${result.label}: ${result.reason}`;\n return `✅ Impact · ${result.label}: ${new ImpactCounts().line(result)}, from ${result.changedFiles} changed file(s)`;\n }\n}\n"]}
@@ -21,8 +21,9 @@ export declare class GraphLegend {
21
21
  runtimeRows(facts: LegendFacts): string;
22
22
  architectureRows(facts: LegendFacts): string;
23
23
  /**
24
- * Which box is which is only known from the branch's sidecar, so all four rows always show. The
25
- * words are the Filter's (#1179): changed · dependent · dependency · not in this build.
24
+ * Which box is which is only known from the branch's sidecar, so every row shows except
25
+ * "unexplained", which the page shows only when the active scan has one. Each affected class says
26
+ * WHY nx included it (#1264) — only the dependent row claims "uses a changed project".
26
27
  */
27
28
  impactRows(): string;
28
29
  /**
@@ -40,6 +41,8 @@ export declare class GraphLegend {
40
41
  private frame;
41
42
  /** A base runtime is solid; a specialization is its inset on the base color. */
42
43
  private envSwatch;
44
+ /** The implicitly-touched hatch: thin alternating violet stripes inside a violet ring. */
45
+ private hatchSwatch;
43
46
  private stripesSwatch;
44
47
  /** The first three product colors as stripes: the "several products" swatch. */
45
48
  private productStripes;
@@ -67,12 +67,16 @@ class GraphLegend {
67
67
  return rows;
68
68
  }
69
69
  /**
70
- * Which box is which is only known from the branch's sidecar, so all four rows always show. The
71
- * words are the Filter's (#1179): changed · dependent · dependency · not in this build.
70
+ * Which box is which is only known from the branch's sidecar, so every row shows except
71
+ * "unexplained", which the page shows only when the active scan has one. Each affected class says
72
+ * WHY nx included it (#1264) — only the dependent row claims "uses a changed project".
72
73
  */
73
74
  impactRows() {
74
75
  return (this.row('touched', this.solid(graph_color_modes_1.IMPACT_TOUCHED, '', ''), 'changed', 'owns a changed file') +
75
- this.row('affected', this.solid(graph_color_modes_1.IMPACT_AFFECTED, graph_color_modes_1.IMPACT_TOUCHED, ''), 'dependent', 'uses a changed project: its tests and build re-run') +
76
+ this.row('dependent', this.solid(graph_color_modes_1.IMPACT_DEPENDENT, graph_color_modes_1.IMPACT_TOUCHED, ''), 'dependent', 'uses a changed project: its tests and build re-run (click it for the path)') +
77
+ this.row('implicit', this.hatchSwatch(), 'implicitly touched', 'a target input glob ({workspaceRoot}/…) matched a changed file; it uses no changed project') +
78
+ this.row('rootFile', this.solid(graph_color_modes_1.IMPACT_ROOT_FILE, graph_color_modes_1.IMPACT_ROOT_FILE_BORDER, ''), 'root-file touched', 'a lockfile, package.json, tsconfig.base.json or nx.json change marked it') +
79
+ this.row('unexplained', this.solid(graph_color_modes_1.IMPACT_DEPENDENT, graph_color_modes_1.IMPACT_UNEXPLAINED_BORDER, '3 2'), 'unexplained', 'nx marked it affected; nothing here could say why') +
76
80
  this.row('build-input', this.solid(graph_color_modes_1.IMPACT_BUILD_INPUT, graph_color_modes_1.IMPACT_BUILD_INPUT_BORDER, '3 2'), 'dependency (built, unchanged)', 'compiled or restored from cache for this build') +
77
81
  this.row('untouched', this.solid(graph_color_modes_1.IMPACT_UNTOUCHED, '', ''), 'not in this build', 'nothing here changed or depends on a change') +
78
82
  '<p class="wp-impact-note" data-wp-impact-note></p>');
@@ -136,6 +140,16 @@ class GraphLegend {
136
140
  const inset = `<rect x="4" y="4" width="${SWATCH_W - 8}" height="${SWATCH_H - 8}" rx="2" fill="${style.color}"/>`;
137
141
  return this.open() + base + inset + this.frame();
138
142
  }
143
+ /** The implicitly-touched hatch: thin alternating violet stripes inside a violet ring. */
144
+ hatchSwatch() {
145
+ const count = 8;
146
+ const width = SWATCH_W / count;
147
+ let stripes = '';
148
+ for (let index = 0; index < count; index++)
149
+ stripes += `<rect x="${(index * width).toFixed(2)}" width="${width.toFixed(2)}" height="${SWATCH_H}" fill="${index % 2 === 0 ? graph_color_modes_1.IMPACT_IMPLICIT : graph_color_modes_1.IMPACT_IMPLICIT_GAP}"/>`;
150
+ const ring = `<rect x="2" y="2" width="${SWATCH_W - 4}" height="${SWATCH_H - 4}" fill="none" stroke="${graph_color_modes_1.IMPACT_IMPLICIT_BORDER}" stroke-width="2"/>`;
151
+ return this.open() + stripes + ring + this.frame();
152
+ }
139
153
  stripesSwatch() {
140
154
  const width = SWATCH_W / graph_color_modes_1.BASE_ORDER.length;
141
155
  const stripes = graph_color_modes_1.BASE_ORDER.map((base, index) => `<rect x="${(index * width).toFixed(2)}" width="${width.toFixed(2)}" height="${SWATCH_H}" fill="${graph_color_modes_1.FRAMEWORK_STYLES[base].color}"/>`).join('');
@@ -1 +1 @@
1
- {"version":3,"file":"graph-legend.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-legend.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The architecture graph's legend, generated per color mode FROM THE PROJECTS ACTUALLY DRAWN.\n *\n * The hand-written legend this replaces listed five frameworks when six existed and never mentioned\n * the `app` and `bundle` borders the renderer drew (#1155). Generating the rows from the same tables\n * the renderer colors with (graph-color-modes.ts) means a color in use always has a row, and a color\n * nothing uses never does.\n *\n * Swatches are inline SVG drawn with presentation attributes, never `style=`, so the page carries\n * no inline CSS.\n */\n\nimport { KNOWN_FRAMEWORKS, KnownFramework } from '@webpieces/rules-sdk';\nimport {\n BASE_ORDER,\n FRAMEWORK_STYLES,\n FrameworkStyle,\n GraphMode,\n IMPACT_AFFECTED,\n IMPACT_BUILD_INPUT,\n IMPACT_BUILD_INPUT_BORDER,\n IMPACT_TOUCHED,\n IMPACT_UNTOUCHED,\n LegendFacts,\n NO_RUNTIME_COLOR,\n ROLE_STYLES,\n RoleStyle,\n} from './graph-color-modes';\nimport {\n PRODUCT_NONE_BORDER,\n PRODUCT_NONE_FILL,\n PRODUCT_SHARED_FILL,\n ProductColor,\n ProductPalette,\n} from './graph-products';\nimport type { ProductDependencyEntry } from '../configs/tag-truth-configs';\n\nconst SWATCH_W = 26;\nconst SWATCH_H = 16;\nconst FRAME = '#3a3c46';\n\nexport class GraphLegend {\n /** One section per mode; the page shows the section of the current mode and hides the rest. */\n sections(facts: LegendFacts): string {\n return (\n this.section(GraphMode.RUNTIME, this.runtimeRows(facts), false) +\n this.section(GraphMode.ARCHITECTURE, this.architectureRows(facts), true) +\n this.section(GraphMode.IMPACT, this.impactRows(), true) +\n this.section(GraphMode.PRODUCT, this.productRows(facts), true)\n );\n }\n\n /** The edge key: why a line exists. Static — every graph can carry every edge kind. */\n edgeKey(): string {\n return (\n '<div class=\"wp-legend-list\">' +\n this.edgeRow('#e9eaf0', '', 'uses', 'calls the API, or a plain library import') +\n this.edgeRow('#e9eaf0', '4 3', 'implements', 'serves the API (labeled with its contracts)') +\n this.edgeRow('#7aa2ff', '4 3', 'uses + implements', 'implements some contracts, uses others') +\n '</div>'\n );\n }\n\n private section(mode: GraphMode, rows: string, hidden: boolean): string {\n const hide = hidden ? ' hidden' : '';\n return `<div class=\"wp-legend-list\" data-wp-legend-mode=\"${mode}\"${hide}>${rows}</div>`;\n }\n\n /** Base runtimes first (stripe order), then specializations, in the shared vocabulary's order. */\n runtimeRows(facts: LegendFacts): string {\n const present = (framework: KnownFramework): boolean => facts.frameworks.includes(framework);\n const ordered: FrameworkStyle[] = [\n ...BASE_ORDER.map((base: KnownFramework): FrameworkStyle => FRAMEWORK_STYLES[base]),\n ...KNOWN_FRAMEWORKS.map((f: KnownFramework): FrameworkStyle => FRAMEWORK_STYLES[f]).filter(\n (style: FrameworkStyle): boolean => !style.isBase(),\n ),\n ];\n let rows = '';\n for (const style of ordered) {\n if (!present(style.framework)) continue;\n rows += this.row(style.framework, this.envSwatch(style), style.framework, style.description);\n }\n if (facts.multiRuntime)\n rows += this.row('multi', this.stripesSwatch(), 'several runtimes', 'one equal stripe per runtime');\n if (facts.noRuntime)\n rows += this.row('none', this.solid(NO_RUNTIME_COLOR, '', ''), 'no framework tag', 'runs nowhere declared');\n return rows;\n }\n\n architectureRows(facts: LegendFacts): string {\n let rows = '';\n for (const style of ROLE_STYLES) {\n if (!facts.roles.includes(style.role)) continue;\n rows += this.row(style.role, this.roleSwatch(style), style.role, style.description);\n }\n return rows;\n }\n\n /**\n * Which box is which is only known from the branch's sidecar, so all four rows always show. The\n * words are the Filter's (#1179): changed · dependent · dependency · not in this build.\n */\n impactRows(): string {\n return (\n this.row('touched', this.solid(IMPACT_TOUCHED, '', ''), 'changed', 'owns a changed file') +\n this.row(\n 'affected',\n this.solid(IMPACT_AFFECTED, IMPACT_TOUCHED, ''),\n 'dependent',\n 'uses a changed project: its tests and build re-run',\n ) +\n this.row(\n 'build-input',\n this.solid(IMPACT_BUILD_INPUT, IMPACT_BUILD_INPUT_BORDER, '3 2'),\n 'dependency (built, unchanged)',\n 'compiled or restored from cache for this build',\n ) +\n this.row('untouched', this.solid(IMPACT_UNTOUCHED, '', ''), 'not in this build', 'nothing here changed or depends on a change') +\n '<p class=\"wp-impact-note\" data-wp-impact-note></p>'\n );\n }\n\n /**\n * Product mode (#1179): one row per product with its counts, then the shared, several-products and\n * no-product rows that some drawn box actually uses.\n */\n productRows(facts: LegendFacts): string {\n if (facts.products.length === 0)\n return this.row(\n 'no-products',\n this.solid(PRODUCT_NONE_FILL, PRODUCT_NONE_BORDER, '3 2'),\n 'no products declared',\n 'tag each project product:<name> to see each product',\n );\n const palette = facts.palette;\n let rows = '';\n for (const count of facts.products) {\n const color = palette.colorOf(count.product);\n const detail = `${count.only} only ${count.product}`;\n rows += this.row(`product:${count.product}`, this.solid(color.color, '', ''), `${count.product} · ${count.total}`, detail);\n }\n if (facts.sharedByAll > 0)\n rows += this.row(\n 'shared',\n this.solid(PRODUCT_SHARED_FILL, '', ''),\n `shared by every product · ${facts.sharedByAll}`,\n 'a change here is a change to every product',\n );\n if (facts.multiProduct)\n rows += this.row('several', this.productStripes(palette), 'several products', 'one stripe per product');\n if (facts.noProduct > 0)\n rows += this.row(\n 'no-product',\n this.solid(PRODUCT_NONE_FILL, PRODUCT_NONE_BORDER, '3 2'),\n `no product · ${facts.noProduct}`,\n 'needs a product:<name> tag',\n );\n return rows + this.boundaryRows(facts, palette);\n }\n\n /**\n * #1204: the dashed cross-product edge, and the product dependency matrix that allows each such\n * edge — `example → openapi, platform` — when the `product-tags` rule supplied one.\n */\n boundaryRows(facts: LegendFacts, palette: ProductPalette): string {\n let rows = '';\n if (facts.crossProductEdges > 0)\n rows += this.row(\n 'cross-product',\n this.line(PRODUCT_NONE_BORDER, '4 3'),\n `crosses into another product · ${facts.crossProductEdges}`,\n \"dashed, in the color of the product it depends on\",\n );\n const matrix = facts.productDependencies;\n if (matrix === null) return rows;\n const stated = matrix.filter((entry: ProductDependencyEntry): boolean => entry.allowedToDependOn.length > 0);\n if (stated.length === 0)\n return (\n rows +\n this.row(\n 'allowed-none',\n this.line(PRODUCT_NONE_BORDER, ''),\n 'no product may depend on another',\n 'product-tags.productDependencies allows no crossing',\n )\n );\n for (const entry of [...stated].sort((a: ProductDependencyEntry, b: ProductDependencyEntry): number => a.name.localeCompare(b.name)))\n rows += this.row(\n `allowed:${entry.name}`,\n this.line(palette.colorOf(entry.name).color, ''),\n `${entry.name} → ${[...entry.allowedToDependOn].sort().join(', ')}`,\n 'allowed by product-tags.productDependencies',\n );\n return rows;\n }\n\n private row(key: string, swatch: string, title: string, detail: string): string {\n return (\n `<div class=\"wp-legend-row\" data-wp-legend=\"${key}\">${swatch}` +\n `<span>${title}<small>${detail}</small></span></div>`\n );\n }\n\n private open(): string {\n return `<svg width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" viewBox=\"0 0 ${SWATCH_W} ${SWATCH_H}\" aria-hidden=\"true\">`;\n }\n\n private frame(): string {\n return `<rect x=\"0.5\" y=\"0.5\" width=\"${SWATCH_W - 1}\" height=\"${SWATCH_H - 1}\" fill=\"none\" stroke=\"${FRAME}\"/></svg>`;\n }\n\n /** A base runtime is solid; a specialization is its inset on the base color. */\n private envSwatch(style: FrameworkStyle): string {\n const base = `<rect width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" fill=\"${FRAMEWORK_STYLES[style.base].color}\"/>`;\n if (style.isBase()) return this.open() + base + this.frame();\n const inset = `<rect x=\"4\" y=\"4\" width=\"${SWATCH_W - 8}\" height=\"${SWATCH_H - 8}\" rx=\"2\" fill=\"${style.color}\"/>`;\n return this.open() + base + inset + this.frame();\n }\n\n private stripesSwatch(): string {\n const width = SWATCH_W / BASE_ORDER.length;\n const stripes = BASE_ORDER.map(\n (base: KnownFramework, index: number): string =>\n `<rect x=\"${(index * width).toFixed(2)}\" width=\"${width.toFixed(2)}\" height=\"${SWATCH_H}\" fill=\"${FRAMEWORK_STYLES[base].color}\"/>`,\n ).join('');\n return this.open() + stripes + this.frame();\n }\n\n /** The first three product colors as stripes: the \"several products\" swatch. */\n private productStripes(palette: ProductPalette): string {\n const colors = palette.colors.slice(0, 3);\n const width = SWATCH_W / colors.length;\n const stripes = colors\n .map(\n (color: ProductColor, index: number): string =>\n `<rect x=\"${(index * width).toFixed(2)}\" width=\"${width.toFixed(2)}\" height=\"${SWATCH_H}\" fill=\"${color.color}\"/>`,\n )\n .join('');\n return this.open() + stripes + this.frame();\n }\n\n private roleSwatch(style: RoleStyle): string {\n return this.solid(style.fill, '', '');\n }\n\n /** A filled swatch, optionally with an inner ring (dashed when `dash` is set). */\n private solid(fill: string, outline: string, dash: string): string {\n const dashed = dash === '' ? '' : ` stroke-dasharray=\"${dash}\"`;\n const ring =\n outline === ''\n ? ''\n : `<rect x=\"2\" y=\"2\" width=\"${SWATCH_W - 4}\" height=\"${SWATCH_H - 4}\" fill=\"none\" stroke=\"${outline}\" stroke-width=\"2\"${dashed}/>`;\n return this.open() + `<rect width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" fill=\"${fill}\"/>` + ring + this.frame();\n }\n\n private edgeRow(color: string, dash: string, title: string, detail: string): string {\n return this.row(title, this.line(color, dash), title, detail);\n }\n\n /** An edge swatch: a short line, dashed when `dash` is set. */\n private line(color: string, dash: string): string {\n const dashed = dash === '' ? '' : ` stroke-dasharray=\"${dash}\"`;\n return `<svg width=\"28\" height=\"10\" aria-hidden=\"true\"><line x1=\"0\" y1=\"5\" x2=\"28\" y2=\"5\" stroke=\"${color}\" stroke-width=\"1.6\"${dashed}/></svg>`;\n }\n}\n"]}
1
+ {"version":3,"file":"graph-legend.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-legend.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The architecture graph's legend, generated per color mode FROM THE PROJECTS ACTUALLY DRAWN.\n *\n * The hand-written legend this replaces listed five frameworks when six existed and never mentioned\n * the `app` and `bundle` borders the renderer drew (#1155). Generating the rows from the same tables\n * the renderer colors with (graph-color-modes.ts) means a color in use always has a row, and a color\n * nothing uses never does.\n *\n * Swatches are inline SVG drawn with presentation attributes, never `style=`, so the page carries\n * no inline CSS.\n */\n\nimport { KNOWN_FRAMEWORKS, KnownFramework } from '@webpieces/rules-sdk';\nimport {\n BASE_ORDER,\n FRAMEWORK_STYLES,\n FrameworkStyle,\n GraphMode,\n IMPACT_BUILD_INPUT,\n IMPACT_BUILD_INPUT_BORDER,\n IMPACT_DEPENDENT,\n IMPACT_IMPLICIT,\n IMPACT_IMPLICIT_BORDER,\n IMPACT_IMPLICIT_GAP,\n IMPACT_ROOT_FILE,\n IMPACT_ROOT_FILE_BORDER,\n IMPACT_TOUCHED,\n IMPACT_UNEXPLAINED_BORDER,\n IMPACT_UNTOUCHED,\n LegendFacts,\n NO_RUNTIME_COLOR,\n ROLE_STYLES,\n RoleStyle,\n} from './graph-color-modes';\nimport {\n PRODUCT_NONE_BORDER,\n PRODUCT_NONE_FILL,\n PRODUCT_SHARED_FILL,\n ProductColor,\n ProductPalette,\n} from './graph-products';\nimport type { ProductDependencyEntry } from '../configs/tag-truth-configs';\n\nconst SWATCH_W = 26;\nconst SWATCH_H = 16;\nconst FRAME = '#3a3c46';\n\nexport class GraphLegend {\n /** One section per mode; the page shows the section of the current mode and hides the rest. */\n sections(facts: LegendFacts): string {\n return (\n this.section(GraphMode.RUNTIME, this.runtimeRows(facts), false) +\n this.section(GraphMode.ARCHITECTURE, this.architectureRows(facts), true) +\n this.section(GraphMode.IMPACT, this.impactRows(), true) +\n this.section(GraphMode.PRODUCT, this.productRows(facts), true)\n );\n }\n\n /** The edge key: why a line exists. Static — every graph can carry every edge kind. */\n edgeKey(): string {\n return (\n '<div class=\"wp-legend-list\">' +\n this.edgeRow('#e9eaf0', '', 'uses', 'calls the API, or a plain library import') +\n this.edgeRow('#e9eaf0', '4 3', 'implements', 'serves the API (labeled with its contracts)') +\n this.edgeRow('#7aa2ff', '4 3', 'uses + implements', 'implements some contracts, uses others') +\n '</div>'\n );\n }\n\n private section(mode: GraphMode, rows: string, hidden: boolean): string {\n const hide = hidden ? ' hidden' : '';\n return `<div class=\"wp-legend-list\" data-wp-legend-mode=\"${mode}\"${hide}>${rows}</div>`;\n }\n\n /** Base runtimes first (stripe order), then specializations, in the shared vocabulary's order. */\n runtimeRows(facts: LegendFacts): string {\n const present = (framework: KnownFramework): boolean => facts.frameworks.includes(framework);\n const ordered: FrameworkStyle[] = [\n ...BASE_ORDER.map((base: KnownFramework): FrameworkStyle => FRAMEWORK_STYLES[base]),\n ...KNOWN_FRAMEWORKS.map((f: KnownFramework): FrameworkStyle => FRAMEWORK_STYLES[f]).filter(\n (style: FrameworkStyle): boolean => !style.isBase(),\n ),\n ];\n let rows = '';\n for (const style of ordered) {\n if (!present(style.framework)) continue;\n rows += this.row(style.framework, this.envSwatch(style), style.framework, style.description);\n }\n if (facts.multiRuntime)\n rows += this.row('multi', this.stripesSwatch(), 'several runtimes', 'one equal stripe per runtime');\n if (facts.noRuntime)\n rows += this.row('none', this.solid(NO_RUNTIME_COLOR, '', ''), 'no framework tag', 'runs nowhere declared');\n return rows;\n }\n\n architectureRows(facts: LegendFacts): string {\n let rows = '';\n for (const style of ROLE_STYLES) {\n if (!facts.roles.includes(style.role)) continue;\n rows += this.row(style.role, this.roleSwatch(style), style.role, style.description);\n }\n return rows;\n }\n\n /**\n * Which box is which is only known from the branch's sidecar, so every row shows except\n * \"unexplained\", which the page shows only when the active scan has one. Each affected class says\n * WHY nx included it (#1264) — only the dependent row claims \"uses a changed project\".\n */\n impactRows(): string {\n return (\n this.row('touched', this.solid(IMPACT_TOUCHED, '', ''), 'changed', 'owns a changed file') +\n this.row(\n 'dependent',\n this.solid(IMPACT_DEPENDENT, IMPACT_TOUCHED, ''),\n 'dependent',\n 'uses a changed project: its tests and build re-run (click it for the path)',\n ) +\n this.row(\n 'implicit',\n this.hatchSwatch(),\n 'implicitly touched',\n 'a target input glob ({workspaceRoot}/…) matched a changed file; it uses no changed project',\n ) +\n this.row(\n 'rootFile',\n this.solid(IMPACT_ROOT_FILE, IMPACT_ROOT_FILE_BORDER, ''),\n 'root-file touched',\n 'a lockfile, package.json, tsconfig.base.json or nx.json change marked it',\n ) +\n this.row(\n 'unexplained',\n this.solid(IMPACT_DEPENDENT, IMPACT_UNEXPLAINED_BORDER, '3 2'),\n 'unexplained',\n 'nx marked it affected; nothing here could say why',\n ) +\n this.row(\n 'build-input',\n this.solid(IMPACT_BUILD_INPUT, IMPACT_BUILD_INPUT_BORDER, '3 2'),\n 'dependency (built, unchanged)',\n 'compiled or restored from cache for this build',\n ) +\n this.row('untouched', this.solid(IMPACT_UNTOUCHED, '', ''), 'not in this build', 'nothing here changed or depends on a change') +\n '<p class=\"wp-impact-note\" data-wp-impact-note></p>'\n );\n }\n\n /**\n * Product mode (#1179): one row per product with its counts, then the shared, several-products and\n * no-product rows that some drawn box actually uses.\n */\n productRows(facts: LegendFacts): string {\n if (facts.products.length === 0)\n return this.row(\n 'no-products',\n this.solid(PRODUCT_NONE_FILL, PRODUCT_NONE_BORDER, '3 2'),\n 'no products declared',\n 'tag each project product:<name> to see each product',\n );\n const palette = facts.palette;\n let rows = '';\n for (const count of facts.products) {\n const color = palette.colorOf(count.product);\n const detail = `${count.only} only ${count.product}`;\n rows += this.row(`product:${count.product}`, this.solid(color.color, '', ''), `${count.product} · ${count.total}`, detail);\n }\n if (facts.sharedByAll > 0)\n rows += this.row(\n 'shared',\n this.solid(PRODUCT_SHARED_FILL, '', ''),\n `shared by every product · ${facts.sharedByAll}`,\n 'a change here is a change to every product',\n );\n if (facts.multiProduct)\n rows += this.row('several', this.productStripes(palette), 'several products', 'one stripe per product');\n if (facts.noProduct > 0)\n rows += this.row(\n 'no-product',\n this.solid(PRODUCT_NONE_FILL, PRODUCT_NONE_BORDER, '3 2'),\n `no product · ${facts.noProduct}`,\n 'needs a product:<name> tag',\n );\n return rows + this.boundaryRows(facts, palette);\n }\n\n /**\n * #1204: the dashed cross-product edge, and the product dependency matrix that allows each such\n * edge — `example → openapi, platform` — when the `product-tags` rule supplied one.\n */\n boundaryRows(facts: LegendFacts, palette: ProductPalette): string {\n let rows = '';\n if (facts.crossProductEdges > 0)\n rows += this.row(\n 'cross-product',\n this.line(PRODUCT_NONE_BORDER, '4 3'),\n `crosses into another product · ${facts.crossProductEdges}`,\n \"dashed, in the color of the product it depends on\",\n );\n const matrix = facts.productDependencies;\n if (matrix === null) return rows;\n const stated = matrix.filter((entry: ProductDependencyEntry): boolean => entry.allowedToDependOn.length > 0);\n if (stated.length === 0)\n return (\n rows +\n this.row(\n 'allowed-none',\n this.line(PRODUCT_NONE_BORDER, ''),\n 'no product may depend on another',\n 'product-tags.productDependencies allows no crossing',\n )\n );\n for (const entry of [...stated].sort((a: ProductDependencyEntry, b: ProductDependencyEntry): number => a.name.localeCompare(b.name)))\n rows += this.row(\n `allowed:${entry.name}`,\n this.line(palette.colorOf(entry.name).color, ''),\n `${entry.name} → ${[...entry.allowedToDependOn].sort().join(', ')}`,\n 'allowed by product-tags.productDependencies',\n );\n return rows;\n }\n\n private row(key: string, swatch: string, title: string, detail: string): string {\n return (\n `<div class=\"wp-legend-row\" data-wp-legend=\"${key}\">${swatch}` +\n `<span>${title}<small>${detail}</small></span></div>`\n );\n }\n\n private open(): string {\n return `<svg width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" viewBox=\"0 0 ${SWATCH_W} ${SWATCH_H}\" aria-hidden=\"true\">`;\n }\n\n private frame(): string {\n return `<rect x=\"0.5\" y=\"0.5\" width=\"${SWATCH_W - 1}\" height=\"${SWATCH_H - 1}\" fill=\"none\" stroke=\"${FRAME}\"/></svg>`;\n }\n\n /** A base runtime is solid; a specialization is its inset on the base color. */\n private envSwatch(style: FrameworkStyle): string {\n const base = `<rect width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" fill=\"${FRAMEWORK_STYLES[style.base].color}\"/>`;\n if (style.isBase()) return this.open() + base + this.frame();\n const inset = `<rect x=\"4\" y=\"4\" width=\"${SWATCH_W - 8}\" height=\"${SWATCH_H - 8}\" rx=\"2\" fill=\"${style.color}\"/>`;\n return this.open() + base + inset + this.frame();\n }\n\n /** The implicitly-touched hatch: thin alternating violet stripes inside a violet ring. */\n private hatchSwatch(): string {\n const count = 8;\n const width = SWATCH_W / count;\n let stripes = '';\n for (let index = 0; index < count; index++)\n stripes += `<rect x=\"${(index * width).toFixed(2)}\" width=\"${width.toFixed(2)}\" height=\"${SWATCH_H}\" fill=\"${index % 2 === 0 ? IMPACT_IMPLICIT : IMPACT_IMPLICIT_GAP}\"/>`;\n const ring = `<rect x=\"2\" y=\"2\" width=\"${SWATCH_W - 4}\" height=\"${SWATCH_H - 4}\" fill=\"none\" stroke=\"${IMPACT_IMPLICIT_BORDER}\" stroke-width=\"2\"/>`;\n return this.open() + stripes + ring + this.frame();\n }\n\n private stripesSwatch(): string {\n const width = SWATCH_W / BASE_ORDER.length;\n const stripes = BASE_ORDER.map(\n (base: KnownFramework, index: number): string =>\n `<rect x=\"${(index * width).toFixed(2)}\" width=\"${width.toFixed(2)}\" height=\"${SWATCH_H}\" fill=\"${FRAMEWORK_STYLES[base].color}\"/>`,\n ).join('');\n return this.open() + stripes + this.frame();\n }\n\n /** The first three product colors as stripes: the \"several products\" swatch. */\n private productStripes(palette: ProductPalette): string {\n const colors = palette.colors.slice(0, 3);\n const width = SWATCH_W / colors.length;\n const stripes = colors\n .map(\n (color: ProductColor, index: number): string =>\n `<rect x=\"${(index * width).toFixed(2)}\" width=\"${width.toFixed(2)}\" height=\"${SWATCH_H}\" fill=\"${color.color}\"/>`,\n )\n .join('');\n return this.open() + stripes + this.frame();\n }\n\n private roleSwatch(style: RoleStyle): string {\n return this.solid(style.fill, '', '');\n }\n\n /** A filled swatch, optionally with an inner ring (dashed when `dash` is set). */\n private solid(fill: string, outline: string, dash: string): string {\n const dashed = dash === '' ? '' : ` stroke-dasharray=\"${dash}\"`;\n const ring =\n outline === ''\n ? ''\n : `<rect x=\"2\" y=\"2\" width=\"${SWATCH_W - 4}\" height=\"${SWATCH_H - 4}\" fill=\"none\" stroke=\"${outline}\" stroke-width=\"2\"${dashed}/>`;\n return this.open() + `<rect width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" fill=\"${fill}\"/>` + ring + this.frame();\n }\n\n private edgeRow(color: string, dash: string, title: string, detail: string): string {\n return this.row(title, this.line(color, dash), title, detail);\n }\n\n /** An edge swatch: a short line, dashed when `dash` is set. */\n private line(color: string, dash: string): string {\n const dashed = dash === '' ? '' : ` stroke-dasharray=\"${dash}\"`;\n return `<svg width=\"28\" height=\"10\" aria-hidden=\"true\"><line x1=\"0\" y1=\"5\" x2=\"28\" y2=\"5\" stroke=\"${color}\" stroke-width=\"1.6\"${dashed}/></svg>`;\n }\n}\n"]}
@@ -32,8 +32,38 @@ declare class WpModeState {
32
32
  subtitle(mode: string): string;
33
33
  /** False (and nothing changes) for an unknown or unavailable mode. */
34
34
  set(mode: string): boolean;
35
- /** Which impact shade a box gets, from the ACTIVE scan. */
36
- status(id: string): 'touched' | 'affected' | 'buildInput' | 'untouched';
35
+ /** Which impact shade a box gets, from the ACTIVE scan: WHY nx included it (#1264). */
36
+ status(id: string): 'touched' | 'dependent' | 'implicit' | 'rootFile' | 'unexplained' | 'buildInput' | 'untouched';
37
+ /** Every affected node id of the active scan, whatever its reason. */
38
+ affected(): string[];
39
+ /** Why `id` is in the active scan's build; null when it is not affected. */
40
+ reason(id: string): AffectedReasonJson | null;
37
41
  private initial;
38
42
  private read;
39
43
  }
44
+ /**
45
+ * What the "why" panel says about one affected project (#1264): never a reason the graph cannot show.
46
+ * Pure text, so a spec reads it without a browser; GraphPage puts it in a panel.
47
+ */
48
+ declare class WpImpactWhy {
49
+ static readonly TITLES: Record<string, string>;
50
+ /**
51
+ * `8 changed · 3 dependents · 22 implicitly touched (runtime-wiring-check inputs) · 47 dependencies`
52
+ * — the same split ImpactCounts (graph-impact.ts) prints on the console.
53
+ */
54
+ counts(impact: ImpactJson): string;
55
+ title(reason: AffectedReasonJson): string;
56
+ lines(reason: AffectedReasonJson): string[];
57
+ }
58
+ /**
59
+ * The "why is this in the build?" panel (#1264): opened from an affected box's menu in Impact mode.
60
+ * Text nodes only, so no project name is parsed as HTML.
61
+ */
62
+ declare class ImpactWhyPanel {
63
+ private readonly panel;
64
+ private readonly text;
65
+ private anchor;
66
+ constructor();
67
+ open(node: SVGGElement, reason: AffectedReasonJson): void;
68
+ close(): void;
69
+ }
@@ -118,17 +118,34 @@ class WpModeState {
118
118
  }
119
119
  return true;
120
120
  }
121
- /** Which impact shade a box gets, from the ACTIVE scan. */
121
+ /** Which impact shade a box gets, from the ACTIVE scan: WHY nx included it (#1264). */
122
122
  status(id) {
123
123
  const impact = this.impact;
124
124
  if (impact?.touched.includes(id))
125
125
  return 'touched';
126
- if (impact?.affected.includes(id))
127
- return 'affected';
126
+ if (impact?.dependents.includes(id))
127
+ return 'dependent';
128
+ if (impact?.implicit.includes(id))
129
+ return 'implicit';
130
+ if (impact?.rootFile.includes(id))
131
+ return 'rootFile';
132
+ if (impact?.unexplained.includes(id))
133
+ return 'unexplained';
128
134
  if (impact?.buildInputs.includes(id))
129
135
  return 'buildInput';
130
136
  return 'untouched';
131
137
  }
138
+ /** Every affected node id of the active scan, whatever its reason. */
139
+ affected() {
140
+ const impact = this.impact;
141
+ if (impact === null)
142
+ return [];
143
+ return [...impact.touched, ...impact.dependents, ...impact.implicit, ...impact.rootFile, ...impact.unexplained];
144
+ }
145
+ /** Why `id` is in the active scan's build; null when it is not affected. */
146
+ reason(id) {
147
+ return this.impact?.reasons.find((reason) => reason.project === id) ?? null;
148
+ }
132
149
  initial() {
133
150
  const hashed = location.hash.slice(1);
134
151
  if (this.available(hashed))
@@ -151,4 +168,121 @@ class WpModeState {
151
168
  }
152
169
  }
153
170
  }
171
+ /**
172
+ * What the "why" panel says about one affected project (#1264): never a reason the graph cannot show.
173
+ * Pure text, so a spec reads it without a browser; GraphPage puts it in a panel.
174
+ */
175
+ class WpImpactWhy {
176
+ static TITLES = {
177
+ touched: 'Changed',
178
+ dependent: 'Dependent',
179
+ implicit: 'Implicitly touched',
180
+ rootFile: 'Root-file touched',
181
+ unexplained: 'Unexplained',
182
+ };
183
+ /**
184
+ * `8 changed · 3 dependents · 22 implicitly touched (runtime-wiring-check inputs) · 47 dependencies`
185
+ * — the same split ImpactCounts (graph-impact.ts) prints on the console.
186
+ */
187
+ counts(impact) {
188
+ const parts = [`${impact.touched.length} changed`, `${impact.dependents.length} dependents`];
189
+ if (impact.implicit.length > 0) {
190
+ const targets = [
191
+ ...new Set(impact.reasons
192
+ .filter((reason) => reason.kind === 'implicit' && reason.target !== '')
193
+ .map((reason) => reason.target)),
194
+ ].sort();
195
+ parts.push(`${impact.implicit.length} implicitly touched${targets.length === 0 ? '' : ` (${targets.join(', ')} inputs)`}`);
196
+ }
197
+ if (impact.rootFile.length > 0)
198
+ parts.push(`${impact.rootFile.length} root-file touched`);
199
+ if (impact.unexplained.length > 0)
200
+ parts.push(`${impact.unexplained.length} unexplained`);
201
+ parts.push(`${impact.buildInputs.length} dependencies`);
202
+ return parts.join(' · ');
203
+ }
204
+ title(reason) {
205
+ return `${WpImpactWhy.TITLES[reason.kind] ?? reason.kind}: ${reason.project}`;
206
+ }
207
+ lines(reason) {
208
+ if (reason.kind === 'touched') {
209
+ const owns = reason.files.length === 1 ? 'this changed file' : `these ${reason.files.length} changed files`;
210
+ return [`It owns ${owns}:`, ...reason.files];
211
+ }
212
+ if (reason.kind === 'dependent')
213
+ return [
214
+ 'It uses a changed or touched project through these dependency edges, so its tests and build re-run:',
215
+ reason.path.join(' -> '),
216
+ ];
217
+ if (reason.kind === 'implicit')
218
+ return [
219
+ reason.target === '' ? reason.detail : `${reason.target} input ${reason.input} matched ${reason.files.join(', ')}`,
220
+ 'nx marks every project whose target input glob matches a changed file. It uses no changed project.',
221
+ ];
222
+ if (reason.kind === 'rootFile')
223
+ return [
224
+ reason.detail,
225
+ ...(reason.path.length > 0 ? [reason.path.join(' -> ')] : []),
226
+ 'nx marked it for a workspace root file; it uses no changed project.',
227
+ ];
228
+ return [reason.detail];
229
+ }
230
+ }
231
+ /**
232
+ * The "why is this in the build?" panel (#1264): opened from an affected box's menu in Impact mode.
233
+ * Text nodes only, so no project name is parsed as HTML.
234
+ */
235
+ class ImpactWhyPanel {
236
+ panel = document.createElement('div');
237
+ text = new WpImpactWhy();
238
+ anchor = null;
239
+ constructor() {
240
+ this.panel.className = 'wp-graph-details wp-impact-why';
241
+ this.panel.hidden = true;
242
+ this.panel.setAttribute('role', 'dialog');
243
+ this.panel.setAttribute('aria-label', 'Why this project is in the build');
244
+ document.body.append(this.panel);
245
+ document.addEventListener('keydown', (ev) => {
246
+ if (ev.key !== 'Escape' || this.panel.hidden)
247
+ return;
248
+ ev.stopPropagation();
249
+ this.close();
250
+ }, true);
251
+ document.addEventListener('click', (ev) => {
252
+ const target = ev.target;
253
+ if (target instanceof Node && !this.panel.contains(target) && !this.anchor?.contains(target))
254
+ this.close();
255
+ });
256
+ }
257
+ open(node, reason) {
258
+ this.anchor = node;
259
+ const heading = document.createElement('strong');
260
+ heading.textContent = this.text.title(reason);
261
+ const list = document.createElement('ul');
262
+ for (const line of this.text.lines(reason)) {
263
+ const item = document.createElement('li');
264
+ item.textContent = line;
265
+ list.append(item);
266
+ }
267
+ const close = document.createElement('button');
268
+ close.type = 'button';
269
+ close.textContent = 'Close';
270
+ close.addEventListener('click', () => this.close());
271
+ this.panel.replaceChildren(heading, list, close);
272
+ this.panel.hidden = false;
273
+ const box = node.getBoundingClientRect();
274
+ this.panel.style.left = `${Math.max(12, Math.min(box.left, innerWidth - this.panel.offsetWidth - 12))}px`;
275
+ this.panel.style.top = `${Math.max(12, Math.min(box.bottom + 6, innerHeight - this.panel.offsetHeight - 12))}px`;
276
+ close.focus({ preventScroll: true });
277
+ }
278
+ close() {
279
+ if (this.panel.hidden)
280
+ return;
281
+ this.panel.hidden = true;
282
+ const anchor = this.anchor;
283
+ this.anchor = null;
284
+ if (anchor?.isConnected)
285
+ anchor.focus({ preventScroll: true });
286
+ }
287
+ }
154
288
  //# sourceMappingURL=graph-mode-state.client.js.map