@stonecrop/stonecrop 0.7.8 → 0.8.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/src/composable.d.ts +8 -0
- package/dist/src/composable.d.ts.map +1 -1
- package/dist/src/composable.js +129 -0
- package/dist/src/registry.d.ts +59 -0
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/registry.js +166 -0
- package/dist/src/stonecrop.d.ts.map +1 -1
- package/dist/src/stonecrop.js +6 -3
- package/dist/src/stores/hst.d.ts +5 -0
- package/dist/src/stores/hst.d.ts.map +1 -1
- package/dist/src/stores/hst.js +10 -3
- package/dist/stonecrop.d.ts +163 -1
- package/dist/stonecrop.js +917 -729
- package/dist/stonecrop.js.map +1 -1
- package/dist/stonecrop.umd.cjs +3 -3
- package/dist/stonecrop.umd.cjs.map +1 -1
- package/package.json +3 -3
- package/src/composable.ts +166 -0
- package/src/registry.ts +189 -0
- package/src/stonecrop.ts +6 -3
- package/src/stores/hst.ts +13 -3
package/dist/src/composable.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Stonecrop } from './stonecrop';
|
|
|
4
4
|
import DoctypeMeta from './doctype';
|
|
5
5
|
import type { HSTNode } from './stores/hst';
|
|
6
6
|
import type { HSTOperation, OperationLogConfig, OperationLogSnapshot } from './types/operation-log';
|
|
7
|
+
import { SchemaTypes } from '@stonecrop/aform';
|
|
7
8
|
/**
|
|
8
9
|
* Operation Log API - nested object containing all operation log functionality
|
|
9
10
|
* @public
|
|
@@ -51,6 +52,13 @@ export type HSTStonecropReturn = BaseStonecropReturn & {
|
|
|
51
52
|
handleHSTChange: (changeData: HSTChangeData) => void;
|
|
52
53
|
hstStore: Ref<HSTNode | undefined>;
|
|
53
54
|
formData: Ref<Record<string, any>>;
|
|
55
|
+
resolvedSchema: Ref<SchemaTypes[]>;
|
|
56
|
+
loadNestedData: (parentPath: string, childDoctype: DoctypeMeta, recordId?: string) => Record<string, any>;
|
|
57
|
+
saveRecursive: (doctype: DoctypeMeta, recordId: string) => Promise<Record<string, any>>;
|
|
58
|
+
createNestedContext: (basePath: string, childDoctype: DoctypeMeta) => {
|
|
59
|
+
provideHSTPath: (fieldname: string) => string;
|
|
60
|
+
handleHSTChange: (changeData: HSTChangeData) => void;
|
|
61
|
+
};
|
|
54
62
|
};
|
|
55
63
|
/**
|
|
56
64
|
* HST Change data structure
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composable.d.ts","sourceRoot":"","sources":["../../src/composable.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,GAAG,EAAiC,WAAW,EAAE,MAAM,KAAK,CAAA;AAExF,OAAO,QAAQ,MAAM,YAAY,CAAA;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,WAAW,MAAM,WAAW,CAAA;AACnC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAG3C,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"composable.d.ts","sourceRoot":"","sources":["../../src/composable.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,GAAG,EAAiC,WAAW,EAAE,MAAM,KAAK,CAAA;AAExF,OAAO,QAAQ,MAAM,YAAY,CAAA;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,WAAW,MAAM,WAAW,CAAA;AACnC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAG3C,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AACnG,OAAO,EAAE,WAAW,EAAiB,MAAM,kBAAkB,CAAA;AAE7D;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG;IAC7B,UAAU,EAAE,GAAG,CAAC,YAAY,EAAE,CAAC,CAAA;IAC/B,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACzB,aAAa,EAAE,WAAW,CAAC;QAC1B,OAAO,EAAE,OAAO,CAAA;QAChB,OAAO,EAAE,OAAO,CAAA;QAChB,SAAS,EAAE,MAAM,CAAA;QACjB,SAAS,EAAE,MAAM,CAAA;QACjB,YAAY,EAAE,MAAM,CAAA;KACpB,CAAC,CAAA;IACF,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,CAAA;IAC7B,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,CAAA;IAC7B,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAC9B,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAC9B,IAAI,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,OAAO,CAAA;IACpC,IAAI,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,OAAO,CAAA;IACpC,UAAU,EAAE,MAAM,IAAI,CAAA;IACtB,WAAW,EAAE,CAAC,WAAW,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAA;IACpD,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,gBAAgB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,YAAY,EAAE,CAAA;IACxE,WAAW,EAAE,MAAM,oBAAoB,CAAA;IACvC,gBAAgB,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/D,SAAS,EAAE,CACV,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,EAAE,EACpB,MAAM,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,EAC1C,KAAK,CAAC,EAAE,MAAM,KACV,MAAM,CAAA;IACX,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,kBAAkB,CAAC,KAAK,IAAI,CAAA;CACzD,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG;IACjC,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC,CAAA;IACrC,YAAY,EAAE,eAAe,CAAA;CAC7B,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,mBAAmB,GAAG;IACtD,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;IAChE,eAAe,EAAE,CAAC,UAAU,EAAE,aAAa,KAAK,IAAI,CAAA;IACpD,QAAQ,EAAE,GAAG,CAAC,OAAO,GAAG,SAAS,CAAC,CAAA;IAClC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAA;IAClC,cAAc,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC,CAAA;IAClC,cAAc,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACzG,aAAa,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAA;IACvF,mBAAmB,EAAE,CACpB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,WAAW,KACrB;QACJ,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAA;QAC7C,eAAe,EAAE,CAAC,UAAU,EAAE,aAAa,KAAK,IAAI,CAAA;KACpD,CAAA;CACD,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,GAAG,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,IAAI,mBAAmB,GAAG,kBAAkB,CAAA;AACxE;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE;IACrC,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB,OAAO,EAAE,WAAW,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;CACjB,GAAG,kBAAkB,CAAA"}
|
package/dist/src/composable.js
CHANGED
|
@@ -16,6 +16,17 @@ export function useStonecrop(options) {
|
|
|
16
16
|
// Use refs for router-loaded doctype to maintain reactivity
|
|
17
17
|
const routerDoctype = ref();
|
|
18
18
|
const routerRecordId = ref();
|
|
19
|
+
// Resolved schema with nested Doctype fields expanded
|
|
20
|
+
const resolvedSchema = ref([]);
|
|
21
|
+
// Auto-resolve schema when doctype is available
|
|
22
|
+
if (options.doctype && registry) {
|
|
23
|
+
const schemaArray = options.doctype.schema
|
|
24
|
+
? Array.isArray(options.doctype.schema)
|
|
25
|
+
? options.doctype.schema
|
|
26
|
+
: Array.from(options.doctype.schema)
|
|
27
|
+
: [];
|
|
28
|
+
resolvedSchema.value = registry.resolveSchema(schemaArray);
|
|
29
|
+
}
|
|
19
30
|
// Operation log state and methods - will be populated after stonecrop instance is created
|
|
20
31
|
const operations = ref([]);
|
|
21
32
|
const currentIndex = ref(-1);
|
|
@@ -116,6 +127,15 @@ export function useStonecrop(options) {
|
|
|
116
127
|
routerDoctype.value = doctype;
|
|
117
128
|
routerRecordId.value = recordId;
|
|
118
129
|
hstStore.value = stonecrop.value.getStore();
|
|
130
|
+
// Resolve schema for router-loaded doctype
|
|
131
|
+
if (registry) {
|
|
132
|
+
const schemaArray = doctype.schema
|
|
133
|
+
? Array.isArray(doctype.schema)
|
|
134
|
+
? doctype.schema
|
|
135
|
+
: Array.from(doctype.schema)
|
|
136
|
+
: [];
|
|
137
|
+
resolvedSchema.value = registry.resolveSchema(schemaArray);
|
|
138
|
+
}
|
|
119
139
|
if (recordId && recordId !== 'new') {
|
|
120
140
|
const existingRecord = stonecrop.value.getRecordById(doctype, recordId);
|
|
121
141
|
if (existingRecord) {
|
|
@@ -230,6 +250,86 @@ export function useStonecrop(options) {
|
|
|
230
250
|
provide('hstPathProvider', provideHSTPath);
|
|
231
251
|
provide('hstChangeHandler', handleHSTChange);
|
|
232
252
|
}
|
|
253
|
+
/**
|
|
254
|
+
* Load nested doctype data from API or initialize empty structure
|
|
255
|
+
* @param parentPath - The parent path (e.g., "customer.123.address")
|
|
256
|
+
* @param childDoctype - The child doctype metadata
|
|
257
|
+
* @param recordId - Optional record ID to load
|
|
258
|
+
* @returns Promise resolving to the loaded or initialized data
|
|
259
|
+
*/
|
|
260
|
+
const loadNestedData = (parentPath, childDoctype, recordId) => {
|
|
261
|
+
if (!stonecrop.value) {
|
|
262
|
+
return initializeNewRecord(childDoctype);
|
|
263
|
+
}
|
|
264
|
+
// If recordId provided, try to load existing data
|
|
265
|
+
if (recordId) {
|
|
266
|
+
try {
|
|
267
|
+
// Check if data already exists in HST
|
|
268
|
+
const existingData = hstStore.value?.get(parentPath);
|
|
269
|
+
if (existingData && typeof existingData === 'object') {
|
|
270
|
+
return existingData;
|
|
271
|
+
}
|
|
272
|
+
// TODO: Add API fetch logic here if needed
|
|
273
|
+
// For now, initialize new record
|
|
274
|
+
return initializeNewRecord(childDoctype);
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
return initializeNewRecord(childDoctype);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// Initialize new record
|
|
281
|
+
return initializeNewRecord(childDoctype);
|
|
282
|
+
};
|
|
283
|
+
/**
|
|
284
|
+
* Recursively save a record with all nested doctype fields
|
|
285
|
+
* @param doctype - The doctype metadata
|
|
286
|
+
* @param recordId - The record ID to save
|
|
287
|
+
* @returns Promise resolving to the complete save payload
|
|
288
|
+
*/
|
|
289
|
+
const saveRecursive = async (doctype, recordId) => {
|
|
290
|
+
if (!hstStore.value || !stonecrop.value) {
|
|
291
|
+
throw new Error('HST store not initialized');
|
|
292
|
+
}
|
|
293
|
+
const recordPath = `${doctype.slug}.${recordId}`;
|
|
294
|
+
const recordData = hstStore.value.get(recordPath) || {};
|
|
295
|
+
// Build the save payload using resolved schema
|
|
296
|
+
const payload = { ...recordData };
|
|
297
|
+
// Use resolveSchema to get the full resolved tree, then walk Doctype fields
|
|
298
|
+
const schemaArray = (doctype.schema ? (Array.isArray(doctype.schema) ? doctype.schema : Array.from(doctype.schema)) : []);
|
|
299
|
+
const resolved = registry ? registry.resolveSchema(schemaArray) : schemaArray;
|
|
300
|
+
const doctypeFields = resolved.filter(field => 'fieldtype' in field && field.fieldtype === 'Doctype' && 'schema' in field && Array.isArray(field.schema));
|
|
301
|
+
// Recursively collect nested data from HST using resolved schemas
|
|
302
|
+
for (const field of doctypeFields) {
|
|
303
|
+
const doctypeField = field;
|
|
304
|
+
const fieldPath = `${recordPath}.${doctypeField.fieldname}`;
|
|
305
|
+
const nestedData = collectNestedData(doctypeField.schema, fieldPath, hstStore.value);
|
|
306
|
+
payload[doctypeField.fieldname] = nestedData;
|
|
307
|
+
}
|
|
308
|
+
return payload;
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* Create a nested context for child forms
|
|
312
|
+
* @param basePath - The base path for the nested context (e.g., "customer.123.address")
|
|
313
|
+
* @param _childDoctype - The child doctype metadata (unused but kept for API consistency)
|
|
314
|
+
* @returns Object with scoped provideHSTPath and handleHSTChange
|
|
315
|
+
*/
|
|
316
|
+
const createNestedContext = (basePath, _childDoctype) => {
|
|
317
|
+
const nestedProvideHSTPath = (fieldname) => {
|
|
318
|
+
return `${basePath}.${fieldname}`;
|
|
319
|
+
};
|
|
320
|
+
const nestedHandleHSTChange = (changeData) => {
|
|
321
|
+
// Update the path to be relative to the nested base path
|
|
322
|
+
const nestedPath = changeData.path.startsWith(basePath) ? changeData.path : `${basePath}.${changeData.fieldname}`;
|
|
323
|
+
handleHSTChange({
|
|
324
|
+
...changeData,
|
|
325
|
+
path: nestedPath,
|
|
326
|
+
});
|
|
327
|
+
};
|
|
328
|
+
return {
|
|
329
|
+
provideHSTPath: nestedProvideHSTPath,
|
|
330
|
+
handleHSTChange: nestedHandleHSTChange,
|
|
331
|
+
};
|
|
332
|
+
};
|
|
233
333
|
// Create operation log API object
|
|
234
334
|
const operationLog = {
|
|
235
335
|
operations,
|
|
@@ -261,6 +361,10 @@ export function useStonecrop(options) {
|
|
|
261
361
|
handleHSTChange,
|
|
262
362
|
hstStore,
|
|
263
363
|
formData,
|
|
364
|
+
resolvedSchema,
|
|
365
|
+
loadNestedData,
|
|
366
|
+
saveRecursive,
|
|
367
|
+
createNestedContext,
|
|
264
368
|
};
|
|
265
369
|
}
|
|
266
370
|
else if (!options.doctype && registry?.router) {
|
|
@@ -272,6 +376,10 @@ export function useStonecrop(options) {
|
|
|
272
376
|
handleHSTChange,
|
|
273
377
|
hstStore,
|
|
274
378
|
formData,
|
|
379
|
+
resolvedSchema,
|
|
380
|
+
loadNestedData,
|
|
381
|
+
saveRecursive,
|
|
382
|
+
createNestedContext,
|
|
275
383
|
};
|
|
276
384
|
}
|
|
277
385
|
// No doctype and no router - basic mode
|
|
@@ -346,3 +454,24 @@ function updateNestedObject(obj, path, value) {
|
|
|
346
454
|
const finalKey = path[path.length - 1];
|
|
347
455
|
current[finalKey] = value;
|
|
348
456
|
}
|
|
457
|
+
/**
|
|
458
|
+
* Recursively collect nested data from HST using pre-resolved schemas
|
|
459
|
+
* @param resolvedSchema - The already-resolved schema (with nested schemas embedded)
|
|
460
|
+
* @param basePath - The base path in HST (e.g., "customer.123.address")
|
|
461
|
+
* @param hstStore - The HST store instance
|
|
462
|
+
* @returns The collected data object
|
|
463
|
+
*/
|
|
464
|
+
function collectNestedData(resolvedSchema, basePath, hstStore) {
|
|
465
|
+
const data = hstStore.get(basePath) || {};
|
|
466
|
+
const payload = { ...data };
|
|
467
|
+
// Find Doctype fields that have resolved child schemas
|
|
468
|
+
const doctypeFields = resolvedSchema.filter(field => 'fieldtype' in field && field.fieldtype === 'Doctype' && 'schema' in field && Array.isArray(field.schema));
|
|
469
|
+
// Recursively collect nested data
|
|
470
|
+
for (const field of doctypeFields) {
|
|
471
|
+
const doctypeField = field;
|
|
472
|
+
const fieldPath = `${basePath}.${doctypeField.fieldname}`;
|
|
473
|
+
const nestedData = collectNestedData(doctypeField.schema, fieldPath, hstStore);
|
|
474
|
+
payload[doctypeField.fieldname] = nestedData;
|
|
475
|
+
}
|
|
476
|
+
return payload;
|
|
477
|
+
}
|
package/dist/src/registry.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SchemaTypes } from '@stonecrop/aform';
|
|
1
2
|
import { Router } from 'vue-router';
|
|
2
3
|
import DoctypeMeta from './doctype';
|
|
3
4
|
import { RouteContext } from './types/registry';
|
|
@@ -44,5 +45,63 @@ export default class Registry {
|
|
|
44
45
|
* @see {@link DoctypeMeta}
|
|
45
46
|
*/
|
|
46
47
|
addDoctype(doctype: DoctypeMeta): void;
|
|
48
|
+
/**
|
|
49
|
+
* Resolve nested Doctype and Table fields in a schema by embedding child schemas inline.
|
|
50
|
+
*
|
|
51
|
+
* @remarks
|
|
52
|
+
* Walks the schema array and for each field with `fieldtype: 'Doctype'` and a string
|
|
53
|
+
* `options` value, looks up the referenced doctype in the registry and embeds its schema
|
|
54
|
+
* as the field's `schema` property. Recurses for deeply nested doctypes.
|
|
55
|
+
*
|
|
56
|
+
* For fields with `fieldtype: 'Table'`, looks up the referenced child doctype and
|
|
57
|
+
* auto-derives `columns` from its schema fields (unless columns are already provided).
|
|
58
|
+
* Also sets sensible defaults for `component` (`'ATable'`) and `config` (`{ view: 'list' }`).
|
|
59
|
+
* Row data is expected to come from the parent form's data model at `data[fieldname]`.
|
|
60
|
+
*
|
|
61
|
+
* Returns a new array — does not mutate the original schema.
|
|
62
|
+
*
|
|
63
|
+
* @param schema - The schema array to resolve
|
|
64
|
+
* @returns A new schema array with nested Doctype fields resolved
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* registry.addDoctype(addressDoctype)
|
|
69
|
+
* registry.addDoctype(customerDoctype)
|
|
70
|
+
*
|
|
71
|
+
* // Before: customer schema has { fieldname: 'address', fieldtype: 'Doctype', options: 'address' }
|
|
72
|
+
* const resolved = registry.resolveSchema(customerSchema)
|
|
73
|
+
* // After: address field now has schema: [...address fields...]
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* @public
|
|
77
|
+
*/
|
|
78
|
+
resolveSchema(schema: SchemaTypes[], visited?: Set<string>): SchemaTypes[];
|
|
79
|
+
/**
|
|
80
|
+
* Initialize a new record with default values based on a schema.
|
|
81
|
+
*
|
|
82
|
+
* @remarks
|
|
83
|
+
* Creates a plain object with keys from the schema's fieldnames and default values
|
|
84
|
+
* derived from each field's `fieldtype`:
|
|
85
|
+
* - Data, Text → `''`
|
|
86
|
+
* - Check → `false`
|
|
87
|
+
* - Int, Float, Decimal, Currency, Quantity → `0`
|
|
88
|
+
* - Table → `[]`
|
|
89
|
+
* - JSON, Doctype → `{}`
|
|
90
|
+
* - All others → `null`
|
|
91
|
+
*
|
|
92
|
+
* For Doctype fields with a resolved `schema` array, recursively initializes the nested record.
|
|
93
|
+
*
|
|
94
|
+
* @param schema - The schema array to derive defaults from
|
|
95
|
+
* @returns A plain object with default values for each field
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* const defaults = registry.initializeRecord(addressSchema)
|
|
100
|
+
* // { street: '', city: '', state: '', zip_code: '' }
|
|
101
|
+
* ```
|
|
102
|
+
*
|
|
103
|
+
* @public
|
|
104
|
+
*/
|
|
105
|
+
initializeRecord(schema: SchemaTypes[]): Record<string, any>;
|
|
47
106
|
}
|
|
48
107
|
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAEnC,OAAO,WAAW,MAAM,WAAW,CAAA;AAEnC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAE/C;;;GAGG;AACH,MAAM,CAAC,OAAO,OAAO,QAAQ;IAC5B;;OAEG;IACH,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAA;IAEtB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IAE9C;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IAExB;;;;OAIG;gBACS,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAWzG;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;IAE5E;;;;;OAKG;IACH,UAAU,CAAC,OAAO,EAAE,WAAW;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAEnC,OAAO,WAAW,MAAM,WAAW,CAAA;AAEnC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAE/C;;;GAGG;AACH,MAAM,CAAC,OAAO,OAAO,QAAQ;IAC5B;;OAEG;IACH,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAA;IAEtB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IAE9C;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IAExB;;;;OAIG;gBACS,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAWzG;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;IAE5E;;;;;OAKG;IACH,UAAU,CAAC,OAAO,EAAE,WAAW;IAsB/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,WAAW,EAAE;IAwF1E;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;CAwD5D"}
|
package/dist/src/registry.js
CHANGED
|
@@ -69,4 +69,170 @@ export default class Registry {
|
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Resolve nested Doctype and Table fields in a schema by embedding child schemas inline.
|
|
74
|
+
*
|
|
75
|
+
* @remarks
|
|
76
|
+
* Walks the schema array and for each field with `fieldtype: 'Doctype'` and a string
|
|
77
|
+
* `options` value, looks up the referenced doctype in the registry and embeds its schema
|
|
78
|
+
* as the field's `schema` property. Recurses for deeply nested doctypes.
|
|
79
|
+
*
|
|
80
|
+
* For fields with `fieldtype: 'Table'`, looks up the referenced child doctype and
|
|
81
|
+
* auto-derives `columns` from its schema fields (unless columns are already provided).
|
|
82
|
+
* Also sets sensible defaults for `component` (`'ATable'`) and `config` (`{ view: 'list' }`).
|
|
83
|
+
* Row data is expected to come from the parent form's data model at `data[fieldname]`.
|
|
84
|
+
*
|
|
85
|
+
* Returns a new array — does not mutate the original schema.
|
|
86
|
+
*
|
|
87
|
+
* @param schema - The schema array to resolve
|
|
88
|
+
* @returns A new schema array with nested Doctype fields resolved
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* registry.addDoctype(addressDoctype)
|
|
93
|
+
* registry.addDoctype(customerDoctype)
|
|
94
|
+
*
|
|
95
|
+
* // Before: customer schema has { fieldname: 'address', fieldtype: 'Doctype', options: 'address' }
|
|
96
|
+
* const resolved = registry.resolveSchema(customerSchema)
|
|
97
|
+
* // After: address field now has schema: [...address fields...]
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* @public
|
|
101
|
+
*/
|
|
102
|
+
resolveSchema(schema, visited) {
|
|
103
|
+
const seen = visited || new Set();
|
|
104
|
+
return schema.map(field => {
|
|
105
|
+
// Check for Doctype fieldtype with a string options (slug reference)
|
|
106
|
+
if ('fieldtype' in field &&
|
|
107
|
+
field.fieldtype === 'Doctype' &&
|
|
108
|
+
'options' in field &&
|
|
109
|
+
typeof field.options === 'string') {
|
|
110
|
+
const doctypeSlug = field.options;
|
|
111
|
+
// Circular reference protection
|
|
112
|
+
if (seen.has(doctypeSlug)) {
|
|
113
|
+
return { ...field };
|
|
114
|
+
}
|
|
115
|
+
const doctype = this.registry[doctypeSlug];
|
|
116
|
+
if (doctype && doctype.schema) {
|
|
117
|
+
// Convert Immutable.List to plain array if needed
|
|
118
|
+
const childSchema = Array.isArray(doctype.schema) ? doctype.schema : Array.from(doctype.schema);
|
|
119
|
+
// Recurse into child schema to resolve deeply nested doctypes
|
|
120
|
+
seen.add(doctypeSlug);
|
|
121
|
+
const resolvedChild = this.resolveSchema(childSchema, seen);
|
|
122
|
+
seen.delete(doctypeSlug);
|
|
123
|
+
return { ...field, schema: resolvedChild };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Resolve Table fieldtype — 1:many child doctype rendered as ATable
|
|
127
|
+
if ('fieldtype' in field &&
|
|
128
|
+
field.fieldtype === 'Table' &&
|
|
129
|
+
'options' in field &&
|
|
130
|
+
typeof field.options === 'string') {
|
|
131
|
+
const doctypeSlug = field.options;
|
|
132
|
+
// Circular reference protection
|
|
133
|
+
if (seen.has(doctypeSlug)) {
|
|
134
|
+
return { ...field };
|
|
135
|
+
}
|
|
136
|
+
const doctype = this.registry[doctypeSlug];
|
|
137
|
+
if (doctype && doctype.schema) {
|
|
138
|
+
const childSchema = Array.isArray(doctype.schema) ? doctype.schema : Array.from(doctype.schema);
|
|
139
|
+
const resolved = { ...field };
|
|
140
|
+
// Auto-derive columns from child schema fields if not already provided
|
|
141
|
+
if (!('columns' in field) || !field.columns) {
|
|
142
|
+
resolved.columns = childSchema.map(childField => ({
|
|
143
|
+
name: childField.fieldname,
|
|
144
|
+
fieldname: childField.fieldname,
|
|
145
|
+
label: ('label' in childField && childField.label) || childField.fieldname,
|
|
146
|
+
fieldtype: 'fieldtype' in childField ? childField.fieldtype : 'Data',
|
|
147
|
+
align: ('align' in childField && childField.align) || 'left',
|
|
148
|
+
edit: 'edit' in childField ? childField.edit : true,
|
|
149
|
+
width: ('width' in childField && childField.width) || '20ch',
|
|
150
|
+
}));
|
|
151
|
+
}
|
|
152
|
+
// Set default component if not already specified
|
|
153
|
+
if (!resolved.component) {
|
|
154
|
+
resolved.component = 'ATable';
|
|
155
|
+
}
|
|
156
|
+
// Set default config if not already specified
|
|
157
|
+
if (!('config' in field) || !field.config) {
|
|
158
|
+
resolved.config = { view: 'list' };
|
|
159
|
+
}
|
|
160
|
+
// Initialize rows to empty array so componentProps fallback
|
|
161
|
+
// routes data from the form's dataModel[fieldname]
|
|
162
|
+
if (!('rows' in field) || !field.rows) {
|
|
163
|
+
resolved.rows = [];
|
|
164
|
+
}
|
|
165
|
+
return resolved;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return { ...field };
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Initialize a new record with default values based on a schema.
|
|
173
|
+
*
|
|
174
|
+
* @remarks
|
|
175
|
+
* Creates a plain object with keys from the schema's fieldnames and default values
|
|
176
|
+
* derived from each field's `fieldtype`:
|
|
177
|
+
* - Data, Text → `''`
|
|
178
|
+
* - Check → `false`
|
|
179
|
+
* - Int, Float, Decimal, Currency, Quantity → `0`
|
|
180
|
+
* - Table → `[]`
|
|
181
|
+
* - JSON, Doctype → `{}`
|
|
182
|
+
* - All others → `null`
|
|
183
|
+
*
|
|
184
|
+
* For Doctype fields with a resolved `schema` array, recursively initializes the nested record.
|
|
185
|
+
*
|
|
186
|
+
* @param schema - The schema array to derive defaults from
|
|
187
|
+
* @returns A plain object with default values for each field
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```ts
|
|
191
|
+
* const defaults = registry.initializeRecord(addressSchema)
|
|
192
|
+
* // { street: '', city: '', state: '', zip_code: '' }
|
|
193
|
+
* ```
|
|
194
|
+
*
|
|
195
|
+
* @public
|
|
196
|
+
*/
|
|
197
|
+
initializeRecord(schema) {
|
|
198
|
+
const record = {};
|
|
199
|
+
schema.forEach(field => {
|
|
200
|
+
const fieldtype = 'fieldtype' in field ? field.fieldtype : 'Data';
|
|
201
|
+
switch (fieldtype) {
|
|
202
|
+
case 'Data':
|
|
203
|
+
case 'Text':
|
|
204
|
+
case 'Code':
|
|
205
|
+
record[field.fieldname] = '';
|
|
206
|
+
break;
|
|
207
|
+
case 'Check':
|
|
208
|
+
record[field.fieldname] = false;
|
|
209
|
+
break;
|
|
210
|
+
case 'Int':
|
|
211
|
+
case 'Float':
|
|
212
|
+
case 'Decimal':
|
|
213
|
+
case 'Currency':
|
|
214
|
+
case 'Quantity':
|
|
215
|
+
record[field.fieldname] = 0;
|
|
216
|
+
break;
|
|
217
|
+
case 'Table':
|
|
218
|
+
record[field.fieldname] = [];
|
|
219
|
+
break;
|
|
220
|
+
case 'JSON':
|
|
221
|
+
record[field.fieldname] = {};
|
|
222
|
+
break;
|
|
223
|
+
case 'Doctype':
|
|
224
|
+
// If nested schema is resolved, recursively initialize
|
|
225
|
+
if ('schema' in field && Array.isArray(field.schema)) {
|
|
226
|
+
record[field.fieldname] = this.initializeRecord(field.schema);
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
record[field.fieldname] = {};
|
|
230
|
+
}
|
|
231
|
+
break;
|
|
232
|
+
default:
|
|
233
|
+
record[field.fieldname] = null;
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
return record;
|
|
237
|
+
}
|
|
72
238
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stonecrop.d.ts","sourceRoot":"","sources":["../../src/stonecrop.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"stonecrop.d.ts","sourceRoot":"","sources":["../../src/stonecrop.ts"],"names":[],"mappings":"AACA,OAAO,WAAW,MAAM,WAAW,CAAA;AACnC,OAAO,QAAQ,MAAM,YAAY,CAAA;AACjC,OAAO,EAAa,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAEpD;;;GAGG;AACH,qBAAa,SAAS;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,kBAAkB,CAAC,CAAyC;IACpE,OAAO,CAAC,mBAAmB,CAAC,CAA6B;IAEzD,+DAA+D;IAC/D,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAE3B;;;;OAIG;gBACS,QAAQ,EAAE,QAAQ,EAAE,kBAAkB,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC;IAWhF;;;OAGG;IACH,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAUpB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAa1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAgBzB;;;;OAIG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,OAAO;IAM/C;;;;;OAKG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,GAAG,IAAI;IASjF;;;;;OAKG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAoBnF;;;;OAIG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAUnE;;;;OAIG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,EAAE;IAYrD;;;OAGG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAWjD;;;OAGG;IACH,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAKjC;;;;;;OAMG;IACH,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI;IAkCnE;;;OAGG;IACG,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAYrD;;;;OAIG;IACG,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQtE;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAM3B;;;;OAIG;IACG,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC;IAOlD;;;OAGG;IACH,QAAQ,IAAI,OAAO;CAGnB"}
|
package/dist/src/stonecrop.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { reactive } from 'vue';
|
|
1
2
|
import { createHST } from './stores/hst';
|
|
2
3
|
import { useOperationLogStore } from './stores/operation-log';
|
|
3
4
|
/**
|
|
@@ -45,7 +46,9 @@ export class Stonecrop {
|
|
|
45
46
|
Object.keys(this.registry.registry).forEach(doctypeSlug => {
|
|
46
47
|
initialStoreStructure[doctypeSlug] = {};
|
|
47
48
|
});
|
|
48
|
-
|
|
49
|
+
// Wrap the store in Vue's reactive() for automatic change detection
|
|
50
|
+
// This enables Vue computed properties to track HST store changes
|
|
51
|
+
this.hstStore = createHST(reactive(initialStoreStructure), 'StonecropStore');
|
|
49
52
|
}
|
|
50
53
|
/**
|
|
51
54
|
* Setup automatic sync with Registry when doctypes are added
|
|
@@ -202,9 +205,9 @@ export class Stonecrop {
|
|
|
202
205
|
*/
|
|
203
206
|
async getRecords(doctype) {
|
|
204
207
|
const response = await fetch(`/${doctype.slug}`);
|
|
205
|
-
const records = await response.json();
|
|
208
|
+
const records = (await response.json());
|
|
206
209
|
// Store each record in HST
|
|
207
|
-
records.forEach(
|
|
210
|
+
records.forEach(record => {
|
|
208
211
|
if (record.id) {
|
|
209
212
|
this.addRecord(doctype, record.id, record);
|
|
210
213
|
}
|
package/dist/src/stores/hst.d.ts
CHANGED
|
@@ -139,6 +139,11 @@ declare class HSTProxy implements HSTNode {
|
|
|
139
139
|
private isPiniaStore;
|
|
140
140
|
private isImmutable;
|
|
141
141
|
private isPrimitive;
|
|
142
|
+
/**
|
|
143
|
+
* Parse a path string into segments, handling both dot notation and array bracket notation
|
|
144
|
+
* @param path - The path string to parse (e.g., "order.456.line_items[0].product")
|
|
145
|
+
* @returns Array of path segments (e.g., ['order', '456', 'line_items', '0', 'product'])
|
|
146
|
+
*/
|
|
142
147
|
private parsePath;
|
|
143
148
|
}
|
|
144
149
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hst.d.ts","sourceRoot":"","sources":["../../../src/stores/hst.ts"],"names":[],"mappings":"AAgBA;;;;;GAKG;AACH,UAAU,OAAO;IAChB;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAA;IAEtB;;;;;OAKG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAE1F;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IAE1B;;;OAGG;IACH,SAAS,IAAI,OAAO,GAAG,IAAI,CAAA;IAE3B;;;OAGG;IACH,OAAO,IAAI,OAAO,CAAA;IAElB;;;OAGG;IACH,OAAO,IAAI,MAAM,CAAA;IAEjB;;;OAGG;IACH,QAAQ,IAAI,MAAM,CAAA;IAElB;;;OAGG;IACH,cAAc,IAAI,MAAM,EAAE,CAAA;IAE1B;;;;OAIG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IAE9B;;;;;OAKG;IACH,iBAAiB,CAChB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;KAAE,GACzF,OAAO,CAAC,GAAG,CAAC,CAAA;CACf;AAGD,UAAU,cAAc;IACvB,QAAQ,CAAC,EAAE;QACV,KAAK,CAAC,EAAE;YACP,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;SAC7B,CAAA;KACD,CAAA;CACD;AAsCD,OAAO,CAAC,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"hst.d.ts","sourceRoot":"","sources":["../../../src/stores/hst.ts"],"names":[],"mappings":"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"}
|
package/dist/src/stores/hst.js
CHANGED
|
@@ -141,7 +141,6 @@ class HSTProxy {
|
|
|
141
141
|
// Detect if this is a DELETE operation (setting to undefined when a value existed)
|
|
142
142
|
const isDelete = value === undefined && beforeValue !== undefined;
|
|
143
143
|
const operationType = isDelete ? 'delete' : 'set';
|
|
144
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
145
144
|
logStore.addOperation({
|
|
146
145
|
type: operationType,
|
|
147
146
|
path: fullPath,
|
|
@@ -254,7 +253,6 @@ class HSTProxy {
|
|
|
254
253
|
// Log FSM transition operation
|
|
255
254
|
const logStore = getOperationLogStore();
|
|
256
255
|
if (logStore && typeof logStore.addOperation === 'function') {
|
|
257
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
258
256
|
logStore.addOperation({
|
|
259
257
|
type: 'transition',
|
|
260
258
|
path: this.parentPath,
|
|
@@ -459,10 +457,19 @@ class HSTProxy {
|
|
|
459
457
|
typeof value === 'symbol' ||
|
|
460
458
|
typeof value === 'bigint');
|
|
461
459
|
}
|
|
460
|
+
/**
|
|
461
|
+
* Parse a path string into segments, handling both dot notation and array bracket notation
|
|
462
|
+
* @param path - The path string to parse (e.g., "order.456.line_items[0].product")
|
|
463
|
+
* @returns Array of path segments (e.g., ['order', '456', 'line_items', '0', 'product'])
|
|
464
|
+
*/
|
|
462
465
|
parsePath(path) {
|
|
463
466
|
if (!path)
|
|
464
467
|
return [];
|
|
465
|
-
|
|
468
|
+
// Replace array bracket notation with dot notation
|
|
469
|
+
// items[0] → items.0
|
|
470
|
+
// items[0][1] → items.0.1
|
|
471
|
+
const normalizedPath = path.replace(/\[(\d+)\]/g, '.$1');
|
|
472
|
+
return normalizedPath.split('.').filter(segment => segment.length > 0);
|
|
466
473
|
}
|
|
467
474
|
}
|
|
468
475
|
/**
|