@barcidev/ngx-autogen 0.1.65 → 0.1.67

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.
Files changed (25) hide show
  1. package/{src/ngrx/store/files/entity/entity.model.ts.template → dist/lib/entity/entity.model.d.ts} +4 -6
  2. package/dist/lib/entity/entity.model.js +2 -0
  3. package/dist/lib/entity/index.d.ts +3 -0
  4. package/dist/lib/entity/index.js +4 -0
  5. package/dist/lib/entity/with-entity-pagination.d.ts +34 -0
  6. package/dist/lib/entity/with-entity-pagination.js +47 -0
  7. package/dist/lib/entity/with-entity-status.d.ts +41 -0
  8. package/dist/lib/entity/with-entity-status.js +40 -0
  9. package/package.json +32 -2
  10. package/src/angular/component/files/__name@dasherize__.component.spec.ts.template +2 -2
  11. package/src/angular/component/files/__name@dasherize__.component.ts.template +4 -4
  12. package/src/angular/component/index.js +15 -3
  13. package/src/angular/component/schema.json +10 -0
  14. package/src/angular/component/types/types.d.ts +3 -0
  15. package/src/common/prompts.d.ts +2 -0
  16. package/src/common/prompts.js +35 -0
  17. package/src/ngrx/store/files/state/models/__name@dasherize__.model.ts.template +1 -1
  18. package/src/ngrx/store/files/state/services/__name@dasherize__.service.ts.template +1 -3
  19. package/src/ngrx/store/files/state/store/__name@dasherize__.store.ts.template +23 -6
  20. package/src/ngrx/store/index.js +32 -22
  21. package/src/ngrx/store/schema.json +13 -0
  22. package/src/ngrx/store/types/types.d.ts +1 -0
  23. package/src/transloco/files/component/__name@dasherize__.i18n.ts.template +1 -1
  24. package/src/ngrx/store/files/entity/with-entity-pagination.ts.template +0 -89
  25. package/src/ngrx/store/files/entity/with-entity-status.ts.template +0 -92
@@ -1,12 +1,10 @@
1
1
  import { HttpErrorResponse } from '@angular/common/http';
2
2
  import { FormControl } from '@angular/forms';
3
-
4
3
  export type FormGroupType<T> = {
5
- [K in keyof T]: FormControl<T[K]>;
4
+ [K in keyof T]: FormControl<T[K]>;
6
5
  };
7
-
8
6
  export interface RequestConfig<T, U = unknown> {
9
- onError?: (error?: HttpErrorResponse) => void;
10
- onSuccess?: (response?: U) => void;
11
- payload: T;
7
+ onError?: (error?: HttpErrorResponse) => void;
8
+ onSuccess?: (response?: U) => void;
9
+ payload: T;
12
10
  }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=entity.model.js.map
