@webpieces/nx-webpieces-rules 0.4.464 → 0.4.466

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,50 +1,186 @@
1
1
  /**
2
2
  * Package Validator
3
3
  *
4
- * Validates that package.json dependencies match the project.json build.dependsOn
5
- * This ensures the two sources of truth don't drift apart.
4
+ * Validates that package.json dependencies match the architecture graph nx derived
5
+ * from the source, and critically that each dependency is declared in the RIGHT
6
+ * SECTION of package.json:
7
+ *
8
+ * - reached from production source → `dependencies` (or `peerDependencies`)
9
+ * - reached ONLY from test/dev files → `devDependencies`
10
+ *
11
+ * WHY the section matters: production images are built with
12
+ * `pnpm --filter=<svc> deploy --prod`, which installs exactly the `dependencies`
13
+ * closure. A test-support package parked in `dependencies` therefore ships test
14
+ * machinery (auth-bypass hooks, canned credentials, fake datastores) into the
15
+ * production container. Before this validator understood `devDependencies`, moving
16
+ * such a package to its correct home FAILED the build — the tool enforced the
17
+ * insecure layout. Now `devDependencies` is the required home for test-only deps,
18
+ * and listing one in `dependencies` is itself a violation.
6
19
  */
20
+ import { DepUsage } from './dep-usage-scanner';
21
+ /**
22
+ * How hard to push back when a test-only package sits in `dependencies`
23
+ * (i.e. inside the production deploy closure).
24
+ *
25
+ * - 'error' (default): fails the build. This is the guardrail the security bug asked for.
26
+ * - 'warn': reports it without failing — the migration setting for a repo that needs a
27
+ * few releases to clean up its package.json files.
28
+ * - 'off': skip the check entirely.
29
+ *
30
+ * Missing deps, and production imports declared only in `devDependencies`, ALWAYS error:
31
+ * their fix is unambiguous and the alternative is a broken runtime.
32
+ */
33
+ export type TestOnlyDepMode = 'error' | 'warn' | 'off';
34
+ /**
35
+ * Options for {@link validatePackageJsonDependencies}. Data-only (CLAUDE.md: data
36
+ * structures are classes, never anonymous object literals).
37
+ */
38
+ export declare class PackageValidatorOptions {
39
+ testOnlyDepMode: TestOnlyDepMode;
40
+ constructor(testOnlyDepMode?: TestOnlyDepMode);
41
+ }
7
42
  /**
8
43
  * Validation result for a single project
9
44
  */
