@webpieces/nx-webpieces-rules 0.4.465 → 0.4.467

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":"package-validator.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/package-validator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Package Validator\n *\n * Validates that package.json dependencies match the project.json build.dependsOn\n * This ensures the two sources of truth don't drift apart.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n createProjectGraphAsync,\n readProjectsConfigurationFromProjectGraph,\n} from '@nx/devkit';\nimport { toError } from '../toError';\n\n/**\n * Validation result for a single project\n */\nexport interface ProjectValidationResult {\n project: string;\n valid: boolean;\n missingInPackageJson: string[];\n extraInPackageJson: string[];\n}\n\n/**\n * Overall validation result\n *\n * `errors` fail the build; their only fix is ADDITIVE (\"add to package.json\"), so they can\n * never push a user toward removing a runtime-required dependency.\n *\n * `warnings` never fail the build. Workspace deps in package.json that the architecture graph\n * can't reach are reported here, NOT as errors: a transitively-reachable or even unreachable\n * entry can still be a real runtime dependency (e.g. a peerDependency or a generated client\n * that nx's import analysis doesn't traverse). Erroring on these is the \"runtime-validity trap\"\n * that previously forced a bad package.json edit — so we only warn.\n */\nexport interface ValidationResult {\n valid: boolean;\n errors: string[];\n warnings: string[];\n projectResults: ProjectValidationResult[];\n}\n\n/**\n * Read package.json dependencies for a project\n * Returns null if package.json doesn't exist (apps often don't have one)\n */\nfunction readPackageJsonDeps(workspaceRoot: string, projectRoot: string): string[] | null {\n const packageJsonPath = path.join(workspaceRoot, projectRoot, 'package.json');\n\n if (!fs.existsSync(packageJsonPath)) {\n return null; // No package.json - skip validation for this project\n }\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));\n const deps: string[] = [];\n\n // Collect ALL dependencies from package.json\n for (const depType of ['dependencies', 'peerDependencies']) {\n const depObj = packageJson[depType] || {};\n for (const depName of Object.keys(depObj)) {\n if (!deps.includes(depName)) {\n deps.push(depName);\n }\n }\n }\n\n return deps.sort();\n } catch (err: unknown) {\n //const error = toError(err);\n void err;\n console.warn(`Could not read package.json at ${packageJsonPath}`);\n return [];\n }\n}\n\n/**\n * Build map of project names to their package names\n * e.g., \"core-util\" → \"@webpieces/core-util\"\n */\nfunction buildProjectToPackageMap(\n workspaceRoot: string,\n // webpieces-disable no-any-unknown -- Nx devkit projectsConfig type is dynamic and not strongly typed\n projectsConfig: any\n): Map<string, string> {\n const map = new Map<string, string>();\n\n // webpieces-disable no-any-unknown -- Nx devkit projects config entries are untyped\n for (const [projectName, config] of Object.entries<any>(projectsConfig.projects)) {\n const packageJsonPath = path.join(workspaceRoot, config.root, 'package.json');\n if (fs.existsSync(packageJsonPath)) {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));\n if (packageJson.name) {\n map.set(projectName, packageJson.name);\n }\n } catch (err: unknown) {\n //const error = toError(err);\n void err;\n // Ignore parse errors\n }\n }\n }\n\n return map;\n}\n\n/**\n * Validate that package.json dependencies match the dependency graph\n *\n * For each project in the graph:\n * - Check that all graph dependencies exist in package.json\n * - Maps project names to package names for accurate comparison\n *\n * @param graph - Enhanced graph with project dependencies (uses project names)\n * @param workspaceRoot - Absolute path to workspace root\n * @returns Validation result with errors if any\n */\ninterface GraphEntry {\n level: number;\n dependsOn: string[];\n}\n\ninterface DepClassification {\n missingInPackageJson: string[];\n extraInPackageJson: string[];\n extraWorkspaceDeps: string[];\n}\n\n/**\n * Compute the transitive closure of a project's dependencies in the graph.\n * Example: server → [core-meta, http-server]; transitive closure includes\n * http-server and everything http-server reaches (http-routing,\n * core-context, core-util, http-api).\n *\n * Used to allow package.json entries for transitive deps (a legitimate pattern:\n * npm install brings the whole dependency tree, so a consumer may list any\n * reachable package directly).\n */\nfunction computeTransitiveClosure(\n projectName: string,\n graph: Record<string, GraphEntry>\n): Set<string> {\n const closure = new Set<string>();\n const stack = [projectName];\n while (stack.length > 0) {\n const current = stack.pop()!;\n const entry = graph[current];\n if (!entry) continue;\n for (const dep of entry.dependsOn) {\n if (!closure.has(dep)) {\n closure.add(dep);\n stack.push(dep);\n }\n }\n }\n return closure;\n}\n\ninterface SingleProjectValidation {\n result: ProjectValidationResult;\n errors: string[];\n warnings: string[];\n}\n\nfunction classifyDeps(\n packageJsonDeps: string[],\n entry: GraphEntry,\n transitiveClosure: Set<string>,\n projectToPackage: Map<string, string>,\n packageToProject: Map<string, string>\n): DepClassification {\n const missingInPackageJson: string[] = [];\n for (const depProjectName of entry.dependsOn) {\n const depPackageName = projectToPackage.get(depProjectName) || depProjectName;\n if (!packageJsonDeps.includes(depPackageName)) {\n missingInPackageJson.push(depProjectName);\n }\n }\n\n // Workspace extras are OK if reachable via transitive closure (matches the\n // ESLint enforce-architecture rule which also allows transitive imports).\n // Only flag extras that are NOT reachable at all — real graph drift.\n const extraInPackageJson: string[] = [];\n const extraWorkspaceDeps: string[] = [];\n for (const dep of packageJsonDeps) {\n const depProjectName = packageToProject.get(dep);\n if (depProjectName === undefined) {\n extraInPackageJson.push(dep);\n continue;\n }\n if (entry.dependsOn.includes(depProjectName)) continue;\n if (transitiveClosure.has(depProjectName)) continue;\n extraWorkspaceDeps.push(dep);\n }\n\n return { missingInPackageJson, extraInPackageJson, extraWorkspaceDeps };\n}\n\nfunction validateSingleProject(\n projectName: string,\n entry: GraphEntry,\n projectRoot: string,\n packageJsonDeps: string[],\n graph: Record<string, GraphEntry>,\n projectToPackage: Map<string, string>,\n packageToProject: Map<string, string>\n): SingleProjectValidation {\n const transitiveClosure = computeTransitiveClosure(projectName, graph);\n const classification = classifyDeps(\n packageJsonDeps,\n entry,\n transitiveClosure,\n projectToPackage,\n packageToProject\n );\n\n const errors: string[] = [];\n if (classification.missingInPackageJson.length > 0) {\n errors.push(\n `Project ${projectName} (${projectRoot}/package.json) is missing dependencies: ${classification.missingInPackageJson.join(', ')}\\n` +\n ` Fix: Add these to package.json dependencies`\n );\n }\n\n // Unreachable workspace extras are WARN-ONLY: they may be real runtime deps that nx's\n // import analysis can't see (peerDependency / generated client). Never error — that is\n // the runtime-validity trap. We surface them so genuine drift is still visible.\n const warnings: string[] = [];\n for (const extraPkg of classification.extraWorkspaceDeps) {\n const extraProject = packageToProject.get(extraPkg);\n warnings.push(\n `Project ${projectName} (${projectRoot}/package.json) has \"${extraPkg}\" but the architecture graph has no path ${projectName} → ${extraProject}.\\n` +\n ` This is allowed (it may be a runtime-only/peer dependency). If it is genuinely unused, you may remove it.`\n );\n }\n\n // extraWorkspaceDeps do NOT affect validity — only missing (additive-fix) errors do.\n const valid = classification.missingInPackageJson.length === 0;\n return {\n result: {\n project: projectName,\n valid,\n missingInPackageJson: classification.missingInPackageJson,\n extraInPackageJson: classification.extraInPackageJson,\n },\n errors,\n warnings,\n };\n}\n\nexport async function validatePackageJsonDependencies(\n graph: Record<string, GraphEntry>,\n workspaceRoot: string\n): Promise<ValidationResult> {\n const projectGraph = await createProjectGraphAsync();\n const projectsConfig = readProjectsConfigurationFromProjectGraph(projectGraph);\n\n const projectToPackage = buildProjectToPackageMap(workspaceRoot, projectsConfig);\n const packageToProject = new Map<string, string>();\n for (const [projName, pkgName] of projectToPackage.entries()) {\n packageToProject.set(pkgName, projName);\n }\n\n const errors: string[] = [];\n const warnings: string[] = [];\n const projectResults: ProjectValidationResult[] = [];\n\n for (const [projectName, entry] of Object.entries(graph)) {\n const projectConfig = projectsConfig.projects[projectName];\n if (!projectConfig) continue;\n\n const packageJsonDeps = readPackageJsonDeps(workspaceRoot, projectConfig.root);\n if (packageJsonDeps === null) continue;\n\n const validation = validateSingleProject(\n projectName,\n entry,\n projectConfig.root,\n packageJsonDeps,\n graph,\n projectToPackage,\n packageToProject\n );\n projectResults.push(validation.result);\n errors.push(...validation.errors);\n warnings.push(...validation.warnings);\n }\n\n return { valid: errors.length === 0, errors, warnings, projectResults };\n}\n"]}
1
+ {"version":3,"file":"package-validator.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/package-validator.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;;;AA6gBH,0EAMC;;AAjhBD,+CAAyB;AACzB,mDAA6B;AAC7B,uCAGoB;AACpB,2DAAgE;AAChE,wCAAqC;AAgBrC;;;GAGG;AACH,MAAa,uBAAuB;IAChC,eAAe,CAAkB;IAEjC,YAAY,kBAAmC,OAAO;QAClD,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;IAC3C,CAAC;CACJ;AAND,0DAMC;AAED;;GAEG;AACH,MAAa,uBAAuB;IAChC,OAAO,CAAS;IAChB,KAAK,CAAU;IACf,oBAAoB,CAAW;IAC/B,kBAAkB,CAAW;IAC7B,yFAAyF;IACzF,0BAA0B,CAAW;IAErC,YACI,OAAe,EACf,KAAc,EACd,oBAA8B,EAC9B,kBAA4B,EAC5B,0BAAoC;QAEpC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,oBAAoB,GAAG,oBAAoB,CAAC;QACjD,IAAI,CAAC,kBAAkB,GAAG,kBAAkB,CAAC;QAC7C,IAAI,CAAC,0BAA0B,GAAG,0BAA0B,CAAC;IACjE,CAAC;CACJ;AArBD,0DAqBC;AAED;;;;;;;;;;;;GAYG;AACH,MAAa,gBAAgB;IACzB,KAAK,CAAU;IACf,MAAM,CAAW;IACjB,QAAQ,CAAW;IACnB,cAAc,CAA4B;IAE1C,YACI,KAAc,EACd,MAAgB,EAChB,QAAkB,EAClB,cAAyC;QAEzC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;IACzC,CAAC;CACJ;AAjBD,4CAiBC;AAED;;;;GAIG;AACH,MAAa,YAAY;IACrB,YAAY,CAAW;IACvB,eAAe,CAAW;IAC1B,gBAAgB,CAAW;IAE3B,YAAY,YAAsB,EAAE,eAAyB,EAAE,gBAA0B;QACrF,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QACvC,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;IAC7C,CAAC;IAED,4EAA4E;IAC5E,GAAG;QACC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;QACjC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,YAAY;YAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,eAAe;YAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1D,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,gBAAgB;YAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC3D,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IACrC,CAAC;IAED,6DAA6D;IAC7D,oBAAoB,CAAC,WAAmB;QACpC,OAAO,CACH,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC;YACvC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,WAAW,CAAC,CAC9C,CAAC;IACN,CAAC;IAED,aAAa,CAAC,WAAmB;QAC7B,OAAO,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IACtD,CAAC;IAED,UAAU,CAAC,WAAmB;QAC1B,OAAO,IAAI,CAAC,oBAAoB,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;IACrF,CAAC;CACJ;AAnCD,oCAmCC;AAUD;;GAEG;AACH,MAAM,iBAAiB;IACnB,6EAA6E;IAC7E,oBAAoB,GAAa,EAAE,CAAC;IACpC,wFAAwF;IACxF,iBAAiB,GAAa,EAAE,CAAC;IACjC,oDAAoD;IACpD,mBAAmB,GAAa,EAAE,CAAC;IACnC,6EAA6E;IAC7E,0BAA0B,GAAa,EAAE,CAAC;IAC1C,6EAA6E;IAC7E,kBAAkB,GAAa,EAAE,CAAC;IAClC,yEAAyE;IACzE,kBAAkB,GAAa,EAAE,CAAC;CACrC;AAED,MAAM,uBAAuB;IACzB,MAAM,CAA0B;IAChC,MAAM,CAAW;IACjB,QAAQ,CAAW;IAEnB,YAAY,MAA+B,EAAE,MAAgB,EAAE,QAAkB;QAC7E,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7B,CAAC;CACJ;AAED;;;GAGG;AACH,MAAM,iBAAiB;IACnB,KAAK,CAA6B;IAClC,gBAAgB,CAAsB;IACtC,gBAAgB,CAAsB;IACtC,OAAO,CAA0B;IAEjC,YACI,KAAiC,EACjC,gBAAqC,EACrC,gBAAqC,EACrC,OAAgC;QAEhC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;QACzC,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;QACzC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;CACJ;AAED,MAAa,gBAAgB;IACR,OAAO,GAAG,IAAI,mCAAe,EAAE,CAAC;IAEjD;;;;OAIG;IACH,gBAAgB,CAAC,aAAqB,EAAE,WAAmB;QACvD,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC;QAC9E,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;YAClC,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,8DAA8D;QAC9D,IAAI,CAAC;YACD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC;YAC1E,OAAO,IAAI,YAAY,CACnB,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,cAAc,CAAC,EACzC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAC5C,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAChD,CAAC;QACN,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,IAAA,iBAAO,EAAC,GAAG,CAAC,CAAC;YAC3B,OAAO,CAAC,IAAI,CAAC,kCAAkC,eAAe,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACpF,OAAO,IAAI,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QACxC,CAAC;IACL,CAAC;IAED,wEAAwE;IAChE,OAAO,CAAC,WAAgB,EAAE,OAAe;QAC7C,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAC1C,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IACtC,CAAC;IAED;;;OAGG;IACH,wBAAwB,CACpB,aAAqB;IACrB,sGAAsG;IACtG,cAAmB;QAEnB,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;QAEtC,oFAAoF;QACpF,KAAK,MAAM,WAAW,IAAI,MAAM,CAAC,OAAO,CAAM,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrE,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;YACnC,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;YACtF,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC;gBAAE,SAAS;YAC9C,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC;YAC1D,IAAI,WAAW,KAAK,IAAI;gBAAE,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;QAChE,CAAC;QAED,OAAO,GAAG,CAAC;IACf,CAAC;IAEO,eAAe,CAAC,eAAuB;QAC3C,8DAA8D;QAC9D,IAAI,CAAC;YACD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC;YAC1E,OAAO,WAAW,CAAC,IAAI,IAAI,IAAI,CAAC;QACpC,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,IAAA,iBAAO,EAAC,GAAG,CAAC,CAAC;YAC3B,OAAO,CAAC,IAAI,CAAC,mBAAmB,eAAe,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACrE,OAAO,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;IAED;;;;;;;;OAQG;IACH,wBAAwB,CACpB,WAAmB,EACnB,KAAiC;QAEjC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;QAClC,MAAM,KAAK,GAAG,CAAC,WAAW,CAAC,CAAC;QAC5B,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,EAAG,CAAC;YAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;YAC7B,IAAI,CAAC,KAAK;gBAAE,SAAS;YACrB,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;gBAChC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBACpB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;oBACjB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACpB,CAAC;YACL,CAAC;QACL,CAAC;QACD,OAAO,OAAO,CAAC;IACnB,CAAC;IAED;;;OAGG;IACH,YAAY,CACR,QAAsB,EACtB,KAAe,EACf,KAAiB,EACjB,iBAA8B,EAC9B,OAA0B;QAE1B,MAAM,cAAc,GAAG,IAAI,iBAAiB,EAAE,CAAC;QAE/C,KAAK,MAAM,cAAc,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YAC3C,MAAM,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,cAAc,CAAC;YACtF,IAAI,CAAC,cAAc,CAAC,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC;QACzF,CAAC;QAED,kFAAkF;QAClF,oFAAoF;QACpF,oDAAoD;QACpD,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC;YAC/B,MAAM,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACzD,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;gBAC/B,cAAc,CAAC,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC5C,SAAS;YACb,CAAC;YACD,IAAI,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC;gBAAE,SAAS;YACvD,IAAI,iBAAiB,CAAC,GAAG,CAAC,cAAc,CAAC;gBAAE,SAAS;YACpD,cAAc,CAAC,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAChD,CAAC;QAED,OAAO,cAAc,CAAC;IAC1B,CAAC;IAED;;;;;;;OAOG;IACK,cAAc,CAClB,cAAsB,EACtB,cAAsB,EACtB,QAAsB,EACtB,KAAe,EACf,cAAiC;QAEjC,IAAI,KAAK,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;gBACvC,cAAc,CAAC,mBAAmB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;gBACxD,OAAO;YACX,CAAC;YACD,IAAI,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;gBACjD,cAAc,CAAC,0BAA0B,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YACnE,CAAC;YACD,OAAO;QACX,CAAC;QAED,IAAI,QAAQ,CAAC,oBAAoB,CAAC,cAAc,CAAC;YAAE,OAAO;QAC1D,IAAI,QAAQ,CAAC,aAAa,CAAC,cAAc,CAAC,EAAE,CAAC;YACzC,cAAc,CAAC,iBAAiB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YACtD,OAAO;QACX,CAAC;QACD,cAAc,CAAC,oBAAoB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC7D,CAAC;IAED,qBAAqB,CACjB,WAAmB,EACnB,KAAiB,EACjB,WAAmB,EACnB,QAAsB,EACtB,KAAe,EACf,OAA0B;QAE1B,MAAM,iBAAiB,GAAG,IAAI,CAAC,wBAAwB,CAAC,WAAW,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QACpF,MAAM,cAAc,GAAG,IAAI,CAAC,YAAY,CACpC,QAAQ,EACR,KAAK,EACL,KAAK,EACL,iBAAiB,EACjB,OAAO,CACV,CAAC;QAEF,MAAM,KAAK,GAAG,WAAW,WAAW,KAAK,WAAW,gBAAgB,CAAC;QACrE,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QACxE,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;QAEjF,MAAM,OAAO,GAAG,cAAc,CAAC,oBAAoB,CAAC,MAAM,CACtD,cAAc,CAAC,mBAAmB,CACrC,CAAC;QACF,MAAM,MAAM,GAAG,IAAI,uBAAuB,CACtC,WAAW,EACX,MAAM,CAAC,MAAM,KAAK,CAAC,EACnB,OAAO,EACP,cAAc,CAAC,kBAAkB,EACjC,cAAc,CAAC,0BAA0B,CAC5C,CAAC;QACF,OAAO,IAAI,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACjE,CAAC;IAEO,WAAW,CACf,KAAa,EACb,cAAiC,EACjC,OAAgC;QAEhC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,cAAc,CAAC,oBAAoB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjD,MAAM,CAAC,IAAI,CACP,GAAG,KAAK,6BAA6B,cAAc,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;gBACnF,oDAAoD;gBACpD,gDAAgD,CACvD,CAAC;QACN,CAAC;QACD,IAAI,cAAc,CAAC,mBAAmB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChD,MAAM,CAAC,IAAI,CACP,GAAG,KAAK,6BAA6B,cAAc,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;gBAClF,sFAAsF;gBACtF,6GAA6G,CACpH,CAAC;QACN,CAAC;QACD,IAAI,cAAc,CAAC,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9C,MAAM,CAAC,IAAI,CACP,GAAG,KAAK,yDAAyD,cAAc,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;gBAC5G,iHAAiH;gBACjH,iDAAiD,CACxD,CAAC;QACN,CAAC;QACD,MAAM,cAAc,GAAG,cAAc,CAAC,0BAA0B,CAAC;QACjE,IAAI,OAAO,CAAC,eAAe,KAAK,OAAO,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC;QACnE,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;IAEO,aAAa,CACjB,KAAa,EACb,WAAmB,EACnB,cAAiC,EACjC,OAA0B;QAE1B,MAAM,QAAQ,GAAa,EAAE,CAAC;QAE9B,MAAM,cAAc,GAAG,cAAc,CAAC,0BAA0B,CAAC;QACjE,IAAI,OAAO,CAAC,OAAO,CAAC,eAAe,KAAK,MAAM,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1E,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC;QACrE,CAAC;QAED,sFAAsF;QACtF,uFAAuF;QACvF,gFAAgF;QAChF,KAAK,MAAM,QAAQ,IAAI,cAAc,CAAC,kBAAkB,EAAE,CAAC;YACvD,MAAM,YAAY,GAAG,OAAO,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC5D,QAAQ,CAAC,IAAI,CACT,GAAG,KAAK,SAAS,QAAQ,4CAA4C,WAAW,MAAM,YAAY,KAAK;gBACnG,6GAA6G,CACpH,CAAC;QACN,CAAC;QACD,OAAO,QAAQ,CAAC;IACpB,CAAC;IAEO,qBAAqB,CAAC,KAAa,EAAE,IAAc;QACvD,OAAO,CACH,GAAG,KAAK,gDAAgD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;YAC3E,kGAAkG;YAClG,kGAAkG;YAClG,oDAAoD;YACpD,oDAAoD,CACvD,CAAC;IACN,CAAC;IAED,KAAK,CAAC,QAAQ,CACV,KAAiC,EACjC,aAAqB,EACrB,OAAgC;QAEhC,MAAM,YAAY,GAAG,MAAM,IAAA,gCAAuB,GAAE,CAAC;QACrD,MAAM,cAAc,GAAG,IAAA,kDAAyC,EAAC,YAAY,CAAC,CAAC;QAE/E,MAAM,gBAAgB,GAAG,IAAI,CAAC,wBAAwB,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;QACtF,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAkB,CAAC;QACnD,KAAK,MAAM,IAAI,IAAI,gBAAgB,CAAC,OAAO,EAAE,EAAE,CAAC;YAC5C,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3C,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;QAE1F,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,cAAc,GAA8B,EAAE,CAAC;QAErD,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5C,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;YACjC,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;YAC3B,MAAM,aAAa,GAAG,cAAc,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YAC3D,IAAI,CAAC,aAAa;gBAAE,SAAS;YAE7B,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,aAAa,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC;YAC1E,IAAI,QAAQ,KAAK,IAAI;gBAAE,SAAS;YAEhC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;YAC9E,MAAM,UAAU,GAAG,IAAI,CAAC,qBAAqB,CACzC,WAAW,EACX,KAAK,EACL,aAAa,CAAC,IAAI,EAClB,QAAQ,EACR,KAAK,EACL,OAAO,CACV,CAAC;YACF,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YACvC,MAAM,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;YAClC,QAAQ,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC1C,CAAC;QAED,OAAO,IAAI,gBAAgB,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;IACvF,CAAC;CACJ;AA5TD,4CA4TC;AAED;;;;;;;GAOG;AACH,2IAA2I;AACpI,KAAK,UAAU,+BAA+B,CACjD,KAAiC,EACjC,aAAqB,EACrB,UAAmC,IAAI,uBAAuB,EAAE;IAEhE,OAAO,IAAI,gBAAgB,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC;AAC1E,CAAC","sourcesContent":["/**\n * Package Validator\n *\n * Validates that package.json dependencies match the architecture graph nx derived\n * from the source, and — critically — that each dependency is declared in the RIGHT\n * SECTION of package.json:\n *\n * - reached from production source → `dependencies` (or `peerDependencies`)\n * - reached ONLY from test/dev files → `devDependencies`\n *\n * WHY the section matters: production images are built with\n * `pnpm --filter=<svc> deploy --prod`, which installs exactly the `dependencies`\n * closure. A test-support package parked in `dependencies` therefore ships test\n * machinery (auth-bypass hooks, canned credentials, fake datastores) into the\n * production container. Before this validator understood `devDependencies`, moving\n * such a package to its correct home FAILED the build — the tool enforced the\n * insecure layout. Now `devDependencies` is the required home for test-only deps,\n * and listing one in `dependencies` is itself a violation.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n createProjectGraphAsync,\n readProjectsConfigurationFromProjectGraph,\n} from '@nx/devkit';\nimport { DepUsage, DepUsageScanner } from './dep-usage-scanner';\nimport { toError } from '../toError';\n\n/**\n * How hard to push back when a test-only package sits in `dependencies`\n * (i.e. inside the production deploy closure).\n *\n * - 'error' (default): fails the build. This is the guardrail the security bug asked for.\n * - 'warn': reports it without failing — the migration setting for a repo that needs a\n * few releases to clean up its package.json files.\n * - 'off': skip the check entirely.\n *\n * Missing deps, and production imports declared only in `devDependencies`, ALWAYS error:\n * their fix is unambiguous and the alternative is a broken runtime.\n */\nexport type TestOnlyDepMode = 'error' | 'warn' | 'off';\n\n/**\n * Options for {@link validatePackageJsonDependencies}. Data-only (CLAUDE.md: data\n * structures are classes, never anonymous object literals).\n */\nexport class PackageValidatorOptions {\n testOnlyDepMode: TestOnlyDepMode;\n\n constructor(testOnlyDepMode: TestOnlyDepMode = 'error') {\n this.testOnlyDepMode = testOnlyDepMode;\n }\n}\n\n/**\n * Validation result for a single project\n */\nexport class ProjectValidationResult {\n project: string;\n valid: boolean;\n missingInPackageJson: string[];\n extraInPackageJson: string[];\n /** Graph deps that are test-only but declared in `dependencies` (production closure). */\n testOnlyInProdDependencies: string[];\n\n constructor(\n project: string,\n valid: boolean,\n missingInPackageJson: string[],\n extraInPackageJson: string[],\n testOnlyInProdDependencies: string[]\n ) {\n this.project = project;\n this.valid = valid;\n this.missingInPackageJson = missingInPackageJson;\n this.extraInPackageJson = extraInPackageJson;\n this.testOnlyInProdDependencies = testOnlyInProdDependencies;\n }\n}\n\n/**\n * Overall validation result\n *\n * `errors` fail the build. Every error's fix is either ADDITIVE (\"add it to package.json\")\n * or a MOVE between sections (\"it belongs in devDependencies\") — never \"delete a\n * dependency\", so no error can push a user toward removing a runtime-required package.\n *\n * `warnings` never fail the build. Workspace deps in package.json that the architecture\n * graph can't reach are reported here, NOT as errors: a transitively-reachable or even\n * unreachable entry can still be a real runtime dependency (e.g. a peerDependency or a\n * generated client that nx's import analysis doesn't traverse). Erroring on these is the\n * \"runtime-validity trap\" that previously forced a bad package.json edit — so we only warn.\n */\nexport class ValidationResult {\n valid: boolean;\n errors: string[];\n warnings: string[];\n projectResults: ProjectValidationResult[];\n\n constructor(\n valid: boolean,\n errors: string[],\n warnings: string[],\n projectResults: ProjectValidationResult[]\n ) {\n this.valid = valid;\n this.errors = errors;\n this.warnings = warnings;\n this.projectResults = projectResults;\n }\n}\n\n/**\n * The three package.json sections that matter, kept apart so the validator can say\n * WHICH one a package belongs in (the old code merged them and lost that information —\n * and never even read devDependencies).\n */\nexport class DeclaredDeps {\n dependencies: string[];\n devDependencies: string[];\n peerDependencies: string[];\n\n constructor(dependencies: string[], devDependencies: string[], peerDependencies: string[]) {\n this.dependencies = dependencies;\n this.devDependencies = devDependencies;\n this.peerDependencies = peerDependencies;\n }\n\n /** Every declared package name, deduped and sorted (all three sections). */\n all(): string[] {\n const merged = new Set<string>();\n for (const name of this.dependencies) merged.add(name);\n for (const name of this.devDependencies) merged.add(name);\n for (const name of this.peerDependencies) merged.add(name);\n return Array.from(merged).sort();\n }\n\n /** Declared somewhere that survives `pnpm deploy --prod`. */\n isProductionDeclared(packageName: string): boolean {\n return (\n this.dependencies.includes(packageName) ||\n this.peerDependencies.includes(packageName)\n );\n }\n\n isDevDeclared(packageName: string): boolean {\n return this.devDependencies.includes(packageName);\n }\n\n isDeclared(packageName: string): boolean {\n return this.isProductionDeclared(packageName) || this.isDevDeclared(packageName);\n }\n}\n\n/**\n * Graph shape produced by graph-sorter (an input contract we never construct here).\n */\ninterface GraphEntry {\n level: number;\n dependsOn: string[];\n}\n\n/**\n * Per-project classification of graph deps against what package.json declares.\n */\nclass DepClassification {\n /** Production-reached deps absent from `dependencies`/`peerDependencies`. */\n missingInPackageJson: string[] = [];\n /** Production-reached deps declared ONLY in `devDependencies` (runtime would break). */\n prodDepsOnlyInDev: string[] = [];\n /** Test-only deps declared in no section at all. */\n missingTestOnlyDeps: string[] = [];\n /** Test-only deps sitting in `dependencies` — i.e. shipped to production. */\n testOnlyInProdDependencies: string[] = [];\n /** Non-workspace (third-party) package.json entries — informational only. */\n extraInPackageJson: string[] = [];\n /** Workspace entries the graph cannot reach at all — warn-only drift. */\n extraWorkspaceDeps: string[] = [];\n}\n\nclass SingleProjectValidation {\n result: ProjectValidationResult;\n errors: string[];\n warnings: string[];\n\n constructor(result: ProjectValidationResult, errors: string[], warnings: string[]) {\n this.result = result;\n this.errors = errors;\n this.warnings = warnings;\n }\n}\n\n/**\n * The per-workspace lookups a single-project validation needs, passed as one object\n * so method signatures stay readable.\n */\nclass ValidationContext {\n graph: Record<string, GraphEntry>;\n projectToPackage: Map<string, string>;\n packageToProject: Map<string, string>;\n options: PackageValidatorOptions;\n\n constructor(\n graph: Record<string, GraphEntry>,\n projectToPackage: Map<string, string>,\n packageToProject: Map<string, string>,\n options: PackageValidatorOptions\n ) {\n this.graph = graph;\n this.projectToPackage = projectToPackage;\n this.packageToProject = packageToProject;\n this.options = options;\n }\n}\n\nexport class PackageValidator {\n private readonly scanner = new DepUsageScanner();\n\n /**\n * Read the three dependency sections of a project's package.json.\n * Returns null when there is no package.json (apps often have none) so the caller\n * can skip the project entirely.\n */\n readDeclaredDeps(workspaceRoot: string, projectRoot: string): DeclaredDeps | null {\n const packageJsonPath = path.join(workspaceRoot, projectRoot, 'package.json');\n if (!fs.existsSync(packageJsonPath)) {\n return null;\n }\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));\n return new DeclaredDeps(\n this.namesOf(packageJson, 'dependencies'),\n this.namesOf(packageJson, 'devDependencies'),\n this.namesOf(packageJson, 'peerDependencies')\n );\n } catch (err: unknown) {\n const error = toError(err);\n console.warn(`Could not read package.json at ${packageJsonPath}: ${error.message}`);\n return new DeclaredDeps([], [], []);\n }\n }\n\n // webpieces-disable no-any-unknown -- parsed JSON is inherently untyped\n private namesOf(packageJson: any, section: string): string[] {\n const depObj = packageJson[section] || {};\n return Object.keys(depObj).sort();\n }\n\n /**\n * Build map of project names to their package names\n * e.g., \"core-util\" → \"@webpieces/core-util\"\n */\n buildProjectToPackageMap(\n workspaceRoot: string,\n // webpieces-disable no-any-unknown -- Nx devkit projectsConfig type is dynamic and not strongly typed\n projectsConfig: any\n ): Map<string, string> {\n const map = new Map<string, string>();\n\n // webpieces-disable no-any-unknown -- Nx devkit projects config entries are untyped\n for (const configEntry of Object.entries<any>(projectsConfig.projects)) {\n const projectName = configEntry[0];\n const packageJsonPath = path.join(workspaceRoot, configEntry[1].root, 'package.json');\n if (!fs.existsSync(packageJsonPath)) continue;\n const packageName = this.readPackageName(packageJsonPath);\n if (packageName !== null) map.set(projectName, packageName);\n }\n\n return map;\n }\n\n private readPackageName(packageJsonPath: string): string | null {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));\n return packageJson.name || null;\n } catch (err: unknown) {\n const error = toError(err);\n console.warn(`Could not parse ${packageJsonPath}: ${error.message}`);\n return null;\n }\n }\n\n /**\n * Compute the transitive closure of a project's dependencies in the graph.\n * Example: server → [core-meta, http-server]; the closure includes http-server and\n * everything http-server reaches.\n *\n * Used to allow package.json entries for transitive deps (a legitimate pattern:\n * npm install brings the whole dependency tree, so a consumer may list any reachable\n * package directly).\n */\n computeTransitiveClosure(\n projectName: string,\n graph: Record<string, GraphEntry>\n ): Set<string> {\n const closure = new Set<string>();\n const stack = [projectName];\n while (stack.length > 0) {\n const current = stack.pop()!;\n const entry = graph[current];\n if (!entry) continue;\n for (const dep of entry.dependsOn) {\n if (!closure.has(dep)) {\n closure.add(dep);\n stack.push(dep);\n }\n }\n }\n return closure;\n }\n\n /**\n * Split a project's graph deps into \"declared correctly\", \"missing\", and \"declared in\n * the wrong section\", using the import scan to decide which section each dep belongs in.\n */\n classifyDeps(\n declared: DeclaredDeps,\n usage: DepUsage,\n entry: GraphEntry,\n transitiveClosure: Set<string>,\n context: ValidationContext\n ): DepClassification {\n const classification = new DepClassification();\n\n for (const depProjectName of entry.dependsOn) {\n const depPackageName = context.projectToPackage.get(depProjectName) || depProjectName;\n this.classifyOneDep(depProjectName, depPackageName, declared, usage, classification);\n }\n\n // Workspace extras are OK if reachable via transitive closure (matches the ESLint\n // enforce-architecture rule which also allows transitive imports). Only flag extras\n // that are NOT reachable at all — real graph drift.\n for (const dep of declared.all()) {\n const depProjectName = context.packageToProject.get(dep);\n if (depProjectName === undefined) {\n classification.extraInPackageJson.push(dep);\n continue;\n }\n if (entry.dependsOn.includes(depProjectName)) continue;\n if (transitiveClosure.has(depProjectName)) continue;\n classification.extraWorkspaceDeps.push(dep);\n }\n\n return classification;\n }\n\n /**\n * The heart of the fix: which SECTION does this dep belong in?\n *\n * A dep is test-only when the scan saw it imported by test/dev files and by NO\n * production file. Anything else — including a dep we never saw imported at all (it\n * may be loaded reflectively at runtime) — is treated as production, so this can\n * never push a runtime-required package out of `dependencies`.\n */\n private classifyOneDep(\n depProjectName: string,\n depPackageName: string,\n declared: DeclaredDeps,\n usage: DepUsage,\n classification: DepClassification\n ): void {\n if (usage.isTestOnly(depPackageName)) {\n if (!declared.isDeclared(depPackageName)) {\n classification.missingTestOnlyDeps.push(depProjectName);\n return;\n }\n if (declared.dependencies.includes(depPackageName)) {\n classification.testOnlyInProdDependencies.push(depProjectName);\n }\n return;\n }\n\n if (declared.isProductionDeclared(depPackageName)) return;\n if (declared.isDevDeclared(depPackageName)) {\n classification.prodDepsOnlyInDev.push(depProjectName);\n return;\n }\n classification.missingInPackageJson.push(depProjectName);\n }\n\n validateSingleProject(\n projectName: string,\n entry: GraphEntry,\n projectRoot: string,\n declared: DeclaredDeps,\n usage: DepUsage,\n context: ValidationContext\n ): SingleProjectValidation {\n const transitiveClosure = this.computeTransitiveClosure(projectName, context.graph);\n const classification = this.classifyDeps(\n declared,\n usage,\n entry,\n transitiveClosure,\n context\n );\n\n const where = `Project ${projectName} (${projectRoot}/package.json)`;\n const errors = this.buildErrors(where, classification, context.options);\n const warnings = this.buildWarnings(where, projectName, classification, context);\n\n const missing = classification.missingInPackageJson.concat(\n classification.missingTestOnlyDeps\n );\n const result = new ProjectValidationResult(\n projectName,\n errors.length === 0,\n missing,\n classification.extraInPackageJson,\n classification.testOnlyInProdDependencies\n );\n return new SingleProjectValidation(result, errors, warnings);\n }\n\n private buildErrors(\n where: string,\n classification: DepClassification,\n options: PackageValidatorOptions\n ): string[] {\n const errors: string[] = [];\n if (classification.missingInPackageJson.length > 0) {\n errors.push(\n `${where} is missing dependencies: ${classification.missingInPackageJson.join(', ')}\\n` +\n ` These are imported by PRODUCTION source files.\\n` +\n ` Fix: Add them to package.json \"dependencies\"`\n );\n }\n if (classification.missingTestOnlyDeps.length > 0) {\n errors.push(\n `${where} is missing dependencies: ${classification.missingTestOnlyDeps.join(', ')}\\n` +\n ` These are imported ONLY by test/dev files (*.spec.ts, __tests__/, test configs).\\n` +\n ` Fix: Add them to package.json \"devDependencies\" — NOT \"dependencies\", which would ship them to production`\n );\n }\n if (classification.prodDepsOnlyInDev.length > 0) {\n errors.push(\n `${where} declares production imports only in devDependencies: ${classification.prodDepsOnlyInDev.join(', ')}\\n` +\n ` Production source files import them, so \\`pnpm deploy --prod\\` would omit them and the runtime would break.\\n` +\n ` Fix: Move them to package.json \"dependencies\"`\n );\n }\n const testOnlyInProd = classification.testOnlyInProdDependencies;\n if (options.testOnlyDepMode === 'error' && testOnlyInProd.length > 0) {\n errors.push(this.testOnlyInProdMessage(where, testOnlyInProd));\n }\n return errors;\n }\n\n private buildWarnings(\n where: string,\n projectName: string,\n classification: DepClassification,\n context: ValidationContext\n ): string[] {\n const warnings: string[] = [];\n\n const testOnlyInProd = classification.testOnlyInProdDependencies;\n if (context.options.testOnlyDepMode === 'warn' && testOnlyInProd.length > 0) {\n warnings.push(this.testOnlyInProdMessage(where, testOnlyInProd));\n }\n\n // Unreachable workspace extras are WARN-ONLY: they may be real runtime deps that nx's\n // import analysis can't see (peerDependency / generated client). Never error — that is\n // the runtime-validity trap. We surface them so genuine drift is still visible.\n for (const extraPkg of classification.extraWorkspaceDeps) {\n const extraProject = context.packageToProject.get(extraPkg);\n warnings.push(\n `${where} has \"${extraPkg}\" but the architecture graph has no path ${projectName} → ${extraProject}.\\n` +\n ` This is allowed (it may be a runtime-only/peer dependency). If it is genuinely unused, you may remove it.`\n );\n }\n return warnings;\n }\n\n private testOnlyInProdMessage(where: string, deps: string[]): string {\n return (\n `${where} lists test-only packages in \"dependencies\": ${deps.join(', ')}\\n` +\n ` No production source file imports them — only test/dev files do — yet \\`pnpm deploy --prod\\`\\n` +\n ` installs the \"dependencies\" closure, so this ships test machinery (fakes, auth-bypass hooks,\\n` +\n ` canned credentials) into the production image.\\n` +\n ` Fix: Move them to package.json \"devDependencies\"`\n );\n }\n\n async validate(\n graph: Record<string, GraphEntry>,\n workspaceRoot: string,\n options: PackageValidatorOptions\n ): Promise<ValidationResult> {\n const projectGraph = await createProjectGraphAsync();\n const projectsConfig = readProjectsConfigurationFromProjectGraph(projectGraph);\n\n const projectToPackage = this.buildProjectToPackageMap(workspaceRoot, projectsConfig);\n const packageToProject = new Map<string, string>();\n for (const pair of projectToPackage.entries()) {\n packageToProject.set(pair[1], pair[0]);\n }\n const context = new ValidationContext(graph, projectToPackage, packageToProject, options);\n\n const errors: string[] = [];\n const warnings: string[] = [];\n const projectResults: ProjectValidationResult[] = [];\n\n for (const graphPair of Object.entries(graph)) {\n const projectName = graphPair[0];\n const entry = graphPair[1];\n const projectConfig = projectsConfig.projects[projectName];\n if (!projectConfig) continue;\n\n const declared = this.readDeclaredDeps(workspaceRoot, projectConfig.root);\n if (declared === null) continue;\n\n const usage = this.scanner.scan(path.join(workspaceRoot, projectConfig.root));\n const validation = this.validateSingleProject(\n projectName,\n entry,\n projectConfig.root,\n declared,\n usage,\n context\n );\n projectResults.push(validation.result);\n errors.push(...validation.errors);\n warnings.push(...validation.warnings);\n }\n\n return new ValidationResult(errors.length === 0, errors, warnings, projectResults);\n }\n}\n\n/**\n * Validate that package.json dependencies cover the dependency graph AND that each dep\n * is declared in the correct section (dependencies vs devDependencies).\n *\n * @param graph - Enhanced graph with project dependencies (uses project names)\n * @param workspaceRoot - Absolute path to workspace root\n * @param options - Strictness of the \"test-only dep in the production closure\" check\n */\n// webpieces-disable no-function-outside-class -- stable module entry point imported by the executor; it only delegates to PackageValidator\nexport async function validatePackageJsonDependencies(\n graph: Record<string, GraphEntry>,\n workspaceRoot: string,\n options: PackageValidatorOptions = new PackageValidatorOptions()\n): Promise<ValidationResult> {\n return new PackageValidator().validate(graph, workspaceRoot, options);\n}\n"]}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Config gate for the Nx infrastructure validators.
3
+ *
4
+ * Every other rule in the system (eslint rules, code-rules, ai-hook rules, validate-ts-in-src) can be
5
+ * turned off or time-boxed from webpieces.config.json. The five infrastructure executors
6
+ * (validate-architecture-unchanged, validate-no-architecture-cycles, validate-packagejson,
7
+ * validate-versions-locked, validate-eslint-sync) hardcoded their behavior instead, which made them
8
+ * the only checks a consuming repo could not adopt gradually. This gate gives them the same
9
+ * semantics, from the same source of truth (`loadAndValidate` → webpieces.config.json).
10
+ *
11
+ * Semantics:
12
+ * - rule entry ABSENT (or no webpieces.config.json at all) → RUN. Fail-safe: an older config, or a
13
+ * repo that has not adopted the keys yet, behaves exactly as it did before this gate existed.
14
+ * - `"mode": "OFF"` → skip with a reason.
15
+ * - `ignoreModifiedUntilEpoch` / `ignoreRuleWhileOnBranch` → honored ONLY when the caller passes
16
+ * `honorEpoch: true`, i.e. only for the two rules that compare against a blessed baseline and can
17
+ * therefore meaningfully grandfather today's state. The other three are all-or-nothing (see the
18
+ * comment block above ValidateArchitectureUnchangedConfig in rules-config/src/rule-configs.ts).
19
+ */
20
+ export declare class RuleGate {
21
+ /**
22
+ * @param workspaceRoot the Nx `context.root` — where webpieces.config.json is looked up from.
23
+ * @param ruleName the webpieces.config.json key, identical to the Nx target name.
24
+ * @param honorEpoch true only for the baseline-comparing rules (see class doc).
25
+ * @returns a human-readable reason when the executor must SKIP, or null when it must RUN.
26
+ */
27
+ skipReason(workspaceRoot: string, ruleName: string, honorEpoch: boolean): string | null;
28
+ /**
29
+ * Convenience wrapper: prints the standard skip line and reports whether the caller should stop.
30
+ * Keeps the four-line preamble identical across all five executors.
31
+ */
32
+ isDisabled(workspaceRoot: string, ruleName: string, honorEpoch: boolean): boolean;
33
+ }
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ /**
3
+ * Config gate for the Nx infrastructure validators.
4
+ *
5
+ * Every other rule in the system (eslint rules, code-rules, ai-hook rules, validate-ts-in-src) can be
6
+ * turned off or time-boxed from webpieces.config.json. The five infrastructure executors
7
+ * (validate-architecture-unchanged, validate-no-architecture-cycles, validate-packagejson,
8
+ * validate-versions-locked, validate-eslint-sync) hardcoded their behavior instead, which made them
9
+ * the only checks a consuming repo could not adopt gradually. This gate gives them the same
10
+ * semantics, from the same source of truth (`loadAndValidate` → webpieces.config.json).
11
+ *
12
+ * Semantics:
13
+ * - rule entry ABSENT (or no webpieces.config.json at all) → RUN. Fail-safe: an older config, or a
14
+ * repo that has not adopted the keys yet, behaves exactly as it did before this gate existed.
15
+ * - `"mode": "OFF"` → skip with a reason.
16
+ * - `ignoreModifiedUntilEpoch` / `ignoreRuleWhileOnBranch` → honored ONLY when the caller passes
17
+ * `honorEpoch: true`, i.e. only for the two rules that compare against a blessed baseline and can
18
+ * therefore meaningfully grandfather today's state. The other three are all-or-nothing (see the
19
+ * comment block above ValidateArchitectureUnchangedConfig in rules-config/src/rule-configs.ts).
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.RuleGate = void 0;
23
+ const rules_config_1 = require("@webpieces/rules-config");
24
+ class RuleGate {
25
+ /**
26
+ * @param workspaceRoot the Nx `context.root` — where webpieces.config.json is looked up from.
27
+ * @param ruleName the webpieces.config.json key, identical to the Nx target name.
28
+ * @param honorEpoch true only for the baseline-comparing rules (see class doc).
29
+ * @returns a human-readable reason when the executor must SKIP, or null when it must RUN.
30
+ */
31
+ skipReason(workspaceRoot, ruleName, honorEpoch) {
32
+ const rule = (0, rules_config_1.loadAndValidate)(workspaceRoot).resolved.rules.get(ruleName);
33
+ // Absent ⇒ run. Never invent a default that silently disables a check.
34
+ if (!rule)
35
+ return null;
36
+ if (rule.isOff)
37
+ return 'mode: OFF';
38
+ if (!honorEpoch)
39
+ return null;
40
+ const epoch = rule.options['ignoreModifiedUntilEpoch'];
41
+ const branch = rule.options['ignoreRuleWhileOnBranch'];
42
+ const skip = (0, rules_config_1.shouldSkipRule)(epoch, branch);
43
+ return skip.skip ? (skip.reason ?? 'temporarily disabled') : null;
44
+ }
45
+ /**
46
+ * Convenience wrapper: prints the standard skip line and reports whether the caller should stop.
47
+ * Keeps the four-line preamble identical across all five executors.
48
+ */
49
+ isDisabled(workspaceRoot, ruleName, honorEpoch) {
50
+ const reason = this.skipReason(workspaceRoot, ruleName, honorEpoch);
51
+ if (reason === null)
52
+ return false;
53
+ console.log(`\n⏭️ Skipping ${ruleName} (${reason}) — configured in webpieces.config.json\n`);
54
+ return true;
55
+ }
56
+ }
57
+ exports.RuleGate = RuleGate;
58
+ //# sourceMappingURL=rule-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-gate.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/rule-gate.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;;;AAEH,0DAA0E;AAE1E,MAAa,QAAQ;IACjB;;;;;OAKG;IACH,UAAU,CAAC,aAAqB,EAAE,QAAgB,EAAE,UAAmB;QACnE,MAAM,IAAI,GAAG,IAAA,8BAAe,EAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzE,uEAAuE;QACvE,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QACvB,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO,WAAW,CAAC;QACnC,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QAE7B,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,0BAA0B,CAAuB,CAAC;QAC7E,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,yBAAyB,CAAuB,CAAC;QAC7E,MAAM,IAAI,GAAG,IAAA,6BAAc,EAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC3C,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,sBAAsB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACtE,CAAC;IAED;;;OAGG;IACH,UAAU,CAAC,aAAqB,EAAE,QAAgB,EAAE,UAAmB;QACnE,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;QACpE,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,kBAAkB,QAAQ,KAAK,MAAM,2CAA2C,CAAC,CAAC;QAC9F,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ;AA9BD,4BA8BC","sourcesContent":["/**\n * Config gate for the Nx infrastructure validators.\n *\n * Every other rule in the system (eslint rules, code-rules, ai-hook rules, validate-ts-in-src) can be\n * turned off or time-boxed from webpieces.config.json. The five infrastructure executors\n * (validate-architecture-unchanged, validate-no-architecture-cycles, validate-packagejson,\n * validate-versions-locked, validate-eslint-sync) hardcoded their behavior instead, which made them\n * the only checks a consuming repo could not adopt gradually. This gate gives them the same\n * semantics, from the same source of truth (`loadAndValidate` → webpieces.config.json).\n *\n * Semantics:\n * - rule entry ABSENT (or no webpieces.config.json at all) → RUN. Fail-safe: an older config, or a\n * repo that has not adopted the keys yet, behaves exactly as it did before this gate existed.\n * - `\"mode\": \"OFF\"` → skip with a reason.\n * - `ignoreModifiedUntilEpoch` / `ignoreRuleWhileOnBranch` → honored ONLY when the caller passes\n * `honorEpoch: true`, i.e. only for the two rules that compare against a blessed baseline and can\n * therefore meaningfully grandfather today's state. The other three are all-or-nothing (see the\n * comment block above ValidateArchitectureUnchangedConfig in rules-config/src/rule-configs.ts).\n */\n\nimport { loadAndValidate, shouldSkipRule } from '@webpieces/rules-config';\n\nexport class RuleGate {\n /**\n * @param workspaceRoot the Nx `context.root` — where webpieces.config.json is looked up from.\n * @param ruleName the webpieces.config.json key, identical to the Nx target name.\n * @param honorEpoch true only for the baseline-comparing rules (see class doc).\n * @returns a human-readable reason when the executor must SKIP, or null when it must RUN.\n */\n skipReason(workspaceRoot: string, ruleName: string, honorEpoch: boolean): string | null {\n const rule = loadAndValidate(workspaceRoot).resolved.rules.get(ruleName);\n // Absent ⇒ run. Never invent a default that silently disables a check.\n if (!rule) return null;\n if (rule.isOff) return 'mode: OFF';\n if (!honorEpoch) return null;\n\n const epoch = rule.options['ignoreModifiedUntilEpoch'] as number | undefined;\n const branch = rule.options['ignoreRuleWhileOnBranch'] as string | undefined;\n const skip = shouldSkipRule(epoch, branch);\n return skip.skip ? (skip.reason ?? 'temporarily disabled') : null;\n }\n\n /**\n * Convenience wrapper: prints the standard skip line and reports whether the caller should stop.\n * Keeps the four-line preamble identical across all five executors.\n */\n isDisabled(workspaceRoot: string, ruleName: string, honorEpoch: boolean): boolean {\n const reason = this.skipReason(workspaceRoot, ruleName, honorEpoch);\n if (reason === null) return false;\n console.log(`\\n⏭️ Skipping ${ruleName} (${reason}) — configured in webpieces.config.json\\n`);\n return true;\n }\n}\n"]}