@ngflow/ng-architect 1.0.3 → 1.0.5

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.
Files changed (33) hide show
  1. package/package.json +9 -4
  2. package/src/collection.json +15 -5
  3. package/src/ng-architect/component/files/__componentKebab__.component.scss +0 -0
  4. package/src/ng-architect/component/files/__componentKebab__.component.ts +0 -0
  5. package/src/ng-architect/component/index.js +18 -0
  6. package/src/ng-architect/component/index.js.map +1 -0
  7. package/src/ng-architect/component/index.ts +27 -0
  8. package/src/ng-architect/component/schema.json +19 -0
  9. package/src/ng-architect/feature/files/src/app/features/__featureKebab__/pages/__featureKebab__.page.scss +0 -0
  10. package/src/ng-architect/feature/index.js +33 -0
  11. package/src/ng-architect/feature/index.js.map +1 -0
  12. package/src/ng-architect/feature/index.ts +47 -0
  13. package/src/ng-architect/{schema.json → feature/schema.json} +1 -1
  14. package/src/ng-architect/service/files/__serviceKebab__/__serviceKebab__.service.ts +27 -0
  15. package/src/ng-architect/service/index.js +1 -0
  16. package/src/ng-architect/service/index.js.map +1 -0
  17. package/src/ng-architect/service/index.ts +0 -0
  18. package/src/ng-architect/service/schema.json +20 -0
  19. package/src/ng-architect/utils/file-utils.js +46 -0
  20. package/src/ng-architect/utils/file-utils.js.map +1 -0
  21. package/src/ng-architect/utils/file-utils.ts +58 -0
  22. package/src/ng-architect/utils/string-utils.js +26 -0
  23. package/src/ng-architect/utils/string-utils.js.map +1 -0
  24. package/src/ng-architect/utils/string-utils.ts +23 -0
  25. package/tsconfig.json +11 -2
  26. package/src/ng-architect/index.ts +0 -76
  27. /package/src/ng-architect/{files/src/app/features/__featureKebab__/pages/__featureKebab__.page.scss → component/files/__componentKebab__.component.html} +0 -0
  28. /package/src/ng-architect/{files → feature/files}/src/app/features/__featureKebab__/__featureKebab__.routes.ts +0 -0
  29. /package/src/ng-architect/{files → feature/files}/src/app/features/__featureKebab__/data/__featureKebab__.service.ts +0 -0
  30. /package/src/ng-architect/{files → feature/files}/src/app/features/__featureKebab__/data/__featureKebab__.store.ts +0 -0
  31. /package/src/ng-architect/{files → feature/files}/src/app/features/__featureKebab__/models/__featureKebab__.model.ts +0 -0
  32. /package/src/ng-architect/{files → feature/files}/src/app/features/__featureKebab__/pages/__featureKebab__.page.html +0 -0
  33. /package/src/ng-architect/{files → feature/files}/src/app/features/__featureKebab__/pages/__featureKebab__.page.ts +0 -0
package/package.json CHANGED
@@ -1,12 +1,17 @@
1
1
  {
2
2
  "name": "@ngflow/ng-architect",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Angular schematics to generate files and maintain clean architecture",
5
5
  "scripts": {
6
6
  "build": "tsc -p tsconfig.json",
7
7
  "test": "npm run build && jasmine src/**/*_spec.js"
8
8
  },
9
- "keywords": ["schematics", "angular", "automation", "architecture"],
9
+ "keywords": [
10
+ "schematics",
11
+ "angular",
12
+ "automation",
13
+ "architecture"
14
+ ],
10
15
  "author": "João Fernandes",
11
16
  "license": "MIT",
12
17
  "schematics": "./src/collection.json",
@@ -15,8 +20,8 @@
15
20
  "@angular-devkit/schematics": "^21.0.4"
16
21
  },
17
22
  "devDependencies": {
18
- "@types/node": "^20.17.19",
19
- "@types/jasmine": "~5.1.0",
23
+ "@types/jasmine": "5.1.13",
24
+ "@types/node": "20.19.27",
20
25
  "jasmine": "~5.12.0",
21
26
  "typescript": "~5.9.2"
22
27
  }