@@ -0,0 +1,3 @@
1
+ export * from './entity.model';
2
+ export * from './with-entity-pagination';
3
+ export * from './with-entity-status';
@@ -0,0 +1,4 @@
1
+ export * from './entity.model';
2
+ export * from './with-entity-pagination';
3
+ export * from './with-entity-status';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,34 @@
1
+ import { Signal } from '@angular/core';
2
+ import { EmptyFeatureResult, SignalStoreFeature } from '@ngrx/signals';
3
+ export interface PaginationState {
4
+ page: number;
5
+ pageSize: number;
6
+ totalCount: number;
7
+ }
8
+ interface PaginationComputedProps {
9
+ hasNext: boolean;
10
+ hasPrevious: boolean;
11
+ totalPages: number;
12
+ }
13
+ /**
14
+ * Resetea el estado de paginación al estado inicial.
15
+ * @returns {PaginationState} - El estado inicial de paginación.
16
+ */
17
+ export declare function resetPaginationState(): PaginationState;
18
+ /**
19
+ * Agrega funcionalidades de paginación a un Store.
20
+ * @param {[number]} initialPageSize - Tamaño inicial de página (opcional).
21
+ * @returns {SignalStoreFeature} - Características de la tienda con estado, computados y métodos de paginación.
22
+ */
23
+ export declare function withPagination(initialPageSize?: number): SignalStoreFeature<EmptyFeatureResult, {
24
+ methods: {
25
+ nextPage: () => void;
26
+ previousPage: () => void;
27
+ setPage: (page: number) => void;
28
+ setPageSize: (pageSize: number) => void;
29
+ setTotalCount: (totalCount: number) => void;
30
+ };
31
+ props: Record<'paginationComputed', Signal<PaginationComputedProps>>;
32
+ state: Record<'pagination', PaginationState>;
33
+ }>;
34
+ export {};
@@ -0,0 +1,47 @@
1
+ import { computed } from '@angular/core';
2
+ import { patchState, signalStoreFeature, withComputed, withMethods, withState } from '@ngrx/signals';
3
+ const initialPaginationState = {
4
+ page: 1,
5
+ pageSize: 10,
6
+ totalCount: 0
7
+ };
8
+ /**
9
+ * Resetea el estado de paginación al estado inicial.
10
+ * @returns {PaginationState} - El estado inicial de paginación.
11
+ */
12
+ export function resetPaginationState() {
13
+ return initialPaginationState;
14
+ }
15
+ /**
16
+ * Agrega funcionalidades de paginación a un Store.
17
+ * @param {[number]} initialPageSize - Tamaño inicial de página (opcional).
18
+ * @returns {SignalStoreFeature} - Características de la tienda con estado, computados y métodos de paginación.
19
+ */
20
+ export function withPagination(initialPageSize) {
21
+ return signalStoreFeature(withState({
22
+ pagination: initialPageSize ? { ...initialPaginationState, pageSize: initialPageSize } : initialPaginationState
23
+ }), withComputed(({ pagination: { page, pageSize, totalCount } }) => ({
24
+ paginationComputed: computed(() => ({
25
+ hasNext: page() < Math.ceil(totalCount() / pageSize()),
26
+ hasPrevious: page() > 1,
27
+ totalPages: Math.ceil(totalCount() / pageSize())
28
+ }))
29
+ })), withMethods((store) => ({
30
+ nextPage: () => {
31
+ if (store.pagination.page() < Math.ceil(store.pagination.totalCount() / store.pagination.pageSize())) {
32
+ patchState(store, (state) => ({ pagination: { ...state.pagination, page: store.pagination.page() + 1 } }));
33
+ }
34
+ },
35
+ previousPage: () => {
36
+ if (store.pagination.page() > 1) {
37
+ patchState(store, (state) => ({ pagination: { ...state.pagination, page: store.pagination.page() - 1 } }));
38
+ }
39
+ },
40
+ setPage: (page) => {
41
+ patchState(store, (state) => ({ pagination: { ...state.pagination, page } }));
42
+ },
43
+ setPageSize: (pageSize) => patchState(store, (state) => ({ pagination: { ...state.pagination, page: 1, pageSize } })), // Reset a pág 1 si cambia el tamaño
44
+ setTotalCount: (totalCount) => patchState(store, (state) => ({ pagination: { ...state.pagination, totalCount } }))
45
+ })));
46
+ }
47
+ //# sourceMappingURL=with-entity-pagination.js.map
@@ -0,0 +1,41 @@
1
+ import { Signal } from '@angular/core';
2
+ import { EntityId } from '@ngrx/signals/entities';
3
+ import { EmptyFeatureResult, SignalStoreFeature } from '@ngrx/signals';
4
+ export interface EntityStatus {
5
+ _removeLoading: boolean;
6
+ _updateLoading: boolean;
7
+ addError: Error | null;
8
+ addLoading: boolean;
9
+ error: Error | null;
10
+ idSelected: EntityId | null;
11
+ idsRemoving: EntityId[];
12
+ idsUpdating: EntityId[];
13
+ loaded: boolean;
14
+ loading: boolean;
15
+ removeError: Error | null;
16
+ selectedError: Error | null;
17
+ selectedLoading: boolean;
18
+ updateError: Error | null;
19
+ }
20
+ interface EntityStatusComputedProps {
21
+ anyError: Error | null;
22
+ isAnyActionLoading: boolean;
23
+ removeLoading: boolean;
24
+ updateLoading: boolean;
25
+ }
26
+ type EntityStatusMethodProps = Record<string, (...args: unknown[]) => unknown>;
27
+ /**
28
+ * Resetea el estado de la entidad al estado inicial.
29
+ * @returns {EntityStatus} - El estado inicial de la entidad.
30
+ */
31
+ export declare function resetEntityStatus(): EntityStatus;
32
+ /**
33
+ * Agrega funcionalidades comunes de estado y computados para manejar el estado de entidades.
34
+ * @returns {SignalStoreFeature} -Características de la tienda con estado y computados para el manejo de entidades.
35
+ */
36
+ export declare function withEntityStatus(): SignalStoreFeature<EmptyFeatureResult, {
37
+ methods: EntityStatusMethodProps;
38
+ props: Record<'statusComputed', Signal<EntityStatusComputedProps>>;
39
+ state: Record<'status', EntityStatus>;
40
+ }>;
41
+ export {};
@@ -0,0 +1,40 @@
1
+ import { computed } from '@angular/core';
2
+ import { signalStoreFeature, withComputed, withState } from '@ngrx/signals';
3
+ const initialState = {
4
+ _removeLoading: false,
5
+ _updateLoading: false,
6
+ addError: null,
7
+ addLoading: false,
8
+ error: null,
9
+ idSelected: null,
10
+ idsRemoving: [],
11
+ idsUpdating: [],
12
+ loaded: false,
13
+ loading: false,
14
+ removeError: null,
15
+ selectedError: null,
16
+ selectedLoading: false,
17
+ updateError: null
18
+ };
19
+ /**
20
+ * Resetea el estado de la entidad al estado inicial.
21
+ * @returns {EntityStatus} - El estado inicial de la entidad.
22
+ */
23
+ export function resetEntityStatus() {
24
+ return initialState;
25
+ }
26
+ /**
27
+ * Agrega funcionalidades comunes de estado y computados para manejar el estado de entidades.
28
+ * @returns {SignalStoreFeature} -Características de la tienda con estado y computados para el manejo de entidades.
29
+ */
30
+ export function withEntityStatus() {
31
+ return signalStoreFeature(withState({ status: initialState }), withComputed(({ status: { _removeLoading, _updateLoading, addError, error, idsRemoving, idsUpdating, removeError, selectedError, updateError } }) => ({
32
+ statusComputed: computed(() => ({
33
+ anyError: error() || addError() || removeError() || updateError() || selectedError(),
34
+ isAnyActionLoading: idsUpdating().length > 0 || idsRemoving().length > 0,
35
+ removeLoading: _removeLoading() || idsRemoving().length > 0,
36
+ updateLoading: _updateLoading() || idsUpdating().length > 0
37
+ }))
38
+ })));
39
+ }
40
+ //# sourceMappingURL=with-entity-status.js.map
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@barcidev/ngx-autogen",
3
- "version": "0.1.65",
3
+ "version": "0.1.67",
4
4
  "description": "A collection of Angular schematics for essential functionalities.",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
