ngx-essentials-schematics 0.0.3 → 0.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ngx-essentials-schematics",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "A collection of Angular schematics for essential functionalities.",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -24,11 +24,13 @@
24
24
  "dependencies": {
25
25
  "@angular-devkit/core": "^20.3.13",
26
26
  "@angular-devkit/schematics": "^20.3.13",
27
+ "pluralize": "^8.0.0",
27
28
  "typescript": "~5.9.2"
28
29
  },
29
30
  "devDependencies": {
30
31
  "@types/jasmine": "~5.1.0",
31
32
  "@types/node": "^20.17.19",
33
+ "@types/pluralize": "^0.0.33",
32
34
  "copyfiles": "^2.4.1",
33
35
  "jasmine": "^5.0.0"
34
36
  }
@@ -0,0 +1,16 @@
1
+ export interface EntityStatus {
2
+ addError?: Error | null;
3
+ addLoading?: boolean;
4
+ deleteError?: Error | null;
5
+ deleteLoading?: boolean;
6
+ error: Error | null;
7
+ idsDeleting?: (number | string)[];
8
+ idSelected?: null | number | string;
9
+ idsUpdating?: (number | string)[];
10
+ loaded: boolean;
11
+ loading: boolean;
12
+ selectedError?: Error | null;
13
+ selectedLoading?: boolean;
14
+ updateError?: Error | null;
15
+ updateLoading?: boolean;
16
+ }
@@ -0,0 +1,4 @@
1
+ import { FormControl } from '@angular/forms';
2
+ export type FormGroupType<T> = {
3
+ [K in keyof T]: FormControl<T[K]>;
4
+ };
@@ -0,0 +1,16 @@
1
+ import { FormGroupType } from '../common/form/form.model';
2
+
3
+ export interface Add<%= classify(name) %> {
4
+ nombre: string;
5
+ descripcion?: string;
6
+ }
7
+
8
+ export type Add<%= classify(name) %>Form = FormGroupType<Add<%= classify(name) %>>;
9
+
10
+ export interface <%= classify(name) %>Dto {
11
+ cod: number;
12
+ nombre: string;
13
+ descripcion?: string;
14
+ }
15
+
16
+ export type Update<%= classify(name) %> = Partial<<%= classify(name) %>Dto> & Pick<<%= classify(name) %>Dto, 'cod'>;
@@ -0,0 +1,29 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { Observable, of } from 'rxjs';
3
+ import {
4
+ Add<%= classify(name) %>,
5
+ <%= classify(name) %>Dto,
6
+ Update<%= classify(name) %>
7
+ } from './<%= dasherize(name) %>.model';
8
+
9
+ @Injectable({
10
+ providedIn: 'root'
11
+ })
12
+ export class <%= classify(name) %>Service {
13
+
14
+ add<%= classify(name) %>$(entity: Add<%= classify(name) %>): Observable<number> {
15
+ return of(0);
16
+ }
17
+
18
+ delete<%= classify(name) %>$(cod: number): Observable<boolean> {
19
+ return of(true);
20
+ }
21
+
22
+ get<%= classify(pluralize(name)) %>$(): Observable<<%= classify(name) %>Dto[]> {
23
+ return of([]);
24
+ }
25
+
26
+ update<%= classify(name) %>$(entity: Update<%= classify(name) %>): Observable<boolean> {
27
+ return of(true);
28
+ }
29
+ }
@@ -0,0 +1,212 @@
1
+ import { computed, inject } from '@angular/core';
2
+ import { patchState, signalStore, type, withComputed, withHooks, withMethods, withState } from '@ngrx/signals';
3
+ import {
4
+ addEntity,
5
+ entityConfig,
6
+ removeEntity,
7
+ setAllEntities,
8
+ updateEntity,
9
+ withEntities
10
+ } from '@ngrx/signals/entities';
11
+ import { rxMethod } from '@ngrx/signals/rxjs-interop';
12
+ import { catchError, of, pipe, switchMap, tap } from 'rxjs';
13
+
14
+ import { EntityStatus } from '../common/entity/entity.model';
15
+ import {
16
+ <%= classify(name) %>Dto,
17
+ Add<%= classify(name) %>,
18
+ Update<%= classify(name) %>
19
+ } from './<%= dasherize(name) %>.model';
20
+ import { <%= classify(name) %>Service } from './<%= dasherize(name) %>.service';
21
+
22
+ const initialStatus: EntityStatus = {
23
+ error: null,
24
+ loaded: false,
25
+ loading: false,
26
+ };
27
+
28
+ const <%= camelize(name) %>EntitiesConfig = entityConfig({
29
+ collection: '<%= camelize(name) %>',
30
+ entity: type<<%= classify(name) %>Dto>(),
31
+ selectId: (entity) => entity.cod,
32
+ });
33
+
34
+ export const <%= classify(name) %>Store = signalStore(
35
+ { providedIn: 'root' },
36
+ withEntities(<%= camelize(name) %>EntitiesConfig),
37
+ withState({
38
+ <%= camelize(name) %>Status: initialStatus,
39
+ }),
40
+ withComputed(({ <%= camelize(name) %>EntityMap, <%= camelize(name) %>Status }) => ({
41
+ <%= camelize(name) %>Seleccionado: computed(() => {
42
+ const id = <%= camelize(name) %>Status().idSelected;
43
+ return id ? <%= camelize(name) %>EntityMap()[id] : null;
44
+ }),
45
+ <%= camelize(pluralize(name)) %>: computed(() => Object.values(<%= camelize(name) %>EntityMap())),
46
+ loading<%= classify(pluralize(name)) %>: computed(() => <%= camelize(name) %>Status().loading),
47
+ loadingRemove<%= classify(name) %>: computed(
48
+ () => (cod?: number) =>
49
+ (cod ? <%= camelize(name) %>Status().idsDeleting?.includes(cod) : <%= camelize(name) %>Status().deleteLoading) || false
50
+ ),
51
+ loadingUpdate<%= classify(name) %>: computed(
52
+ () => (cod?: number) =>
53
+ (cod ? <%= camelize(name) %>Status().idsUpdating?.includes(cod) : <%= camelize(name) %>Status().updateLoading) || false
54
+ ),
55
+ })),
56
+ withMethods((store, <%= camelize(name) %>Service = inject(<%= classify(name) %>Service)) => ({
57
+ add<%= classify(name) %>: rxMethod<Add<%= classify(name) %>>(
58
+ pipe(
59
+ tap(() => {
60
+ patchState(store, { <%= camelize(name) %>Status: { ...store.<%= camelize(name) %>Status(), addLoading: true } });
61
+ }),
62
+ switchMap((entity) => {
63
+ return <%= camelize(name) %>Service.add<%= classify(name) %>$(entity).pipe(
64
+ tap((cod) => {
65
+ patchState(store, addEntity({ ...entity, cod }, <%= camelize(name) %>EntitiesConfig), {
66
+ <%= camelize(name) %>Status: {
67
+ ...store.<%= camelize(name) %>Status(),
68
+ addLoading: false,
69
+ error: null,
70
+ },
71
+ });
72
+ }),
73
+ catchError(() => {
74
+ patchState(store, {
75
+ <%= camelize(name) %>Status: {
76
+ ...store.<%= camelize(name) %>Status(),
77
+ addLoading: false,
78
+ error: new Error('Error al agregar <%= name %>'),
79
+ },
80
+ });
81
+ return of(entity);
82
+ })
83
+ );
84
+ })
85
+ )
86
+ ),
87
+ load<%= classify(pluralize(name)) %>: rxMethod<void>(
88
+ pipe(
89
+ tap(() => {
90
+ patchState(store, { <%= camelize(name) %>Status: { ...store.<%= camelize(name) %>Status(), loading: true } });
91
+ }),
92
+ switchMap(() => {
93
+ return <%= camelize(name) %>Service.get<%= classify(pluralize(name)) %>$().pipe(
94
+ tap((response) => {
95
+ patchState(store, setAllEntities(response, <%= camelize(name) %>EntitiesConfig), {
96
+ <%= camelize(name) %>Status: {
97
+ ...store.<%= camelize(name) %>Status(),
98
+ error: null,
99
+ loaded: true,
100
+ loading: false,
101
+ },
102
+ });
103
+ }),
104
+ catchError(() => {
105
+ patchState(store, {
106
+ <%= camelize(name) %>Status: {
107
+ ...store.<%= camelize(name) %>Status(),
108
+ error: new Error('Error al cargar <%= pluralize(name) %>'),
109
+ loading: false,
110
+ },
111
+ });
112
+ return of([]);
113
+ })
114
+ );
115
+ })
116
+ )
117
+ ),
118
+ remove<%= classify(name) %>: rxMethod<number>(
119
+ pipe(
120
+ tap((cod) => {
121
+ patchState(store, {
122
+ <%= camelize(name) %>Status: {
123
+ ...store.<%= camelize(name) %>Status(),
124
+ deleteLoading: true,
125
+ idsDeleting: [...(store.<%= camelize(name) %>Status().idsDeleting || []), cod],
126
+ },
127
+ });
128
+ }),
129
+ switchMap((cod) => {
130
+ return <%= camelize(name) %>Service.delete<%= classify(name) %>$(cod).pipe(
131
+ tap((success) => {
132
+ if (success) {
133
+ const idsDeleting = store.<%= camelize(name) %>Status().idsDeleting || [];
134
+ patchState(store, removeEntity(cod, <%= camelize(name) %>EntitiesConfig), {
135
+ <%= camelize(name) %>Status: {
136
+ ...store.<%= camelize(name) %>Status(),
137
+ deleteLoading: false,
138
+ error: null,
139
+ idsDeleting: idsDeleting.filter((id) => id !== cod),
140
+ },
141
+ });
142
+ } else {
143
+ throw new Error('Error al eliminar <%= name %>');
144
+ }
145
+ }),
146
+ catchError(() => {
147
+ const idsDeleting = store.<%= camelize(name) %>Status().idsDeleting || [];
148
+ patchState(store, {
149
+ <%= camelize(name) %>Status: {
150
+ ...store.<%= camelize(name) %>Status(),
151
+ deleteLoading: false,
152
+ error: new Error('Error al eliminar <%= name %>'),
153
+ idsDeleting: idsDeleting.filter((id) => id !== cod),
154
+ },
155
+ });
156
+ return of(false);
157
+ })
158
+ );
159
+ })
160
+ )
161
+ ),
162
+ update<%= classify(name) %>: rxMethod<Update<%= classify(name) %>>(
163
+ pipe(
164
+ tap((entity) => {
165
+ patchState(store, {
166
+ <%= camelize(name) %>Status: {
167
+ ...store.<%= camelize(name) %>Status(),
168
+ idsUpdating: [...(store.<%= camelize(name) %>Status().idsUpdating || []), entity.cod],
169
+ updateLoading: true,
170
+ },
171
+ });
172
+ }),
173
+ switchMap((entity) => {
174
+ return <%= camelize(name) %>Service.update<%= classify(name) %>$(entity).pipe(
175
+ tap((success) => {
176
+ if (success) {
177
+ const idsUpdating = store.<%= camelize(name) %>Status().idsUpdating || [];
178
+ patchState(store, updateEntity({ changes: entity, id: entity.cod }, <%= camelize(name) %>EntitiesConfig), {
179
+ <%= camelize(name) %>Status: {
180
+ ...store.<%= camelize(name) %>Status(),
181
+ error: null,
182
+ idsUpdating: idsUpdating.filter((id) => id !== entity.cod),
183
+ updateLoading: false,
184
+ },
185
+ });
186
+ } else {
187
+ throw new Error('Error al actualizar <%= name %>');
188
+ }
189
+ }),
190
+ catchError(() => {
191
+ const idsUpdating = store.<%= camelize(name) %>Status().idsUpdating || [];
192
+ patchState(store, {
193
+ <%= camelize(name) %>Status: {
194
+ ...store.<%= camelize(name) %>Status(),
195
+ error: new Error('Error al actualizar <%= name %>'),
196
+ idsUpdating: idsUpdating.filter((id) => id !== entity.cod),
197
+ updateLoading: false,
198
+ },
199
+ });
200
+ return of(false);
201
+ })
202
+ );
203
+ })
204
+ )
205
+ ),
206
+ })),
207
+ withHooks({
208
+ onInit: (store) => {
209
+ store.load<%= classify(pluralize(name)) %>();
210
+ },
211
+ })
212
+ );
@@ -1,5 +1,5 @@
1
- import { Rule } from '@angular-devkit/schematics';
2
- import { SchemaOptions } from './schema';
1
+ import { Rule } from "@angular-devkit/schematics";
2
+ import { SchemaOptions } from "./schema";
3
3
  /**
4
4
  * Genera un Signal Store profesional para Angular 20
5
5
  * @param {SchemaOptions} options - Opciones del esquema
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.signalStore = signalStore;
4
4
  const core_1 = require("@angular-devkit/core");
5
5
  const schematics_1 = require("@angular-devkit/schematics");
6
+ const pluralize = require("pluralize");
6
7
  /**
7
8
  * Genera un Signal Store profesional para Angular 20
8
9
  * @param {SchemaOptions} options - Opciones del esquema
@@ -10,10 +11,10 @@ const schematics_1 = require("@angular-devkit/schematics");
10
11
  */