@@ -15,11 +15,21 @@
15
15
  // The factory is required, except when using the extends field. Then the factory can
16
16
  // overwrite the extended schematic factory.
17
17
  "schematics": {
18
- "ng-architect": {
19
- "description": "Gera uma feature Angular completa com rotas e arquivos",
20
- "factory": "./ng-architect/index#default",
21
- "schema": "./ng-architect/schema.json"
22
- },
18
+ "ng-architect": {
19
+ "description": "Gera uma feature Angular completa com rotas e arquivos",
20
+ "factory": "./ng-architect/feature/index#default",
21
+ "schema": "./ng-architect/feature/schema.json"
22
+ },
23
+ "component": {
24
+ "description": "Generate a reusable Angular component",
25
+ "factory": "./ng-architect/component/index",
26
+ "schema": "./ng-architect/component/schema.json"
27
+ },
28
+ "service": {
29
+ "description": "Generate a service with optional store and tests",
30
+ "factory": "./ng-architect/service/index",
31
+ "schema": "./ng-architect/service/schema.json"
32
+ },
23
33
  "my-extend-schematic": {
24
34
  "description": "A schematic that extends another schematic.",
25
35
  "extends": "my-full-schematic"
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = default_1;
4
+ const schematics_1 = require("@angular-devkit/schematics");
5
+ const string_utils_1 = require("../utils/string-utils");
6
+ function default_1(options) {
7
+ const componentKebab = (0, string_utils_1.toKebabCase)(options.name);
8
+ const componentPascal = (0, string_utils_1.toPascalCase)(options.name);
9
+ return (0, schematics_1.chain)([
10
+ (_tree, context) => {
11
+ context.logger.info(`✅ Creating component: ${componentPascal} (${componentKebab})`);
12
+ },
13
+ (0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)('./files'), [
14
+ (0, schematics_1.template)({ componentKebab, componentPascal, module: options.module })
15
+ ]))
16
+ ]);
17
+ }
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;AAYA,4BAcC;AA1BD,2DASoC;AACpC,wDAAkE;AAElE,mBAAwB,OAAY;IAClC,MAAM,cAAc,GAAG,IAAA,0BAAW,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,MAAM,eAAe,GAAG,IAAA,2BAAY,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnD,OAAO,IAAA,kBAAK,EAAC;QACX,CAAC,KAAW,EAAE,OAAyB,EAAE,EAAE;YACzC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,eAAe,KAAK,cAAc,GAAG,CAAC,CAAC;QACtF,CAAC;QACD,IAAA,sBAAS,EACP,IAAA,kBAAK,EAAC,IAAA,gBAAG,EAAC,SAAS,CAAC,EAAE;YACpB,IAAA,qBAAQ,EAAC,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;SACtE,CAAC,CACH;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,27 @@
1
+ import {
2
+ Rule,
3
+ SchematicContext,
4
+ Tree,
5
+ apply,
6
+ chain,
7
+ mergeWith,
8
+ template,
9
+ url
10
+ } from '@angular-devkit/schematics';
11
+ import { toKebabCase, toPascalCase } from '../utils/string-utils';
12
+
13
+ export default function(options: any): Rule {
14
+ const componentKebab = toKebabCase(options.name);
15
+ const componentPascal = toPascalCase(options.name);
16
+
17
+ return chain([
18
+ (_tree: Tree, context: SchematicContext) => {
19
+ context.logger.info(`✅ Creating component: ${componentPascal} (${componentKebab})`);
20
+ },
21
+ mergeWith(
22
+ apply(url('./files'), [
23
+ template({ componentKebab, componentPascal, module: options.module })
24
+ ])
25
+ )
26
+ ]);
27
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema",
3
+ "$id": "ComponentSchema",
4
+ "title": "Angular Component Generator",
5
+ "description": "Generates a reusable Angular component",
6
+ "type": "object",
7
+ "properties": {
8
+ "name": {
9
+ "type": "string",
10
+ "description": "The name of the component (e.g., navbar, footer)",
11
+ "minLength": 1
12
+ },
13
+ "module": {
14
+ "type": "string",
15
+ "description": "Optional: The Angular module to declare this component in"
16
+ }
17
+ },
18
+ "required": ["name"]
19
+ }
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = default_1;
4
+ const schematics_1 = require("@angular-devkit/schematics");
5
+ const string_utils_1 = require("../utils/string-utils");
6
+ const file_utils_1 = require("../utils/file-utils");
7
+ function default_1(options) {
8
+ const featureKebab = (0, string_utils_1.toKebabCase)(options.name);
9
+ const featurePascal = (0, string_utils_1.toPascalCase)(options.name);
10
+ return (0, schematics_1.chain)([
11
+ // Log inicial
12
+ (_tree, context) => {
13
+ context.logger.info(`✅ Creating feature: ${featurePascal} (${featureKebab})`);
14
+ },
15
+ // Gera os arquivos a partir do template
16
+ (0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)('./files'), [
17
+ (0, schematics_1.filter)(path => !path.endsWith('.swp')),
18
+ (0, schematics_1.template)({ featureKebab, featurePascal })
19
+ ])),
20
+ // Atualiza app.routes.ts adicionando a rota
21
+ (tree, context) => {
22
+ (0, file_utils_1.addRoute)(tree, context, featureKebab);
23
+ // Cria barrels automáticos em data, models e pages
24
+ const folders = ['data', 'models', 'pages'];
25
+ folders.forEach(folder => {
26
+ const path = `src/app/features/${featureKebab}/${folder}`;
27
+ (0, file_utils_1.createOrUpdateBarrel)(tree, context, path);
28
+ });
29
+ return tree;
30
+ }
31
+ ]);
32
+ }
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;AAcA,4BAgCC;AA9CD,2DAUoC;AACpC,wDAAkE;AAClE,oDAAqE;AAErE,mBAAyB,OAAyB;IAChD,MAAM,YAAY,GAAG,IAAA,0BAAW,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,aAAa,GAAG,IAAA,2BAAY,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjD,OAAO,IAAA,kBAAK,EAAC;QACX,cAAc;QACd,CAAC,KAAW,EAAE,OAAyB,EAAE,EAAE;YACzC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,uBAAuB,aAAa,KAAK,YAAY,GAAG,CAAC,CAAC;QAChF,CAAC;QAED,wCAAwC;QACxC,IAAA,sBAAS,EACP,IAAA,kBAAK,EAAC,IAAA,gBAAG,EAAC,SAAS,CAAC,EAAE;YACpB,IAAA,mBAAM,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACtC,IAAA,qBAAQ,EAAC,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC;SAC1C,CAAC,CACH;QAED,4CAA4C;QAC5C,CAAC,IAAU,EAAE,OAAyB,EAAE,EAAE;YACxC,IAAA,qBAAQ,EAAC,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;YAEtC,mDAAmD;YACnD,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC5C,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;gBACvB,MAAM,IAAI,GAAG,oBAAoB,YAAY,IAAI,MAAM,EAAE,CAAC;gBAC1D,IAAA,iCAAoB,EAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;YAC5C,CAAC,CAAC,CAAC;YAEH,OAAO,IAAI,CAAC;QACd,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,47 @@
1
+ import {
2
+ Rule,
3
+ SchematicContext,
4
+ Tree,
5
+ apply,
6
+ chain,
7
+ filter,
8
+ mergeWith,
9
+ template,
10
+ url
11
+ } from '@angular-devkit/schematics';
12
+ import { toKebabCase, toPascalCase } from '../utils/string-utils';
13
+ import { addRoute, createOrUpdateBarrel } from '../utils/file-utils';
14
+
15
+ export default function (options: { name: string }): Rule {
16
+ const featureKebab = toKebabCase(options.name);
17
+ const featurePascal = toPascalCase(options.name);
18
+
19
+ return chain([
20
+ // Log inicial
21
+ (_tree: Tree, context: SchematicContext) => {
22
+ context.logger.info(`✅ Creating feature: ${featurePascal} (${featureKebab})`);
23
+ },
24
+
25
+ // Gera os arquivos a partir do template
26
+ mergeWith(
27
+ apply(url('./files'), [
28
+ filter(path => !path.endsWith('.swp')),
29
+ template({ featureKebab, featurePascal })
30
+ ])
31
+ ),
32
+
33
+ // Atualiza app.routes.ts adicionando a rota
34
+ (tree: Tree, context: SchematicContext) => {
35
+ addRoute(tree, context, featureKebab);
36
+
37
+ // Cria barrels automáticos em data, models e pages
38
+ const folders = ['data', 'models', 'pages'];
39
+ folders.forEach(folder => {
40
+ const path = `src/app/features/${featureKebab}/${folder}`;
41
+ createOrUpdateBarrel(tree, context, path);
42
+ });
43
+
44
+ return tree;
45
+ }
46
+ ]);
47
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema",
3
- "$id": "MyFullSchematicsSchema",
3
+ "$id": "ngArchitectSchema",
4
4
  "title": "Angular Feature Generator",
5
5
  "description": "Generates a complete Angular feature with pages, services, store, models and routes",
6
6
  "type": "object",
@@ -0,0 +1,27 @@
1
+ import {
2
+ Rule,
3
+ SchematicContext,
4
+ Tree,
5
+ apply,
6
+ chain,
7
+ mergeWith,
8
+ template,
9
+ url
10
+ } from '@angular-devkit/schematics';
11
+ import { toKebabCase, toPascalCase } from '../../../utils/string-utils';
12
+
13
+ export default function(options: any): Rule {
14
+ const serviceKebab = toKebabCase(options.name);
15
+ const servicePascal = toPascalCase(options.name);
16
+
17
+ return chain([
18
+ (tree: Tree, context: SchematicContext) => {
19
+ context.logger.info(`✅ Creating service: ${servicePascal} (${serviceKebab})`);
20
+ },
21
+ mergeWith(
22
+ apply(url('./files'), [
23
+ template({ serviceKebab, servicePascal, store: options.store })
24
+ ])
25
+ )
26
+ ]);
27
+ }
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":""}
File without changes
@@ -0,0 +1,20 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema",
3
+ "$id": "ServiceSchema",
4
+ "title": "Angular Service Generator",
5
+ "description": "Generates an Angular service with optional store and tests",
6
+ "type": "object",
7
+ "properties": {
8
+ "name": {
9
+ "type": "string",
10
+ "description": "The name of the service (e.g., user, auth)",
11
+ "minLength": 1
12
+ },
13
+ "store": {
14
+ "type": "boolean",
15
+ "description": "Whether to generate a store alongside the service",
16
+ "default": false
17
+ }
18
+ },
19
+ "required": ["name"]
20
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addRoute = addRoute;
4
+ exports.createOrUpdateBarrel = createOrUpdateBarrel;
5
+ const string_utils_1 = require("./string-utils");
6
+ /**
7
+ * Atualiza o app.routes.ts adicionando uma nova rota
8
+ */
9
+ function addRoute(tree, context, featureName) {
10
+ var _a;
11
+ const appRoutesPath = 'src/app/app.routes.ts';
12
+ const featureKebab = (0, string_utils_1.toKebabCase)(featureName);
13
+ const featurePascal = (0, string_utils_1.toPascalCase)(featureName);
14
+ if (!tree.exists(appRoutesPath)) {
15
+ context.logger.warn(`⚠️ ${appRoutesPath} não encontrado, rota não registrada`);
16
+ return;
17
+ }
18
+ let content = ((_a = tree.read(appRoutesPath)) === null || _a === void 0 ? void 0 : _a.toString('utf-8')) || '';
19
+ const routePattern = new RegExp(`path:\\s*['"]${featureKebab}['"]`);
20
+ if (routePattern.test(content)) {
21
+ context.logger.warn(`ℹ️ Rota "${featureKebab}" já existe em app.routes.ts`);
22
+ return;
23
+ }
24
+ const routeBlock = ` {
25
+ path: '${featureKebab}',
26
+ loadChildren: () =>
27
+ import('./features/${featureKebab}/${featureKebab}.routes')
28
+ .then(m => m.${featurePascal}Routes),
29
+ },`;
30
+ content = content.replace(/\n\];\s*$/, `\n${routeBlock}\n];`);
31
+ tree.overwrite(appRoutesPath, content);
32
+ context.logger.info(`➕ Rota "${featureKebab}" registrada em app.routes.ts`);
33
+ }
34
+ /**
35
+ * Cria ou atualiza um arquivo barrel (index.ts) em uma pasta
36
+ */
37
+ function createOrUpdateBarrel(tree, context, folderPath) {
38
+ if (!tree.exists(folderPath))
39
+ return;
40
+ const files = tree.getDir(folderPath).subfiles.filter(f => f.endsWith('.ts'));
41
+ const exports = files.map(f => `export * from './${f.replace('.ts', '')}';`).join('\n');
42
+ const barrelPath = `${folderPath}/index.ts`;
43
+ tree.overwrite(barrelPath, exports);
44
+ context.logger.info(`📦 Barrel atualizado em ${folderPath}`);
45
+ }
46
+ //# sourceMappingURL=file-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-utils.js","sourceRoot":"","sources":["file-utils.ts"],"names":[],"mappings":";;AAOA,4BA+BC;AAKD,oDAcC;AAvDD,iDAA2D;AAE3D;;GAEG;AACH,SAAgB,QAAQ,CACtB,IAAU,EACV,OAAyB,EACzB,WAAmB;;IAEnB,MAAM,aAAa,GAAG,uBAAuB,CAAC;IAC9C,MAAM,YAAY,GAAG,IAAA,0BAAW,EAAC,WAAW,CAAC,CAAC;IAC9C,MAAM,aAAa,GAAG,IAAA,2BAAY,EAAC,WAAW,CAAC,CAAC;IAEhD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,aAAa,sCAAsC,CAAC,CAAC;QAC/E,OAAO;IACT,CAAC;IAED,IAAI,OAAO,GAAG,CAAA,MAAA,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,0CAAE,QAAQ,CAAC,OAAO,CAAC,KAAI,EAAE,CAAC;IAChE,MAAM,YAAY,GAAG,IAAI,MAAM,CAAC,gBAAgB,YAAY,MAAM,CAAC,CAAC;IACpE,IAAI,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,YAAY,8BAA8B,CAAC,CAAC;QAC5E,OAAO;IACT,CAAC;IAED,MAAM,UAAU,GAAG;aACR,YAAY;;2BAEE,YAAY,IAAI,YAAY;uBAChC,aAAa;KAC/B,CAAC;IAEJ,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,UAAU,MAAM,CAAC,CAAC;IAC9D,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IACvC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,YAAY,+BAA+B,CAAC,CAAC;AAC9E,CAAC;AAED;;GAEG;AACH,SAAgB,oBAAoB,CAClC,IAAU,EACV,OAAyB,EACzB,UAAkB;IAElB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;QAAE,OAAO;IAErC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9E,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,OAAO,CAAC,KAAK,EAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEvF,MAAM,UAAU,GAAG,GAAG,UAAU,WAAW,CAAC;IAC5C,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAEpC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,2BAA2B,UAAU,EAAE,CAAC,CAAC;AAC/D,CAAC"}
@@ -0,0 +1,58 @@
1
+ // utils/file-utils.ts
2
+ import { Tree, SchematicContext } from '@angular-devkit/schematics';
3
+ import { toPascalCase, toKebabCase } from './string-utils';
4
+
5
+ /**
6
+ * Atualiza o app.routes.ts adicionando uma nova rota
7
+ */
8
+ export function addRoute(
9
+ tree: Tree,
10
+ context: SchematicContext,
11
+ featureName: string
12
+ ) {
13
+ const appRoutesPath = 'src/app/app.routes.ts';
14
+ const featureKebab = toKebabCase(featureName);
15
+ const featurePascal = toPascalCase(featureName);
16
+
17
+ if (!tree.exists(appRoutesPath)) {
18
+ context.logger.warn(`⚠️ ${appRoutesPath} não encontrado, rota não registrada`);
19
+ return;
20
+ }
21
+
22
+ let content = tree.read(appRoutesPath)?.toString('utf-8') || '';
23
+ const routePattern = new RegExp(`path:\\s*['"]${featureKebab}['"]`);
24
+ if (routePattern.test(content)) {
25
+ context.logger.warn(`ℹ️ Rota "${featureKebab}" já existe em app.routes.ts`);
26
+ return;
27
+ }
28
+
29
+ const routeBlock = ` {
30
+ path: '${featureKebab}',
31
+ loadChildren: () =>
32
+ import('./features/${featureKebab}/${featureKebab}.routes')
33
+ .then(m => m.${featurePascal}Routes),
34
+ },`;
35
+
36
+ content = content.replace(/\n\];\s*$/, `\n${routeBlock}\n];`);
37
+ tree.overwrite(appRoutesPath, content);
38
+ context.logger.info(`➕ Rota "${featureKebab}" registrada em app.routes.ts`);
39
+ }
40
+
41
+ /**
42
+ * Cria ou atualiza um arquivo barrel (index.ts) em uma pasta
43
+ */
44
+ export function createOrUpdateBarrel(
45
+ tree: Tree,
46
+ context: SchematicContext,
47
+ folderPath: string
48
+ ) {
49
+ if (!tree.exists(folderPath)) return;
50
+
51
+ const files = tree.getDir(folderPath).subfiles.filter(f => f.endsWith('.ts'));
52
+ const exports = files.map(f => `export * from './${f.replace('.ts','')}';`).join('\n');
53
+
54
+ const barrelPath = `${folderPath}/index.ts`;
55
+ tree.overwrite(barrelPath, exports);
56
+
57
+ context.logger.info(`📦 Barrel atualizado em ${folderPath}`);
58
+ }
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ // utils/string-utils.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.toKebabCase = toKebabCase;
5
+ exports.toPascalCase = toPascalCase;
6
+ /**
7
+ * Converte uma string para kebab-case
8
+ * Ex: "UserProfile" -> "user-profile"
9
+ */
10
+ function toKebabCase(value) {
11
+ return value
12
+ .replace(/([a-z])([A-Z])/g, '$1-$2') // separa camelCase
13
+ .replace(/[\s_]+/g, '-') // substitui espaços ou underscores por "-"
14
+ .toLowerCase();
15
+ }
16
+ /**
17
+ * Converte uma string para PascalCase
18
+ * Ex: "user-profile" -> "UserProfile"
19
+ */
20
+ function toPascalCase(value) {
21
+ return value
22
+ .split(/[-_\s]/)
23
+ .map(part => part.charAt(0).toUpperCase() + part.slice(1))
24
+ .join('');
25
+ }
26
+ //# sourceMappingURL=string-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"string-utils.js","sourceRoot":"","sources":["string-utils.ts"],"names":[],"mappings":";AAAA,wBAAwB;;AAMxB,kCAKC;AAMD,oCAKC;AApBD;;;GAGG;AACH,SAAgB,WAAW,CAAC,KAAa;IACvC,OAAO,KAAK;SACT,OAAO,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC,mBAAmB;SACvD,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAa,2CAA2C;SAC/E,WAAW,EAAE,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,SAAgB,YAAY,CAAC,KAAa;IACxC,OAAO,KAAK;SACT,KAAK,CAAC,QAAQ,CAAC;SACf,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SACzD,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC"}
@@ -0,0 +1,23 @@
1
+ // utils/string-utils.ts
2
+
3
+ /**
4
+ * Converte uma string para kebab-case
5
+ * Ex: "UserProfile" -> "user-profile"
6
+ */
7
+ export function toKebabCase(value: string): string {
8
+ return value
9
+ .replace(/([a-z])([A-Z])/g, '$1-$2') // separa camelCase
10
+ .replace(/[\s_]+/g, '-') // substitui espaços ou underscores por "-"
11
+ .toLowerCase();
12
+ }
13
+
14
+ /**
15
+ * Converte uma string para PascalCase
16
+ * Ex: "user-profile" -> "UserProfile"
17
+ */
18
+ export function toPascalCase(value: string): string {
19
+ return value
20
+ .split(/[-_\s]/)
21
+ .map(part => part.charAt(0).toUpperCase() + part.slice(1))
22
+ .join('');
23
+ }
package/tsconfig.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "baseUrl": "tsconfig",
3
+ "baseUrl": ".",
4
4
  "lib": ["es2018", "dom"],