7
- "build": "tsc -p tsconfig.json",
7
+ "build": "tsc -p tsconfig.json && tsc -p tsconfig.lib.json",
8
8
  "release": "npm run build && npm publish --access public",
9
9
  "test": "npm run build && jasmine src/**/*_spec.js",
10
10
  "prepublishOnly": "npm run build"
@@ -15,6 +15,8 @@
15
15
  "src/**/*.d.ts",
16
16
  "src/**/schema.json",
17
17
  "src/collection.json",
18
+ "dist/lib/**/*.js",
19
+ "dist/lib/**/*.d.ts",
18
20
  "README.md",
19
21
  "LICENSE"
20
22
  ],
@@ -56,9 +58,37 @@
56
58
  },
57
59
  "devDependencies": {
58
60
  "@angular-devkit/schematics-cli": "^21.2.0",
61
+ "@angular/forms": "^21.2.11",
62
+ "@ngrx/signals": "^21.1.0",
59
63
  "@types/jasmine": "~5.1.0",
60
64
  "@types/node": "^20.17.19",
61
65
  "copyfiles": "^2.4.1",
62
66
  "jasmine": "^5.0.0"
67
+ },
68
+ "peerDependencies": {
69
+ "@angular/common": ">=17.0.0",
70
+ "@angular/core": ">=17.0.0",
71
+ "@angular/forms": ">=17.0.0",
72
+ "@ngrx/signals": ">=17.0.0"
73
+ },
74
+ "peerDependenciesMeta": {
75
+ "@angular/common": {
76
+ "optional": true
77
+ },
78
+ "@angular/core": {
79
+ "optional": true
80
+ },
81
+ "@angular/forms": {
82
+ "optional": true
83
+ },
84
+ "@ngrx/signals": {
85
+ "optional": true
86
+ }
87
+ },
88
+ "exports": {
89
+ "./entity": {
90
+ "types": "./dist/lib/entity/index.d.ts",
91
+ "default": "./dist/lib/entity/index.js"
92
+ }
63
93
  }
64
94
  }
@@ -1,6 +1,6 @@
1
1
  import { ComponentFixture, TestBed } from '@angular/core/testing';
2
2
  import { <%= classify(name) %>Component } from './<%= dasherize(name) %>.component';
3
- <% if (store === 'Yes') { %>import { <%= classify(name) %>Store } from './state';<% } %>
3
+ <% if (store === 'Yes') { %>import { <%= classify(storeName) %>Store } from './state';<% } %>
4
4
 
