@barcidev/ngx-autogen 0.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.
@@ -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 config = entityConfig({
29
+ entity: type<<%= classify(name) %>Dto>(),
30
+ selectId: (entity) => entity.<%= pk %>,
31
+ });
32
+
33
+ export const <%= classify(name) %>Store = signalStore(
34
+ withEntities(config),
35
+ withState({
36
+ _status: initialStatus,
37
+ }),
38
+ withComputed(({ entityMap, _status }) => ({
39
+ <%= camelize(pluralize(name)) %>: computed(() => Object.values(entityMap())),
40
+ <%= camelize(name) %>Seleccionado: computed(() => {
41
+ const <%= pk %> = _status().idSelected;
42
+ return <%= pk %> ? entityMap()[<%= pk %>] : null;
43
+ }),
44
+ error: computed(() => _status().error),
45
+ loaded: computed(() => _status().loaded),
46
+ loading: computed(() => _status().loading),
47
+ loadingRemove: computed(
48
+ () => (<%= pk %>?: number) =>
49
+ (<%= pk %> ? _status().idsRemoving?.includes(<%= pk %>) : _status().removeLoading) || false
50
+ ),
51
+ loadingUpdate: computed(
52
+ () => (<%= pk %>?: number) =>
53
+ (<%= pk %> ? _status().idsUpdating?.includes(<%= pk %>) : _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, { _status: { ...store._status(), addLoading: true } });
61
+ }),
62
+ switchMap((entity) => {
63
+ return <%= camelize(name) %>Service.add<%= classify(name) %>$(entity).pipe(
64
+ tap((<%= pk %>) => {
65
+ patchState(store, addEntity({ ...entity, <%= pk %> }, config), {
66
+ _status: {
67
+ ...store._status(),
68
+ addLoading: false,
69
+ error: null,
70
+ },
71
+ });
72
+ }),
73
+ catchError(() => {
74
+ patchState(store, {
75
+ _status: {
76
+ ...store._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, { _status: { ...store._status(), loading: true } });
91
+ }),
92
+ switchMap(() => {
93
+ return <%= camelize(name) %>Service.get<%= classify(pluralize(name)) %>$().pipe(
94
+ tap((response) => {
95
+ patchState(store, setAllEntities(response, config), {
96
+ _status: {
97
+ ...store._status(),
98
+ error: null,
99
+ loaded: true,
100
+ loading: false,
101
+ },
102
+ });
103
+ }),
104
+ catchError(() => {
105
+ patchState(store, {
106
+ _status: {
107
+ ...store._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((<%= pk %>) => {
121
+ patchState(store, {
122
+ _status: {
123
+ ...store._status(),
124
+ removeLoading: true,
125
+ idsRemoving: [...(store._status().idsRemoving || []), <%= pk %>],
126
+ },
127
+ });
128
+ }),
129
+ switchMap((<%= pk %>) => {
130
+ return <%= camelize(name) %>Service.remove<%= classify(name) %>$(<%= pk %>).pipe(
131
+ tap((success) => {
132
+ if (success) {
133
+ const idsRemoving = store._status().idsRemoving || [];
134
+ patchState(store, removeEntity(<%= pk %>), {
135
+ _status: {
136
+ ...store._status(),
137
+ removeLoading: false,
138
+ error: null,
139
+ idsRemoving: idsRemoving.filter((idRemoving) => idRemoving !== <%= pk %>),
140
+ },
141
+ });
142
+ } else {
143
+ throw new Error('Error al eliminar <%= name %>');
144
+ }
145
+ }),
146
+ catchError(() => {
147
+ const idsRemoving = store._status().idsRemoving || [];
148
+ patchState(store, {
149
+ _status: {
150
+ ...store._status(),
151
+ removeLoading: false,
152
+ error: new Error('Error al eliminar <%= name %>'),
153
+ idsRemoving: idsRemoving.filter((idRemoving) => idRemoving !== <%= pk %>),
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
+ _status: {
167
+ ...store._status(),
168
+ idsUpdating: [...(store._status().idsUpdating || []), entity.<%= pk %>],
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._status().idsUpdating || [];
178
+ patchState(store, updateEntity({ changes: entity, id: entity.<%= pk %> }, config), {
179
+ _status: {
180
+ ...store._status(),
181
+ error: null,
182
+ idsUpdating: idsUpdating.filter((idUpdating) => idUpdating !== entity.<%= pk %>),
183
+ updateLoading: false,
184
+ },
185
+ });
186
+ } else {
187
+ throw new Error('Error al actualizar <%= name %>');
188
+ }
189
+ }),
190
+ catchError(() => {
191
+ const idsUpdating = store._status().idsUpdating || [];
192
+ patchState(store, {
193
+ _status: {
194
+ ...store._status(),
195
+ error: new Error('Error al actualizar <%= name %>'),
196
+ idsUpdating: idsUpdating.filter((idUpdating) => idUpdating !== entity.<%= pk %>),
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
+ );
@@ -0,0 +1,3 @@
1
+ import { Rule } from "@angular-devkit/schematics";
2
+ import { StoreSchemaOptions } from "./schema";
3
+ export declare function signalStore(options: StoreSchemaOptions): Rule;
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.signalStore = signalStore;
13
+ const core_1 = require("@angular-devkit/core");
14
+ const schematics_1 = require("@angular-devkit/schematics");
15
+ const workspace_1 = require("@schematics/angular/utility/workspace");
16
+ const pluralizeEs = (name) => {
17
+ if (!name)
18
+ return name;
19
+ const lastChar = name.slice(-1).toLowerCase();
20
+ const vowels = ["a", "e", "i", "o", "u"];
21
+ if (vowels.includes(lastChar))
22
+ return name + "s";
23
+ if (lastChar === "z")
24
+ return name.slice(0, -1) + "ces";
25
+ return name + "es";
26
+ };
27
+ const pluralizeEn = (name) => {
28
+ if (!name)
29
+ return name;
30
+ const lastChar = name.slice(-1).toLowerCase();
31
+ const vowels = ["a", "e", "i", "o", "u"];
32
+ if (lastChar === "y" && !vowels.includes(name.slice(-2, -1).toLowerCase())) {
33
+ return name.slice(0, -1) + "ies";
34
+ }
35
+ if (["s", "x", "z", "ch", "sh"].some((end) => name.toLowerCase().endsWith(end))) {
36
+ return name + "es";
37
+ }
38
+ return name + "s";
39
+ };
40
+ function mergeFilesSmart(urlPath, destPath, options) {
41
+ return (0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)(urlPath), [
42
+ (0, schematics_1.applyTemplates)(Object.assign(Object.assign({}, core_1.strings), options)),
43
+ (0, schematics_1.move)(destPath),
44
+ (0, schematics_1.forEach)((fileEntry) => {
45
+ // Si el archivo ya existe en el árbol
46
+ if (treeRef.exists(fileEntry.path)) {
47
+ const existingContent = treeRef.read(fileEntry.path).toString();
48
+ const newContent = fileEntry.content.toString();
49
+ // Solo escribimos si el contenido nuevo no está ya incluido (basado en una cadena clave o firma)
50
+ // Puedes ajustar esta condición según lo que necesites verificar
51
+ if (existingContent.includes(newContent.trim())) {
52
+ return null; // Descarta el archivo del proceso de merge (no hace nada)
53
+ }
54
+ // Si el archivo existe pero queremos añadir contenido al final (opcional)
55
+ // treeRef.overwrite(fileEntry.path, existingContent + '\n' + newContent);
56
+ return null;
57
+ }
58
+ return fileEntry;
59
+ }),
60
+ ]));
61
+ }
62
+ let treeRef;
63
+ function signalStore(options) {
64
+ return (tree) => __awaiter(this, void 0, void 0, function* () {
65
+ var _a;
66
+ const workspace = yield (0, workspace_1.getWorkspace)(tree);
67
+ const globalConfig = (_a = workspace.extensions.schematics) === null || _a === void 0 ? void 0 : _a["ngx-autogen:all"];
68
+ if (globalConfig && globalConfig.pk && !options.pk) {
69
+ options.pk = globalConfig.pk;
70
+ }
71
+ treeRef = tree;
72
+ const movePath = (0, core_1.normalize)(options.path);
73
+ const indexPath = (0, core_1.join)(movePath, "index.ts");
74
+ const nameDash = core_1.strings.dasherize(options.name);
75
+ const entityName = core_1.strings.classify(options.name);
76
+ const entityHeader = `/* ${entityName.toUpperCase()} */`;
77
+ const exportBlock = [
78
+ entityHeader,
79
+ `export * from './${nameDash}/${nameDash}.model';`,
80
+ `export * from './${nameDash}/${nameDash}.service';`,
81
+ `export * from './${nameDash}/${nameDash}.store';`,
82
+ "",
83
+ ].join("\n");
84
+ let content = "";
85
+ if (tree.exists(indexPath)) {
86
+ content = tree.read(indexPath).toString();
87
+ }
88
+ if (content.includes(entityHeader)) {
89
+ const lines = exportBlock.split("\n");
90
+ lines.forEach((line) => {
91
+ if (line.trim() !== "" && !content.includes(line)) {
92
+ content += line + "\n";
93
+ }
94
+ });
95
+ }
96
+ else {
97
+ content =
98
+ content.trim() + (content.length > 0 ? "\n\n" : "") + exportBlock;
99
+ }
100
+ if (tree.exists(indexPath)) {
101
+ tree.overwrite(indexPath, content);
102
+ }
103
+ else {
104
+ tree.create(indexPath, content);
105
+ }
106
+ const templateStoreSource = (0, schematics_1.apply)((0, schematics_1.url)("./files/store"), [
107
+ (0, schematics_1.applyTemplates)(Object.assign(Object.assign(Object.assign({}, core_1.strings), options), { pluralize: (word) => {
108
+ switch (options.lang) {
109
+ case "es":
110
+ return pluralizeEs(word);
111
+ default:
112
+ return pluralizeEn(word);
113
+ }
114
+ }, pk: options.pk || "id" })),
115
+ (0, schematics_1.move)((0, core_1.join)(movePath, core_1.strings.dasherize(options.name))),
116
+ ]);
117
+ const commonEntityRule = mergeFilesSmart("./files/entity", (0, core_1.join)(movePath, "common/entity"), options);
118
+ return (0, schematics_1.chain)([(0, schematics_1.mergeWith)(templateStoreSource), commonEntityRule]);
119
+ });
120
+ }
121
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,6 @@
1
+ export interface StoreSchemaOptions {
2
+ name: string;
3
+ path: string;
4
+ pk?: string;
5
+ lang: "en" | "es";
6
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "$id": "SignalStoreSchematic",
4
+ "title": "Signal Store Schema",
5
+ "type": "object",
6
+ "properties": {
7
+ "name": {
8
+ "type": "string",
9
+ "description": "Name of the entity.",
10
+ "x-prompt": "What's the name of the entity?",
11
+ "priority": 1
12
+ },
13
+ "path": {
14
+ "type": "string",
15
+ "description": "Destination path.",
16
+ "default": "src/app/core"
17
+ },
18
+ "lang": {
19
+ "type": "string",
20
+ "description": "Language for pluralization ('en' for English, 'es' for Spanish).",
21
+ "enum": ["en", "es"],
22
+ "default": "en"
23
+ },
24
+ "pk": {
25
+ "type": "string",
26
+ "description": "Name of the primary key."
27
+ }
28
+ },
29
+ "required": ["name"]
30
+ }