dt-toolbox 7.4.6 → 7.4.7

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/Changelog.md CHANGED
@@ -2,6 +2,28 @@
2
2
 
3
3
 
4
4
 
5
+ ### 7.4.7 ( 2026-07-15)
6
+ - [x] Fix: circular reference in data no longer crashes Node with OOM — `init` now throws a clear error;
7
+ - [x] Fix: Date and RegExp instances are now preserved when round-tripping through `init`/`model` (they were silently collapsed to `{}` by the walk library);
8
+ - [x] Fix: NaN and Infinity values are now preserved through `init`/`model` round-trips;
9
+ - [x] Fix: `model({as:'std'})` no longer drops data from extra segments — extra segments are now merged into the result;
10
+ - [x] Fix: `store.set` with a non-root breadcrumbs or a primitive value (string/number/boolean/null) now returns the value correctly through `model` (was: char-indexed string, missing data, or `undefined`);
11
+ - [x] Fix: `dt.index('root/a')` and other scalar-property breadcrumbs now return the property value (was: `null` for any scalar);
12
+ - [x] Fix: `dt.export(name)` now throws a clear error for non-string argument types (was: silently returned the whole model for some, `[]` for others);
13
+ - [x] Fix: `dt.copy(name)` now throws a clear error for non-string argument types (was: inconsistent `null` vs root-copy behavior);
14
+ - [x] Fix: `dt.extractList(['c/d'])` now resolves nested property paths via the dt-model (was: always returned `null` for any nested path);
15
+ - [x] Fix: `dt.insertSegment` now throws clear errors for missing/invalid `name` and for `data` that is `null`/`undefined`/a primitive (was: cryptic `Cannot read properties of ...reading '0'`);
16
+ - [x] Fix: `init(42)` / `init('hello')` / `init(true)` / `init(null)` now work — primitive values are wrapped in `{ value: <primitive> }` and preserved through the round-trip;
17
+ - [x] Fix: `dt.model(() => ({as: 42}))` / `({as: {}})` / unknown model names now throw clear errors (was: `console.error` + return `null`);
18
+ - [x] Fix: `dtbox.flat(null)` / `flat(undefined)` / `flat(42)` / `flat('hello')` now throw clear errors (was: silently returned `[]`);
19
+ - [x] Fix: `dtbox.flat(data, {model:'unknown'})` and `dtbox.convert(data, {as:'unknown'})` now throw clear errors (was: silently returned `null`);
20
+ - [x] New regression test file `test/06_bugfixes.test.js` covering all of the above with 51 new tests;
21
+ - [x] Two existing test cases updated to match the new throw-on-invalid-model behaviour for `flat` and `convert`;
22
+ - [x] Fix: `insertSegment` no longer accepts a segment name that already exists — it now throws a clear error. Before the fix, the second insert created a duplicate dt-line at the same breadcrumbs, and `model({as:'std'})` / `extractList` silently kept the first segment and dropped the second;
23
+ - [x] Fix: `insertSegment` no longer accepts segment names containing `/` — it now throws a clear error. The `/` is the breadcrumbs separator in the dt-model, so a name like `'a/b'` would create ambiguous dt-lines that silently broke `index()`, `extractList()`, and `model()` lookups;
24
+
25
+
26
+
5
27
  ### 7.4.6 ( 2026-07-14)
6
28
  - [x] Dependencies updates. @peter.naydenov/walk to version 5.0.6;
7
29
 
@@ -217,9 +239,9 @@
217
239
  - [x] Export API was removed. Methods were moved to main API or removed;
218
240
  - [x] Method that is searching for string in keys was renamed from 'folder' to 'find';
219
241
  - [x] Method 'folder' works like 'space' in previous versions. That makes more sense...;
220
- - [x] Method 'space' is depricated;
242
+ - [x] Method 'space' is deprecated;
221
243
  - [x] New method 'purify'. Removes empty structures from the selection;
222
- - [x] Method 'loadFast' was depricated. Use 'load' instead;
244
+ - [x] Method 'loadFast' was deprecated. Use 'load' instead;
223
245
  - [x] Added support for different data-models: standard, tuples, flat, midFlat, breadcrumbs, files;
224
246
  - [x] New method 'flatten' was added;
225
247
  - [x] New method 'mix' was added;
@@ -30,7 +30,7 @@ dt.query ( (store) => {
30
30
 
31
31
  ```
32
32
 
33
- Method `insert` was renamed to `insertSegment` to be clear that data is not mixed. Segments are separated peaces of data.
33
+ Method `insert` was renamed to `insertSegment` to be clear that data is not mixed. Segments are separated pieces of data.
34
34
 
35
35
  ```js
36
36
  // before
@@ -39,7 +39,7 @@ Method `insert` was renamed to `insertSegment` to be clear that data is not mixe
39
39
 
40
40
  // after
41
41
  const dt = dtbox.init ( a );
42
- dt.insertSegment ( 'specificDataName' b ) // b is a dt-object
42
+ dt.insertSegment ( 'specificDataName', b ) // b is a dt-object
43
43
  // it's possible to insert a standard js object but it's not recomended
44
44
  // dt.insertSegment ( 'specialDataName', a ) // a is a standard js object
45
45
  // also possible to insert a dt model object directly
@@ -60,7 +60,7 @@ const storage = dtbox.init ( first ); // first will become a root segment
60
60
  storage.insertSegment ( 'second', second );
61
61
  storage.insertSegment ( 'third', third );
62
62
 
63
- const [ a, b c, firstData ] = storage.extractList ( ['first', 'second', 'third', 'data' ], { type: 'std' } ));
63
+ const [ a, b, c, firstData ] = storage.extractList ( ['first', 'second', 'third', 'data' ], { as: 'std' } ));
64
64
  // a -> { name: 'first', data: 'first data' }
65
65
  // b -> { name: 'second', data: 'second data' }
66
66
  // c -> { name: 'third', data: 'third data' }