5
5
  describe('<%= classify(name) %>Component', () => {
6
6
  let component: <%= classify(name) %>Component;
@@ -10,7 +10,7 @@ describe('<%= classify(name) %>Component', () => {
10
10
  await TestBed.configureTestingModule({
11
11
  imports: [<%= classify(name) %>Component],
12
12
  providers: [
13
- <% if (store === 'Yes') { %><%= classify(name) %>Store,<% } %>
13
+ <% if (store === 'Yes') { %><%= classify(storeName) %>Store,<% } %>
14
14
  ]
15
15
  }).compileComponents();
16
16
 
@@ -1,17 +1,17 @@
1
1
  import { Component, inject } from '@angular/core';
2
2
  <% if (store === 'Yes') { %>
3
- import { <%= classify(name) %>Store } from './state';
3
+ import { <%= classify(storeName) %>Store<% if (!isProvideInRoot) { %>, provide<%= classify(storeName) %>Store<% } %> } from './state';
4
4
  import { JsonPipe } from '@angular/common';
5
5
  <% } %>
6
6
 
7
7
  @Component({
8
8
  imports: [<% if (store === 'Yes') { %>JsonPipe<% } %>],
9
- providers: [],
9
+ providers: [<% if (store === 'Yes' && !isProvideInRoot) { %>...provide<%= classify(storeName) %>Store()<% } %>],
10
10
  selector: 'app-<%= dasherize(name) %>',
11
11
  styleUrls: ['./<%= dasherize(name) %>.component.css'],
12
12
  templateUrl: './<%= dasherize(name) %>.component.html',
13
13
  })
14
14
  export class <%= classify(name) %>Component {
15
- <% if (store === 'Yes') { %> private _<%= camelize(name) %>Store = inject(<%= classify(name) %>Store);
16
- data$ = this._<%= camelize(name) %>Store.entities();<% } %>
15
+ <% if (store === 'Yes') { %> private _<%= camelize(storeName) %>Store = inject(<%= classify(storeName) %>Store);
16
+ data$ = this._<%= camelize(storeName) %>Store.entities();<% } %>
17
17
  }
@@ -14,12 +14,22 @@ const schematics_1 = require("@angular-devkit/schematics");
14
14
  const workspace_1 = require("@schematics/angular/utility/workspace");
15
15
  const path_1 = require("path");
16
16
  const pluralize_1 = require("../../common/pluralize");
17
+ const prompts_1 = require("../../common/prompts");
17
18
  function component(options) {
18
19
  return (tree) => __awaiter(this, void 0, void 0, function* () {
19
20
  const workspace = yield (0, workspace_1.getWorkspace)(tree);
20
- // 1. Preparar contexto y opciones enriquecidas
21
+ if (options.store === "Yes") {
22
+ if (!options.storeName) {
23
+ options.storeName = yield (0, prompts_1.askInput)("What is the name of the entity store to create?", options.name);
24
+ }
25
+ if (!options.pk) {
26
+ options.pk = yield (0, prompts_1.askInput)("What is the name of the default Primary Key (e.g., id, cod, uuid)?", "id");
27
+ }
28
+ if (options.isProvideInRoot === undefined) {
29
+ options.isProvideInRoot = yield (0, prompts_1.askConfirm)("Should the store and service be provided in root?", false);
30
+ }
31
+ }
21
32
  const context = resolveComponentContext(workspace, options);
22
- // Aquí podrías agregar más reglas para otras funcionalidades, como NgRx
23
33
  return (0, schematics_1.chain)([
24
34
  generateComponentFiles(context),
25
35
  options.i18n === "Yes"
@@ -30,8 +40,10 @@ function component(options) {
30
40
  : (0, schematics_1.noop)(),
31
41
  options.store === "Yes"
32
42
  ? (0, schematics_1.schematic)("app-store", {
33
- name: context.options.name,
43
+ name: options.storeName || context.options.name,
34
44
  path: (0, path_1.join)(context.movePath, context.nameDash),
45
+ pk: context.options.pk,
46
+ isProvideInRoot: context.options.isProvideInRoot,
35
47
  })
36
48
  : (0, schematics_1.noop)(),
37
49
  ]);
@@ -22,6 +22,16 @@
22
22
  "x-prompt": "Do you want to create an i18n file for the component?",
23
23
  "enum": ["Yes", "No"]
24
24
  },
25
+ "pk": {
26
+ "type": "string",
27
+ "description": "The name of the default Primary Key (e.g., id, cod, uuid); default is 'id'.",
28
+ "default": "id"
29
+ },
30
+ "isProvideInRoot": {
31
+ "type": "boolean",
32
+ "description": "Whether the store and service should be provided in root.",
33
+ "default": false
34
+ },
25
35
  "path": {
26
36
  "type": "string",
27
37
  "description": "Destination path."
@@ -9,7 +9,10 @@ export interface ComponentSchemaOptions {
9
9
  name: string;
10
10
  project?: string;
11
11
  store: "Yes" | "No";
12
+ storeName?: string;
12
13
  i18n: "Yes" | "No";
14
+ pk?: string;
15
+ isProvideInRoot?: boolean;
13
16
  path?: string;
14
17
  lang?: "en" | "es";
15
18
  }
@@ -0,0 +1,2 @@
1
+ export declare function askInput(question: string, defaultValue?: string): Promise<string>;
2
+ export declare function askConfirm(question: string, defaultValue?: boolean): Promise<boolean>;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.askInput = askInput;
4
+ exports.askConfirm = askConfirm;
5
+ const readline = require("readline");
6
+ function askInput(question, defaultValue) {
7
+ const rl = readline.createInterface({
8
+ input: process.stdin,
9
+ output: process.stdout,
10
+ });
11
+ const suffix = defaultValue ? ` (${defaultValue})` : "";
12
+ return new Promise((resolve) => {
13
+ rl.question(`${question}${suffix}: `, (answer) => {
14
+ rl.close();
15
+ resolve(answer.trim() || defaultValue || "");
16
+ });
17
+ });
18
+ }
19
+ function askConfirm(question, defaultValue = false) {
20
+ const rl = readline.createInterface({
21
+ input: process.stdin,
22
+ output: process.stdout,
23
+ });
24
+ const hint = defaultValue ? "(Y/n)" : "(y/N)";
25
+ return new Promise((resolve) => {
26
+ rl.question(`${question} ${hint}: `, (answer) => {
27
+ rl.close();
28
+ const normalized = answer.trim().toLowerCase();
29
+ if (normalized === "")
30
+ return resolve(defaultValue);
31
+ resolve(normalized === "y" || normalized === "yes");
32
+ });
33
+ });
34
+ }
35
+ //# sourceMappingURL=prompts.js.map
@@ -1,4 +1,4 @@
1
- import { FormGroupType } from '@shared-state/entity.model';
1
+ import { FormGroupType } from '@barcidev/ngx-autogen/entity';
2
2
 
3
3
  export interface Add<%= classify(name) %> {
4
4
  }
@@ -6,9 +6,7 @@ import {
6
6
  Update<%= classify(name) %>
7
7
  } from '<%= grouped ? "../models/" + dasherize(name) + ".model" : "./" + dasherize(name) + ".model" %>';
8
8
 
9
- @Injectable({
10
- providedIn: 'root'
11
- })
9
+ @Injectable(<%= isProvideInRoot ? "{ providedIn: 'root' }" : "" %>)
12
10
  export class <%= classify(name) %>Service {
13
11
 
14
12
  add<%= classify(name) %>$(payload: Add<%= classify(name) %>): Observable<number> {
@@ -10,10 +10,9 @@ import {
10
10
  } from '@ngrx/signals/entities';
11
11
  import { rxMethod } from '@ngrx/signals/rxjs-interop';
12
12
  import { catchError, EMPTY, pipe, switchMap, tap } from 'rxjs';
13
+ import { EntityId } from '@ngrx/signals/entities';
13
14
 
14
- import { RequestConfig } from '@shared-state/entity.model';
15
- import { withPagination } from '@shared-state/with-entity-pagination';
16
- import { withEntityStatus } from '@shared-state/with-entity-status';
15
+ import { RequestConfig, withEntityStatus, withPagination } from '@barcidev/ngx-autogen/entity';
17
16
  import {
18
17
  Add<%= classify(name) %>,
19
18
  <%= classify(name) %>Dto,
@@ -27,12 +26,11 @@ const config = entityConfig({
27
26
  });
28
27
 
29
28
  export const <%= classify(name) %>Store = signalStore(
30
- { providedIn: 'root' },
29
+ <%= isProvideInRoot ? "{ providedIn: 'root' }," : "" %>
31
30
  withEntities(config),
32
31
  withEntityStatus(),
33
32
  withPagination(),
34
33
  withComputed(({ entities, entityMap, status: { idSelected } }) => ({
35
- <%= camelize(pluralize(name)) %>: computed(() => entities()),
36
34
  <%= camelize(name) %>Seleccionado: computed(() => {
37
35
  const <%= pk %> = idSelected();
38
36
  return <%= pk %> ? entityMap()[<%= pk %>] : null;
@@ -142,6 +140,18 @@ export const <%= classify(name) %>Store = signalStore(
142
140
  })
143
141
  )
144
142
  ),
143
+ select<%= classify(name) %>: rxMethod<EntityId | null>(
144
+ pipe(
145
+ tap((payload) => {
146
+ patchState(store, (state) => ({
147
+ status: {
148
+ ...state.status,
149
+ idSelected: payload
150
+ }
151
+ }));
152
+ })
153
+ )
154
+ ),
145
155
  update<%= classify(name) %>: rxMethod<RequestConfig<Update<%= classify(name) %>, boolean>>(
146
156
  pipe(
147
157
  tap(({ payload }) => {
@@ -198,4 +208,11 @@ export const <%= classify(name) %>Store = signalStore(
198
208
  store.load<%= classify(pluralize(name)) %>();
199
209
  },
200
210
  })
201
- );
211
+ );
212
+
213
+ export function provide<%= classify(name) %>Store() {
214
+ return <%= isProvideInRoot ? [
215
+ <%= classify(name) %>Service,
216
+ <%= classify(name) %>Store,
217
+ ] : [ <%= classify(name) %>Store ]
218
+ }
@@ -16,12 +16,13 @@ const tasks_1 = require("@angular-devkit/schematics/tasks");
16
16
  const dependencies_1 = require("@schematics/angular/utility/dependencies");
17
17
  const workspace_1 = require("@schematics/angular/utility/workspace");
18
18
  const jsonc_parser_1 = require("jsonc-parser");
19
- const file_actions_1 = require("../../common/file-actions");
20
19
  const pluralize_1 = require("../../common/pluralize");
21
20
  const project_metadata_1 = require("../../common/project-metadata");
22
21
  const NGRX_SIGNALS = "@ngrx/signals";
22
+ let _needsInstall = false;
23
23
  function signalStore(options) {
24
24
  return (tree) => __awaiter(this, void 0, void 0, function* () {
25
+ _needsInstall = false;
25
26
  const workspace = yield (0, workspace_1.getWorkspace)(tree);
26
27
  // 1. Preparar contexto y opciones enriquecidas
27
28
  const context = resolveStoreContext(workspace, options);
@@ -35,12 +36,14 @@ function signalStore(options) {
35
36
  ensureNgrxSignals(angularVersion),
36
37
  updateIndexFile(context),
37
38
  generateStoreFiles(context),
38
- (0, file_actions_1.mergeFilesSmart)("./files/entity", "src/app/shared/state", context.options, tree),
39
39
  updateAngularJson(context.options),
40
40
  updateTsConfigRule(projectRoot),
41
- (host, context) => {
42
- context.addTask(new tasks_1.NodePackageInstallTask());
43
- context.logger.info("🚀 Entorno preparado con éxito.");
41
+ (host, ctx) => {
42
+ if (_needsInstall) {
43
+ ctx.addTask(new tasks_1.NodePackageInstallTask());
44
+ ctx.logger.info("📦 Instalando dependencias...");
45
+ }
46
+ ctx.logger.info("🚀 Entorno preparado con éxito.");
44
47
  return host;
45
48
  },
46
49
  ]);
@@ -85,20 +88,16 @@ function resolveStoreContext(workspace, options) {
85
88
  */
86
89
  function ensureNgrxSignals(version) {
87
90
  return (tree) => {
88
- // 1. Intentamos obtener la dependencia si ya existe
89
91
  const existingDep = (0, dependencies_1.getPackageJsonDependency)(tree, NGRX_SIGNALS);
90
- // 2. Si existe, simplemente retornamos el árbol sin hacer nada
91
- if (existingDep) {
92
- // Opcional: podrías loguear un mensaje aquí
92
+ if (existingDep)
93
93
  return tree;
94
- }
95
- // 3. Si no existe, la añadimos
96
94
  (0, dependencies_1.addPackageJsonDependency)(tree, {
97
95
  type: dependencies_1.NodeDependencyType.Default,
98
96
  name: NGRX_SIGNALS,
99
97
  version: `^${version}.0.0`,
100
98
  overwrite: false,
101
99
  });
100
+ _needsInstall = true;
102
101
  return tree;
103
102
  };
104
103
  }
@@ -147,7 +146,7 @@ function generateStoreFiles(ctx) {
147
146
  }
148
147
  function updateTsConfigRule(root) {
149
148
  return (tree, context) => {
150
- var _a, _b;
149
+ var _a, _b, _c, _d, _e;
151
150
  const tsConfigPath = tree.exists("/tsconfig.app.json")
152
151
  ? "/tsconfig.app.json"
153
152
  : "/tsconfig.json";
@@ -155,21 +154,28 @@ function updateTsConfigRule(root) {
155
154
  if (!buffer)
156
155
  return;
157
156
  let content = buffer.toString();
158
- const modOptions = {
159
- formattingOptions: { insertSpaces: true, tabSize: 2 },
160
- };
161
- // 1. Asegurar baseUrl
162
- if (!((_a = (0, jsonc_parser_1.parse)(content).compilerOptions) === null || _a === void 0 ? void 0 : _a.baseUrl)) {
163
- content = (0, jsonc_parser_1.applyEdits)(content, (0, jsonc_parser_1.modify)(content, ["compilerOptions", "baseUrl"], "./", modOptions));
164
- }
165
- // 2. Calcular path relativo al baseUrl
166
- const baseUrl = ((_b = (0, jsonc_parser_1.parse)(content).compilerOptions) === null || _b === void 0 ? void 0 : _b.baseUrl) || "./";
157
+ const parsed = (0, jsonc_parser_1.parse)(content);
158
+ // Calcular el path esperado del alias
159
+ const baseUrl = ((_a = parsed.compilerOptions) === null || _a === void 0 ? void 0 : _a.baseUrl) || "./";
167
160
  let i18nPath = `${root}/app/shared/state/*`;
168
161
  const normalizedBase = baseUrl.replace(/^\.\/|\/$/g, "");
169
162
  if (normalizedBase && i18nPath.startsWith(normalizedBase)) {
170
163
  i18nPath = i18nPath.replace(normalizedBase, "").replace(/^\//, "");
171
164
  }
172
- // 3. Aplicar alias
165
+ // Verificar si ya tiene baseUrl y el alias correcto
166
+ const existingPaths = (_c = (_b = parsed.compilerOptions) === null || _b === void 0 ? void 0 : _b.paths) === null || _c === void 0 ? void 0 : _c["@shared-state/*"];
167
+ const alreadyConfigured = ((_d = parsed.compilerOptions) === null || _d === void 0 ? void 0 : _d.baseUrl) &&
168
+ Array.isArray(existingPaths) &&
169
+ existingPaths.length === 1 &&
170
+ existingPaths[0] === i18nPath;
171
+ if (alreadyConfigured)
172
+ return;
173
+ const modOptions = {
174
+ formattingOptions: { insertSpaces: true, tabSize: 2 },
175
+ };
176
+ if (!((_e = parsed.compilerOptions) === null || _e === void 0 ? void 0 : _e.baseUrl)) {
177
+ content = (0, jsonc_parser_1.applyEdits)(content, (0, jsonc_parser_1.modify)(content, ["compilerOptions", "baseUrl"], "./", modOptions));
178
+ }
173
179
  const finalContent = (0, jsonc_parser_1.applyEdits)(content, (0, jsonc_parser_1.modify)(content, ["compilerOptions", "paths", "@shared-state/*"], [i18nPath], modOptions));
174
180
  tree.overwrite(tsConfigPath, finalContent);
175
181
  context.logger.info(`✅ Alias @shared-state configurado.`);
@@ -177,11 +183,15 @@ function updateTsConfigRule(root) {
177
183
  }
178
184
  function updateAngularJson(options) {
179
185
  return (tree) => {
186
+ var _a;
180
187
  const path = "/angular.json";
181
188
  const buffer = tree.read(path);
182
189
  if (!buffer)
183
190
  return;
184
191
  const workspace = JSON.parse(buffer.toString());
192
+ const existing = (_a = workspace.schematics) === null || _a === void 0 ? void 0 : _a["@barcidev/ngx-autogen:signal-state"];
193
+ if ((existing === null || existing === void 0 ? void 0 : existing.pk) === options.pk && (existing === null || existing === void 0 ? void 0 : existing.lang) === options.lang)
194
+ return;
185
195
  if (!workspace.schematics)
186
196
  workspace.schematics = {};
187
197
  workspace.schematics["@barcidev/ngx-autogen:signal-state"] = {
@@ -28,6 +28,19 @@
28
28
  "lang":{
29
29
  "type": "string",
30
30
  "description": "The default language for the application (en, es); default is 'en'."
31
+ },
32
+ "isProvideInRoot": {
33
+ "type": "boolean",
34
+ "description": "Whether the store and service should be provided in root.",
35
+ "default": false,
36
+ "x-prompt": {
37
+ "message": "Should the store and service be provided in root?",
38
+ "type": "list",
39
+ "items": [
40
+ { "value": true, "label": "Yes" },
41
+ { "value": false, "label": "No" }
42
+ ]
43
+ }
31
44
  }
32
45
  },
33
46
  "required": ["name"]
@@ -5,4 +5,5 @@ export interface StoreSchemaOptions {
5
5
  grouped: boolean;
6
6
  pk?: string;
7
7
  lang: "en" | "es";
8
+ isProvideInRoot: boolean;
8
9
  }
@@ -1,4 +1,4 @@
1
- import { TranslationScopeConfig, TranslocoUtils } from '@barcidev/typed-transloco';
1
+ import { TranslocoUtils } from '@barcidev/typed-transloco';
2
2
 
3
3
  const esCO = {
4
4
  title: 'Titulo'
@@ -1,89 +0,0 @@
1
- import { computed, Signal } from '@angular/core';
2
- import {
3
- EmptyFeatureResult,
4
- patchState,
5
- SignalStoreFeature,
6
- signalStoreFeature,
7
- withComputed,
8
- withMethods,
9
- withState
10
- } from '@ngrx/signals';
11
-
12
- export interface PaginationState {
13
- page: number;
14
- pageSize: number;
15
- totalCount: number;
16
- }
17
-
18
- interface PaginationComputedProps {
19
- hasNext: boolean;
20
- hasPrevious: boolean;
21
- totalPages: number;
22
- }
23
-
24
- const initialPaginationState: PaginationState = {
25
- page: 1,
26
- pageSize: 10,
27
- totalCount: 0
28
- };
29
-
30
- /**
31
- * Resetea el estado de paginación al estado inicial.
32
- * @returns {PaginationState} - El estado inicial de paginación.
33
- */
34
- export function resetPaginationState(): PaginationState {
35
- return initialPaginationState;
36
- }
37
-
38
- /**
39
- * Agrega funcionalidades de paginación a un Store.
40
- * @param {[number]} initialPageSize - Tamaño inicial de página (opcional).
41
- * @returns {SignalStoreFeature} - Características de la tienda con estado, computados y métodos de paginación.
42
- */
43
- export function withPagination(initialPageSize?: number): SignalStoreFeature<
44
- EmptyFeatureResult,
45
- {
46
- methods: {
47
- nextPage: () => void;
48
- previousPage: () => void;
49
- setPage: (page: number) => void;
50
- setPageSize: (pageSize: number) => void;
51
- setTotalCount: (totalCount: number) => void;
52
- };
53
- props: Record<'paginationComputed', Signal<PaginationComputedProps>>;
54
- state: Record<'pagination', PaginationState>;
55
- }
56
- > {
57
- return signalStoreFeature(
58
- withState({
59
- pagination: initialPageSize ? { ...initialPaginationState, pageSize: initialPageSize } : initialPaginationState
60
- }),
61
-
62
- withComputed(({ pagination: { page, pageSize, totalCount } }) => ({
63
- paginationComputed: computed(() => ({
64
- hasNext: page() < Math.ceil(totalCount() / pageSize()),
65
- hasPrevious: page() > 1,
66
- totalPages: Math.ceil(totalCount() / pageSize())
67
- }))
68
- })),
69
- withMethods((store) => ({
70
- nextPage: () => {
71
- if (store.pagination.page() < Math.ceil(store.pagination.totalCount() / store.pagination.pageSize())) {
72
- patchState(store, (state) => ({ pagination: { ...state.pagination, page: store.pagination.page() + 1 } }));
73
- }
74
- },
75
- previousPage: () => {
76
- if (store.pagination.page() > 1) {
77
- patchState(store, (state) => ({ pagination: { ...state.pagination, page: store.pagination.page() - 1 } }));
78
- }
79
- },
80
- setPage: (page: number) => {
81
- patchState(store, (state) => ({ pagination: { ...state.pagination, page } }));
82
- },
83
- setPageSize: (pageSize: number) =>
84
- patchState(store, (state) => ({ pagination: { ...state.pagination, page: 1, pageSize } })), // Reset a pág 1 si cambia el tamaño
85
- setTotalCount: (totalCount: number) =>
86
- patchState(store, (state) => ({ pagination: { ...state.pagination, totalCount } }))
87
- }))
88
- );
89
- }
@@ -1,92 +0,0 @@
1
- import { computed, Signal } from '@angular/core';
2
- import { EmptyFeatureResult, SignalStoreFeature, signalStoreFeature, withComputed, withState } from '@ngrx/signals';
3
-
4
- export interface EntityStatus {
5
- _removeLoading: boolean;
6
- _updateLoading: boolean;
7
- addError: Error | null;
8
- addLoading: boolean;
9
- error: Error | null;
10
- idSelected: null | number | string;
11
- idsRemoving: (number | string)[];
12
- idsUpdating: (number | string)[];
13
- loaded: boolean;
14
- loading: boolean;
15
- removeError: Error | null;
16
- selectedError: Error | null;
17
- selectedLoading: boolean;
18
- updateError: Error | null;
19
- }
20
-
21
- interface EntityStatusComputedProps {
22
- anyError: Error | null;
23
- isAnyActionLoading: boolean;
24
- removeLoading: boolean;
25
- updateLoading: boolean;
26
- }
27
-
28
- type EntityStatusMethodProps = Record<string, (...args: unknown[]) => unknown>;
29
-
30
- const initialState: EntityStatus = {
31
- _removeLoading: false,
32
- _updateLoading: false,
33
- addError: null,
34
- addLoading: false,
35
- error: null,
36
- idSelected: null,
37
- idsRemoving: [],
38
- idsUpdating: [],
39
- loaded: false,
40
- loading: false,
41
- removeError: null,
42
- selectedError: null,
43
- selectedLoading: false,
44
- updateError: null
45
- };
46
-
47
- /**
48
- * Resetea el estado de la entidad al estado inicial.
49
- * @returns {EntityStatus} - El estado inicial de la entidad.
50
- */
51
- export function resetEntityStatus(): EntityStatus {
52
- return initialState;
53
- }
54
-
55
- /**
56
- * Agrega funcionalidades comunes de estado y computados para manejar el estado de entidades.
57
- * @returns {SignalStoreFeature} -Características de la tienda con estado y computados para el manejo de entidades.
58
- */
59
- export function withEntityStatus(): SignalStoreFeature<
60
- EmptyFeatureResult,
61
- {
62
- methods: EntityStatusMethodProps;
63
- props: Record<'statusComputed', Signal<EntityStatusComputedProps>>;
64
- state: Record<'status', EntityStatus>;
65
- }
66
- > {
67
- return signalStoreFeature(
68
- withState({ status: initialState }),
69
- withComputed(
70
- ({
71
- status: {
72
- _removeLoading,
73
- _updateLoading,
74
- addError,
75
- error,
76
- idsRemoving,
77
- idsUpdating,
78
- removeError,
79
- selectedError,
80
- updateError
81
- }
82
- }) => ({
83
- statusComputed: computed(() => ({
84
- anyError: error() || addError() || removeError() || updateError() || selectedError(),
85
- isAnyActionLoading: idsUpdating().length > 0 || idsRemoving().length > 0,
86
- removeLoading: _removeLoading() || idsRemoving().length > 0,
87
- updateLoading: _updateLoading() || idsUpdating().length > 0
88
- }))
89
- })
90
- )
91
- );
92
- }