@ngflow/ng-architect 1.0.0
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/README.md +28 -0
- package/package.json +23 -0
- package/src/collection.json +28 -0
- package/src/ng-architect/files/src/app/features/__featureKebab__/pages/__featureKebab__.page.html +1 -0
- package/src/ng-architect/files/src/app/features/__featureKebab__/pages/__featureKebab__.page.scss +0 -0
- package/src/ng-architect/index.d.ts +2 -0
- package/src/ng-architect/index.js +58 -0
- package/src/ng-architect/index.js.map +1 -0
- package/src/ng-architect/index_spec.d.ts +1 -0
- package/src/ng-architect/index_spec.js +21 -0
- package/src/ng-architect/index_spec.js.map +1 -0
- package/src/ng-architect/schema.json +15 -0
- package/tsconfig.json +23 -0
package/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Getting Started With Schematics
|
|
2
|
+
|
|
3
|
+
This repository is a basic Schematic implementation that serves as a starting point to create and publish Schematics to NPM.
|
|
4
|
+
|
|
5
|
+
### Testing
|
|
6
|
+
|
|
7
|
+
To test locally, install `@angular-devkit/schematics-cli` globally and use the `schematics` command line tool. That tool acts the same as the `generate` command of the Angular CLI, but also has a debug mode.
|
|
8
|
+
|
|
9
|
+
Check the documentation with
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
schematics --help
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Unit Testing
|
|
16
|
+
|
|
17
|
+
`npm run test` will run the unit tests, using Jasmine as a runner and test framework.
|
|
18
|
+
|
|
19
|
+
### Publishing
|
|
20
|
+
|
|
21
|
+
To publish, simply do:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm run build
|
|
25
|
+
npm publish
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
That's it!
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ngflow/ng-architect",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Angular schematics to generate files and maintain clean architecture",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "tsc -p tsconfig.json",
|
|
7
|
+
"test": "npm run build && jasmine src/**/*_spec.js"
|
|
8
|
+
},
|
|
9
|
+
"keywords": ["schematics", "angular", "automation", "architecture"],
|
|
10
|
+
"author": "João Fernandes",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"schematics": "./src/collection.json",
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@angular-devkit/core": "^21.0.4",
|
|
15
|
+
"@angular-devkit/schematics": "^21.0.4"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "^20.17.19",
|
|
19
|
+
"@types/jasmine": "~5.1.0",
|
|
20
|
+
"jasmine": "~5.12.0",
|
|
21
|
+
"typescript": "~5.9.2"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// By default, collection.json is a Loose-format JSON5 format, which means it's loaded using a
|
|
2
|
+
// special loader and you can use comments, as well as single quotes or no-quotes for standard
|
|
3
|
+
// JavaScript identifiers.
|
|
4
|
+
// Note that this is only true for collection.json and it depends on the tooling itself.
|
|
5
|
+
// We read package.json using a require() call, which is standard JSON.
|
|
6
|
+
{
|
|
7
|
+
// This is just to indicate to your IDE that there is a schema for collection.json.
|
|
8
|
+
"$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
|
|
9
|
+
|
|
10
|
+
// Schematics are listed as a map of schematicName => schematicDescription.
|
|
11
|
+
// Each description contains a description field which is required, a factory reference,
|
|
12
|
+
// an extends field and a schema reference.
|
|
13
|
+
// The extends field points to another schematic (either in the same collection or a
|
|
14
|
+
// separate collection using the format collectionName:schematicName).
|
|
15
|
+
// The factory is required, except when using the extends field. Then the factory can
|
|
16
|
+
// overwrite the extended schematic factory.
|
|
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
|
+
},
|
|
23
|
+
"my-extend-schematic": {
|
|
24
|
+
"description": "A schematic that extends another schematic.",
|
|
25
|
+
"extends": "my-full-schematic"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/ng-architect/files/src/app/features/__featureKebab__/pages/__featureKebab__.page.html
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<p><%= featureKebab %> works!</p>
|
package/src/ng-architect/files/src/app/features/__featureKebab__/pages/__featureKebab__.page.scss
ADDED
|
File without changes
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = default_1;
|
|
4
|
+
const schematics_1 = require("@angular-devkit/schematics");
|
|
5
|
+
// Helper functions
|
|
6
|
+
const toKebabCase = (value) => value
|
|
7
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
8
|
+
.replace(/_/g, '-')
|
|
9
|
+
.toLowerCase();
|
|
10
|
+
const toPascalCase = (value) => value
|
|
11
|
+
.split(/[-_]/)
|
|
12
|
+
.map(part => part.charAt(0).toUpperCase() + part.slice(1))
|
|
13
|
+
.join('');
|
|
14
|
+
function default_1(options) {
|
|
15
|
+
const featureKebab = toKebabCase(options.name);
|
|
16
|
+
const featurePascal = toPascalCase(options.name);
|
|
17
|
+
return (0, schematics_1.chain)([
|
|
18
|
+
(_tree, context) => {
|
|
19
|
+
context.logger.info(`✅ Criando feature: ${featurePascal} (${featureKebab})`);
|
|
20
|
+
},
|
|
21
|
+
// Generate files from templates
|
|
22
|
+
(0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)('./files'), [
|
|
23
|
+
(0, schematics_1.filter)(path => !path.endsWith('.swp')),
|
|
24
|
+
(0, schematics_1.template)({
|
|
25
|
+
featureKebab,
|
|
26
|
+
featurePascal,
|
|
27
|
+
}),
|
|
28
|
+
])),
|
|
29
|
+
// Update app.routes.ts if it exists
|
|
30
|
+
(tree, context) => {
|
|
31
|
+
const appRoutesPath = 'src/app/app.routes.ts';
|
|
32
|
+
if (tree.exists(appRoutesPath)) {
|
|
33
|
+
let content = tree.read(appRoutesPath)?.toString('utf-8') || '';
|
|
34
|
+
const routePattern = new RegExp(`path:\\s*['"]${featureKebab}['"]`);
|
|
35
|
+
if (!routePattern.test(content)) {
|
|
36
|
+
const routeBlock = ` {
|
|
37
|
+
path: '${featureKebab}',
|
|
38
|
+
loadChildren: () =>
|
|
39
|
+
import('./features/${featureKebab}/${featureKebab}.routes')
|
|
40
|
+
.then(m => m.${featurePascal}Routes),
|
|
41
|
+
},`;
|
|
42
|
+
// Insert before the closing bracket
|
|
43
|
+
content = content.replace(/\n\];\s*$/, `\n${routeBlock}\n];`);
|
|
44
|
+
tree.overwrite(appRoutesPath, content);
|
|
45
|
+
context.logger.info(`➕ Rota "${featureKebab}" registada em app.routes.ts`);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
context.logger.warn(`ℹ️ Rota "${featureKebab}" já existe em app.routes.ts`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
context.logger.warn('⚠️ app.routes.ts não encontrado, rota não registada automaticamente');
|
|
53
|
+
}
|
|
54
|
+
return tree;
|
|
55
|
+
},
|
|
56
|
+
]);
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;AAyBA,4BAkDC;AA3ED,2DAUoC;AAEpC,mBAAmB;AACnB,MAAM,WAAW,GAAG,CAAC,KAAa,EAAU,EAAE,CAC5C,KAAK;KACF,OAAO,CAAC,iBAAiB,EAAE,OAAO,CAAC;KACnC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC;KAClB,WAAW,EAAE,CAAC;AAEnB,MAAM,YAAY,GAAG,CAAC,KAAa,EAAU,EAAE,CAC7C,KAAK;KACF,KAAK,CAAC,MAAM,CAAC;KACb,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;KACzD,IAAI,CAAC,EAAE,CAAC,CAAC;AAEd,mBAAyB,OAAY;IACnC,MAAM,YAAY,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,aAAa,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjD,OAAO,IAAA,kBAAK,EAAC;QACX,CAAC,KAAW,EAAE,OAAyB,EAAE,EAAE;YACzC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,sBAAsB,aAAa,KAAK,YAAY,GAAG,CAAC,CAAC;QAC/E,CAAC;QAED,gCAAgC;QAChC,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;gBACP,YAAY;gBACZ,aAAa;aACd,CAAC;SACH,CAAC,CACH;QAED,oCAAoC;QACpC,CAAC,IAAU,EAAE,OAAyB,EAAE,EAAE;YACxC,MAAM,aAAa,GAAG,uBAAuB,CAAC;YAE9C,IAAI,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;gBAC/B,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;gBAEhE,MAAM,YAAY,GAAG,IAAI,MAAM,CAAC,gBAAgB,YAAY,MAAM,CAAC,CAAC;gBACpE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;oBAChC,MAAM,UAAU,GAAG;aAChB,YAAY;;2BAEE,YAAY,IAAI,YAAY;uBAChC,aAAa;KAC/B,CAAC;oBAEI,oCAAoC;oBACpC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,UAAU,MAAM,CAAC,CAAC;oBAC9D,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;oBACvC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,YAAY,8BAA8B,CAAC,CAAC;gBAC7E,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,YAAY,8BAA8B,CAAC,CAAC;gBAC9E,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,qEAAqE,CAAC,CAAC;YAC7F,CAAC;YAED,OAAO,IAAI,CAAC;QACd,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const schematics_1 = require("@angular-devkit/schematics");
|
|
4
|
+
const testing_1 = require("@angular-devkit/schematics/testing");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
// SchematicTestRunner needs an absolute path to the collection to test.
|
|
7
|
+
const collectionPath = path.join(__dirname, '../collection.json');
|
|
8
|
+
describe('my-full-schematic', () => {
|
|
9
|
+
it('requires required option', async () => {
|
|
10
|
+
// We test that
|
|
11
|
+
const runner = new testing_1.SchematicTestRunner('schematics', collectionPath);
|
|
12
|
+
await expectAsync(runner.runSchematic('my-full-schematic', {}, schematics_1.Tree.empty())).toBeRejected();
|
|
13
|
+
});
|
|
14
|
+
it('works', async () => {
|
|
15
|
+
const runner = new testing_1.SchematicTestRunner('schematics', collectionPath);
|
|
16
|
+
const tree = await runner.runSchematic('my-full-schematic', { name: 'str' }, schematics_1.Tree.empty());
|
|
17
|
+
// Listing files
|
|
18
|
+
expect(tree.files.sort()).toEqual(['/allo', '/hola', '/test1', '/test2']);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=index_spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index_spec.js","sourceRoot":"","sources":["index_spec.ts"],"names":[],"mappings":";;AAAA,2DAAkD;AAClD,gEAAyE;AACzE,6BAA6B;AAE7B,wEAAwE;AACxE,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;AAElE,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;QACxC,eAAe;QACf,MAAM,MAAM,GAAG,IAAI,6BAAmB,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;QACrE,MAAM,WAAW,CACf,MAAM,CAAC,YAAY,CAAC,mBAAmB,EAAE,EAAE,EAAE,iBAAI,CAAC,KAAK,EAAE,CAAC,CAC3D,CAAC,YAAY,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE;QACrB,MAAM,MAAM,GAAG,IAAI,6BAAmB,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;QACrE,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,mBAAmB,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,iBAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAE3F,gBAAgB;QAChB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema",
|
|
3
|
+
"$id": "MyFullSchematicsSchema",
|
|
4
|
+
"title": "Angular Feature Generator",
|
|
5
|
+
"description": "Generates a complete Angular feature with pages, services, store, models and routes",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"name": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "The name of the feature (e.g., user-profile, product-list)",
|
|
11
|
+
"minLength": 1
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"required": ["name"]
|
|
15
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"baseUrl": "tsconfig",
|
|
4
|
+
"lib": ["es2018", "dom"],
|
|
5
|
+
"module": "commonjs",
|
|
6
|
+
"moduleResolution": "node",
|
|
7
|
+
"noEmitOnError": true,
|
|
8
|
+
"noFallthroughCasesInSwitch": true,
|
|
9
|
+
"noImplicitAny": true,
|
|
10
|
+
"noImplicitThis": true,
|
|
11
|
+
"noUnusedParameters": true,
|
|
12
|
+
"noUnusedLocals": true,
|
|
13
|
+
"rootDir": "src/",
|
|
14
|
+
"skipDefaultLibCheck": true,
|
|
15
|
+
"skipLibCheck": true,
|
|
16
|
+
"sourceMap": true,
|
|
17
|
+
"strictNullChecks": true,
|
|
18
|
+
"target": "es6",
|
|
19
|
+
"types": ["jasmine", "node"]
|
|
20
|
+
},
|
|
21
|
+
"include": ["src/**/*"],
|
|
22
|
+
"exclude": ["src/*/files/**/*"]
|
|
23
|
+
}
|