@@ -69,9 +69,9 @@ const [ a, b c, firstData ] = storage.extractList ( ['first', 'second', 'third',
69
69
 
70
70
  ## From v.4.x.x - v.6.x.x
71
71
 
72
- The library "dt-toolbox" exist for a full 7 years and now version 6 is coming as full rewrite of the original idea. Difference are more then similarity and better aproach is to read a version 6 documentation first. Then you will find that:
72
+ The library "dt-toolbox" has existed for a full 7 years and now version 6 is coming as full rewrite of the original idea. Differences are more than similarities and a better approach is to read a version 6 documentation first. Then you will find that:
73
73
 
74
- - Data creation is very simular;
74
+ - Data creation is very similar;
75
75
  - Dt-Object becomes a storage and you can add more data to it;
76
76
  - Dt-Object data will stay always immutable;
77
77
  - For extracting data you can use 'query' and 'model' functions;
@@ -122,7 +122,7 @@ Method 'spread' has a lot of changes. Instruction 'st' now is available as 'stan
122
122
 
123
123
 
124
124
  ### [x] Data-type 'dt'
125
- Internal data representation in the library was changed. I have recognized the need of information about data structures and their relations. So data-type `dt` was depricated as main internal representation data-type and we started to use `flat`. If you have build your application around 'dt' data-type, the library will continue to support it (load/spread). Code change required.
125
+ Internal data representation in the library was changed. I have recognized the need for information about data structures and their relations. So data-type `dt` was deprecated as main internal representation data-type and we started to use `flat`. If you have built your application around 'dt' data-type, the library will continue to support it (load/spread). Code change required.
126
126
 
127
127
  Old code:
128
128
  ```js
@@ -159,7 +159,7 @@ dtbox
159
159
  ### [x] Select methods 'folder' and 'space' were renamed
160
160
  Method `folder` was used to search for specific string into keys. Name is not very intuitive and was renamed to `find`. Library has also another problematic method name - `space`. Space can select internal flat structures by breadcrumb representation. Name `folder` is more appropriate here, so `space` was renamed to `folder`.
161
161
 
162
- Method `space` still exists but was depricated.
162
+ Method `space` still exists but was deprecated.
163
163
 
164
164
 
165
165
  Old code:
package/README.md CHANGED
@@ -14,7 +14,7 @@
14
14
  ## Last Updates
15
15
  - After version 7.4.2 - load the library with `require` or `import`. Folder '**dist**' contains the library in commonjs, esm and umd formats;
16
16
  - After version 7.3.0 extractList options.as can receive a `dt-model` and `dt-object`;
17
- - After version 7.1.x `dt-object` api has a new method `extractList` that helps to extract a multiple segments or properties, defined as a list. Use '**options**'(the second argument) to define a model of extracted data if needed. Reed about `extractList` bellow.
17
+ - After version 7.1.x `dt-object` api has a new method `extractList` that helps to extract a multiple segments or properties, defined as a list. Use '**options**'(the second argument) to define a model of extracted data if needed. Read about `extractList` bellow.
18
18
 
19
19
 
20
20
 
@@ -34,11 +34,11 @@ It's an internal 'dt-object' data description. Data is an array of lines where e
34
34
  // Where ->
35
35
  // name: string. Name of the dt-line;
36
36
  // flatData: object or array of primitive types;
37
- // breadcrumbs: string. Bredcrumbs description(identifier) of the current dt-line;
37
+ // breadcrumbs: string. Breadcrumbs description(identifier) of the current dt-line;
38
38
  // edges: string[]. List of breadcrumbs of the related dt-lines(children);
39
39
  ```
40
40
 
41
- This data-description is easy to read, saved, or transfered.
41
+ This data-description is easy to read, saved, or transferred.
42
42
 
43
43
  DT-model can become a storage for multiple data blocks - `data-segments`. Each data-segment can be extracted but also can be queried and modeled together with other data-segments in a way to create a new dt-object.
44
44
 
@@ -73,7 +73,7 @@ Use Dt-toolbox methods(init and load) to create a `dt-object`.
73
73
 
74
74
  DT-object:
75
75
  - Provides multiple insertion of data-segments. Data from each insertion stays differentiated;
76
- - Has prebuilded filters for fast search of data;
76
+ - Has prebuilt filters for fast search of data;
77
77
  - Can create and register a customized filters for fast search of data;
78
78
  - Can apply `query functions` to find, extract and reshape the data;
79
79
  - Can apply `model function` to reshape the final result;
@@ -125,10 +125,10 @@ Take a look on the library APIs and see the '**Examples**' section bellow.
125
125
  ### dt-toolbox API Fast Reference
126
126
 
127
127
  ```js
128
- init : 'Create a new dt-object from data that is not a DT-model and needs a convertion'
128
+ init : 'Create a new dt-object from data that is not a DT-model and needs a conversion'
129
129
  , load : 'Create a new dt-object from data that is a DT-model'
130
130
  , flat : 'Convert a data to DT-model without creation of dt-object'
131
- , convert : 'Direct convertion from model to model without creation of dt-object'
131
+ , convert : 'Direct conversion from model to model without creation of dt-object'
132
132
  , getWalk : 'Returns a instance of "walk" library'
133
133
  ```
134
134
 
@@ -175,7 +175,7 @@ Object `dt-storage` is available as argument to '**query**' and '**model**' func
175
175
  ## DT Toolbox API
176
176
 
177
177
  ### dtbox.init ()
178
- Create a new dt-object from data that is not a DT-model and needs a convertion. Please take a look on section `Init/Export Data-Models` for more details.
178
+ Create a new dt-object from data that is not a DT-model and needs a conversion. Please take a look on section `Init/Export Data-Models` for more details.
179
179
 
180
180
  ```js
181
181
  const data = { // Standard JS object
@@ -292,7 +292,7 @@ const inFlatModel = dtbox.flat ( a ) // Default data-model is set to 'standard'(
292
292
 
293
293
 
294
294
  ### dtbox.convert ()
295
- Direct convertion from model to model without creation of dt-object.
295
+ Direct conversion from model to model without creation of dt-object.
296
296
 
297
297
  ```js
298
298
 
@@ -491,9 +491,9 @@ function blueFn ({
491
491
  , breadcrumbs // Location description
492
492
  , edges // List of breadcrumbs related to this dt-line
493
493
  }) {
494
- if ( flatData.hasOwnProperty('eyes') && flatData.eyes === 'blue' ) return true // confirm that dt-line should be in that filter list
494
+ if ( flatData.hasOwnProperty('eyes') && flatData.eyes === 'blue' ) return true // confirm that dt-line should be in that filter list
495
495
  return false // ignore this dt-line
496
- // dt-lines that are
496
+ // dt-lines that are returned as `true` are added to the filter scan-list
497
497
  }
498
498
 
499
499
  dt.setupFilter (
@@ -538,7 +538,7 @@ dt.listSegments ()
538
538
 
539
539
  ### dt.extractList ()
540
540
 
541
- After version 7.1.x method `extractList` was added. Method can extract a list of segments and properties as a single instruction. Options are coming as a second argument. Use optioins(the second argument) to define a model of extracted data if needed. Modeling is applied only on objects.
541
+ After version 7.1.x method `extractList` was added. Method can extract a list of segments and properties as a single instruction. Options are coming as a second argument. Use options (the second argument) to define a model of extracted data if needed. Modeling is applied only on objects.
542
542
 
543
543
  If requested segment or property is not available, response will be '**null**'.
544
544
  Segments have priority over properties. If there is a segment with the same name as a property, segment will be extracted.
@@ -553,7 +553,7 @@ const storage = dtbox.init ( first ); // first will become a root segment
553
553
  storage.insertSegment ( 'second', second );
554
554
  storage.insertSegment ( 'third', third );
555
555
 
556
- const [ a, b c, firstData, otherData ] = storage.extractList ( ['first', 'second', 'third', 'data', 'secondData' ], { as: 'std' } ));
556
+ const [ a, b, c, firstData, otherData ] = storage.extractList ( ['first', 'second', 'third', 'data', 'secondData' ], { as: 'std' } ));
557
557
  // a -> { name: 'first', data: 'first data' }
558
558
  // b -> { name: 'second', data: 'second data' }
559
559
  // c -> { name: 'third', data: 'third data' }
@@ -960,7 +960,7 @@ It's a two level deep javascript object. First object properties represent the l
960
960
 
961
961
 
962
962
  ### Breadcrumbs
963
- It's a flat interpratation of the data and looks like this:
963
+ It's a flat interpretation of the data and looks like this:
964
964
 
965
965
  ```js
966
966
  {
package/dist/dtbox.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var t=require("@peter.naydenov/walk");function e(t,e){return function(n,r){const{convert:o,isDTO:s,isDTM:c,walk:a}=t();let u,i;s(r)?(u=r.export(),i=r.copy()):c(r)?(u=a({data:r}),i=a({data:r})):([i,,u]=o.from("std").toFlat(t,r),console.warn('A non "dt-object" data segment was inserted. Autoconverted to "dt-object".'));const l=new RegExp("^root/");u.forEach((t=>{t[0]===t[2]&&(t[0]=n,t[2]=n),t[2]=t[2].replace(l,`${n}/`),t[3].forEach(((e,r)=>t[3][r]=e.replace(l,`${n}/`)))})),e.insert([i,,u])}}function n(t,e){return t=>e.export(t)}function r(t,e){return function(n="root"){const r=e.getCopy(n),{walk:o}=t();return r?o({data:r}):null}}function o(t,e,n){return function(){let r=[],o={};const{convert:s,draft:c,INIT_DATA_TYPES:a,main:{load:u}}=t(),i={set:c.set(r,o),connect:c.connect(o),save:c.save(o),push:c.push(o)},[l,...f]=arguments,{as:p}=l({...n,...i},...f)||{},d=0===r.length?e.export():r,h=!!p&&a.includes(p);let m;return"dt-object"===p?u(d):p&&!h?(console.error(`Model '${p}' is unknown data-model.`),null):(m=p?s.to(p,t,d):u(d),e.resetScan(),m)}}function s(t,e,n){return function(){const{main:{load:r},draft:o}=t(),[s,...c]=arguments;let a=[],u={};const i={set:o.set(a,u),connect:o.connect(u),save:o.save(u),push:o.push(u)};return s({...n,...i},...c),e.resetScan(),0===a.length?this:r(a)}}function c(t){return function(e,n){t.setupFilter(e,n)}}function a(t,a){const{flatData:u}=t(),[i,l]=u(t,a),f={insertSegment:e(t,i),export:n(0,i),copy:r(t,i),model:o(t,i,l),query:s(t,i,l),setupFilter:c(i),listSegments:()=>Object.keys(i.getIndexes()).reduce(((t,e)=>(e.includes("/")||t.push(e),t)),[]),index:p};function p(t){if(null==t)return null;let e=i.getLine(t);if(e){let t,[n,r,o,s]=e;return t=r instanceof Array?[...r]:{...r},[n,t,o,[...s]]}return null}return f.extractList=function(t,e,n){return function(r,o){const s=n("root"),{main:{load:c},INIT_DATA_TYPES:a}=t(),u=[...a,"dt-object"];let i=!1,l="";if(o&&(o.as||(i=!0,l='Options should be an object and property "as" is required'),i||u.includes(o.as)||(i=!0,l=`Invalid option "as" value: ${o.as}.`),i))throw new Error(l);return r.map((t=>{let n=e.export(t);return 0===n.length?s[1].hasOwnProperty(t)?s[1][t]:null:n})).map((t=>null==t?null:t instanceof Array?c(t).model((()=>o)):t))}}(t,i,p),f}function u(t,e,n){return function(r){const[o,,s]=r,c=s[0][0],[a,u,i]=t,l=n();a[c]=o,s.forEach((t=>{const[,,n]=t;u[n]=t,i.push(t),l.forEach((n=>e(n,t)))}))}}function i(t){return function(e){const[,n,r]=t;if(e&&!n[e])return[];if(!e){const t=[];return r.forEach((e=>{const[n,r,o,s]=e,c=r instanceof Array?[...r]:{...r};t.push([n,c,o,[...s]])})),t}const o=[];return r.forEach((t=>{const[n,r,s,c]=t,a=new RegExp(`^${e}/`);if(s===e||s.match(a)){let t=n===s?"root":n,e=r instanceof Array?[...r]:{...r},u=s.includes("/")?s.replace(a,"root/"):"root",i=c.map((t=>t.replace(a,"root/")));o.push([t,e,u,i])}})),o}}function l(t,e,n,r){return function(o,s){const c=r(),[,,a]=t;if(c.includes(o))return console.error(`Filter name "${o}" is already defined`),this;e[o]=s,a.forEach((t=>n(o,t)))}}function f(t){return function(e){const n=t.getIndexes(),r=n[e],o=[];return r?(o.push(r),p(n,o,r[3]),t.setupScanList(o),this):(t.setupScanList([]),this)}}function p(t,e,n){n.forEach((n=>{const r=t[n];r&&(e.push(r),p(t,e,r[3]))}))}function d(t){return function(e){const n=[];return t.getScanList().forEach((t=>{t[0]===e&&n.push(t)})),t.setupScanList(n),this}}function h(t){return function(e){const n=[],r=e instanceof Array?e:[e];return t.getScanList().forEach((t=>{const e=t[0];r.forEach((r=>{e.includes(r)&&n.push(t)}))})),t.setupScanList(n),this}}function m(t){return function(e){t.getScanList().forEach((n=>{const[r,o,s,c]=n,a=o instanceof Array,u=()=>"$__NEXT__LOOK_",i=()=>"$__FINISH__WITH__THE__LOOKING_";let l=!1;const f=c.map((t=>{let e=t.replace(`${s}/`,"");return[r,e]}));if(a)0===o.length?p([]):o.every(((t,n)=>{if(l)return!1;const c=e({value:t,key:n,name:r,flatData:o,breadcrumbs:s,links:f,next:u,finish:i});return"$__FINISH__WITH__THE__LOOKING_"===c&&(l=!0),!["$__FINISH__WITH__THE__LOOKING_","$__NEXT__LOOK_"].includes(c)}));else{const t=Object.entries(o);0===t.length?p({}):t.every((([t,n])=>{if(l)return!1;const c=e({value:n,key:t,name:r,flatData:o,breadcrumbs:s,links:f,next:u,finish:i});return"$__FINISH__WITH__THE__LOOKING_"===c&&(l=!0),!["$__FINISH__WITH__THE__LOOKING_","$__NEXT__LOOK_"].includes(c)}))}function p(t){e({value:null,key:null,name:r,flatData:t,breadcrumbs:s,links:f,empty:!0,next:u,finish:i})}t.resetScan()}))}}function b(t){return function(e){const n=[];return t.getScanList().every((t=>t[2]!==e||(n.push(t),!1))),t.setupScanList(n),this}}function _({flatData:t}){return t instanceof Array}function y({name:t,flatData:e}){return!(e instanceof Array)&&!isNaN(t)}function g({flatData:t}){return!(t instanceof Array)}function $({name:t,breadcrumbs:e}){return t===e}function E(t,e){const[n,r,o]=e,s=[n,r,o],c={},a={list:_,listObject:y,object:g,root:$};let p=o;const E=()=>Object.keys(a),v=(t,e)=>{if(a[t]){const[n,o,s,u]=e;if(c[t]||(c[t]=[]),a[t]({name:n,flatData:o,breadcrumbs:s,edges:u})){const e=r[s];c[t].push(e)}}};E().forEach((t=>o.forEach((e=>v(t,e)))));const j={insert:u(s,v,E),export:i(s),getCopy:t=>n[t]?n[t]:null,getIndexes:()=>r,getLine:t=>r[t]?r[t]:null,getFilters:()=>c,getScanList:()=>p,setupScanList:t=>p=t,setupFilter:l(s,a,v,E),resetScan:()=>{p=o}};var O;return[j,{from:f(j),use:(O=j,function(t){const e=O.getFilters()[t];return e&&O.setupScanList(e),this}),get:b(j),find:d(j),like:h(j),look:m(j)}]}var v={toFlat:function(t,e){const{walk:n}=t(),r=[],o={};return[{root:n({data:e,keyCallback:function({value:t,key:e,breadcrumbs:n}){const r=new RegExp(`/${e}$`),s=n.replace(r,"");return o[s][1][e]=t,t},objectCallback:function({value:t,key:e,breadcrumbs:n}){const s="root"===n&&"root"===e,c=t instanceof Array?[]:{},a=e,u=new RegExp(`/${e}$`),i=n.replace(u,""),l=[a,c,n,[]];return s||o[i][3].push(n),r.push(l),o[n]=r.at(-1),t}})},o,r]},toType:function(t){let e={};return t.reverse().forEach((([t,n,r,o])=>{const s=n instanceof Array?[...n]:{...n};e[r]=s,o.forEach((t=>{if(e[t]){const n=t.replace(`${r}/`,"");e[r][n]=e[t]}}))})),e.root}};var j={toFlat:function(t,e){const n=Object.entries(e),{walk:r}=t(),o={},s=[],c={},a={};function u(t){c[t]||(c[t]="object");const e=t.split("/");1!=e.length&&(e.pop(),1!=e.length&&u(e.join("/")))}return n.forEach((([t,e])=>{t.startsWith("root")||(t=`root/${t}`),u(t),function(t,e){Object.keys(e).forEach((e=>{isNaN(e)||(c[t]="array")}))}(t,e),a[t]=e})),Object.entries(c).forEach((([t,e])=>{if("object"===a[t])return;if(a[t]){const n=a[t]instanceof Array;if("array"===e&&!n){const e=Object.values(a[t]);a[t]=e}return}const n="object"===e?{}:[];a[t]=n})),Object.entries(a).sort().forEach((([t,e])=>{const n=t.split("/").pop(),r=t.replace(`/${n}`,""),c=[n,e instanceof Array?[...e]:{...e},t,[]];o[t]=c,s.push(c),"root"!==t&&r&&o[r]&&o[r][3].push(t)})),[r({data:e}),o,s]},toType:function(t){const e={};return t.forEach((t=>{const[,n,r]=t;if(0===Object.keys(n).length)return;const o=r.replace("root/",""),s=n instanceof Array?[...n]:{...n};e[o]=s})),e}};var O={toFlat:function(t,e){const{walk:n}=t(),r={},o={root:[]},s=[];function c(t){if("root"===t)return;const e=t.split("/");e.pop();const n=e.join("/");o[n]||(o[n]=[]),n.includes("/")&&c(n)}e.forEach((t=>{const[e,n]=t,r="root"===e?"root":`root/${e}`;o[r]?o[r].push(n):o[r]=[n],c(r)}));let a=Object.entries(o).sort();const u={root:"object"};return a.forEach((([t,e])=>{if("root"===t)return;const n=t.split("/"),r=n.pop(),o=n.join("/");"array"!==u[o]&&!isNaN(r)&&(u[o]="array"),0===e.length&&(u[t]="object")})),a=Object.entries(o).sort(),a.forEach((([t,e])=>{const[n,o,c]=function(t){let e,n,r;if("root"==t)return e="root",n="root",r=null,[e,n,r];const o=t.split("/");return 2===o.length&&(e="root",n="root",r=o.pop()),o.length>2&&(r=o.pop(),e=o.pop(),n=0===o.length?`root/${e}`:`${o.join("/")}/${e}`),[e,n,r]}(t),a=0===e.length,i=1===e.length;let l,f;if(a){if(r[`${o}/${c}`])return;return null==c?(f="object"===u.root?{}:[],l=["root",f,"root",[]],r.root=l,void s.push(l)):(f="object"===u[`${o}/${c}`]?{}:[],l=[c,f,`${o}/${c}`,[]],r[`${o}/${c}`]=l,void s.push(l))}if(!i)return l=[c,e,`${o}/${c}`,[]],r[`${o}/${c}`]=l,void s.push(l);if(r[`${o}`])r[o][1][c]=e[0];else{const t={};t[c]=e[0],l=[n,t,o,[]],r[o]=l,s.push(l)}})),s.reverse(),s.forEach((t=>{const[e,n,o]=t,s=o.replace(`/${e}`,""),c=r[s];s!==o&&c&&c[3].push(o)})),s.reverse(),[n({data:e}),r,s]},toType:function(t){let e=[];return t.forEach((t=>{const[n,r,o]=t,s=r instanceof Array;let c="";if("root"!==n&&(c=o.replace("root/","")),s)return void(0==c.length?r.forEach(((t,n)=>e.push(["root",t]))):r.forEach((t=>e.push([c,t]))));Object.entries(r).forEach((([t,n])=>{0==c.length?e.push([t,n]):e.push([`${c}/${t}`,n])}))})),e}};const T=t=>(e,n)=>{switch(t){case"std":case"standard":return v.toFlat(e,n);case"tuple":case"tuples":return O.toFlat(e,n);case"breadcrumb":case"breadcrumbs":const t=Object.entries(n);return O.toFlat(e,t);case"file":case"files":const r=n.map((t=>{let e=t.split("/");1===e.length&&(e=["root"].concat(e));const n=e.pop();return[e.join("/"),n]}));return O.toFlat(e,r);case"midFlat":return j.toFlat(e,n)}return[["object",0],{}]};var I={from:function(t){return{toFlat:T(t)}},to:function(t,e,n){const r={},{walk:o}=e(),s=new Set,c=new Set;let a,u=0;switch(t){case"flat":case"dt-model":return o({data:n});case"std":case"standard":return v.toType(n);case"midflat":case"midFlat":return j.toType(n);case"tuple":case"tuples":return O.toType(n);case"files":return a=O.toType(n),a.map((([t,e])=>"function"==typeof e?`${t}/function:${e.name}`:e?.nodeType?`${t}/HtmlElement:${e.tagName?e.tagName.toLowerCase():"notSpecified"}`:"root"===t?e:`${t}/${e}`));case"breadcrumb":case"breadcrumbs":let t;return a=O.toType(n),a.forEach((([t,e])=>s.has(t)?c.add(t):s.add(t))),a.forEach((([e,n])=>{if(c.has(e)){t!==e&&(t=e,u=0),r["root"===e?u:`${e}/${u}`]=n,u++}else r[e]=n})),r}}};function S(t,e,n){const r=t[e],o=r[2];r[2]=n,t[o]=r,r[3].forEach(((e,r)=>{const s=new RegExp(`^${o}/`),c=e.replace(s,`${n}/`);S(t[e],e,c)}))}var k={push:function(t){return function(e,n){const r=!!t[e]&&t[e][1];return r&&r instanceof Array?("object"==typeof value||r.push(n),this):this}},set:function(t,e){return function(n,r){const o=r instanceof Array,s=[];return s.push(n),o?s.push([...r]):s.push({...r}),s.push(n),s.push([]),t.push(s),e[n]=s,this}},connect:function(t){return function(e){e.forEach((e=>{let n=e.split("/");const r=n.pop(),o=n.pop(),s=t[o];if(!t[r])return this;if(!s)return this;if(s[1][r])return this;let c=`${s[2]}/${r}`;return S(t,r,c),s[3].includes(c)||s[3].push(c),this}))}},save:function(t){return function(e,n,r){const o=!!t[e]&&t[e][1];return o?(o[n]||(o[n]=r),this):this}}};const A=["std","standard","tuple","tuples","breadcrumb","breadcrumbs","file","files","midFlat","midflat","flat","dt-model"],F={dependencies:()=>({walk:t,flatData:E,flatObject:a,convert:I,INIT_DATA_TYPES:A,main:{load:F.load},isDTO:t=>"function"==typeof t.insertSegment,isDTM:t=>t instanceof Array&&(t[0]instanceof Array&&(4===t[0].length&&"root"===t[0][0])),draft:k}),init(t,e={}){let{model:n}=Object.assign({},{model:"std"},e),r=F.dependencies;if(!A.includes(n))return console.error(`Can't understand your data-model: ${n}. Please, find what is possible on https://github.com/PeterNaydenov/dt-toolbox`),null;return a(r,["flat","dt-model"].includes(n)?F.load(t):I.from(n).toFlat(r,t))},load(e){const n={};e.forEach((t=>{const[,,e]=t;n[e]=t}));const r=t({data:e});return a(F.dependencies,[r,n,e])},flating(t,e={}){let{model:n}=Object.assign({},{model:"std"},e);if(!A.includes(n))return null;let[,,r]=I.from("std").toFlat(F.dependencies,t);return r},converting(t,e={}){let{model:n,as:r}=Object.assign({},{model:"std",as:"std"},e);if(!A.includes(n))return null;if(!A.includes(r))return null;let[,,o]=I.from("std").toFlat(F.dependencies,t);return I.to(r,F.dependencies,o)},getWalk:()=>t},{init:w,load:N,flating:L,converting:x,getWalk:D}=F,H={init:w,load:N,flat:L,convert:x,getWalk:D};module.exports=H;
1
+ "use strict";var t=require("@peter.naydenov/walk");function e(t,e){return function(n,r){const{convert:o,isDTO:s,isDTM:a,walk:c}=t();let i,u;if("string"!=typeof n||""===n)throw new Error(`insertSegment(name, data) requires a non-empty string segment name. Got: ${JSON.stringify(n)}`);if(n.includes("/"))throw new Error(`insertSegment(name, data) does not allow '/' in the segment name (it's the breadcrumbs separator). Got: ${JSON.stringify(n)}`);if(e.getIndexes()&&e.getIndexes()[n])throw new Error(`Segment "${n}" already exists. Use a different name or remove the existing segment first.`);if(null==r)throw new Error(`insertSegment('${n}', data) requires a value. Got: ${r}`);if("object"!=typeof r)throw new Error(`insertSegment('${n}', data) requires an object, dt-object, dt-model, or array. Got: ${typeof r} (${r})`);s(r)?(i=r.export(),u=r.copy()):a(r)?(i=c({data:r}),u=c({data:r})):([u,,i]=o.from("std").toFlat(t,r),console.warn('A non "dt-object" data segment was inserted. Autoconverted to "dt-object".'));const f=new RegExp("^root/");i.forEach(t=>{t[0]===t[2]&&(t[0]=n,t[2]=n),t[2]=t[2].replace(f,`${n}/`),t[3].forEach((e,r)=>t[3][r]=e.replace(f,`${n}/`))}),e.insert([u,,i])}}function n(t,e){return t=>e.export(t)}function r(t,e){return function(n="root"){if(void 0!==n&&"string"!=typeof n)throw new Error(`copy(name) expects a string segment name or no argument. Got: ${typeof n} (${n}).`);const r=e.getCopy(n),{walk:o}=t();return r?o({data:r}):null}}function o(t,e,n){return function(){let r=[],o={};const{convert:s,draft:a,INIT_DATA_TYPES:c,main:{load:i}}=t(),u={set:a.set(r,o),connect:a.connect(o),save:a.save(o),push:a.push(o)},[f,...l]=arguments,p=f({...n,...u},...l),{as:d}=p||{},h=0===r.length?e.export():r,y=!!d&&c.includes(d);if(void 0!==d&&"dt-object"!==d&&"string"!=typeof d)throw new Error(`model(fn) requires the 'as' value to be a string. Got: ${typeof d} (${d})`);if(d&&"dt-object"!==d&&!y)throw new Error(`Model '${d}' is unknown. Supported: ${c.join(", ")}, dt-object`);let g;return"dt-object"===d?i(h):(g=d?s.to(d,t,h):i(h),e.resetScan(),g)}}function s(t,e,n){return function(){const{main:{load:r},draft:o}=t(),[s,...a]=arguments;let c=[],i={};const u={set:o.set(c,i),connect:o.connect(i),save:o.save(i),push:o.push(i)};return s({...n,...u},...a),e.resetScan(),0===c.length?this:r(c)}}function a(t){return function(e,n){t.setupFilter(e,n)}}function c(t,e,n){return function(r,o){const s=n("root"),{main:{load:a},INIT_DATA_TYPES:c}=t(),i=[...c,"dt-object"];let u=!1,f="";if(o&&(o.as||(u=!0,f='Options should be an object and property "as" is required'),u||i.includes(o.as)||(u=!0,f=`Invalid option "as" value: ${o.as}.`),u))throw new Error(f);return r.map(t=>{let r=e.export(t);if(0===r.length){if(s&&s[1]&&Object.prototype.hasOwnProperty.call(s[1],t))return s[1][t];const e=(t=>{if(!t)return;const e=n(t);return e?e[1]:void 0})(t);return void 0!==e?e:function(t,e){const n=t.startsWith("root/")?[t]:[t,`root/${t}`];for(const t of n){const n=t.split("/");for(let t=n.length;t>0;t--){const r=e(n.slice(0,t).join("/"));if(r){if(t===n.length)return r[1];const e=n.slice(t);let o=r[1];for(const t of e){if(null==o)return;if(Array.isArray(o)){const e=parseInt(t,10);if(isNaN(e))return;o=o[e]}else{if("object"!=typeof o)return;o=o[t]}}return o}}}return}(t,n)}return r}).map(t=>null==t?null:t instanceof Array?a(t).model(()=>o):t)}}function i(t,i){const{flatData:u}=t(),[f,l]=u(t,i),p={insertSegment:e(t,f),export:n(0,f),copy:r(t,f),model:o(t,f,l),query:s(t,f,l),setupFilter:a(f),listSegments:()=>Object.keys(f.getIndexes()).reduce((t,e)=>(e.includes("/")||t.push(e),t),[]),index:d};function d(t){if(null==t)return null;let e=f.getLine(t);if(e){let t,[n,r,o,s]=e;return t=null==r||"object"!=typeof r?r:r instanceof Array?[...r]:{...r},[n,t,o,[...s]]}const n=t.lastIndexOf("/");if(n>0){const e=t.slice(0,n),r=t.slice(n+1),o=f.getLine(e);if(o){const[,e]=o;if(e&&"object"==typeof e&&!Array.isArray(e)&&Object.prototype.hasOwnProperty.call(e,r)){const n=e[r];let o;return o=null==n||"object"!=typeof n?n:n instanceof Array?[...n]:n instanceof Date?new Date(n.getTime()):n instanceof RegExp?new RegExp(n.source,n.flags):{...n},[r,o,t,[]]}}}return null}return p.extractList=c(t,f,d),p}function u(t,e,n){return function(r){const[o,,s]=r,a=s[0][0],[c,i,u]=t,f=n();c[a]=o,s.forEach(t=>{const[,,n]=t;i[n]=t,u.push(t),f.forEach(n=>e(n,t))})}}function f(t){return function(e){const[,n,r]=t;if(void 0!==e&&"string"!=typeof e)throw new Error(`export(name) expects a string segment name or no argument. Got: ${typeof e} (${e}).`);if(e&&!n[e])return[];if(!e){const t=[];return r.forEach(e=>{const[n,r,o,s]=e,a=l(r);t.push([n,a,o,[...s]])}),t}const o=[];return r.forEach(t=>{const[n,r,s,a]=t,c=new RegExp(`^${e}/`);if(s===e||s.match(c)){let t=n===s?"root":n,e=l(r),i=s.includes("/")?s.replace(c,"root/"):"root",u=a.map(t=>t.replace(c,"root/"));o.push([t,e,i,u])}}),o}}function l(t){return null==t||"object"!=typeof t?t:Array.isArray(t)?[...t]:t instanceof Date?new Date(t.getTime()):t instanceof RegExp?new RegExp(t.source,t.flags):{...t}}function p(t,e,n,r){return function(o,s){const a=r(),[,,c]=t;if(a.includes(o))return console.error(`Filter name "${o}" is already defined`),this;e[o]=s,c.forEach(t=>n(o,t))}}function d(t){return function(e){const n=t.getIndexes(),r=n[e],o=[];return r?(o.push(r),h(n,o,r[3]),t.setupScanList(o),this):(t.setupScanList([]),this)}}function h(t,e,n){n.forEach(n=>{const r=t[n];r&&(e.push(r),h(t,e,r[3]))})}function y(t){return function(e){const n=[];return t.getScanList().forEach(t=>{t[0]===e&&n.push(t)}),t.setupScanList(n),this}}function g(t){return function(e){const n=[],r=e instanceof Array?e:[e];return t.getScanList().forEach(t=>{const e=t[0];r.forEach(r=>{e.includes(r)&&n.push(t)})}),t.setupScanList(n),this}}function m(t){return function(e){t.getScanList().forEach(n=>{const[r,o,s,a]=n,c=o instanceof Array,i=()=>"$__NEXT__LOOK_",u=()=>"$__FINISH__WITH__THE__LOOKING_";let f=!1;const l=a.map(t=>{let e=t.replace(`${s}/`,"");return[r,e]});if(c)0===o.length?p([]):o.every((t,n)=>{if(f)return!1;const a=e({value:t,key:n,name:r,flatData:o,breadcrumbs:s,links:l,next:i,finish:u});return"$__FINISH__WITH__THE__LOOKING_"===a&&(f=!0),!["$__FINISH__WITH__THE__LOOKING_","$__NEXT__LOOK_"].includes(a)});else{const t=Object.entries(o);0===t.length?p({}):t.every(([t,n])=>{if(f)return!1;const a=e({value:n,key:t,name:r,flatData:o,breadcrumbs:s,links:l,next:i,finish:u});return"$__FINISH__WITH__THE__LOOKING_"===a&&(f=!0),!["$__FINISH__WITH__THE__LOOKING_","$__NEXT__LOOK_"].includes(a)})}function p(t){e({value:null,key:null,name:r,flatData:t,breadcrumbs:s,links:l,empty:!0,next:i,finish:u})}t.resetScan()})}}function b(t){return function(e){const n=[];return t.getScanList().every(t=>t[2]!==e||(n.push(t),!1)),t.setupScanList(n),this}}function $({flatData:t}){return t instanceof Array}function E({name:t,flatData:e}){return!(e instanceof Array)&&!isNaN(t)}function j({flatData:t}){return!(t instanceof Array)}function _({name:t,breadcrumbs:e}){return t===e}function w(t,e){const[n,r,o]=e,s=[n,r,o],a={},c={list:$,listObject:E,object:j,root:_};let i=o;const l=()=>Object.keys(c),h=(t,e)=>{if(c[t]){const[n,o,s,i]=e;if(a[t]||(a[t]=[]),c[t]({name:n,flatData:o,breadcrumbs:s,edges:i})){const e=r[s];a[t].push(e)}}};l().forEach(t=>o.forEach(e=>h(t,e)));const w={insert:u(s,h,l),export:f(s),getCopy:t=>n[t]?n[t]:null,getIndexes:()=>r,getLine:t=>r[t]?r[t]:null,getFilters:()=>a,getScanList:()=>i,setupScanList:t=>i=t,setupFilter:p(s,c,h,l),resetScan:()=>{i=o}};var v;return[w,{from:d(w),use:(v=w,function(t){const e=v.getFilters()[t];return e&&v.setupScanList(e),this}),get:b(w),find:y(w),like:g(w),look:m(w)}]}const v=t=>{if(null==t)return t;if("object"!=typeof t)return t;if(Array.isArray(t))return t.map(v);if(t instanceof Date)return new Date(t.getTime());if(t instanceof RegExp)return new RegExp(t.source,t.flags);if("function"==typeof t)return t;if(t.nodeType)return t;const e={};for(const n in t)e[n]=v(t[n]);return e},O="__dtSentinel__",S="date",A="regexp",T=(t,e)=>null!==t&&"object"==typeof t&&t[O]===e,x=t=>{if(null==t)return t;if("object"!=typeof t)return t;if(Array.isArray(t))return t.map(x);if(t instanceof Date)return{[O]:S,iso:t.toISOString()};if(t instanceof RegExp)return{[O]:A,source:t.source,flags:t.flags};if("function"==typeof t||t.nodeType)return t;const e={};for(const n in t)e[n]=x(t[n]);return e};const I=t=>{if(null==t)return t;if("object"!=typeof t)return t;const e=(t=>T(t,S)?new Date(t.iso):T(t,A)?new RegExp(t.source,t.flags):t)(t);if(e!==t)return e;if(Array.isArray(t))return t.map(I);const n={};for(const e in t)n[e]=I(t[e]);return n};var k={toFlat:function(t,e){const{walk:n}=t(),r=[],o={};return[{root:n({data:x(e),keyCallback:function({value:t,key:e,breadcrumbs:n}){const r=new RegExp(`/${e}$`),s=n.replace(r,"");return o[s][1][e]=t,t},objectCallback:function({value:t,key:e,breadcrumbs:n}){const s="root"===n&&"root"===e,a=t instanceof Array?[]:{},c=e,i=new RegExp(`/${e}$`),u=n.replace(i,""),f=[c,a,n,[]];return s||o[u][3].push(n),r.push(f),o[n]=r.at(-1),t}})},o,r]},toType:function(t){let e={},n=t.reverse(),r=[];n.forEach(([t,n,o,s])=>{const a=v(n);"root"===o||o.startsWith("root/")?(e[o]=a,s.forEach(t=>{if(e[t]){const n=t.replace(`${o}/`,"");e[o][n]=e[t]}})):r.push({name:t,breadcrumbs:o,data:a})});const o=e.root||{};return r.forEach(({name:t,breadcrumbs:e,data:n})=>{const r=o[t];!r||"object"!=typeof r||Array.isArray(r)||"object"!=typeof n||Array.isArray(n)?o[t]=n:o[t]={...r,...n}}),I(o)}};var N={toFlat:function(t,e){const n=Object.entries(e),{walk:r}=t(),o={},s=[],a={},c={};function i(t){a[t]||(a[t]="object");const e=t.split("/");1!=e.length&&(e.pop(),1!=e.length&&i(e.join("/")))}return n.forEach(([t,e])=>{t.startsWith("root")||(t=`root/${t}`),i(t),function(t,e){Object.keys(e).forEach(e=>{isNaN(e)||(a[t]="array")})}(t,e),c[t]=e}),Object.entries(a).forEach(([t,e])=>{if("object"===c[t])return;if(c[t]){const n=c[t]instanceof Array;if("array"===e&&!n){const e=Object.values(c[t]);c[t]=e}return}const n="object"===e?{}:[];c[t]=n}),Object.entries(c).sort().forEach(([t,e])=>{const n=t.split("/").pop(),r=t.replace(`/${n}`,""),a=[n,e instanceof Array?[...e]:{...e},t,[]];o[t]=a,s.push(a),"root"!==t&&r&&o[r]&&o[r][3].push(t)}),[r({data:e}),o,s]},toType:function(t){const e={};return t.forEach(t=>{const[,n,r]=t;if(0===Object.keys(n).length)return;const o=r.replace("root/",""),s=n instanceof Array?[...n]:{...n};e[o]=s}),e}};var F={toFlat:function(t,e){const{walk:n}=t(),r={},o={root:[]},s=[];function a(t){if("root"===t)return;const e=t.split("/");e.pop();const n=e.join("/");o[n]||(o[n]=[]),n.includes("/")&&a(n)}e.forEach(t=>{const[e,n]=t,r="root"===e?"root":`root/${e}`;o[r]?o[r].push(n):o[r]=[n],a(r)});let c=Object.entries(o).sort();const i={root:"object"};return c.forEach(([t,e])=>{if("root"===t)return;const n=t.split("/"),r=n.pop(),o=n.join("/");"array"!==i[o]&&!isNaN(r)&&(i[o]="array"),0===e.length&&(i[t]="object")}),c=Object.entries(o).sort(),c.forEach(([t,e])=>{const[n,o,a]=function(t){let e,n,r;if("root"==t)return e="root",n="root",r=null,[e,n,r];const o=t.split("/");return 2===o.length&&(e="root",n="root",r=o.pop()),o.length>2&&(r=o.pop(),e=o.pop(),n=0===o.length?`root/${e}`:`${o.join("/")}/${e}`),[e,n,r]}(t),c=0===e.length,u=1===e.length;let f,l;if(c){if(r[`${o}/${a}`])return;return null==a?(l="object"===i.root?{}:[],f=["root",l,"root",[]],r.root=f,void s.push(f)):(l="object"===i[`${o}/${a}`]?{}:[],f=[a,l,`${o}/${a}`,[]],r[`${o}/${a}`]=f,void s.push(f))}if(!u)return f=[a,e,`${o}/${a}`,[]],r[`${o}/${a}`]=f,void s.push(f);if(r[`${o}`])r[o][1][a]=e[0];else{const t={};t[a]=e[0],f=[n,t,o,[]],r[o]=f,s.push(f)}}),s.reverse(),s.forEach(t=>{const[e,n,o]=t,s=o.replace(`/${e}`,""),a=r[s];s!==o&&a&&a[3].push(o)}),s.reverse(),[n({data:e}),r,s]},toType:function(t){let e=[];return t.forEach(t=>{const[n,r,o]=t,s=r instanceof Array;let a="";if("root"!==n&&(a=o.replace("root/","")),s)return void(0==a.length?r.forEach((t,n)=>e.push(["root",t])):r.forEach(t=>e.push([a,t])));Object.entries(r).forEach(([t,n])=>{0==a.length?e.push([t,n]):e.push([`${a}/${t}`,n])})}),e}};const L=t=>(e,n)=>{switch(t){case"std":case"standard":return k.toFlat(e,n);case"tuple":case"tuples":return F.toFlat(e,n);case"breadcrumb":case"breadcrumbs":const t=Object.entries(n);return F.toFlat(e,t);case"file":case"files":const r=n.map(t=>{let e=t.split("/");1===e.length&&(e=["root"].concat(e));const n=e.pop();return[e.join("/"),n]});return F.toFlat(e,r);case"midFlat":return N.toFlat(e,n)}return[["object",0],{}]};var D={from:function(t){return{toFlat:L(t)}},to:function(t,e,n){const r={},{walk:o}=e(),s=new Set,a=new Set;let c,i=0;switch(t){case"flat":case"dt-model":return o({data:n});case"std":case"standard":return k.toType(n);case"midflat":case"midFlat":return N.toType(n);case"tuple":case"tuples":return F.toType(n);case"files":return c=F.toType(n),c.map(([t,e])=>"function"==typeof e?`${t}/function:${e.name}`:e?.nodeType?`${t}/HtmlElement:${e.tagName?e.tagName.toLowerCase():"notSpecified"}`:"root"===t?e:`${t}/${e}`);case"breadcrumb":case"breadcrumbs":let t;return c=F.toType(n),c.forEach(([t,e])=>s.has(t)?a.add(t):s.add(t)),c.forEach(([e,n])=>{if(a.has(e)){t!==e&&(t=e,i=0),r["root"===e?i:`${e}/${i}`]=n,i++}else r[e]=n}),r}}};function H(t,e,n){const r=t[e],o=r[2];r[2]=n,t[o]=r,r[3].forEach((e,r)=>{const s=new RegExp(`^${o}/`),a=e.replace(s,`${n}/`);H(t[e],e,a)})}var G={push:function(t){return function(e,n){const r=!!t[e]&&t[e][1];return r&&r instanceof Array?("object"==typeof value||r.push(n),this):this}},set:function(t,e){return function(n,r){const o=r instanceof Array,s=[];return s.push(n),null==r||"object"!=typeof r?s.push(r):o?s.push([...r]):s.push({...r}),s.push(n),s.push([]),t.push(s),e[n]=s,this}},connect:function(t){return function(e){e.forEach(e=>{let n=e.split("/");const r=n.pop(),o=n.pop(),s=t[o];if(!t[r])return this;if(!s)return this;if(s[1][r])return this;let a=`${s[2]}/${r}`;return H(t,r,a),s[3].includes(a)||s[3].push(a),this})}},save:function(t){return function(e,n,r){const o=!!t[e]&&t[e][1];return o?(o[n]||(o[n]=r),this):this}}};const R=["std","standard","tuple","tuples","breadcrumb","breadcrumbs","file","files","midFlat","midflat","flat","dt-model"],W=(t,e=new WeakSet)=>{if(null===t||"object"!=typeof t)return!1;if(e.has(t))return!0;if(e.add(t),Array.isArray(t)){for(const n of t)if(W(n,e))return!0}else for(const n in t)if(W(t[n],e))return!0;return!1},C={dependencies:()=>({walk:t,flatData:w,flatObject:i,convert:D,INIT_DATA_TYPES:R,main:{load:C.load},isDTO:t=>"function"==typeof t.insertSegment,isDTM:t=>t instanceof Array&&(t[0]instanceof Array&&(4===t[0].length&&"root"===t[0][0])),draft:G}),init(t,e={}){let{model:n}=Object.assign({},{model:"std"},e),r=C.dependencies;if(!R.includes(n))return console.error(`Can't understand your data-model: ${n}. Please, find what is possible on https://github.com/PeterNaydenov/dt-toolbox`),null;if(t&&"object"==typeof t&&W(t))throw new Error("Circular reference detected in data. dt-toolbox cannot initialise a self-referencing object.");let o=t;null!=t&&"object"==typeof t||(o={value:t});return i(r,["flat","dt-model"].includes(n)?C.load(o):D.from(n).toFlat(r,o))},load(e){const n={};e.forEach(t=>{const[,,e]=t;n[e]=t});const r=t({data:e});return i(C.dependencies,[r,n,e])},flating(t,e={}){let{model:n}=Object.assign({},{model:"std"},e);if(!R.includes(n))throw new Error(`Can't understand your data-model: ${n}. Supported: ${R.join(", ")}`);if(null==t||"object"!=typeof t)throw new Error(`flat(data, options) requires an object or array. Got: ${null===t?"null":typeof t}${null===t?"":" ("+t+")"}`);let[,,r]=D.from("std").toFlat(C.dependencies,t);return r},converting(t,e={}){let{model:n,as:r}=Object.assign({},{model:"std",as:"std"},e);if(!R.includes(n))throw new Error(`Can't understand source data-model: ${n}. Supported: ${R.join(", ")}`);if(!R.includes(r))throw new Error(`Can't understand target data-model: ${r}. Supported: ${R.join(", ")}`);if(null==t||"object"!=typeof t)throw new Error("convert(data, options) requires an object or array. Got: "+(null===t?"null":typeof t));let[,,o]=D.from("std").toFlat(C.dependencies,t);return D.to(r,C.dependencies,o)},getWalk:()=>t},{init:q,load:K,flating:P,converting:M,getWalk:X}=C,Y={init:q,load:K,flat:P,convert:M,getWalk:X};module.exports=Y;
@@ -1 +1 @@
1
- import t from"@peter.naydenov/walk";function e(t,e){return function(n,r){const{convert:o,isDTO:s,isDTM:c,walk:a}=t();let u,i;s(r)?(u=r.export(),i=r.copy()):c(r)?(u=a({data:r}),i=a({data:r})):([i,,u]=o.from("std").toFlat(t,r),console.warn('A non "dt-object" data segment was inserted. Autoconverted to "dt-object".'));const l=new RegExp("^root/");u.forEach((t=>{t[0]===t[2]&&(t[0]=n,t[2]=n),t[2]=t[2].replace(l,`${n}/`),t[3].forEach(((e,r)=>t[3][r]=e.replace(l,`${n}/`)))})),e.insert([i,,u])}}function n(t,e){return t=>e.export(t)}function r(t,e){return function(n="root"){const r=e.getCopy(n),{walk:o}=t();return r?o({data:r}):null}}function o(t,e,n){return function(){let r=[],o={};const{convert:s,draft:c,INIT_DATA_TYPES:a,main:{load:u}}=t(),i={set:c.set(r,o),connect:c.connect(o),save:c.save(o),push:c.push(o)},[l,...f]=arguments,{as:p}=l({...n,...i},...f)||{},d=0===r.length?e.export():r,h=!!p&&a.includes(p);let m;return"dt-object"===p?u(d):p&&!h?(console.error(`Model '${p}' is unknown data-model.`),null):(m=p?s.to(p,t,d):u(d),e.resetScan(),m)}}function s(t,e,n){return function(){const{main:{load:r},draft:o}=t(),[s,...c]=arguments;let a=[],u={};const i={set:o.set(a,u),connect:o.connect(u),save:o.save(u),push:o.push(u)};return s({...n,...i},...c),e.resetScan(),0===a.length?this:r(a)}}function c(t){return function(e,n){t.setupFilter(e,n)}}function a(t,a){const{flatData:u}=t(),[i,l]=u(t,a),f={insertSegment:e(t,i),export:n(0,i),copy:r(t,i),model:o(t,i,l),query:s(t,i,l),setupFilter:c(i),listSegments:()=>Object.keys(i.getIndexes()).reduce(((t,e)=>(e.includes("/")||t.push(e),t)),[]),index:p};function p(t){if(null==t)return null;let e=i.getLine(t);if(e){let t,[n,r,o,s]=e;return t=r instanceof Array?[...r]:{...r},[n,t,o,[...s]]}return null}return f.extractList=function(t,e,n){return function(r,o){const s=n("root"),{main:{load:c},INIT_DATA_TYPES:a}=t(),u=[...a,"dt-object"];let i=!1,l="";if(o&&(o.as||(i=!0,l='Options should be an object and property "as" is required'),i||u.includes(o.as)||(i=!0,l=`Invalid option "as" value: ${o.as}.`),i))throw new Error(l);return r.map((t=>{let n=e.export(t);return 0===n.length?s[1].hasOwnProperty(t)?s[1][t]:null:n})).map((t=>null==t?null:t instanceof Array?c(t).model((()=>o)):t))}}(t,i,p),f}function u(t,e,n){return function(r){const[o,,s]=r,c=s[0][0],[a,u,i]=t,l=n();a[c]=o,s.forEach((t=>{const[,,n]=t;u[n]=t,i.push(t),l.forEach((n=>e(n,t)))}))}}function i(t){return function(e){const[,n,r]=t;if(e&&!n[e])return[];if(!e){const t=[];return r.forEach((e=>{const[n,r,o,s]=e,c=r instanceof Array?[...r]:{...r};t.push([n,c,o,[...s]])})),t}const o=[];return r.forEach((t=>{const[n,r,s,c]=t,a=new RegExp(`^${e}/`);if(s===e||s.match(a)){let t=n===s?"root":n,e=r instanceof Array?[...r]:{...r},u=s.includes("/")?s.replace(a,"root/"):"root",i=c.map((t=>t.replace(a,"root/")));o.push([t,e,u,i])}})),o}}function l(t,e,n,r){return function(o,s){const c=r(),[,,a]=t;if(c.includes(o))return console.error(`Filter name "${o}" is already defined`),this;e[o]=s,a.forEach((t=>n(o,t)))}}function f(t){return function(e){const n=t.getIndexes(),r=n[e],o=[];return r?(o.push(r),p(n,o,r[3]),t.setupScanList(o),this):(t.setupScanList([]),this)}}function p(t,e,n){n.forEach((n=>{const r=t[n];r&&(e.push(r),p(t,e,r[3]))}))}function d(t){return function(e){const n=[];return t.getScanList().forEach((t=>{t[0]===e&&n.push(t)})),t.setupScanList(n),this}}function h(t){return function(e){const n=[],r=e instanceof Array?e:[e];return t.getScanList().forEach((t=>{const e=t[0];r.forEach((r=>{e.includes(r)&&n.push(t)}))})),t.setupScanList(n),this}}function m(t){return function(e){t.getScanList().forEach((n=>{const[r,o,s,c]=n,a=o instanceof Array,u=()=>"$__NEXT__LOOK_",i=()=>"$__FINISH__WITH__THE__LOOKING_";let l=!1;const f=c.map((t=>{let e=t.replace(`${s}/`,"");return[r,e]}));if(a)0===o.length?p([]):o.every(((t,n)=>{if(l)return!1;const c=e({value:t,key:n,name:r,flatData:o,breadcrumbs:s,links:f,next:u,finish:i});return"$__FINISH__WITH__THE__LOOKING_"===c&&(l=!0),!["$__FINISH__WITH__THE__LOOKING_","$__NEXT__LOOK_"].includes(c)}));else{const t=Object.entries(o);0===t.length?p({}):t.every((([t,n])=>{if(l)return!1;const c=e({value:n,key:t,name:r,flatData:o,breadcrumbs:s,links:f,next:u,finish:i});return"$__FINISH__WITH__THE__LOOKING_"===c&&(l=!0),!["$__FINISH__WITH__THE__LOOKING_","$__NEXT__LOOK_"].includes(c)}))}function p(t){e({value:null,key:null,name:r,flatData:t,breadcrumbs:s,links:f,empty:!0,next:u,finish:i})}t.resetScan()}))}}function b(t){return function(e){const n=[];return t.getScanList().every((t=>t[2]!==e||(n.push(t),!1))),t.setupScanList(n),this}}function _({flatData:t}){return t instanceof Array}function y({name:t,flatData:e}){return!(e instanceof Array)&&!isNaN(t)}function g({flatData:t}){return!(t instanceof Array)}function $({name:t,breadcrumbs:e}){return t===e}function E(t,e){const[n,r,o]=e,s=[n,r,o],c={},a={list:_,listObject:y,object:g,root:$};let p=o;const E=()=>Object.keys(a),j=(t,e)=>{if(a[t]){const[n,o,s,u]=e;if(c[t]||(c[t]=[]),a[t]({name:n,flatData:o,breadcrumbs:s,edges:u})){const e=r[s];c[t].push(e)}}};E().forEach((t=>o.forEach((e=>j(t,e)))));const v={insert:u(s,j,E),export:i(s),getCopy:t=>n[t]?n[t]:null,getIndexes:()=>r,getLine:t=>r[t]?r[t]:null,getFilters:()=>c,getScanList:()=>p,setupScanList:t=>p=t,setupFilter:l(s,a,j,E),resetScan:()=>{p=o}};var O;return[v,{from:f(v),use:(O=v,function(t){const e=O.getFilters()[t];return e&&O.setupScanList(e),this}),get:b(v),find:d(v),like:h(v),look:m(v)}]}var j={toFlat:function(t,e){const{walk:n}=t(),r=[],o={};return[{root:n({data:e,keyCallback:function({value:t,key:e,breadcrumbs:n}){const r=new RegExp(`/${e}$`),s=n.replace(r,"");return o[s][1][e]=t,t},objectCallback:function({value:t,key:e,breadcrumbs:n}){const s="root"===n&&"root"===e,c=t instanceof Array?[]:{},a=e,u=new RegExp(`/${e}$`),i=n.replace(u,""),l=[a,c,n,[]];return s||o[i][3].push(n),r.push(l),o[n]=r.at(-1),t}})},o,r]},toType:function(t){let e={};return t.reverse().forEach((([t,n,r,o])=>{const s=n instanceof Array?[...n]:{...n};e[r]=s,o.forEach((t=>{if(e[t]){const n=t.replace(`${r}/`,"");e[r][n]=e[t]}}))})),e.root}};var v={toFlat:function(t,e){const n=Object.entries(e),{walk:r}=t(),o={},s=[],c={},a={};function u(t){c[t]||(c[t]="object");const e=t.split("/");1!=e.length&&(e.pop(),1!=e.length&&u(e.join("/")))}return n.forEach((([t,e])=>{t.startsWith("root")||(t=`root/${t}`),u(t),function(t,e){Object.keys(e).forEach((e=>{isNaN(e)||(c[t]="array")}))}(t,e),a[t]=e})),Object.entries(c).forEach((([t,e])=>{if("object"===a[t])return;if(a[t]){const n=a[t]instanceof Array;if("array"===e&&!n){const e=Object.values(a[t]);a[t]=e}return}const n="object"===e?{}:[];a[t]=n})),Object.entries(a).sort().forEach((([t,e])=>{const n=t.split("/").pop(),r=t.replace(`/${n}`,""),c=[n,e instanceof Array?[...e]:{...e},t,[]];o[t]=c,s.push(c),"root"!==t&&r&&o[r]&&o[r][3].push(t)})),[r({data:e}),o,s]},toType:function(t){const e={};return t.forEach((t=>{const[,n,r]=t;if(0===Object.keys(n).length)return;const o=r.replace("root/",""),s=n instanceof Array?[...n]:{...n};e[o]=s})),e}};var O={toFlat:function(t,e){const{walk:n}=t(),r={},o={root:[]},s=[];function c(t){if("root"===t)return;const e=t.split("/");e.pop();const n=e.join("/");o[n]||(o[n]=[]),n.includes("/")&&c(n)}e.forEach((t=>{const[e,n]=t,r="root"===e?"root":`root/${e}`;o[r]?o[r].push(n):o[r]=[n],c(r)}));let a=Object.entries(o).sort();const u={root:"object"};return a.forEach((([t,e])=>{if("root"===t)return;const n=t.split("/"),r=n.pop(),o=n.join("/");"array"!==u[o]&&!isNaN(r)&&(u[o]="array"),0===e.length&&(u[t]="object")})),a=Object.entries(o).sort(),a.forEach((([t,e])=>{const[n,o,c]=function(t){let e,n,r;if("root"==t)return e="root",n="root",r=null,[e,n,r];const o=t.split("/");return 2===o.length&&(e="root",n="root",r=o.pop()),o.length>2&&(r=o.pop(),e=o.pop(),n=0===o.length?`root/${e}`:`${o.join("/")}/${e}`),[e,n,r]}(t),a=0===e.length,i=1===e.length;let l,f;if(a){if(r[`${o}/${c}`])return;return null==c?(f="object"===u.root?{}:[],l=["root",f,"root",[]],r.root=l,void s.push(l)):(f="object"===u[`${o}/${c}`]?{}:[],l=[c,f,`${o}/${c}`,[]],r[`${o}/${c}`]=l,void s.push(l))}if(!i)return l=[c,e,`${o}/${c}`,[]],r[`${o}/${c}`]=l,void s.push(l);if(r[`${o}`])r[o][1][c]=e[0];else{const t={};t[c]=e[0],l=[n,t,o,[]],r[o]=l,s.push(l)}})),s.reverse(),s.forEach((t=>{const[e,n,o]=t,s=o.replace(`/${e}`,""),c=r[s];s!==o&&c&&c[3].push(o)})),s.reverse(),[n({data:e}),r,s]},toType:function(t){let e=[];return t.forEach((t=>{const[n,r,o]=t,s=r instanceof Array;let c="";if("root"!==n&&(c=o.replace("root/","")),s)return void(0==c.length?r.forEach(((t,n)=>e.push(["root",t]))):r.forEach((t=>e.push([c,t]))));Object.entries(r).forEach((([t,n])=>{0==c.length?e.push([t,n]):e.push([`${c}/${t}`,n])}))})),e}};const T=t=>(e,n)=>{switch(t){case"std":case"standard":return j.toFlat(e,n);case"tuple":case"tuples":return O.toFlat(e,n);case"breadcrumb":case"breadcrumbs":const t=Object.entries(n);return O.toFlat(e,t);case"file":case"files":const r=n.map((t=>{let e=t.split("/");1===e.length&&(e=["root"].concat(e));const n=e.pop();return[e.join("/"),n]}));return O.toFlat(e,r);case"midFlat":return v.toFlat(e,n)}return[["object",0],{}]};var I={from:function(t){return{toFlat:T(t)}},to:function(t,e,n){const r={},{walk:o}=e(),s=new Set,c=new Set;let a,u=0;switch(t){case"flat":case"dt-model":return o({data:n});case"std":case"standard":return j.toType(n);case"midflat":case"midFlat":return v.toType(n);case"tuple":case"tuples":return O.toType(n);case"files":return a=O.toType(n),a.map((([t,e])=>"function"==typeof e?`${t}/function:${e.name}`:e?.nodeType?`${t}/HtmlElement:${e.tagName?e.tagName.toLowerCase():"notSpecified"}`:"root"===t?e:`${t}/${e}`));case"breadcrumb":case"breadcrumbs":let t;return a=O.toType(n),a.forEach((([t,e])=>s.has(t)?c.add(t):s.add(t))),a.forEach((([e,n])=>{if(c.has(e)){t!==e&&(t=e,u=0),r["root"===e?u:`${e}/${u}`]=n,u++}else r[e]=n})),r}}};function S(t,e,n){const r=t[e],o=r[2];r[2]=n,t[o]=r,r[3].forEach(((e,r)=>{const s=new RegExp(`^${o}/`),c=e.replace(s,`${n}/`);S(t[e],e,c)}))}var k={push:function(t){return function(e,n){const r=!!t[e]&&t[e][1];return r&&r instanceof Array?("object"==typeof value||r.push(n),this):this}},set:function(t,e){return function(n,r){const o=r instanceof Array,s=[];return s.push(n),o?s.push([...r]):s.push({...r}),s.push(n),s.push([]),t.push(s),e[n]=s,this}},connect:function(t){return function(e){e.forEach((e=>{let n=e.split("/");const r=n.pop(),o=n.pop(),s=t[o];if(!t[r])return this;if(!s)return this;if(s[1][r])return this;let c=`${s[2]}/${r}`;return S(t,r,c),s[3].includes(c)||s[3].push(c),this}))}},save:function(t){return function(e,n,r){const o=!!t[e]&&t[e][1];return o?(o[n]||(o[n]=r),this):this}}};const A=["std","standard","tuple","tuples","breadcrumb","breadcrumbs","file","files","midFlat","midflat","flat","dt-model"],F={dependencies:()=>({walk:t,flatData:E,flatObject:a,convert:I,INIT_DATA_TYPES:A,main:{load:F.load},isDTO:t=>"function"==typeof t.insertSegment,isDTM:t=>t instanceof Array&&(t[0]instanceof Array&&(4===t[0].length&&"root"===t[0][0])),draft:k}),init(t,e={}){let{model:n}=Object.assign({},{model:"std"},e),r=F.dependencies;if(!A.includes(n))return console.error(`Can't understand your data-model: ${n}. Please, find what is possible on https://github.com/PeterNaydenov/dt-toolbox`),null;return a(r,["flat","dt-model"].includes(n)?F.load(t):I.from(n).toFlat(r,t))},load(e){const n={};e.forEach((t=>{const[,,e]=t;n[e]=t}));const r=t({data:e});return a(F.dependencies,[r,n,e])},flating(t,e={}){let{model:n}=Object.assign({},{model:"std"},e);if(!A.includes(n))return null;let[,,r]=I.from("std").toFlat(F.dependencies,t);return r},converting(t,e={}){let{model:n,as:r}=Object.assign({},{model:"std",as:"std"},e);if(!A.includes(n))return null;if(!A.includes(r))return null;let[,,o]=I.from("std").toFlat(F.dependencies,t);return I.to(r,F.dependencies,o)},getWalk:()=>t},{init:w,load:N,flating:L,converting:x,getWalk:D}=F,H={init:w,load:N,flat:L,convert:x,getWalk:D};export{H as default};
1
+ import t from"@peter.naydenov/walk";function e(t,e){return function(n,r){const{convert:o,isDTO:s,isDTM:a,walk:c}=t();let i,u;if("string"!=typeof n||""===n)throw new Error(`insertSegment(name, data) requires a non-empty string segment name. Got: ${JSON.stringify(n)}`);if(n.includes("/"))throw new Error(`insertSegment(name, data) does not allow '/' in the segment name (it's the breadcrumbs separator). Got: ${JSON.stringify(n)}`);if(e.getIndexes()&&e.getIndexes()[n])throw new Error(`Segment "${n}" already exists. Use a different name or remove the existing segment first.`);if(null==r)throw new Error(`insertSegment('${n}', data) requires a value. Got: ${r}`);if("object"!=typeof r)throw new Error(`insertSegment('${n}', data) requires an object, dt-object, dt-model, or array. Got: ${typeof r} (${r})`);s(r)?(i=r.export(),u=r.copy()):a(r)?(i=c({data:r}),u=c({data:r})):([u,,i]=o.from("std").toFlat(t,r),console.warn('A non "dt-object" data segment was inserted. Autoconverted to "dt-object".'));const f=new RegExp("^root/");i.forEach(t=>{t[0]===t[2]&&(t[0]=n,t[2]=n),t[2]=t[2].replace(f,`${n}/`),t[3].forEach((e,r)=>t[3][r]=e.replace(f,`${n}/`))}),e.insert([u,,i])}}function n(t,e){return t=>e.export(t)}function r(t,e){return function(n="root"){if(void 0!==n&&"string"!=typeof n)throw new Error(`copy(name) expects a string segment name or no argument. Got: ${typeof n} (${n}).`);const r=e.getCopy(n),{walk:o}=t();return r?o({data:r}):null}}function o(t,e,n){return function(){let r=[],o={};const{convert:s,draft:a,INIT_DATA_TYPES:c,main:{load:i}}=t(),u={set:a.set(r,o),connect:a.connect(o),save:a.save(o),push:a.push(o)},[f,...l]=arguments,p=f({...n,...u},...l),{as:d}=p||{},h=0===r.length?e.export():r,y=!!d&&c.includes(d);if(void 0!==d&&"dt-object"!==d&&"string"!=typeof d)throw new Error(`model(fn) requires the 'as' value to be a string. Got: ${typeof d} (${d})`);if(d&&"dt-object"!==d&&!y)throw new Error(`Model '${d}' is unknown. Supported: ${c.join(", ")}, dt-object`);let m;return"dt-object"===d?i(h):(m=d?s.to(d,t,h):i(h),e.resetScan(),m)}}function s(t,e,n){return function(){const{main:{load:r},draft:o}=t(),[s,...a]=arguments;let c=[],i={};const u={set:o.set(c,i),connect:o.connect(i),save:o.save(i),push:o.push(i)};return s({...n,...u},...a),e.resetScan(),0===c.length?this:r(c)}}function a(t){return function(e,n){t.setupFilter(e,n)}}function c(t,e,n){return function(r,o){const s=n("root"),{main:{load:a},INIT_DATA_TYPES:c}=t(),i=[...c,"dt-object"];let u=!1,f="";if(o&&(o.as||(u=!0,f='Options should be an object and property "as" is required'),u||i.includes(o.as)||(u=!0,f=`Invalid option "as" value: ${o.as}.`),u))throw new Error(f);return r.map(t=>{let r=e.export(t);if(0===r.length){if(s&&s[1]&&Object.prototype.hasOwnProperty.call(s[1],t))return s[1][t];const e=(t=>{if(!t)return;const e=n(t);return e?e[1]:void 0})(t);return void 0!==e?e:function(t,e){const n=t.startsWith("root/")?[t]:[t,`root/${t}`];for(const t of n){const n=t.split("/");for(let t=n.length;t>0;t--){const r=e(n.slice(0,t).join("/"));if(r){if(t===n.length)return r[1];const e=n.slice(t);let o=r[1];for(const t of e){if(null==o)return;if(Array.isArray(o)){const e=parseInt(t,10);if(isNaN(e))return;o=o[e]}else{if("object"!=typeof o)return;o=o[t]}}return o}}}return}(t,n)}return r}).map(t=>null==t?null:t instanceof Array?a(t).model(()=>o):t)}}function i(t,i){const{flatData:u}=t(),[f,l]=u(t,i),p={insertSegment:e(t,f),export:n(0,f),copy:r(t,f),model:o(t,f,l),query:s(t,f,l),setupFilter:a(f),listSegments:()=>Object.keys(f.getIndexes()).reduce((t,e)=>(e.includes("/")||t.push(e),t),[]),index:d};function d(t){if(null==t)return null;let e=f.getLine(t);if(e){let t,[n,r,o,s]=e;return t=null==r||"object"!=typeof r?r:r instanceof Array?[...r]:{...r},[n,t,o,[...s]]}const n=t.lastIndexOf("/");if(n>0){const e=t.slice(0,n),r=t.slice(n+1),o=f.getLine(e);if(o){const[,e]=o;if(e&&"object"==typeof e&&!Array.isArray(e)&&Object.prototype.hasOwnProperty.call(e,r)){const n=e[r];let o;return o=null==n||"object"!=typeof n?n:n instanceof Array?[...n]:n instanceof Date?new Date(n.getTime()):n instanceof RegExp?new RegExp(n.source,n.flags):{...n},[r,o,t,[]]}}}return null}return p.extractList=c(t,f,d),p}function u(t,e,n){return function(r){const[o,,s]=r,a=s[0][0],[c,i,u]=t,f=n();c[a]=o,s.forEach(t=>{const[,,n]=t;i[n]=t,u.push(t),f.forEach(n=>e(n,t))})}}function f(t){return function(e){const[,n,r]=t;if(void 0!==e&&"string"!=typeof e)throw new Error(`export(name) expects a string segment name or no argument. Got: ${typeof e} (${e}).`);if(e&&!n[e])return[];if(!e){const t=[];return r.forEach(e=>{const[n,r,o,s]=e,a=l(r);t.push([n,a,o,[...s]])}),t}const o=[];return r.forEach(t=>{const[n,r,s,a]=t,c=new RegExp(`^${e}/`);if(s===e||s.match(c)){let t=n===s?"root":n,e=l(r),i=s.includes("/")?s.replace(c,"root/"):"root",u=a.map(t=>t.replace(c,"root/"));o.push([t,e,i,u])}}),o}}function l(t){return null==t||"object"!=typeof t?t:Array.isArray(t)?[...t]:t instanceof Date?new Date(t.getTime()):t instanceof RegExp?new RegExp(t.source,t.flags):{...t}}function p(t,e,n,r){return function(o,s){const a=r(),[,,c]=t;if(a.includes(o))return console.error(`Filter name "${o}" is already defined`),this;e[o]=s,c.forEach(t=>n(o,t))}}function d(t){return function(e){const n=t.getIndexes(),r=n[e],o=[];return r?(o.push(r),h(n,o,r[3]),t.setupScanList(o),this):(t.setupScanList([]),this)}}function h(t,e,n){n.forEach(n=>{const r=t[n];r&&(e.push(r),h(t,e,r[3]))})}function y(t){return function(e){const n=[];return t.getScanList().forEach(t=>{t[0]===e&&n.push(t)}),t.setupScanList(n),this}}function m(t){return function(e){const n=[],r=e instanceof Array?e:[e];return t.getScanList().forEach(t=>{const e=t[0];r.forEach(r=>{e.includes(r)&&n.push(t)})}),t.setupScanList(n),this}}function g(t){return function(e){t.getScanList().forEach(n=>{const[r,o,s,a]=n,c=o instanceof Array,i=()=>"$__NEXT__LOOK_",u=()=>"$__FINISH__WITH__THE__LOOKING_";let f=!1;const l=a.map(t=>{let e=t.replace(`${s}/`,"");return[r,e]});if(c)0===o.length?p([]):o.every((t,n)=>{if(f)return!1;const a=e({value:t,key:n,name:r,flatData:o,breadcrumbs:s,links:l,next:i,finish:u});return"$__FINISH__WITH__THE__LOOKING_"===a&&(f=!0),!["$__FINISH__WITH__THE__LOOKING_","$__NEXT__LOOK_"].includes(a)});else{const t=Object.entries(o);0===t.length?p({}):t.every(([t,n])=>{if(f)return!1;const a=e({value:n,key:t,name:r,flatData:o,breadcrumbs:s,links:l,next:i,finish:u});return"$__FINISH__WITH__THE__LOOKING_"===a&&(f=!0),!["$__FINISH__WITH__THE__LOOKING_","$__NEXT__LOOK_"].includes(a)})}function p(t){e({value:null,key:null,name:r,flatData:t,breadcrumbs:s,links:l,empty:!0,next:i,finish:u})}t.resetScan()})}}function b(t){return function(e){const n=[];return t.getScanList().every(t=>t[2]!==e||(n.push(t),!1)),t.setupScanList(n),this}}function $({flatData:t}){return t instanceof Array}function E({name:t,flatData:e}){return!(e instanceof Array)&&!isNaN(t)}function j({flatData:t}){return!(t instanceof Array)}function _({name:t,breadcrumbs:e}){return t===e}function w(t,e){const[n,r,o]=e,s=[n,r,o],a={},c={list:$,listObject:E,object:j,root:_};let i=o;const l=()=>Object.keys(c),h=(t,e)=>{if(c[t]){const[n,o,s,i]=e;if(a[t]||(a[t]=[]),c[t]({name:n,flatData:o,breadcrumbs:s,edges:i})){const e=r[s];a[t].push(e)}}};l().forEach(t=>o.forEach(e=>h(t,e)));const w={insert:u(s,h,l),export:f(s),getCopy:t=>n[t]?n[t]:null,getIndexes:()=>r,getLine:t=>r[t]?r[t]:null,getFilters:()=>a,getScanList:()=>i,setupScanList:t=>i=t,setupFilter:p(s,c,h,l),resetScan:()=>{i=o}};var v;return[w,{from:d(w),use:(v=w,function(t){const e=v.getFilters()[t];return e&&v.setupScanList(e),this}),get:b(w),find:y(w),like:m(w),look:g(w)}]}const v=t=>{if(null==t)return t;if("object"!=typeof t)return t;if(Array.isArray(t))return t.map(v);if(t instanceof Date)return new Date(t.getTime());if(t instanceof RegExp)return new RegExp(t.source,t.flags);if("function"==typeof t)return t;if(t.nodeType)return t;const e={};for(const n in t)e[n]=v(t[n]);return e},O="__dtSentinel__",S="date",A="regexp",T=(t,e)=>null!==t&&"object"==typeof t&&t[O]===e,x=t=>{if(null==t)return t;if("object"!=typeof t)return t;if(Array.isArray(t))return t.map(x);if(t instanceof Date)return{[O]:S,iso:t.toISOString()};if(t instanceof RegExp)return{[O]:A,source:t.source,flags:t.flags};if("function"==typeof t||t.nodeType)return t;const e={};for(const n in t)e[n]=x(t[n]);return e};const I=t=>{if(null==t)return t;if("object"!=typeof t)return t;const e=(t=>T(t,S)?new Date(t.iso):T(t,A)?new RegExp(t.source,t.flags):t)(t);if(e!==t)return e;if(Array.isArray(t))return t.map(I);const n={};for(const e in t)n[e]=I(t[e]);return n};var k={toFlat:function(t,e){const{walk:n}=t(),r=[],o={};return[{root:n({data:x(e),keyCallback:function({value:t,key:e,breadcrumbs:n}){const r=new RegExp(`/${e}$`),s=n.replace(r,"");return o[s][1][e]=t,t},objectCallback:function({value:t,key:e,breadcrumbs:n}){const s="root"===n&&"root"===e,a=t instanceof Array?[]:{},c=e,i=new RegExp(`/${e}$`),u=n.replace(i,""),f=[c,a,n,[]];return s||o[u][3].push(n),r.push(f),o[n]=r.at(-1),t}})},o,r]},toType:function(t){let e={},n=t.reverse(),r=[];n.forEach(([t,n,o,s])=>{const a=v(n);"root"===o||o.startsWith("root/")?(e[o]=a,s.forEach(t=>{if(e[t]){const n=t.replace(`${o}/`,"");e[o][n]=e[t]}})):r.push({name:t,breadcrumbs:o,data:a})});const o=e.root||{};return r.forEach(({name:t,breadcrumbs:e,data:n})=>{const r=o[t];!r||"object"!=typeof r||Array.isArray(r)||"object"!=typeof n||Array.isArray(n)?o[t]=n:o[t]={...r,...n}}),I(o)}};var N={toFlat:function(t,e){const n=Object.entries(e),{walk:r}=t(),o={},s=[],a={},c={};function i(t){a[t]||(a[t]="object");const e=t.split("/");1!=e.length&&(e.pop(),1!=e.length&&i(e.join("/")))}return n.forEach(([t,e])=>{t.startsWith("root")||(t=`root/${t}`),i(t),function(t,e){Object.keys(e).forEach(e=>{isNaN(e)||(a[t]="array")})}(t,e),c[t]=e}),Object.entries(a).forEach(([t,e])=>{if("object"===c[t])return;if(c[t]){const n=c[t]instanceof Array;if("array"===e&&!n){const e=Object.values(c[t]);c[t]=e}return}const n="object"===e?{}:[];c[t]=n}),Object.entries(c).sort().forEach(([t,e])=>{const n=t.split("/").pop(),r=t.replace(`/${n}`,""),a=[n,e instanceof Array?[...e]:{...e},t,[]];o[t]=a,s.push(a),"root"!==t&&r&&o[r]&&o[r][3].push(t)}),[r({data:e}),o,s]},toType:function(t){const e={};return t.forEach(t=>{const[,n,r]=t;if(0===Object.keys(n).length)return;const o=r.replace("root/",""),s=n instanceof Array?[...n]:{...n};e[o]=s}),e}};var F={toFlat:function(t,e){const{walk:n}=t(),r={},o={root:[]},s=[];function a(t){if("root"===t)return;const e=t.split("/");e.pop();const n=e.join("/");o[n]||(o[n]=[]),n.includes("/")&&a(n)}e.forEach(t=>{const[e,n]=t,r="root"===e?"root":`root/${e}`;o[r]?o[r].push(n):o[r]=[n],a(r)});let c=Object.entries(o).sort();const i={root:"object"};return c.forEach(([t,e])=>{if("root"===t)return;const n=t.split("/"),r=n.pop(),o=n.join("/");"array"!==i[o]&&!isNaN(r)&&(i[o]="array"),0===e.length&&(i[t]="object")}),c=Object.entries(o).sort(),c.forEach(([t,e])=>{const[n,o,a]=function(t){let e,n,r;if("root"==t)return e="root",n="root",r=null,[e,n,r];const o=t.split("/");return 2===o.length&&(e="root",n="root",r=o.pop()),o.length>2&&(r=o.pop(),e=o.pop(),n=0===o.length?`root/${e}`:`${o.join("/")}/${e}`),[e,n,r]}(t),c=0===e.length,u=1===e.length;let f,l;if(c){if(r[`${o}/${a}`])return;return null==a?(l="object"===i.root?{}:[],f=["root",l,"root",[]],r.root=f,void s.push(f)):(l="object"===i[`${o}/${a}`]?{}:[],f=[a,l,`${o}/${a}`,[]],r[`${o}/${a}`]=f,void s.push(f))}if(!u)return f=[a,e,`${o}/${a}`,[]],r[`${o}/${a}`]=f,void s.push(f);if(r[`${o}`])r[o][1][a]=e[0];else{const t={};t[a]=e[0],f=[n,t,o,[]],r[o]=f,s.push(f)}}),s.reverse(),s.forEach(t=>{const[e,n,o]=t,s=o.replace(`/${e}`,""),a=r[s];s!==o&&a&&a[3].push(o)}),s.reverse(),[n({data:e}),r,s]},toType:function(t){let e=[];return t.forEach(t=>{const[n,r,o]=t,s=r instanceof Array;let a="";if("root"!==n&&(a=o.replace("root/","")),s)return void(0==a.length?r.forEach((t,n)=>e.push(["root",t])):r.forEach(t=>e.push([a,t])));Object.entries(r).forEach(([t,n])=>{0==a.length?e.push([t,n]):e.push([`${a}/${t}`,n])})}),e}};const L=t=>(e,n)=>{switch(t){case"std":case"standard":return k.toFlat(e,n);case"tuple":case"tuples":return F.toFlat(e,n);case"breadcrumb":case"breadcrumbs":const t=Object.entries(n);return F.toFlat(e,t);case"file":case"files":const r=n.map(t=>{let e=t.split("/");1===e.length&&(e=["root"].concat(e));const n=e.pop();return[e.join("/"),n]});return F.toFlat(e,r);case"midFlat":return N.toFlat(e,n)}return[["object",0],{}]};var D={from:function(t){return{toFlat:L(t)}},to:function(t,e,n){const r={},{walk:o}=e(),s=new Set,a=new Set;let c,i=0;switch(t){case"flat":case"dt-model":return o({data:n});case"std":case"standard":return k.toType(n);case"midflat":case"midFlat":return N.toType(n);case"tuple":case"tuples":return F.toType(n);case"files":return c=F.toType(n),c.map(([t,e])=>"function"==typeof e?`${t}/function:${e.name}`:e?.nodeType?`${t}/HtmlElement:${e.tagName?e.tagName.toLowerCase():"notSpecified"}`:"root"===t?e:`${t}/${e}`);case"breadcrumb":case"breadcrumbs":let t;return c=F.toType(n),c.forEach(([t,e])=>s.has(t)?a.add(t):s.add(t)),c.forEach(([e,n])=>{if(a.has(e)){t!==e&&(t=e,i=0),r["root"===e?i:`${e}/${i}`]=n,i++}else r[e]=n}),r}}};function H(t,e,n){const r=t[e],o=r[2];r[2]=n,t[o]=r,r[3].forEach((e,r)=>{const s=new RegExp(`^${o}/`),a=e.replace(s,`${n}/`);H(t[e],e,a)})}var G={push:function(t){return function(e,n){const r=!!t[e]&&t[e][1];return r&&r instanceof Array?("object"==typeof value||r.push(n),this):this}},set:function(t,e){return function(n,r){const o=r instanceof Array,s=[];return s.push(n),null==r||"object"!=typeof r?s.push(r):o?s.push([...r]):s.push({...r}),s.push(n),s.push([]),t.push(s),e[n]=s,this}},connect:function(t){return function(e){e.forEach(e=>{let n=e.split("/");const r=n.pop(),o=n.pop(),s=t[o];if(!t[r])return this;if(!s)return this;if(s[1][r])return this;let a=`${s[2]}/${r}`;return H(t,r,a),s[3].includes(a)||s[3].push(a),this})}},save:function(t){return function(e,n,r){const o=!!t[e]&&t[e][1];return o?(o[n]||(o[n]=r),this):this}}};const R=["std","standard","tuple","tuples","breadcrumb","breadcrumbs","file","files","midFlat","midflat","flat","dt-model"],W=(t,e=new WeakSet)=>{if(null===t||"object"!=typeof t)return!1;if(e.has(t))return!0;if(e.add(t),Array.isArray(t)){for(const n of t)if(W(n,e))return!0}else for(const n in t)if(W(t[n],e))return!0;return!1},C={dependencies:()=>({walk:t,flatData:w,flatObject:i,convert:D,INIT_DATA_TYPES:R,main:{load:C.load},isDTO:t=>"function"==typeof t.insertSegment,isDTM:t=>t instanceof Array&&(t[0]instanceof Array&&(4===t[0].length&&"root"===t[0][0])),draft:G}),init(t,e={}){let{model:n}=Object.assign({},{model:"std"},e),r=C.dependencies;if(!R.includes(n))return console.error(`Can't understand your data-model: ${n}. Please, find what is possible on https://github.com/PeterNaydenov/dt-toolbox`),null;if(t&&"object"==typeof t&&W(t))throw new Error("Circular reference detected in data. dt-toolbox cannot initialise a self-referencing object.");let o=t;null!=t&&"object"==typeof t||(o={value:t});return i(r,["flat","dt-model"].includes(n)?C.load(o):D.from(n).toFlat(r,o))},load(e){const n={};e.forEach(t=>{const[,,e]=t;n[e]=t});const r=t({data:e});return i(C.dependencies,[r,n,e])},flating(t,e={}){let{model:n}=Object.assign({},{model:"std"},e);if(!R.includes(n))throw new Error(`Can't understand your data-model: ${n}. Supported: ${R.join(", ")}`);if(null==t||"object"!=typeof t)throw new Error(`flat(data, options) requires an object or array. Got: ${null===t?"null":typeof t}${null===t?"":" ("+t+")"}`);let[,,r]=D.from("std").toFlat(C.dependencies,t);return r},converting(t,e={}){let{model:n,as:r}=Object.assign({},{model:"std",as:"std"},e);if(!R.includes(n))throw new Error(`Can't understand source data-model: ${n}. Supported: ${R.join(", ")}`);if(!R.includes(r))throw new Error(`Can't understand target data-model: ${r}. Supported: ${R.join(", ")}`);if(null==t||"object"!=typeof t)throw new Error("convert(data, options) requires an object or array. Got: "+(null===t?"null":typeof t));let[,,o]=D.from("std").toFlat(C.dependencies,t);return D.to(r,C.dependencies,o)},getWalk:()=>t},{init:q,load:K,flating:P,converting:M,getWalk:X}=C,Y={init:q,load:K,flat:P,convert:M,getWalk:X};export{Y as default};
package/dist/dtbox.umd.js CHANGED
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("@peter.naydenov/walk")):"function"==typeof define&&define.amd?define(["@peter.naydenov/walk"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).dtbox=e(t.walk)}(this,(function(t){"use strict";function e(t,e){return function(n,r){const{convert:o,isDTO:s,isDTM:c,walk:a}=t();let u,i;s(r)?(u=r.export(),i=r.copy()):c(r)?(u=a({data:r}),i=a({data:r})):([i,,u]=o.from("std").toFlat(t,r),console.warn('A non "dt-object" data segment was inserted. Autoconverted to "dt-object".'));const l=new RegExp("^root/");u.forEach((t=>{t[0]===t[2]&&(t[0]=n,t[2]=n),t[2]=t[2].replace(l,`${n}/`),t[3].forEach(((e,r)=>t[3][r]=e.replace(l,`${n}/`)))})),e.insert([i,,u])}}function n(t,e){return t=>e.export(t)}function r(t,e){return function(n="root"){const r=e.getCopy(n),{walk:o}=t();return r?o({data:r}):null}}function o(t,e,n){return function(){let r=[],o={};const{convert:s,draft:c,INIT_DATA_TYPES:a,main:{load:u}}=t(),i={set:c.set(r,o),connect:c.connect(o),save:c.save(o),push:c.push(o)},[l,...f]=arguments,{as:d}=l({...n,...i},...f)||{},p=0===r.length?e.export():r,h=!!d&&a.includes(d);let b;return"dt-object"===d?u(p):d&&!h?(console.error(`Model '${d}' is unknown data-model.`),null):(b=d?s.to(d,t,p):u(p),e.resetScan(),b)}}function s(t,e,n){return function(){const{main:{load:r},draft:o}=t(),[s,...c]=arguments;let a=[],u={};const i={set:o.set(a,u),connect:o.connect(u),save:o.save(u),push:o.push(u)};return s({...n,...i},...c),e.resetScan(),0===a.length?this:r(a)}}function c(t){return function(e,n){t.setupFilter(e,n)}}function a(t,a){const{flatData:u}=t(),[i,l]=u(t,a),f={insertSegment:e(t,i),export:n(0,i),copy:r(t,i),model:o(t,i,l),query:s(t,i,l),setupFilter:c(i),listSegments:()=>Object.keys(i.getIndexes()).reduce(((t,e)=>(e.includes("/")||t.push(e),t)),[]),index:d};function d(t){if(null==t)return null;let e=i.getLine(t);if(e){let t,[n,r,o,s]=e;return t=r instanceof Array?[...r]:{...r},[n,t,o,[...s]]}return null}return f.extractList=function(t,e,n){return function(r,o){const s=n("root"),{main:{load:c},INIT_DATA_TYPES:a}=t(),u=[...a,"dt-object"];let i=!1,l="";if(o&&(o.as||(i=!0,l='Options should be an object and property "as" is required'),i||u.includes(o.as)||(i=!0,l=`Invalid option "as" value: ${o.as}.`),i))throw new Error(l);return r.map((t=>{let n=e.export(t);return 0===n.length?s[1].hasOwnProperty(t)?s[1][t]:null:n})).map((t=>null==t?null:t instanceof Array?c(t).model((()=>o)):t))}}(t,i,d),f}function u(t,e,n){return function(r){const[o,,s]=r,c=s[0][0],[a,u,i]=t,l=n();a[c]=o,s.forEach((t=>{const[,,n]=t;u[n]=t,i.push(t),l.forEach((n=>e(n,t)))}))}}function i(t){return function(e){const[,n,r]=t;if(e&&!n[e])return[];if(!e){const t=[];return r.forEach((e=>{const[n,r,o,s]=e,c=r instanceof Array?[...r]:{...r};t.push([n,c,o,[...s]])})),t}const o=[];return r.forEach((t=>{const[n,r,s,c]=t,a=new RegExp(`^${e}/`);if(s===e||s.match(a)){let t=n===s?"root":n,e=r instanceof Array?[...r]:{...r},u=s.includes("/")?s.replace(a,"root/"):"root",i=c.map((t=>t.replace(a,"root/")));o.push([t,e,u,i])}})),o}}function l(t,e,n,r){return function(o,s){const c=r(),[,,a]=t;if(c.includes(o))return console.error(`Filter name "${o}" is already defined`),this;e[o]=s,a.forEach((t=>n(o,t)))}}function f(t){return function(e){const n=t.getIndexes(),r=n[e],o=[];return r?(o.push(r),d(n,o,r[3]),t.setupScanList(o),this):(t.setupScanList([]),this)}}function d(t,e,n){n.forEach((n=>{const r=t[n];r&&(e.push(r),d(t,e,r[3]))}))}function p(t){return function(e){const n=[];return t.getScanList().forEach((t=>{t[0]===e&&n.push(t)})),t.setupScanList(n),this}}function h(t){return function(e){const n=[],r=e instanceof Array?e:[e];return t.getScanList().forEach((t=>{const e=t[0];r.forEach((r=>{e.includes(r)&&n.push(t)}))})),t.setupScanList(n),this}}function b(t){return function(e){t.getScanList().forEach((n=>{const[r,o,s,c]=n,a=o instanceof Array,u=()=>"$__NEXT__LOOK_",i=()=>"$__FINISH__WITH__THE__LOOKING_";let l=!1;const f=c.map((t=>{let e=t.replace(`${s}/`,"");return[r,e]}));if(a)0===o.length?d([]):o.every(((t,n)=>{if(l)return!1;const c=e({value:t,key:n,name:r,flatData:o,breadcrumbs:s,links:f,next:u,finish:i});return"$__FINISH__WITH__THE__LOOKING_"===c&&(l=!0),!["$__FINISH__WITH__THE__LOOKING_","$__NEXT__LOOK_"].includes(c)}));else{const t=Object.entries(o);0===t.length?d({}):t.every((([t,n])=>{if(l)return!1;const c=e({value:n,key:t,name:r,flatData:o,breadcrumbs:s,links:f,next:u,finish:i});return"$__FINISH__WITH__THE__LOOKING_"===c&&(l=!0),!["$__FINISH__WITH__THE__LOOKING_","$__NEXT__LOOK_"].includes(c)}))}function d(t){e({value:null,key:null,name:r,flatData:t,breadcrumbs:s,links:f,empty:!0,next:u,finish:i})}t.resetScan()}))}}function m(t){return function(e){const n=[];return t.getScanList().every((t=>t[2]!==e||(n.push(t),!1))),t.setupScanList(n),this}}function _({flatData:t}){return t instanceof Array}function y({name:t,flatData:e}){return!(e instanceof Array)&&!isNaN(t)}function g({flatData:t}){return!(t instanceof Array)}function $({name:t,breadcrumbs:e}){return t===e}function E(t,e){const[n,r,o]=e,s=[n,r,o],c={},a={list:_,listObject:y,object:g,root:$};let d=o;const E=()=>Object.keys(a),j=(t,e)=>{if(a[t]){const[n,o,s,u]=e;if(c[t]||(c[t]=[]),a[t]({name:n,flatData:o,breadcrumbs:s,edges:u})){const e=r[s];c[t].push(e)}}};E().forEach((t=>o.forEach((e=>j(t,e)))));const v={insert:u(s,j,E),export:i(s),getCopy:t=>n[t]?n[t]:null,getIndexes:()=>r,getLine:t=>r[t]?r[t]:null,getFilters:()=>c,getScanList:()=>d,setupScanList:t=>d=t,setupFilter:l(s,a,j,E),resetScan:()=>{d=o}};var O;return[v,{from:f(v),use:(O=v,function(t){const e=O.getFilters()[t];return e&&O.setupScanList(e),this}),get:m(v),find:p(v),like:h(v),look:b(v)}]}var j={toFlat:function(t,e){const{walk:n}=t(),r=[],o={};return[{root:n({data:e,keyCallback:function({value:t,key:e,breadcrumbs:n}){const r=new RegExp(`/${e}$`),s=n.replace(r,"");return o[s][1][e]=t,t},objectCallback:function({value:t,key:e,breadcrumbs:n}){const s="root"===n&&"root"===e,c=t instanceof Array?[]:{},a=e,u=new RegExp(`/${e}$`),i=n.replace(u,""),l=[a,c,n,[]];return s||o[i][3].push(n),r.push(l),o[n]=r.at(-1),t}})},o,r]},toType:function(t){let e={};return t.reverse().forEach((([t,n,r,o])=>{const s=n instanceof Array?[...n]:{...n};e[r]=s,o.forEach((t=>{if(e[t]){const n=t.replace(`${r}/`,"");e[r][n]=e[t]}}))})),e.root}};var v={toFlat:function(t,e){const n=Object.entries(e),{walk:r}=t(),o={},s=[],c={},a={};function u(t){c[t]||(c[t]="object");const e=t.split("/");1!=e.length&&(e.pop(),1!=e.length&&u(e.join("/")))}return n.forEach((([t,e])=>{t.startsWith("root")||(t=`root/${t}`),u(t),function(t,e){Object.keys(e).forEach((e=>{isNaN(e)||(c[t]="array")}))}(t,e),a[t]=e})),Object.entries(c).forEach((([t,e])=>{if("object"===a[t])return;if(a[t]){const n=a[t]instanceof Array;if("array"===e&&!n){const e=Object.values(a[t]);a[t]=e}return}const n="object"===e?{}:[];a[t]=n})),Object.entries(a).sort().forEach((([t,e])=>{const n=t.split("/").pop(),r=t.replace(`/${n}`,""),c=[n,e instanceof Array?[...e]:{...e},t,[]];o[t]=c,s.push(c),"root"!==t&&r&&o[r]&&o[r][3].push(t)})),[r({data:e}),o,s]},toType:function(t){const e={};return t.forEach((t=>{const[,n,r]=t;if(0===Object.keys(n).length)return;const o=r.replace("root/",""),s=n instanceof Array?[...n]:{...n};e[o]=s})),e}};var O={toFlat:function(t,e){const{walk:n}=t(),r={},o={root:[]},s=[];function c(t){if("root"===t)return;const e=t.split("/");e.pop();const n=e.join("/");o[n]||(o[n]=[]),n.includes("/")&&c(n)}e.forEach((t=>{const[e,n]=t,r="root"===e?"root":`root/${e}`;o[r]?o[r].push(n):o[r]=[n],c(r)}));let a=Object.entries(o).sort();const u={root:"object"};return a.forEach((([t,e])=>{if("root"===t)return;const n=t.split("/"),r=n.pop(),o=n.join("/");"array"!==u[o]&&!isNaN(r)&&(u[o]="array"),0===e.length&&(u[t]="object")})),a=Object.entries(o).sort(),a.forEach((([t,e])=>{const[n,o,c]=function(t){let e,n,r;if("root"==t)return e="root",n="root",r=null,[e,n,r];const o=t.split("/");return 2===o.length&&(e="root",n="root",r=o.pop()),o.length>2&&(r=o.pop(),e=o.pop(),n=0===o.length?`root/${e}`:`${o.join("/")}/${e}`),[e,n,r]}(t),a=0===e.length,i=1===e.length;let l,f;if(a){if(r[`${o}/${c}`])return;return null==c?(f="object"===u.root?{}:[],l=["root",f,"root",[]],r.root=l,void s.push(l)):(f="object"===u[`${o}/${c}`]?{}:[],l=[c,f,`${o}/${c}`,[]],r[`${o}/${c}`]=l,void s.push(l))}if(!i)return l=[c,e,`${o}/${c}`,[]],r[`${o}/${c}`]=l,void s.push(l);if(r[`${o}`])r[o][1][c]=e[0];else{const t={};t[c]=e[0],l=[n,t,o,[]],r[o]=l,s.push(l)}})),s.reverse(),s.forEach((t=>{const[e,n,o]=t,s=o.replace(`/${e}`,""),c=r[s];s!==o&&c&&c[3].push(o)})),s.reverse(),[n({data:e}),r,s]},toType:function(t){let e=[];return t.forEach((t=>{const[n,r,o]=t,s=r instanceof Array;let c="";if("root"!==n&&(c=o.replace("root/","")),s)return void(0==c.length?r.forEach(((t,n)=>e.push(["root",t]))):r.forEach((t=>e.push([c,t]))));Object.entries(r).forEach((([t,n])=>{0==c.length?e.push([t,n]):e.push([`${c}/${t}`,n])}))})),e}};const T=t=>(e,n)=>{switch(t){case"std":case"standard":return j.toFlat(e,n);case"tuple":case"tuples":return O.toFlat(e,n);case"breadcrumb":case"breadcrumbs":const t=Object.entries(n);return O.toFlat(e,t);case"file":case"files":const r=n.map((t=>{let e=t.split("/");1===e.length&&(e=["root"].concat(e));const n=e.pop();return[e.join("/"),n]}));return O.toFlat(e,r);case"midFlat":return v.toFlat(e,n)}return[["object",0],{}]};var k={from:function(t){return{toFlat:T(t)}},to:function(t,e,n){const r={},{walk:o}=e(),s=new Set,c=new Set;let a,u=0;switch(t){case"flat":case"dt-model":return o({data:n});case"std":case"standard":return j.toType(n);case"midflat":case"midFlat":return v.toType(n);case"tuple":case"tuples":return O.toType(n);case"files":return a=O.toType(n),a.map((([t,e])=>"function"==typeof e?`${t}/function:${e.name}`:e?.nodeType?`${t}/HtmlElement:${e.tagName?e.tagName.toLowerCase():"notSpecified"}`:"root"===t?e:`${t}/${e}`));case"breadcrumb":case"breadcrumbs":let t;return a=O.toType(n),a.forEach((([t,e])=>s.has(t)?c.add(t):s.add(t))),a.forEach((([e,n])=>{if(c.has(e)){t!==e&&(t=e,u=0),r["root"===e?u:`${e}/${u}`]=n,u++}else r[e]=n})),r}}};function I(t,e,n){const r=t[e],o=r[2];r[2]=n,t[o]=r,r[3].forEach(((e,r)=>{const s=new RegExp(`^${o}/`),c=e.replace(s,`${n}/`);I(t[e],e,c)}))}var S={push:function(t){return function(e,n){const r=!!t[e]&&t[e][1];return r&&r instanceof Array?("object"==typeof value||r.push(n),this):this}},set:function(t,e){return function(n,r){const o=r instanceof Array,s=[];return s.push(n),o?s.push([...r]):s.push({...r}),s.push(n),s.push([]),t.push(s),e[n]=s,this}},connect:function(t){return function(e){e.forEach((e=>{let n=e.split("/");const r=n.pop(),o=n.pop(),s=t[o];if(!t[r])return this;if(!s)return this;if(s[1][r])return this;let c=`${s[2]}/${r}`;return I(t,r,c),s[3].includes(c)||s[3].push(c),this}))}},save:function(t){return function(e,n,r){const o=!!t[e]&&t[e][1];return o?(o[n]||(o[n]=r),this):this}}};const w=["std","standard","tuple","tuples","breadcrumb","breadcrumbs","file","files","midFlat","midflat","flat","dt-model"],A={dependencies:()=>({walk:t,flatData:E,flatObject:a,convert:k,INIT_DATA_TYPES:w,main:{load:A.load},isDTO:t=>"function"==typeof t.insertSegment,isDTM:t=>t instanceof Array&&(t[0]instanceof Array&&(4===t[0].length&&"root"===t[0][0])),draft:S}),init(t,e={}){let{model:n}=Object.assign({},{model:"std"},e),r=A.dependencies;if(!w.includes(n))return console.error(`Can't understand your data-model: ${n}. Please, find what is possible on https://github.com/PeterNaydenov/dt-toolbox`),null;return a(r,["flat","dt-model"].includes(n)?A.load(t):k.from(n).toFlat(r,t))},load(e){const n={};e.forEach((t=>{const[,,e]=t;n[e]=t}));const r=t({data:e});return a(A.dependencies,[r,n,e])},flating(t,e={}){let{model:n}=Object.assign({},{model:"std"},e);if(!w.includes(n))return null;let[,,r]=k.from("std").toFlat(A.dependencies,t);return r},converting(t,e={}){let{model:n,as:r}=Object.assign({},{model:"std",as:"std"},e);if(!w.includes(n))return null;if(!w.includes(r))return null;let[,,o]=k.from("std").toFlat(A.dependencies,t);return k.to(r,A.dependencies,o)},getWalk:()=>t},{init:F,load:N,flating:L,converting:x,getWalk:D}=A;return{init:F,load:N,flat:L,convert:x,getWalk:D}}));
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("@peter.naydenov/walk")):"function"==typeof define&&define.amd?define(["@peter.naydenov/walk"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).dtbox=e(t.walk)}(this,function(t){"use strict";function e(t,e){return function(n,r){const{convert:o,isDTO:s,isDTM:a,walk:c}=t();let i,u;if("string"!=typeof n||""===n)throw new Error(`insertSegment(name, data) requires a non-empty string segment name. Got: ${JSON.stringify(n)}`);if(n.includes("/"))throw new Error(`insertSegment(name, data) does not allow '/' in the segment name (it's the breadcrumbs separator). Got: ${JSON.stringify(n)}`);if(e.getIndexes()&&e.getIndexes()[n])throw new Error(`Segment "${n}" already exists. Use a different name or remove the existing segment first.`);if(null==r)throw new Error(`insertSegment('${n}', data) requires a value. Got: ${r}`);if("object"!=typeof r)throw new Error(`insertSegment('${n}', data) requires an object, dt-object, dt-model, or array. Got: ${typeof r} (${r})`);s(r)?(i=r.export(),u=r.copy()):a(r)?(i=c({data:r}),u=c({data:r})):([u,,i]=o.from("std").toFlat(t,r),console.warn('A non "dt-object" data segment was inserted. Autoconverted to "dt-object".'));const f=new RegExp("^root/");i.forEach(t=>{t[0]===t[2]&&(t[0]=n,t[2]=n),t[2]=t[2].replace(f,`${n}/`),t[3].forEach((e,r)=>t[3][r]=e.replace(f,`${n}/`))}),e.insert([u,,i])}}function n(t,e){return t=>e.export(t)}function r(t,e){return function(n="root"){if(void 0!==n&&"string"!=typeof n)throw new Error(`copy(name) expects a string segment name or no argument. Got: ${typeof n} (${n}).`);const r=e.getCopy(n),{walk:o}=t();return r?o({data:r}):null}}function o(t,e,n){return function(){let r=[],o={};const{convert:s,draft:a,INIT_DATA_TYPES:c,main:{load:i}}=t(),u={set:a.set(r,o),connect:a.connect(o),save:a.save(o),push:a.push(o)},[f,...l]=arguments,p=f({...n,...u},...l),{as:d}=p||{},h=0===r.length?e.export():r,y=!!d&&c.includes(d);if(void 0!==d&&"dt-object"!==d&&"string"!=typeof d)throw new Error(`model(fn) requires the 'as' value to be a string. Got: ${typeof d} (${d})`);if(d&&"dt-object"!==d&&!y)throw new Error(`Model '${d}' is unknown. Supported: ${c.join(", ")}, dt-object`);let g;return"dt-object"===d?i(h):(g=d?s.to(d,t,h):i(h),e.resetScan(),g)}}function s(t,e,n){return function(){const{main:{load:r},draft:o}=t(),[s,...a]=arguments;let c=[],i={};const u={set:o.set(c,i),connect:o.connect(i),save:o.save(i),push:o.push(i)};return s({...n,...u},...a),e.resetScan(),0===c.length?this:r(c)}}function a(t){return function(e,n){t.setupFilter(e,n)}}function c(t,e,n){return function(r,o){const s=n("root"),{main:{load:a},INIT_DATA_TYPES:c}=t(),i=[...c,"dt-object"];let u=!1,f="";if(o&&(o.as||(u=!0,f='Options should be an object and property "as" is required'),u||i.includes(o.as)||(u=!0,f=`Invalid option "as" value: ${o.as}.`),u))throw new Error(f);return r.map(t=>{let r=e.export(t);if(0===r.length){if(s&&s[1]&&Object.prototype.hasOwnProperty.call(s[1],t))return s[1][t];const e=(t=>{if(!t)return;const e=n(t);return e?e[1]:void 0})(t);return void 0!==e?e:function(t,e){const n=t.startsWith("root/")?[t]:[t,`root/${t}`];for(const t of n){const n=t.split("/");for(let t=n.length;t>0;t--){const r=e(n.slice(0,t).join("/"));if(r){if(t===n.length)return r[1];const e=n.slice(t);let o=r[1];for(const t of e){if(null==o)return;if(Array.isArray(o)){const e=parseInt(t,10);if(isNaN(e))return;o=o[e]}else{if("object"!=typeof o)return;o=o[t]}}return o}}}return}(t,n)}return r}).map(t=>null==t?null:t instanceof Array?a(t).model(()=>o):t)}}function i(t,i){const{flatData:u}=t(),[f,l]=u(t,i),p={insertSegment:e(t,f),export:n(0,f),copy:r(t,f),model:o(t,f,l),query:s(t,f,l),setupFilter:a(f),listSegments:()=>Object.keys(f.getIndexes()).reduce((t,e)=>(e.includes("/")||t.push(e),t),[]),index:d};function d(t){if(null==t)return null;let e=f.getLine(t);if(e){let t,[n,r,o,s]=e;return t=null==r||"object"!=typeof r?r:r instanceof Array?[...r]:{...r},[n,t,o,[...s]]}const n=t.lastIndexOf("/");if(n>0){const e=t.slice(0,n),r=t.slice(n+1),o=f.getLine(e);if(o){const[,e]=o;if(e&&"object"==typeof e&&!Array.isArray(e)&&Object.prototype.hasOwnProperty.call(e,r)){const n=e[r];let o;return o=null==n||"object"!=typeof n?n:n instanceof Array?[...n]:n instanceof Date?new Date(n.getTime()):n instanceof RegExp?new RegExp(n.source,n.flags):{...n},[r,o,t,[]]}}}return null}return p.extractList=c(t,f,d),p}function u(t,e,n){return function(r){const[o,,s]=r,a=s[0][0],[c,i,u]=t,f=n();c[a]=o,s.forEach(t=>{const[,,n]=t;i[n]=t,u.push(t),f.forEach(n=>e(n,t))})}}function f(t){return function(e){const[,n,r]=t;if(void 0!==e&&"string"!=typeof e)throw new Error(`export(name) expects a string segment name or no argument. Got: ${typeof e} (${e}).`);if(e&&!n[e])return[];if(!e){const t=[];return r.forEach(e=>{const[n,r,o,s]=e,a=l(r);t.push([n,a,o,[...s]])}),t}const o=[];return r.forEach(t=>{const[n,r,s,a]=t,c=new RegExp(`^${e}/`);if(s===e||s.match(c)){let t=n===s?"root":n,e=l(r),i=s.includes("/")?s.replace(c,"root/"):"root",u=a.map(t=>t.replace(c,"root/"));o.push([t,e,i,u])}}),o}}function l(t){return null==t||"object"!=typeof t?t:Array.isArray(t)?[...t]:t instanceof Date?new Date(t.getTime()):t instanceof RegExp?new RegExp(t.source,t.flags):{...t}}function p(t,e,n,r){return function(o,s){const a=r(),[,,c]=t;if(a.includes(o))return console.error(`Filter name "${o}" is already defined`),this;e[o]=s,c.forEach(t=>n(o,t))}}function d(t){return function(e){const n=t.getIndexes(),r=n[e],o=[];return r?(o.push(r),h(n,o,r[3]),t.setupScanList(o),this):(t.setupScanList([]),this)}}function h(t,e,n){n.forEach(n=>{const r=t[n];r&&(e.push(r),h(t,e,r[3]))})}function y(t){return function(e){const n=[];return t.getScanList().forEach(t=>{t[0]===e&&n.push(t)}),t.setupScanList(n),this}}function g(t){return function(e){const n=[],r=e instanceof Array?e:[e];return t.getScanList().forEach(t=>{const e=t[0];r.forEach(r=>{e.includes(r)&&n.push(t)})}),t.setupScanList(n),this}}function m(t){return function(e){t.getScanList().forEach(n=>{const[r,o,s,a]=n,c=o instanceof Array,i=()=>"$__NEXT__LOOK_",u=()=>"$__FINISH__WITH__THE__LOOKING_";let f=!1;const l=a.map(t=>{let e=t.replace(`${s}/`,"");return[r,e]});if(c)0===o.length?p([]):o.every((t,n)=>{if(f)return!1;const a=e({value:t,key:n,name:r,flatData:o,breadcrumbs:s,links:l,next:i,finish:u});return"$__FINISH__WITH__THE__LOOKING_"===a&&(f=!0),!["$__FINISH__WITH__THE__LOOKING_","$__NEXT__LOOK_"].includes(a)});else{const t=Object.entries(o);0===t.length?p({}):t.every(([t,n])=>{if(f)return!1;const a=e({value:n,key:t,name:r,flatData:o,breadcrumbs:s,links:l,next:i,finish:u});return"$__FINISH__WITH__THE__LOOKING_"===a&&(f=!0),!["$__FINISH__WITH__THE__LOOKING_","$__NEXT__LOOK_"].includes(a)})}function p(t){e({value:null,key:null,name:r,flatData:t,breadcrumbs:s,links:l,empty:!0,next:i,finish:u})}t.resetScan()})}}function b(t){return function(e){const n=[];return t.getScanList().every(t=>t[2]!==e||(n.push(t),!1)),t.setupScanList(n),this}}function $({flatData:t}){return t instanceof Array}function E({name:t,flatData:e}){return!(e instanceof Array)&&!isNaN(t)}function j({flatData:t}){return!(t instanceof Array)}function _({name:t,breadcrumbs:e}){return t===e}function w(t,e){const[n,r,o]=e,s=[n,r,o],a={},c={list:$,listObject:E,object:j,root:_};let i=o;const l=()=>Object.keys(c),h=(t,e)=>{if(c[t]){const[n,o,s,i]=e;if(a[t]||(a[t]=[]),c[t]({name:n,flatData:o,breadcrumbs:s,edges:i})){const e=r[s];a[t].push(e)}}};l().forEach(t=>o.forEach(e=>h(t,e)));const w={insert:u(s,h,l),export:f(s),getCopy:t=>n[t]?n[t]:null,getIndexes:()=>r,getLine:t=>r[t]?r[t]:null,getFilters:()=>a,getScanList:()=>i,setupScanList:t=>i=t,setupFilter:p(s,c,h,l),resetScan:()=>{i=o}};var v;return[w,{from:d(w),use:(v=w,function(t){const e=v.getFilters()[t];return e&&v.setupScanList(e),this}),get:b(w),find:y(w),like:g(w),look:m(w)}]}const v=t=>{if(null==t)return t;if("object"!=typeof t)return t;if(Array.isArray(t))return t.map(v);if(t instanceof Date)return new Date(t.getTime());if(t instanceof RegExp)return new RegExp(t.source,t.flags);if("function"==typeof t)return t;if(t.nodeType)return t;const e={};for(const n in t)e[n]=v(t[n]);return e},O="__dtSentinel__",S="date",A="regexp",T=(t,e)=>null!==t&&"object"==typeof t&&t[O]===e,x=t=>{if(null==t)return t;if("object"!=typeof t)return t;if(Array.isArray(t))return t.map(x);if(t instanceof Date)return{[O]:S,iso:t.toISOString()};if(t instanceof RegExp)return{[O]:A,source:t.source,flags:t.flags};if("function"==typeof t||t.nodeType)return t;const e={};for(const n in t)e[n]=x(t[n]);return e};const I=t=>{if(null==t)return t;if("object"!=typeof t)return t;const e=(t=>T(t,S)?new Date(t.iso):T(t,A)?new RegExp(t.source,t.flags):t)(t);if(e!==t)return e;if(Array.isArray(t))return t.map(I);const n={};for(const e in t)n[e]=I(t[e]);return n};var k={toFlat:function(t,e){const{walk:n}=t(),r=[],o={};return[{root:n({data:x(e),keyCallback:function({value:t,key:e,breadcrumbs:n}){const r=new RegExp(`/${e}$`),s=n.replace(r,"");return o[s][1][e]=t,t},objectCallback:function({value:t,key:e,breadcrumbs:n}){const s="root"===n&&"root"===e,a=t instanceof Array?[]:{},c=e,i=new RegExp(`/${e}$`),u=n.replace(i,""),f=[c,a,n,[]];return s||o[u][3].push(n),r.push(f),o[n]=r.at(-1),t}})},o,r]},toType:function(t){let e={},n=t.reverse(),r=[];n.forEach(([t,n,o,s])=>{const a=v(n);"root"===o||o.startsWith("root/")?(e[o]=a,s.forEach(t=>{if(e[t]){const n=t.replace(`${o}/`,"");e[o][n]=e[t]}})):r.push({name:t,breadcrumbs:o,data:a})});const o=e.root||{};return r.forEach(({name:t,breadcrumbs:e,data:n})=>{const r=o[t];!r||"object"!=typeof r||Array.isArray(r)||"object"!=typeof n||Array.isArray(n)?o[t]=n:o[t]={...r,...n}}),I(o)}};var N={toFlat:function(t,e){const n=Object.entries(e),{walk:r}=t(),o={},s=[],a={},c={};function i(t){a[t]||(a[t]="object");const e=t.split("/");1!=e.length&&(e.pop(),1!=e.length&&i(e.join("/")))}return n.forEach(([t,e])=>{t.startsWith("root")||(t=`root/${t}`),i(t),function(t,e){Object.keys(e).forEach(e=>{isNaN(e)||(a[t]="array")})}(t,e),c[t]=e}),Object.entries(a).forEach(([t,e])=>{if("object"===c[t])return;if(c[t]){const n=c[t]instanceof Array;if("array"===e&&!n){const e=Object.values(c[t]);c[t]=e}return}const n="object"===e?{}:[];c[t]=n}),Object.entries(c).sort().forEach(([t,e])=>{const n=t.split("/").pop(),r=t.replace(`/${n}`,""),a=[n,e instanceof Array?[...e]:{...e},t,[]];o[t]=a,s.push(a),"root"!==t&&r&&o[r]&&o[r][3].push(t)}),[r({data:e}),o,s]},toType:function(t){const e={};return t.forEach(t=>{const[,n,r]=t;if(0===Object.keys(n).length)return;const o=r.replace("root/",""),s=n instanceof Array?[...n]:{...n};e[o]=s}),e}};var F={toFlat:function(t,e){const{walk:n}=t(),r={},o={root:[]},s=[];function a(t){if("root"===t)return;const e=t.split("/");e.pop();const n=e.join("/");o[n]||(o[n]=[]),n.includes("/")&&a(n)}e.forEach(t=>{const[e,n]=t,r="root"===e?"root":`root/${e}`;o[r]?o[r].push(n):o[r]=[n],a(r)});let c=Object.entries(o).sort();const i={root:"object"};return c.forEach(([t,e])=>{if("root"===t)return;const n=t.split("/"),r=n.pop(),o=n.join("/");"array"!==i[o]&&!isNaN(r)&&(i[o]="array"),0===e.length&&(i[t]="object")}),c=Object.entries(o).sort(),c.forEach(([t,e])=>{const[n,o,a]=function(t){let e,n,r;if("root"==t)return e="root",n="root",r=null,[e,n,r];const o=t.split("/");return 2===o.length&&(e="root",n="root",r=o.pop()),o.length>2&&(r=o.pop(),e=o.pop(),n=0===o.length?`root/${e}`:`${o.join("/")}/${e}`),[e,n,r]}(t),c=0===e.length,u=1===e.length;let f,l;if(c){if(r[`${o}/${a}`])return;return null==a?(l="object"===i.root?{}:[],f=["root",l,"root",[]],r.root=f,void s.push(f)):(l="object"===i[`${o}/${a}`]?{}:[],f=[a,l,`${o}/${a}`,[]],r[`${o}/${a}`]=f,void s.push(f))}if(!u)return f=[a,e,`${o}/${a}`,[]],r[`${o}/${a}`]=f,void s.push(f);if(r[`${o}`])r[o][1][a]=e[0];else{const t={};t[a]=e[0],f=[n,t,o,[]],r[o]=f,s.push(f)}}),s.reverse(),s.forEach(t=>{const[e,n,o]=t,s=o.replace(`/${e}`,""),a=r[s];s!==o&&a&&a[3].push(o)}),s.reverse(),[n({data:e}),r,s]},toType:function(t){let e=[];return t.forEach(t=>{const[n,r,o]=t,s=r instanceof Array;let a="";if("root"!==n&&(a=o.replace("root/","")),s)return void(0==a.length?r.forEach((t,n)=>e.push(["root",t])):r.forEach(t=>e.push([a,t])));Object.entries(r).forEach(([t,n])=>{0==a.length?e.push([t,n]):e.push([`${a}/${t}`,n])})}),e}};const L=t=>(e,n)=>{switch(t){case"std":case"standard":return k.toFlat(e,n);case"tuple":case"tuples":return F.toFlat(e,n);case"breadcrumb":case"breadcrumbs":const t=Object.entries(n);return F.toFlat(e,t);case"file":case"files":const r=n.map(t=>{let e=t.split("/");1===e.length&&(e=["root"].concat(e));const n=e.pop();return[e.join("/"),n]});return F.toFlat(e,r);case"midFlat":return N.toFlat(e,n)}return[["object",0],{}]};var D={from:function(t){return{toFlat:L(t)}},to:function(t,e,n){const r={},{walk:o}=e(),s=new Set,a=new Set;let c,i=0;switch(t){case"flat":case"dt-model":return o({data:n});case"std":case"standard":return k.toType(n);case"midflat":case"midFlat":return N.toType(n);case"tuple":case"tuples":return F.toType(n);case"files":return c=F.toType(n),c.map(([t,e])=>"function"==typeof e?`${t}/function:${e.name}`:e?.nodeType?`${t}/HtmlElement:${e.tagName?e.tagName.toLowerCase():"notSpecified"}`:"root"===t?e:`${t}/${e}`);case"breadcrumb":case"breadcrumbs":let t;return c=F.toType(n),c.forEach(([t,e])=>s.has(t)?a.add(t):s.add(t)),c.forEach(([e,n])=>{if(a.has(e)){t!==e&&(t=e,i=0),r["root"===e?i:`${e}/${i}`]=n,i++}else r[e]=n}),r}}};function H(t,e,n){const r=t[e],o=r[2];r[2]=n,t[o]=r,r[3].forEach((e,r)=>{const s=new RegExp(`^${o}/`),a=e.replace(s,`${n}/`);H(t[e],e,a)})}var G={push:function(t){return function(e,n){const r=!!t[e]&&t[e][1];return r&&r instanceof Array?("object"==typeof value||r.push(n),this):this}},set:function(t,e){return function(n,r){const o=r instanceof Array,s=[];return s.push(n),null==r||"object"!=typeof r?s.push(r):o?s.push([...r]):s.push({...r}),s.push(n),s.push([]),t.push(s),e[n]=s,this}},connect:function(t){return function(e){e.forEach(e=>{let n=e.split("/");const r=n.pop(),o=n.pop(),s=t[o];if(!t[r])return this;if(!s)return this;if(s[1][r])return this;let a=`${s[2]}/${r}`;return H(t,r,a),s[3].includes(a)||s[3].push(a),this})}},save:function(t){return function(e,n,r){const o=!!t[e]&&t[e][1];return o?(o[n]||(o[n]=r),this):this}}};const R=["std","standard","tuple","tuples","breadcrumb","breadcrumbs","file","files","midFlat","midflat","flat","dt-model"],W=(t,e=new WeakSet)=>{if(null===t||"object"!=typeof t)return!1;if(e.has(t))return!0;if(e.add(t),Array.isArray(t)){for(const n of t)if(W(n,e))return!0}else for(const n in t)if(W(t[n],e))return!0;return!1},C={dependencies:()=>({walk:t,flatData:w,flatObject:i,convert:D,INIT_DATA_TYPES:R,main:{load:C.load},isDTO:t=>"function"==typeof t.insertSegment,isDTM:t=>t instanceof Array&&(t[0]instanceof Array&&(4===t[0].length&&"root"===t[0][0])),draft:G}),init(t,e={}){let{model:n}=Object.assign({},{model:"std"},e),r=C.dependencies;if(!R.includes(n))return console.error(`Can't understand your data-model: ${n}. Please, find what is possible on https://github.com/PeterNaydenov/dt-toolbox`),null;if(t&&"object"==typeof t&&W(t))throw new Error("Circular reference detected in data. dt-toolbox cannot initialise a self-referencing object.");let o=t;null!=t&&"object"==typeof t||(o={value:t});return i(r,["flat","dt-model"].includes(n)?C.load(o):D.from(n).toFlat(r,o))},load(e){const n={};e.forEach(t=>{const[,,e]=t;n[e]=t});const r=t({data:e});return i(C.dependencies,[r,n,e])},flating(t,e={}){let{model:n}=Object.assign({},{model:"std"},e);if(!R.includes(n))throw new Error(`Can't understand your data-model: ${n}. Supported: ${R.join(", ")}`);if(null==t||"object"!=typeof t)throw new Error(`flat(data, options) requires an object or array. Got: ${null===t?"null":typeof t}${null===t?"":" ("+t+")"}`);let[,,r]=D.from("std").toFlat(C.dependencies,t);return r},converting(t,e={}){let{model:n,as:r}=Object.assign({},{model:"std",as:"std"},e);if(!R.includes(n))throw new Error(`Can't understand source data-model: ${n}. Supported: ${R.join(", ")}`);if(!R.includes(r))throw new Error(`Can't understand target data-model: ${r}. Supported: ${R.join(", ")}`);if(null==t||"object"!=typeof t)throw new Error("convert(data, options) requires an object or array. Got: "+(null===t?"null":typeof t));let[,,o]=D.from("std").toFlat(C.dependencies,t);return D.to(r,C.dependencies,o)},getWalk:()=>t},{init:q,load:K,flating:P,converting:M,getWalk:X}=C;return{init:q,load:K,flat:P,convert:M,getWalk:X}});
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dt-toolbox",
3
3
  "description": "Data manipulation tool",
