@devstroupe/devkit-cli 1.0.1 → 1.1.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/dist/boilerplates/angular-template/src/app/services/user.service.ts +12 -0
- package/dist/boilerplates/nest-template/src/app.module.ts +23 -0
- package/dist/boilerplates/nest-template/src/database/migrations/1600000000000-create-roles.ts +20 -0
- package/dist/boilerplates/nest-template/src/database/migrations/1700000000000-create-users.ts +13 -2
- package/dist/boilerplates/nest-template/src/modules/auth/auth.controller.ts +16 -0
- package/dist/boilerplates/nest-template/src/modules/auth/auth.service.ts +44 -5
- package/dist/boilerplates/nest-template/src/modules/storage/infra/http/storage-download.controller.ts +38 -0
- package/dist/boilerplates/nest-template/src/modules/storage/storage.module.ts +7 -0
- package/dist/boilerplates/nest-template/src/modules/user/database-seed.service.ts +31 -18
- package/dist/boilerplates/nest-template/src/modules/user/domain/user.repository.ts +1 -0
- package/dist/boilerplates/nest-template/src/modules/user/domain/user.ts +1 -0
- package/dist/boilerplates/nest-template/src/modules/user/infra/database/user.orm-entity.ts +3 -0
- package/dist/boilerplates/nest-template/src/modules/user/infra/database/user.repository.adapter.ts +6 -0
- package/dist/boilerplates/nest-template/src/modules/user/infra/http/user.controller.ts +56 -0
- package/dist/boilerplates/nest-template/src/modules/user/service/user.service.ts +4 -0
- package/dist/boilerplates/nest-template/src/modules/user/user.module.ts +2 -0
- package/dist/index.js +24 -3
- package/dist/templates/angular/form.template.js +85 -9
- package/dist/templates/angular/list.template.js +27 -5
- package/dist/templates/nest/crud.templates.d.ts +16 -2
- package/dist/templates/nest/crud.templates.js +175 -13
- package/dist/templates/nest/migration.template.js +82 -6
- package/dist/templates/shared/relationships.js +7 -4
- package/dist/templates/ui/components/index.d.ts +1 -0
- package/dist/templates/ui/components/index.js +1 -0
- package/dist/templates/ui/components/input.template.js +17 -9
- package/dist/templates/ui/components/textarea.template.d.ts +4 -0
- package/dist/templates/ui/components/textarea.template.js +76 -0
- package/package.json +3 -3
|
@@ -17,17 +17,19 @@ function normalizeRelationship(property) {
|
|
|
17
17
|
throw new Error(`Relationship property "${property.name}" must define relation.target.`);
|
|
18
18
|
}
|
|
19
19
|
const config = property.relation;
|
|
20
|
+
const rawTarget = config.target;
|
|
21
|
+
const target = rawTarget.startsWith('$') ? rawTarget.slice(1) : rawTarget;
|
|
20
22
|
const kind = config.kind ?? 'many-to-one';
|
|
21
23
|
const collection = isCollectionRelationship(kind);
|
|
22
24
|
const relationName = config.relationName
|
|
23
|
-
?? (collection ? property.name :
|
|
25
|
+
?? (collection ? property.name : target);
|
|
24
26
|
const control = config.control
|
|
25
27
|
?? (kind === 'one-to-many' ? 'table' : kind === 'many-to-many' ? 'multi-select' : 'select');
|
|
26
28
|
const foreignKey = config.foreignKey
|
|
27
29
|
?? (isSingularRelationship(kind) ? property.name : undefined);
|
|
28
30
|
return {
|
|
29
31
|
property,
|
|
30
|
-
target
|
|
32
|
+
target,
|
|
31
33
|
kind,
|
|
32
34
|
control,
|
|
33
35
|
displayField: config.displayField ?? 'name',
|
|
@@ -61,7 +63,8 @@ function validateRelationships(entities) {
|
|
|
61
63
|
if (property.type !== 'relationship')
|
|
62
64
|
continue;
|
|
63
65
|
const relationship = normalizeRelationship(property);
|
|
64
|
-
|
|
66
|
+
const targetIsNative = ['user', 'role'].includes(relationship.target);
|
|
67
|
+
if (!entityNames.has(relationship.target) && !targetIsNative) {
|
|
65
68
|
throw new Error(`Entity "${entity.name}" relationship "${property.name}" targets unknown entity "${relationship.target}".`);
|
|
66
69
|
}
|
|
67
70
|
if (isSingularRelationship(relationship.kind) && relationship.foreignKey === relationship.relationName) {
|
|
@@ -76,7 +79,7 @@ function validateRelationships(entities) {
|
|
|
76
79
|
if (relationship.kind === 'one-to-many' && !relationship.foreignKey) {
|
|
77
80
|
throw new Error(`Entity "${entity.name}" one-to-many relationship "${property.name}" must define relation.foreignKey.`);
|
|
78
81
|
}
|
|
79
|
-
if (relationship.kind === 'one-to-many') {
|
|
82
|
+
if (relationship.kind === 'one-to-many' && !targetIsNative) {
|
|
80
83
|
const target = entities.find((candidate) => candidate.name === relationship.target);
|
|
81
84
|
const targetHasForeignKey = target?.properties.some((candidate) => candidate.name === relationship.foreignKey
|
|
82
85
|
|| (candidate.type === 'relationship'
|
|
@@ -24,3 +24,4 @@ __exportStar(require("./simple-list.template"), exports);
|
|
|
24
24
|
__exportStar(require("./dialog.template"), exports);
|
|
25
25
|
__exportStar(require("./badge.template"), exports);
|
|
26
26
|
__exportStar(require("./avatar.template"), exports);
|
|
27
|
+
__exportStar(require("./textarea.template"), exports);
|
|
@@ -25,6 +25,7 @@ export class DevkitInputComponent implements ControlValueAccessor {
|
|
|
25
25
|
@Input() label = '';
|
|
26
26
|
@Input() placeholder = '';
|
|
27
27
|
@Input() type = 'text';
|
|
28
|
+
@Input() prefix = '';
|
|
28
29
|
@Input() required = false;
|
|
29
30
|
@Input() disabled = false;
|
|
30
31
|
|
|
@@ -60,15 +61,22 @@ export class DevkitInputComponent implements ControlValueAccessor {
|
|
|
60
61
|
<label *ngIf="label" class="text-xs font-semibold text-muted-foreground">
|
|
61
62
|
{{ label }}<span *ngIf="required" class="text-destructive ml-0.5">*</span>
|
|
62
63
|
</label>
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
64
|
+
<div class="relative flex items-center w-full">
|
|
65
|
+
<span *ngIf="prefix" class="absolute left-3 text-sm text-muted-foreground select-none pointer-events-none">
|
|
66
|
+
{{ prefix }}
|
|
67
|
+
</span>
|
|
68
|
+
<input
|
|
69
|
+
hlmInput
|
|
70
|
+
[type]="type"
|
|
71
|
+
[value]="value"
|
|
72
|
+
[placeholder]="placeholder"
|
|
73
|
+
[disabled]="disabled"
|
|
74
|
+
(input)="onInput($event)"
|
|
75
|
+
(blur)="onTouched()"
|
|
76
|
+
[class.pl-9]="prefix"
|
|
77
|
+
class="w-full"
|
|
78
|
+
/>
|
|
79
|
+
</div>
|
|
72
80
|
</div>
|
|
73
81
|
`
|
|
74
82
|
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.devkitTextareaTemplate = devkitTextareaTemplate;
|
|
4
|
+
function devkitTextareaTemplate() {
|
|
5
|
+
return {
|
|
6
|
+
ts: `import { Component, Input, forwardRef } from '@angular/core';
|
|
7
|
+
import { CommonModule } from '@angular/common';
|
|
8
|
+
import { ControlValueAccessor, NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
|
|
9
|
+
import { HlmInput } from '@spartan-ng/helm/input';
|
|
10
|
+
|
|
11
|
+
@Component({
|
|
12
|
+
selector: 'devkit-textarea',
|
|
13
|
+
standalone: true,
|
|
14
|
+
imports: [CommonModule, FormsModule, HlmInput],
|
|
15
|
+
templateUrl: './textarea.component.html',
|
|
16
|
+
providers: [
|
|
17
|
+
{
|
|
18
|
+
provide: NG_VALUE_ACCESSOR,
|
|
19
|
+
useExisting: forwardRef(() => DevkitTextareaComponent),
|
|
20
|
+
multi: true
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
})
|
|
24
|
+
export class DevkitTextareaComponent implements ControlValueAccessor {
|
|
25
|
+
@Input() label = '';
|
|
26
|
+
@Input() placeholder = '';
|
|
27
|
+
@Input() rows = 3;
|
|
28
|
+
@Input() required = false;
|
|
29
|
+
@Input() disabled = false;
|
|
30
|
+
|
|
31
|
+
value: string = '';
|
|
32
|
+
|
|
33
|
+
onChange: any = () => {};
|
|
34
|
+
onTouched: any = () => {};
|
|
35
|
+
|
|
36
|
+
writeValue(value: any): void {
|
|
37
|
+
this.value = value || '';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
registerOnChange(fn: any): void {
|
|
41
|
+
this.onChange = fn;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
registerOnTouched(fn: any): void {
|
|
45
|
+
this.onTouched = fn;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
setDisabledState(isDisabled: boolean): void {
|
|
49
|
+
this.disabled = isDisabled;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
onInput(event: Event): void {
|
|
53
|
+
const val = (event.target as HTMLTextAreaElement).value;
|
|
54
|
+
this.value = val;
|
|
55
|
+
this.onChange(val);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
`,
|
|
59
|
+
html: `<div class="flex flex-col space-y-1.5 w-full">
|
|
60
|
+
<label *ngIf="label" class="text-xs font-semibold text-muted-foreground">
|
|
61
|
+
{{ label }}<span *ngIf="required" class="text-destructive ml-0.5">*</span>
|
|
62
|
+
</label>
|
|
63
|
+
<textarea
|
|
64
|
+
hlmInput
|
|
65
|
+
[rows]="rows"
|
|
66
|
+
[value]="value"
|
|
67
|
+
[placeholder]="placeholder"
|
|
68
|
+
[disabled]="disabled"
|
|
69
|
+
(input)="onInput($event)"
|
|
70
|
+
(blur)="onTouched()"
|
|
71
|
+
class="min-h-[80px]"
|
|
72
|
+
></textarea>
|
|
73
|
+
</div>
|
|
74
|
+
`
|
|
75
|
+
};
|
|
76
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devstroupe/devkit-cli",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "DevsTroupe Development Kit CLI — scaffold NestJS+Angular projects, inject Spartan UI, generate CRUDs and audit architectural governance",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"devstroupe": "./dist/index.js"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@devstroupe/devkit-core": "^1.0.0",
|
|
38
37
|
"commander": "^12.0.0",
|
|
39
|
-
"fs-extra": "^11.2.0"
|
|
38
|
+
"fs-extra": "^11.2.0",
|
|
39
|
+
"@devstroupe/devkit-core": "1.1.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/fs-extra": "^11.0.4",
|