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 +24 -2
- package/Migration.guide.md +7 -7
- package/README.md +13 -13
- package/dist/dtbox.cjs +1 -1
- package/dist/dtbox.esm.mjs +1 -1
- package/dist/dtbox.umd.js +1 -1
- package/package.json +1 -1
- package/src/convertors/standard.js +124 -11
- package/src/draft/set.js +8 -2
- package/src/flatData/export.js +28 -5
- package/src/flatObject/copy.js +8 -2
- package/src/flatObject/extractList.js +77 -6
- package/src/flatObject/index.js +32 -5
- package/src/flatObject/insert.js +31 -2
- package/src/flatObject/model.js +17 -8
- package/src/mainLib.js +62 -9
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
|
|
242
|
+
- [x] Method 'space' is deprecated;
|
|
221
243
|
- [x] New method 'purify'. Removes empty structures from the selection;
|
|
222
|
-
- [x] Method 'loadFast' was
|
|
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;
|
package/Migration.guide.md
CHANGED
|
@@ -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
|
|
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' ], {
|
|
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"
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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;
|
package/dist/dtbox.esm.mjs
CHANGED
|
@@ -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
|
@@ -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 :
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
14
|
-
|
|
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 )
|
package/src/flatData/export.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
package/src/flatObject/copy.js
CHANGED
|
@@ -4,10 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
function copy ( dependencies, flatIO ) {
|
|
6
6
|
return function copy ( name = 'root' ) {
|
|
7
|
-
|
|
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 )
|
|
33
|
-
|
|
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
|
package/src/flatObject/index.js
CHANGED
|
@@ -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
|
|
48
|
-
else
|
|
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
|
-
|
|
52
|
-
|
|
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.
|
package/src/flatObject/insert.js
CHANGED
|
@@ -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
|
}
|
package/src/flatObject/model.js
CHANGED
|
@@ -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
|
-
,
|
|
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
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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) )
|
|
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) )
|
|
171
|
-
|
|
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 )
|