10
- export interface ProjectValidationResult {
45
+ export declare class ProjectValidationResult {
11
46
  project: string;
12
47
  valid: boolean;
13
48
  missingInPackageJson: string[];
14
49
  extraInPackageJson: string[];
50
+ /** Graph deps that are test-only but declared in `dependencies` (production closure). */
51
+ testOnlyInProdDependencies: string[];
52
+ constructor(project: string, valid: boolean, missingInPackageJson: string[], extraInPackageJson: string[], testOnlyInProdDependencies: string[]);
15
53
  }
16
54
  /**
17
55
  * Overall validation result
18
56
  *
19
- * `errors` fail the build; their only fix is ADDITIVE ("add to package.json"), so they can
20
- * never push a user toward removing a runtime-required dependency.
57
+ * `errors` fail the build. Every error's fix is either ADDITIVE ("add it to package.json")
58
+ * or a MOVE between sections ("it belongs in devDependencies") — never "delete a
59
+ * dependency", so no error can push a user toward removing a runtime-required package.
21
60
  *
22
- * `warnings` never fail the build. Workspace deps in package.json that the architecture graph
23
- * can't reach are reported here, NOT as errors: a transitively-reachable or even unreachable
24
- * entry can still be a real runtime dependency (e.g. a peerDependency or a generated client
25
- * that nx's import analysis doesn't traverse). Erroring on these is the "runtime-validity trap"
26
- * that previously forced a bad package.json edit — so we only warn.
61
+ * `warnings` never fail the build. Workspace deps in package.json that the architecture
62
+ * graph can't reach are reported here, NOT as errors: a transitively-reachable or even
63
+ * unreachable entry can still be a real runtime dependency (e.g. a peerDependency or a
64
+ * generated client that nx's import analysis doesn't traverse). Erroring on these is the
65
+ * "runtime-validity trap" that previously forced a bad package.json edit — so we only warn.
27
66
  */
28
- export interface ValidationResult {
67
+ export declare class ValidationResult {
29
68
  valid: boolean;
30
69
  errors: string[];
31
70
  warnings: string[];
32
71
  projectResults: ProjectValidationResult[];
72
+ constructor(valid: boolean, errors: string[], warnings: string[], projectResults: ProjectValidationResult[]);
33
73
  }
34
74
  /**
35
- * Validate that package.json dependencies match the dependency graph
36
- *
37
- * For each project in the graph:
38
- * - Check that all graph dependencies exist in package.json
39
- * - Maps project names to package names for accurate comparison
40
- *
41
- * @param graph - Enhanced graph with project dependencies (uses project names)
42
- * @param workspaceRoot - Absolute path to workspace root
43
- * @returns Validation result with errors if any
75
+ * The three package.json sections that matter, kept apart so the validator can say
76
+ * WHICH one a package belongs in (the old code merged them and lost that information —
77
+ * and never even read devDependencies).
78
+ */
79
+ export declare class DeclaredDeps {
80
+ dependencies: string[];
81
+ devDependencies: string[];
82
+ peerDependencies: string[];
83
+ constructor(dependencies: string[], devDependencies: string[], peerDependencies: string[]);
84
+ /** Every declared package name, deduped and sorted (all three sections). */
85
+ all(): string[];
86
+ /** Declared somewhere that survives `pnpm deploy --prod`. */
87
+ isProductionDeclared(packageName: string): boolean;
88
+ isDevDeclared(packageName: string): boolean;
89
+ isDeclared(packageName: string): boolean;
90
+ }
91
+ /**
92
+ * Graph shape produced by graph-sorter (an input contract we never construct here).
44
93
  */
45
94
  interface GraphEntry {
46
95
  level: number;
47
96
  dependsOn: string[];
48
97
  }
49
- export declare function validatePackageJsonDependencies(graph: Record<string, GraphEntry>, workspaceRoot: string): Promise<ValidationResult>;
98
+ /**
99
+ * Per-project classification of graph deps against what package.json declares.
100
+ */
101
+ declare class DepClassification {
102
+ /** Production-reached deps absent from `dependencies`/`peerDependencies`. */
103
+ missingInPackageJson: string[];
104
+ /** Production-reached deps declared ONLY in `devDependencies` (runtime would break). */
105
+ prodDepsOnlyInDev: string[];
106
+ /** Test-only deps declared in no section at all. */
107
+ missingTestOnlyDeps: string[];
108
+ /** Test-only deps sitting in `dependencies` — i.e. shipped to production. */
109
+ testOnlyInProdDependencies: string[];
110
+ /** Non-workspace (third-party) package.json entries — informational only. */
111
+ extraInPackageJson: string[];
112
+ /** Workspace entries the graph cannot reach at all — warn-only drift. */
113
+ extraWorkspaceDeps: string[];
114
+ }
115
+ declare class SingleProjectValidation {
116
+ result: ProjectValidationResult;
117
+ errors: string[];
118
+ warnings: string[];
119
+ constructor(result: ProjectValidationResult, errors: string[], warnings: string[]);
120
+ }
121
+ /**
122
+ * The per-workspace lookups a single-project validation needs, passed as one object
123
+ * so method signatures stay readable.
124
+ */
125
+ declare class ValidationContext {
126
+ graph: Record<string, GraphEntry>;
127
+ projectToPackage: Map<string, string>;
128
+ packageToProject: Map<string, string>;
129
+ options: PackageValidatorOptions;
130
+ constructor(graph: Record<string, GraphEntry>, projectToPackage: Map<string, string>, packageToProject: Map<string, string>, options: PackageValidatorOptions);
131
+ }
132
+ export declare class PackageValidator {
133
+ private readonly scanner;
134
+ /**
135
+ * Read the three dependency sections of a project's package.json.
136
+ * Returns null when there is no package.json (apps often have none) so the caller
137
+ * can skip the project entirely.
138
+ */
139
+ readDeclaredDeps(workspaceRoot: string, projectRoot: string): DeclaredDeps | null;
140
+ private namesOf;
141
+ /**
142
+ * Build map of project names to their package names
143
+ * e.g., "core-util" → "@webpieces/core-util"
144
+ */
145
+ buildProjectToPackageMap(workspaceRoot: string, projectsConfig: any): Map<string, string>;
146
+ private readPackageName;
147
+ /**
148
+ * Compute the transitive closure of a project's dependencies in the graph.
149
+ * Example: server → [core-meta, http-server]; the closure includes http-server and
150
+ * everything http-server reaches.
151
+ *
152
+ * Used to allow package.json entries for transitive deps (a legitimate pattern:
153
+ * npm install brings the whole dependency tree, so a consumer may list any reachable
154
+ * package directly).
155
+ */
156
+ computeTransitiveClosure(projectName: string, graph: Record<string, GraphEntry>): Set<string>;
157
+ /**
158
+ * Split a project's graph deps into "declared correctly", "missing", and "declared in
159
+ * the wrong section", using the import scan to decide which section each dep belongs in.
160
+ */
161
+ classifyDeps(declared: DeclaredDeps, usage: DepUsage, entry: GraphEntry, transitiveClosure: Set<string>, context: ValidationContext): DepClassification;
162
+ /**
163
+ * The heart of the fix: which SECTION does this dep belong in?
164
+ *
165
+ * A dep is test-only when the scan saw it imported by test/dev files and by NO
166
+ * production file. Anything else — including a dep we never saw imported at all (it
167
+ * may be loaded reflectively at runtime) — is treated as production, so this can
168
+ * never push a runtime-required package out of `dependencies`.
169
+ */
170
+ private classifyOneDep;
171
+ validateSingleProject(projectName: string, entry: GraphEntry, projectRoot: string, declared: DeclaredDeps, usage: DepUsage, context: ValidationContext): SingleProjectValidation;
172
+ private buildErrors;
173
+ private buildWarnings;
174
+ private testOnlyInProdMessage;
175
+ validate(graph: Record<string, GraphEntry>, workspaceRoot: string, options: PackageValidatorOptions): Promise<ValidationResult>;
176
+ }
177
+ /**
178
+ * Validate that package.json dependencies cover the dependency graph AND that each dep
179
+ * is declared in the correct section (dependencies vs devDependencies).
180
+ *
181
+ * @param graph - Enhanced graph with project dependencies (uses project names)
182
+ * @param workspaceRoot - Absolute path to workspace root
183
+ * @param options - Strictness of the "test-only dep in the production closure" check
184
+ */
185
+ export declare function validatePackageJsonDependencies(graph: Record<string, GraphEntry>, workspaceRoot: string, options?: PackageValidatorOptions): Promise<ValidationResult>;
50
186
  export {};