11
12
  function signalStore(options) {
12
13
  return (tree) => {
13
- const movePath = (0, core_1.normalize)(options.path || 'src/app/state');
14
- // 1. Lógica para actualizar el index.ts (Barrel)
15
- const indexPath = (0, core_1.join)(movePath, 'index.ts');
16
- const exportLine = `export * from './${core_1.strings.dasherize(options.name)}.store';\n`;
14
+ const defaultPath = "src/app/core";
15
+ const movePath = (0, core_1.normalize)(options.path || defaultPath);
16
+ const indexPath = (0, core_1.join)(movePath, "index.ts");
17
+ const exportLine = `export * from './${core_1.strings.dasherize(options.name)}/${core_1.strings.dasherize(options.name)}.store';\n`;
17
18
  if (tree.exists(indexPath)) {
18
19
  const content = tree.read(indexPath).toString();
19
20
  if (!content.includes(exportLine)) {
@@ -23,9 +24,25 @@ function signalStore(options) {
23
24
  else {
24
25
  tree.create(indexPath, exportLine);
25
26
  }
26
- // 2. Lógica de generación del archivo .store.ts
27
- const templateSource = (0, schematics_1.apply)((0, schematics_1.url)('./files'), [(0, schematics_1.applyTemplates)(Object.assign(Object.assign({}, core_1.strings), options)), (0, schematics_1.move)(movePath)]);
28
- return (0, schematics_1.chain)([(0, schematics_1.mergeWith)(templateSource)]);
27
+ const templateEntitySource = (0, schematics_1.apply)((0, schematics_1.url)("./files/entity"), [
28
+ (0, schematics_1.applyTemplates)(Object.assign(Object.assign(Object.assign({}, core_1.strings), options), { pluralize: (word) => {
29
+ return pluralize(word);
30
+ } })),
31
+ (0, schematics_1.move)(defaultPath + "/common/entity"),
32
+ ]);
33
+ const templateFormSource = (0, schematics_1.apply)((0, schematics_1.url)("./files/form"), [
34
+ (0, schematics_1.applyTemplates)(Object.assign(Object.assign({}, core_1.strings), options)),
35
+ (0, schematics_1.move)(defaultPath + "/common/form"),
36
+ ]);
37
+ const templateStoreSource = (0, schematics_1.apply)((0, schematics_1.url)("./files/store"), [
38
+ (0, schematics_1.applyTemplates)(Object.assign(Object.assign({}, core_1.strings), options)),
39
+ (0, schematics_1.move)(movePath + `/${core_1.strings.dasherize(options.name)}`),
40
+ ]);
41
+ return (0, schematics_1.chain)([
42
+ (0, schematics_1.mergeWith)(templateStoreSource),
43
+ (0, schematics_1.mergeWith)(templateEntitySource),
44
+ (0, schematics_1.mergeWith)(templateFormSource),
45
+ ]);
29
46
  };
30
47
  }
31
48
  //# sourceMappingURL=index.js.map
@@ -1,34 +0,0 @@
1
- import { signalStore, withState, withMethods, withComputed, patchState } from '@ngrx/signals';
2
- import { withEntities } from '@ngrx/signals/entities';
3
- import { computed } from '@angular/core';
4
- import { EntityStatus } from '@shared/models/common.model';
5
-
6
- export interface <%= classify(name) %> {
7
- cod: number;
8
- }
9
-
10
- const initialStatus: EntityStatus = {
11
- loading: false,
12
- error: null,
13
- };
14
-
15
- export const <%= classify(name) %>Store = signalStore(
16
- { providedIn: 'root' },
17
- withEntities<<%= classify(name) %>>(),
18
- withState({
19
- status: initialStatus,
20
- selectedId: null as number | null,
21
- }),
22
- withComputed(({ entityMap, selectedId }) => ({
23
- selectedEntity: computed(() => {
24
- const id = selectedId();
25
- return id ? entityMap()[id] : null;
26
- }),
27
- })),
28
- withMethods((store) => ({
29
- setLoading: (loading: boolean) =>
30
- patchState(store, (state) => ({ status: { ...state.status, loading } })),
31
- setError: (error: string | null) =>
32
- patchState(store, (state) => ({ status: { ...state.status, error, loading: false } })),
33
- }))
34
- );