4
- "version": "7.4.6",
4
+ "version": "7.4.7",
5
5
  "license": "MIT",
6
6
  "author": "Peter Naydenov",
7
7
  "main": "./dist/dtbox.umd.js",
@@ -2,6 +2,73 @@
2
2
 
3
3
 
4
4
 
5
+ /**
6
+ * Deep-copy a value while preserving special JS types.
7
+ * Plain objects and arrays are spread-copied (matching the old behaviour).
8
+ * Date, RegExp, and other non-plain objects are returned by reference so
9
+ * they round-trip intact — the previous `{...d}` silently dropped them to
10
+ * `{}` because their own properties are non-enumerable.
11
+ * NaN / Infinity / -Infinity are also returned as-is (was: coerced to null
12
+ * somewhere down the pipeline).
13
+ * @param {*} v - value to copy
14
+ * @returns {*} deep copy of the value
15
+ */
16
+ const deepCopy = ( v ) => {
17
+ if ( v === null || v === undefined ) return v
18
+ if ( typeof v !== 'object' ) return v
19
+ if ( Array.isArray ( v ) ) return v.map ( deepCopy )
20
+ if ( v instanceof Date ) return new Date ( v.getTime () )
21
+ if ( v instanceof RegExp ) return new RegExp ( v.source, v.flags )
22
+ // DOM nodes and functions are returned by reference (see Changelog 7.2.0)
23
+ if ( typeof v === 'function' ) return v
24
+ if ( v.nodeType ) return v
25
+ // plain object
26
+ const out = {};
27
+ for ( const k in v ) out[k] = deepCopy ( v[k] )
28
+ return out
29
+ };
30
+
31
+
32
+
33
+ // Sentinel for Date/RegExp encoding (see toFlat below).
34
+ // The walk library treats Date/RegExp as plain objects and copies them to
35
+ // empty `{}` (because their own properties are non-enumerable). To preserve
36
+ // them across the walk, we encode them as plain sentinel objects BEFORE
37
+ // walking and decode them back AFTER.
38
+ // The sentinel is a plain object with a known key shape so `toType` (and
39
+ // any future code that walks the dt-model) can decode it without needing
40
+ // a side-channel store.
41
+ const SENTINEL_KEY = '__dtSentinel__'
42
+ const SENTINEL_DATE = 'date'
43
+ const SENTINEL_REGEXP = 'regexp'
44
+
45
+ const isSentinel = ( v, kind ) =>
46
+ v !== null && typeof v === 'object' && v[SENTINEL_KEY] === kind
47
+
48
+ const decodeSentinel = ( v ) => {
49
+ if ( isSentinel ( v, SENTINEL_DATE ) ) return new Date ( v.iso )
50
+ if ( isSentinel ( v, SENTINEL_REGEXP ) ) return new RegExp ( v.source, v.flags )
51
+ return v
52
+ };
53
+
54
+ const encodeSpecialTypes = ( v ) => {
55
+ if ( v === null || v === undefined ) return v
56
+ if ( typeof v !== 'object' ) return v
57
+ if ( Array.isArray ( v ) ) return v.map ( encodeSpecialTypes )
58
+ if ( v instanceof Date ) {
59
+ return { [SENTINEL_KEY]: SENTINEL_DATE, iso: v.toISOString () }
60
+ }
61
+ if ( v instanceof RegExp ) {
62
+ return { [SENTINEL_KEY]: SENTINEL_REGEXP, source: v.source, flags: v.flags }
63
+ }
64
+ if ( typeof v === 'function' || v.nodeType ) return v // pass through
65
+ const out = {};
66
+ for ( const k in v ) out[k] = encodeSpecialTypes ( v[k] )
67
+ return out
68
+ };
69
+
70
+
71
+
5
72
  function toFlat ( dependencies, d ) { // Convert data to 'dt' model
6
73
  const
7
74
  { walk } = dependencies ()
@@ -11,8 +78,12 @@ function toFlat ( dependencies, d ) { // Convert data to 'dt' model
11
78
  , dtEDGES = 3 // Const: Edges in store record line;
12
79
  ;
13
80
 
81
+ // Encode Date/RegExp as plain sentinels so they survive the walk
82
+ // (the walk library collapses them to `{}` otherwise).
83
+ const encodedInput = encodeSpecialTypes ( d );
84
+
14
85
  function objCallbackFn ({ value, key, breadcrumbs }) {
15
- const
86
+ const
16
87
  isRoot = (breadcrumbs === 'root' ) && ( key === 'root' )
17
88
  , isArray = value instanceof Array ? true : false
18
89
  , dataType = isArray ? [] : {}
@@ -21,7 +92,7 @@ function toFlat ( dependencies, d ) { // Convert data to 'dt' model
21
92
  , parentName = breadcrumbs.replace ( search, '' )
22
93
  , newObject = [ objectName, dataType, breadcrumbs, [] ]
23
94
  ;
24
-
95
+
25
96
  if ( !isRoot ) index[ parentName][dtEDGES].push ( breadcrumbs )
26
97
  dt.push ( newObject )
27
98
  index [ breadcrumbs ] = dt.at(-1)
@@ -32,17 +103,17 @@ function toFlat ( dependencies, d ) { // Convert data to 'dt' model
32
103
  const
33
104
  search = new RegExp ( `\/${key}$` )
34
105
  , parentName = breadcrumbs.replace ( search, '' )
35
- ;
106
+ ;
36
107
  index [parentName][dtDATA][key] = value
37
108
  return value
38
109
  } // keyCallbackFn
39
110
 
40
111
  const copy = walk ({
41
- data : d
112
+ data : encodedInput
42
113
  , keyCallback : keyCallbackFn
43
- , objectCallback : objCallbackFn
114
+ , objectCallback : objCallbackFn
44
115
  })
45
- return [ { root:copy }, index, dt ]
116
+ return [ { root:copy }, index, dt ]
46
117
  } // getFlat func.
47
118
 
48
119
 
@@ -55,24 +126,66 @@ function toFlat ( dependencies, d ) { // Convert data to 'dt' model
55
126
 
56
127
 
57
128
  function toType ( dt ) {
58
- let
129
+ let
59
130
  result = {}
60
131
  , revDT = dt.reverse ()
132
+ , extraSegments = [] // dt-lines outside the root hierarchy;
61
133
  ;
62
134
  revDT.forEach ( ([ name, d, breadcrumbs, edges ]) => {
63
- const copy = d instanceof Array ? [...d] : {...d};
64
-
135
+ const copy = deepCopy ( d );
136
+
137
+ // A dt-line is "extra" if its breadcrumbs don't start
138
+ // with 'root/' (i.e. it's a top-level segment like 'extra1').
139
+ if ( breadcrumbs !== 'root' && !breadcrumbs.startsWith ( 'root/' ) ) {
140
+ extraSegments.push ( { name, breadcrumbs, data: copy } )
141
+ return
142
+ }
65
143
  result[breadcrumbs] = copy
66
144
  edges.forEach ( edge => {
67
145
  if ( result[edge] ) {
68
146
  const name = edge.replace (`${breadcrumbs}/`, '' );
69
147
  result[breadcrumbs][name] = result[edge]
70
- }
148
+ }
71
149
  })
72
150
  })
73
- return result['root']
151
+ // Merge any extra segments into the root result. Each becomes
152
+ // a top-level key, matching the same shape the user would get
153
+ // if all the data were in a single nested object.
154
+ const root = result['root'] || {}
155
+ extraSegments.forEach ( ({ name, breadcrumbs, data }) => {
156
+ const existing = root[name]
157
+ if ( existing && typeof existing === 'object' && !Array.isArray(existing) && typeof data === 'object' && !Array.isArray(data) ) {
158
+ // Same name as an existing root property: merge.
159
+ root[name] = { ...existing, ...data }
160
+ }
161
+ else {
162
+ // Use segment name; if name collides with a key on
163
+ // 'breadcrumbs' path, store under breadcrumbs key.
164
+ root[ name === breadcrumbs ? name : name ] = data
165
+ }
166
+ })
167
+ // Decode any Date/RegExp sentinels back to their original types.
168
+ return decodeSpecialTypesInResult ( root )
74
169
  } // toType func.
75
170
 
171
+ /**
172
+ * Walk a model result and replace any Date/RegExp sentinel objects
173
+ * with real Date/RegExp instances.
174
+ * @param {*} v - value to walk (typically result['root'])
175
+ * @returns {*} same shape with sentinels decoded
176
+ */
177
+ const decodeSpecialTypesInResult = ( v ) => {
178
+ if ( v === null || v === undefined ) return v
179
+ if ( typeof v !== 'object' ) return v
180
+ // Sentinel?
181
+ const decoded = decodeSentinel ( v )
182
+ if ( decoded !== v ) return decoded
183
+ if ( Array.isArray ( v ) ) return v.map ( decodeSpecialTypesInResult )
184
+ const out = {};
185
+ for ( const k in v ) out[k] = decodeSpecialTypesInResult ( v[k] )
186
+ return out
187
+ };
188
+
76
189
 
77
190
 
78
191
 
package/src/draft/set.js CHANGED
@@ -10,8 +10,14 @@ return function set ( name, data ) {
10
10
  ;
11
11
 
12
12
  newRecord.push (name)
13
- if ( isArray ) newRecord.push ( [...data] )
14
- else newRecord.push ( {...data} )
13
+ // Match the deepCopy semantics in the standard convertor so strings,
14
+ // numbers, booleans, null and undefined stay intact instead of being
15
+ // spread (which would char-index a string into {0:'n',1:'e',...}).
16
+ if ( data === null || data === undefined || typeof data !== 'object' ) {
17
+ newRecord.push ( data )
18
+ }
19
+ else if ( isArray ) newRecord.push ( [...data] )
20
+ else newRecord.push ( {...data} )
15
21
  newRecord.push ( name )
16
22
  newRecord.push ( [] )
17
23
  selection.push ( newRecord )
@@ -4,13 +4,20 @@ function ex ( flatStorage ) {
4
4
  return function ex ( name ) {
5
5
  const [ , indexes, flatData ] = flatStorage;
6
6
 
7
+ // Reject invalid argument types with a clear message.
8
+ // Before the fix, `export(null)`/`export(0)`/`export('') silently
9
+ // returned the whole model, and `export(42)` silently returned `[]`.
10
+ if ( name !== undefined && typeof name !== 'string' ) {
11
+ throw new Error ( `export(name) expects a string segment name or no argument. Got: ${typeof name} (${name}).` )
12
+ }
13
+
7
14
  if ( name && !indexes[name] ) return []
8
15
  if ( !name ) {
9
16
  const exportCopy = []
10
17
  flatData.forEach ( line => {
11
- const
18
+ const
12
19
  [ lnName, data, breadcrumbs, edges ] = line
13
- , dataChange = ( data instanceof Array ) ? [ ...data] : { ...data }
20
+ , dataChange = copyData ( data )
14
21
  ;
15
22
  exportCopy.push ([ lnName, dataChange, breadcrumbs, [...edges] ])
16
23
 
@@ -21,14 +28,14 @@ return function ex ( name ) {
21
28
  // If existing name:
22
29
  const selection = [];
23
30
  flatData.forEach ( line => {
24
- const
31
+ const
25
32
  [ lnName, data, breadcrumbs, edges ] = line
26
33
  , search = new RegExp ( `^${name}\/`)
27
34
  ;
28
35
  if ( breadcrumbs === name || breadcrumbs.match(search) ) {
29
- let
36
+ let
30
37
  nameChange = ( lnName === breadcrumbs ) ? 'root' : lnName
31
- , dataChange = ( data instanceof Array ) ? [ ...data ] : { ...data }
38
+ , dataChange = copyData ( data )
32
39
  , breadcrumbsChange = ( breadcrumbs.includes('/') ) ? breadcrumbs.replace ( search, 'root/' ) : 'root'
33
40
  , edgesChange = edges.map ( edge => edge.replace ( search, 'root/'))
34
41
  ;
@@ -39,6 +46,22 @@ return function ex ( name ) {
39
46
  return selection
40
47
  }}
41
48
 
49
+ /**
50
+ * Copy a flatData value while preserving primitive types.
51
+ * Previously this used `data instanceof Array ? [...data] : {...data}`,
52
+ * which silently spread a string into `{0:'n',1:'e',...}` (Bug fix 7).
53
+ * @param {*} data - value to copy
54
+ * @returns {*} copy
55
+ */
56
+ function copyData ( data ) {
57
+ if ( data === null || data === undefined ) return data
58
+ if ( typeof data !== 'object' ) return data // string, number, boolean, bigint, symbol, function
59
+ if ( Array.isArray ( data ) ) return [ ...data ]
60
+ if ( data instanceof Date ) return new Date ( data.getTime () )
61
+ if ( data instanceof RegExp ) return new RegExp ( data.source, data.flags )
62
+ return { ...data }
63
+ }
64
+
42
65
 
43
66
 
44
67
  export default ex
@@ -4,10 +4,16 @@
4
4
 
5
5
  function copy ( dependencies, flatIO ) {
6
6
  return function copy ( name = 'root' ) {
7
- const
7
+ // Reject invalid types with a clear error.
8
+ // Before the fix, copy(null)/copy(42) returned null silently while
9
+ // copy(undefined) returned the root — inconsistent.
10
+ if ( name !== undefined && typeof name !== 'string' ) {
11
+ throw new Error ( `copy(name) expects a string segment name or no argument. Got: ${typeof name} (${name}).` )
12
+ }
13
+ const
8
14
  c = flatIO.getCopy (name)
9
15
  , { walk } = dependencies ()
10
- ;
16
+ ;
11
17
  if ( !c ) return null
12
18
  return walk ({ data : c })
13
19
  }} // copy func.
@@ -4,33 +4,59 @@
4
4
 
5
5
  function extractList ( dependencies, flatIO, indexFn ) {
6
6
  return function extractList ( list, options ) {
7
- const
7
+ const
8
8
  root = indexFn ( 'root' )
9
9
  , { main:{load}, INIT_DATA_TYPES } = dependencies ()
10
10
  , asTypes = [ ...INIT_DATA_TYPES, 'dt-object' ]
11
11
  ;
12
- let
12
+ let
13
13
  error = false
14
14
  , errorMsg = ''
15
15
  ;
16
-
16
+
17
17
  if ( options ) {
18
18
  if ( !options.as ) {
19
19
  error = true
20
20
  errorMsg = `Options should be an object and property "as" is required`
21
21
  }
22
- if ( !error && !asTypes.includes(options.as) ) {
22
+ if ( !error && !asTypes.includes(options.as) ) {
23
23
  error = true
24
24
  errorMsg = `Invalid option "as" value: ${options.as}.`
25
25
  }
26
26
  if ( error ) throw new Error ( errorMsg )
27
27
  }
28
28
 
29
+ // Helper: resolve a name (which can be a single key, a segment
30
+ // name, or a 'breadcrumbs-style' path like 'c/d') against the
31
+ // dt-object. Before the fix, this only checked root[1] directly,
32
+ // so nested paths like 'c/d' returned null even when they exist.
33
+ //
34
+ // Strategy:
35
+ // 1. Try flatIO.export(name) — handles segments (returns dt-lines)
36
+ // and returns [] for properties.
37
+ // 2. Try the index function for the exact breadcrumbs.
38
+ // 3. Walk the dt-model via index breadcrumbs to resolve the path.
39
+ const resolveByIndex = ( name ) => {
40
+ if ( !name ) return undefined
41
+ const ix = indexFn ( name )
42
+ return ix ? ix[1] : undefined
43
+ };
44
+
29
45
  return list
30
46
  .map ( name => {
31
47
  let lines = flatIO.export ( name );
32
- if ( lines.length === 0 ) return root[1].hasOwnProperty(name) ? root[1][name] : null
33
- else return lines
48
+ if ( lines.length === 0 ) {
49
+ // 1. Try direct property lookup on root flatData
50
+ if ( root && root[1] && Object.prototype.hasOwnProperty.call ( root[1], name ) ) {
51
+ return root[1][name]
52
+ }
53
+ // 2. Try the index function with the full path
54
+ const v = resolveByIndex ( name )
55
+ if ( v !== undefined ) return v
56
+ // 3. Walk the path manually across the dt-model
57
+ return walkPath ( name, indexFn )
58
+ }
59
+ else return lines
34
60
  })
35
61
  .map ( item => {
36
62
  if ( item == null ) return null
@@ -39,6 +65,51 @@ return function extractList ( list, options ) {
39
65
  })
40
66
  }} // extractList func.
41
67
 
68
+ /**
69
+ * Walk a breadcrumbs-style path (e.g. 'root/c/d') across the dt-model
70
+ * and return the value at the end. Used by `extractList` to resolve
71
+ * nested property paths that don't correspond to a single dt-line.
72
+ *
73
+ * The caller may pass the path with or without a leading 'root/' —
74
+ * both forms are tried.
75
+ * @param {string} name - breadcrumbs-style path
76
+ * @param {function} indexFn - index function for looking up dt-lines
77
+ * @returns {*} value at the path, or undefined if not found
78
+ */
79
+ function walkPath ( name, indexFn ) {
80
+ const candidates = name.startsWith ( 'root/' ) ? [ name ] : [ name, `root/${name}` ]
81
+ for ( const fullPath of candidates ) {
82
+ const segments = fullPath.split ( '/' )
83
+ // Build up the breadcrumbs one segment at a time
84
+ for ( let i = segments.length; i > 0; i-- ) {
85
+ const br = segments.slice ( 0, i ).join ( '/' )
86
+ const dtLine = indexFn ( br )
87
+ if ( dtLine ) {
88
+ // Found a parent dt-line. If the path ends here,
89
+ // return its data; otherwise look up the remaining
90
+ // keys as properties of the parent's data.
91
+ if ( i === segments.length ) return dtLine[1]
92
+ const tail = segments.slice ( i )
93
+ let cur = dtLine[1]
94
+ for ( const k of tail ) {
95
+ if ( cur == null ) return undefined
96
+ if ( Array.isArray ( cur ) ) {
97
+ const idx = parseInt ( k, 10 )
98
+ if ( isNaN ( idx ) ) return undefined
99
+ cur = cur[idx]
100
+ }
101
+ else if ( typeof cur === 'object' ) {
102
+ cur = cur[k]
103
+ }
104
+ else return undefined
105
+ }
106
+ return cur
107
+ }
108
+ }
109
+ }
110
+ return undefined
111
+ }
112
+
42
113
 
43
114
 
44
115
  export default extractList
@@ -40,17 +40,44 @@ function flatObject ( dependencies, d ) {
40
40
 
41
41
  function index ( n ) {
42
42
  if ( n == null ) return null
43
+ // 1) Try the exact dt-line first
43
44
  let r = flatIO.getLine ( n )
44
45
  if ( r ) {
45
46
  let [ name, d, breadcrumbs, links ] = r;
46
47
  let copy;
47
- if ( d instanceof Array ) copy = [...d ]
48
- else copy = {...d }
48
+ if ( d === null || d === undefined ) copy = d
49
+ else if ( typeof d !== 'object' ) copy = d
50
+ else if ( d instanceof Array ) copy = [...d]
51
+ else copy = {...d}
49
52
  return [ name, copy, breadcrumbs, [...links] ]
50
53
  }
51
- else return null
52
- } // index func.
53
-
54
+ // 2) Try a scalar property on a parent dt-line.
55
+ // E.g. 'root/a' for the 'a' property of the 'root' dt-line,
56
+ // which lives in root flatData, not as its own dt-line.
57
+ const lastSlash = n.lastIndexOf ( '/' )
58
+ if ( lastSlash > 0 ) {
59
+ const parentBr = n.slice ( 0, lastSlash )
60
+ const propName = n.slice ( lastSlash + 1 )
61
+ const parent = flatIO.getLine ( parentBr )
62
+ if ( parent ) {
63
+ const [ , parentData ] = parent
64
+ if ( parentData && typeof parentData === 'object' && !Array.isArray(parentData)
65
+ && Object.prototype.hasOwnProperty.call ( parentData, propName ) ) {
66
+ const value = parentData[ propName ]
67
+ let copy
68
+ if ( value === null || value === undefined ) copy = value
69
+ else if ( typeof value !== 'object' ) copy = value
70
+ else if ( value instanceof Array ) copy = [...value]
71
+ else if ( value instanceof Date ) copy = new Date ( value.getTime () )
72
+ else if ( value instanceof RegExp ) copy = new RegExp ( value.source, value.flags )
73
+ else copy = { ...value }
74
+ return [ propName, copy, n, [] ]
75
+ }
76
+ }
77
+ }
78
+ return null
79
+ } // index func.
80
+
54
81
  objectAPI [ 'extractList' ] = extractList ( dependencies, flatIO, index )
55
82
  return objectAPI
56
83
  } // flatObject func.
@@ -5,6 +5,35 @@ return function insert ( name, inData ) {
5
5
  const { convert, isDTO, isDTM, walk } = dependencies();
6
6
  let d, copy;
7
7
 
8
+ // Validate the segment name (must be a non-empty string)
9
+ if ( typeof name !== 'string' || name === '' ) {
10
+ throw new Error ( `insertSegment(name, data) requires a non-empty string segment name. Got: ${JSON.stringify(name)}` )
11
+ }
12
+ // Reject segment names containing '/' because '/' is the
13
+ // breadcrumbs separator inside the dt-model. A name like
14
+ // 'a/b' would create a dt-line with breadcrumbs 'a/b' that
15
+ // collides with parent/child paths and silently breaks
16
+ // index(), extractList(), and model() lookups.
17
+ if ( name.includes ( '/' ) ) {
18
+ throw new Error ( `insertSegment(name, data) does not allow '/' in the segment name (it's the breadcrumbs separator). Got: ${JSON.stringify(name)}` )
19
+ }
20
+ // Reject duplicate segment names. Before the fix, a second
21
+ // insertSegment with the same name created two dt-lines at
22
+ // the same breadcrumbs, and model()/extractList() silently
23
+ // kept the FIRST and dropped the second.
24
+ if ( flatIO.getIndexes () && flatIO.getIndexes ()[name] ) {
25
+ throw new Error ( `Segment "${name}" already exists. Use a different name or remove the existing segment first.` )
26
+ }
27
+ // Reject missing/non-object data with a clear error.
28
+ // Before the fix, passing null/undefined/number/array produced
29
+ // cryptic "Cannot read properties of null" / "...reading '0'" errors.
30
+ if ( inData === null || inData === undefined ) {
31
+ throw new Error ( `insertSegment('${name}', data) requires a value. Got: ${inData}` )
32
+ }
33
+ if ( typeof inData !== 'object' ) {
34
+ throw new Error ( `insertSegment('${name}', data) requires an object, dt-object, dt-model, or array. Got: ${typeof inData} (${inData})` )
35
+ }
36
+
8
37
  if ( isDTO(inData) ) {
9
38
  d = inData.export ()
10
39
  copy = inData.copy ()
@@ -17,10 +46,10 @@ return function insert ( name, inData ) {
17
46
  [ copy,, d ] = convert.from ( 'std' ).toFlat ( dependencies, inData )
18
47
  console.warn ( 'A non "dt-object" data segment was inserted. Autoconverted to "dt-object".' )
19
48
  }
20
-
49
+
21
50
  const search = new RegExp ( `^root\/` );
22
51
  d.forEach ( line => { // Word 'root' should be changed to the argument 'name'.
23
- if ( line[0] === line[2] ) {
52
+ if ( line[0] === line[2] ) {
24
53
  line[0] = name
25
54
  line[2] = name
26
55
  }
@@ -4,11 +4,11 @@
4
4
 
5
5
  function model ( dependencies, flatIO ,flatStore ) {
6
6
  return function model () {
7
- let
7
+ let
8
8
  selection = [] // Place for building a query/model result;
9
9
  , selectionIx = {}
10
10
  ;
11
- const
11
+ const
12
12
  { convert, draft, INIT_DATA_TYPES, main:{load} } = dependencies ()
13
13
  , draft_API = {
14
14
  set : draft.set ( selection, selectionIx ) // Selection: Creates a new row;
@@ -17,19 +17,28 @@ return function model () {
17
17
  , push : draft.push ( selectionIx ) // Selection: Adds a new value to selection row if data is an array structure;
18
18
  }
19
19
  , [ fn, ...args ] = arguments
20
- , { as } = fn ( {...flatStore,...draft_API}, ...args ) || {}
20
+ , fnResult = fn ( {...flatStore,...draft_API}, ...args )
21
+ , { as } = fnResult || {}
21
22
  , data = ( selection.length === 0 ) ? flatIO.export() : selection
22
23
  , hasConvertor = as ? INIT_DATA_TYPES.includes ( as ) : false
23
24
  ;
24
25
 
26
+ // Validate `as` early. Before the fix, non-string `as` (e.g. 42, {})
27
+ // was coerced to string by JS, and unknown names logged to console.error
28
+ // and returned null — silent and confusing.
29
+ // 'dt-object' is also a valid 'as' value (returns a new dt-object)
30
+ // but isn't in INIT_DATA_TYPES so check it separately.
31
+ if ( as !== undefined && as !== 'dt-object' && typeof as !== 'string' ) {
32
+ throw new Error ( `model(fn) requires the 'as' value to be a string. Got: ${typeof as} (${as})` )
33
+ }
34
+ if ( as && as !== 'dt-object' && !hasConvertor ) {
35
+ throw new Error ( `Model '${as}' is unknown. Supported: ${INIT_DATA_TYPES.join(', ')}, dt-object` )
36
+ }
37
+
25
38
  let result;
26
- if ( as === 'dt-object' ) {
39
+ if ( as === 'dt-object' ) {
27
40
  return load ( data )
28
41
  }
29
- if ( as && !hasConvertor ) {
30
- console.error ( `Model '${as}' is unknown data-model.` )
31
- return null
32
- }
33
42
  if ( as ) result = convert.to ( as, dependencies, data )
34
43
  else result = load ( data )
35
44
  flatIO.resetScan ()
package/src/mainLib.js CHANGED
@@ -21,6 +21,31 @@ const INIT_DATA_TYPES = [
21
21
  ]
22
22
  ;
23
23
 
24
+ /**
25
+ * Detect circular references in data before it gets walked.
26
+ * Without this, `init()` enters infinite recursion and crashes Node
27
+ * with "JavaScript heap out of memory".
28
+ * @param {*} data - data to scan
29
+ * @param {WeakSet} [seen] - internal set of already-visited objects
30
+ * @returns {boolean} true if a cycle is detected
31
+ */
32
+ const hasCircularRef = ( data, seen = new WeakSet() ) => {
33
+ if ( data === null || typeof data !== 'object' ) return false
34
+ if ( seen.has ( data ) ) return true
35
+ seen.add ( data )
36
+ if ( Array.isArray ( data ) ) {
37
+ for ( const v of data ) {
38
+ if ( hasCircularRef ( v, seen ) ) return true
39
+ }
40
+ }
41
+ else {
42
+ for ( const k in data ) {
43
+ if ( hasCircularRef ( data[k], seen ) ) return true
44
+ }
45
+ }
46
+ return false
47
+ };
48
+
24
49
 
25
50
 
26
51
  /**
@@ -97,7 +122,7 @@ const mainLib = {
97
122
  * @returns {DTObject} - dt-object
98
123
  */
99
124
  init ( inData, options={} ) {
100
- let
125
+ let
101
126
  defaultOptions = { model : 'std' }
102
127
  , { model } = Object.assign ( {}, defaultOptions, options )
103
128
  , dependencies = mainLib.dependencies
@@ -106,9 +131,22 @@ const mainLib = {
106
131
  console.error ( `Can't understand your data-model: ${model}. Please, find what is possible on https://github.com/PeterNaydenov/dt-toolbox` )
107
132
  return null
108
133
  }
109
- const d = ['flat', 'dt-model'].includes ( model ) ?
110
- mainLib.load ( inData ) :
111
- convert.from ( model ).toFlat ( dependencies, inData );
134
+ // Circular reference guard: `walk` recurses without tracking, so
135
+ // cycles cause a fatal OOM crash. Catch them up-front.
136
+ if ( inData && typeof inData === 'object' && hasCircularRef ( inData ) ) {
137
+ throw new Error ( 'Circular reference detected in data. dt-toolbox cannot initialise a self-referencing object.' )
138
+ }
139
+ // Primitive inputs (number, string, boolean, null, undefined) are
140
+ // wrapped in { value: <primitive> } so the data is preserved
141
+ // and round-trippable. Before the fix, primitives silently
142
+ // produced empty dt-objects and the value was lost.
143
+ let actualData = inData
144
+ if ( inData === null || inData === undefined || typeof inData !== 'object' ) {
145
+ actualData = { value: inData }
146
+ }
147
+ const d = ['flat', 'dt-model'].includes ( model ) ?
148
+ mainLib.load ( actualData ) :
149
+ convert.from ( model ).toFlat ( dependencies, actualData );
112
150
  return flatObject ( dependencies, d )
113
151
  }, // init func.
114
152
 
@@ -144,11 +182,19 @@ const mainLib = {
144
182
  * @returns {Dtmodel[]} - dt-model
145
183
  */
146
184
  flating ( inData, options={} ) {
147
- let
185
+ let
148
186
  defaultOptions = { model : 'std' }
149
187
  , { model } = Object.assign ( {}, defaultOptions, options )
150
188
  ;
151
- if ( !INIT_DATA_TYPES.includes(model) ) return null
189
+ if ( !INIT_DATA_TYPES.includes(model) ) {
190
+ throw new Error ( `Can't understand your data-model: ${model}. Supported: ${INIT_DATA_TYPES.join(', ')}` )
191
+ }
192
+ // Reject non-object input with a clear error.
193
+ // Before the fix, flat(null)/flat(undefined)/flat(42) silently
194
+ // returned [].
195
+ if ( inData === null || inData === undefined || typeof inData !== 'object' ) {
196
+ throw new Error ( `flat(data, options) requires an object or array. Got: ${inData === null ? 'null' : typeof inData}${inData === null ? '' : ' (' + inData + ')'}` )
197
+ }
152
198
  let [,,dt] = convert.from ('std').toFlat ( mainLib.dependencies, inData );
153
199
  return dt
154
200
  }, // flating func.
@@ -163,12 +209,19 @@ const mainLib = {
163
209
  * @returns {Array|Object} - converted data
164
210
  */
165
211
  converting ( inData, options={} ) {
166
- let
212
+ let
167
213
  defaultOptions = { model : 'std', as: 'std' }
168
214
  , { model, as } = Object.assign ( {}, defaultOptions, options )
169
215
  ;
170
- if ( !INIT_DATA_TYPES.includes(model) ) return null
171
- if ( !INIT_DATA_TYPES.includes(as) ) return null
216
+ if ( !INIT_DATA_TYPES.includes(model) ) {
217
+ throw new Error ( `Can't understand source data-model: ${model}. Supported: ${INIT_DATA_TYPES.join(', ')}` )
218
+ }
219
+ if ( !INIT_DATA_TYPES.includes(as) ) {
220
+ throw new Error ( `Can't understand target data-model: ${as}. Supported: ${INIT_DATA_TYPES.join(', ')}` )
221
+ }
222
+ if ( inData === null || inData === undefined || typeof inData !== 'object' ) {
223
+ throw new Error ( `convert(data, options) requires an object or array. Got: ${inData === null ? 'null' : typeof inData}` )
224
+ }
172
225
  let [,,dt] = convert.from ('std').toFlat ( mainLib.dependencies, inData );
173
226
 
174
227
  return convert.to ( as, mainLib.dependencies, dt )