@peter.naydenov/morph 1.2.3 → 2.0.1
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 +13 -0
- package/Migration.guide.md +35 -0
- package/README.md +39 -1
- package/dist/morph.cjs +1 -1
- package/dist/morph.esm.mjs +1 -1
- package/dist/morph.umd.js +1 -1
- package/package.json +2 -2
- package/src/methods/_defineData.js +7 -7
- package/src/methods/_readTemplate.js +5 -3
- package/src/methods/_setupActions.js +16 -0
- package/src/methods/build.js +25 -19
package/Changelog.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
### 2.0.1 (2025-03-25)
|
|
6
|
+
- [x] Fix: Deep data render index;
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### 2.0.0 (2025-03-25)
|
|
11
|
+
- [x] Memory action intoduced - memory is available in data functions;
|
|
12
|
+
- [x] Change in arguments format for helper functions;
|
|
13
|
+
- [x] Overwrite action introduced - when change in data should be available for all placeholders;
|
|
14
|
+
- [ ] Bug: Fix: Deep data render index;
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
5
18
|
### 1.2.3 (2025-03-17)
|
|
6
19
|
- [x] Refactoring: Extended render;
|
|
7
20
|
|
package/Migration.guide.md
CHANGED
|
@@ -1,6 +1,41 @@
|
|
|
1
1
|
# Migration Guides
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## 1.x.x -> 2.x.x
|
|
5
|
+
Modification of data is available only for current placeholder. If you need to remember changes in data, use the new memory action - '^something' where '^' is for memory and 'something' is the name. Memory will make a snapshot of the current data and will be available in helper functions. If you need to provide changes to all placeholders, use overwrite action. It's a snapshot that will be remember as a main data and will be available for all placeholders.
|
|
6
|
+
|
|
7
|
+
Arguments for helper functions are chaged. Because we want to have many arguments and we don't want to think about their order, we make an object with named arguments. Available arguments are: data, dependencies, memory.
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
// Before
|
|
11
|
+
const template = {
|
|
12
|
+
template : `Hello from {{ @all : name }}. I'm {{ age }} years old {{ job }}`
|
|
13
|
+
, helpers : {
|
|
14
|
+
name: ( data ) => data.name // Change in arguments of helper functions!
|
|
15
|
+
}
|
|
16
|
+
, handshake: {
|
|
17
|
+
name: 'Peter'
|
|
18
|
+
, age: 40
|
|
19
|
+
, job: 'developer'
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// After
|
|
24
|
+
const template = {
|
|
25
|
+
template : `Hello from {{ @all : name }}. I'm {{ age }} years old {{ job }}`
|
|
26
|
+
, helpers : {
|
|
27
|
+
name: ({ data, memory, dependencies }) => data.name // data is named argument
|
|
28
|
+
}
|
|
29
|
+
, handshake: {
|
|
30
|
+
name: 'Peter'
|
|
31
|
+
, age: 40
|
|
32
|
+
, job: 'developer'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
4
39
|
## 0.x.x -> 1.x.x
|
|
5
40
|
Main change is how you address templates. Before template name and storage were separated arguments. Now they are a single argument where the first element is the template name and the second element is the storage name. Storage name is optional and defaults to 'default'.
|
|
6
41
|
|
package/README.md
CHANGED
|
@@ -8,6 +8,15 @@
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
## What's new in version 2.x.x
|
|
12
|
+
- Data helper functions modifies the data per placeholder;
|
|
13
|
+
- Arguments for helper functions are named arguments;
|
|
14
|
+
- Memory action introduced - memory is available in helper functions as a named argument;
|
|
15
|
+
- Overwrite action introduced - when change in data should be available for all placeholders;
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
11
20
|
## General Information
|
|
12
21
|
|
|
13
22
|
`Morph` has a logic-less template syntax. Placeholders are places surrounded by double curly braces `{{ }}` and they represents the pleces where the data will be inserted.
|
|
@@ -17,6 +26,7 @@ Some features of Morph:
|
|
|
17
26
|
- Simple logic-less template syntax;
|
|
18
27
|
- Builtin storage;
|
|
19
28
|
- Powerfull action system for data decoration;
|
|
29
|
+
- Demo request can render the template with the builtin data;
|
|
20
30
|
- Nesting templates as part of the action system;
|
|
21
31
|
- Partial rendering (render only available data);
|
|
22
32
|
- Option to connect templates to external data sources;
|
|
@@ -26,6 +36,10 @@ Some features of Morph:
|
|
|
26
36
|
|
|
27
37
|
|
|
28
38
|
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
29
43
|
## Installation
|
|
30
44
|
|
|
31
45
|
```
|
|
@@ -50,13 +64,22 @@ import morph from "@peter.naydenov/morph"
|
|
|
50
64
|
|
|
51
65
|
const myTemplateDescription = {
|
|
52
66
|
template: `Hello, {{name}}!` // simple template - a string with a placeholder
|
|
67
|
+
, helers : {
|
|
68
|
+
// helper functions
|
|
69
|
+
}
|
|
70
|
+
, handshake : {
|
|
71
|
+
// ... demo data here
|
|
72
|
+
name : 'Ivan'
|
|
73
|
+
}
|
|
53
74
|
}
|
|
54
75
|
const myTemplate = morph.build ( myTemplateDescription ); // myTemplate is a render function
|
|
55
76
|
const htmlBlock = myTemplate ( { name: 'Peter' } ) // Provide data to the render function and get the result
|
|
56
77
|
// htmlBlock === 'Hello, Peter!'
|
|
78
|
+
const demo = myTemplate ( 'demo' )
|
|
79
|
+
// demo === 'Hello, Ivan!'
|
|
57
80
|
```
|
|
58
81
|
|
|
59
|
-
Morph contains also a builtin template
|
|
82
|
+
Morph contains also a builtin template storages. Instead of creating variable for each template, we can use the storages.
|
|
60
83
|
|
|
61
84
|
```js
|
|
62
85
|
// add template to the storage. Automatically builds the render function
|
|
@@ -64,6 +87,14 @@ Morph contains also a builtin template storage. Instead of creating variable for
|
|
|
64
87
|
morph.add ( ['myTemplate'], myTemplateDescription )
|
|
65
88
|
// get template from the storage and render it
|
|
66
89
|
const htmlBlock = morph.get ( ['myTemplate'] )({ name: 'Peter' })
|
|
90
|
+
// it's same as text above
|
|
91
|
+
morph.add ( ['myTemplate', 'default'], myTemplateDescription )
|
|
92
|
+
const htmlBlock = morph.get ( ['myTemplate', 'default'] )({ name: 'Peter' })
|
|
93
|
+
// if we use custom storage:
|
|
94
|
+
morph.add ( ['myTemplate', 'hidden'], myTemplateDescription ) // write template in storage 'hidden'
|
|
95
|
+
const htmlBlock = morph.get ( ['myTemplate', 'hidden'] )({ name: 'Peter' }) // render template from 'hidden' storage
|
|
96
|
+
morph.get ( ['myTemplate'] )({ name: 'Peter' }) // call template 'myTemplate' from default storage
|
|
97
|
+
// will return error, because default storage does not have template "myTemplate"
|
|
67
98
|
```
|
|
68
99
|
|
|
69
100
|
Let's see a more complex example before we go into details:
|
|
@@ -80,6 +111,9 @@ const myTemplateDescription = {
|
|
|
80
111
|
, a: `<a href="{{href}}">{{text}}</a>`
|
|
81
112
|
, getAge: (person) => person.age
|
|
82
113
|
}
|
|
114
|
+
, handshake: {
|
|
115
|
+
// ... demo data here
|
|
116
|
+
}
|
|
83
117
|
}
|
|
84
118
|
const myTemplate = morph.build ( myTemplateDescription );
|
|
85
119
|
const htmlBlock = myTemplate ( { person: {
|
|
@@ -182,6 +216,10 @@ Actions are concise representations of a sequence of function calls. Some functi
|
|
|
182
216
|
- `Mixing` functions start with '[]';
|
|
183
217
|
- `Conditional render` actions start with '?';
|
|
184
218
|
- `Extended render` start with '+';
|
|
219
|
+
- `Memory` actions start with '^'. Memory action will take a data snapshot and will be available in helper functions as a named argument 'memory'. The name after the prefix is the name of the snapshot. Request saved data from helper functions by calling 'memory[name]';
|
|
220
|
+
- `Overwrite` action is marked with '^^'. Means that the current data will be available for all placeholders, not only for the current placeholder;
|
|
221
|
+
|
|
222
|
+
|
|
185
223
|
|
|
186
224
|
Here are some examples:
|
|
187
225
|
```js
|
package/dist/morph.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("@peter.naydenov/walk"),t=require("@peter.naydenov/stack");function r(e){return function t(r){const{TG_PRX:a,TG_SFX:o,TG_SIZE_P:s,TG_SIZE_S:
|
|
1
|
+
"use strict";var e=require("@peter.naydenov/walk"),t=require("@peter.naydenov/stack");function r(e){return function t(r){const{TG_PRX:a,TG_SFX:o,TG_SIZE_P:s,TG_SIZE_S:c}=e;let i,l,u,f=[];if("string"!=typeof r)return n("notAString");if(0==r.length)return[];if(i=r.indexOf(a),0<i&&f.push(r.slice(0,i)),-1==i)return f.push(r),f;{if(u=r.indexOf(a,i+s),l=r.indexOf(o),-1==l)return n("missingClosing");if(l<i)return n("closedBeforeOpened");if(l+=c,-1!=u&&u<l)return n("newBeforeClosed");f.push(r.slice(i,l));let e=t(r.slice(l));return f.concat(e)}}}function n(e){switch(e){case"notAString":return"Error: Template is not a string.";case"missingClosing":return"Error: Placeholder with missing closing tag.";case"closedBeforeOpened":return"Error: Placeholder closing tag without starting one.";case"newBeforeClosed":return"Error: Nested placeholders. Close placeholder before open new one.";default:return"Error: Unknown template error."}}function a(t,r){const n=[];let a=0;if(t instanceof Function)return{dataDeepLevel:0,nestedData:[[t()]]};if(null==t)return{dataDeepLevel:0,nestedData:[null]};if("string"==typeof t)return{dataDeepLevel:0,nestedData:[[t]]};const o=structuredClone(t);if(!r.includes("#"))return n.push([o]),{dataDeepLevel:0,nestedData:n};return e({data:o,objectCallback:function({key:e,value:t,breadcrumbs:r}){return e===r?(n[0]=[t],t):(a=r.split("/").length-1,n[a]||(n[a]=[]),n[a].push(t),t)}}),{dataDeepLevel:a,nestedData:n}}var o={TG_PRX:"{{",TG_SFX:"}}",TG_SIZE_P:2,TG_SIZE_S:2};function s(e){return null==e?"null":"string"==typeof e||"number"==typeof e||"boolean"==typeof e?"primitive":"function"==typeof e?"function":e instanceof Array?"array":e instanceof Object?"object":void 0}function c(e,t,n,...a){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text),r instanceof Array&&(e[t]=r[0])}));const s="function"==typeof n[t];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),s?n[t](e,...a):function(e,t){if(null==t)return null;const n=r(o)(e),a=o;return n.forEach(((e,r)=>{if(e.includes(a.TG_PRX)){const o=e.replace(a.TG_PRX,"").replace(a.TG_SFX,"").trim();t[o]&&(n[r]=t[o])}})),n.join("")}(n[t],e)}function i(n,i=!1,l={}){const{hasError:u,placeholders:f,chop:d,helpers:p,handshake:h}=function(e){const{template:t,helpers:n={},handshake:a}=e,{TG_PRX:s,TG_SFX:c}=o,i=[],l="string"==typeof t?t.replace(/<!--[\s\S]*?-->/g,"").replace(/\s{2,}/g," "):t;let u=null;const f=r(o)(l);return"string"==typeof f?u=f:f.forEach(((e,t)=>{const r=RegExp(s+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?"+c,"g");if(e.includes(s)){const a=r.exec(e);i.push({index:t,data:(n=a[1],n||null),action:a[2]?a[2].split(",").map((e=>e.trim())):null})}var n})),i.forEach((e=>{e.action&&e.action.every((e=>"#"===e||"^^"===e||!(!e.startsWith("^")||"^^"===e)||(e.startsWith("?")&&(e=e.replace("?","")),e.startsWith("+")&&(e=e.replace("+","")),e.startsWith("[]")&&(e=e.replace("[]","")),e.startsWith(">")&&(e=e.replace(">","")),""===e||!!n[e]||(u=`Error: Missing helper: ${e}`,!1))))})),{hasError:u,placeholders:i,chop:f,helpers:n,handshake:a}}(n);if(u){function b(){return u}return i?[!1,b]:b}{let m=structuredClone(d);function y(r={},n={},...o){const i=[],u={};let d=s(r),b={...l,...n};if(r=e({data:r}),"null"===d)return m.join("");if("string"==typeof r)switch(r){case"raw":return m.join("");case"demo":if(!h)return"Error: No handshake data.";d=s(r=h);break;case"handshake":return h?structuredClone(h):"Error: No handshake data.";case"placeholders":return f.map((e=>m[e.index])).join(", ");default:return`Error: Wrong command "${r}". Available commands: raw, demo, handshake, placeholders.`}return"array"!==d&&(r=[r]),"null"===d?m.join(""):(r.forEach((r=>{f.forEach((n=>{const{index:o,data:i,action:l}=n,f=!l&&i,d=structuredClone(u),h={dependencies:b,memory:d};if(f){const e=r[i];switch(s(e)){case"function":return void(m[o]=e());case"primitive":return void(m[o]=e);case"array":return void("primitive"===s(e[0])&&(m[o]=e[0]));case"object":return void(e.text&&(m[o]=e.text))}}else{let{dataDeepLevel:n,nestedData:f}=a("@all"===i||null===i||"@root"===i?r:r[i],l),d=function*(e,r){let n=t({type:"LIFO"});for(let t=0;t<=r;t++)n.push(e[t]);for(;n&&!n.isEmpty();){let e=yield n.pull();e&&n.push(e)}}(function(e,t=10){let r={},n=[...e],a=0,o=0,s=0;n.forEach((e=>{"#"===e&&s++})),s<t&&console.error(`Error: Not enough level markers (#) for data with depth level ${t}. Found ${s} level markers in actions: ${e.join(", ")}`);do{r[o]=[],o++}while(o<=t);return n.every((e=>"#"===e?(a++,!(a>t)):e.startsWith("?")?(r[a].push({type:"route",name:e.replace("?",""),level:a}),!0):e.startsWith("^")&&"^^"!==e?(r[a].push({type:"save",name:e.replace("^",""),level:a}),!0):"^^"===e?(r[a].push({type:"overwrite",name:"none",level:a}),!0):e.startsWith("+")?(r[a].push({type:"extendedRender",name:e.replace("+",""),level:a}),!0):e.startsWith("[]")?(r[a].push({type:"mix",name:e.replace("[]",""),level:a}),!0):e.startsWith(">")?(r[a].push({type:"data",name:e.replace(">",""),level:a}),!0):(""===e||r[a].push({type:"render",name:e,level:a}),!0))),r}(l,n),n);for(let t of d){let{type:n,name:a,level:o}=t;(f[o]||[]).forEach(((t,i)=>{let l=s(t);switch(n){case"route":switch(l){case"array":t.forEach(((e,r)=>{if(null==e)return;const n=s(e),o=p[a]({data:e,...h});null!=o&&("object"===n?t[r].text=c(e,o,p,b):t[r]=c(e,o,p,b))}));break;case"object":t.text=c(t,a,p,b)}break;case"save":u[a]=structuredClone(t);break;case"overwrite":r=structuredClone(t);break;case"data":switch(l){case"array":t.forEach(((e,r)=>t[r]=e instanceof Function?p[a]({data:e(),...h}):p[a]({data:e,...h})));break;case"object":f[o]=[p[a]({data:t,...h})];break;case"function":f[o]=[p[a]({data:t(),...h})];break;case"primitive":f[o]=p[a]({data:t,...h})}break;case"render":const d="function"==typeof p[a];switch(l){case"array":d?t.forEach(((e,r)=>{if(null==e)return;const n=s(e),o=p[a]({data:e,...h});null==o&&(t[r]=null),"object"===n?e.text=o:t[r]=o})):t.forEach(((e,r)=>{if(null==e)return;const n=s(e),o=c(e,a,p,b);null==o?t[r]=null:"object"===n?e.text=o:t[r]=o}));break;case"function":f[o]=p[a]({data:t(),...h});break;case"primitive":f[o]=c(t,a,p,b);break;case"object":d?f[o][i].text=p[a]({data:t,...h}):t.text=c(t,a,p,b)}break;case"extendedRender":"function"==typeof p[a]&&f[0].forEach(((e,t)=>f[0][t]=p[a]({data:e,...h})));break;case"mix":if(""===a)switch(l){case"object":Object.keys(t).find((e=>e.includes("/")))?Object.entries(t).forEach((([e,t])=>f[o][e]=t.text)):f[o]=t.text;for(let y=o-1;y>=0;y--)f[y]=e({data:f[y],objectCallback:m});function m({value:e,breadcrumbs:t}){return f[o][t]?f[o][t]:e}break;case"array":t.forEach(((e,r)=>{if(r>0){let n=s(e);if(null==e)return;t[0]+="object"===n?`${e.text}`:`${e}`,t.toSpliced(r,1)}else{let r=s(e);if(t[0]="",null===r)return;t[0]="object"===r?`${e.text}`:`${e}`}})),t.length=1}else{let v=p[a]({data:t,...h}),g=s(v);switch(t.forEach(((e,r)=>t.splice(r,1))),t.length=0,g){case"primitive":t[0]=v;break;case"array":t.push(...v)}}}}))}if(f instanceof Array&&1===f.length&&f[0]instanceof Array&&(f=f[0]),null==f[0])return;let y=s(f[0]),v=f[0];switch(y){case"primitive":if(null==v)return;m[o]=v;break;case"object":if(null==v.text)return;m[o]=v.text;break;case"array":const e=s(v[0]);m[o]="object"===e?v.map((e=>e.text)).join(""):v.join("")}}})),i.push(m.join(""))})),"array"===d?i:o?o.reduce(((e,t)=>"function"!=typeof t?e:t(e,b)),i.join("")):i.join(""))}return i?[!0,y]:y}}const l={default:{}};const u={build:i,get:function(e){if(!(e instanceof Array))return function(){return'Error: Argument "location" is a string. Should be an array. E.g. ["templateName", "storageName"].'};const[t,r="default"]=e;return l[r]?l[r][t]?l[r][t]:function(){return`Error: Template "${t}" does not exist in storage "${r}".`}:function(){return`Error: Storage "${r}" does not exist.`}},add:function(e,t,...r){const[n,a="default"]=e;if(null==t)return void console.warn(`Warning: Template ${a}/${n} is not added to storage. The template is null.`);let o=t,s=!0;if(l[a]||(l[a]={}),"function"!=typeof t){let e=i(t,!0,...r);s=e[0],o=e[1]}s?l[a][n]=o:console.error(`Error: Template "${n}" looks broken and is not added to storage.`)},list:function(e=["default"]){return e.map((e=>l[e]?Object.keys(l[e]):[])).flat()},clear:function(){Object.keys(l).forEach((e=>{"default"!=e?delete l[e]:l.default={}}))},remove:function(e){const[t,r="default"]=e;return l[r]?l[r][t]?void delete l[r][t]:`Error: Template "${t}" does not exist in storage "${r}".`:`Error: Storage "${r}" does not exist.`}};module.exports=u;
|
package/dist/morph.esm.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"@peter.naydenov/walk";import t from"@peter.naydenov/stack";function r(e){return function t(r){const{TG_PRX:a,TG_SFX:o,TG_SIZE_P:s,TG_SIZE_S:
|
|
1
|
+
import e from"@peter.naydenov/walk";import t from"@peter.naydenov/stack";function r(e){return function t(r){const{TG_PRX:a,TG_SFX:o,TG_SIZE_P:s,TG_SIZE_S:c}=e;let i,l,u,f=[];if("string"!=typeof r)return n("notAString");if(0==r.length)return[];if(i=r.indexOf(a),0<i&&f.push(r.slice(0,i)),-1==i)return f.push(r),f;{if(u=r.indexOf(a,i+s),l=r.indexOf(o),-1==l)return n("missingClosing");if(l<i)return n("closedBeforeOpened");if(l+=c,-1!=u&&u<l)return n("newBeforeClosed");f.push(r.slice(i,l));let e=t(r.slice(l));return f.concat(e)}}}function n(e){switch(e){case"notAString":return"Error: Template is not a string.";case"missingClosing":return"Error: Placeholder with missing closing tag.";case"closedBeforeOpened":return"Error: Placeholder closing tag without starting one.";case"newBeforeClosed":return"Error: Nested placeholders. Close placeholder before open new one.";default:return"Error: Unknown template error."}}function a(t,r){const n=[];let a=0;if(t instanceof Function)return{dataDeepLevel:0,nestedData:[[t()]]};if(null==t)return{dataDeepLevel:0,nestedData:[null]};if("string"==typeof t)return{dataDeepLevel:0,nestedData:[[t]]};const o=structuredClone(t);if(!r.includes("#"))return n.push([o]),{dataDeepLevel:0,nestedData:n};return e({data:o,objectCallback:function({key:e,value:t,breadcrumbs:r}){return e===r?(n[0]=[t],t):(a=r.split("/").length-1,n[a]||(n[a]=[]),n[a].push(t),t)}}),{dataDeepLevel:a,nestedData:n}}var o={TG_PRX:"{{",TG_SFX:"}}",TG_SIZE_P:2,TG_SIZE_S:2};function s(e){return null==e?"null":"string"==typeof e||"number"==typeof e||"boolean"==typeof e?"primitive":"function"==typeof e?"function":e instanceof Array?"array":e instanceof Object?"object":void 0}function c(e,t,n,...a){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text),r instanceof Array&&(e[t]=r[0])}));const s="function"==typeof n[t];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),s?n[t](e,...a):function(e,t){if(null==t)return null;const n=r(o)(e),a=o;return n.forEach(((e,r)=>{if(e.includes(a.TG_PRX)){const o=e.replace(a.TG_PRX,"").replace(a.TG_SFX,"").trim();t[o]&&(n[r]=t[o])}})),n.join("")}(n[t],e)}function i(n,i=!1,l={}){const{hasError:u,placeholders:f,chop:d,helpers:p,handshake:h}=function(e){const{template:t,helpers:n={},handshake:a}=e,{TG_PRX:s,TG_SFX:c}=o,i=[],l="string"==typeof t?t.replace(/<!--[\s\S]*?-->/g,"").replace(/\s{2,}/g," "):t;let u=null;const f=r(o)(l);return"string"==typeof f?u=f:f.forEach(((e,t)=>{const r=RegExp(s+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?"+c,"g");if(e.includes(s)){const a=r.exec(e);i.push({index:t,data:(n=a[1],n||null),action:a[2]?a[2].split(",").map((e=>e.trim())):null})}var n})),i.forEach((e=>{e.action&&e.action.every((e=>"#"===e||"^^"===e||!(!e.startsWith("^")||"^^"===e)||(e.startsWith("?")&&(e=e.replace("?","")),e.startsWith("+")&&(e=e.replace("+","")),e.startsWith("[]")&&(e=e.replace("[]","")),e.startsWith(">")&&(e=e.replace(">","")),""===e||!!n[e]||(u=`Error: Missing helper: ${e}`,!1))))})),{hasError:u,placeholders:i,chop:f,helpers:n,handshake:a}}(n);if(u){function m(){return u}return i?[!1,m]:m}{let b=structuredClone(d);function y(r={},n={},...o){const i=[],u={};let d=s(r),m={...l,...n};if(r=e({data:r}),"null"===d)return b.join("");if("string"==typeof r)switch(r){case"raw":return b.join("");case"demo":if(!h)return"Error: No handshake data.";d=s(r=h);break;case"handshake":return h?structuredClone(h):"Error: No handshake data.";case"placeholders":return f.map((e=>b[e.index])).join(", ");default:return`Error: Wrong command "${r}". Available commands: raw, demo, handshake, placeholders.`}return"array"!==d&&(r=[r]),"null"===d?b.join(""):(r.forEach((r=>{f.forEach((n=>{const{index:o,data:i,action:l}=n,f=!l&&i,d=structuredClone(u),h={dependencies:m,memory:d};if(f){const e=r[i];switch(s(e)){case"function":return void(b[o]=e());case"primitive":return void(b[o]=e);case"array":return void("primitive"===s(e[0])&&(b[o]=e[0]));case"object":return void(e.text&&(b[o]=e.text))}}else{let{dataDeepLevel:n,nestedData:f}=a("@all"===i||null===i||"@root"===i?r:r[i],l),d=function*(e,r){let n=t({type:"LIFO"});for(let t=0;t<=r;t++)n.push(e[t]);for(;n&&!n.isEmpty();){let e=yield n.pull();e&&n.push(e)}}(function(e,t=10){let r={},n=[...e],a=0,o=0,s=0;n.forEach((e=>{"#"===e&&s++})),s<t&&console.error(`Error: Not enough level markers (#) for data with depth level ${t}. Found ${s} level markers in actions: ${e.join(", ")}`);do{r[o]=[],o++}while(o<=t);return n.every((e=>"#"===e?(a++,!(a>t)):e.startsWith("?")?(r[a].push({type:"route",name:e.replace("?",""),level:a}),!0):e.startsWith("^")&&"^^"!==e?(r[a].push({type:"save",name:e.replace("^",""),level:a}),!0):"^^"===e?(r[a].push({type:"overwrite",name:"none",level:a}),!0):e.startsWith("+")?(r[a].push({type:"extendedRender",name:e.replace("+",""),level:a}),!0):e.startsWith("[]")?(r[a].push({type:"mix",name:e.replace("[]",""),level:a}),!0):e.startsWith(">")?(r[a].push({type:"data",name:e.replace(">",""),level:a}),!0):(""===e||r[a].push({type:"render",name:e,level:a}),!0))),r}(l,n),n);for(let t of d){let{type:n,name:a,level:o}=t;(f[o]||[]).forEach(((t,i)=>{let l=s(t);switch(n){case"route":switch(l){case"array":t.forEach(((e,r)=>{if(null==e)return;const n=s(e),o=p[a]({data:e,...h});null!=o&&("object"===n?t[r].text=c(e,o,p,m):t[r]=c(e,o,p,m))}));break;case"object":t.text=c(t,a,p,m)}break;case"save":u[a]=structuredClone(t);break;case"overwrite":r=structuredClone(t);break;case"data":switch(l){case"array":t.forEach(((e,r)=>t[r]=e instanceof Function?p[a]({data:e(),...h}):p[a]({data:e,...h})));break;case"object":f[o]=[p[a]({data:t,...h})];break;case"function":f[o]=[p[a]({data:t(),...h})];break;case"primitive":f[o]=p[a]({data:t,...h})}break;case"render":const d="function"==typeof p[a];switch(l){case"array":d?t.forEach(((e,r)=>{if(null==e)return;const n=s(e),o=p[a]({data:e,...h});null==o&&(t[r]=null),"object"===n?e.text=o:t[r]=o})):t.forEach(((e,r)=>{if(null==e)return;const n=s(e),o=c(e,a,p,m);null==o?t[r]=null:"object"===n?e.text=o:t[r]=o}));break;case"function":f[o]=p[a]({data:t(),...h});break;case"primitive":f[o]=c(t,a,p,m);break;case"object":d?f[o][i].text=p[a]({data:t,...h}):t.text=c(t,a,p,m)}break;case"extendedRender":"function"==typeof p[a]&&f[0].forEach(((e,t)=>f[0][t]=p[a]({data:e,...h})));break;case"mix":if(""===a)switch(l){case"object":Object.keys(t).find((e=>e.includes("/")))?Object.entries(t).forEach((([e,t])=>f[o][e]=t.text)):f[o]=t.text;for(let y=o-1;y>=0;y--)f[y]=e({data:f[y],objectCallback:b});function b({value:e,breadcrumbs:t}){return f[o][t]?f[o][t]:e}break;case"array":t.forEach(((e,r)=>{if(r>0){let n=s(e);if(null==e)return;t[0]+="object"===n?`${e.text}`:`${e}`,t.toSpliced(r,1)}else{let r=s(e);if(t[0]="",null===r)return;t[0]="object"===r?`${e.text}`:`${e}`}})),t.length=1}else{let v=p[a]({data:t,...h}),g=s(v);switch(t.forEach(((e,r)=>t.splice(r,1))),t.length=0,g){case"primitive":t[0]=v;break;case"array":t.push(...v)}}}}))}if(f instanceof Array&&1===f.length&&f[0]instanceof Array&&(f=f[0]),null==f[0])return;let y=s(f[0]),v=f[0];switch(y){case"primitive":if(null==v)return;b[o]=v;break;case"object":if(null==v.text)return;b[o]=v.text;break;case"array":const e=s(v[0]);b[o]="object"===e?v.map((e=>e.text)).join(""):v.join("")}}})),i.push(b.join(""))})),"array"===d?i:o?o.reduce(((e,t)=>"function"!=typeof t?e:t(e,m)),i.join("")):i.join(""))}return i?[!0,y]:y}}const l={default:{}};const u={build:i,get:function(e){if(!(e instanceof Array))return function(){return'Error: Argument "location" is a string. Should be an array. E.g. ["templateName", "storageName"].'};const[t,r="default"]=e;return l[r]?l[r][t]?l[r][t]:function(){return`Error: Template "${t}" does not exist in storage "${r}".`}:function(){return`Error: Storage "${r}" does not exist.`}},add:function(e,t,...r){const[n,a="default"]=e;if(null==t)return void console.warn(`Warning: Template ${a}/${n} is not added to storage. The template is null.`);let o=t,s=!0;if(l[a]||(l[a]={}),"function"!=typeof t){let e=i(t,!0,...r);s=e[0],o=e[1]}s?l[a][n]=o:console.error(`Error: Template "${n}" looks broken and is not added to storage.`)},list:function(e=["default"]){return e.map((e=>l[e]?Object.keys(l[e]):[])).flat()},clear:function(){Object.keys(l).forEach((e=>{"default"!=e?delete l[e]:l.default={}}))},remove:function(e){const[t,r="default"]=e;return l[r]?l[r][t]?void delete l[r][t]:`Error: Template "${t}" does not exist in storage "${r}".`:`Error: Storage "${r}" does not exist.`}};export{u as default};
|
package/dist/morph.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@peter.naydenov/walk")):"function"==typeof define&&define.amd?define(["@peter.naydenov/walk"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).morph=t(e.walk)}(this,(function(e){"use strict";function t(e){return function t(n){const{TG_PRX:o,TG_SFX:a,TG_SIZE_P:l,TG_SIZE_S:i}=e;let s,c,u,f=[];if("string"!=typeof n)return r("notAString");if(0==n.length)return[];if(s=n.indexOf(o),0<s&&f.push(n.slice(0,s)),-1==s)return f.push(n),f;{if(u=n.indexOf(o,s+l),c=n.indexOf(a),-1==c)return r("missingClosing");if(c<s)return r("closedBeforeOpened");if(c+=i,-1!=u&&u<c)return r("newBeforeClosed");f.push(n.slice(s,c));let e=t(n.slice(c));return f.concat(e)}}}function r(e){switch(e){case"notAString":return"Error: Template is not a string.";case"missingClosing":return"Error: Placeholder with missing closing tag.";case"closedBeforeOpened":return"Error: Placeholder closing tag without starting one.";case"newBeforeClosed":return"Error: Nested placeholders. Close placeholder before open new one.";default:return"Error: Unknown template error."}}function n(t,r){const n=[];let o=0;if(t instanceof Function)return{dataDeepLevel:0,nestedData:[[t()]]};if(null==t)return{dataDeepLevel:0,nestedData:[null]};if("string"==typeof t)return{dataDeepLevel:0,nestedData:[[t]]};if(!r.includes("#"))return n.push([t]),{dataDeepLevel:0,nestedData:n};return e({data:t,objectCallback:function({key:e,value:t,breadcrumbs:r}){return e===r?(n[0]=[t],t):(o=r.split("/").length-1,n[o]||(n[o]=[]),n[o].push(t),t)}}),{dataDeepLevel:o,nestedData:n}}function*o(e,t){let r=function(e={}){let t=[],{type:r,limit:n,onLimit:o}=Object.assign({},{type:"FIFO",limit:!1,onLimit:"update"},e),a="LIFO"===r.toUpperCase(),l=!1;function i(e=1,r=0){let n=[];return r>0&&Array.from({length:r}).map((()=>t.pop())),1==e?t.pop():(Array.from({length:e}).map((()=>{let e=t.pop();null!=e&&n.push(e)})),n)}function s(e=1,r=0){let n=[],o=t.length-r;return e>1&&Array.from({length:e}).map((()=>{null!=t[o-1]&&n.push(t[o-1]),o--})),1==e?t[t.length-1]:n}function c(){}return c.prototype={pull:i,pullReverse:function(e=1,t=0){let r=i(e,t);return r instanceof Array?r.reverse():r},peek:s,peekReverse:function(e=1,t=0){const r=s(e,t);return r instanceof Array?r.reverse():r},getSize:()=>t.length,isEmpty:()=>0==t.length,reset:()=>(t=[],!0),debug:()=>[...t]},c.prototype.push=a?function(e){const r=e instanceof Array,a=r?e.length:1;let s=!1;if("full"!==o||!l){if(n&&r&&a>n&&(e=e.slice(0,-a+n)),n){const a=(r?e.length:1)+t.length;a>=n&&"full"===o&&(e=e.slice(0,-(a-n))),a>=n&&"update"===o&&(s=i(a-n))}return t=e instanceof Array?t.concat(e):t.concat([e]),l=!!n&&t.length===n,s||void 0}}:function(e){const r=e instanceof Array,a=r?e.length:1;let s=!1;if("full"!==o||!l){if(n&&r&&a>n&&(e=e.slice(a-n)),n){const a=(r?e.length:1)+t.length;a>=n&&"full"===o&&(e=e.slice(0,-(a-n))),a>=n&&"update"===o&&(s=i(a-n))}return t=r?e.reduce(((e,t)=>[t,...e]),t):[e].reduce(((e,t)=>[t,...e]),t),l=!!n&&t.length===n,s||void 0}},new c}({type:"LIFO"});for(let n=0;n<=t;n++)r.push(e[n]);for(;r&&!r.isEmpty();){let e=yield r.pull();e&&r.push(e)}}var a={TG_PRX:"{{",TG_SFX:"}}",TG_SIZE_P:2,TG_SIZE_S:2};function l(e){return null==e?"null":"string"==typeof e||"number"==typeof e||"boolean"==typeof e?"primitive":"function"==typeof e?"function":e instanceof Array?"array":e instanceof Object?"object":void 0}function i(e,r,n,...o){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text),r instanceof Array&&(e[t]=r[0])}));const l="function"==typeof n[r];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),l?n[r](e,...o):function(e,r){if(null==r)return null;const n=t(a)(e),o=a;return n.forEach(((e,t)=>{if(e.includes(o.TG_PRX)){const a=e.replace(o.TG_PRX,"").replace(o.TG_SFX,"").trim();r[a]&&(n[t]=r[a])}})),n.join("")}(n[r],e)}function s(r,s=!1,c={}){const{hasError:u,placeholders:f,chop:p,helpers:d,handshake:h}=function(e){const{template:r,helpers:n={},handshake:o}=e,{TG_PRX:l,TG_SFX:i}=a,s=[],c="string"==typeof r?r.replace(/<!--[\s\S]*?-->/g,"").replace(/\s{2,}/g," "):r;let u=null;const f=t(a)(c);return"string"==typeof f?u=f:f.forEach(((e,t)=>{const r=RegExp(l+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?"+i,"g");if(e.includes(l)){const o=r.exec(e);s.push({index:t,data:(n=o[1],n||null),action:o[2]?o[2].split(",").map((e=>e.trim())):null})}var n})),s.forEach((e=>{e.action&&e.action.every((e=>"#"===e||(e.startsWith("?")&&(e=e.replace("?","")),e.startsWith("+")&&(e=e.replace("+","")),e.startsWith("[]")&&(e=e.replace("[]","")),e.startsWith(">")&&(e=e.replace(">","")),""===e||!!n[e]||(u=`Error: Missing helper: ${e}`,!1))))})),{hasError:u,placeholders:s,chop:f,helpers:n,handshake:o}}(r);if(u){function y(){return u}return s?[!1,y]:y}{let g=structuredClone(p);function m(t={},r={},...a){const s=[];let u=l(t),p={...c,...r};if(t=e({data:t}),"null"===u)return g.join("");if("string"==typeof t)switch(t){case"raw":return g.join("");case"demo":if(!h)return"Error: No handshake data.";u=l(t=h);break;case"handshake":return h?structuredClone(h):"Error: No handshake data.";case"placeholders":return f.map((e=>g[e.index])).join(", ");default:return`Error: Wrong command "${t}". Available commands: raw, demo, handshake, placeholders.`}return"array"!==u&&(t=[t]),"null"===u?g.join(""):(t.forEach((t=>{f.forEach((r=>{const{index:a,data:s,action:c}=r;if(!c&&s){const e=t[s];switch(l(e)){case"function":return void(g[a]=e());case"primitive":return void(g[a]=e);case"array":return void("primitive"===l(e[0])&&(g[a]=e[0]));case"object":return void(e.text&&(g[a]=e.text))}}else{let{dataDeepLevel:r,nestedData:u}=n("@all"===s||null===s||"@root"===s?t:t[s],c),f=o(function(e,t=10){let r={},n=[...e],o=0,a=0,l=0;n.forEach((e=>{"#"===e&&l++})),l<t&&console.error(`Error: Not enough level markers (#) for data with depth level ${t}. Found ${l} level markers in actions: ${e.join(", ")}`);do{r[a]=[],a++}while(a<=t);return n.every((e=>"#"===e?(o++,!(o>t)):e.startsWith("?")?(r[o].push({type:"route",name:e.replace("?",""),level:o}),!0):e.startsWith("+")?(r[o].push({type:"extendedRender",name:e.replace("+",""),level:o}),!0):e.startsWith("[]")?(r[o].push({type:"mix",name:e.replace("[]",""),level:o}),!0):e.startsWith(">")?(r[o].push({type:"data",name:e.replace(">",""),level:o}),!0):(""===e||r[o].push({type:"render",name:e,level:o}),!0))),r}(c,r),r);for(let t of f){let{type:r,name:n,level:o}=t;(u[o]||[]).forEach((t=>{let a=l(t);switch(r){case"route":switch(a){case"array":t.forEach(((e,r)=>{if(null==e)return;const o=l(e),a=d[n](e);null!=a&&("object"===o?t[r].text=i(e,a,d,p):t[r]=i(e,a,d,p))}));break;case"object":t.text=i(t,n,d,p)}break;case"data":switch(a){case"array":t.forEach(((e,r)=>t[r]=e instanceof Function?d[n](e()):d[n](e)));break;case"object":u[o]=[d[n](t)];break;case"function":u[o]=[d[n](t())];break;case"primitive":u[o]=d[n](t)}break;case"render":const s="function"==typeof d[n];switch(a){case"array":s?t.forEach(((e,r)=>{if(null==e)return;const o=l(e),a=d[n](e,p);null==a&&(t[r]=null),"object"===o?e.text=a:t[r]=a})):t.forEach(((e,r)=>{if(null==e)return;const o=l(e),a=i(e,n,d,p);null==a?t[r]=null:"object"===o?e.text=a:t[r]=a}));break;case"function":u[o]=d[n](t(),p);break;case"primitive":u[o]=i(t,n,d,p);break;case"object":s?u[o][0].text=d[n](t,p):t.text=i(t,n,d,p)}break;case"extendedRender":"function"==typeof d[n]&&u[0].forEach(((e,t)=>u[0][t]=d[n](e)));break;case"mix":if(""===n)switch(a){case"object":Object.keys(t).find((e=>e.includes("/")))?Object.entries(t).forEach((([e,t])=>u[o][e]=t.text)):u[o]=t.text;for(let f=o-1;f>=0;f--)u[f]=e({data:u[f],objectCallback:c});function c({value:e,breadcrumbs:t}){return u[o][t]?u[o][t]:e}break;case"array":t.forEach(((e,r)=>{if(r>0){let n=l(e);if(null==e)return;t[0]+="object"===n?`${e.text}`:`${e}`,t.toSpliced(r,1)}else{let r=l(e);if(t[0]="",null===r)return;t[0]="object"===r?`${e.text}`:`${e}`}})),t.length=1}else{let h=d[n](t),y=l(h);switch(t.forEach(((e,r)=>t.splice(r,1))),t.length=0,y){case"primitive":t[0]=h;break;case"array":t.push(...h)}}}}))}if(u instanceof Array&&1===u.length&&u[0]instanceof Array&&(u=u[0]),null==u[0])return;let h=l(u[0]),y=u[0];switch(h){case"primitive":if(null==y)return;g[a]=y;break;case"object":if(null==y.text)return;g[a]=y.text;break;case"array":const e=l(y[0]);g[a]="object"===e?y.map((e=>e.text)).join(""):y.join("")}}})),s.push(g.join(""))})),"array"===u?s:a?a.reduce(((e,t)=>"function"!=typeof t?e:t(e,p)),s.join("")):s.join(""))}return s?[!0,m]:m}}const c={default:{}};return{build:s,get:function(e){if(!(e instanceof Array))return function(){return'Error: Argument "location" is a string. Should be an array. E.g. ["templateName", "storageName"].'};const[t,r="default"]=e;return c[r]?c[r][t]?c[r][t]:function(){return`Error: Template "${t}" does not exist in storage "${r}".`}:function(){return`Error: Storage "${r}" does not exist.`}},add:function(e,t,...r){const[n,o="default"]=e;if(null==t)return void console.warn(`Warning: Template ${o}/${n} is not added to storage. The template is null.`);let a=t,l=!0;if(c[o]||(c[o]={}),"function"!=typeof t){let e=s(t,!0,...r);l=e[0],a=e[1]}l?c[o][n]=a:console.error(`Error: Template "${n}" looks broken and is not added to storage.`)},list:function(e=["default"]){return e.map((e=>c[e]?Object.keys(c[e]):[])).flat()},clear:function(){Object.keys(c).forEach((e=>{"default"!=e?delete c[e]:c.default={}}))},remove:function(e){const[t,r="default"]=e;return c[r]?c[r][t]?void delete c[r][t]:`Error: Template "${t}" does not exist in storage "${r}".`:`Error: Storage "${r}" does not exist.`}}}));
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@peter.naydenov/walk")):"function"==typeof define&&define.amd?define(["@peter.naydenov/walk"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).morph=t(e.walk)}(this,(function(e){"use strict";function t(e){return function t(n){const{TG_PRX:a,TG_SFX:o,TG_SIZE_P:l,TG_SIZE_S:s}=e;let i,c,u,f=[];if("string"!=typeof n)return r("notAString");if(0==n.length)return[];if(i=n.indexOf(a),0<i&&f.push(n.slice(0,i)),-1==i)return f.push(n),f;{if(u=n.indexOf(a,i+l),c=n.indexOf(o),-1==c)return r("missingClosing");if(c<i)return r("closedBeforeOpened");if(c+=s,-1!=u&&u<c)return r("newBeforeClosed");f.push(n.slice(i,c));let e=t(n.slice(c));return f.concat(e)}}}function r(e){switch(e){case"notAString":return"Error: Template is not a string.";case"missingClosing":return"Error: Placeholder with missing closing tag.";case"closedBeforeOpened":return"Error: Placeholder closing tag without starting one.";case"newBeforeClosed":return"Error: Nested placeholders. Close placeholder before open new one.";default:return"Error: Unknown template error."}}function n(t,r){const n=[];let a=0;if(t instanceof Function)return{dataDeepLevel:0,nestedData:[[t()]]};if(null==t)return{dataDeepLevel:0,nestedData:[null]};if("string"==typeof t)return{dataDeepLevel:0,nestedData:[[t]]};const o=structuredClone(t);if(!r.includes("#"))return n.push([o]),{dataDeepLevel:0,nestedData:n};return e({data:o,objectCallback:function({key:e,value:t,breadcrumbs:r}){return e===r?(n[0]=[t],t):(a=r.split("/").length-1,n[a]||(n[a]=[]),n[a].push(t),t)}}),{dataDeepLevel:a,nestedData:n}}function*a(e,t){let r=function(e={}){let t=[],{type:r,limit:n,onLimit:a}=Object.assign({},{type:"FIFO",limit:!1,onLimit:"update"},e),o="LIFO"===r.toUpperCase(),l=!1;function s(e=1,r=0){let n=[];return r>0&&Array.from({length:r}).map((()=>t.pop())),1==e?t.pop():(Array.from({length:e}).map((()=>{let e=t.pop();null!=e&&n.push(e)})),n)}function i(e=1,r=0){let n=[],a=t.length-r;return e>1&&Array.from({length:e}).map((()=>{null!=t[a-1]&&n.push(t[a-1]),a--})),1==e?t[t.length-1]:n}function c(){}return c.prototype={pull:s,pullReverse:function(e=1,t=0){let r=s(e,t);return r instanceof Array?r.reverse():r},peek:i,peekReverse:function(e=1,t=0){const r=i(e,t);return r instanceof Array?r.reverse():r},getSize:()=>t.length,isEmpty:()=>0==t.length,reset:()=>(t=[],!0),debug:()=>[...t]},c.prototype.push=o?function(e){const r=e instanceof Array,o=r?e.length:1;let i=!1;if("full"!==a||!l){if(n&&r&&o>n&&(e=e.slice(0,-o+n)),n){const o=(r?e.length:1)+t.length;o>=n&&"full"===a&&(e=e.slice(0,-(o-n))),o>=n&&"update"===a&&(i=s(o-n))}return t=e instanceof Array?t.concat(e):t.concat([e]),l=!!n&&t.length===n,i||void 0}}:function(e){const r=e instanceof Array,o=r?e.length:1;let i=!1;if("full"!==a||!l){if(n&&r&&o>n&&(e=e.slice(o-n)),n){const o=(r?e.length:1)+t.length;o>=n&&"full"===a&&(e=e.slice(0,-(o-n))),o>=n&&"update"===a&&(i=s(o-n))}return t=r?e.reduce(((e,t)=>[t,...e]),t):[e].reduce(((e,t)=>[t,...e]),t),l=!!n&&t.length===n,i||void 0}},new c}({type:"LIFO"});for(let n=0;n<=t;n++)r.push(e[n]);for(;r&&!r.isEmpty();){let e=yield r.pull();e&&r.push(e)}}var o={TG_PRX:"{{",TG_SFX:"}}",TG_SIZE_P:2,TG_SIZE_S:2};function l(e){return null==e?"null":"string"==typeof e||"number"==typeof e||"boolean"==typeof e?"primitive":"function"==typeof e?"function":e instanceof Array?"array":e instanceof Object?"object":void 0}function s(e,r,n,...a){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text),r instanceof Array&&(e[t]=r[0])}));const l="function"==typeof n[r];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),l?n[r](e,...a):function(e,r){if(null==r)return null;const n=t(o)(e),a=o;return n.forEach(((e,t)=>{if(e.includes(a.TG_PRX)){const o=e.replace(a.TG_PRX,"").replace(a.TG_SFX,"").trim();r[o]&&(n[t]=r[o])}})),n.join("")}(n[r],e)}function i(r,i=!1,c={}){const{hasError:u,placeholders:f,chop:d,helpers:p,handshake:h}=function(e){const{template:r,helpers:n={},handshake:a}=e,{TG_PRX:l,TG_SFX:s}=o,i=[],c="string"==typeof r?r.replace(/<!--[\s\S]*?-->/g,"").replace(/\s{2,}/g," "):r;let u=null;const f=t(o)(c);return"string"==typeof f?u=f:f.forEach(((e,t)=>{const r=RegExp(l+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?"+s,"g");if(e.includes(l)){const a=r.exec(e);i.push({index:t,data:(n=a[1],n||null),action:a[2]?a[2].split(",").map((e=>e.trim())):null})}var n})),i.forEach((e=>{e.action&&e.action.every((e=>"#"===e||"^^"===e||!(!e.startsWith("^")||"^^"===e)||(e.startsWith("?")&&(e=e.replace("?","")),e.startsWith("+")&&(e=e.replace("+","")),e.startsWith("[]")&&(e=e.replace("[]","")),e.startsWith(">")&&(e=e.replace(">","")),""===e||!!n[e]||(u=`Error: Missing helper: ${e}`,!1))))})),{hasError:u,placeholders:i,chop:f,helpers:n,handshake:a}}(r);if(u){function m(){return u}return i?[!1,m]:m}{let y=structuredClone(d);function g(t={},r={},...o){const i=[],u={};let d=l(t),m={...c,...r};if(t=e({data:t}),"null"===d)return y.join("");if("string"==typeof t)switch(t){case"raw":return y.join("");case"demo":if(!h)return"Error: No handshake data.";d=l(t=h);break;case"handshake":return h?structuredClone(h):"Error: No handshake data.";case"placeholders":return f.map((e=>y[e.index])).join(", ");default:return`Error: Wrong command "${t}". Available commands: raw, demo, handshake, placeholders.`}return"array"!==d&&(t=[t]),"null"===d?y.join(""):(t.forEach((t=>{f.forEach((r=>{const{index:o,data:i,action:c}=r,f=!c&&i,d=structuredClone(u),h={dependencies:m,memory:d};if(f){const e=t[i];switch(l(e)){case"function":return void(y[o]=e());case"primitive":return void(y[o]=e);case"array":return void("primitive"===l(e[0])&&(y[o]=e[0]));case"object":return void(e.text&&(y[o]=e.text))}}else{let{dataDeepLevel:r,nestedData:f}=n("@all"===i||null===i||"@root"===i?t:t[i],c),d=a(function(e,t=10){let r={},n=[...e],a=0,o=0,l=0;n.forEach((e=>{"#"===e&&l++})),l<t&&console.error(`Error: Not enough level markers (#) for data with depth level ${t}. Found ${l} level markers in actions: ${e.join(", ")}`);do{r[o]=[],o++}while(o<=t);return n.every((e=>"#"===e?(a++,!(a>t)):e.startsWith("?")?(r[a].push({type:"route",name:e.replace("?",""),level:a}),!0):e.startsWith("^")&&"^^"!==e?(r[a].push({type:"save",name:e.replace("^",""),level:a}),!0):"^^"===e?(r[a].push({type:"overwrite",name:"none",level:a}),!0):e.startsWith("+")?(r[a].push({type:"extendedRender",name:e.replace("+",""),level:a}),!0):e.startsWith("[]")?(r[a].push({type:"mix",name:e.replace("[]",""),level:a}),!0):e.startsWith(">")?(r[a].push({type:"data",name:e.replace(">",""),level:a}),!0):(""===e||r[a].push({type:"render",name:e,level:a}),!0))),r}(c,r),r);for(let r of d){let{type:n,name:a,level:o}=r;(f[o]||[]).forEach(((r,i)=>{let c=l(r);switch(n){case"route":switch(c){case"array":r.forEach(((e,t)=>{if(null==e)return;const n=l(e),o=p[a]({data:e,...h});null!=o&&("object"===n?r[t].text=s(e,o,p,m):r[t]=s(e,o,p,m))}));break;case"object":r.text=s(r,a,p,m)}break;case"save":u[a]=structuredClone(r);break;case"overwrite":t=structuredClone(r);break;case"data":switch(c){case"array":r.forEach(((e,t)=>r[t]=e instanceof Function?p[a]({data:e(),...h}):p[a]({data:e,...h})));break;case"object":f[o]=[p[a]({data:r,...h})];break;case"function":f[o]=[p[a]({data:r(),...h})];break;case"primitive":f[o]=p[a]({data:r,...h})}break;case"render":const d="function"==typeof p[a];switch(c){case"array":d?r.forEach(((e,t)=>{if(null==e)return;const n=l(e),o=p[a]({data:e,...h});null==o&&(r[t]=null),"object"===n?e.text=o:r[t]=o})):r.forEach(((e,t)=>{if(null==e)return;const n=l(e),o=s(e,a,p,m);null==o?r[t]=null:"object"===n?e.text=o:r[t]=o}));break;case"function":f[o]=p[a]({data:r(),...h});break;case"primitive":f[o]=s(r,a,p,m);break;case"object":d?f[o][i].text=p[a]({data:r,...h}):r.text=s(r,a,p,m)}break;case"extendedRender":"function"==typeof p[a]&&f[0].forEach(((e,t)=>f[0][t]=p[a]({data:e,...h})));break;case"mix":if(""===a)switch(c){case"object":Object.keys(r).find((e=>e.includes("/")))?Object.entries(r).forEach((([e,t])=>f[o][e]=t.text)):f[o]=r.text;for(let g=o-1;g>=0;g--)f[g]=e({data:f[g],objectCallback:y});function y({value:e,breadcrumbs:t}){return f[o][t]?f[o][t]:e}break;case"array":r.forEach(((e,t)=>{if(t>0){let n=l(e);if(null==e)return;r[0]+="object"===n?`${e.text}`:`${e}`,r.toSpliced(t,1)}else{let t=l(e);if(r[0]="",null===t)return;r[0]="object"===t?`${e.text}`:`${e}`}})),r.length=1}else{let b=p[a]({data:r,...h}),v=l(b);switch(r.forEach(((e,t)=>r.splice(t,1))),r.length=0,v){case"primitive":r[0]=b;break;case"array":r.push(...b)}}}}))}if(f instanceof Array&&1===f.length&&f[0]instanceof Array&&(f=f[0]),null==f[0])return;let g=l(f[0]),b=f[0];switch(g){case"primitive":if(null==b)return;y[o]=b;break;case"object":if(null==b.text)return;y[o]=b.text;break;case"array":const e=l(b[0]);y[o]="object"===e?b.map((e=>e.text)).join(""):b.join("")}}})),i.push(y.join(""))})),"array"===d?i:o?o.reduce(((e,t)=>"function"!=typeof t?e:t(e,m)),i.join("")):i.join(""))}return i?[!0,g]:g}}const c={default:{}};return{build:i,get:function(e){if(!(e instanceof Array))return function(){return'Error: Argument "location" is a string. Should be an array. E.g. ["templateName", "storageName"].'};const[t,r="default"]=e;return c[r]?c[r][t]?c[r][t]:function(){return`Error: Template "${t}" does not exist in storage "${r}".`}:function(){return`Error: Storage "${r}" does not exist.`}},add:function(e,t,...r){const[n,a="default"]=e;if(null==t)return void console.warn(`Warning: Template ${a}/${n} is not added to storage. The template is null.`);let o=t,l=!0;if(c[a]||(c[a]={}),"function"!=typeof t){let e=i(t,!0,...r);l=e[0],o=e[1]}l?c[a][n]=o:console.error(`Error: Template "${n}" looks broken and is not added to storage.`)},list:function(e=["default"]){return e.map((e=>c[e]?Object.keys(c[e]):[])).flat()},clear:function(){Object.keys(c).forEach((e=>{"default"!=e?delete c[e]:c.default={}}))},remove:function(e){const[t,r="default"]=e;return c[r]?c[r][t]?void delete c[r][t]:`Error: Template "${t}" does not exist in storage "${r}".`:`Error: Storage "${r}" does not exist.`}}}));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peter.naydenov/morph",
|
|
3
3
|
"description": "Template engine",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "2.0.1",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Peter Naydenov",
|
|
7
7
|
"main": "./src/main.js",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"c8": "^10.1.3",
|
|
34
34
|
"chai": "5.2.0",
|
|
35
35
|
"mocha": "11.1.0",
|
|
36
|
-
"rollup": "^4.
|
|
36
|
+
"rollup": "^4.37.0"
|
|
37
37
|
},
|
|
38
38
|
"repository": {
|
|
39
39
|
"type": "git",
|
|
@@ -2,22 +2,22 @@ import walk from '@peter.naydenov/walk'
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
function _defineData (
|
|
5
|
+
function _defineData ( dSource, action ) {
|
|
6
6
|
const nestedData = [];
|
|
7
7
|
let dataDeepLevel = 0;
|
|
8
8
|
|
|
9
|
-
if (
|
|
10
|
-
if (
|
|
11
|
-
if ( typeof
|
|
9
|
+
if ( dSource instanceof Function ) return { dataDeepLevel:0, nestedData:[[dSource()]] }
|
|
10
|
+
if ( dSource == null ) return { dataDeepLevel:0, nestedData:[ null ] }
|
|
11
|
+
if ( typeof dSource === 'string' ) return { dataDeepLevel:0, nestedData:[[dSource]] }
|
|
12
|
+
|
|
13
|
+
const d = structuredClone ( dSource )
|
|
12
14
|
|
|
13
15
|
// Note: Nest data only if action has '#'
|
|
14
16
|
if ( !action.includes('#') ) {
|
|
15
17
|
nestedData.push ( [d] )
|
|
16
18
|
return { dataDeepLevel:0, nestedData }
|
|
17
19
|
}
|
|
18
|
-
|
|
19
|
-
// nestedData[0] = [d]
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
function findObjects ({key, value, breadcrumbs}) {
|
|
22
22
|
if ( key === breadcrumbs ) {
|
|
23
23
|
nestedData[0] = [ value ]
|
|
@@ -52,13 +52,15 @@ function _readTemplate ( tpl ) {
|
|
|
52
52
|
placeholders.forEach ( holder => {
|
|
53
53
|
if ( !holder.action ) return
|
|
54
54
|
holder.action.every ( act => {
|
|
55
|
-
if ( act === '#'
|
|
55
|
+
if ( act === '#' ) return true
|
|
56
|
+
if ( act === '^^' ) return true
|
|
57
|
+
if ( act.startsWith('^') && act !== '^^' ) return true
|
|
56
58
|
if ( act.startsWith ( '?' )) act = act.replace ( '?', '' )
|
|
57
59
|
if ( act.startsWith ( '+' )) act = act.replace ( '+', '' )
|
|
58
60
|
if ( act.startsWith ( '[]' )) act = act.replace ( '[]', '' )
|
|
59
61
|
if ( act.startsWith ( '>' )) act = act.replace ( '>', '' )
|
|
60
|
-
if ( act === '' )
|
|
61
|
-
if ( helpers[act] )
|
|
62
|
+
if ( act === '' ) return true
|
|
63
|
+
if ( helpers[act] ) return true
|
|
62
64
|
else {
|
|
63
65
|
hasError = `Error: Missing helper: ${act}`
|
|
64
66
|
return false
|
|
@@ -31,6 +31,22 @@ function _setupActions ( actions, dataDeepLevel=10 ) {
|
|
|
31
31
|
})
|
|
32
32
|
return true
|
|
33
33
|
}
|
|
34
|
+
if ( act.startsWith ('^') && act !== '^^' ) {
|
|
35
|
+
actSetup[actLevel].push ({
|
|
36
|
+
type: 'save'
|
|
37
|
+
, name: act.replace ( '^', '' )
|
|
38
|
+
, level: actLevel
|
|
39
|
+
})
|
|
40
|
+
return true
|
|
41
|
+
}
|
|
42
|
+
if ( act === '^^') {
|
|
43
|
+
actSetup[actLevel].push ({
|
|
44
|
+
type: 'overwrite'
|
|
45
|
+
, name : 'none'
|
|
46
|
+
, level: actLevel
|
|
47
|
+
})
|
|
48
|
+
return true
|
|
49
|
+
}
|
|
34
50
|
if ( act.startsWith ( '+' ) ) { // it's a extended render action
|
|
35
51
|
actSetup[actLevel].push ({
|
|
36
52
|
type: 'extendedRender'
|
package/src/methods/build.js
CHANGED
|
@@ -60,9 +60,10 @@ function build ( tpl, extra=false, buildDependencies={} ) {
|
|
|
60
60
|
*/
|
|
61
61
|
function success ( d={}, dependencies={}, ...args ) {
|
|
62
62
|
const endData = [];
|
|
63
|
+
const memory = {};
|
|
63
64
|
let topLevelType = _defineDataType ( d );
|
|
64
65
|
let deps = { ...buildDependencies, ...dependencies }
|
|
65
|
-
d = walk ({data:d})
|
|
66
|
+
d = walk ({data:d}) // Creates copy of data to avoid mutation of the original
|
|
66
67
|
|
|
67
68
|
if ( topLevelType === 'null' ) return cuts.join ( '' )
|
|
68
69
|
// Commands : raw, demo, handshake, placeholders
|
|
@@ -94,7 +95,9 @@ function build ( tpl, extra=false, buildDependencies={} ) {
|
|
|
94
95
|
placeholders.forEach ( holder => { // Placeholders
|
|
95
96
|
const
|
|
96
97
|
{ index, data, action } = holder // index - placeholder index, data - key of data, action - list of operations
|
|
97
|
-
, dataOnly
|
|
98
|
+
, dataOnly = !action && data
|
|
99
|
+
, mem = structuredClone ( memory )
|
|
100
|
+
, extendArguments = { dependencies: deps, memory:mem }
|
|
98
101
|
;
|
|
99
102
|
|
|
100
103
|
if ( dataOnly ) {
|
|
@@ -129,8 +132,8 @@ function build ( tpl, extra=false, buildDependencies={} ) {
|
|
|
129
132
|
, levelData = nestedData[level] || []
|
|
130
133
|
;
|
|
131
134
|
|
|
132
|
-
levelData.forEach ( theData => {
|
|
133
|
-
let dataType = _defineDataType ( theData )
|
|
135
|
+
levelData.forEach ( (theData, iData ) => {
|
|
136
|
+
let dataType = _defineDataType ( theData )
|
|
134
137
|
|
|
135
138
|
switch ( type ) { // Action type 'route','data', 'render', or mix -> different operations
|
|
136
139
|
case 'route':
|
|
@@ -139,7 +142,7 @@ function build ( tpl, extra=false, buildDependencies={} ) {
|
|
|
139
142
|
theData.forEach ( (d,i) => {
|
|
140
143
|
if ( d == null ) return
|
|
141
144
|
const dType = _defineDataType ( d )
|
|
142
|
-
const routeName = helpers[name]( d );
|
|
145
|
+
const routeName = helpers[name]( {data:d, ...extendArguments});
|
|
143
146
|
if ( routeName == null ) return
|
|
144
147
|
if ( dType === 'object' ) theData[i]['text'] = render ( d, routeName, helpers, deps )
|
|
145
148
|
else theData[i] = render ( d, routeName, helpers, deps )
|
|
@@ -149,33 +152,38 @@ function build ( tpl, extra=false, buildDependencies={} ) {
|
|
|
149
152
|
theData['text'] = render ( theData, name, helpers, deps )
|
|
150
153
|
break
|
|
151
154
|
}
|
|
152
|
-
break
|
|
153
|
-
case '
|
|
155
|
+
break
|
|
156
|
+
case 'save' :
|
|
157
|
+
memory[name] = structuredClone ( theData )
|
|
158
|
+
break
|
|
159
|
+
case 'overwrite':
|
|
160
|
+
dElement = structuredClone ( theData )
|
|
161
|
+
break
|
|
162
|
+
case 'data':
|
|
154
163
|
switch ( dataType ) {
|
|
155
164
|
case 'array':
|
|
156
|
-
theData.forEach ( (d,i) => theData[i] = ( d instanceof Function ) ? helpers[name]( d() ) : helpers[name]( d ) )
|
|
165
|
+
theData.forEach ( (d,i) => theData[i] = ( d instanceof Function ) ? helpers[name]({ data:d(), ...extendArguments }) : helpers[name]( {data:d, ...extendArguments} ) )
|
|
157
166
|
break
|
|
158
167
|
case 'object':
|
|
159
|
-
nestedData[level] = [helpers[name]( theData )]
|
|
168
|
+
nestedData[level] = [helpers[name]( {data:theData,...extendArguments} )]
|
|
160
169
|
break
|
|
161
170
|
case 'function':
|
|
162
|
-
nestedData[level] = [helpers[name]( theData() )]
|
|
171
|
+
nestedData[level] = [helpers[name]( {data:theData(),...extendArguments} )]
|
|
163
172
|
break
|
|
164
173
|
case 'primitive':
|
|
165
|
-
nestedData[level] = helpers[name]( theData )
|
|
174
|
+
nestedData[level] = helpers[name]( {data:theData,...extendArguments} )
|
|
166
175
|
break
|
|
167
176
|
} // switch dataType
|
|
168
177
|
|
|
169
178
|
break
|
|
170
179
|
case 'render':
|
|
171
180
|
const isRenderFunction = typeof helpers[name] === 'function'; // Render could be a function and template.
|
|
172
|
-
|
|
173
181
|
switch ( dataType ) {
|
|
174
182
|
case 'array':
|
|
175
183
|
if ( isRenderFunction ) theData.forEach ( (d,i) => {
|
|
176
184
|
if ( d == null ) return
|
|
177
185
|
const dType = _defineDataType ( d );
|
|
178
|
-
const text = helpers[name]( d,
|
|
186
|
+
const text = helpers[name]( {data:d, ...extendArguments} );
|
|
179
187
|
|
|
180
188
|
if ( text == null ) theData[i] = null
|
|
181
189
|
if ( dType === 'object' ) d['text'] = text
|
|
@@ -183,8 +191,6 @@ function build ( tpl, extra=false, buildDependencies={} ) {
|
|
|
183
191
|
})
|
|
184
192
|
else theData.forEach ( (d,i) => {
|
|
185
193
|
if ( d == null ) return
|
|
186
|
-
|
|
187
|
-
|
|
188
194
|
const
|
|
189
195
|
dType = _defineDataType ( d )
|
|
190
196
|
, text = render ( d, name, helpers, deps )
|
|
@@ -195,13 +201,13 @@ function build ( tpl, extra=false, buildDependencies={} ) {
|
|
|
195
201
|
})
|
|
196
202
|
break
|
|
197
203
|
case 'function':
|
|
198
|
-
nestedData[level] = helpers[name]( theData(),
|
|
204
|
+
nestedData[level] = helpers[name]( {data:theData(), ...extendArguments} )
|
|
199
205
|
break
|
|
200
206
|
case 'primitive':
|
|
201
207
|
nestedData[level] = render ( theData, name, helpers, deps )
|
|
202
208
|
break
|
|
203
209
|
case 'object':
|
|
204
|
-
if ( isRenderFunction ) nestedData[level][
|
|
210
|
+
if ( isRenderFunction ) nestedData[level][iData]['text'] = helpers[name]({ data:theData, ...extendArguments} )
|
|
205
211
|
else {
|
|
206
212
|
theData [ 'text' ] = render ( theData, name, helpers, deps )
|
|
207
213
|
}
|
|
@@ -212,7 +218,7 @@ function build ( tpl, extra=false, buildDependencies={} ) {
|
|
|
212
218
|
// TODO: Test extendedRender
|
|
213
219
|
const isValid = typeof helpers[name] === 'function'; // Render could be a function and template.
|
|
214
220
|
if ( isValid ) {
|
|
215
|
-
nestedData[0].forEach ( (d,i) => nestedData[0][i] = helpers[name]( d ) )
|
|
221
|
+
nestedData[0].forEach ( (d,i) => nestedData[0][i] = helpers[name]( {data:d, ...extendArguments} ) )
|
|
216
222
|
}
|
|
217
223
|
else {
|
|
218
224
|
// TODO: Error...
|
|
@@ -256,7 +262,7 @@ function build ( tpl, extra=false, buildDependencies={} ) {
|
|
|
256
262
|
} // if name === ''
|
|
257
263
|
else {
|
|
258
264
|
let
|
|
259
|
-
val = helpers[name]( theData )
|
|
265
|
+
val = helpers[name]({ data:theData, ...extendArguments })
|
|
260
266
|
, valType = _defineDataType ( val )
|
|
261
267
|
;
|
|
262
268
|
|