@webpieces/dev-config 0.2.24 → 0.2.26

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.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/generators.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "$schema": "http://json-schema.org/schema",
3
3
  "generators": {
4
4
  "init": {
5
- "factory": "./generators/init/generator",
6
- "schema": "./generators/init/schema.json",
5
+ "factory": "./src/generators/init/generator",
6
+ "schema": "./src/generators/init/schema.json",
7
7
  "description": "Initialize @webpieces/dev-config in an Nx workspace"
8
8
  }
9
9
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/dev-config",
3
- "version": "0.2.24",
3
+ "version": "0.2.26",
4
4
  "description": "Development configuration, scripts, and patterns for WebPieces projects",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -34,7 +34,8 @@
34
34
  "plugins/**/*",
35
35
  "plugin/**/*",
36
36
  "plugin.js",
37
- "generators/**/*",
37
+ "templates/**/*",
38
+ "src/**/*",
38
39
  "generators.json",
39
40
  "architecture/**/*",
40
41
  "executors.json",
@@ -0,0 +1,20 @@
1
+ import { Tree } from '@nx/devkit';
2
+ export interface InitGeneratorSchema {
3
+ skipFormat?: boolean;
4
+ }
5
+ /**
6
+ * Init generator for @webpieces/dev-config
7
+ *
8
+ * Automatically runs when users execute: nx add @webpieces/dev-config
9
+ *
10
+ * Responsibilities:
11
+ * - Registers the plugin in nx.json
12
+ * - Creates architecture/ directory if needed
13
+ * - Adds madge as a devDependency (required for circular dep checking)
14
+ * - Adds convenient npm scripts to package.json
15
+ * - Always creates eslint.webpieces.config.mjs with @webpieces rules
16
+ * - Creates eslint.config.mjs (if not exists) that imports eslint.webpieces.config.mjs
17
+ * - If eslint.config.mjs exists, shows user how to import eslint.webpieces.config.mjs
18
+ * - Provides helpful output about available targets
19
+ */
20
+ export default function initGenerator(tree: Tree, options: InitGeneratorSchema): Promise<() => Promise<void>>;
@@ -0,0 +1,195 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = initGenerator;
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
+ }
17
+ /**
18
+ * Init generator for @webpieces/dev-config
19
+ *
20
+ * Automatically runs when users execute: nx add @webpieces/dev-config
21
+ *
22
+ * Responsibilities:
23
+ * - Registers the plugin in nx.json
24
+ * - Creates architecture/ directory if needed
25
+ * - Adds madge as a devDependency (required for circular dep checking)
26
+ * - Adds convenient npm scripts to package.json
27
+ * - Always creates eslint.webpieces.config.mjs with @webpieces rules
28
+ * - Creates eslint.config.mjs (if not exists) that imports eslint.webpieces.config.mjs
29
+ * - If eslint.config.mjs exists, shows user how to import eslint.webpieces.config.mjs
30
+ * - Provides helpful output about available targets
31
+ */
32
+ async function initGenerator(tree, options) {
33
+ registerPlugin(tree);
34
+ const installTask = addMadgeDependency(tree);
35
+ createArchitectureDirectory(tree);
36
+ addNpmScripts(tree);
37
+ createEslintConfig(tree);
38
+ if (!options.skipFormat) {
39
+ await (0, devkit_1.formatFiles)(tree);
40
+ }
41
+ return createSuccessCallback(installTask);
42
+ }
43
+ function registerPlugin(tree) {
44
+ const nxJson = (0, devkit_1.readNxJson)(tree);
45
+ if (!nxJson) {
46
+ throw new Error('Could not read nx.json. Are you in an Nx workspace?');
47
+ }
48
+ if (!nxJson.plugins) {
49
+ nxJson.plugins = [];
50
+ }
51
+ const pluginName = '@webpieces/dev-config';
52
+ const alreadyRegistered = nxJson.plugins.some((p) => typeof p === 'string' ? p === pluginName : p.plugin === pluginName);
53
+ if (!alreadyRegistered) {
54
+ nxJson.plugins.push(pluginName);
55
+ (0, devkit_1.updateNxJson)(tree, nxJson);
56
+ console.log(`✅ Registered ${pluginName} plugin in nx.json`);
57
+ }
58
+ else {
59
+ console.log(`ℹ️ ${pluginName} plugin is already registered`);
60
+ }
61
+ }
62
+ function addMadgeDependency(tree) {
63
+ return (0, devkit_1.addDependenciesToPackageJson)(tree, {}, { 'madge': '^8.0.0' });
64
+ }
65
+ function createArchitectureDirectory(tree) {
66
+ if (!tree.exists('architecture')) {
67
+ tree.write('architecture/.gitkeep', '');
68
+ console.log('✅ Created architecture/ directory');
69
+ }
70
+ }
71
+ function addNpmScripts(tree) {
72
+ (0, devkit_1.updateJson)(tree, 'package.json', (pkgJson) => {
73
+ pkgJson.scripts = pkgJson.scripts ?? {};
74
+ // Add architecture validation scripts
75
+ pkgJson.scripts['arch:generate'] = 'nx run .:arch:generate';
76
+ pkgJson.scripts['arch:visualize'] = 'nx run .:arch:visualize';
77
+ pkgJson.scripts['arch:validate'] = 'nx run .:arch:validate-no-cycles && nx run .:arch:validate-no-skiplevel-deps';
78
+ pkgJson.scripts['arch:validate-all'] = 'nx run .:arch:validate-no-cycles && nx run .:arch:validate-no-skiplevel-deps && nx run .:arch:validate-architecture-unchanged';
79
+ // Add circular dependency checking scripts
80
+ pkgJson.scripts['arch:check-circular'] = 'nx run-many --target=check-circular-deps --all';
81
+ pkgJson.scripts['arch:check-circular-affected'] = 'nx affected --target=check-circular-deps';
82
+ // Complete validation including circular deps
83
+ pkgJson.scripts['arch:validate-complete'] = 'npm run arch:validate-all && npm run arch:check-circular';
84
+ return pkgJson;
85
+ });
86
+ console.log('✅ Added npm scripts for architecture validation and circular dependency checking');
87
+ }
88
+ function createEslintConfig(tree) {
89
+ const webpiecesConfigPath = 'eslint.webpieces.config.mjs';
90
+ const mainConfigPath = 'eslint.config.mjs';
91
+ // Always create eslint.webpieces.config.mjs with our rules
92
+ createWebpiecesEslintConfig(tree, webpiecesConfigPath);
93
+ // Check if main eslint.config.mjs exists
94
+ if (tree.exists(mainConfigPath)) {
95
+ // Existing config - show them how to import
96
+ console.log('');
97
+ console.log('📋 Existing eslint.config.mjs detected');
98
+ console.log('');
99
+ console.log('To use @webpieces/dev-config ESLint rules, add this import to your eslint.config.mjs:');
100
+ console.log('');
101
+ console.log(' import webpiecesConfig from \'./eslint.webpieces.config.mjs\';');
102
+ console.log('');
103
+ console.log('Then spread it into your config array:');
104
+ console.log('');
105
+ console.log(' export default [');
106
+ console.log(' ...webpiecesConfig, // Add this line');
107
+ console.log(' // ... your existing config');
108
+ console.log(' ];');
109
+ console.log('');
110
+ }
111
+ else {
112
+ // No existing config - create one that imports webpieces config
113
+ const mainConfig = `// ESLint configuration
114
+ // Imports @webpieces/dev-config rules
115
+
116
+ import webpiecesConfig from './eslint.webpieces.config.mjs';
117
+
118
+ // Export the webpieces configuration
119
+ // You can add your own rules after spreading webpiecesConfig
120
+ export default [
121
+ ...webpiecesConfig,
122
+ // Add your custom ESLint configuration here
123
+ ];
124
+ `;
125
+ tree.write(mainConfigPath, mainConfig);
126
+ console.log('✅ Created eslint.config.mjs with @webpieces/dev-config rules');
127
+ }
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
+ }
154
+ function createWebpiecesEslintConfig(tree, configPath) {
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);
174
+ }
175
+ function createSuccessCallback(installTask) {
176
+ return async () => {
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('');
183
+ console.log('✅ Added madge to devDependencies');
184
+ 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}`);
192
+ console.log('');
193
+ };
194
+ }
195
+ //# sourceMappingURL=generator.js.map
@@ -0,0 +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 * - 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"]}
package/src/index.d.ts ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @webpieces/dev-config
3
+ *
4
+ * Development configuration, scripts, and patterns for WebPieces projects.
5
+ *
6
+ * This package provides:
7
+ * - Executable scripts (via bin commands: wp-start, wp-stop, etc.)
8
+ * - Shareable ESLint configuration
9
+ * - Jest preset
10
+ * - Base TypeScript configuration
11
+ * - Claude Code pattern documentation
12
+ *
13
+ * @packageDocumentation
14
+ */
15
+ /**
16
+ * This is primarily a configuration and scripts package.
17
+ * The actual exports are defined in package.json:
18
+ *
19
+ * - bin: Executable scripts (wp-start, wp-stop, etc.)
20
+ * - exports: Configuration files (eslint, jest, tsconfig)
21
+ *
22
+ * See README.md for usage instructions.
23
+ */
24
+ export declare const version = "0.0.0-dev";
25
+ export declare const packageName = "@webpieces/dev-config";
26
+ /**
27
+ * Check if running in webpieces-ts workspace
28
+ */
29
+ export declare function isWebpiecesWorkspace(): boolean;
30
+ /**
31
+ * Get project root directory
32
+ */
33
+ export declare function getProjectRoot(): string;
package/src/index.js ADDED
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ /**
3
+ * @webpieces/dev-config
4
+ *
5
+ * Development configuration, scripts, and patterns for WebPieces projects.
6
+ *
7
+ * This package provides:
8
+ * - Executable scripts (via bin commands: wp-start, wp-stop, etc.)
9
+ * - Shareable ESLint configuration
10
+ * - Jest preset
11
+ * - Base TypeScript configuration
12
+ * - Claude Code pattern documentation
13
+ *
14
+ * @packageDocumentation
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.packageName = exports.version = void 0;
18
+ exports.isWebpiecesWorkspace = isWebpiecesWorkspace;
19
+ exports.getProjectRoot = getProjectRoot;
20
+ /**
21
+ * This is primarily a configuration and scripts package.
22
+ * The actual exports are defined in package.json:
23
+ *
24
+ * - bin: Executable scripts (wp-start, wp-stop, etc.)
25
+ * - exports: Configuration files (eslint, jest, tsconfig)
26
+ *
27
+ * See README.md for usage instructions.
28
+ */
29
+ exports.version = '0.0.0-dev';
30
+ exports.packageName = '@webpieces/dev-config';
31
+ /**
32
+ * Check if running in webpieces-ts workspace
33
+ */
34
+ function isWebpiecesWorkspace() {
35
+ return process.cwd().includes('webpieces-ts');
36
+ }
37
+ /**
38
+ * Get project root directory
39
+ */
40
+ function getProjectRoot() {
41
+ // This is a simple helper, actual path detection is in bash scripts
42
+ return process.cwd();
43
+ }
44
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/tooling/dev-config/src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;;AAkBH,oDAEC;AAKD,wCAGC;AA1BD;;;;;;;;GAQG;AAEU,QAAA,OAAO,GAAG,WAAW,CAAC;AACtB,QAAA,WAAW,GAAG,uBAAuB,CAAC;AAEnD;;GAEG;AACH,SAAgB,oBAAoB;IAChC,OAAO,OAAO,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc;IAC1B,oEAAoE;IACpE,OAAO,OAAO,CAAC,GAAG,EAAE,CAAC;AACzB,CAAC","sourcesContent":["/**\n * @webpieces/dev-config\n *\n * Development configuration, scripts, and patterns for WebPieces projects.\n *\n * This package provides:\n * - Executable scripts (via bin commands: wp-start, wp-stop, etc.)\n * - Shareable ESLint configuration\n * - Jest preset\n * - Base TypeScript configuration\n * - Claude Code pattern documentation\n *\n * @packageDocumentation\n */\n\n/**\n * This is primarily a configuration and scripts package.\n * The actual exports are defined in package.json:\n *\n * - bin: Executable scripts (wp-start, wp-stop, etc.)\n * - exports: Configuration files (eslint, jest, tsconfig)\n *\n * See README.md for usage instructions.\n */\n\nexport const version = '0.0.0-dev';\nexport const packageName = '@webpieces/dev-config';\n\n/**\n * Check if running in webpieces-ts workspace\n */\nexport function isWebpiecesWorkspace(): boolean {\n return process.cwd().includes('webpieces-ts');\n}\n\n/**\n * Get project root directory\n */\nexport function getProjectRoot(): string {\n // This is a simple helper, actual path detection is in bash scripts\n return process.cwd();\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
+ ];
@@ -1,240 +0,0 @@
1
- import { formatFiles, readNxJson, Tree, updateNxJson, updateJson, addDependenciesToPackageJson } from '@nx/devkit';
2
- import type { InitGeneratorSchema } from './schema';
3
-
4
- /**
5
- * Init generator for @webpieces/dev-config
6
- *
7
- * Automatically runs when users execute: nx add @webpieces/dev-config
8
- *
9
- * Responsibilities:
10
- * - Registers the plugin in nx.json
11
- * - Creates architecture/ directory if needed
12
- * - Adds madge as a devDependency (required for circular dep checking)
13
- * - Adds convenient npm scripts to package.json
14
- * - Always creates eslint.webpieces.config.mjs with @webpieces rules
15
- * - Creates eslint.config.mjs (if not exists) that imports eslint.webpieces.config.mjs
16
- * - If eslint.config.mjs exists, shows user how to import eslint.webpieces.config.mjs
17
- * - Provides helpful output about available targets
18
- */
19
- export default async function initGenerator(tree: Tree, options: InitGeneratorSchema) {
20
- registerPlugin(tree);
21
- const installTask = addMadgeDependency(tree);
22
- createArchitectureDirectory(tree);
23
- addNpmScripts(tree);
24
- createEslintConfig(tree);
25
-
26
- if (!options.skipFormat) {
27
- await formatFiles(tree);
28
- }
29
-
30
- return createSuccessCallback(installTask);
31
- }
32
-
33
- function registerPlugin(tree: Tree): void {
34
- const nxJson = readNxJson(tree);
35
- if (!nxJson) {
36
- throw new Error('Could not read nx.json. Are you in an Nx workspace?');
37
- }
38
-
39
- if (!nxJson.plugins) {
40
- nxJson.plugins = [];
41
- }
42
-
43
- const pluginName = '@webpieces/dev-config';
44
- const alreadyRegistered = nxJson.plugins.some(
45
- (p) => typeof p === 'string' ? p === pluginName : p.plugin === pluginName
46
- );
47
-
48
- if (!alreadyRegistered) {
49
- nxJson.plugins.push(pluginName);
50
- updateNxJson(tree, nxJson);
51
- console.log(`✅ Registered ${pluginName} plugin in nx.json`);
52
- } else {
53
- console.log(`ℹ️ ${pluginName} plugin is already registered`);
54
- }
55
- }
56
-
57
- function addMadgeDependency(tree: Tree) {
58
- return addDependenciesToPackageJson(tree, {}, { 'madge': '^8.0.0' });
59
- }
60
-
61
- function createArchitectureDirectory(tree: Tree): void {
62
- if (!tree.exists('architecture')) {
63
- tree.write('architecture/.gitkeep', '');
64
- console.log('✅ Created architecture/ directory');
65
- }
66
- }
67
-
68
- function addNpmScripts(tree: Tree): void {
69
- updateJson(tree, 'package.json', (pkgJson) => {
70
- pkgJson.scripts = pkgJson.scripts ?? {};
71
-
72
- // Add architecture validation scripts
73
- pkgJson.scripts['arch:generate'] = 'nx run .:arch:generate';
74
- pkgJson.scripts['arch:visualize'] = 'nx run .:arch:visualize';
75
- pkgJson.scripts['arch:validate'] = 'nx run .:arch:validate-no-cycles && nx run .:arch:validate-no-skiplevel-deps';
76
- pkgJson.scripts['arch:validate-all'] = 'nx run .:arch:validate-no-cycles && nx run .:arch:validate-no-skiplevel-deps && nx run .:arch:validate-architecture-unchanged';
77
-
78
- // Add circular dependency checking scripts
79
- pkgJson.scripts['arch:check-circular'] = 'nx run-many --target=check-circular-deps --all';
80
- pkgJson.scripts['arch:check-circular-affected'] = 'nx affected --target=check-circular-deps';
81
-
82
- // Complete validation including circular deps
83
- pkgJson.scripts['arch:validate-complete'] = 'npm run arch:validate-all && npm run arch:check-circular';
84
-
85
- return pkgJson;
86
- });
87
-
88
- console.log('✅ Added npm scripts for architecture validation and circular dependency checking');
89
- }
90
-
91
- function createEslintConfig(tree: Tree): void {
92
- const webpiecesConfigPath = 'eslint.webpieces.config.mjs';
93
- const mainConfigPath = 'eslint.config.mjs';
94
-
95
- // Always create eslint.webpieces.config.mjs with our rules
96
- createWebpiecesEslintConfig(tree, webpiecesConfigPath);
97
-
98
- // Check if main eslint.config.mjs exists
99
- if (tree.exists(mainConfigPath)) {
100
- // Existing config - show them how to import
101
- console.log('');
102
- console.log('📋 Existing eslint.config.mjs detected');
103
- console.log('');
104
- console.log('To use @webpieces/dev-config ESLint rules, add this import to your eslint.config.mjs:');
105
- console.log('');
106
- console.log(' import webpiecesConfig from \'./eslint.webpieces.config.mjs\';');
107
- console.log('');
108
- console.log('Then spread it into your config array:');
109
- console.log('');
110
- console.log(' export default [');
111
- console.log(' ...webpiecesConfig, // Add this line');
112
- console.log(' // ... your existing config');
113
- console.log(' ];');
114
- console.log('');
115
- } else {
116
- // No existing config - create one that imports webpieces config
117
- const mainConfig = `// ESLint configuration
118
- // Imports @webpieces/dev-config rules
119
-
120
- import webpiecesConfig from './eslint.webpieces.config.mjs';
121
-
122
- // Export the webpieces configuration
123
- // You can add your own rules after spreading webpiecesConfig
124
- export default [
125
- ...webpiecesConfig,
126
- // Add your custom ESLint configuration here
127
- ];
128
- `;
129
-
130
- tree.write(mainConfigPath, mainConfig);
131
- console.log('✅ Created eslint.config.mjs with @webpieces/dev-config rules');
132
- }
133
- }
134
-
135
- function createWebpiecesEslintConfig(tree: Tree, configPath: string): void {
136
- const webpiecesConfig = `// @webpieces/dev-config ESLint rules
137
- // This file contains the ESLint configuration provided by @webpieces/dev-config
138
- // You can modify or remove rules as needed for your project
139
-
140
- import webpiecesPlugin from '@webpieces/dev-config/eslint-plugin';
141
- import tseslint from '@typescript-eslint/eslint-plugin';
142
- import tsparser from '@typescript-eslint/parser';
143
-
144
- export default [
145
- {
146
- ignores: ['**/dist', '**/node_modules', '**/coverage', '**/.nx'],
147
- },
148
- {
149
- files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
150
- plugins: {
151
- '@webpieces': webpiecesPlugin,
152
- '@typescript-eslint': tseslint,
153
- },
154
- languageOptions: {
155
- parser: tsparser,
156
- ecmaVersion: 2021,
157
- sourceType: 'module',
158
- },
159
- rules: {
160
- // WebPieces custom rules
161
- '@webpieces/catch-error-pattern': 'error',
162
- '@webpieces/no-unmanaged-exceptions': 'error',
163
- '@webpieces/max-method-lines': ['error', { max: 70 }],
164
- '@webpieces/max-file-lines': ['error', { max: 700 }],
165
- '@webpieces/enforce-architecture': 'error',
166
-
167
- // TypeScript rules
168
- '@typescript-eslint/no-explicit-any': 'off',
169
- '@typescript-eslint/explicit-function-return-type': 'off',
170
- '@typescript-eslint/no-unused-vars': 'off',
171
- '@typescript-eslint/no-empty-interface': 'off',
172
- '@typescript-eslint/no-empty-function': 'off',
173
-
174
- // General code quality
175
- 'no-console': 'off',
176
- 'no-debugger': 'off',
177
- 'no-var': 'error',
178
- 'prefer-const': 'off',
179
- },
180
- },
181
- {
182
- // Test files - relaxed rules
183
- files: ['**/*.spec.ts', '**/*.test.ts'],
184
- rules: {
185
- '@typescript-eslint/no-explicit-any': 'off',
186
- '@typescript-eslint/no-non-null-assertion': 'off',
187
- '@webpieces/max-method-lines': 'off',
188
- },
189
- },
190
- ];
191
- `;
192
-
193
- tree.write(configPath, webpiecesConfig);
194
- console.log('✅ Created eslint.webpieces.config.mjs with @webpieces/dev-config rules');
195
- }
196
-
197
- function createSuccessCallback(installTask: ReturnType<typeof addDependenciesToPackageJson>) {
198
- return async () => {
199
- await installTask();
200
- console.log('✅ Added madge to devDependencies');
201
- console.log('');
202
- console.log('✅ @webpieces/dev-config plugin initialized!');
203
- console.log('');
204
- printAvailableTargets();
205
- };
206
- }
207
-
208
- function printAvailableTargets(): void {
209
- console.log('📝 Available npm scripts (convenient shortcuts):');
210
- console.log('');
211
- console.log(' Architecture graph:');
212
- console.log(' npm run arch:generate # Generate dependency graph');
213
- console.log(' npm run arch:visualize # Visualize dependency graph');
214
- console.log('');
215
- console.log(' Validation:');
216
- console.log(' npm run arch:validate # Quick validation (no-cycles + no-skiplevel-deps)');
217
- console.log(' npm run arch:validate-all # Full arch validation (+ unchanged check)');
218
- console.log(' npm run arch:check-circular # Check all projects for circular deps');
219
- console.log(' npm run arch:check-circular-affected # Check affected projects only');
220
- console.log(' npm run arch:validate-complete # Complete validation (arch + circular)');
221
- console.log('');
222
- console.log('📝 Available Nx targets:');
223
- console.log('');
224
- console.log(' Workspace-level architecture validation:');
225
- console.log(' nx run .:arch:generate # Generate dependency graph');
226
- console.log(' nx run .:arch:visualize # Visualize dependency graph');
227
- console.log(' nx run .:arch:validate-no-cycles # Check for circular dependencies');
228
- console.log(' nx run .:arch:validate-no-skiplevel-deps # Check for redundant dependencies');
229
- console.log(' nx run .:arch:validate-architecture-unchanged # Validate against blessed graph');
230
- console.log('');
231
- console.log(' Per-project circular dependency checking:');
232
- console.log(' nx run <project>:check-circular-deps # Check project for circular deps');
233
- console.log(' nx affected --target=check-circular-deps # Check all affected projects');
234
- console.log(' nx run-many --target=check-circular-deps --all # Check all projects');
235
- console.log('');
236
- console.log('💡 Quick start:');
237
- console.log(' npm run arch:generate # Generate the graph first');
238
- console.log(' npm run arch:validate-complete # Run complete validation');
239
- console.log('');
240
- }
File without changes