@webpieces/dev-config 0.2.95 → 0.2.97
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.
- package/config/eslint/base.mjs +1 -1
- package/executors.json +6 -91
- package/package.json +6 -19
- package/{executors → src/executors}/help/executor.d.ts +4 -2
- package/src/executors/help/executor.js.map +1 -0
- package/src/executors/validate-eslint-sync/executor.js.map +1 -0
- package/{executors → src/executors}/validate-versions-locked/executor.js +2 -1
- package/src/executors/validate-versions-locked/executor.js.map +1 -0
- package/src/index.d.ts +1 -1
- package/src/index.js +1 -1
- package/src/index.js.map +1 -1
- package/src/plugin.d.ts +86 -0
- package/{plugin.js → src/plugin.js} +31 -15
- package/src/plugin.js.map +1 -0
- package/src/toError.d.ts +5 -0
- package/src/toError.js +37 -0
- package/src/toError.js.map +1 -0
- package/templates/eslint.webpieces.config.mjs +1 -1
- package/architecture/executors/diff-utils.d.ts +0 -24
- package/architecture/executors/diff-utils.js +0 -119
- package/architecture/executors/diff-utils.js.map +0 -1
- package/architecture/executors/diff-utils.ts +0 -127
- package/architecture/executors/generate/executor.d.ts +0 -16
- package/architecture/executors/generate/executor.js +0 -44
- package/architecture/executors/generate/executor.js.map +0 -1
- package/architecture/executors/generate/executor.ts +0 -59
- package/architecture/executors/generate/schema.json +0 -14
- package/architecture/executors/validate-architecture-unchanged/executor.d.ts +0 -17
- package/architecture/executors/validate-architecture-unchanged/executor.js +0 -229
- package/architecture/executors/validate-architecture-unchanged/executor.js.map +0 -1
- package/architecture/executors/validate-architecture-unchanged/executor.ts +0 -251
- package/architecture/executors/validate-architecture-unchanged/schema.json +0 -14
- package/architecture/executors/validate-code/executor.d.ts +0 -78
- package/architecture/executors/validate-code/executor.js +0 -243
- package/architecture/executors/validate-code/executor.js.map +0 -1
- package/architecture/executors/validate-code/executor.ts +0 -406
- package/architecture/executors/validate-code/schema.json +0 -227
- package/architecture/executors/validate-dtos/executor.d.ts +0 -42
- package/architecture/executors/validate-dtos/executor.js +0 -561
- package/architecture/executors/validate-dtos/executor.js.map +0 -1
- package/architecture/executors/validate-dtos/executor.ts +0 -689
- package/architecture/executors/validate-dtos/schema.json +0 -33
- package/architecture/executors/validate-modified-files/executor.d.ts +0 -25
- package/architecture/executors/validate-modified-files/executor.js +0 -501
- package/architecture/executors/validate-modified-files/executor.js.map +0 -1
- package/architecture/executors/validate-modified-files/executor.ts +0 -571
- package/architecture/executors/validate-modified-files/schema.json +0 -25
- package/architecture/executors/validate-modified-methods/executor.d.ts +0 -31
- package/architecture/executors/validate-modified-methods/executor.js +0 -694
- package/architecture/executors/validate-modified-methods/executor.js.map +0 -1
- package/architecture/executors/validate-modified-methods/executor.ts +0 -797
- package/architecture/executors/validate-modified-methods/schema.json +0 -25
- package/architecture/executors/validate-new-methods/executor.d.ts +0 -28
- package/architecture/executors/validate-new-methods/executor.js +0 -513
- package/architecture/executors/validate-new-methods/executor.js.map +0 -1
- package/architecture/executors/validate-new-methods/executor.ts +0 -584
- package/architecture/executors/validate-new-methods/schema.json +0 -25
- package/architecture/executors/validate-no-any-unknown/executor.d.ts +0 -42
- package/architecture/executors/validate-no-any-unknown/executor.js +0 -462
- package/architecture/executors/validate-no-any-unknown/executor.js.map +0 -1
- package/architecture/executors/validate-no-any-unknown/executor.ts +0 -540
- package/architecture/executors/validate-no-any-unknown/schema.json +0 -24
- package/architecture/executors/validate-no-architecture-cycles/executor.d.ts +0 -16
- package/architecture/executors/validate-no-architecture-cycles/executor.js +0 -48
- package/architecture/executors/validate-no-architecture-cycles/executor.js.map +0 -1
- package/architecture/executors/validate-no-architecture-cycles/executor.ts +0 -60
- package/architecture/executors/validate-no-architecture-cycles/schema.json +0 -8
- package/architecture/executors/validate-no-destructure/executor.d.ts +0 -52
- package/architecture/executors/validate-no-destructure/executor.js +0 -491
- package/architecture/executors/validate-no-destructure/executor.js.map +0 -1
- package/architecture/executors/validate-no-destructure/executor.ts +0 -578
- package/architecture/executors/validate-no-destructure/schema.json +0 -24
- package/architecture/executors/validate-no-direct-api-resolver/executor.d.ts +0 -47
- package/architecture/executors/validate-no-direct-api-resolver/executor.js +0 -566
- package/architecture/executors/validate-no-direct-api-resolver/executor.js.map +0 -1
- package/architecture/executors/validate-no-direct-api-resolver/executor.ts +0 -666
- package/architecture/executors/validate-no-direct-api-resolver/schema.json +0 -29
- package/architecture/executors/validate-no-inline-types/executor.d.ts +0 -91
- package/architecture/executors/validate-no-inline-types/executor.js +0 -669
- package/architecture/executors/validate-no-inline-types/executor.js.map +0 -1
- package/architecture/executors/validate-no-inline-types/executor.ts +0 -775
- package/architecture/executors/validate-no-inline-types/schema.json +0 -24
- package/architecture/executors/validate-no-skiplevel-deps/executor.d.ts +0 -19
- package/architecture/executors/validate-no-skiplevel-deps/executor.js +0 -227
- package/architecture/executors/validate-no-skiplevel-deps/executor.js.map +0 -1
- package/architecture/executors/validate-no-skiplevel-deps/executor.ts +0 -267
- package/architecture/executors/validate-no-skiplevel-deps/schema.json +0 -8
- package/architecture/executors/validate-packagejson/executor.d.ts +0 -16
- package/architecture/executors/validate-packagejson/executor.js +0 -57
- package/architecture/executors/validate-packagejson/executor.js.map +0 -1
- package/architecture/executors/validate-packagejson/executor.ts +0 -74
- package/architecture/executors/validate-packagejson/schema.json +0 -8
- package/architecture/executors/validate-prisma-converters/executor.d.ts +0 -60
- package/architecture/executors/validate-prisma-converters/executor.js +0 -634
- package/architecture/executors/validate-prisma-converters/executor.js.map +0 -1
- package/architecture/executors/validate-prisma-converters/executor.ts +0 -822
- package/architecture/executors/validate-prisma-converters/schema.json +0 -38
- package/architecture/executors/validate-return-types/executor.d.ts +0 -29
- package/architecture/executors/validate-return-types/executor.js +0 -439
- package/architecture/executors/validate-return-types/executor.js.map +0 -1
- package/architecture/executors/validate-return-types/executor.ts +0 -524
- package/architecture/executors/validate-return-types/schema.json +0 -24
- package/architecture/executors/visualize/executor.d.ts +0 -17
- package/architecture/executors/visualize/executor.js +0 -49
- package/architecture/executors/visualize/executor.js.map +0 -1
- package/architecture/executors/visualize/executor.ts +0 -63
- package/architecture/executors/visualize/schema.json +0 -14
- package/architecture/index.d.ts +0 -19
- package/architecture/index.js +0 -23
- package/architecture/index.js.map +0 -1
- package/architecture/index.ts +0 -20
- package/architecture/lib/graph-comparator.d.ts +0 -39
- package/architecture/lib/graph-comparator.js +0 -100
- package/architecture/lib/graph-comparator.js.map +0 -1
- package/architecture/lib/graph-comparator.ts +0 -141
- package/architecture/lib/graph-generator.d.ts +0 -19
- package/architecture/lib/graph-generator.js +0 -84
- package/architecture/lib/graph-generator.js.map +0 -1
- package/architecture/lib/graph-generator.ts +0 -97
- package/architecture/lib/graph-loader.d.ts +0 -31
- package/architecture/lib/graph-loader.js +0 -98
- package/architecture/lib/graph-loader.js.map +0 -1
- package/architecture/lib/graph-loader.ts +0 -116
- package/architecture/lib/graph-sorter.d.ts +0 -37
- package/architecture/lib/graph-sorter.js +0 -110
- package/architecture/lib/graph-sorter.js.map +0 -1
- package/architecture/lib/graph-sorter.ts +0 -137
- package/architecture/lib/graph-visualizer.d.ts +0 -29
- package/architecture/lib/graph-visualizer.js +0 -217
- package/architecture/lib/graph-visualizer.js.map +0 -1
- package/architecture/lib/graph-visualizer.ts +0 -231
- package/architecture/lib/package-validator.d.ts +0 -38
- package/architecture/lib/package-validator.js +0 -126
- package/architecture/lib/package-validator.js.map +0 -1
- package/architecture/lib/package-validator.ts +0 -170
- package/eslint-plugin/__tests__/catch-error-pattern.test.ts +0 -374
- package/eslint-plugin/__tests__/max-file-lines.test.ts +0 -207
- package/eslint-plugin/__tests__/max-method-lines.test.ts +0 -258
- package/eslint-plugin/__tests__/no-unmanaged-exceptions.test.ts +0 -359
- package/eslint-plugin/index.d.ts +0 -23
- package/eslint-plugin/index.js +0 -30
- package/eslint-plugin/index.js.map +0 -1
- package/eslint-plugin/index.ts +0 -29
- package/eslint-plugin/rules/catch-error-pattern.d.ts +0 -11
- package/eslint-plugin/rules/catch-error-pattern.js +0 -143
- package/eslint-plugin/rules/catch-error-pattern.js.map +0 -1
- package/eslint-plugin/rules/catch-error-pattern.ts +0 -246
- package/eslint-plugin/rules/enforce-architecture.d.ts +0 -15
- package/eslint-plugin/rules/enforce-architecture.js +0 -476
- package/eslint-plugin/rules/enforce-architecture.js.map +0 -1
- package/eslint-plugin/rules/enforce-architecture.ts +0 -543
- package/eslint-plugin/rules/max-file-lines.d.ts +0 -12
- package/eslint-plugin/rules/max-file-lines.js +0 -257
- package/eslint-plugin/rules/max-file-lines.js.map +0 -1
- package/eslint-plugin/rules/max-file-lines.ts +0 -272
- package/eslint-plugin/rules/max-method-lines.d.ts +0 -12
- package/eslint-plugin/rules/max-method-lines.js +0 -240
- package/eslint-plugin/rules/max-method-lines.js.map +0 -1
- package/eslint-plugin/rules/max-method-lines.ts +0 -287
- package/eslint-plugin/rules/no-unmanaged-exceptions.d.ts +0 -22
- package/eslint-plugin/rules/no-unmanaged-exceptions.js +0 -160
- package/eslint-plugin/rules/no-unmanaged-exceptions.js.map +0 -1
- package/eslint-plugin/rules/no-unmanaged-exceptions.ts +0 -179
- package/executors/help/executor.js.map +0 -1
- package/executors/help/executor.ts +0 -61
- package/executors/validate-eslint-sync/executor.js.map +0 -1
- package/executors/validate-eslint-sync/executor.ts +0 -87
- package/executors/validate-versions-locked/executor.js.map +0 -1
- package/executors/validate-versions-locked/executor.ts +0 -368
- package/plugin/README.md +0 -243
- package/plugin/index.d.ts +0 -4
- package/plugin/index.js +0 -8
- package/plugin/index.js.map +0 -1
- package/plugin/index.ts +0 -4
- /package/{executors → src/executors}/help/executor.js +0 -0
- /package/{executors → src/executors}/help/schema.json +0 -0
- /package/{executors → src/executors}/validate-eslint-sync/executor.d.ts +0 -0
- /package/{executors → src/executors}/validate-eslint-sync/executor.js +0 -0
- /package/{executors → src/executors}/validate-eslint-sync/schema.json +0 -0
- /package/{executors → src/executors}/validate-versions-locked/executor.d.ts +0 -0
- /package/{executors → src/executors}/validate-versions-locked/schema.json +0 -0
|
@@ -1,368 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Validate Versions Locked Executor
|
|
3
|
-
*
|
|
4
|
-
* Validates that package.json versions are:
|
|
5
|
-
* 1. LOCKED (exact versions, no semver ranges like ^, ~, *)
|
|
6
|
-
* 2. CONSISTENT across all package.json files (no version conflicts)
|
|
7
|
-
*
|
|
8
|
-
* Why locked versions matter:
|
|
9
|
-
* - Micro bugs ARE introduced via patch versions (1.4.5 → 1.4.6)
|
|
10
|
-
* - git bisect fails when software changes OUTSIDE of git
|
|
11
|
-
* - Library upgrades must be explicit via PR/commit, not implicit drift
|
|
12
|
-
*
|
|
13
|
-
* Usage:
|
|
14
|
-
* nx run architecture:validate-versions-locked
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import type { ExecutorContext } from '@nx/devkit';
|
|
18
|
-
import * as fs from 'fs';
|
|
19
|
-
import * as path from 'path';
|
|
20
|
-
import { toError } from '../../toError';
|
|
21
|
-
|
|
22
|
-
export interface ValidateVersionsLockedOptions {
|
|
23
|
-
// No options needed
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface ExecutorResult {
|
|
27
|
-
success: boolean;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// webpieces-disable max-lines-new-methods -- Existing method from renamed validate-versions file
|
|
31
|
-
// Find all package.json files except node_modules, dist, .nx, .angular
|
|
32
|
-
function findPackageJsonFiles(dir: string, basePath = ''): string[] {
|
|
33
|
-
const files: string[] = [];
|
|
34
|
-
const items = fs.readdirSync(dir);
|
|
35
|
-
|
|
36
|
-
for (const item of items) {
|
|
37
|
-
const fullPath = path.join(dir, item);
|
|
38
|
-
const relativePath = path.join(basePath, item);
|
|
39
|
-
|
|
40
|
-
// Skip these directories
|
|
41
|
-
if (
|
|
42
|
-
['node_modules', 'dist', '.nx', '.angular', 'tmp', '.git'].includes(
|
|
43
|
-
item,
|
|
44
|
-
)
|
|
45
|
-
) {
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Skip all hidden directories (starting with .)
|
|
50
|
-
if (item.startsWith('.')) {
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const stat = fs.statSync(fullPath);
|
|
55
|
-
if (stat.isDirectory()) {
|
|
56
|
-
files.push(...findPackageJsonFiles(fullPath, relativePath));
|
|
57
|
-
} else if (item === 'package.json') {
|
|
58
|
-
files.push(fullPath);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return files;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Check if a version string uses semver ranges
|
|
66
|
-
function hasSemverRange(version: string): boolean {
|
|
67
|
-
// Allow workspace protocol
|
|
68
|
-
if (version.startsWith('workspace:')) {
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Allow file: protocol (for local packages)
|
|
73
|
-
if (version.startsWith('file:')) {
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Check for common semver range patterns
|
|
78
|
-
const semverPatterns = [
|
|
79
|
-
/^\^/, // ^1.2.3
|
|
80
|
-
/^~/, // ~1.2.3
|
|
81
|
-
/^\+/, // +1.2.3
|
|
82
|
-
/^\*/, // *
|
|
83
|
-
/^>/, // >1.2.3
|
|
84
|
-
/^</, // <1.2.3
|
|
85
|
-
/^>=/, // >=1.2.3
|
|
86
|
-
/^<=/, // <=1.2.3
|
|
87
|
-
/\|\|/, // 1.2.3 || 2.x
|
|
88
|
-
/ - /, // 1.2.3 - 2.3.4
|
|
89
|
-
/^\d+\.x/, // 1.x, 1.2.x
|
|
90
|
-
/^latest$/, // latest
|
|
91
|
-
/^next$/, // next
|
|
92
|
-
];
|
|
93
|
-
|
|
94
|
-
return semverPatterns.some((pattern) => pattern.test(version));
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// webpieces-disable max-lines-new-methods -- Existing method from renamed validate-versions file
|
|
98
|
-
// Validate a single package.json file for semver ranges
|
|
99
|
-
function validatePackageJson(filePath: string): string[] {
|
|
100
|
-
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
101
|
-
try {
|
|
102
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
103
|
-
const pkg = JSON.parse(content);
|
|
104
|
-
const errors: string[] = [];
|
|
105
|
-
|
|
106
|
-
// Check dependencies
|
|
107
|
-
if (pkg.dependencies) {
|
|
108
|
-
for (const [name, version] of Object.entries(pkg.dependencies)) {
|
|
109
|
-
// Skip internal workspace packages
|
|
110
|
-
if (name.startsWith('@webpieces/')) {
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (hasSemverRange(version as string)) {
|
|
115
|
-
errors.push(
|
|
116
|
-
`dependencies.${name}: "${version}" uses semver range (must be locked to exact version)`,
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Check devDependencies
|
|
123
|
-
if (pkg.devDependencies) {
|
|
124
|
-
for (const [name, version] of Object.entries(pkg.devDependencies)) {
|
|
125
|
-
// Skip internal workspace packages
|
|
126
|
-
if (name.startsWith('@webpieces/')) {
|
|
127
|
-
continue;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (hasSemverRange(version as string)) {
|
|
131
|
-
errors.push(
|
|
132
|
-
`devDependencies.${name}: "${version}" uses semver range (must be locked to exact version)`,
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Check peerDependencies (these can have ranges for compatibility)
|
|
139
|
-
// We don't validate peerDependencies for semver ranges since they're meant to be flexible
|
|
140
|
-
|
|
141
|
-
return errors;
|
|
142
|
-
} catch (err: unknown) {
|
|
143
|
-
const error = toError(err);
|
|
144
|
-
return [`Failed to parse ${filePath}: ${error.message}`];
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Track all dependency versions across the monorepo
|
|
149
|
-
interface DependencyUsage {
|
|
150
|
-
version: string;
|
|
151
|
-
file: string;
|
|
152
|
-
type: 'dependencies' | 'devDependencies';
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// webpieces-disable max-lines-new-methods -- Collecting dependencies from all package.json files
|
|
156
|
-
// Collect all dependency versions from all package.json files
|
|
157
|
-
function collectAllDependencies(workspaceRoot: string): Map<string, DependencyUsage[]> {
|
|
158
|
-
const dependencyMap = new Map<string, DependencyUsage[]>();
|
|
159
|
-
const packageFiles = findPackageJsonFiles(workspaceRoot);
|
|
160
|
-
|
|
161
|
-
for (const filePath of packageFiles) {
|
|
162
|
-
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
163
|
-
try {
|
|
164
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
165
|
-
const pkg = JSON.parse(content);
|
|
166
|
-
const relativePath = path.relative(workspaceRoot, filePath);
|
|
167
|
-
|
|
168
|
-
// Collect dependencies
|
|
169
|
-
if (pkg.dependencies) {
|
|
170
|
-
for (const [name, version] of Object.entries(pkg.dependencies)) {
|
|
171
|
-
// Skip internal workspace packages
|
|
172
|
-
if (name.startsWith('@webpieces/')) continue;
|
|
173
|
-
|
|
174
|
-
const usage: DependencyUsage = {
|
|
175
|
-
version: version as string,
|
|
176
|
-
file: relativePath,
|
|
177
|
-
type: 'dependencies'
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
if (!dependencyMap.has(name)) {
|
|
181
|
-
dependencyMap.set(name, []);
|
|
182
|
-
}
|
|
183
|
-
dependencyMap.get(name)!.push(usage);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Collect devDependencies
|
|
188
|
-
if (pkg.devDependencies) {
|
|
189
|
-
for (const [name, version] of Object.entries(pkg.devDependencies)) {
|
|
190
|
-
// Skip internal workspace packages
|
|
191
|
-
if (name.startsWith('@webpieces/')) continue;
|
|
192
|
-
|
|
193
|
-
const usage: DependencyUsage = {
|
|
194
|
-
version: version as string,
|
|
195
|
-
file: relativePath,
|
|
196
|
-
type: 'devDependencies'
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
if (!dependencyMap.has(name)) {
|
|
200
|
-
dependencyMap.set(name, []);
|
|
201
|
-
}
|
|
202
|
-
dependencyMap.get(name)!.push(usage);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
} catch (err: unknown) {
|
|
206
|
-
// const error = toError(err);
|
|
207
|
-
// Intentionally skip files that can't be parsed - this is expected for some package.json files
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
return dependencyMap;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// webpieces-disable max-lines-new-methods -- Simple iteration logic, splitting would reduce clarity
|
|
215
|
-
// Check for version conflicts across package.json files
|
|
216
|
-
function checkVersionConflicts(workspaceRoot: string): string[] {
|
|
217
|
-
console.log('\n🔍 Checking for version conflicts across package.json files:');
|
|
218
|
-
|
|
219
|
-
const dependencyMap = collectAllDependencies(workspaceRoot);
|
|
220
|
-
const conflicts: string[] = [];
|
|
221
|
-
|
|
222
|
-
for (const [packageName, usages] of dependencyMap.entries()) {
|
|
223
|
-
// Get unique versions (ignoring workspace: and file: protocols)
|
|
224
|
-
const versions = new Set(
|
|
225
|
-
usages
|
|
226
|
-
.map(u => u.version)
|
|
227
|
-
.filter(v => !v.startsWith('workspace:') && !v.startsWith('file:'))
|
|
228
|
-
);
|
|
229
|
-
|
|
230
|
-
if (versions.size > 1) {
|
|
231
|
-
const conflictDetails = usages
|
|
232
|
-
.filter(u => !u.version.startsWith('workspace:') && !u.version.startsWith('file:'))
|
|
233
|
-
.map(u => ` ${u.file} (${u.type}): ${u.version}`)
|
|
234
|
-
.join('\n');
|
|
235
|
-
|
|
236
|
-
conflicts.push(` ❌ ${packageName} has ${versions.size} different versions:\n${conflictDetails}`);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
if (conflicts.length === 0) {
|
|
241
|
-
console.log(' ✅ No version conflicts found');
|
|
242
|
-
} else {
|
|
243
|
-
for (const conflict of conflicts) {
|
|
244
|
-
console.log(conflict);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
return conflicts;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Prints the educational message explaining why semver ranges are forbidden.
|
|
253
|
-
* This helps developers understand the rationale behind locked versions.
|
|
254
|
-
*/
|
|
255
|
-
// webpieces-disable max-lines-new-methods -- Educational message template, splitting reduces clarity
|
|
256
|
-
function printSemverRangeEducationalMessage(semverErrors: number): void {
|
|
257
|
-
console.log(`
|
|
258
|
-
❌ SEMVER RANGES DETECTED - BUILD FAILED
|
|
259
|
-
|
|
260
|
-
Found ${semverErrors} package(s) using semver ranges (^, ~, *, etc.) instead of locked versions.
|
|
261
|
-
|
|
262
|
-
WHY THIS IS A HARD FAILURE:
|
|
263
|
-
═══════════════════════════════════════════════════════════════════════════════
|
|
264
|
-
|
|
265
|
-
1. MICRO BUGS ARE REAL
|
|
266
|
-
Thinking that patch versions (1.4.5 → 1.4.6) don't introduce bugs is wrong.
|
|
267
|
-
They do. Sometimes what looks like an "easy fix" breaks things in subtle ways.
|
|
268
|
-
|
|
269
|
-
2. GIT BISECT BECOMES USELESS
|
|
270
|
-
When you run "git bisect" to find when a bug was introduced, it fails if
|
|
271
|
-
software changed OUTSIDE of git. You checkout an old commit, but node_modules
|
|
272
|
-
has different versions than when that commit was made. The bug persists even
|
|
273
|
-
in "known good" commits because the library versions drifted.
|
|
274
|
-
|
|
275
|
-
3. THE "MAGIC BUG" PROBLEM
|
|
276
|
-
You checkout code from 6 months ago to debug an issue. The bug is still there!
|
|
277
|
-
But it wasn't there 6 months ago... The culprit: a minor version upgrade that
|
|
278
|
-
happened silently without any PR or git commit. Impossible to track down.
|
|
279
|
-
|
|
280
|
-
4. CHANGES OUTSIDE GIT = BAD
|
|
281
|
-
Every change to your software should be tracked in version control.
|
|
282
|
-
Implicit library upgrades via semver ranges violate this principle.
|
|
283
|
-
|
|
284
|
-
THE SOLUTION:
|
|
285
|
-
═══════════════════════════════════════════════════════════════════════════════
|
|
286
|
-
|
|
287
|
-
Use LOCKED (exact) versions for all dependencies:
|
|
288
|
-
❌ "lodash": "^4.17.21" <- BAD: allows 4.17.22, 4.18.0, etc.
|
|
289
|
-
❌ "lodash": "~4.17.21" <- BAD: allows 4.17.22, 4.17.23, etc.
|
|
290
|
-
✅ "lodash": "4.17.21" <- GOOD: locked to this exact version
|
|
291
|
-
|
|
292
|
-
To upgrade libraries, use an explicit process:
|
|
293
|
-
1. Run: npm update <package-name>
|
|
294
|
-
2. Test thoroughly
|
|
295
|
-
3. Commit the package.json AND package-lock.json changes
|
|
296
|
-
4. Create a PR so the upgrade is reviewed and tracked in git history
|
|
297
|
-
|
|
298
|
-
This way, every library change is:
|
|
299
|
-
• Intentional (not accidental)
|
|
300
|
-
• Reviewed (via PR)
|
|
301
|
-
• Tracked (in git history)
|
|
302
|
-
• Bisectable (git bisect works correctly)
|
|
303
|
-
|
|
304
|
-
`);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// Check semver ranges in all package.json files - FAILS if any found
|
|
308
|
-
function checkSemverRanges(workspaceRoot: string): { errors: number } {
|
|
309
|
-
console.log('\n📋 Checking for unlocked versions (semver ranges):');
|
|
310
|
-
const packageFiles = findPackageJsonFiles(workspaceRoot);
|
|
311
|
-
let semverErrors = 0;
|
|
312
|
-
|
|
313
|
-
for (const filePath of packageFiles) {
|
|
314
|
-
const relativePath = path.relative(workspaceRoot, filePath);
|
|
315
|
-
const errors = validatePackageJson(filePath);
|
|
316
|
-
|
|
317
|
-
if (errors.length > 0) {
|
|
318
|
-
console.log(` ❌ ${relativePath}:`);
|
|
319
|
-
for (const error of errors) {
|
|
320
|
-
console.log(` ${error}`);
|
|
321
|
-
}
|
|
322
|
-
semverErrors += errors.length;
|
|
323
|
-
} else {
|
|
324
|
-
console.log(` ✅ ${relativePath}`);
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
return { errors: semverErrors };
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
export default async function runExecutor(
|
|
332
|
-
_options: ValidateVersionsLockedOptions,
|
|
333
|
-
context: ExecutorContext
|
|
334
|
-
): Promise<ExecutorResult> {
|
|
335
|
-
console.log('\n🔒 Validating Package Versions are LOCKED and CONSISTENT\n');
|
|
336
|
-
|
|
337
|
-
const workspaceRoot = context.root;
|
|
338
|
-
|
|
339
|
-
// Step 1: Check for semver ranges (FAILS if any found)
|
|
340
|
-
const { errors: semverErrors } = checkSemverRanges(workspaceRoot);
|
|
341
|
-
const packageFiles = findPackageJsonFiles(workspaceRoot);
|
|
342
|
-
|
|
343
|
-
// Step 2: Check for version conflicts across package.json files
|
|
344
|
-
const versionConflicts = checkVersionConflicts(workspaceRoot);
|
|
345
|
-
|
|
346
|
-
// Summary
|
|
347
|
-
console.log(`\n📊 Summary:`);
|
|
348
|
-
console.log(` Files checked: ${packageFiles.length}`);
|
|
349
|
-
console.log(` Unlocked versions (semver ranges): ${semverErrors}`);
|
|
350
|
-
console.log(` Version conflicts: ${versionConflicts.length}`);
|
|
351
|
-
|
|
352
|
-
// Fail on semver ranges with educational message
|
|
353
|
-
if (semverErrors > 0) {
|
|
354
|
-
printSemverRangeEducationalMessage(semverErrors);
|
|
355
|
-
return { success: false };
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
// Fail on version conflicts
|
|
359
|
-
if (versionConflicts.length > 0) {
|
|
360
|
-
console.log('\n❌ VALIDATION FAILED!');
|
|
361
|
-
console.log(' Fix version conflicts - all package.json files must use the same version for each dependency.');
|
|
362
|
-
console.log(' This prevents "works on my machine" bugs where different projects use different library versions.\n');
|
|
363
|
-
return { success: false };
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
console.log('\n✅ VALIDATION PASSED! All versions are locked and consistent.');
|
|
367
|
-
return { success: true };
|
|
368
|
-
}
|
package/plugin/README.md
DELETED
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
# @webpieces/dev-config Plugin
|
|
2
|
-
|
|
3
|
-
Nx inference plugin that automatically provides architecture validation and circular dependency checking for your workspace.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
### Workspace-Level Architecture Validation
|
|
8
|
-
|
|
9
|
-
Automatically adds targets for managing and validating your project architecture:
|
|
10
|
-
|
|
11
|
-
- **`arch:generate`** - Generate dependency graph from project.json files
|
|
12
|
-
- **`arch:visualize`** - Create visual representations of the dependency graph
|
|
13
|
-
- **`arch:validate-no-architecture-cycles`** - Validate the architecture has no circular project dependencies
|
|
14
|
-
- **`arch:validate-no-skiplevel-deps`** - Validate no redundant transitive dependencies
|
|
15
|
-
- **`arch:validate-architecture-unchanged`** - Validate against blessed dependency graph
|
|
16
|
-
|
|
17
|
-
### Per-Project File Import Cycle Checking
|
|
18
|
-
|
|
19
|
-
Automatically adds a `validate-no-file-import-cycles` target to every project with a `src/` directory using [madge](https://github.com/pahen/madge).
|
|
20
|
-
|
|
21
|
-
## Installation
|
|
22
|
-
|
|
23
|
-
Add the plugin to your Nx workspace:
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
nx add @webpieces/dev-config
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
This automatically:
|
|
30
|
-
- Registers the plugin in `nx.json`
|
|
31
|
-
- Adds `madge` as a devDependency (required for circular dependency checking)
|
|
32
|
-
- Creates the `architecture/` directory
|
|
33
|
-
- Adds convenient npm scripts to `package.json`
|
|
34
|
-
- Creates `eslint.webpieces.config.mjs` with @webpieces ESLint rules
|
|
35
|
-
- Creates `eslint.config.mjs` (if you don't have one) that imports the webpieces rules
|
|
36
|
-
- If you already have `eslint.config.mjs`, shows you how to import the webpieces rules (one line)
|
|
37
|
-
- Makes all targets immediately available
|
|
38
|
-
|
|
39
|
-
**For new projects: Zero configuration needed!** All architecture validation, circular dependency checking, and ESLint rules are active.
|
|
40
|
-
|
|
41
|
-
**For existing projects with ESLint:** Just add one import line shown during installation to enable the @webpieces ESLint rules.
|
|
42
|
-
|
|
43
|
-
## Usage
|
|
44
|
-
|
|
45
|
-
### Convenient npm Scripts
|
|
46
|
-
|
|
47
|
-
The init generator adds these npm scripts for easy access:
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
# Generate and visualize
|
|
51
|
-
npm run arch:generate # Generate dependency graph
|
|
52
|
-
npm run arch:visualize # Visualize in browser
|
|
53
|
-
|
|
54
|
-
# Validation
|
|
55
|
-
npm run arch:validate # Quick: no-cycles + no-skiplevel-deps
|
|
56
|
-
npm run arch:validate-all # Full: adds architecture-unchanged check
|
|
57
|
-
npm run arch:check-circular # Check all projects for circular deps (madge)
|
|
58
|
-
npm run arch:check-circular-affected # Check only affected projects
|
|
59
|
-
npm run arch:validate-complete # Complete: all validations + circular deps
|
|
60
|
-
|
|
61
|
-
# Recommended workflow
|
|
62
|
-
npm run arch:generate # 1. Generate graph first
|
|
63
|
-
npm run arch:validate-complete # 2. Run all validations
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### Direct Nx Targets
|
|
67
|
-
|
|
68
|
-
You can also run targets directly with Nx:
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
# Generate the dependency graph
|
|
72
|
-
nx run architecture:generate
|
|
73
|
-
|
|
74
|
-
# Visualize the graph in your browser
|
|
75
|
-
nx run architecture:visualize
|
|
76
|
-
|
|
77
|
-
# Validate no circular project dependencies
|
|
78
|
-
nx run architecture:validate-no-architecture-cycles
|
|
79
|
-
|
|
80
|
-
# Validate against blessed graph (for CI)
|
|
81
|
-
nx run architecture:validate-architecture-unchanged
|
|
82
|
-
|
|
83
|
-
# Check for redundant dependencies
|
|
84
|
-
nx run architecture:validate-no-skiplevel-deps
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### Per-Project File Import Cycle Checking
|
|
88
|
-
|
|
89
|
-
```bash
|
|
90
|
-
# Check a specific project
|
|
91
|
-
nx run my-project:validate-no-file-import-cycles
|
|
92
|
-
|
|
93
|
-
# Check all affected projects
|
|
94
|
-
nx affected --target=validate-no-file-import-cycles
|
|
95
|
-
|
|
96
|
-
# Check all projects
|
|
97
|
-
nx run-many --target=validate-no-file-import-cycles --all
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## Configuration
|
|
101
|
-
|
|
102
|
-
Configure the plugin in `nx.json`:
|
|
103
|
-
|
|
104
|
-
```json
|
|
105
|
-
{
|
|
106
|
-
"plugins": [
|
|
107
|
-
{
|
|
108
|
-
"plugin": "@webpieces/dev-config",
|
|
109
|
-
"options": {
|
|
110
|
-
"circularDeps": {
|
|
111
|
-
"enabled": true,
|
|
112
|
-
"targetName": "validate-no-file-import-cycles",
|
|
113
|
-
"excludePatterns": ["**/test-fixtures/**"]
|
|
114
|
-
},
|
|
115
|
-
"workspace": {
|
|
116
|
-
"enabled": true,
|
|
117
|
-
"targetPrefix": "architecture:",
|
|
118
|
-
"validations": {
|
|
119
|
-
"noCycles": true,
|
|
120
|
-
"noSkipLevelDeps": true,
|
|
121
|
-
"architectureUnchanged": true
|
|
122
|
-
},
|
|
123
|
-
"features": {
|
|
124
|
-
"generate": true,
|
|
125
|
-
"visualize": true
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
]
|
|
131
|
-
}
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
### Configuration Options
|
|
135
|
-
|
|
136
|
-
#### `circularDeps`
|
|
137
|
-
|
|
138
|
-
- **`enabled`** (boolean, default: `true`) - Enable/disable file import cycle checking
|
|
139
|
-
- **`targetName`** (string, default: `'validate-no-file-import-cycles'`) - Name of the target to create
|
|
140
|
-
- **`excludePatterns`** (string[], default: `[]`) - Patterns to exclude from checking
|
|
141
|
-
|
|
142
|
-
#### `workspace`
|
|
143
|
-
|
|
144
|
-
- **`enabled`** (boolean, default: `true`) - Enable/disable workspace-level validation
|
|
145
|
-
- **`targetPrefix`** (string, default: `'arch:'`) - Prefix for workspace target names
|
|
146
|
-
- **`graphPath`** (string, default: `'architecture/dependencies.json'`) - Path to dependency graph file
|
|
147
|
-
|
|
148
|
-
##### `workspace.validations`
|
|
149
|
-
|
|
150
|
-
- **`noCycles`** (boolean, default: `true`) - Enable no-cycles validation
|
|
151
|
-
- **`noSkipLevelDeps`** (boolean, default: `true`) - Enable skip-level deps validation
|
|
152
|
-
- **`architectureUnchanged`** (boolean, default: `true`) - Enable unchanged graph validation
|
|
153
|
-
|
|
154
|
-
##### `workspace.features`
|
|
155
|
-
|
|
156
|
-
- **`generate`** (boolean, default: `true`) - Enable graph generation target
|
|
157
|
-
- **`visualize`** (boolean, default: `true`) - Enable visualization target
|
|
158
|
-
|
|
159
|
-
## Examples
|
|
160
|
-
|
|
161
|
-
### Disable Architecture Validation, Keep Circular Deps
|
|
162
|
-
|
|
163
|
-
```json
|
|
164
|
-
{
|
|
165
|
-
"plugin": "@webpieces/dev-config",
|
|
166
|
-
"options": {
|
|
167
|
-
"workspace": { "enabled": false }
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### Disable Circular Deps, Keep Architecture Validation
|
|
173
|
-
|
|
174
|
-
```json
|
|
175
|
-
{
|
|
176
|
-
"plugin": "@webpieces/dev-config",
|
|
177
|
-
"options": {
|
|
178
|
-
"circularDeps": { "enabled": false }
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
### Disable Specific Validations
|
|
184
|
-
|
|
185
|
-
```json
|
|
186
|
-
{
|
|
187
|
-
"plugin": "@webpieces/dev-config",
|
|
188
|
-
"options": {
|
|
189
|
-
"workspace": {
|
|
190
|
-
"validations": {
|
|
191
|
-
"architectureUnchanged": false,
|
|
192
|
-
"noSkipLevelDeps": false
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### Exclude Test Fixtures from Circular Deps
|
|
200
|
-
|
|
201
|
-
```json
|
|
202
|
-
{
|
|
203
|
-
"plugin": "@webpieces/dev-config",
|
|
204
|
-
"options": {
|
|
205
|
-
"circularDeps": {
|
|
206
|
-
"excludePatterns": ["**/test-fixtures/**", "**/__tests__/**"]
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
### Custom Target Names
|
|
213
|
-
|
|
214
|
-
```json
|
|
215
|
-
{
|
|
216
|
-
"plugin": "@webpieces/dev-config",
|
|
217
|
-
"options": {
|
|
218
|
-
"circularDeps": { "targetName": "circular-check" },
|
|
219
|
-
"workspace": { "targetPrefix": "architecture:" }
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
## How It Works
|
|
225
|
-
|
|
226
|
-
The plugin uses Nx's [Project Crystal (Inferred Tasks)](https://nx.dev/concepts/inferred-tasks) feature via the `createNodesV2` API to automatically detect and configure targets:
|
|
227
|
-
|
|
228
|
-
1. **Workspace Detection**: Looks for a `project.json` at the workspace root to add architecture targets
|
|
229
|
-
2. **Project Detection**: Scans all projects for `src/` directories to add circular-deps targets
|
|
230
|
-
3. **Pattern Matching**: Respects exclude patterns for fine-grained control
|
|
231
|
-
|
|
232
|
-
## Requirements
|
|
233
|
-
|
|
234
|
-
- Nx >= 18.0.0
|
|
235
|
-
- Node.js >= 18.0.0
|
|
236
|
-
- [Graphviz](https://graphviz.org/) (for visualization)
|
|
237
|
-
- [madge](https://github.com/pahen/madge) (bundled, used for circular dep checking)
|
|
238
|
-
|
|
239
|
-
## Related Documentation
|
|
240
|
-
|
|
241
|
-
- [Nx Inferred Tasks](https://nx.dev/concepts/inferred-tasks)
|
|
242
|
-
- [Architecture Validation Guide](../../architecture/README.md)
|
|
243
|
-
- [ESLint Plugin](../eslint-plugin/README.md)
|
package/plugin/index.d.ts
DELETED
package/plugin/index.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const tslib_1 = require("tslib");
|
|
4
|
-
/**
|
|
5
|
-
* Re-export plugin from parent directory for clean imports
|
|
6
|
-
*/
|
|
7
|
-
tslib_1.__exportStar(require("../plugin"), exports);
|
|
8
|
-
//# sourceMappingURL=index.js.map
|
package/plugin/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/tooling/dev-config/plugin/index.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,oDAA0B","sourcesContent":["/**\n * Re-export plugin from parent directory for clean imports\n */\nexport * from '../plugin';\n"]}
|
package/plugin/index.ts
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|