@devmed555/angular-clean-architecture-cli 0.0.1 → 0.0.2

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/bin/index.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  console.log("ACA CLI installed successfully!");
4
4
  console.log("To use the generator, run: nx g @devmed555/angular-clean-architecture-cli:clean-feature");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devmed555/angular-clean-architecture-cli",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "CLI generator for Angular Clean Architecture features using NgRx SignalStore",
5
5
  "keywords": [
6
6
  "angular",
@@ -25,10 +25,8 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@nx/devkit": "20.0.4",
28
- "@nx/js": "20.0.4",
29
- "@nx/angular": "20.0.4",
30
28
  "tslib": "^2.3.0",
31
- "inquirer": "^9.2.12"
29
+ "inquirer": "^8.2.6"
32
30
  },
33
31
  "type": "commonjs",
34
32
  "main": "./src/index.js",
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.cleanFeatureGenerator = cleanFeatureGenerator;
4
4
  const tslib_1 = require("tslib");
5
5
  const devkit_1 = require("@nx/devkit");
6
+ const inquirer = require("inquirer");
6
7
  /**
7
8
  * Capitalizes the first letter of a string
8
9
  */
@@ -15,31 +16,67 @@ function capitalizeFirst(str) {
15
16
  function toPascalCase(str) {
16
17
  return str
17
18
  .split('-')
18
- .map(part => capitalizeFirst(part))
19
+ .map((part) => capitalizeFirst(part))
19
20
  .join('');
20
21
  }
21
22
  function cleanFeatureGenerator(tree, options) {
22
23
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
23
- const name = options.name;
24
+ let name = options.name;
25
+ let attributes = [];
26
+ // Interactive mode if no name provided or explicit interactive flag (though we don't have a specific flag in schema, strict missing name is enough)
27
+ if (!name) {
28
+ const questions = [
29
+ {
30
+ type: 'input',
31
+ name: 'name',
32
+ message: 'What is the name of the feature (singular)?',
33
+ validate: (input) => input.length > 0 ? true : 'Name is required',
34
+ },
35
+ ];
36
+ const answers = yield inquirer.prompt(questions);
37
+ name = answers.name;
38
+ }
39
+ // Auto-pluralize: simply add 's' for now as requested
40
+ // Ideally use a pluralize library, but sticking to simple requirement
41
+ if (!name.endsWith('s')) {
42
+ name = name + 's';
43
+ }
24
44
  const targetPath = (0, devkit_1.joinPathFragments)('apps/sandbox/src/app/features', name);
25
45
  // Format names for templates
26
46
  const pascalName = toPascalCase(name);
27
- // Parse attributes
28
- let attributes = [];
29
47
  if (options.attributes) {
30
- attributes = options.attributes.split(',').map(attr => {
31
- const [name, type] = attr.split(':');
32
- return { name, type: type || 'string' };
48
+ attributes = options.attributes.split(',').map((attr) => {
49
+ const [n, t] = attr.split(':');
50
+ return { name: n, type: t || 'string' };
33
51
  });
34
52
  }
35
53
  else {
36
- // If running in interactive mode (and no attributes provided), we could prompt
37
- // But since this runs in Nx context, standard inquirer might conflict if not handled carefully
38
- // For now we'll support the --attributes flag passed from the interactive CLI wrapper
39
- attributes = [
40
- { name: 'createdAt', type: 'Date' },
41
- { name: 'updatedAt', type: 'Date' }
42
- ];
54
+ // Interactive attribute prompting
55
+ console.log('Let\'s add some attributes (property fields).');
56
+ let addingAttributes = true;
57
+ while (addingAttributes) {
58
+ const { attrName } = yield inquirer.prompt([
59
+ {
60
+ type: 'input',
61
+ name: 'attrName',
62
+ message: 'Enter attribute name (or press enter to finish):',
63
+ },
64
+ ]);
65
+ if (!attrName || attrName.trim() === '') {
66
+ addingAttributes = false;
67
+ break;
68
+ }
69
+ const { attrType } = yield inquirer.prompt([
70
+ {
71
+ type: 'list',
72
+ name: 'attrType',
73
+ message: 'Select type:',
74
+ choices: ['string', 'number', 'boolean', 'Date', 'any'],
75
+ default: 'string',
76
+ },
77
+ ]);
78
+ attributes.push({ name: attrName, type: attrType });
79
+ }
43
80
  }
44
81
  // Generate files from templates
45
82
  (0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, 'files'), targetPath, Object.assign(Object.assign({}, options), { name,
@@ -1 +1 @@
1
- {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../../apps/cli/src/generators/clean-feature/generator.ts"],"names":[],"mappings":";;AAyBA,sDA2CC;;AApED,uCAKoB;AAGpB;;GAEG;AACH,SAAS,eAAe,CAAC,GAAW;IAClC,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpD,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,GAAW;IAC/B,OAAO,GAAG;SACP,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;SAClC,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED,SAAsB,qBAAqB,CACzC,IAAU,EACV,OAAoC;;QAEpC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QAC1B,MAAM,UAAU,GAAG,IAAA,0BAAiB,EAAC,+BAA+B,EAAE,IAAI,CAAC,CAAC;QAE5E,6BAA6B;QAC7B,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QAEtC,mBAAmB;QACnB,IAAI,UAAU,GAAqC,EAAE,CAAC;QAEtD,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACvB,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;gBACpD,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBACrC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC1C,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,+EAA+E;YAC/E,+FAA+F;YAC/F,sFAAsF;YACtF,UAAU,GAAG;gBACX,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE;gBACnC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE;aACpC,CAAC;QACJ,CAAC;QAED,gCAAgC;QAChC,IAAA,sBAAa,EACX,IAAI,EACJ,IAAA,0BAAiB,EAAC,SAAS,EAAE,OAAO,CAAC,EACrC,UAAU,kCAEL,OAAO,KACV,IAAI;YACJ,UAAU;YACV,UAAU,EACV,IAAI,EAAE,EAAE,IAEX,CAAC;QAEF,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;CAAA;AAED,kBAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../../apps/cli/src/generators/clean-feature/generator.ts"],"names":[],"mappings":"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"}
@@ -10,14 +10,12 @@
10
10
  "$default": {
11
11
  "$source": "argv",
12
12
  "index": 0
13
- },
14
- "x-prompt": "What name would you like to use?"
13
+ }
15
14
  },
16
15
  "attributes": {
17
16
  "type": "string",
18
- "description": "Comma-separated list of attributes (e.g., name:string,age:number)",
19
- "x-prompt": "Enter attributes (format: name:string,age:number) or leave empty:"
17
+ "description": "Comma-separated list of attributes (e.g., name:string,age:number)"
20
18
  }
21
19
  },
22
- "required": ["name"]
20
+ "required": []
23
21
  }
package/README.md DELETED
@@ -1,183 +0,0 @@
1
- # CLI Documentation
2
-
3
- The CLI is an Nx generator designed to scaffold clean architecture features within the `sandbox` application.
4
-
5
- ## Usage
6
-
7
- To generate a new feature, run:
8
-
9
- ```bash
10
- npm run generate:feature -- --name=<feature-name>
11
-
12
- # Examples:
13
- npm run generate:feature -- --name=products
14
- npm run generate:feature -- --name=user-profile
15
- npm run generate:feature -- --name=shopping-cart
16
-
17
- # Interactive mode with prompts:
18
- npm run generate:feature:interactive
19
- ```
20
-
21
- ### Arguments
22
-
23
- | Argument | Description | Required |
24
- | --- | --- | --- |
25
- | `--name` | The name of the feature to generate (kebab-case recommended). | Yes |
26
-
27
- ### Generated Structure
28
-
29
- The generator will create the following structure in `apps/sandbox/src/app/features/<name>`:
30
-
31
- ```
32
- <feature-name>/
33
- ├── domain/
34
- │ └── model.ts # Business entities (PascalCase interfaces)
35
- ├── infrastructure/
36
- │ └── service.ts # HTTP services with CRUD operations
37
- ├── application/
38
- │ └── store.ts # NgRx SignalStore for state management
39
- └── ui/
40
- └── component.ts # Standalone Angular component with store injection
41
- ```
42
-
43
- ### Naming Conventions
44
-
45
- The generator automatically handles naming:
46
- - **Input**: kebab-case (e.g., `user-profile`)
47
- - **Classes/Interfaces**: PascalCase (e.g., `UserProfileComponent`, `UserProfile`)
48
- - **Stores**: PascalCase with "Store" suffix (e.g., `UserProfileStore`)
49
- - **Services**: PascalCase with "Service" suffix (e.g., `UserProfileService`)
50
-
51
- ### Example Generated Code
52
-
53
- For `npm run generate:feature -- --name=product`:
54
-
55
- **Domain Model** (`domain/model.ts`):
56
- ```typescript
57
- export interface Product {
58
- id: string;
59
- createdAt: Date;
60
- updatedAt: Date;
61
- }
62
- ```
63
-
64
- **Infrastructure Service** (`infrastructure/service.ts`):
65
- ```typescript
66
- @Injectable({ providedIn: 'root' })
67
- export class ProductService {
68
- private readonly apiUrl = '/api/products';
69
-
70
- getAll(): Observable<Product[]> { ... }
71
- getById(id: string): Observable<Product> { ... }
72
- create(data: Omit<Product, 'id' | 'createdAt' | 'updatedAt'>): Observable<Product> { ... }
73
- update(id: string, data: Partial<Product>): Observable<Product> { ... }
74
- delete(id: string): Observable<void> { ... }
75
- }
76
- ```
77
-
78
- **Application Store** (`application/store.ts`):
79
- ```typescript
80
- export const ProductStore = signalStore(
81
- { providedIn: 'root' },
82
- withState({ loading: false })
83
- );
84
- ```
85
-
86
- **UI Component** (`ui/component.ts`):
87
- ```typescript
88
- @Component({
89
- selector: 'app-product-feature',
90
- standalone: true,
91
- imports: [CommonModule],
92
- template: `
93
- <div class="product-feature">
94
- <h1>Product Feature</h1>
95
- @if (store.loading()) {
96
- <p>Loading...</p>
97
- } @else {
98
- <p>Ready to build your product feature!</p>
99
- }
100
- </div>
101
- `,
102
- })
103
- export class ProductComponent {
104
- protected readonly store = inject(ProductStore);
105
- }
106
- ```
107
-
108
- ## Template Structure
109
-
110
- Templates are located in `src/generators/clean-feature/files/`:
111
-
112
- ```
113
- files/
114
- ├── application/
115
- │ └── store.ts.template # SignalStore template
116
- ├── domain/
117
- │ └── model.ts.template # Interface template
118
- ├── infrastructure/
119
- │ └── service.ts.template # Service template with CRUD
120
- └── ui/
121
- └── component.ts.template # Component template with store
122
- ```
123
-
124
- Templates use EJS syntax:
125
- - `<%= name %>` - Original kebab-case feature name
126
- - `<%= pascalName %>` - PascalCase version of the name
127
-
128
- ## Development
129
-
130
- ### Build the CLI
131
-
132
- ```bash
133
- npm run cli:build
134
- ```
135
-
136
- ### Test the CLI
137
-
138
- ```bash
139
- npm run cli:test
140
- ```
141
-
142
- ### Lint the CLI
143
-
144
- ```bash
145
- npm run cli:lint
146
- ```
147
-
148
- ### Development Workflow
149
-
150
- 1. **Modify templates** in `src/generators/clean-feature/files/`
151
- 2. **Update generator logic** in `generator.ts` if needed
152
- 3. **Build**: `npm run cli:build`
153
- 4. **Test**: Generate a feature with `npm run generate:feature -- --name=test`
154
- 5. **Verify**: Check generated code in `apps/sandbox/src/app/features/test`
155
- 6. **Clean up**: Delete test feature after verification
156
-
157
- ### Adding New Template Variables
158
-
159
- To add new template variables:
160
-
161
- 1. Update `generator.ts`:
162
- ```typescript
163
- generateFiles(tree, ..., targetPath, {
164
- ...options,
165
- name,
166
- pascalName,
167
- yourNewVariable: computeValue(name), // Add here
168
- tmpl: '',
169
- });
170
- ```
171
-
172
- 2. Use in templates:
173
- ```typescript
174
- // In any .template file
175
- export class <%= yourNewVariable %>Something { }
176
- ```
177
-
178
- ## Tips
179
-
180
- - **Feature naming**: Use kebab-case for multi-word features (e.g., `user-profile`, not `userProfile`)
181
- - **Testing**: Always test generated code in the sandbox app
182
- - **Customization**: Modify templates to match your team's conventions
183
- - **Validation**: Consider adding name validation in `generator.ts` to prevent duplicates