5
5
  "module": "commonjs",
6
6
  "moduleResolution": "node",
@@ -19,5 +19,14 @@
19
19
  "types": ["jasmine", "node"]
20
20
  },
21
21
  "include": ["src/**/*.ts"],
22
- "exclude": ["src/*/files/**/*"]
22
+ "exclude": [
23
+ "node_modules",
24
+ "dist",
25
+ "src/**/*.spec.ts",
26
+ "src/ng-architect/feature/files/**/*",
27
+ "src/ng-architect/component/files/**/*",
28
+ "src/ng-architect/service/files/**/*"
29
+ ]
30
+
31
+
23
32
  }
@@ -1,76 +0,0 @@
1
- import {
2
- Rule,
3
- SchematicContext,
4
- Tree,
5
- apply,
6
- chain,
7
- filter,
8
- mergeWith,
9
- template,
10
- url,
11
- } from '@angular-devkit/schematics';
12
-
13
- // Helper functions
14
- const toKebabCase = (value: string): string =>
15
- value
16
- .replace(/([a-z])([A-Z])/g, '$1-$2')
17
- .replace(/_/g, '-')
18
- .toLowerCase();
19
-
20
- const toPascalCase = (value: string): string =>
21
- value
22
- .split(/[-_]/)
23
- .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
24
- .join('');
25
-
26
- export default function (options: any): Rule {
27
- const featureKebab = toKebabCase(options.name);
28
- const featurePascal = toPascalCase(options.name);
29
-
30
- return chain([
31
- (_tree: Tree, context: SchematicContext) => {
32
- context.logger.info(`✅ Criando feature: ${featurePascal} (${featureKebab})`);
33
- },
34
-
35
- // Generate files from templates
36
- mergeWith(
37
- apply(url('./files'), [
38
- filter((path) => !path.endsWith('.swp')),
39
- template({
40
- featureKebab,
41
- featurePascal,
42
- }),
43
- ])
44
- ),
45
-
46
- // Update app.routes.ts if it exists
47
- (tree: Tree, context: SchematicContext) => {
48
- const appRoutesPath = 'src/app/app.routes.ts';
49
-
50
- if (tree.exists(appRoutesPath)) {
51
- let content = tree.read(appRoutesPath)?.toString('utf-8') || '';
52
-
53
- const routePattern = new RegExp(`path:\\s*['"]${featureKebab}['"]`);
54
- if (!routePattern.test(content)) {
55
- const routeBlock = ` {
56
- path: '${featureKebab}',
57
- loadChildren: () =>
58
- import('./features/${featureKebab}/${featureKebab}.routes')
59
- .then(m => m.${featurePascal}Routes),
60
- },`;
61
-
62
- // Insert before the closing bracket
63
- content = content.replace(/\n\];\s*$/, `\n${routeBlock}\n];`);
64
- tree.overwrite(appRoutesPath, content);
65
- context.logger.info(`➕ Rota "${featureKebab}" registada em app.routes.ts`);
66
- } else {
67
- context.logger.warn(`ℹ️ Rota "${featureKebab}" já existe em app.routes.ts`);
68
- }
69
- } else {
70
- context.logger.warn('⚠️ app.routes.ts não encontrado, rota não registada automaticamente');
71
- }
72
-
73
- return tree;
74
- },
75
- ]);
76
- }