@webpieces/dev-config 0.2.25 â 0.2.27
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/executors/help/executor.d.ts +6 -0
- package/executors/help/executor.js +45 -0
- package/executors/help/executor.js.map +1 -0
- package/executors/help/executor.ts +50 -0
- package/executors/help/schema.json +7 -0
- package/executors/validate-eslint-sync/executor.d.ts +6 -0
- package/executors/validate-eslint-sync/executor.js +69 -0
- package/executors/validate-eslint-sync/executor.js.map +1 -0
- package/executors/validate-eslint-sync/executor.ts +83 -0
- package/executors/validate-eslint-sync/schema.json +7 -0
- package/executors.json +10 -0
- package/package.json +3 -1
- package/src/generators/init/generator.js +68 -93
- package/src/generators/init/generator.js.map +1 -1
- package/templates/eslint.webpieces.config.mjs +29 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = helpExecutor;
|
|
4
|
+
async function helpExecutor(options, context) {
|
|
5
|
+
// ANSI color codes
|
|
6
|
+
const GREEN = '\x1b[32m\x1b[1m';
|
|
7
|
+
const BOLD = '\x1b[1m';
|
|
8
|
+
const RESET = '\x1b[0m';
|
|
9
|
+
console.log('');
|
|
10
|
+
console.log(`${GREEN}đĄ @webpieces/dev-config - Available Commands${RESET}`);
|
|
11
|
+
console.log('');
|
|
12
|
+
console.log(`${BOLD}đ Available npm scripts (convenient shortcuts):${RESET}`);
|
|
13
|
+
console.log('');
|
|
14
|
+
console.log(' Architecture graph:');
|
|
15
|
+
console.log(' npm run arch:generate # Generate dependency graph');
|
|
16
|
+
console.log(' npm run arch:visualize # Visualize dependency graph');
|
|
17
|
+
console.log('');
|
|
18
|
+
console.log(' Validation:');
|
|
19
|
+
console.log(' npm run arch:validate # Quick validation (no-cycles + no-skiplevel-deps)');
|
|
20
|
+
console.log(' npm run arch:validate-all # Full arch validation (+ unchanged check)');
|
|
21
|
+
console.log(' npm run arch:check-circular # Check all projects for circular deps');
|
|
22
|
+
console.log(' npm run arch:check-circular-affected # Check affected projects only');
|
|
23
|
+
console.log(' npm run arch:validate-complete # Complete validation (arch + circular)');
|
|
24
|
+
console.log('');
|
|
25
|
+
console.log(`${BOLD}đ Available Nx targets:${RESET}`);
|
|
26
|
+
console.log('');
|
|
27
|
+
console.log(' Workspace-level architecture validation:');
|
|
28
|
+
console.log(' nx run .:arch:generate # Generate dependency graph');
|
|
29
|
+
console.log(' nx run .:arch:visualize # Visualize dependency graph');
|
|
30
|
+
console.log(' nx run .:arch:validate-no-cycles # Check for circular dependencies');
|
|
31
|
+
console.log(' nx run .:arch:validate-no-skiplevel-deps # Check for redundant dependencies');
|
|
32
|
+
console.log(' nx run .:arch:validate-architecture-unchanged # Validate against blessed graph');
|
|
33
|
+
console.log('');
|
|
34
|
+
console.log(' Per-project circular dependency checking:');
|
|
35
|
+
console.log(' nx run <project>:check-circular-deps # Check project for circular deps');
|
|
36
|
+
console.log(' nx affected --target=check-circular-deps # Check all affected projects');
|
|
37
|
+
console.log(' nx run-many --target=check-circular-deps --all # Check all projects');
|
|
38
|
+
console.log('');
|
|
39
|
+
console.log(`${GREEN}đĄ Quick start:${RESET}`);
|
|
40
|
+
console.log(` ${BOLD}npm run arch:generate${RESET} # Generate the graph first`);
|
|
41
|
+
console.log(` ${BOLD}npm run arch:validate-complete${RESET} # Run complete validation`);
|
|
42
|
+
console.log('');
|
|
43
|
+
return { success: true };
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../packages/tooling/dev-config/executors/help/executor.ts"],"names":[],"mappings":";;AAIA,+BA6CC;AA7Cc,KAAK,UAAU,YAAY,CACtC,OAA4B,EAC5B,OAAwB;IAExB,mBAAmB;IACnB,MAAM,KAAK,GAAG,iBAAiB,CAAC;IAChC,MAAM,IAAI,GAAG,SAAS,CAAC;IACvB,MAAM,KAAK,GAAG,SAAS,CAAC;IAExB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,gDAAgD,KAAK,EAAE,CAAC,CAAC;IAC7E,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,mDAAmD,KAAK,EAAE,CAAC,CAAC;IAC/E,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,wEAAwE,CAAC,CAAC;IACtF,OAAO,CAAC,GAAG,CAAC,yEAAyE,CAAC,CAAC;IACvF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAC7B,OAAO,CAAC,GAAG,CAAC,+FAA+F,CAAC,CAAC;IAC7G,OAAO,CAAC,GAAG,CAAC,uFAAuF,CAAC,CAAC;IACrG,OAAO,CAAC,GAAG,CAAC,mFAAmF,CAAC,CAAC;IACjG,OAAO,CAAC,GAAG,CAAC,2EAA2E,CAAC,CAAC;IACzF,OAAO,CAAC,GAAG,CAAC,oFAAoF,CAAC,CAAC;IAClG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,2BAA2B,KAAK,EAAE,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;IAC1D,OAAO,CAAC,GAAG,CAAC,gFAAgF,CAAC,CAAC;IAC9F,OAAO,CAAC,GAAG,CAAC,iFAAiF,CAAC,CAAC;IAC/F,OAAO,CAAC,GAAG,CAAC,sFAAsF,CAAC,CAAC;IACpG,OAAO,CAAC,GAAG,CAAC,uFAAuF,CAAC,CAAC;IACrG,OAAO,CAAC,GAAG,CAAC,qFAAqF,CAAC,CAAC;IACnG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;IAC3D,OAAO,CAAC,GAAG,CAAC,sFAAsF,CAAC,CAAC;IACpG,OAAO,CAAC,GAAG,CAAC,kFAAkF,CAAC,CAAC;IAChG,OAAO,CAAC,GAAG,CAAC,yEAAyE,CAAC,CAAC;IACvF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,kBAAkB,KAAK,EAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,wBAAwB,KAAK,uCAAuC,CAAC,CAAC;IAC5F,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,iCAAiC,KAAK,6BAA6B,CAAC,CAAC;IAC3F,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC7B,CAAC","sourcesContent":["import type { ExecutorContext } from '@nx/devkit';\n\nexport interface HelpExecutorOptions {}\n\nexport default async function helpExecutor(\n options: HelpExecutorOptions,\n context: ExecutorContext\n): Promise<{ success: true }> {\n // ANSI color codes\n const GREEN = '\\x1b[32m\\x1b[1m';\n const BOLD = '\\x1b[1m';\n const RESET = '\\x1b[0m';\n\n console.log('');\n console.log(`${GREEN}đĄ @webpieces/dev-config - Available Commands${RESET}`);\n console.log('');\n console.log(`${BOLD}đ Available npm scripts (convenient shortcuts):${RESET}`);\n console.log('');\n console.log(' Architecture graph:');\n console.log(' npm run arch:generate # Generate dependency graph');\n console.log(' npm run arch:visualize # Visualize dependency graph');\n console.log('');\n console.log(' Validation:');\n console.log(' npm run arch:validate # Quick validation (no-cycles + no-skiplevel-deps)');\n console.log(' npm run arch:validate-all # Full arch validation (+ unchanged check)');\n console.log(' npm run arch:check-circular # Check all projects for circular deps');\n console.log(' npm run arch:check-circular-affected # Check affected projects only');\n console.log(' npm run arch:validate-complete # Complete validation (arch + circular)');\n console.log('');\n console.log(`${BOLD}đ Available Nx targets:${RESET}`);\n console.log('');\n console.log(' Workspace-level architecture validation:');\n console.log(' nx run .:arch:generate # Generate dependency graph');\n console.log(' nx run .:arch:visualize # Visualize dependency graph');\n console.log(' nx run .:arch:validate-no-cycles # Check for circular dependencies');\n console.log(' nx run .:arch:validate-no-skiplevel-deps # Check for redundant dependencies');\n console.log(' nx run .:arch:validate-architecture-unchanged # Validate against blessed graph');\n console.log('');\n console.log(' Per-project circular dependency checking:');\n console.log(' nx run <project>:check-circular-deps # Check project for circular deps');\n console.log(' nx affected --target=check-circular-deps # Check all affected projects');\n console.log(' nx run-many --target=check-circular-deps --all # Check all projects');\n console.log('');\n console.log(`${GREEN}đĄ Quick start:${RESET}`);\n console.log(` ${BOLD}npm run arch:generate${RESET} # Generate the graph first`);\n console.log(` ${BOLD}npm run arch:validate-complete${RESET} # Run complete validation`);\n console.log('');\n\n return { success: true };\n}\n"]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ExecutorContext } from '@nx/devkit';
|
|
2
|
+
|
|
3
|
+
export interface HelpExecutorOptions {}
|
|
4
|
+
|
|
5
|
+
export default async function helpExecutor(
|
|
6
|
+
options: HelpExecutorOptions,
|
|
7
|
+
context: ExecutorContext
|
|
8
|
+
): Promise<{ success: true }> {
|
|
9
|
+
// ANSI color codes
|
|
10
|
+
const GREEN = '\x1b[32m\x1b[1m';
|
|
11
|
+
const BOLD = '\x1b[1m';
|
|
12
|
+
const RESET = '\x1b[0m';
|
|
13
|
+
|
|
14
|
+
console.log('');
|
|
15
|
+
console.log(`${GREEN}đĄ @webpieces/dev-config - Available Commands${RESET}`);
|
|
16
|
+
console.log('');
|
|
17
|
+
console.log(`${BOLD}đ Available npm scripts (convenient shortcuts):${RESET}`);
|
|
18
|
+
console.log('');
|
|
19
|
+
console.log(' Architecture graph:');
|
|
20
|
+
console.log(' npm run arch:generate # Generate dependency graph');
|
|
21
|
+
console.log(' npm run arch:visualize # Visualize dependency graph');
|
|
22
|
+
console.log('');
|
|
23
|
+
console.log(' Validation:');
|
|
24
|
+
console.log(' npm run arch:validate # Quick validation (no-cycles + no-skiplevel-deps)');
|
|
25
|
+
console.log(' npm run arch:validate-all # Full arch validation (+ unchanged check)');
|
|
26
|
+
console.log(' npm run arch:check-circular # Check all projects for circular deps');
|
|
27
|
+
console.log(' npm run arch:check-circular-affected # Check affected projects only');
|
|
28
|
+
console.log(' npm run arch:validate-complete # Complete validation (arch + circular)');
|
|
29
|
+
console.log('');
|
|
30
|
+
console.log(`${BOLD}đ Available Nx targets:${RESET}`);
|
|
31
|
+
console.log('');
|
|
32
|
+
console.log(' Workspace-level architecture validation:');
|
|
33
|
+
console.log(' nx run .:arch:generate # Generate dependency graph');
|
|
34
|
+
console.log(' nx run .:arch:visualize # Visualize dependency graph');
|
|
35
|
+
console.log(' nx run .:arch:validate-no-cycles # Check for circular dependencies');
|
|
36
|
+
console.log(' nx run .:arch:validate-no-skiplevel-deps # Check for redundant dependencies');
|
|
37
|
+
console.log(' nx run .:arch:validate-architecture-unchanged # Validate against blessed graph');
|
|
38
|
+
console.log('');
|
|
39
|
+
console.log(' Per-project circular dependency checking:');
|
|
40
|
+
console.log(' nx run <project>:check-circular-deps # Check project for circular deps');
|
|
41
|
+
console.log(' nx affected --target=check-circular-deps # Check all affected projects');
|
|
42
|
+
console.log(' nx run-many --target=check-circular-deps --all # Check all projects');
|
|
43
|
+
console.log('');
|
|
44
|
+
console.log(`${GREEN}đĄ Quick start:${RESET}`);
|
|
45
|
+
console.log(` ${BOLD}npm run arch:generate${RESET} # Generate the graph first`);
|
|
46
|
+
console.log(` ${BOLD}npm run arch:validate-complete${RESET} # Run complete validation`);
|
|
47
|
+
console.log('');
|
|
48
|
+
|
|
49
|
+
return { success: true };
|
|
50
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = validateEslintSyncExecutor;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
const crypto_1 = require("crypto");
|
|
7
|
+
function calculateHash(content) {
|
|
8
|
+
return (0, crypto_1.createHash)('sha256').update(content).digest('hex');
|
|
9
|
+
}
|
|
10
|
+
function normalizeContent(content) {
|
|
11
|
+
// Normalize line endings and trim whitespace
|
|
12
|
+
return content.replace(/\r\n/g, '\n').trim();
|
|
13
|
+
}
|
|
14
|
+
async function validateEslintSyncExecutor(options, context) {
|
|
15
|
+
const workspaceRoot = context.root;
|
|
16
|
+
const templatePath = (0, path_1.join)(workspaceRoot, 'packages/tooling/dev-config/templates/eslint.webpieces.config.mjs');
|
|
17
|
+
const workspacePath = (0, path_1.join)(workspaceRoot, 'eslint.webpieces.config.mjs');
|
|
18
|
+
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
19
|
+
try {
|
|
20
|
+
const templateContent = (0, fs_1.readFileSync)(templatePath, 'utf-8');
|
|
21
|
+
const workspaceContent = (0, fs_1.readFileSync)(workspacePath, 'utf-8');
|
|
22
|
+
const templateRules = extractRulesSection(templateContent);
|
|
23
|
+
const workspaceRules = extractRulesSection(workspaceContent);
|
|
24
|
+
const templateHash = calculateHash(normalizeContent(templateRules));
|
|
25
|
+
const workspaceHash = calculateHash(normalizeContent(workspaceRules));
|
|
26
|
+
if (templateHash !== workspaceHash) {
|
|
27
|
+
printValidationError(templatePath, workspacePath);
|
|
28
|
+
return { success: false };
|
|
29
|
+
}
|
|
30
|
+
console.log('â
ESLint configuration sync validated - rules match!');
|
|
31
|
+
return { success: true };
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
// Error occurred during validation - log and fail
|
|
35
|
+
// eslint-disable-next-line @webpieces/catch-error-pattern
|
|
36
|
+
console.error('â Error validating ESLint sync:', err);
|
|
37
|
+
return { success: false };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function printValidationError(templatePath, workspacePath) {
|
|
41
|
+
console.error('');
|
|
42
|
+
console.error('â ESLint configuration sync validation FAILED');
|
|
43
|
+
console.error('');
|
|
44
|
+
console.error('The @webpieces ESLint rules must be identical in both files:');
|
|
45
|
+
console.error(` 1. ${templatePath}`);
|
|
46
|
+
console.error(` 2. ${workspacePath}`);
|
|
47
|
+
console.error('');
|
|
48
|
+
console.error('These files must have identical rules sections so that:');
|
|
49
|
+
console.error(' - External clients get the same rules we use internally');
|
|
50
|
+
console.error(' - We "eat our own dog food" - same rules for everyone');
|
|
51
|
+
console.error('');
|
|
52
|
+
console.error('To fix:');
|
|
53
|
+
console.error(' 1. Modify the rules in ONE file (recommend: templates/eslint.webpieces.config.mjs)');
|
|
54
|
+
console.error(' 2. Copy the rules section to the other file');
|
|
55
|
+
console.error(' 3. Keep import statements different (template uses npm, workspace uses loadWorkspaceRules)');
|
|
56
|
+
console.error('');
|
|
57
|
+
console.error('Customization for webpieces workspace goes in: eslint.config.mjs');
|
|
58
|
+
console.error('');
|
|
59
|
+
}
|
|
60
|
+
function extractRulesSection(content) {
|
|
61
|
+
// Extract everything between "export default [" and the final "];"
|
|
62
|
+
// This includes the rules configuration
|
|
63
|
+
const match = content.match(/export default \[([\s\S]*)\];/);
|
|
64
|
+
if (!match) {
|
|
65
|
+
throw new Error('Could not extract rules section - export default not found');
|
|
66
|
+
}
|
|
67
|
+
return match[1].trim();
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../packages/tooling/dev-config/executors/validate-eslint-sync/executor.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExecutorContext } from '@nx/devkit';\nimport { readFileSync } from 'fs';\nimport { join } from 'path';\nimport { createHash } from 'crypto';\n\nexport interface ValidateEslintSyncOptions {}\n\nfunction calculateHash(content: string): string {\n return createHash('sha256').update(content).digest('hex');\n}\n\nfunction normalizeContent(content: string): string {\n // Normalize line endings and trim whitespace\n return content.replace(/\\r\\n/g, '\\n').trim();\n}\n\nexport default async function validateEslintSyncExecutor(\n options: ValidateEslintSyncOptions,\n context: ExecutorContext\n): Promise<{ success: boolean }> {\n const workspaceRoot = context.root;\n\n const templatePath = join(workspaceRoot, 'packages/tooling/dev-config/templates/eslint.webpieces.config.mjs');\n const workspacePath = join(workspaceRoot, 'eslint.webpieces.config.mjs');\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const templateContent = readFileSync(templatePath, 'utf-8');\n const workspaceContent = readFileSync(workspacePath, 'utf-8');\n\n const templateRules = extractRulesSection(templateContent);\n const workspaceRules = extractRulesSection(workspaceContent);\n\n const templateHash = calculateHash(normalizeContent(templateRules));\n const workspaceHash = calculateHash(normalizeContent(workspaceRules));\n\n if (templateHash !== workspaceHash) {\n printValidationError(templatePath, workspacePath);\n return { success: false };\n }\n\n console.log('â
ESLint configuration sync validated - rules match!');\n return { success: true };\n\n } catch (err: any) {\n // Error occurred during validation - log and fail\n // eslint-disable-next-line @webpieces/catch-error-pattern\n console.error('â Error validating ESLint sync:', err);\n return { success: false };\n }\n}\n\nfunction printValidationError(templatePath: string, workspacePath: string): void {\n console.error('');\n console.error('â ESLint configuration sync validation FAILED');\n console.error('');\n console.error('The @webpieces ESLint rules must be identical in both files:');\n console.error(` 1. ${templatePath}`);\n console.error(` 2. ${workspacePath}`);\n console.error('');\n console.error('These files must have identical rules sections so that:');\n console.error(' - External clients get the same rules we use internally');\n console.error(' - We \"eat our own dog food\" - same rules for everyone');\n console.error('');\n console.error('To fix:');\n console.error(' 1. Modify the rules in ONE file (recommend: templates/eslint.webpieces.config.mjs)');\n console.error(' 2. Copy the rules section to the other file');\n console.error(' 3. Keep import statements different (template uses npm, workspace uses loadWorkspaceRules)');\n console.error('');\n console.error('Customization for webpieces workspace goes in: eslint.config.mjs');\n console.error('');\n}\n\nfunction extractRulesSection(content: string): string {\n // Extract everything between \"export default [\" and the final \"];\"\n // This includes the rules configuration\n const match = content.match(/export default \\[([\\s\\S]*)\\];/);\n if (!match) {\n throw new Error('Could not extract rules section - export default not found');\n }\n\n return match[1].trim();\n}\n"]}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { ExecutorContext } from '@nx/devkit';
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { createHash } from 'crypto';
|
|
5
|
+
|
|
6
|
+
export interface ValidateEslintSyncOptions {}
|
|
7
|
+
|
|
8
|
+
function calculateHash(content: string): string {
|
|
9
|
+
return createHash('sha256').update(content).digest('hex');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function normalizeContent(content: string): string {
|
|
13
|
+
// Normalize line endings and trim whitespace
|
|
14
|
+
return content.replace(/\r\n/g, '\n').trim();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default async function validateEslintSyncExecutor(
|
|
18
|
+
options: ValidateEslintSyncOptions,
|
|
19
|
+
context: ExecutorContext
|
|
20
|
+
): Promise<{ success: boolean }> {
|
|
21
|
+
const workspaceRoot = context.root;
|
|
22
|
+
|
|
23
|
+
const templatePath = join(workspaceRoot, 'packages/tooling/dev-config/templates/eslint.webpieces.config.mjs');
|
|
24
|
+
const workspacePath = join(workspaceRoot, 'eslint.webpieces.config.mjs');
|
|
25
|
+
|
|
26
|
+
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
27
|
+
try {
|
|
28
|
+
const templateContent = readFileSync(templatePath, 'utf-8');
|
|
29
|
+
const workspaceContent = readFileSync(workspacePath, 'utf-8');
|
|
30
|
+
|
|
31
|
+
const templateRules = extractRulesSection(templateContent);
|
|
32
|
+
const workspaceRules = extractRulesSection(workspaceContent);
|
|
33
|
+
|
|
34
|
+
const templateHash = calculateHash(normalizeContent(templateRules));
|
|
35
|
+
const workspaceHash = calculateHash(normalizeContent(workspaceRules));
|
|
36
|
+
|
|
37
|
+
if (templateHash !== workspaceHash) {
|
|
38
|
+
printValidationError(templatePath, workspacePath);
|
|
39
|
+
return { success: false };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
console.log('â
ESLint configuration sync validated - rules match!');
|
|
43
|
+
return { success: true };
|
|
44
|
+
|
|
45
|
+
} catch (err: any) {
|
|
46
|
+
// Error occurred during validation - log and fail
|
|
47
|
+
// eslint-disable-next-line @webpieces/catch-error-pattern
|
|
48
|
+
console.error('â Error validating ESLint sync:', err);
|
|
49
|
+
return { success: false };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function printValidationError(templatePath: string, workspacePath: string): void {
|
|
54
|
+
console.error('');
|
|
55
|
+
console.error('â ESLint configuration sync validation FAILED');
|
|
56
|
+
console.error('');
|
|
57
|
+
console.error('The @webpieces ESLint rules must be identical in both files:');
|
|
58
|
+
console.error(` 1. ${templatePath}`);
|
|
59
|
+
console.error(` 2. ${workspacePath}`);
|
|
60
|
+
console.error('');
|
|
61
|
+
console.error('These files must have identical rules sections so that:');
|
|
62
|
+
console.error(' - External clients get the same rules we use internally');
|
|
63
|
+
console.error(' - We "eat our own dog food" - same rules for everyone');
|
|
64
|
+
console.error('');
|
|
65
|
+
console.error('To fix:');
|
|
66
|
+
console.error(' 1. Modify the rules in ONE file (recommend: templates/eslint.webpieces.config.mjs)');
|
|
67
|
+
console.error(' 2. Copy the rules section to the other file');
|
|
68
|
+
console.error(' 3. Keep import statements different (template uses npm, workspace uses loadWorkspaceRules)');
|
|
69
|
+
console.error('');
|
|
70
|
+
console.error('Customization for webpieces workspace goes in: eslint.config.mjs');
|
|
71
|
+
console.error('');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function extractRulesSection(content: string): string {
|
|
75
|
+
// Extract everything between "export default [" and the final "];"
|
|
76
|
+
// This includes the rules configuration
|
|
77
|
+
const match = content.match(/export default \[([\s\S]*)\];/);
|
|
78
|
+
if (!match) {
|
|
79
|
+
throw new Error('Could not extract rules section - export default not found');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return match[1].trim();
|
|
83
|
+
}
|
package/executors.json
CHANGED
|
@@ -24,6 +24,16 @@
|
|
|
24
24
|
"implementation": "./architecture/executors/validate-no-skiplevel-deps/executor",
|
|
25
25
|
"schema": "./architecture/executors/validate-no-skiplevel-deps/schema.json",
|
|
26
26
|
"description": "Validate no project has redundant transitive dependencies"
|
|
27
|
+
},
|
|
28
|
+
"help": {
|
|
29
|
+
"implementation": "./executors/help/executor",
|
|
30
|
+
"schema": "./executors/help/schema.json",
|
|
31
|
+
"description": "Display help for @webpieces/dev-config commands and targets"
|
|
32
|
+
},
|
|
33
|
+
"validate-eslint-sync": {
|
|
34
|
+
"implementation": "./executors/validate-eslint-sync/executor",
|
|
35
|
+
"schema": "./executors/validate-eslint-sync/schema.json",
|
|
36
|
+
"description": "Validate that workspace and template eslint.webpieces.config.mjs files have identical rules"
|
|
27
37
|
}
|
|
28
38
|
}
|
|
29
39
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/dev-config",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.27",
|
|
4
4
|
"description": "Development configuration, scripts, and patterns for WebPieces projects",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"bin": {
|
|
@@ -34,6 +34,8 @@
|
|
|
34
34
|
"plugins/**/*",
|
|
35
35
|
"plugin/**/*",
|
|
36
36
|
"plugin.js",
|
|
37
|
+
"templates/**/*",
|
|
38
|
+
"executors/**/*",
|
|
37
39
|
"src/**/*",
|
|
38
40
|
"generators.json",
|
|
39
41
|
"architecture/**/*",
|
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = initGenerator;
|
|
4
4
|
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
const crypto_1 = require("crypto");
|
|
6
|
+
function calculateHash(content) {
|
|
7
|
+
return (0, crypto_1.createHash)('sha256').update(content).digest('hex');
|
|
8
|
+
}
|
|
9
|
+
function getPackageVersion(tree) {
|
|
10
|
+
const content = tree.read('node_modules/@webpieces/dev-config/package.json', 'utf-8');
|
|
11
|
+
if (!content) {
|
|
12
|
+
throw new Error('Could not read package.json from node_modules/@webpieces/dev-config');
|
|
13
|
+
}
|
|
14
|
+
const pkgJson = JSON.parse(content);
|
|
15
|
+
return pkgJson.version;
|
|
16
|
+
}
|
|
5
17
|
/**
|
|
6
18
|
* Init generator for @webpieces/dev-config
|
|
7
19
|
*
|
|
@@ -114,107 +126,70 @@ export default [
|
|
|
114
126
|
console.log('â
Created eslint.config.mjs with @webpieces/dev-config rules');
|
|
115
127
|
}
|
|
116
128
|
}
|
|
129
|
+
function getWebpiecesEslintConfigTemplate(tree) {
|
|
130
|
+
// Read from canonical template file (single source of truth)
|
|
131
|
+
const templatePath = 'node_modules/@webpieces/dev-config/templates/eslint.webpieces.config.mjs';
|
|
132
|
+
const template = tree.read(templatePath, 'utf-8');
|
|
133
|
+
if (!template) {
|
|
134
|
+
throw new Error(`Could not read ESLint template from ${templatePath}`);
|
|
135
|
+
}
|
|
136
|
+
return template;
|
|
137
|
+
}
|
|
138
|
+
function warnConfigChanges(tree, configPath, newConfig) {
|
|
139
|
+
const version = getPackageVersion(tree);
|
|
140
|
+
const versionedFilename = `${configPath}.v${version}`;
|
|
141
|
+
tree.write(versionedFilename, newConfig);
|
|
142
|
+
console.log('');
|
|
143
|
+
console.log(`â ī¸ ${configPath} has changes`);
|
|
144
|
+
console.log('');
|
|
145
|
+
console.log(' Either you modified the file OR @webpieces/dev-config has updates.');
|
|
146
|
+
console.log('');
|
|
147
|
+
console.log(` Created: ${versionedFilename} with latest version`);
|
|
148
|
+
console.log('');
|
|
149
|
+
console.log(' Please review and merge if needed:');
|
|
150
|
+
console.log(` - Your current: ${configPath}`);
|
|
151
|
+
console.log(` - New version: ${versionedFilename}`);
|
|
152
|
+
console.log('');
|
|
153
|
+
}
|
|
117
154
|
function createWebpiecesEslintConfig(tree, configPath) {
|
|
118
|
-
const webpiecesConfig =
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
parser: tsparser,
|
|
138
|
-
ecmaVersion: 2021,
|
|
139
|
-
sourceType: 'module',
|
|
140
|
-
},
|
|
141
|
-
rules: {
|
|
142
|
-
// WebPieces custom rules
|
|
143
|
-
'@webpieces/catch-error-pattern': 'error',
|
|
144
|
-
'@webpieces/no-unmanaged-exceptions': 'error',
|
|
145
|
-
'@webpieces/max-method-lines': ['error', { max: 70 }],
|
|
146
|
-
'@webpieces/max-file-lines': ['error', { max: 700 }],
|
|
147
|
-
'@webpieces/enforce-architecture': 'error',
|
|
148
|
-
|
|
149
|
-
// TypeScript rules
|
|
150
|
-
'@typescript-eslint/no-explicit-any': 'off',
|
|
151
|
-
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
152
|
-
'@typescript-eslint/no-unused-vars': 'off',
|
|
153
|
-
'@typescript-eslint/no-empty-interface': 'off',
|
|
154
|
-
'@typescript-eslint/no-empty-function': 'off',
|
|
155
|
-
|
|
156
|
-
// General code quality
|
|
157
|
-
'no-console': 'off',
|
|
158
|
-
'no-debugger': 'off',
|
|
159
|
-
'no-var': 'error',
|
|
160
|
-
'prefer-const': 'off',
|
|
161
|
-
},
|
|
162
|
-
},
|
|
163
|
-
{
|
|
164
|
-
// Test files - relaxed rules
|
|
165
|
-
files: ['**/*.spec.ts', '**/*.test.ts'],
|
|
166
|
-
rules: {
|
|
167
|
-
'@typescript-eslint/no-explicit-any': 'off',
|
|
168
|
-
'@typescript-eslint/no-non-null-assertion': 'off',
|
|
169
|
-
'@webpieces/max-method-lines': 'off',
|
|
170
|
-
},
|
|
171
|
-
},
|
|
172
|
-
];
|
|
173
|
-
`;
|
|
174
|
-
tree.write(configPath, webpiecesConfig);
|
|
175
|
-
console.log('â
Created eslint.webpieces.config.mjs with @webpieces/dev-config rules');
|
|
155
|
+
const webpiecesConfig = getWebpiecesEslintConfigTemplate(tree);
|
|
156
|
+
if (!tree.exists(configPath)) {
|
|
157
|
+
tree.write(configPath, webpiecesConfig);
|
|
158
|
+
console.log(`â
Created ${configPath}`);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const currentContent = tree.read(configPath, 'utf-8');
|
|
162
|
+
if (!currentContent) {
|
|
163
|
+
tree.write(configPath, webpiecesConfig);
|
|
164
|
+
console.log(`â
Created ${configPath}`);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const currentHash = calculateHash(currentContent);
|
|
168
|
+
const newHash = calculateHash(webpiecesConfig);
|
|
169
|
+
if (currentHash === newHash) {
|
|
170
|
+
console.log(`â
${configPath} is up to date`);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
warnConfigChanges(tree, configPath, webpiecesConfig);
|
|
176
174
|
}
|
|
177
175
|
function createSuccessCallback(installTask) {
|
|
178
176
|
return async () => {
|
|
179
177
|
await installTask();
|
|
178
|
+
// ANSI color codes for formatted output
|
|
179
|
+
const GREEN = '\x1b[32m\x1b[1m';
|
|
180
|
+
const BOLD = '\x1b[1m';
|
|
181
|
+
const RESET = '\x1b[0m';
|
|
182
|
+
console.log('');
|
|
180
183
|
console.log('â
Added madge to devDependencies');
|
|
181
184
|
console.log('');
|
|
182
|
-
console.log(
|
|
185
|
+
console.log(`${GREEN}â
@webpieces/dev-config plugin initialized!${RESET}`);
|
|
186
|
+
console.log('');
|
|
187
|
+
console.log(`${GREEN}đĄ Quick start:${RESET}`);
|
|
188
|
+
console.log(` ${BOLD}npm run arch:generate${RESET} # Generate the dependency graph`);
|
|
189
|
+
console.log(` ${BOLD}npm run arch:validate-complete${RESET} # Run complete validation`);
|
|
190
|
+
console.log('');
|
|
191
|
+
console.log(`đĄ For full documentation, run: ${BOLD}nx run .:webpieces:help${RESET}`);
|
|
183
192
|
console.log('');
|
|
184
|
-
printAvailableTargets();
|
|
185
193
|
};
|
|
186
194
|
}
|
|
187
|
-
function printAvailableTargets() {
|
|
188
|
-
console.log('đ Available npm scripts (convenient shortcuts):');
|
|
189
|
-
console.log('');
|
|
190
|
-
console.log(' Architecture graph:');
|
|
191
|
-
console.log(' npm run arch:generate # Generate dependency graph');
|
|
192
|
-
console.log(' npm run arch:visualize # Visualize dependency graph');
|
|
193
|
-
console.log('');
|
|
194
|
-
console.log(' Validation:');
|
|
195
|
-
console.log(' npm run arch:validate # Quick validation (no-cycles + no-skiplevel-deps)');
|
|
196
|
-
console.log(' npm run arch:validate-all # Full arch validation (+ unchanged check)');
|
|
197
|
-
console.log(' npm run arch:check-circular # Check all projects for circular deps');
|
|
198
|
-
console.log(' npm run arch:check-circular-affected # Check affected projects only');
|
|
199
|
-
console.log(' npm run arch:validate-complete # Complete validation (arch + circular)');
|
|
200
|
-
console.log('');
|
|
201
|
-
console.log('đ Available Nx targets:');
|
|
202
|
-
console.log('');
|
|
203
|
-
console.log(' Workspace-level architecture validation:');
|
|
204
|
-
console.log(' nx run .:arch:generate # Generate dependency graph');
|
|
205
|
-
console.log(' nx run .:arch:visualize # Visualize dependency graph');
|
|
206
|
-
console.log(' nx run .:arch:validate-no-cycles # Check for circular dependencies');
|
|
207
|
-
console.log(' nx run .:arch:validate-no-skiplevel-deps # Check for redundant dependencies');
|
|
208
|
-
console.log(' nx run .:arch:validate-architecture-unchanged # Validate against blessed graph');
|
|
209
|
-
console.log('');
|
|
210
|
-
console.log(' Per-project circular dependency checking:');
|
|
211
|
-
console.log(' nx run <project>:check-circular-deps # Check project for circular deps');
|
|
212
|
-
console.log(' nx affected --target=check-circular-deps # Check all affected projects');
|
|
213
|
-
console.log(' nx run-many --target=check-circular-deps --all # Check all projects');
|
|
214
|
-
console.log('');
|
|
215
|
-
console.log('đĄ Quick start:');
|
|
216
|
-
console.log(' npm run arch:generate # Generate the graph first');
|
|
217
|
-
console.log(' npm run arch:validate-complete # Run complete validation');
|
|
218
|
-
console.log('');
|
|
219
|
-
}
|
|
220
195
|
//# sourceMappingURL=generator.js.map
|
|
@@ -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';\n\nexport interface InitGeneratorSchema {\n skipFormat?: boolean;\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 * - 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 const installTask = addMadgeDependency(tree);\n createArchitectureDirectory(tree);\n addNpmScripts(tree);\n createEslintConfig(tree);\n\n if (!options.skipFormat) {\n await formatFiles(tree);\n }\n\n return createSuccessCallback(installTask);\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 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 .:arch:generate';\n pkgJson.scripts['arch:visualize'] = 'nx run .:arch:visualize';\n pkgJson.scripts['arch:validate'] = 'nx run .:arch:validate-no-cycles && nx run .:arch:validate-no-skiplevel-deps';\n pkgJson.scripts['arch:validate-all'] = 'nx run .:arch:validate-no-cycles && nx run .:arch:validate-no-skiplevel-deps && nx run .:arch:validate-architecture-unchanged';\n\n // Add circular dependency checking scripts\n pkgJson.scripts['arch:check-circular'] = 'nx run-many --target=check-circular-deps --all';\n pkgJson.scripts['arch:check-circular-affected'] = 'nx affected --target=check-circular-deps';\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): void {\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 if (tree.exists(mainConfigPath)) {\n // Existing config - show them how to import\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 console.log('');\n } else {\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\nfunction createWebpiecesEslintConfig(tree: Tree, configPath: string): void {\n const webpiecesConfig = `// @webpieces/dev-config ESLint rules\n// This file contains the ESLint configuration provided by @webpieces/dev-config\n// You can modify or remove rules as needed for your project\n\nimport webpiecesPlugin from '@webpieces/dev-config/eslint-plugin';\nimport tseslint from '@typescript-eslint/eslint-plugin';\nimport tsparser from '@typescript-eslint/parser';\n\nexport default [\n {\n ignores: ['**/dist', '**/node_modules', '**/coverage', '**/.nx'],\n },\n {\n files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],\n plugins: {\n '@webpieces': webpiecesPlugin,\n '@typescript-eslint': tseslint,\n },\n languageOptions: {\n parser: tsparser,\n ecmaVersion: 2021,\n sourceType: 'module',\n },\n rules: {\n // WebPieces custom rules\n '@webpieces/catch-error-pattern': 'error',\n '@webpieces/no-unmanaged-exceptions': 'error',\n '@webpieces/max-method-lines': ['error', { max: 70 }],\n '@webpieces/max-file-lines': ['error', { max: 700 }],\n '@webpieces/enforce-architecture': 'error',\n\n // TypeScript rules\n '@typescript-eslint/no-explicit-any': 'off',\n '@typescript-eslint/explicit-function-return-type': 'off',\n '@typescript-eslint/no-unused-vars': 'off',\n '@typescript-eslint/no-empty-interface': 'off',\n '@typescript-eslint/no-empty-function': 'off',\n\n // General code quality\n 'no-console': 'off',\n 'no-debugger': 'off',\n 'no-var': 'error',\n 'prefer-const': 'off',\n },\n },\n {\n // Test files - relaxed rules\n files: ['**/*.spec.ts', '**/*.test.ts'],\n rules: {\n '@typescript-eslint/no-explicit-any': 'off',\n '@typescript-eslint/no-non-null-assertion': 'off',\n '@webpieces/max-method-lines': 'off',\n },\n },\n];\n`;\n\n tree.write(configPath, webpiecesConfig);\n console.log('â
Created eslint.webpieces.config.mjs with @webpieces/dev-config rules');\n}\n\nfunction createSuccessCallback(installTask: ReturnType<typeof addDependenciesToPackageJson>) {\n return async () => {\n await installTask();\n console.log('â
Added madge to devDependencies');\n console.log('');\n console.log('â
@webpieces/dev-config plugin initialized!');\n console.log('');\n printAvailableTargets();\n };\n}\n\nfunction printAvailableTargets(): void {\n console.log('đ Available npm scripts (convenient shortcuts):');\n console.log('');\n console.log(' Architecture graph:');\n console.log(' npm run arch:generate # Generate dependency graph');\n console.log(' npm run arch:visualize # Visualize dependency graph');\n console.log('');\n console.log(' Validation:');\n console.log(' npm run arch:validate # Quick validation (no-cycles + no-skiplevel-deps)');\n console.log(' npm run arch:validate-all # Full arch validation (+ unchanged check)');\n console.log(' npm run arch:check-circular # Check all projects for circular deps');\n console.log(' npm run arch:check-circular-affected # Check affected projects only');\n console.log(' npm run arch:validate-complete # Complete validation (arch + circular)');\n console.log('');\n console.log('đ Available Nx targets:');\n console.log('');\n console.log(' Workspace-level architecture validation:');\n console.log(' nx run .:arch:generate # Generate dependency graph');\n console.log(' nx run .:arch:visualize # Visualize dependency graph');\n console.log(' nx run .:arch:validate-no-cycles # Check for circular dependencies');\n console.log(' nx run .:arch:validate-no-skiplevel-deps # Check for redundant dependencies');\n console.log(' nx run .:arch:validate-architecture-unchanged # Validate against blessed graph');\n console.log('');\n console.log(' Per-project circular dependency checking:');\n console.log(' nx run <project>:check-circular-deps # Check project for circular deps');\n console.log(' nx affected --target=check-circular-deps # Check all affected projects');\n console.log(' nx run-many --target=check-circular-deps --all # Check all projects');\n console.log('');\n console.log('đĄ Quick start:');\n console.log(' npm run arch:generate # Generate the graph first');\n console.log(' npm run arch:validate-complete # Run complete validation');\n console.log('');\n}\n"]}
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/dev-config/src/generators/init/generator.ts"],"names":[],"mappings":";;AAmCA,gCAYC;AA/CD,uCAAmH;AACnH,mCAAoC;AAMpC,SAAS,aAAa,CAAC,OAAe;IAClC,OAAO,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAU;IACjC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,iDAAiD,EAAE,OAAO,CAAC,CAAC;IACtF,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;IAC3F,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACpC,OAAO,OAAO,CAAC,OAAO,CAAC;AAC3B,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACY,KAAK,UAAU,aAAa,CAAC,IAAU,EAAE,OAA4B;IAChF,cAAc,CAAC,IAAI,CAAC,CAAC;IACrB,MAAM,WAAW,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC7C,2BAA2B,CAAC,IAAI,CAAC,CAAC;IAClC,aAAa,CAAC,IAAI,CAAC,CAAC;IACpB,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAEzB,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QACtB,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,qBAAqB,CAAC,WAAW,CAAC,CAAC;AAC9C,CAAC;AAED,SAAS,cAAc,CAAC,IAAU;IAC9B,MAAM,MAAM,GAAG,IAAA,mBAAU,EAAC,IAAI,CAAC,CAAC;IAChC,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IAC3E,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,CAAC,OAAO,GAAG,EAAE,CAAC;IACxB,CAAC;IAED,MAAM,UAAU,GAAG,uBAAuB,CAAC;IAC3C,MAAM,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CACzC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAC5E,CAAC;IAEF,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACrB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAChC,IAAA,qBAAY,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,gBAAgB,UAAU,oBAAoB,CAAC,CAAC;IAChE,CAAC;SAAM,CAAC;QACJ,OAAO,CAAC,GAAG,CAAC,OAAO,UAAU,+BAA+B,CAAC,CAAC;IAClE,CAAC;AACL,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAU;IAClC,OAAO,IAAA,qCAA4B,EAAC,IAAI,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;AACzE,CAAC;AAED,SAAS,2BAA2B,CAAC,IAAU;IAC3C,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IACrD,CAAC;AACL,CAAC;AAED,SAAS,aAAa,CAAC,IAAU;IAC7B,IAAA,mBAAU,EAAC,IAAI,EAAE,cAAc,EAAE,CAAC,OAAO,EAAE,EAAE;QACzC,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;QAExC,sCAAsC;QACtC,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,GAAG,wBAAwB,CAAC;QAC5D,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,GAAG,yBAAyB,CAAC;QAC9D,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,GAAG,8EAA8E,CAAC;QAClH,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,GAAG,+HAA+H,CAAC;QAEvK,2CAA2C;QAC3C,OAAO,CAAC,OAAO,CAAC,qBAAqB,CAAC,GAAG,gDAAgD,CAAC;QAC1F,OAAO,CAAC,OAAO,CAAC,8BAA8B,CAAC,GAAG,0CAA0C,CAAC;QAE7F,8CAA8C;QAC9C,OAAO,CAAC,OAAO,CAAC,wBAAwB,CAAC,GAAG,0DAA0D,CAAC;QAEvG,OAAO,OAAO,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,kFAAkF,CAAC,CAAC;AACpG,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAU;IAClC,MAAM,mBAAmB,GAAG,6BAA6B,CAAC;IAC1D,MAAM,cAAc,GAAG,mBAAmB,CAAC;IAE3C,2DAA2D;IAC3D,2BAA2B,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;IAEvD,yCAAyC;IACzC,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC;QAC9B,4CAA4C;QAC5C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,uFAAuF,CAAC,CAAC;QACrG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;QAChF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACpB,CAAC;SAAM,CAAC;QACJ,gEAAgE;QAChE,MAAM,UAAU,GAAG;;;;;;;;;;;CAW1B,CAAC;QAEM,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAC;IAChF,CAAC;AACL,CAAC;AAED,SAAS,gCAAgC,CAAC,IAAU;IAChD,6DAA6D;IAC7D,MAAM,YAAY,GAAG,0EAA0E,CAAC;IAChG,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAElD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,uCAAuC,YAAY,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,OAAO,QAAQ,CAAC;AACpB,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAU,EAAE,UAAkB,EAAE,SAAiB;IACxE,MAAM,OAAO,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,iBAAiB,GAAG,GAAG,UAAU,KAAK,OAAO,EAAE,CAAC;IAEtD,IAAI,CAAC,KAAK,CAAC,iBAAiB,EAAE,SAAS,CAAC,CAAC;IAEzC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,OAAO,UAAU,cAAc,CAAC,CAAC;IAC7C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,uEAAuE,CAAC,CAAC;IACrF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,eAAe,iBAAiB,sBAAsB,CAAC,CAAC;IACpE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,wBAAwB,UAAU,EAAE,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,wBAAwB,iBAAiB,EAAE,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AACpB,CAAC;AAED,SAAS,2BAA2B,CAAC,IAAU,EAAE,UAAkB;IAC/D,MAAM,eAAe,GAAG,gCAAgC,CAAC,IAAI,CAAC,CAAC;IAE/D,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,aAAa,UAAU,EAAE,CAAC,CAAC;QACvC,OAAO;IACX,CAAC;IAED,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACtD,IAAI,CAAC,cAAc,EAAE,CAAC;QAClB,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,aAAa,UAAU,EAAE,CAAC,CAAC;QACvC,OAAO;IACX,CAAC;IAED,MAAM,WAAW,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,aAAa,CAAC,eAAe,CAAC,CAAC;IAE/C,IAAI,WAAW,KAAK,OAAO,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,UAAU,gBAAgB,CAAC,CAAC;QAC7C,OAAO;IACX,CAAC;IAED,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;AACzD,CAAC;AAED,SAAS,qBAAqB,CAAC,WAA4D;IACvF,OAAO,KAAK,IAAI,EAAE;QACd,MAAM,WAAW,EAAE,CAAC;QAEpB,wCAAwC;QACxC,MAAM,KAAK,GAAG,iBAAiB,CAAC;QAChC,MAAM,IAAI,GAAG,SAAS,CAAC;QACvB,MAAM,KAAK,GAAG,SAAS,CAAC;QAExB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,8CAA8C,KAAK,EAAE,CAAC,CAAC;QAC3E,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,kBAAkB,KAAK,EAAE,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,wBAAwB,KAAK,4CAA4C,CAAC,CAAC;QACjG,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,iCAAiC,KAAK,6BAA6B,CAAC,CAAC;QAC3F,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,mCAAmC,IAAI,0BAA0B,KAAK,EAAE,CAAC,CAAC;QACtF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACpB,CAAC,CAAC;AACN,CAAC","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 * - 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 const installTask = addMadgeDependency(tree);\n createArchitectureDirectory(tree);\n addNpmScripts(tree);\n createEslintConfig(tree);\n\n if (!options.skipFormat) {\n await formatFiles(tree);\n }\n\n return createSuccessCallback(installTask);\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 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 .:arch:generate';\n pkgJson.scripts['arch:visualize'] = 'nx run .:arch:visualize';\n pkgJson.scripts['arch:validate'] = 'nx run .:arch:validate-no-cycles && nx run .:arch:validate-no-skiplevel-deps';\n pkgJson.scripts['arch:validate-all'] = 'nx run .:arch:validate-no-cycles && nx run .:arch:validate-no-skiplevel-deps && nx run .:arch:validate-architecture-unchanged';\n\n // Add circular dependency checking scripts\n pkgJson.scripts['arch:check-circular'] = 'nx run-many --target=check-circular-deps --all';\n pkgJson.scripts['arch:check-circular-affected'] = 'nx affected --target=check-circular-deps';\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): void {\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 if (tree.exists(mainConfigPath)) {\n // Existing config - show them how to import\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 console.log('');\n } else {\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\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(installTask: ReturnType<typeof addDependenciesToPackageJson>) {\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 .:webpieces:help${RESET}`);\n console.log('');\n };\n}\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// @webpieces/dev-config ESLint Configuration
|
|
2
|
+
// This is the canonical template for external clients
|
|
3
|
+
//
|
|
4
|
+
// IMPORTANT: When modifying rules here, also update:
|
|
5
|
+
// - /eslint.webpieces.config.mjs (webpieces workspace version with loadWorkspaceRules)
|
|
6
|
+
//
|
|
7
|
+
// Only includes @webpieces custom rules
|
|
8
|
+
// Configure your own TypeScript and general rules in your main eslint.config.mjs as needed
|
|
9
|
+
|
|
10
|
+
import webpiecesPlugin from '@webpieces/dev-config/eslint-plugin';
|
|
11
|
+
|
|
12
|
+
export default [
|
|
13
|
+
{
|
|
14
|
+
ignores: ['**/dist', '**/node_modules', '**/coverage', '**/.nx'],
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
|
|
18
|
+
plugins: {
|
|
19
|
+
'@webpieces': webpiecesPlugin,
|
|
20
|
+
},
|
|
21
|
+
rules: {
|
|
22
|
+
'@webpieces/catch-error-pattern': 'error',
|
|
23
|
+
'@webpieces/no-unmanaged-exceptions': 'error',
|
|
24
|
+
'@webpieces/max-method-lines': ['error', { max: 70 }],
|
|
25
|
+
'@webpieces/max-file-lines': ['error', { max: 700 }],
|
|
26
|
+
'@webpieces/enforce-architecture': 'error',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
];
|