@webpieces/dev-config 0.2.46 → 0.2.51
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/architecture/executors/validate-modified-methods/executor.d.ts +26 -0
- package/architecture/executors/validate-modified-methods/executor.js +505 -0
- package/architecture/executors/validate-modified-methods/executor.js.map +1 -0
- package/architecture/executors/validate-modified-methods/executor.ts +569 -0
- package/architecture/executors/validate-modified-methods/schema.json +14 -0
- package/architecture/executors/validate-new-methods/executor.d.ts +1 -1
- package/architecture/executors/validate-new-methods/executor.js +23 -10
- package/architecture/executors/validate-new-methods/executor.js.map +1 -1
- package/architecture/executors/validate-new-methods/executor.ts +23 -10
- package/architecture/lib/graph-loader.js +29 -1
- package/architecture/lib/graph-loader.js.map +1 -1
- package/architecture/lib/graph-loader.ts +35 -1
- package/executors/validate-versions-locked/executor.d.ts +21 -0
- package/executors/{validate-versions → validate-versions-locked}/executor.js +93 -21
- package/executors/validate-versions-locked/executor.js.map +1 -0
- package/executors/{validate-versions → validate-versions-locked}/executor.ts +99 -25
- package/executors/validate-versions-locked/schema.json +8 -0
- package/executors.json +9 -4
- package/package.json +1 -1
- package/plugin.js +78 -30
- package/src/generators/init/generator.js +16 -3
- package/src/generators/init/generator.js.map +1 -1
- package/templates/eslint.webpieces.config.mjs +2 -2
- package/executors/validate-versions/executor.d.ts +0 -16
- package/executors/validate-versions/executor.js.map +0 -1
- package/executors/validate-versions/schema.json +0 -8
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Validate Versions Executor
|
|
2
|
+
* Validate Versions Locked Executor
|
|
3
3
|
*
|
|
4
|
-
* Validates package.json versions
|
|
5
|
-
*
|
|
4
|
+
* Validates that package.json versions are LOCKED (exact versions, no semver ranges)
|
|
5
|
+
* and checks npm ci compatibility for peer dependency conflicts.
|
|
6
|
+
*
|
|
7
|
+
* Why locked versions matter:
|
|
8
|
+
* - Micro bugs ARE introduced via patch versions (1.4.5 → 1.4.6)
|
|
9
|
+
* - git bisect fails when software changes OUTSIDE of git
|
|
10
|
+
* - Library upgrades must be explicit via PR/commit, not implicit drift
|
|
6
11
|
*
|
|
7
12
|
* Usage:
|
|
8
|
-
* nx run
|
|
13
|
+
* nx run architecture:validate-versions-locked
|
|
9
14
|
*/
|
|
10
15
|
|
|
11
16
|
import type { ExecutorContext } from '@nx/devkit';
|
|
@@ -13,7 +18,7 @@ import { execSync } from 'child_process';
|
|
|
13
18
|
import * as fs from 'fs';
|
|
14
19
|
import * as path from 'path';
|
|
15
20
|
|
|
16
|
-
export interface
|
|
21
|
+
export interface ValidateVersionsLockedOptions {
|
|
17
22
|
// No options needed
|
|
18
23
|
}
|
|
19
24
|
|
|
@@ -21,6 +26,7 @@ export interface ExecutorResult {
|
|
|
21
26
|
success: boolean;
|
|
22
27
|
}
|
|
23
28
|
|
|
29
|
+
// webpieces-disable max-lines-new-methods -- Existing method from renamed validate-versions file
|
|
24
30
|
// Find all package.json files except node_modules, dist, .nx, .angular
|
|
25
31
|
function findPackageJsonFiles(dir: string, basePath = ''): string[] {
|
|
26
32
|
const files: string[] = [];
|
|
@@ -87,6 +93,7 @@ function hasSemverRange(version: string): boolean {
|
|
|
87
93
|
return semverPatterns.some((pattern) => pattern.test(version));
|
|
88
94
|
}
|
|
89
95
|
|
|
96
|
+
// webpieces-disable max-lines-new-methods -- Existing method from renamed validate-versions file
|
|
90
97
|
// Validate a single package.json file for semver ranges
|
|
91
98
|
function validatePackageJson(filePath: string): string[] {
|
|
92
99
|
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
@@ -105,7 +112,7 @@ function validatePackageJson(filePath: string): string[] {
|
|
|
105
112
|
|
|
106
113
|
if (hasSemverRange(version as string)) {
|
|
107
114
|
errors.push(
|
|
108
|
-
`dependencies.${name}: "${version}" uses semver range (
|
|
115
|
+
`dependencies.${name}: "${version}" uses semver range (must be locked to exact version)`,
|
|
109
116
|
);
|
|
110
117
|
}
|
|
111
118
|
}
|
|
@@ -121,7 +128,7 @@ function validatePackageJson(filePath: string): string[] {
|
|
|
121
128
|
|
|
122
129
|
if (hasSemverRange(version as string)) {
|
|
123
130
|
errors.push(
|
|
124
|
-
`devDependencies.${name}: "${version}" uses semver range (
|
|
131
|
+
`devDependencies.${name}: "${version}" uses semver range (must be locked to exact version)`,
|
|
125
132
|
);
|
|
126
133
|
}
|
|
127
134
|
}
|
|
@@ -137,6 +144,7 @@ function validatePackageJson(filePath: string): string[] {
|
|
|
137
144
|
}
|
|
138
145
|
}
|
|
139
146
|
|
|
147
|
+
// webpieces-disable max-lines-new-methods -- Existing method from renamed validate-versions file
|
|
140
148
|
// Check npm ci compatibility
|
|
141
149
|
function checkNpmCiCompatibility(workspaceRoot: string): string[] {
|
|
142
150
|
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
@@ -162,6 +170,13 @@ function checkNpmCiCompatibility(workspaceRoot: string): string[] {
|
|
|
162
170
|
// Parse the error output to extract peer dependency conflicts
|
|
163
171
|
const output = err.stdout || err.stderr || err.message;
|
|
164
172
|
|
|
173
|
+
// Ignore errors about internal @webpieces/* packages with 0.0.0-dev versions
|
|
174
|
+
// These don't exist on npm registry (only locally) but that's expected in development/CI
|
|
175
|
+
if (output.includes('npm error') && output.includes('@webpieces/') && output.includes('0.0.0-dev')) {
|
|
176
|
+
console.log(' ⏭️ Skipping npm ci check - internal @webpieces packages use local 0.0.0-dev versions');
|
|
177
|
+
return [];
|
|
178
|
+
}
|
|
179
|
+
|
|
165
180
|
// Check if it's a peer dependency error (npm error, not npm warn)
|
|
166
181
|
if (output.includes('npm error') && (output.includes('ERESOLVE') || output.includes('peer'))) {
|
|
167
182
|
return [output];
|
|
@@ -177,39 +192,91 @@ function checkNpmCiCompatibility(workspaceRoot: string): string[] {
|
|
|
177
192
|
}
|
|
178
193
|
}
|
|
179
194
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
195
|
+
/**
|
|
196
|
+
* Prints the educational message explaining why semver ranges are forbidden.
|
|
197
|
+
* This helps developers understand the rationale behind locked versions.
|
|
198
|
+
*/
|
|
199
|
+
// webpieces-disable max-lines-new-methods -- Educational message template, splitting reduces clarity
|
|
200
|
+
function printSemverRangeEducationalMessage(semverErrors: number): void {
|
|
201
|
+
console.log(`
|
|
202
|
+
❌ SEMVER RANGES DETECTED - BUILD FAILED
|
|
203
|
+
|
|
204
|
+
Found ${semverErrors} package(s) using semver ranges (^, ~, *, etc.) instead of locked versions.
|
|
205
|
+
|
|
206
|
+
WHY THIS IS A HARD FAILURE:
|
|
207
|
+
═══════════════════════════════════════════════════════════════════════════════
|
|
208
|
+
|
|
209
|
+
1. MICRO BUGS ARE REAL
|
|
210
|
+
Thinking that patch versions (1.4.5 → 1.4.6) don't introduce bugs is wrong.
|
|
211
|
+
They do. Sometimes what looks like an "easy fix" breaks things in subtle ways.
|
|
212
|
+
|
|
213
|
+
2. GIT BISECT BECOMES USELESS
|
|
214
|
+
When you run "git bisect" to find when a bug was introduced, it fails if
|
|
215
|
+
software changed OUTSIDE of git. You checkout an old commit, but node_modules
|
|
216
|
+
has different versions than when that commit was made. The bug persists even
|
|
217
|
+
in "known good" commits because the library versions drifted.
|
|
218
|
+
|
|
219
|
+
3. THE "MAGIC BUG" PROBLEM
|
|
220
|
+
You checkout code from 6 months ago to debug an issue. The bug is still there!
|
|
221
|
+
But it wasn't there 6 months ago... The culprit: a minor version upgrade that
|
|
222
|
+
happened silently without any PR or git commit. Impossible to track down.
|
|
223
|
+
|
|
224
|
+
4. CHANGES OUTSIDE GIT = BAD
|
|
225
|
+
Every change to your software should be tracked in version control.
|
|
226
|
+
Implicit library upgrades via semver ranges violate this principle.
|
|
227
|
+
|
|
228
|
+
THE SOLUTION:
|
|
229
|
+
═══════════════════════════════════════════════════════════════════════════════
|
|
230
|
+
|
|
231
|
+
Use LOCKED (exact) versions for all dependencies:
|
|
232
|
+
❌ "lodash": "^4.17.21" <- BAD: allows 4.17.22, 4.18.0, etc.
|
|
233
|
+
❌ "lodash": "~4.17.21" <- BAD: allows 4.17.22, 4.17.23, etc.
|
|
234
|
+
✅ "lodash": "4.17.21" <- GOOD: locked to this exact version
|
|
235
|
+
|
|
236
|
+
To upgrade libraries, use an explicit process:
|
|
237
|
+
1. Run: npm update <package-name>
|
|
238
|
+
2. Test thoroughly
|
|
239
|
+
3. Commit the package.json AND package-lock.json changes
|
|
240
|
+
4. Create a PR so the upgrade is reviewed and tracked in git history
|
|
241
|
+
|
|
242
|
+
This way, every library change is:
|
|
243
|
+
• Intentional (not accidental)
|
|
244
|
+
• Reviewed (via PR)
|
|
245
|
+
• Tracked (in git history)
|
|
246
|
+
• Bisectable (git bisect works correctly)
|
|
247
|
+
|
|
248
|
+
`);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Check semver ranges in all package.json files - FAILS if any found
|
|
252
|
+
function checkSemverRanges(workspaceRoot: string): { errors: number } {
|
|
253
|
+
console.log('\n📋 Checking for unlocked versions (semver ranges):');
|
|
183
254
|
const packageFiles = findPackageJsonFiles(workspaceRoot);
|
|
184
|
-
let
|
|
255
|
+
let semverErrors = 0;
|
|
185
256
|
|
|
186
257
|
for (const filePath of packageFiles) {
|
|
187
258
|
const relativePath = path.relative(workspaceRoot, filePath);
|
|
188
259
|
const errors = validatePackageJson(filePath);
|
|
189
260
|
|
|
190
261
|
if (errors.length > 0) {
|
|
191
|
-
console.log(`
|
|
262
|
+
console.log(` ❌ ${relativePath}:`);
|
|
192
263
|
for (const error of errors) {
|
|
193
264
|
console.log(` ${error}`);
|
|
194
265
|
}
|
|
195
|
-
|
|
266
|
+
semverErrors += errors.length;
|
|
196
267
|
} else {
|
|
197
268
|
console.log(` ✅ ${relativePath}`);
|
|
198
269
|
}
|
|
199
270
|
}
|
|
200
271
|
|
|
201
|
-
|
|
202
|
-
console.log(`\n ⚠️ Note: ${semverWarnings} semver ranges found (consider using fixed versions for reproducibility)`);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
return { warnings: semverWarnings };
|
|
272
|
+
return { errors: semverErrors };
|
|
206
273
|
}
|
|
207
274
|
|
|
208
275
|
export default async function runExecutor(
|
|
209
|
-
_options:
|
|
276
|
+
_options: ValidateVersionsLockedOptions,
|
|
210
277
|
context: ExecutorContext
|
|
211
278
|
): Promise<ExecutorResult> {
|
|
212
|
-
console.log('\n
|
|
279
|
+
console.log('\n🔒 Validating Package Versions are LOCKED (no semver ranges)\n');
|
|
213
280
|
|
|
214
281
|
const workspaceRoot = context.root;
|
|
215
282
|
|
|
@@ -233,23 +300,30 @@ export default async function runExecutor(
|
|
|
233
300
|
console.log(' ✅ npm ci compatibility check passed');
|
|
234
301
|
}
|
|
235
302
|
|
|
236
|
-
// Step 2: Check for semver ranges
|
|
237
|
-
const {
|
|
303
|
+
// Step 2: Check for semver ranges (FAILS if any found)
|
|
304
|
+
const { errors: semverErrors } = checkSemverRanges(workspaceRoot);
|
|
238
305
|
const packageFiles = findPackageJsonFiles(workspaceRoot);
|
|
239
306
|
|
|
240
307
|
// Summary
|
|
241
308
|
console.log(`\n📊 Summary:`);
|
|
242
309
|
console.log(` npm ci compatibility: ${npmCiErrors.length === 0 ? '✅' : '❌'}`);
|
|
243
310
|
console.log(` Files checked: ${packageFiles.length}`);
|
|
244
|
-
console.log(`
|
|
245
|
-
console.log(`
|
|
311
|
+
console.log(` Unlocked versions: ${semverErrors}`);
|
|
312
|
+
console.log(` Peer dep errors: ${npmCiErrors.length}`);
|
|
246
313
|
|
|
314
|
+
// Fail on npm ci errors
|
|
247
315
|
if (npmCiErrors.length > 0) {
|
|
248
316
|
console.log('\n❌ VALIDATION FAILED!');
|
|
249
317
|
console.log(' Fix peer dependency conflicts to avoid CI failures.\n');
|
|
250
318
|
return { success: false };
|
|
251
319
|
}
|
|
252
320
|
|
|
253
|
-
|
|
321
|
+
// Fail on semver ranges with educational message
|
|
322
|
+
if (semverErrors > 0) {
|
|
323
|
+
printSemverRangeEducationalMessage(semverErrors);
|
|
324
|
+
return { success: false };
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
console.log('\n✅ VALIDATION PASSED! All versions are locked.');
|
|
254
328
|
return { success: true };
|
|
255
329
|
}
|
package/executors.json
CHANGED
|
@@ -35,6 +35,11 @@
|
|
|
35
35
|
"schema": "./architecture/executors/validate-new-methods/schema.json",
|
|
36
36
|
"description": "Validate new methods don't exceed max line count (only runs in affected mode)"
|
|
37
37
|
},
|
|
38
|
+
"validate-modified-methods": {
|
|
39
|
+
"implementation": "./architecture/executors/validate-modified-methods/executor",
|
|
40
|
+
"schema": "./architecture/executors/validate-modified-methods/schema.json",
|
|
41
|
+
"description": "Validate modified methods don't exceed max line count (encourages gradual cleanup)"
|
|
42
|
+
},
|
|
38
43
|
"help": {
|
|
39
44
|
"implementation": "./executors/help/executor",
|
|
40
45
|
"schema": "./executors/help/schema.json",
|
|
@@ -45,10 +50,10 @@
|
|
|
45
50
|
"schema": "./executors/validate-eslint-sync/schema.json",
|
|
46
51
|
"description": "Validate that workspace and template eslint.webpieces.config.mjs files have identical rules"
|
|
47
52
|
},
|
|
48
|
-
"validate-versions": {
|
|
49
|
-
"implementation": "./executors/validate-versions/executor",
|
|
50
|
-
"schema": "./executors/validate-versions/schema.json",
|
|
51
|
-
"description": "Validate package.json versions and npm ci
|
|
53
|
+
"validate-versions-locked": {
|
|
54
|
+
"implementation": "./executors/validate-versions-locked/executor",
|
|
55
|
+
"schema": "./executors/validate-versions-locked/schema.json",
|
|
56
|
+
"description": "Validate package.json versions are locked (no semver ranges) and npm ci compatible"
|
|
52
57
|
}
|
|
53
58
|
}
|
|
54
59
|
}
|
package/package.json
CHANGED
package/plugin.js
CHANGED
|
@@ -36,6 +36,10 @@ const DEFAULT_OPTIONS = {
|
|
|
36
36
|
architectureUnchanged: true,
|
|
37
37
|
validatePackageJson: true,
|
|
38
38
|
validateNewMethods: true,
|
|
39
|
+
validateModifiedMethods: true,
|
|
40
|
+
validateVersionsLocked: true,
|
|
41
|
+
newMethodsMaxLines: 30,
|
|
42
|
+
modifiedAndNewMethodsMaxLines: 80,
|
|
39
43
|
},
|
|
40
44
|
features: {
|
|
41
45
|
generate: true,
|
|
@@ -112,8 +116,9 @@ function addPerProjectTargets(results, projectFiles, opts, context) {
|
|
|
112
116
|
targets[targetName] = createCircularDepsTarget(projectRoot, targetName);
|
|
113
117
|
}
|
|
114
118
|
}
|
|
115
|
-
// Add ci target - composite target that runs lint, build, test
|
|
116
|
-
//
|
|
119
|
+
// Add ci target - composite target that runs lint, build, test, and typecheck
|
|
120
|
+
// The 'typecheck' target from @nx/js/typescript plugin already type-checks ALL files
|
|
121
|
+
// including *.spec.ts and *.test.ts via tsconfig.json references
|
|
117
122
|
targets['ci'] = createCiTarget();
|
|
118
123
|
if (Object.keys(targets).length === 0)
|
|
119
124
|
continue;
|
|
@@ -137,6 +142,27 @@ exports.createNodesV2 = [
|
|
|
137
142
|
// Inference function
|
|
138
143
|
createNodesFunction,
|
|
139
144
|
];
|
|
145
|
+
/**
|
|
146
|
+
* Build list of enabled validation target names for validate-complete dependency chain
|
|
147
|
+
*/
|
|
148
|
+
function buildValidationTargetsList(validations) {
|
|
149
|
+
const targets = [];
|
|
150
|
+
if (validations.noCycles)
|
|
151
|
+
targets.push('validate-no-architecture-cycles');
|
|
152
|
+
if (validations.architectureUnchanged)
|
|
153
|
+
targets.push('validate-architecture-unchanged');
|
|
154
|
+
if (validations.noSkipLevelDeps)
|
|
155
|
+
targets.push('validate-no-skiplevel-deps');
|
|
156
|
+
if (validations.validatePackageJson)
|
|
157
|
+
targets.push('validate-packagejson');
|
|
158
|
+
if (validations.validateNewMethods)
|
|
159
|
+
targets.push('validate-new-methods');
|
|
160
|
+
if (validations.validateModifiedMethods)
|
|
161
|
+
targets.push('validate-modified-methods');
|
|
162
|
+
if (validations.validateVersionsLocked)
|
|
163
|
+
targets.push('validate-versions-locked');
|
|
164
|
+
return targets;
|
|
165
|
+
}
|
|
140
166
|
/**
|
|
141
167
|
* Create workspace-level architecture validation targets WITHOUT prefix
|
|
142
168
|
* Used for virtual 'architecture' project
|
|
@@ -144,6 +170,7 @@ exports.createNodesV2 = [
|
|
|
144
170
|
function createWorkspaceTargetsWithoutPrefix(opts) {
|
|
145
171
|
const targets = {};
|
|
146
172
|
const graphPath = opts.workspace.graphPath;
|
|
173
|
+
const validations = opts.workspace.validations;
|
|
147
174
|
// Add help target (always available)
|
|
148
175
|
targets['help'] = createHelpTarget();
|
|
149
176
|
if (opts.workspace.features.generate) {
|
|
@@ -152,38 +179,29 @@ function createWorkspaceTargetsWithoutPrefix(opts) {
|
|
|
152
179
|
if (opts.workspace.features.visualize) {
|
|
153
180
|
targets['visualize'] = createVisualizeTargetWithoutPrefix(graphPath);
|
|
154
181
|
}
|
|
155
|
-
if (
|
|
182
|
+
if (validations.noCycles) {
|
|
156
183
|
targets['validate-no-architecture-cycles'] = createValidateNoCyclesTarget();
|
|
157
184
|
}
|
|
158
|
-
if (
|
|
185
|
+
if (validations.architectureUnchanged) {
|
|
159
186
|
targets['validate-architecture-unchanged'] = createValidateUnchangedTarget(graphPath);
|
|
160
187
|
}
|
|
161
|
-
if (
|
|
188
|
+
if (validations.noSkipLevelDeps) {
|
|
162
189
|
targets['validate-no-skiplevel-deps'] = createValidateNoSkipLevelTarget();
|
|
163
190
|
}
|
|
164
|
-
if (
|
|
191
|
+
if (validations.validatePackageJson) {
|
|
165
192
|
targets['validate-packagejson'] = createValidatePackageJsonTarget();
|
|
166
193
|
}
|
|
167
|
-
if (
|
|
168
|
-
targets['validate-new-methods'] = createValidateNewMethodsTarget();
|
|
169
|
-
}
|
|
170
|
-
// Add validate-complete target that runs all validations
|
|
171
|
-
const validationTargets = [];
|
|
172
|
-
if (opts.workspace.validations.noCycles) {
|
|
173
|
-
validationTargets.push('validate-no-architecture-cycles');
|
|
194
|
+
if (validations.validateNewMethods) {
|
|
195
|
+
targets['validate-new-methods'] = createValidateNewMethodsTarget(validations.newMethodsMaxLines);
|
|
174
196
|
}
|
|
175
|
-
if (
|
|
176
|
-
|
|
197
|
+
if (validations.validateModifiedMethods) {
|
|
198
|
+
targets['validate-modified-methods'] = createValidateModifiedMethodsTarget(validations.modifiedAndNewMethodsMaxLines);
|
|
177
199
|
}
|
|
178
|
-
if (
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
if (opts.workspace.validations.validatePackageJson) {
|
|
182
|
-
validationTargets.push('validate-packagejson');
|
|
183
|
-
}
|
|
184
|
-
if (opts.workspace.validations.validateNewMethods) {
|
|
185
|
-
validationTargets.push('validate-new-methods');
|
|
200
|
+
if (validations.validateVersionsLocked) {
|
|
201
|
+
targets['validate-versions-locked'] = createValidateVersionsLockedTarget();
|
|
186
202
|
}
|
|
203
|
+
// Add validate-complete target that runs all enabled validations
|
|
204
|
+
const validationTargets = buildValidationTargetsList(validations);
|
|
187
205
|
if (validationTargets.length > 0) {
|
|
188
206
|
targets['validate-complete'] = createValidateCompleteTarget(validationTargets);
|
|
189
207
|
}
|
|
@@ -218,7 +236,10 @@ function createWorkspaceTargets(opts) {
|
|
|
218
236
|
targets[`${prefix}validate-packagejson`] = createValidatePackageJsonTarget();
|
|
219
237
|
}
|
|
220
238
|
if (opts.workspace.validations.validateNewMethods) {
|
|
221
|
-
targets[`${prefix}validate-new-methods`] = createValidateNewMethodsTarget();
|
|
239
|
+
targets[`${prefix}validate-new-methods`] = createValidateNewMethodsTarget(opts.workspace.validations.newMethodsMaxLines);
|
|
240
|
+
}
|
|
241
|
+
if (opts.workspace.validations.validateModifiedMethods) {
|
|
242
|
+
targets[`${prefix}validate-modified-methods`] = createValidateModifiedMethodsTarget(opts.workspace.validations.modifiedAndNewMethodsMaxLines);
|
|
222
243
|
}
|
|
223
244
|
return targets;
|
|
224
245
|
}
|
|
@@ -302,15 +323,38 @@ function createValidatePackageJsonTarget() {
|
|
|
302
323
|
},
|
|
303
324
|
};
|
|
304
325
|
}
|
|
305
|
-
function createValidateNewMethodsTarget() {
|
|
326
|
+
function createValidateNewMethodsTarget(maxLines) {
|
|
306
327
|
return {
|
|
307
328
|
executor: '@webpieces/dev-config:validate-new-methods',
|
|
308
329
|
cache: false, // Don't cache - depends on git state
|
|
309
330
|
inputs: ['default'],
|
|
310
|
-
options: { max:
|
|
331
|
+
options: { max: maxLines },
|
|
311
332
|
metadata: {
|
|
312
333
|
technologies: ['nx'],
|
|
313
|
-
description:
|
|
334
|
+
description: `Validate new methods do not exceed ${maxLines} lines (only runs in affected mode)`,
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
function createValidateModifiedMethodsTarget(maxLines) {
|
|
339
|
+
return {
|
|
340
|
+
executor: '@webpieces/dev-config:validate-modified-methods',
|
|
341
|
+
cache: false, // Don't cache - depends on git state
|
|
342
|
+
inputs: ['default'],
|
|
343
|
+
options: { max: maxLines },
|
|
344
|
+
metadata: {
|
|
345
|
+
technologies: ['nx'],
|
|
346
|
+
description: `Validate new and modified methods do not exceed ${maxLines} lines (encourages gradual cleanup)`,
|
|
347
|
+
},
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
function createValidateVersionsLockedTarget() {
|
|
351
|
+
return {
|
|
352
|
+
executor: '@webpieces/dev-config:validate-versions-locked',
|
|
353
|
+
cache: true,
|
|
354
|
+
inputs: ['default'],
|
|
355
|
+
metadata: {
|
|
356
|
+
technologies: ['nx'],
|
|
357
|
+
description: 'Validate package.json versions are locked (no semver ranges) and npm ci compatible',
|
|
314
358
|
},
|
|
315
359
|
};
|
|
316
360
|
}
|
|
@@ -327,16 +371,20 @@ function createValidateCompleteTarget(validationTargets) {
|
|
|
327
371
|
}
|
|
328
372
|
/**
|
|
329
373
|
* Create per-project ci target - Gradle-style composite target
|
|
330
|
-
* Runs lint, build, and
|
|
374
|
+
* Runs lint, build, test, and typecheck in parallel
|
|
375
|
+
* (with test depending on build via targetDefaults)
|
|
376
|
+
*
|
|
377
|
+
* The 'typecheck' target from @nx/js/typescript plugin type-checks ALL *.ts files
|
|
378
|
+
* including test files (*.spec.ts, *.test.ts) via tsconfig.json references.
|
|
331
379
|
*/
|
|
332
380
|
function createCiTarget() {
|
|
333
381
|
return {
|
|
334
382
|
executor: 'nx:noop',
|
|
335
383
|
cache: true,
|
|
336
|
-
dependsOn: ['lint', 'build', 'test'],
|
|
384
|
+
dependsOn: ['lint', 'build', 'test', 'typecheck'],
|
|
337
385
|
metadata: {
|
|
338
386
|
technologies: ['nx'],
|
|
339
|
-
description: 'Run all CI checks: lint, build, and
|
|
387
|
+
description: 'Run all CI checks: lint, build, test, and typecheck (Gradle-style composite target)',
|
|
340
388
|
},
|
|
341
389
|
};
|
|
342
390
|
}
|
|
@@ -53,9 +53,20 @@ function registerPlugin(tree) {
|
|
|
53
53
|
const pluginName = '@webpieces/dev-config';
|
|
54
54
|
const alreadyRegistered = nxJson.plugins.some((p) => typeof p === 'string' ? p === pluginName : p.plugin === pluginName);
|
|
55
55
|
if (!alreadyRegistered) {
|
|
56
|
-
|
|
56
|
+
// Register plugin with default options for method size validation
|
|
57
|
+
nxJson.plugins.push({
|
|
58
|
+
plugin: pluginName,
|
|
59
|
+
options: {
|
|
60
|
+
workspace: {
|
|
61
|
+
validations: {
|
|
62
|
+
newMethodsMaxLines: 30,
|
|
63
|
+
modifiedAndNewMethodsMaxLines: 80,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
});
|
|
57
68
|
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
58
|
-
console.log(`✅ Registered ${pluginName} plugin in nx.json`);
|
|
69
|
+
console.log(`✅ Registered ${pluginName} plugin in nx.json with default options`);
|
|
59
70
|
}
|
|
60
71
|
else {
|
|
61
72
|
console.log(`ℹ️ ${pluginName} plugin is already registered`);
|
|
@@ -197,9 +208,11 @@ function addNpmScripts(tree) {
|
|
|
197
208
|
pkgJson.scripts['arch:check-circular-affected'] = 'nx affected --target=validate-no-file-import-cycles';
|
|
198
209
|
// Complete validation including circular deps
|
|
199
210
|
pkgJson.scripts['arch:validate-complete'] = 'npm run arch:validate-all && npm run arch:check-circular';
|
|
211
|
+
// Add CI script that runs lint, build, test on affected projects
|
|
212
|
+
pkgJson.scripts['webpieces:ci'] = 'npx nx affected --target=ci';
|
|
200
213
|
return pkgJson;
|
|
201
214
|
});
|
|
202
|
-
console.log('✅ Added npm scripts for architecture validation
|
|
215
|
+
console.log('✅ Added npm scripts for architecture validation, circular dependency checking, and CI');
|
|
203
216
|
}
|
|
204
217
|
function createEslintConfig(tree) {
|
|
205
218
|
const webpiecesConfigPath = 'eslint.webpieces.config.mjs';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/dev-config/src/generators/init/generator.ts"],"names":[],"mappings":"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","sourcesContent":["import { formatFiles, readNxJson, Tree, updateNxJson, updateJson, addDependenciesToPackageJson } from '@nx/devkit';\nimport { createHash } from 'crypto';\n\nexport interface InitGeneratorSchema {\n skipFormat?: boolean;\n}\n\nfunction calculateHash(content: string): string {\n return createHash('sha256').update(content).digest('hex');\n}\n\nfunction getPackageVersion(tree: Tree): string {\n const content = tree.read('node_modules/@webpieces/dev-config/package.json', 'utf-8');\n if (!content) {\n throw new Error('Could not read package.json from node_modules/@webpieces/dev-config');\n }\n const pkgJson = JSON.parse(content);\n return pkgJson.version;\n}\n\n/**\n * Init generator for @webpieces/dev-config\n *\n * Automatically runs when users execute: nx add @webpieces/dev-config\n *\n * Responsibilities:\n * - Registers the plugin in nx.json\n * - Adds architecture validation to targetDefaults (runs once before all builds)\n * - Creates architecture/ directory if needed\n * - Adds madge as a devDependency (required for circular dep checking)\n * - Adds convenient npm scripts to package.json\n * - Always creates eslint.webpieces.config.mjs with @webpieces rules\n * - Creates eslint.config.mjs (if not exists) that imports eslint.webpieces.config.mjs\n * - If eslint.config.mjs exists, shows user how to import eslint.webpieces.config.mjs\n * - Provides helpful output about available targets\n */\nexport default async function initGenerator(tree: Tree, options: InitGeneratorSchema) {\n registerPlugin(tree);\n addTargetDefaults(tree);\n const installTask = addMadgeDependency(tree);\n createArchitectureDirectory(tree);\n addNpmScripts(tree);\n const hasExistingEslintConfig = createEslintConfig(tree);\n\n if (!options.skipFormat) {\n await formatFiles(tree);\n }\n\n return createSuccessCallback(installTask, hasExistingEslintConfig);\n}\n\nfunction registerPlugin(tree: Tree): void {\n const nxJson = readNxJson(tree);\n if (!nxJson) {\n throw new Error('Could not read nx.json. Are you in an Nx workspace?');\n }\n\n if (!nxJson.plugins) {\n nxJson.plugins = [];\n }\n\n const pluginName = '@webpieces/dev-config';\n const alreadyRegistered = nxJson.plugins.some(\n (p) => typeof p === 'string' ? p === pluginName : p.plugin === pluginName\n );\n\n if (!alreadyRegistered) {\n nxJson.plugins.push(pluginName);\n updateNxJson(tree, nxJson);\n console.log(`✅ Registered ${pluginName} plugin in nx.json`);\n } else {\n console.log(`ℹ️ ${pluginName} plugin is already registered`);\n }\n}\n\nfunction addTargetDefaults(tree: Tree): void {\n const nxJson = readNxJson(tree);\n if (!nxJson) {\n throw new Error('Could not read nx.json. Are you in an Nx workspace?');\n }\n\n if (!nxJson.targetDefaults) {\n nxJson.targetDefaults = {};\n }\n\n // Find which executors are actually used in this workspace\n const usedExecutors = findUsedExecutors(tree);\n\n // Only add targetDefaults for executors that are actually used\n let updated = false;\n\n usedExecutors.forEach((executor) => {\n if (!nxJson.targetDefaults![executor]) {\n nxJson.targetDefaults![executor] = {};\n }\n\n const targetDef = nxJson.targetDefaults![executor];\n let dependsOn = targetDef.dependsOn || [];\n\n // Ensure dependsOn is an array\n if (!Array.isArray(dependsOn)) {\n dependsOn = [dependsOn];\n }\n\n // Check if architecture validation is already in dependsOn\n const hasArchValidation = dependsOn.some((dep) => {\n if (typeof dep === 'string') {\n return dep === 'architecture:validate-complete';\n }\n return dep.target === 'architecture:validate-complete';\n });\n\n // Check if circular deps validation is already in dependsOn\n const hasCircularDepsValidation = dependsOn.some((dep) => {\n if (typeof dep === 'string') {\n return dep === 'validate-no-file-import-cycles';\n }\n return dep.target === 'validate-no-file-import-cycles';\n });\n\n if (!hasCircularDepsValidation) {\n // Add circular deps validation (per-project check)\n dependsOn.unshift('validate-no-file-import-cycles');\n targetDef.dependsOn = dependsOn;\n updated = true;\n console.log(` ✅ Added circular deps validation to ${executor}`);\n }\n\n if (!hasArchValidation) {\n // Add architecture validation before other dependencies\n dependsOn.unshift('architecture:validate-complete');\n targetDef.dependsOn = dependsOn;\n updated = true;\n console.log(` ✅ Added architecture validation to ${executor}`);\n }\n });\n\n if (updated) {\n updateNxJson(tree, nxJson);\n console.log('✅ Added architecture validation to targetDefaults for used executors');\n } else {\n console.log('ℹ️ Architecture validation already configured in targetDefaults');\n }\n}\n\n/**\n * Scan all project.json files to find which build executors are actually used\n */\nfunction findUsedExecutors(tree: Tree): Set<string> {\n const usedExecutors = new Set<string>();\n\n // Known build executors we care about\n const buildExecutors = new Set([\n '@nx/js:tsc',\n '@nx/esbuild:esbuild',\n '@nx/webpack:webpack',\n '@nx/rollup:rollup',\n '@nx/vite:build',\n '@angular/build:application',\n '@angular-devkit/build-angular:browser',\n '@angular-devkit/build-angular:application'\n ]);\n\n // Scan all project.json files\n tree.listChanges(); // Force tree to be aware of all files\n\n const scanDir = (dir: string) => {\n for (const child of tree.children(dir)) {\n const childPath = dir === '.' ? child : `${dir}/${child}`;\n\n if (tree.isFile(childPath)) {\n if (child === 'project.json') {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- Intentionally ignoring JSON parse errors for malformed project.json files\n try {\n const content = tree.read(childPath, 'utf-8');\n if (content) {\n const projectJson = JSON.parse(content);\n if (projectJson.targets) {\n for (const target of Object.values(projectJson.targets)) {\n const executor = (target as { executor?: string })?.executor;\n if (executor && buildExecutors.has(executor)) {\n usedExecutors.add(executor);\n }\n }\n }\n }\n } catch (err: any) {\n //const error = toError(err);\n }\n }\n } else {\n // Skip node_modules and dist\n if (child !== 'node_modules' && child !== 'dist' && child !== '.git') {\n scanDir(childPath);\n }\n }\n }\n };\n\n scanDir('.');\n\n console.log(`ℹ️ Found ${usedExecutors.size} build executors in use: ${[...usedExecutors].join(', ')}`);\n\n return usedExecutors;\n}\n\nfunction addMadgeDependency(tree: Tree) {\n return addDependenciesToPackageJson(tree, {}, { 'madge': '^8.0.0' });\n}\n\nfunction createArchitectureDirectory(tree: Tree): void {\n if (!tree.exists('architecture')) {\n tree.write('architecture/.gitkeep', '');\n console.log('✅ Created architecture/ directory');\n }\n}\n\nfunction addNpmScripts(tree: Tree): void {\n updateJson(tree, 'package.json', (pkgJson) => {\n pkgJson.scripts = pkgJson.scripts ?? {};\n\n // Add architecture validation scripts\n pkgJson.scripts['arch:generate'] = 'nx run architecture:generate';\n pkgJson.scripts['arch:visualize'] = 'nx run architecture:visualize';\n pkgJson.scripts['arch:validate'] = 'nx run architecture:validate-no-architecture-cycles && nx run architecture:validate-no-skiplevel-deps';\n pkgJson.scripts['arch:validate-all'] = 'nx run architecture:validate-no-architecture-cycles && nx run architecture:validate-no-skiplevel-deps && nx run architecture:validate-architecture-unchanged';\n\n // Add file import cycle checking scripts\n pkgJson.scripts['arch:check-circular'] = 'nx run-many --target=validate-no-file-import-cycles --all';\n pkgJson.scripts['arch:check-circular-affected'] = 'nx affected --target=validate-no-file-import-cycles';\n\n // Complete validation including circular deps\n pkgJson.scripts['arch:validate-complete'] = 'npm run arch:validate-all && npm run arch:check-circular';\n\n return pkgJson;\n });\n\n console.log('✅ Added npm scripts for architecture validation and circular dependency checking');\n}\n\nfunction createEslintConfig(tree: Tree): boolean {\n const webpiecesConfigPath = 'eslint.webpieces.config.mjs';\n const mainConfigPath = 'eslint.config.mjs';\n\n // Always create eslint.webpieces.config.mjs with our rules\n createWebpiecesEslintConfig(tree, webpiecesConfigPath);\n\n // Check if main eslint.config.mjs exists\n const hasExistingConfig = tree.exists(mainConfigPath);\n\n if (!hasExistingConfig) {\n // No existing config - create one that imports webpieces config\n const mainConfig = `// ESLint configuration\n// Imports @webpieces/dev-config rules\n\nimport webpiecesConfig from './eslint.webpieces.config.mjs';\n\n// Export the webpieces configuration\n// You can add your own rules after spreading webpiecesConfig\nexport default [\n ...webpiecesConfig,\n // Add your custom ESLint configuration here\n];\n`;\n\n tree.write(mainConfigPath, mainConfig);\n console.log('✅ Created eslint.config.mjs with @webpieces/dev-config rules');\n }\n\n return hasExistingConfig;\n}\n\nfunction getWebpiecesEslintConfigTemplate(tree: Tree): string {\n // Read from canonical template file (single source of truth)\n const templatePath = 'node_modules/@webpieces/dev-config/templates/eslint.webpieces.config.mjs';\n const template = tree.read(templatePath, 'utf-8');\n\n if (!template) {\n throw new Error(`Could not read ESLint template from ${templatePath}`);\n }\n\n return template;\n}\n\nfunction warnConfigChanges(tree: Tree, configPath: string, newConfig: string): void {\n const version = getPackageVersion(tree);\n const versionedFilename = `${configPath}.v${version}`;\n\n tree.write(versionedFilename, newConfig);\n\n console.log('');\n console.log(`⚠️ ${configPath} has changes`);\n console.log('');\n console.log(' Either you modified the file OR @webpieces/dev-config has updates.');\n console.log('');\n console.log(` Created: ${versionedFilename} with latest version`);\n console.log('');\n console.log(' Please review and merge if needed:');\n console.log(` - Your current: ${configPath}`);\n console.log(` - New version: ${versionedFilename}`);\n console.log('');\n}\n\nfunction createWebpiecesEslintConfig(tree: Tree, configPath: string): void {\n const webpiecesConfig = getWebpiecesEslintConfigTemplate(tree);\n\n if (!tree.exists(configPath)) {\n tree.write(configPath, webpiecesConfig);\n console.log(`✅ Created ${configPath}`);\n return;\n }\n\n const currentContent = tree.read(configPath, 'utf-8');\n if (!currentContent) {\n tree.write(configPath, webpiecesConfig);\n console.log(`✅ Created ${configPath}`);\n return;\n }\n\n const currentHash = calculateHash(currentContent);\n const newHash = calculateHash(webpiecesConfig);\n\n if (currentHash === newHash) {\n console.log(`✅ ${configPath} is up to date`);\n return;\n }\n\n warnConfigChanges(tree, configPath, webpiecesConfig);\n}\n\nfunction createSuccessCallback(\n installTask: ReturnType<typeof addDependenciesToPackageJson>,\n hasExistingEslintConfig: boolean\n) {\n return async () => {\n await installTask();\n\n // ANSI color codes for formatted output\n const GREEN = '\\x1b[32m\\x1b[1m';\n const BOLD = '\\x1b[1m';\n const RESET = '\\x1b[0m';\n\n console.log('');\n console.log('✅ Added madge to devDependencies');\n console.log('');\n console.log(`${GREEN}✅ @webpieces/dev-config plugin initialized!${RESET}`);\n console.log('');\n console.log(`${GREEN}💡 Quick start:${RESET}`);\n console.log(` ${BOLD}npm run arch:generate${RESET} # Generate the dependency graph`);\n console.log(` ${BOLD}npm run arch:validate-complete${RESET} # Run complete validation`);\n console.log('');\n console.log(`💡 For full documentation, run: ${BOLD}nx run architecture:help${RESET}`);\n\n // Show ESLint integration instructions if they have an existing config\n if (hasExistingEslintConfig) {\n console.log('');\n console.log('📋 Existing eslint.config.mjs detected');\n console.log('');\n console.log('To use @webpieces/dev-config ESLint rules, add this import to your eslint.config.mjs:');\n console.log('');\n console.log(' import webpiecesConfig from \\'./eslint.webpieces.config.mjs\\';');\n console.log('');\n console.log('Then spread it into your config array:');\n console.log('');\n console.log(' export default [');\n console.log(' ...webpiecesConfig, // Add this line');\n console.log(' // ... your existing config');\n console.log(' ];');\n }\n\n console.log('');\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/dev-config/src/generators/init/generator.ts"],"names":[],"mappings":"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","sourcesContent":["import { formatFiles, readNxJson, Tree, updateNxJson, updateJson, addDependenciesToPackageJson } from '@nx/devkit';\nimport { createHash } from 'crypto';\n\nexport interface InitGeneratorSchema {\n skipFormat?: boolean;\n}\n\nfunction calculateHash(content: string): string {\n return createHash('sha256').update(content).digest('hex');\n}\n\nfunction getPackageVersion(tree: Tree): string {\n const content = tree.read('node_modules/@webpieces/dev-config/package.json', 'utf-8');\n if (!content) {\n throw new Error('Could not read package.json from node_modules/@webpieces/dev-config');\n }\n const pkgJson = JSON.parse(content);\n return pkgJson.version;\n}\n\n/**\n * Init generator for @webpieces/dev-config\n *\n * Automatically runs when users execute: nx add @webpieces/dev-config\n *\n * Responsibilities:\n * - Registers the plugin in nx.json\n * - Adds architecture validation to targetDefaults (runs once before all builds)\n * - Creates architecture/ directory if needed\n * - Adds madge as a devDependency (required for circular dep checking)\n * - Adds convenient npm scripts to package.json\n * - Always creates eslint.webpieces.config.mjs with @webpieces rules\n * - Creates eslint.config.mjs (if not exists) that imports eslint.webpieces.config.mjs\n * - If eslint.config.mjs exists, shows user how to import eslint.webpieces.config.mjs\n * - Provides helpful output about available targets\n */\nexport default async function initGenerator(tree: Tree, options: InitGeneratorSchema) {\n registerPlugin(tree);\n addTargetDefaults(tree);\n const installTask = addMadgeDependency(tree);\n createArchitectureDirectory(tree);\n addNpmScripts(tree);\n const hasExistingEslintConfig = createEslintConfig(tree);\n\n if (!options.skipFormat) {\n await formatFiles(tree);\n }\n\n return createSuccessCallback(installTask, hasExistingEslintConfig);\n}\n\nfunction registerPlugin(tree: Tree): void {\n const nxJson = readNxJson(tree);\n if (!nxJson) {\n throw new Error('Could not read nx.json. Are you in an Nx workspace?');\n }\n\n if (!nxJson.plugins) {\n nxJson.plugins = [];\n }\n\n const pluginName = '@webpieces/dev-config';\n const alreadyRegistered = nxJson.plugins.some(\n (p) => typeof p === 'string' ? p === pluginName : p.plugin === pluginName\n );\n\n if (!alreadyRegistered) {\n // Register plugin with default options for method size validation\n nxJson.plugins.push({\n plugin: pluginName,\n options: {\n workspace: {\n validations: {\n newMethodsMaxLines: 30,\n modifiedAndNewMethodsMaxLines: 80,\n },\n },\n },\n });\n updateNxJson(tree, nxJson);\n console.log(`✅ Registered ${pluginName} plugin in nx.json with default options`);\n } else {\n console.log(`ℹ️ ${pluginName} plugin is already registered`);\n }\n}\n\nfunction addTargetDefaults(tree: Tree): void {\n const nxJson = readNxJson(tree);\n if (!nxJson) {\n throw new Error('Could not read nx.json. Are you in an Nx workspace?');\n }\n\n if (!nxJson.targetDefaults) {\n nxJson.targetDefaults = {};\n }\n\n // Find which executors are actually used in this workspace\n const usedExecutors = findUsedExecutors(tree);\n\n // Only add targetDefaults for executors that are actually used\n let updated = false;\n\n usedExecutors.forEach((executor) => {\n if (!nxJson.targetDefaults![executor]) {\n nxJson.targetDefaults![executor] = {};\n }\n\n const targetDef = nxJson.targetDefaults![executor];\n let dependsOn = targetDef.dependsOn || [];\n\n // Ensure dependsOn is an array\n if (!Array.isArray(dependsOn)) {\n dependsOn = [dependsOn];\n }\n\n // Check if architecture validation is already in dependsOn\n const hasArchValidation = dependsOn.some((dep) => {\n if (typeof dep === 'string') {\n return dep === 'architecture:validate-complete';\n }\n return dep.target === 'architecture:validate-complete';\n });\n\n // Check if circular deps validation is already in dependsOn\n const hasCircularDepsValidation = dependsOn.some((dep) => {\n if (typeof dep === 'string') {\n return dep === 'validate-no-file-import-cycles';\n }\n return dep.target === 'validate-no-file-import-cycles';\n });\n\n if (!hasCircularDepsValidation) {\n // Add circular deps validation (per-project check)\n dependsOn.unshift('validate-no-file-import-cycles');\n targetDef.dependsOn = dependsOn;\n updated = true;\n console.log(` ✅ Added circular deps validation to ${executor}`);\n }\n\n if (!hasArchValidation) {\n // Add architecture validation before other dependencies\n dependsOn.unshift('architecture:validate-complete');\n targetDef.dependsOn = dependsOn;\n updated = true;\n console.log(` ✅ Added architecture validation to ${executor}`);\n }\n });\n\n if (updated) {\n updateNxJson(tree, nxJson);\n console.log('✅ Added architecture validation to targetDefaults for used executors');\n } else {\n console.log('ℹ️ Architecture validation already configured in targetDefaults');\n }\n}\n\n/**\n * Scan all project.json files to find which build executors are actually used\n */\nfunction findUsedExecutors(tree: Tree): Set<string> {\n const usedExecutors = new Set<string>();\n\n // Known build executors we care about\n const buildExecutors = new Set([\n '@nx/js:tsc',\n '@nx/esbuild:esbuild',\n '@nx/webpack:webpack',\n '@nx/rollup:rollup',\n '@nx/vite:build',\n '@angular/build:application',\n '@angular-devkit/build-angular:browser',\n '@angular-devkit/build-angular:application'\n ]);\n\n // Scan all project.json files\n tree.listChanges(); // Force tree to be aware of all files\n\n const scanDir = (dir: string) => {\n for (const child of tree.children(dir)) {\n const childPath = dir === '.' ? child : `${dir}/${child}`;\n\n if (tree.isFile(childPath)) {\n if (child === 'project.json') {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- Intentionally ignoring JSON parse errors for malformed project.json files\n try {\n const content = tree.read(childPath, 'utf-8');\n if (content) {\n const projectJson = JSON.parse(content);\n if (projectJson.targets) {\n for (const target of Object.values(projectJson.targets)) {\n const executor = (target as { executor?: string })?.executor;\n if (executor && buildExecutors.has(executor)) {\n usedExecutors.add(executor);\n }\n }\n }\n }\n } catch (err: any) {\n //const error = toError(err);\n }\n }\n } else {\n // Skip node_modules and dist\n if (child !== 'node_modules' && child !== 'dist' && child !== '.git') {\n scanDir(childPath);\n }\n }\n }\n };\n\n scanDir('.');\n\n console.log(`ℹ️ Found ${usedExecutors.size} build executors in use: ${[...usedExecutors].join(', ')}`);\n\n return usedExecutors;\n}\n\nfunction addMadgeDependency(tree: Tree) {\n return addDependenciesToPackageJson(tree, {}, { 'madge': '^8.0.0' });\n}\n\nfunction createArchitectureDirectory(tree: Tree): void {\n if (!tree.exists('architecture')) {\n tree.write('architecture/.gitkeep', '');\n console.log('✅ Created architecture/ directory');\n }\n}\n\nfunction addNpmScripts(tree: Tree): void {\n updateJson(tree, 'package.json', (pkgJson) => {\n pkgJson.scripts = pkgJson.scripts ?? {};\n\n // Add architecture validation scripts\n pkgJson.scripts['arch:generate'] = 'nx run architecture:generate';\n pkgJson.scripts['arch:visualize'] = 'nx run architecture:visualize';\n pkgJson.scripts['arch:validate'] = 'nx run architecture:validate-no-architecture-cycles && nx run architecture:validate-no-skiplevel-deps';\n pkgJson.scripts['arch:validate-all'] = 'nx run architecture:validate-no-architecture-cycles && nx run architecture:validate-no-skiplevel-deps && nx run architecture:validate-architecture-unchanged';\n\n // Add file import cycle checking scripts\n pkgJson.scripts['arch:check-circular'] = 'nx run-many --target=validate-no-file-import-cycles --all';\n pkgJson.scripts['arch:check-circular-affected'] = 'nx affected --target=validate-no-file-import-cycles';\n\n // Complete validation including circular deps\n pkgJson.scripts['arch:validate-complete'] = 'npm run arch:validate-all && npm run arch:check-circular';\n\n // Add CI script that runs lint, build, test on affected projects\n pkgJson.scripts['webpieces:ci'] = 'npx nx affected --target=ci';\n\n return pkgJson;\n });\n\n console.log('✅ Added npm scripts for architecture validation, circular dependency checking, and CI');\n}\n\nfunction createEslintConfig(tree: Tree): boolean {\n const webpiecesConfigPath = 'eslint.webpieces.config.mjs';\n const mainConfigPath = 'eslint.config.mjs';\n\n // Always create eslint.webpieces.config.mjs with our rules\n createWebpiecesEslintConfig(tree, webpiecesConfigPath);\n\n // Check if main eslint.config.mjs exists\n const hasExistingConfig = tree.exists(mainConfigPath);\n\n if (!hasExistingConfig) {\n // No existing config - create one that imports webpieces config\n const mainConfig = `// ESLint configuration\n// Imports @webpieces/dev-config rules\n\nimport webpiecesConfig from './eslint.webpieces.config.mjs';\n\n// Export the webpieces configuration\n// You can add your own rules after spreading webpiecesConfig\nexport default [\n ...webpiecesConfig,\n // Add your custom ESLint configuration here\n];\n`;\n\n tree.write(mainConfigPath, mainConfig);\n console.log('✅ Created eslint.config.mjs with @webpieces/dev-config rules');\n }\n\n return hasExistingConfig;\n}\n\nfunction getWebpiecesEslintConfigTemplate(tree: Tree): string {\n // Read from canonical template file (single source of truth)\n const templatePath = 'node_modules/@webpieces/dev-config/templates/eslint.webpieces.config.mjs';\n const template = tree.read(templatePath, 'utf-8');\n\n if (!template) {\n throw new Error(`Could not read ESLint template from ${templatePath}`);\n }\n\n return template;\n}\n\nfunction warnConfigChanges(tree: Tree, configPath: string, newConfig: string): void {\n const version = getPackageVersion(tree);\n const versionedFilename = `${configPath}.v${version}`;\n\n tree.write(versionedFilename, newConfig);\n\n console.log('');\n console.log(`⚠️ ${configPath} has changes`);\n console.log('');\n console.log(' Either you modified the file OR @webpieces/dev-config has updates.');\n console.log('');\n console.log(` Created: ${versionedFilename} with latest version`);\n console.log('');\n console.log(' Please review and merge if needed:');\n console.log(` - Your current: ${configPath}`);\n console.log(` - New version: ${versionedFilename}`);\n console.log('');\n}\n\nfunction createWebpiecesEslintConfig(tree: Tree, configPath: string): void {\n const webpiecesConfig = getWebpiecesEslintConfigTemplate(tree);\n\n if (!tree.exists(configPath)) {\n tree.write(configPath, webpiecesConfig);\n console.log(`✅ Created ${configPath}`);\n return;\n }\n\n const currentContent = tree.read(configPath, 'utf-8');\n if (!currentContent) {\n tree.write(configPath, webpiecesConfig);\n console.log(`✅ Created ${configPath}`);\n return;\n }\n\n const currentHash = calculateHash(currentContent);\n const newHash = calculateHash(webpiecesConfig);\n\n if (currentHash === newHash) {\n console.log(`✅ ${configPath} is up to date`);\n return;\n }\n\n warnConfigChanges(tree, configPath, webpiecesConfig);\n}\n\nfunction createSuccessCallback(\n installTask: ReturnType<typeof addDependenciesToPackageJson>,\n hasExistingEslintConfig: boolean\n) {\n return async () => {\n await installTask();\n\n // ANSI color codes for formatted output\n const GREEN = '\\x1b[32m\\x1b[1m';\n const BOLD = '\\x1b[1m';\n const RESET = '\\x1b[0m';\n\n console.log('');\n console.log('✅ Added madge to devDependencies');\n console.log('');\n console.log(`${GREEN}✅ @webpieces/dev-config plugin initialized!${RESET}`);\n console.log('');\n console.log(`${GREEN}💡 Quick start:${RESET}`);\n console.log(` ${BOLD}npm run arch:generate${RESET} # Generate the dependency graph`);\n console.log(` ${BOLD}npm run arch:validate-complete${RESET} # Run complete validation`);\n console.log('');\n console.log(`💡 For full documentation, run: ${BOLD}nx run architecture:help${RESET}`);\n\n // Show ESLint integration instructions if they have an existing config\n if (hasExistingEslintConfig) {\n console.log('');\n console.log('📋 Existing eslint.config.mjs detected');\n console.log('');\n console.log('To use @webpieces/dev-config ESLint rules, add this import to your eslint.config.mjs:');\n console.log('');\n console.log(' import webpiecesConfig from \\'./eslint.webpieces.config.mjs\\';');\n console.log('');\n console.log('Then spread it into your config array:');\n console.log('');\n console.log(' export default [');\n console.log(' ...webpiecesConfig, // Add this line');\n console.log(' // ... your existing config');\n console.log(' ];');\n }\n\n console.log('');\n };\n}\n"]}
|
|
@@ -21,8 +21,8 @@ export default [
|
|
|
21
21
|
rules: {
|
|
22
22
|
'@webpieces/catch-error-pattern': 'error',
|
|
23
23
|
'@webpieces/no-unmanaged-exceptions': 'error',
|
|
24
|
-
'@webpieces/max-method-lines': ['error', { max: 70 }],
|
|
25
|
-
'@webpieces/max-file-lines': ['error', { max: 700 }],
|
|
24
|
+
// '@webpieces/max-method-lines': ['error', { max: 70 }],
|
|
25
|
+
// '@webpieces/max-file-lines': ['error', { max: 700 }],
|
|
26
26
|
'@webpieces/enforce-architecture': 'error',
|
|
27
27
|
},
|
|
28
28
|
},
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Validate Versions Executor
|
|
3
|
-
*
|
|
4
|
-
* Validates package.json versions and checks npm ci compatibility.
|
|
5
|
-
* This catches peer dependency conflicts that npm ci catches but npm install doesn't.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* nx run dev-config:validate-versions
|
|
9
|
-
*/
|
|
10
|
-
import type { ExecutorContext } from '@nx/devkit';
|
|
11
|
-
export interface ValidateVersionsOptions {
|
|
12
|
-
}
|
|
13
|
-
export interface ExecutorResult {
|
|
14
|
-
success: boolean;
|
|
15
|
-
}
|
|
16
|
-
export default function runExecutor(_options: ValidateVersionsOptions, context: ExecutorContext): Promise<ExecutorResult>;
|