@nano-app/frontend 0.3.3 → 0.3.4

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.
@@ -28,7 +28,9 @@ export default [
28
28
  "name": "app",
29
29
  "type": "app",
30
30
  "data": {
31
- "isRegister": false,
31
+ "login": {
32
+ "isRegister": false
33
+ },
32
34
  "navbar": {
33
35
  "tabs": [],
34
36
  "selectedTabKey": "home",
@@ -44,7 +46,6 @@ export default [
44
46
  "formType": "",
45
47
  "title": ""
46
48
  },
47
- "totales": {},
48
49
  "config": {
49
50
  "theme": "dark"
50
51
  }
@@ -62,7 +63,7 @@ export default [
62
63
  { key: "admin", href: "/admin", label: "Administración", minRole: -1 },
63
64
  { key: "uli", href: "/", label: "Uli :v", minRole: -1 },
64
65
  { key: "luka", href: "/", label: "Lucas :v", minRole: -1 }].
65
- filter((tab) => tab.minRole >= rolId),
66
+ filter((tab) => tab.minRole <= rolId),
66
67
  "initialForms": {
67
68
  "User": {
68
69
  "rolId": 1,
@@ -113,7 +114,11 @@ export default [
113
114
  {
114
115
  "fieldName": "password",
115
116
  "inputType": "password",
116
- "isRequired": true
117
+ "isRequired": true,
118
+ "validateFn": (oForm) =>
119
+ (oForm.password?.length || 0) < 4 ?
120
+ "La contraseña debe tener al menos 4 caracteres" :
121
+ ""
117
122
  }
118
123
  ],
119
124
  "register": [
@@ -133,12 +138,20 @@ export default [
133
138
  {
134
139
  "fieldName": "password",
135
140
  "inputType": "password",
136
- "isRequired": true
141
+ "isRequired": true,
142
+ "validateFn": (oForm) =>
143
+ (oForm.password?.length || 0) < 4 ?
144
+ "La contraseña debe tener al menos 4 caracteres" :
145
+ ""
137
146
  },
138
147
  {
139
148
  "fieldName": "confirmPassword",
140
149
  "inputType": "password",
141
- "isRequired": true
150
+ "isRequired": true,
151
+ "validateFn": (oForm) =>
152
+ oForm.confirmPassword != oForm.password ?
153
+ 'Las contraseñas no coinciden' :
154
+ ''
142
155
  }
143
156
  ],
144
157
  "Users": [
@@ -254,10 +267,14 @@ export default [
254
267
  "name": "i18n",
255
268
  "type": "app",
256
269
  "data": {
257
- "login": {
258
- "header": (isRegister) => isRegister ? "REGISTRARSE" : "INICIAR SESIÓN",
259
- "footer": (isRegister) => isRegister ? "o iniciar sesión" : "o registrarse",
260
- "buttonText": (isRegister) => isRegister ? "Crear" : "Ingresar"
270
+ "loginTexts": (isRegister) => ({
271
+ headerText: isRegister ? "REGISTRARSE" : "INICIAR SESIÓN",
272
+ footerText: isRegister ? "o iniciar sesión" : "o registrarse",
273
+ buttonText: isRegister ? "Crear" : "Ingresar",
274
+ formType: isRegister ? "register" : "login"
275
+ }),
276
+ "button": {
277
+ "confirm": "Confirmar"
261
278
  },
262
279
  "create": (entity) => `Crear ${entity}`,
263
280
  "edit": (entity) => `Editar ${entity}`,
@@ -16,7 +16,7 @@ class ApiStore extends AppStore_1.AppStore {
16
16
  read = async (query, params = {}) => {
17
17
  const path = query.split("?")[0];
18
18
  const response = await this.request("GET", QueryBuilder_1.QueryBuilder.build(query, params));
19
- this.set(`/${path}`, response.result);
19
+ this.set(`${path}`, response.result);
20
20
  return response;
21
21
  };
22
22
  update = (entity, body) => this.request("PUT", entity, body);
@@ -52,8 +52,8 @@ class AppStore {
52
52
  * @param value - El valor a asignar
53
53
  */
54
54
  set(path, value) {
55
- RenderManager_1.default.refresh(path, this.name);
56
55
  this.manageState(path, value);
56
+ RenderManager_1.default.refresh(path, this.name);
57
57
  }
58
58
  }
59
59
  exports.AppStore = AppStore;
@@ -1,9 +1,12 @@
1
- import { ReactParams } from "./createComponent";
2
1
  import { ApiResponse } from "@nano-app/backend";
2
+ import { ReactNode } from "react";
3
+ export type ReactParams = Record<string, any> & {
4
+ children?: ReactNode;
5
+ hook?: () => void;
6
+ };
3
7
  export declare abstract class Controller {
4
8
  private componentId;
5
- params: ReactParams;
6
- constructor(params: ReactParams);
9
+ constructor(hook: () => void, params: any);
7
10
  get<T = any>(path: string, name?: string): T;
8
11
  read<T = any>(path: string, params?: {}, name?: string): Promise<ApiResponse<T>>;
9
12
  set(path: string, value: any, name?: string): void;
@@ -11,6 +14,7 @@ export declare abstract class Controller {
11
14
  update<T = any>(path: string, body: any, name?: string): Promise<ApiResponse<T>>;
12
15
  delete<T = any>(path: string, id: any, name?: string): Promise<ApiResponse<T>>;
13
16
  destroy(): void;
14
- onInit(): void;
15
- onRender(): void;
17
+ onInit(params?: any): void;
18
+ onRender(params?: any): void;
19
+ useHooks(): void;
16
20
  }
@@ -8,17 +8,12 @@ const StoreManager_1 = __importDefault(require("../store/StoreManager"));
8
8
  const RenderManager_1 = __importDefault(require("../store/RenderManager"));
9
9
  class Controller {
10
10
  componentId;
11
- params;
12
- // public router!: ReturnType<typeof useRouter>;
13
- // public pathname!: string | null;
14
- constructor(params) {
11
+ constructor(hook, params) {
15
12
  // Registra el componente para reactividad
16
13
  this.componentId = Symbol();
17
- RenderManager_1.default.register(this.componentId, params.hook || (() => { }));
18
- // Inicializa los parámetros
19
- this.params = params;
14
+ RenderManager_1.default.register(this.componentId, hook);
20
15
  // Inicializa el controller
21
- this.onInit();
16
+ this.onInit(params);
22
17
  }
23
18
  get(path, name = 'app') {
24
19
  // Registra el path como dependencia
@@ -28,7 +23,7 @@ class Controller {
28
23
  }
29
24
  read(path, params = {}, name = 'api') {
30
25
  // Registra el path como dependencia
31
- RenderManager_1.default.dependsOn(this.componentId, path, "api");
26
+ RenderManager_1.default.dependsOn(this.componentId, path, name);
32
27
  // Retorna el valor de la api
33
28
  return StoreManager_1.default.getStore(name)?.read(path, params);
34
29
  }
@@ -47,7 +42,8 @@ class Controller {
47
42
  destroy() {
48
43
  RenderManager_1.default.unregister(this.componentId);
49
44
  }
50
- onInit() { }
51
- onRender() { }
45
+ onInit(params) { }
46
+ onRender(params) { }
47
+ useHooks() { }
52
48
  }
53
49
  exports.Controller = Controller;
@@ -1,13 +1,12 @@
1
1
  import { ReactNode } from "react";
2
2
  import { Controller } from "./Controller";
3
- export type ReactParams = Record<string, unknown> & {
3
+ export type ViewParams = any & {
4
4
  children?: ReactNode;
5
- hook?: () => void;
6
5
  };
6
+ export type View<C> = (controller: C, params: ViewParams) => ReactNode;
7
7
  export type CreateComponentProps<C> = {
8
- controller?: new (params: ReactParams) => C;
9
- view?: (controller: C) => ReactNode;
10
- hooks?: (controller: C) => void;
8
+ controller?: new (hook: () => void, params: any) => C;
9
+ view?: View<C>;
11
10
  };
12
11
  /**
13
12
  * Crea un componente reactivo que se actualiza automáticamente cuando los datos de los stores cambian.
@@ -15,4 +14,4 @@ export type CreateComponentProps<C> = {
15
14
  * @param view - Función que renderiza el componente
16
15
  * @returns - Función que retorna el componente reactivo
17
16
  */
18
- export declare function createComponent<C extends Controller = Controller>({ controller, view, hooks }: CreateComponentProps<C>): (params?: ReactParams) => ReactNode;
17
+ export declare function createComponent<C extends Controller = Controller>({ controller, view }: CreateComponentProps<C>): (params: ViewParams) => ReactNode;
@@ -5,27 +5,28 @@ const react_1 = require("react");
5
5
  const Controller_1 = require("./Controller");
6
6
  class BaseController extends Controller_1.Controller {
7
7
  }
8
- const BaseView = ({ params: { children } }) => children;
8
+ const BaseView = (_, { children }) => children;
9
9
  /**
10
10
  * Crea un componente reactivo que se actualiza automáticamente cuando los datos de los stores cambian.
11
11
  * @param ControllerClass - Clase del controller
12
12
  * @param view - Función que renderiza el componente
13
13
  * @returns - Función que retorna el componente reactivo
14
14
  */
15
- function createComponent({ controller, view, hooks }) {
15
+ function createComponent({ controller, view }) {
16
16
  return function (params) {
17
17
  // Hook para re-renderizar el componente
18
18
  const [, setTick] = (0, react_1.useState)(0);
19
19
  // Instancia el controller
20
20
  const controllerRef = (0, react_1.useRef)();
21
21
  if (!controllerRef.current) {
22
- controllerRef.current = new (controller || BaseController)({ ...params, hook: () => setTick((t) => t + 1) });
22
+ controllerRef.current = new (controller || BaseController)(() => setTick((t) => t + 1), params);
23
23
  }
24
+ // Ejecuta el método onRender del controller
25
+ controllerRef.current.onRender(params);
24
26
  // Ejecuta las hooks del usuario
25
- if (hooks)
26
- hooks(controllerRef.current);
27
+ controllerRef.current.useHooks();
27
28
  // Cleanup del componente
28
29
  (0, react_1.useEffect)(() => () => controllerRef.current?.destroy(), []);
29
- return view ? view(controllerRef.current) : BaseView(controllerRef.current);
30
+ return view ? view(controllerRef.current, params) : BaseView(controllerRef.current, params);
30
31
  };
31
32
  }
@@ -10,8 +10,10 @@ function buildFilters(filters) {
10
10
  }
11
11
  class QueryBuilder {
12
12
  static build(path, params = {}) {
13
- const { skip, filters, expand, orderby, top } = params;
14
- const queryParams = [];
13
+ const { skip, filters, expand, orderby, top, ...extraParams } = params;
14
+ const queryParams = [
15
+ ...Object.entries(extraParams).map(([key, value]) => `${key}=${value}`)
16
+ ];
15
17
  const filtersQuery = buildFilters(filters);
16
18
  if (filtersQuery)
17
19
  queryParams.push(`filter=${filtersQuery}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nano-app/frontend",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "description": "View + Controller frontend architecture for React/Next.js",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,6 +0,0 @@
1
- declare const _default: {
2
- name: string;
3
- type: string;
4
- data: {};
5
- }[];
6
- export default _default;
@@ -1,9 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = [
4
- {
5
- name: "app",
6
- type: "app",
7
- data: {},
8
- }
9
- ];
@@ -1,336 +0,0 @@
1
- // Auto-generado por @nano-app
2
- // No editar manualmente.
3
- export default [
4
- {
5
- "name": "api",
6
- "type": "api",
7
- "path": "/api",
8
- "data": {
9
- "busy": true,
10
- "refresh": false,
11
- "DefaultItems": [],
12
- "UserStatusItems": [
13
- {
14
- "key": "SUSPENDED",
15
- "text": "Suspendido"
16
- },
17
- {
18
- "key": "PENDING",
19
- "text": "Pendiente"
20
- },
21
- {
22
- "key": "ACTIVE",
23
- "text": "Activo"
24
- }
25
- ]
26
- }
27
- },
28
- {
29
- "name": "app",
30
- "type": "app",
31
- "data": {
32
- "isRegister": false,
33
- "navbar": {
34
- "tabs": [],
35
- "selectedTabKey": "home",
36
- "selectedTab": {},
37
- "isMenuOpen": false
38
- },
39
- "form": {
40
- "data": {},
41
- "validate": []
42
- },
43
- "drawer": {
44
- "isOpen": false,
45
- "formType": "",
46
- "title": ""
47
- },
48
- "totales": {},
49
- "config": {
50
- "theme": "dark"
51
- }
52
- }
53
- },
54
- {
55
- "name": "const",
56
- "type": "app",
57
- "data": {
58
- "alias": "42974117.prex",
59
- "stepSkipTop": 20,
60
- "tabs": [
61
- {
62
- "key": "home",
63
- "href": "/",
64
- "label": "Home",
65
- "minRole": 1
66
- },
67
- {
68
- "key": "resumen",
69
- "href": "/resumen",
70
- "label": "Resumen",
71
- "minRole": 2
72
- },
73
- {
74
- "key": "admin",
75
- "href": "/admin",
76
- "label": "Administración",
77
- "minRole": 3
78
- },
79
- {
80
- "key": "uli",
81
- "href": "/",
82
- "label": "Uli :v",
83
- "minRole": 1
84
- },
85
- {
86
- "key": "luka",
87
- "href": "/",
88
- "label": "Lucas :v",
89
- "minRole": 1
90
- }
91
- ],
92
- "initialForms": {
93
- "User": {
94
- "rolId": 1,
95
- "status": "PENDING"
96
- },
97
- "Collection": {
98
- "total_months": 1,
99
- "start_date": "2026-03-01T00:00:00.000Z"
100
- }
101
- },
102
- "tableColumns": {
103
- "Users": [
104
- "name",
105
- "phone",
106
- "mail",
107
- "pending",
108
- "favor",
109
- "rol.name",
110
- "status"
111
- ],
112
- "Collections": [
113
- "user.name",
114
- "price",
115
- "description",
116
- "start_date",
117
- "total_months",
118
- "subscription.description"
119
- ],
120
- "Subscriptions": [
121
- "description",
122
- "price"
123
- ]
124
- },
125
- "formField": {
126
- "pay": [
127
- {
128
- "fieldName": "total",
129
- "valueType": "price",
130
- "isRequired": true
131
- }
132
- ],
133
- "login": [
134
- {
135
- "fieldName": "mail",
136
- "inputType": "email",
137
- "isRequired": true
138
- },
139
- {
140
- "fieldName": "password",
141
- "inputType": "password",
142
- "isRequired": true
143
- }
144
- ],
145
- "register": [
146
- {
147
- "fieldName": "name",
148
- "isRequired": true
149
- },
150
- {
151
- "fieldName": "phone",
152
- "isRequired": true
153
- },
154
- {
155
- "fieldName": "mail",
156
- "inputType": "email",
157
- "isRequired": true
158
- },
159
- {
160
- "fieldName": "password",
161
- "inputType": "password",
162
- "isRequired": true
163
- },
164
- {
165
- "fieldName": "confirmPassword",
166
- "inputType": "password",
167
- "isRequired": true
168
- }
169
- ],
170
- "Users": [
171
- {
172
- "fieldName": "name",
173
- "isRequired": true
174
- },
175
- {
176
- "fieldName": "mail",
177
- "inputType": "email",
178
- "isRequired": true
179
- },
180
- {
181
- "fieldName": "rolId",
182
- "valueType": "number",
183
- "isRequired": true,
184
- "inputType": "select",
185
- "select": {
186
- "items": "/Roles",
187
- "itemKey": "id",
188
- "showValues": [
189
- "name"
190
- ]
191
- }
192
- },
193
- {
194
- "fieldName": "status",
195
- "inputType": "select",
196
- "isRequired": true,
197
- "select": {
198
- "items": "/UserStatusItems",
199
- "itemKey": "key",
200
- "showValues": [
201
- "text"
202
- ]
203
- }
204
- },
205
- {
206
- "fieldName": "pending",
207
- "valueType": "price"
208
- },
209
- {
210
- "fieldName": "favor",
211
- "valueType": "price"
212
- }
213
- ],
214
- "Collections": [
215
- {
216
- "fieldName": "userId",
217
- "valueType": "number",
218
- "inputType": "select",
219
- "isRequired": true,
220
- "select": {
221
- "items": "Users",
222
- "itemKey": "id",
223
- "showValues": [
224
- "name"
225
- ]
226
- }
227
- },
228
- {
229
- "fieldName": "price",
230
- "valueType": "price",
231
- "isRequired": true
232
- },
233
- {
234
- "fieldName": "description",
235
- "isRequired": true
236
- },
237
- {
238
- "fieldName": "total_months",
239
- "valueType": "number",
240
- "isRequired": true
241
- },
242
- {
243
- "fieldName": "start_date",
244
- "valueType": "date",
245
- "inputType": "date",
246
- "isRequired": true
247
- },
248
- {
249
- "fieldName": "subscriptionId",
250
- "valueType": "number",
251
- "inputType": "select",
252
- "select": {
253
- "items": "Subscriptions",
254
- "itemKey": "id",
255
- "showValues": [
256
- "description"
257
- ]
258
- }
259
- }
260
- ],
261
- "Subscriptions": [
262
- {
263
- "fieldName": "description",
264
- "isRequired": true
265
- },
266
- {
267
- "fieldName": "price",
268
- "valueType": "price",
269
- "isRequired": true
270
- }
271
- ]
272
- },
273
- "expandFields": {
274
- "Users": "rol",
275
- "Collections": "user,subscription"
276
- }
277
- }
278
- },
279
- {
280
- "name": "i18n",
281
- "type": "app",
282
- "data": {
283
- "login": {
284
- "header": (isRegister) => isRegister ? "REGISTRARSE" : "INICIAR SESIÓN",
285
- "footer": (isRegister) => isRegister ? "o iniciar sesión" : "o registrarse",
286
- "buttonText": (isRegister) => isRegister ? "Crear" : "Ingresar"
287
- },
288
- "create": (entity) => `Crear ${entity}`,
289
- "edit": (entity) => `Editar ${entity}`,
290
- "mapping": {
291
- "name": "Nombre",
292
- "phone": "Teléfono",
293
- "mail": "Mail",
294
- "pending": "Pendiente",
295
- "favor": "A favor",
296
- "rolId": "Rol",
297
- "rol.name": "Rol",
298
- "status": "Estado",
299
- "password": "Contraseña",
300
- "confirmPassword": "Repetir contraseña",
301
- "user.name": "Usuario",
302
- "userId": "Usuario",
303
- "price": "Precio",
304
- "description": "Descripción",
305
- "start_date": "Fecha de inicio",
306
- "total_months": "Meses totales",
307
- "subscription.description": "Subscripción",
308
- "subscriptionId": "Subscripción",
309
- "last_pay": "Último pago",
310
- "first_month": "Mes de inicio",
311
- "current_month": "Último mes pagado",
312
- "payed_months": "Meses pagados",
313
- "actions": "Acciones",
314
- "created_at": "Creado",
315
- "Users": "Usuarios",
316
- "Collections": "Cuotas",
317
- "Subscriptions": "Subscripciones",
318
- "total": "TOTAL"
319
- },
320
- "months": {
321
- "1": "Enero",
322
- "2": "Febrero",
323
- "3": "Marzo",
324
- "4": "Abril",
325
- "5": "Mayo",
326
- "6": "Junio",
327
- "7": "Julio",
328
- "8": "Agosto",
329
- "9": "Septiembre",
330
- "10": "Octubre",
331
- "11": "Noviembre",
332
- "12": "Diciembre"
333
- }
334
- }
335
- }
336
- ];
@@ -1,47 +0,0 @@
1
- type ComponentId = symbol;
2
- /**
3
- {
4
- store1: {
5
- path1: {
6
- component1: true,
7
- component2: true,
8
- },
9
- path2: {
10
- component1: true,
11
- },
12
- path3: {
13
- component1: true,
14
- },
15
- }
16
- }
17
- */
18
- export declare class RenderManager {
19
- private dependenciesMap;
20
- private hooksMap;
21
- /**
22
- * Registra un hook de re-render para un componente
23
- * @param componentId - El id del componente
24
- * @param hook - El hook de re-render
25
- */
26
- register(componentId: ComponentId, hook: () => void): void;
27
- /**
28
- * Agrega una dependencia de path a un componente
29
- * @param componentId - El id del componente
30
- * @param path - El path del estado
31
- * @param storeName - El nombre del store
32
- */
33
- dependsOn(componentId: ComponentId, path: string, storeName: string): void;
34
- /**
35
- * Actualiza los componentes que dependen de este path
36
- * @param path - El path del estado
37
- * @param storeName - El nombre del store
38
- */
39
- refresh(path: string, storeName: string): void;
40
- /**
41
- * Elimina un componente del manager
42
- * @param componentId - El id del componente
43
- */
44
- unregister(componentId: ComponentId): void;
45
- }
46
- declare const _default: RenderManager;
47
- export default _default;
@@ -1,78 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RenderManager = void 0;
4
- /**
5
- {
6
- store1: {
7
- path1: {
8
- component1: true,
9
- component2: true,
10
- },
11
- path2: {
12
- component1: true,
13
- },
14
- path3: {
15
- component1: true,
16
- },
17
- }
18
- }
19
- */
20
- class RenderManager {
21
- dependenciesMap = new Map();
22
- hooksMap = new Map();
23
- /**
24
- * Registra un hook de re-render para un componente
25
- * @param componentId - El id del componente
26
- * @param hook - El hook de re-render
27
- */
28
- register(componentId, hook) {
29
- this.hooksMap.set(componentId, hook);
30
- }
31
- /**
32
- * Agrega una dependencia de path a un componente
33
- * @param componentId - El id del componente
34
- * @param path - El path del estado
35
- * @param storeName - El nombre del store
36
- */
37
- dependsOn(componentId, path, storeName) {
38
- // Si no existe el store, crea un nuevo mapa
39
- if (!this.dependenciesMap.has(storeName)) {
40
- this.dependenciesMap.set(storeName, new Map());
41
- }
42
- // Si no existe el path, crea un nuevo conjunto
43
- if (!this.dependenciesMap.get(storeName)?.has(path)) {
44
- this.dependenciesMap.get(storeName)?.set(path, new Set());
45
- }
46
- // Agrega el componente al conjunto de dependencias
47
- this.dependenciesMap.get(storeName)?.get(path)?.add(componentId);
48
- }
49
- /**
50
- * Actualiza los componentes que dependen de este path
51
- * @param path - El path del estado
52
- * @param storeName - El nombre del store
53
- */
54
- refresh(path, storeName) {
55
- // Obtiene los componentes que dependen de este path
56
- const components = this.dependenciesMap.get(storeName)?.get(path);
57
- // Si hay componentes que dependen de este path, actualiza cada uno
58
- if (components) {
59
- components.forEach((componentId) => {
60
- this.hooksMap.get(componentId)?.();
61
- });
62
- }
63
- }
64
- /**
65
- * Elimina un componente del manager
66
- * @param componentId - El id del componente
67
- */
68
- unregister(componentId) {
69
- this.hooksMap.delete(componentId);
70
- this.dependenciesMap.forEach((store) => {
71
- store.forEach((path) => {
72
- path.delete(componentId);
73
- });
74
- });
75
- }
76
- }
77
- exports.RenderManager = RenderManager;
78
- exports.default = new RenderManager();
@@ -1,4 +0,0 @@
1
- export declare class StateManager {
2
- private state;
3
- constructor(initialState?: Record<string, any>);
4
- }
@@ -1,10 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.StateManager = void 0;
4
- class StateManager {
5
- state = {};
6
- constructor(initialState = {}) {
7
- this.state = initialState;
8
- }
9
- }
10
- exports.StateManager = StateManager;
@@ -1,6 +0,0 @@
1
- declare const _default: {
2
- name: string;
3
- type: string;
4
- data: {};
5
- }[];
6
- export default _default;
@@ -1,9 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = [
4
- {
5
- name: "app",
6
- type: "app",
7
- data: {},
8
- }
9
- ];
@@ -1,14 +0,0 @@
1
- /**
2
- * Resuelve un path slash-based sobre un objeto y retorna el valor en esa ruta.
3
- * Retorna undefined de forma segura si algún segmento no existe.
4
- *
5
- * Ejemplo: resolvePath(state, "/user/profile/name")
6
- */
7
- export declare function resolvePath(obj: unknown, path: string): unknown;
8
- /**
9
- * Retorna un nuevo objeto con el valor en el path slash-based asignado de forma inmutable.
10
- * Los objetos intermedios se clonan superficialmente. Los nodos intermedios faltantes se crean.
11
- *
12
- * Ejemplo: setPath(state, "/user/profile/name", "Alice")
13
- */
14
- export declare function setPath(obj: unknown, path: string, value: unknown): Record<string, unknown>;
@@ -1,43 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolvePath = resolvePath;
4
- exports.setPath = setPath;
5
- /**
6
- * Resuelve un path slash-based sobre un objeto y retorna el valor en esa ruta.
7
- * Retorna undefined de forma segura si algún segmento no existe.
8
- *
9
- * Ejemplo: resolvePath(state, "/user/profile/name")
10
- */
11
- function resolvePath(obj, path) {
12
- const segments = path.split("/").filter((s) => s !== "");
13
- let current = obj;
14
- for (const segment of segments) {
15
- if (current === null || current === undefined || typeof current !== "object") {
16
- return undefined;
17
- }
18
- current = current[segment];
19
- }
20
- return current;
21
- }
22
- /**
23
- * Retorna un nuevo objeto con el valor en el path slash-based asignado de forma inmutable.
24
- * Los objetos intermedios se clonan superficialmente. Los nodos intermedios faltantes se crean.
25
- *
26
- * Ejemplo: setPath(state, "/user/profile/name", "Alice")
27
- */
28
- function setPath(obj, path, value) {
29
- const segments = path.split("/").filter((s) => s !== "");
30
- const root = obj && typeof obj === "object" ? { ...obj } : {};
31
- if (segments.length === 0)
32
- return root;
33
- let node = root;
34
- for (let i = 0; i < segments.length - 1; i++) {
35
- const key = segments[i];
36
- const child = node[key];
37
- const cloned = child && typeof child === "object" ? { ...child } : {};
38
- node[key] = cloned;
39
- node = cloned;
40
- }
41
- node[segments[segments.length - 1]] = value;
42
- return root;
43
- }