Skip to content

Commit 05efac6

Browse files
committed
feat(ui): add new UI library schematic
1 parent 7dbc4f1 commit 05efac6

File tree

6 files changed

+186
-2
lines changed

6 files changed

+186
-2
lines changed

libs/ddd/collection.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@
1616
"factory": "./src/schematics/feature/index",
1717
"schema": "./src/schematics/feature/schema.json",
1818
"description": "adds a feature lib to a domain"
19+
},
20+
"ui": {
21+
"factory": "./src/schematics/ui/ui",
22+
"schema": "./src/schematics/ui/schema.json",
23+
"description": "adds a UI library to a domain or as a shared library"
1924
}
20-
2125
}
22-
}
26+
}

libs/ddd/src/schematics/json-schema-to-ts.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@ toTypeScript
99
.compileFromFile('libs/ddd/src/schematics/feature/schema.json')
1010
.then(ts => fs.writeFileSync('libs/ddd/src/schematics/feature/schema.ts', ts));
1111

12+
13+
toTypeScript
14+
.compileFromFile('libs/ddd/src/schematics/ui/schema.json')
15+
.then(ts => fs.writeFileSync('libs/ddd/src/schematics/ui/schema.ts', ts));
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"$schema": "http://json-schema.org/schema",
3+
"id": "ui-options",
4+
"type": "object",
5+
"properties": {
6+
"name": {
7+
"type": "string",
8+
"description": "Name of the UI library",
9+
"$default": {
10+
"$source": "argv",
11+
"index": 0
12+
}
13+
},
14+
"shared": {
15+
"type": "boolean",
16+
"description": "Whether the library should be shared across all domains.",
17+
"default": false
18+
},
19+
"domain": {
20+
"type": "string",
21+
"description": "Domain name, if the library belongs to a certain domain."
22+
},
23+
"type": {
24+
"type": "string",
25+
"enum": [
26+
"internal",
27+
"buildable",
28+
"publishable"
29+
],
30+
"description": "A type to determine if and how to build the library.",
31+
"default": "buildable"
32+
}
33+
},
34+
"required": [
35+
"name"
36+
]
37+
}

libs/ddd/src/schematics/ui/schema.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/* tslint:disable */
2+
/**
3+
* This file was automatically generated by json-schema-to-typescript.
4+
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
5+
* and run json-schema-to-typescript to regenerate this file.
6+
*/
7+
8+
export interface UiOptions {
9+
/**
10+
* Name of the UI library
11+
*/
12+
name: string;
13+
/**
14+
* Whether the library should be shared across all domains.
15+
*/
16+
shared?: boolean;
17+
/**
18+
* Domain name, if the library belongs to a certain domain.
19+
*/
20+
domain?: string;
21+
/**
22+
* A type to determine if and how to build the library.
23+
*/
24+
type?: "internal" | "buildable" | "publishable";
25+
[k: string]: any;
26+
}

libs/ddd/src/schematics/ui/ui.spec.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { Tree } from '@angular-devkit/schematics';
2+
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
3+
import { NxJson, readJsonInTree } from '@nrwl/workspace';
4+
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
5+
import { join } from 'path';
6+
import { UiOptions } from './schema';
7+
8+
describe('ui', () => {
9+
let appTree: Tree;
10+
11+
const testRunner = new SchematicTestRunner(
12+
'@angular-architects/ddd',
13+
join(__dirname, '../../../collection.json')
14+
);
15+
16+
function runSchematic<SchemaOptions = any>(
17+
schematicName: string,
18+
options: SchemaOptions,
19+
tree: Tree
20+
) {
21+
return testRunner
22+
.runSchematicAsync(schematicName, options, tree)
23+
.toPromise();
24+
}
25+
26+
beforeEach(() => {
27+
appTree = Tree.empty();
28+
appTree = createEmptyWorkspace(appTree);
29+
});
30+
31+
it('should add correct tags if ui lib is shared', async () => {
32+
const tree = await runSchematic<UiOptions>(
33+
'ui',
34+
{ name: 'form-components', shared: true },
35+
appTree
36+
);
37+
38+
const nxJson = readJsonInTree<NxJson>(tree, '/nx.json');
39+
expect(nxJson.projects).toEqual({
40+
'shared-ui-form-components': {
41+
tags: ['domain:shared', 'type:ui']
42+
}
43+
});
44+
});
45+
46+
it('should add correct tags if ui lib belongs to a domain', async () => {
47+
const tree = await runSchematic<UiOptions>(
48+
'ui',
49+
{ name: 'form-components', domain: 'customer' },
50+
appTree
51+
);
52+
53+
const nxJson = readJsonInTree<NxJson>(tree, '/nx.json');
54+
expect(nxJson.projects).toEqual({
55+
'customer-ui-form-components': {
56+
tags: ['domain:customer', 'type:ui']
57+
}
58+
});
59+
});
60+
61+
it('should throw error if neither domain nor shared option is provided', async () => {
62+
const schematicFunc = async () =>
63+
await runSchematic<UiOptions>('ui', { name: 'form-components' }, appTree);
64+
await expect(schematicFunc()).rejects.toThrowError();
65+
});
66+
67+
it('should throw error if domain and shared option is provided', async () => {
68+
const schematicFunc = async () =>
69+
await runSchematic<UiOptions>(
70+
'ui',
71+
{ name: 'form-components', domain: 'customer', shared: true },
72+
appTree
73+
);
74+
await expect(schematicFunc()).rejects.toThrowError();
75+
});
76+
});

libs/ddd/src/schematics/ui/ui.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { strings } from '@angular-devkit/core';
2+
import { chain, externalSchematic, Rule } from '@angular-devkit/schematics';
3+
import { UiOptions } from './schema';
4+
5+
6+
function validateInputs(options: UiOptions): void {
7+
if (options.shared && options.domain) {
8+
throw new Error(`A UI library should either belong to a specific domain or be shared globally.
9+
If you want to share a UI library across multiple specific domains,
10+
consider using an API library. Hence, you should not provide the shared option in combination
11+
with the domain option.`);
12+
}
13+
14+
if (!options.shared && !options.domain) {
15+
throw new Error(`A UI library should either belong to a domain or be shared globally.
16+
Please provide either of these two options: --domain / --shared`);
17+
}
18+
}
19+
20+
export default function(options: UiOptions): Rule {
21+
validateInputs(options);
22+
23+
const libName = strings.dasherize(options.name);
24+
const libDir = options.shared ? "shared" : options.domain;
25+
26+
return chain([
27+
externalSchematic('@nrwl/angular', 'lib', {
28+
name: `ui-${libName}`,
29+
directory: libDir,
30+
tags: `domain:${libDir},type:ui`,
31+
style: 'scss',
32+
prefix: options.name,
33+
publishable: options.type === 'publishable',
34+
buildable: options.type === 'buildable',
35+
})
36+
]);
37+
}

0 commit comments

Comments
 (0)