@peter.naydenov/morph 0.0.2 → 0.0.3
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 +16 -2
- package/README.md +1 -1
- package/dist/morph.cjs +1 -1
- package/dist/morph.esm.mjs +1 -1
- package/dist/morph.umd.js +1 -1
- package/package.json +1 -1
- package/src/methods/_readTemplate.js +1 -1
- package/rollup.config.js +0 -42
- package/test/01-chop.test.js +0 -24
- package/test/02-build.test.js +0 -470
- package/test/03-storage.test.js +0 -78
- package/test/04-commands.js +0 -73
- package/test/05-data.test.js +0 -168
package/Changelog.md
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
## Release History
|
|
2
2
|
|
|
3
|
-
### 1.0.0 (2017-11-30)
|
|
4
3
|
|
|
4
|
+
|
|
5
|
+
### 0.0.3 (2017-12-02)
|
|
6
|
+
- [x] Fix: Breaks on missing helper;
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### 0.0.2 (2017-11-30)
|
|
11
|
+
- [x] Fix: Storage is not working;
|
|
12
|
+
- [ ] Bug: Breaks on missing helper;
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### 0.0.1 (2017-11-30)
|
|
5
17
|
- [x] Initial code;
|
|
6
18
|
- [x] Test package;
|
|
7
|
-
- [x] Documentation;
|
|
19
|
+
- [x] Documentation;
|
|
20
|
+
- [ ] Bug: Storage is not working;
|
|
21
|
+
- [ ] Bug: Breaks on missing helper;
|
package/README.md
CHANGED
|
@@ -36,7 +36,7 @@ npm install @peter.naydenov/morph
|
|
|
36
36
|
Morph can be used in browser and node.js.
|
|
37
37
|
```js
|
|
38
38
|
import morph from "@peter.naydenov/morph"
|
|
39
|
-
//
|
|
39
|
+
// Morph supports also require:
|
|
40
40
|
// const morph = require("@peter.naydenov/morph")
|
|
41
41
|
```
|
|
42
42
|
|
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: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){const r={};let n=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]};return e({data:t,objectCallback:function({key:e,value:t,breadcrumbs:a}){let o=!1;return n=a.split("/").length-1,isNaN(e)||(o=!0),r[n]||(r[n]=o?[]:{}),"root"===e?r[n]=t:o?r[n].push(t):r[n][a]=t,t}}),{dataDeepLevel:n,nestedData:r}}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){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text)}));const a="function"==typeof n[t];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),a?n[t](e):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){const{hasError:l,placeholders:u,chop:f,helpers:d,handshake:p}=function(e){const{template:t,helpers:n,handshake:a}=e,{TG_PRX:s,TG_SFX:c,TG_SIZE_P:i,TG_SIZE_S:l}=o,u=[];let f=null;const d=r(o)(t);return"string"==typeof d?f=d:d.forEach(((e,t)=>{const r=RegExp(s+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?"+c,"g");if(e.includes(s)){const a=r.exec(e);u.push({index:t,data:(n=a[1],n||null),action:a[2]?a[2].split(",").map((e=>e.trim())):null})}var n})),u.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]||(f=`Error: Missing helper: ${e}`,!1))))})),{hasError:f,placeholders:u,chop:d,helpers:n,handshake:a}}(n);if(l){function h(){return l}return i?[!1,h]:h}{let b=structuredClone(f);function m(r={},...n){const o=s(r),i=[];if("null"===o)return b.join("");if("string"==typeof r)switch(r){case"raw":return b.join("");case"demo":if(!p)return"Error: No handshake data.";r=p;break;case"handshake":return p?structuredClone(p):"Error: No handshake data.";case"placeholders":return u.map((e=>b[e.index])).join(", ");default:return`Error: Wrong command "${r}". Available commands: raw, demo, handshake, placeholders.`}return"array"!==o&&(r=[r]),r.forEach((r=>{u.forEach((n=>{const{index:o,data:i,action:l}=n;if(!l&&i){const u=r[i];switch(s(u)){case"function":return void(b[o]=u());case"primitive":return void(b[o]=u);case"array":return void("primitive"===s(u[0])&&(b[o]=u[0]));case"object":return void(u.text&&(b[o]=u.text))}}else{const{dataDeepLevel:f,nestedData:p}=a("@all"===i||null===i||"@root"===i?r:r[i]),h=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=0,a=[...e],o=0;do{r[o]=[],o++}while(o<=t);return a.every((e=>"#"===e?(n++,!(n>t)):e.startsWith("?")?(r[n].push({type:"route",name:e.replace("?",""),level:n}),!0):e.startsWith("+")?(r[n].push({type:"extendedRender",name:e.replace("+",""),level:n}),!0):e.startsWith("[]")?(r[n].push({type:"mix",name:e.replace("[]",""),level:n}),!0):e.startsWith(">")?(r[n].push({type:"data",name:e.replace(">",""),level:n}),!0):(""===e||r[n].push({type:"render",name:e,level:n}),!0))),r}(l,f),f);for(let E of h){let{type:v,name:k,level:j}=E,x=p[j],g=s(x);switch(v){case"route":switch(g){case"array":x.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=d[k](e);null!=n&&("object"===r?x[t].text=c(e,n,d):x[t]=c(e,n,d))}));break;case"object":x.text=c(x,routeName,d);break;case"primitive":p[j]=c(x,routeName,d)}break;case"data":switch(g){case"array":x.forEach(((e,t)=>x[t]=e instanceof Function?d[k](e()):d[k](e)));break;case"object":case"primitive":p[j]=d[k](x);break;case"function":p[j]=d[k](x())}break;case"render":const _="function"==typeof d[k];switch(g){case"array":_?x.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=d[k](e);null==n&&(x[t]=null),"object"===r?e.text=n:x[t]=n})):x.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=c(e,k,d);null==n&&(x[t]=null),"object"===r?e.text=n:x[t]=n}));break;case"primitive":p[j]=c(x,k,d);break;case"object":Object.keys(x).find((e=>e.includes("/")))?Object.entries(x).forEach((([e,t])=>t.text=c(t,k,d))):x.text=c(x,k,d)}break;case"extendedRender":"function"==typeof d[k]&&(p[j]=d[k](p[0]));break;case"mix":if(""===k)switch(g){case"object":Object.keys(x).find((e=>e.includes("/")))?Object.entries(x).forEach((([e,t])=>p[j][e]=t.text)):p[j]=x.text;for(let T=j-1;T>=0;T--)p[T]=e({data:p[T],objectCallback:w});function w({value:e,breadcrumbs:t}){return p[j][t]?p[j][t]:e}break;case"array":p[j]=x.map((e=>"object"===s(e)?e.text:e)).filter((e=>null!=e)).join("")}else p[j]=d[k](x)}}let m=s(p[0]),y=p[0];switch(m){case"primitive":if(null==y)return;b[o]=y;break;case"object":if(null==y.text)return;b[o]=y.text;break;case"array":b[o]=y.join("")}}})),i.push(b.join(""))})),"array"===o?i:n?n.reduce(((e,t)=>t(e)),i.join("")):i.join("")}return i?[!0,m]:m}}const l={default:{}};const u={build:i,get:function(e,t="default"){return l[t]?l[t][e]?l[t][e]:function(){return`Error: Template "${e}" does not exist in storage "${t}".`}:function(){return`Error: Storage "${t}" does not exist.`}},add:function(e,t,r="default"){let n=t,a=!0;l[r]||(l[r]={}),"function"!=typeof t&&([a,n]=i(t,!0)),a?l[r][e]=n:console.error(`Error: Template "${e}" looks broken and is not added to storage.`)},list:function(e="default"){return l[e]?Object.keys(l[e]):[]},clear:function(){Object.keys(l).forEach((e=>{"default"!=e?delete l[e]:l.default={}}))},remove:function(e,t="default"){return l[t]?l[t][e]?void delete l[t][e]:`Error: Template "${e}" does not exist in storage "${t}".`:`Error: Storage "${t}" does not exist.`}};module.exports=u;
|
|
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){const r={};let n=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]};return e({data:t,objectCallback:function({key:e,value:t,breadcrumbs:a}){let o=!1;return n=a.split("/").length-1,isNaN(e)||(o=!0),r[n]||(r[n]=o?[]:{}),"root"===e?r[n]=t:o?r[n].push(t):r[n][a]=t,t}}),{dataDeepLevel:n,nestedData:r}}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){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text)}));const a="function"==typeof n[t];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),a?n[t](e):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){const{hasError:l,placeholders:u,chop:f,helpers:d,handshake:p}=function(e){const{template:t,helpers:n={},handshake:a}=e,{TG_PRX:s,TG_SFX:c,TG_SIZE_P:i,TG_SIZE_S:l}=o,u=[];let f=null;const d=r(o)(t);return"string"==typeof d?f=d:d.forEach(((e,t)=>{const r=RegExp(s+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?"+c,"g");if(e.includes(s)){const a=r.exec(e);u.push({index:t,data:(n=a[1],n||null),action:a[2]?a[2].split(",").map((e=>e.trim())):null})}var n})),u.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]||(f=`Error: Missing helper: ${e}`,!1))))})),{hasError:f,placeholders:u,chop:d,helpers:n,handshake:a}}(n);if(l){function h(){return l}return i?[!1,h]:h}{let b=structuredClone(f);function m(r={},...n){const o=s(r),i=[];if("null"===o)return b.join("");if("string"==typeof r)switch(r){case"raw":return b.join("");case"demo":if(!p)return"Error: No handshake data.";r=p;break;case"handshake":return p?structuredClone(p):"Error: No handshake data.";case"placeholders":return u.map((e=>b[e.index])).join(", ");default:return`Error: Wrong command "${r}". Available commands: raw, demo, handshake, placeholders.`}return"array"!==o&&(r=[r]),r.forEach((r=>{u.forEach((n=>{const{index:o,data:i,action:l}=n;if(!l&&i){const u=r[i];switch(s(u)){case"function":return void(b[o]=u());case"primitive":return void(b[o]=u);case"array":return void("primitive"===s(u[0])&&(b[o]=u[0]));case"object":return void(u.text&&(b[o]=u.text))}}else{const{dataDeepLevel:f,nestedData:p}=a("@all"===i||null===i||"@root"===i?r:r[i]),h=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=0,a=[...e],o=0;do{r[o]=[],o++}while(o<=t);return a.every((e=>"#"===e?(n++,!(n>t)):e.startsWith("?")?(r[n].push({type:"route",name:e.replace("?",""),level:n}),!0):e.startsWith("+")?(r[n].push({type:"extendedRender",name:e.replace("+",""),level:n}),!0):e.startsWith("[]")?(r[n].push({type:"mix",name:e.replace("[]",""),level:n}),!0):e.startsWith(">")?(r[n].push({type:"data",name:e.replace(">",""),level:n}),!0):(""===e||r[n].push({type:"render",name:e,level:n}),!0))),r}(l,f),f);for(let E of h){let{type:v,name:k,level:j}=E,x=p[j],g=s(x);switch(v){case"route":switch(g){case"array":x.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=d[k](e);null!=n&&("object"===r?x[t].text=c(e,n,d):x[t]=c(e,n,d))}));break;case"object":x.text=c(x,routeName,d);break;case"primitive":p[j]=c(x,routeName,d)}break;case"data":switch(g){case"array":x.forEach(((e,t)=>x[t]=e instanceof Function?d[k](e()):d[k](e)));break;case"object":case"primitive":p[j]=d[k](x);break;case"function":p[j]=d[k](x())}break;case"render":const _="function"==typeof d[k];switch(g){case"array":_?x.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=d[k](e);null==n&&(x[t]=null),"object"===r?e.text=n:x[t]=n})):x.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=c(e,k,d);null==n&&(x[t]=null),"object"===r?e.text=n:x[t]=n}));break;case"primitive":p[j]=c(x,k,d);break;case"object":Object.keys(x).find((e=>e.includes("/")))?Object.entries(x).forEach((([e,t])=>t.text=c(t,k,d))):x.text=c(x,k,d)}break;case"extendedRender":"function"==typeof d[k]&&(p[j]=d[k](p[0]));break;case"mix":if(""===k)switch(g){case"object":Object.keys(x).find((e=>e.includes("/")))?Object.entries(x).forEach((([e,t])=>p[j][e]=t.text)):p[j]=x.text;for(let T=j-1;T>=0;T--)p[T]=e({data:p[T],objectCallback:w});function w({value:e,breadcrumbs:t}){return p[j][t]?p[j][t]:e}break;case"array":p[j]=x.map((e=>"object"===s(e)?e.text:e)).filter((e=>null!=e)).join("")}else p[j]=d[k](x)}}let m=s(p[0]),y=p[0];switch(m){case"primitive":if(null==y)return;b[o]=y;break;case"object":if(null==y.text)return;b[o]=y.text;break;case"array":b[o]=y.join("")}}})),i.push(b.join(""))})),"array"===o?i:n?n.reduce(((e,t)=>t(e)),i.join("")):i.join("")}return i?[!0,m]:m}}const l={default:{}};const u={build:i,get:function(e,t="default"){return l[t]?l[t][e]?l[t][e]:function(){return`Error: Template "${e}" does not exist in storage "${t}".`}:function(){return`Error: Storage "${t}" does not exist.`}},add:function(e,t,r="default"){let n=t,a=!0;l[r]||(l[r]={}),"function"!=typeof t&&([a,n]=i(t,!0)),a?l[r][e]=n:console.error(`Error: Template "${e}" looks broken and is not added to storage.`)},list:function(e="default"){return l[e]?Object.keys(l[e]):[]},clear:function(){Object.keys(l).forEach((e=>{"default"!=e?delete l[e]:l.default={}}))},remove:function(e,t="default"){return l[t]?l[t][e]?void delete l[t][e]:`Error: Template "${e}" does not exist in storage "${t}".`:`Error: Storage "${t}" 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: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){const r={};let n=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]};return e({data:t,objectCallback:function({key:e,value:t,breadcrumbs:a}){let o=!1;return n=a.split("/").length-1,isNaN(e)||(o=!0),r[n]||(r[n]=o?[]:{}),"root"===e?r[n]=t:o?r[n].push(t):r[n][a]=t,t}}),{dataDeepLevel:n,nestedData:r}}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){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text)}));const a="function"==typeof n[t];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),a?n[t](e):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){const{hasError:l,placeholders:u,chop:f,helpers:d,handshake:p}=function(e){const{template:t,helpers:n,handshake:a}=e,{TG_PRX:s,TG_SFX:c,TG_SIZE_P:i,TG_SIZE_S:l}=o,u=[];let f=null;const d=r(o)(t);return"string"==typeof d?f=d:d.forEach(((e,t)=>{const r=RegExp(s+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?"+c,"g");if(e.includes(s)){const a=r.exec(e);u.push({index:t,data:(n=a[1],n||null),action:a[2]?a[2].split(",").map((e=>e.trim())):null})}var n})),u.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]||(f=`Error: Missing helper: ${e}`,!1))))})),{hasError:f,placeholders:u,chop:d,helpers:n,handshake:a}}(n);if(l){function h(){return l}return i?[!1,h]:h}{let b=structuredClone(f);function m(r={},...n){const o=s(r),i=[];if("null"===o)return b.join("");if("string"==typeof r)switch(r){case"raw":return b.join("");case"demo":if(!p)return"Error: No handshake data.";r=p;break;case"handshake":return p?structuredClone(p):"Error: No handshake data.";case"placeholders":return u.map((e=>b[e.index])).join(", ");default:return`Error: Wrong command "${r}". Available commands: raw, demo, handshake, placeholders.`}return"array"!==o&&(r=[r]),r.forEach((r=>{u.forEach((n=>{const{index:o,data:i,action:l}=n;if(!l&&i){const u=r[i];switch(s(u)){case"function":return void(b[o]=u());case"primitive":return void(b[o]=u);case"array":return void("primitive"===s(u[0])&&(b[o]=u[0]));case"object":return void(u.text&&(b[o]=u.text))}}else{const{dataDeepLevel:f,nestedData:p}=a("@all"===i||null===i||"@root"===i?r:r[i]),h=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=0,a=[...e],o=0;do{r[o]=[],o++}while(o<=t);return a.every((e=>"#"===e?(n++,!(n>t)):e.startsWith("?")?(r[n].push({type:"route",name:e.replace("?",""),level:n}),!0):e.startsWith("+")?(r[n].push({type:"extendedRender",name:e.replace("+",""),level:n}),!0):e.startsWith("[]")?(r[n].push({type:"mix",name:e.replace("[]",""),level:n}),!0):e.startsWith(">")?(r[n].push({type:"data",name:e.replace(">",""),level:n}),!0):(""===e||r[n].push({type:"render",name:e,level:n}),!0))),r}(l,f),f);for(let E of h){let{type:v,name:k,level:j}=E,x=p[j],g=s(x);switch(v){case"route":switch(g){case"array":x.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=d[k](e);null!=n&&("object"===r?x[t].text=c(e,n,d):x[t]=c(e,n,d))}));break;case"object":x.text=c(x,routeName,d);break;case"primitive":p[j]=c(x,routeName,d)}break;case"data":switch(g){case"array":x.forEach(((e,t)=>x[t]=e instanceof Function?d[k](e()):d[k](e)));break;case"object":case"primitive":p[j]=d[k](x);break;case"function":p[j]=d[k](x())}break;case"render":const _="function"==typeof d[k];switch(g){case"array":_?x.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=d[k](e);null==n&&(x[t]=null),"object"===r?e.text=n:x[t]=n})):x.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=c(e,k,d);null==n&&(x[t]=null),"object"===r?e.text=n:x[t]=n}));break;case"primitive":p[j]=c(x,k,d);break;case"object":Object.keys(x).find((e=>e.includes("/")))?Object.entries(x).forEach((([e,t])=>t.text=c(t,k,d))):x.text=c(x,k,d)}break;case"extendedRender":"function"==typeof d[k]&&(p[j]=d[k](p[0]));break;case"mix":if(""===k)switch(g){case"object":Object.keys(x).find((e=>e.includes("/")))?Object.entries(x).forEach((([e,t])=>p[j][e]=t.text)):p[j]=x.text;for(let T=j-1;T>=0;T--)p[T]=e({data:p[T],objectCallback:w});function w({value:e,breadcrumbs:t}){return p[j][t]?p[j][t]:e}break;case"array":p[j]=x.map((e=>"object"===s(e)?e.text:e)).filter((e=>null!=e)).join("")}else p[j]=d[k](x)}}let m=s(p[0]),y=p[0];switch(m){case"primitive":if(null==y)return;b[o]=y;break;case"object":if(null==y.text)return;b[o]=y.text;break;case"array":b[o]=y.join("")}}})),i.push(b.join(""))})),"array"===o?i:n?n.reduce(((e,t)=>t(e)),i.join("")):i.join("")}return i?[!0,m]:m}}const l={default:{}};const u={build:i,get:function(e,t="default"){return l[t]?l[t][e]?l[t][e]:function(){return`Error: Template "${e}" does not exist in storage "${t}".`}:function(){return`Error: Storage "${t}" does not exist.`}},add:function(e,t,r="default"){let n=t,a=!0;l[r]||(l[r]={}),"function"!=typeof t&&([a,n]=i(t,!0)),a?l[r][e]=n:console.error(`Error: Template "${e}" looks broken and is not added to storage.`)},list:function(e="default"){return l[e]?Object.keys(l[e]):[]},clear:function(){Object.keys(l).forEach((e=>{"default"!=e?delete l[e]:l.default={}}))},remove:function(e,t="default"){return l[t]?l[t][e]?void delete l[t][e]:`Error: Template "${e}" does not exist in storage "${t}".`:`Error: Storage "${t}" does not exist.`}};export{u as default};
|
|
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){const r={};let n=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]};return e({data:t,objectCallback:function({key:e,value:t,breadcrumbs:a}){let o=!1;return n=a.split("/").length-1,isNaN(e)||(o=!0),r[n]||(r[n]=o?[]:{}),"root"===e?r[n]=t:o?r[n].push(t):r[n][a]=t,t}}),{dataDeepLevel:n,nestedData:r}}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){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text)}));const a="function"==typeof n[t];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),a?n[t](e):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){const{hasError:l,placeholders:u,chop:f,helpers:d,handshake:p}=function(e){const{template:t,helpers:n={},handshake:a}=e,{TG_PRX:s,TG_SFX:c,TG_SIZE_P:i,TG_SIZE_S:l}=o,u=[];let f=null;const d=r(o)(t);return"string"==typeof d?f=d:d.forEach(((e,t)=>{const r=RegExp(s+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?"+c,"g");if(e.includes(s)){const a=r.exec(e);u.push({index:t,data:(n=a[1],n||null),action:a[2]?a[2].split(",").map((e=>e.trim())):null})}var n})),u.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]||(f=`Error: Missing helper: ${e}`,!1))))})),{hasError:f,placeholders:u,chop:d,helpers:n,handshake:a}}(n);if(l){function h(){return l}return i?[!1,h]:h}{let b=structuredClone(f);function m(r={},...n){const o=s(r),i=[];if("null"===o)return b.join("");if("string"==typeof r)switch(r){case"raw":return b.join("");case"demo":if(!p)return"Error: No handshake data.";r=p;break;case"handshake":return p?structuredClone(p):"Error: No handshake data.";case"placeholders":return u.map((e=>b[e.index])).join(", ");default:return`Error: Wrong command "${r}". Available commands: raw, demo, handshake, placeholders.`}return"array"!==o&&(r=[r]),r.forEach((r=>{u.forEach((n=>{const{index:o,data:i,action:l}=n;if(!l&&i){const u=r[i];switch(s(u)){case"function":return void(b[o]=u());case"primitive":return void(b[o]=u);case"array":return void("primitive"===s(u[0])&&(b[o]=u[0]));case"object":return void(u.text&&(b[o]=u.text))}}else{const{dataDeepLevel:f,nestedData:p}=a("@all"===i||null===i||"@root"===i?r:r[i]),h=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=0,a=[...e],o=0;do{r[o]=[],o++}while(o<=t);return a.every((e=>"#"===e?(n++,!(n>t)):e.startsWith("?")?(r[n].push({type:"route",name:e.replace("?",""),level:n}),!0):e.startsWith("+")?(r[n].push({type:"extendedRender",name:e.replace("+",""),level:n}),!0):e.startsWith("[]")?(r[n].push({type:"mix",name:e.replace("[]",""),level:n}),!0):e.startsWith(">")?(r[n].push({type:"data",name:e.replace(">",""),level:n}),!0):(""===e||r[n].push({type:"render",name:e,level:n}),!0))),r}(l,f),f);for(let E of h){let{type:v,name:k,level:j}=E,x=p[j],g=s(x);switch(v){case"route":switch(g){case"array":x.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=d[k](e);null!=n&&("object"===r?x[t].text=c(e,n,d):x[t]=c(e,n,d))}));break;case"object":x.text=c(x,routeName,d);break;case"primitive":p[j]=c(x,routeName,d)}break;case"data":switch(g){case"array":x.forEach(((e,t)=>x[t]=e instanceof Function?d[k](e()):d[k](e)));break;case"object":case"primitive":p[j]=d[k](x);break;case"function":p[j]=d[k](x())}break;case"render":const _="function"==typeof d[k];switch(g){case"array":_?x.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=d[k](e);null==n&&(x[t]=null),"object"===r?e.text=n:x[t]=n})):x.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=c(e,k,d);null==n&&(x[t]=null),"object"===r?e.text=n:x[t]=n}));break;case"primitive":p[j]=c(x,k,d);break;case"object":Object.keys(x).find((e=>e.includes("/")))?Object.entries(x).forEach((([e,t])=>t.text=c(t,k,d))):x.text=c(x,k,d)}break;case"extendedRender":"function"==typeof d[k]&&(p[j]=d[k](p[0]));break;case"mix":if(""===k)switch(g){case"object":Object.keys(x).find((e=>e.includes("/")))?Object.entries(x).forEach((([e,t])=>p[j][e]=t.text)):p[j]=x.text;for(let T=j-1;T>=0;T--)p[T]=e({data:p[T],objectCallback:w});function w({value:e,breadcrumbs:t}){return p[j][t]?p[j][t]:e}break;case"array":p[j]=x.map((e=>"object"===s(e)?e.text:e)).filter((e=>null!=e)).join("")}else p[j]=d[k](x)}}let m=s(p[0]),y=p[0];switch(m){case"primitive":if(null==y)return;b[o]=y;break;case"object":if(null==y.text)return;b[o]=y.text;break;case"array":b[o]=y.join("")}}})),i.push(b.join(""))})),"array"===o?i:n?n.reduce(((e,t)=>t(e)),i.join("")):i.join("")}return i?[!0,m]:m}}const l={default:{}};const u={build:i,get:function(e,t="default"){return l[t]?l[t][e]?l[t][e]:function(){return`Error: Template "${e}" does not exist in storage "${t}".`}:function(){return`Error: Storage "${t}" does not exist.`}},add:function(e,t,r="default"){let n=t,a=!0;l[r]||(l[r]={}),"function"!=typeof t&&([a,n]=i(t,!0)),a?l[r][e]=n:console.error(`Error: Template "${e}" looks broken and is not added to storage.`)},list:function(e="default"){return l[e]?Object.keys(l[e]):[]},clear:function(){Object.keys(l).forEach((e=>{"default"!=e?delete l[e]:l.default={}}))},remove:function(e,t="default"){return l[t]?l[t][e]?void delete l[t][e]:`Error: Template "${e}" does not exist in storage "${t}".`:`Error: Storage "${t}" 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:i,TG_SIZE_S:l}=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+i),c=n.indexOf(a),-1==c)return r("missingClosing");if(c<s)return r("closedBeforeOpened");if(c+=l,-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){const r={};let n=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]};return e({data:t,objectCallback:function({key:e,value:t,breadcrumbs:o}){let a=!1;return n=o.split("/").length-1,isNaN(e)||(a=!0),r[n]||(r[n]=a?[]:{}),"root"===e?r[n]=t:a?r[n].push(t):r[n][o]=t,t}}),{dataDeepLevel:n,nestedData:r}}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(),i=!1;function l(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:l,pullReverse:function(e=1,t=0){let r=l(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||!i){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=l(a-n))}return t=e instanceof Array?t.concat(e):t.concat([e]),i=!!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||!i){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=l(a-n))}return t=r?e.reduce(((e,t)=>[t,...e]),t):[e].reduce(((e,t)=>[t,...e]),t),i=!!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 i(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 l(e,r,n){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text)}));const o="function"==typeof n[r];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),o?n[r](e):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){const{hasError:c,placeholders:u,chop:f,helpers:p,handshake:d}=function(e){const{template:r,helpers:n,handshake:o}=e,{TG_PRX:i,TG_SFX:l,TG_SIZE_P:s,TG_SIZE_S:c}=a,u=[];let f=null;const p=t(a)(r);return"string"==typeof p?f=p:p.forEach(((e,t)=>{const r=RegExp(i+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?"+l,"g");if(e.includes(i)){const o=r.exec(e);u.push({index:t,data:(n=o[1],n||null),action:o[2]?o[2].split(",").map((e=>e.trim())):null})}var n})),u.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]||(f=`Error: Missing helper: ${e}`,!1))))})),{hasError:f,placeholders:u,chop:p,helpers:n,handshake:o}}(r);if(c){function h(){return c}return s?[!1,h]:h}{let y=structuredClone(f);function m(t={},...r){const a=i(t),s=[];if("null"===a)return y.join("");if("string"==typeof t)switch(t){case"raw":return y.join("");case"demo":if(!d)return"Error: No handshake data.";t=d;break;case"handshake":return d?structuredClone(d):"Error: No handshake data.";case"placeholders":return u.map((e=>y[e.index])).join(", ");default:return`Error: Wrong command "${t}". Available commands: raw, demo, handshake, placeholders.`}return"array"!==a&&(t=[t]),t.forEach((t=>{u.forEach((r=>{const{index:a,data:s,action:c}=r;if(!c&&s){const u=t[s];switch(i(u)){case"function":return void(y[a]=u());case"primitive":return void(y[a]=u);case"array":return void("primitive"===i(u[0])&&(y[a]=u[0]));case"object":return void(u.text&&(y[a]=u.text))}}else{const{dataDeepLevel:f,nestedData:d}=n("@all"===s||null===s||"@root"===s?t:t[s]),h=o(function(e,t=10){let r={},n=0,o=[...e],a=0;do{r[a]=[],a++}while(a<=t);return o.every((e=>"#"===e?(n++,!(n>t)):e.startsWith("?")?(r[n].push({type:"route",name:e.replace("?",""),level:n}),!0):e.startsWith("+")?(r[n].push({type:"extendedRender",name:e.replace("+",""),level:n}),!0):e.startsWith("[]")?(r[n].push({type:"mix",name:e.replace("[]",""),level:n}),!0):e.startsWith(">")?(r[n].push({type:"data",name:e.replace(">",""),level:n}),!0):(""===e||r[n].push({type:"render",name:e,level:n}),!0))),r}(c,f),f);for(let g of h){let{type:v,name:E,level:k}=g,j=d[k],x=i(j);switch(v){case"route":switch(x){case"array":j.forEach(((e,t)=>{if(null==e)return;const r=i(e),n=p[E](e);null!=n&&("object"===r?j[t].text=l(e,n,p):j[t]=l(e,n,p))}));break;case"object":j.text=l(j,routeName,p);break;case"primitive":d[k]=l(j,routeName,p)}break;case"data":switch(x){case"array":j.forEach(((e,t)=>j[t]=e instanceof Function?p[E](e()):p[E](e)));break;case"object":case"primitive":d[k]=p[E](j);break;case"function":d[k]=p[E](j())}break;case"render":const w="function"==typeof p[E];switch(x){case"array":w?j.forEach(((e,t)=>{if(null==e)return;const r=i(e),n=p[E](e);null==n&&(j[t]=null),"object"===r?e.text=n:j[t]=n})):j.forEach(((e,t)=>{if(null==e)return;const r=i(e),n=l(e,E,p);null==n&&(j[t]=null),"object"===r?e.text=n:j[t]=n}));break;case"primitive":d[k]=l(j,E,p);break;case"object":Object.keys(j).find((e=>e.includes("/")))?Object.entries(j).forEach((([e,t])=>t.text=l(t,E,p))):j.text=l(j,E,p)}break;case"extendedRender":"function"==typeof p[E]&&(d[k]=p[E](d[0]));break;case"mix":if(""===E)switch(x){case"object":Object.keys(j).find((e=>e.includes("/")))?Object.entries(j).forEach((([e,t])=>d[k][e]=t.text)):d[k]=j.text;for(let _=k-1;_>=0;_--)d[_]=e({data:d[_],objectCallback:T});function T({value:e,breadcrumbs:t}){return d[k][t]?d[k][t]:e}break;case"array":d[k]=j.map((e=>"object"===i(e)?e.text:e)).filter((e=>null!=e)).join("")}else d[k]=p[E](j)}}let m=i(d[0]),b=d[0];switch(m){case"primitive":if(null==b)return;y[a]=b;break;case"object":if(null==b.text)return;y[a]=b.text;break;case"array":y[a]=b.join("")}}})),s.push(y.join(""))})),"array"===a?s:r?r.reduce(((e,t)=>t(e)),s.join("")):s.join("")}return s?[!0,m]:m}}const c={default:{}};return{build:s,get:function(e,t="default"){return c[t]?c[t][e]?c[t][e]:function(){return`Error: Template "${e}" does not exist in storage "${t}".`}:function(){return`Error: Storage "${t}" does not exist.`}},add:function(e,t,r="default"){let n=t,o=!0;c[r]||(c[r]={}),"function"!=typeof t&&([o,n]=s(t,!0)),o?c[r][e]=n:console.error(`Error: Template "${e}" looks broken and is not added to storage.`)},list:function(e="default"){return c[e]?Object.keys(c[e]):[]},clear:function(){Object.keys(c).forEach((e=>{"default"!=e?delete c[e]:c.default={}}))},remove:function(e,t="default"){return c[t]?c[t][e]?void delete c[t][e]:`Error: Template "${e}" does not exist in storage "${t}".`:`Error: Storage "${t}" 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:o,TG_SFX:a,TG_SIZE_P:i,TG_SIZE_S:l}=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+i),c=n.indexOf(a),-1==c)return r("missingClosing");if(c<s)return r("closedBeforeOpened");if(c+=l,-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){const r={};let n=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]};return e({data:t,objectCallback:function({key:e,value:t,breadcrumbs:o}){let a=!1;return n=o.split("/").length-1,isNaN(e)||(a=!0),r[n]||(r[n]=a?[]:{}),"root"===e?r[n]=t:a?r[n].push(t):r[n][o]=t,t}}),{dataDeepLevel:n,nestedData:r}}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(),i=!1;function l(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:l,pullReverse:function(e=1,t=0){let r=l(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||!i){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=l(a-n))}return t=e instanceof Array?t.concat(e):t.concat([e]),i=!!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||!i){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=l(a-n))}return t=r?e.reduce(((e,t)=>[t,...e]),t):[e].reduce(((e,t)=>[t,...e]),t),i=!!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 i(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 l(e,r,n){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text)}));const o="function"==typeof n[r];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),o?n[r](e):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){const{hasError:c,placeholders:u,chop:f,helpers:p,handshake:d}=function(e){const{template:r,helpers:n={},handshake:o}=e,{TG_PRX:i,TG_SFX:l,TG_SIZE_P:s,TG_SIZE_S:c}=a,u=[];let f=null;const p=t(a)(r);return"string"==typeof p?f=p:p.forEach(((e,t)=>{const r=RegExp(i+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?"+l,"g");if(e.includes(i)){const o=r.exec(e);u.push({index:t,data:(n=o[1],n||null),action:o[2]?o[2].split(",").map((e=>e.trim())):null})}var n})),u.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]||(f=`Error: Missing helper: ${e}`,!1))))})),{hasError:f,placeholders:u,chop:p,helpers:n,handshake:o}}(r);if(c){function h(){return c}return s?[!1,h]:h}{let y=structuredClone(f);function m(t={},...r){const a=i(t),s=[];if("null"===a)return y.join("");if("string"==typeof t)switch(t){case"raw":return y.join("");case"demo":if(!d)return"Error: No handshake data.";t=d;break;case"handshake":return d?structuredClone(d):"Error: No handshake data.";case"placeholders":return u.map((e=>y[e.index])).join(", ");default:return`Error: Wrong command "${t}". Available commands: raw, demo, handshake, placeholders.`}return"array"!==a&&(t=[t]),t.forEach((t=>{u.forEach((r=>{const{index:a,data:s,action:c}=r;if(!c&&s){const u=t[s];switch(i(u)){case"function":return void(y[a]=u());case"primitive":return void(y[a]=u);case"array":return void("primitive"===i(u[0])&&(y[a]=u[0]));case"object":return void(u.text&&(y[a]=u.text))}}else{const{dataDeepLevel:f,nestedData:d}=n("@all"===s||null===s||"@root"===s?t:t[s]),h=o(function(e,t=10){let r={},n=0,o=[...e],a=0;do{r[a]=[],a++}while(a<=t);return o.every((e=>"#"===e?(n++,!(n>t)):e.startsWith("?")?(r[n].push({type:"route",name:e.replace("?",""),level:n}),!0):e.startsWith("+")?(r[n].push({type:"extendedRender",name:e.replace("+",""),level:n}),!0):e.startsWith("[]")?(r[n].push({type:"mix",name:e.replace("[]",""),level:n}),!0):e.startsWith(">")?(r[n].push({type:"data",name:e.replace(">",""),level:n}),!0):(""===e||r[n].push({type:"render",name:e,level:n}),!0))),r}(c,f),f);for(let g of h){let{type:v,name:E,level:k}=g,j=d[k],x=i(j);switch(v){case"route":switch(x){case"array":j.forEach(((e,t)=>{if(null==e)return;const r=i(e),n=p[E](e);null!=n&&("object"===r?j[t].text=l(e,n,p):j[t]=l(e,n,p))}));break;case"object":j.text=l(j,routeName,p);break;case"primitive":d[k]=l(j,routeName,p)}break;case"data":switch(x){case"array":j.forEach(((e,t)=>j[t]=e instanceof Function?p[E](e()):p[E](e)));break;case"object":case"primitive":d[k]=p[E](j);break;case"function":d[k]=p[E](j())}break;case"render":const w="function"==typeof p[E];switch(x){case"array":w?j.forEach(((e,t)=>{if(null==e)return;const r=i(e),n=p[E](e);null==n&&(j[t]=null),"object"===r?e.text=n:j[t]=n})):j.forEach(((e,t)=>{if(null==e)return;const r=i(e),n=l(e,E,p);null==n&&(j[t]=null),"object"===r?e.text=n:j[t]=n}));break;case"primitive":d[k]=l(j,E,p);break;case"object":Object.keys(j).find((e=>e.includes("/")))?Object.entries(j).forEach((([e,t])=>t.text=l(t,E,p))):j.text=l(j,E,p)}break;case"extendedRender":"function"==typeof p[E]&&(d[k]=p[E](d[0]));break;case"mix":if(""===E)switch(x){case"object":Object.keys(j).find((e=>e.includes("/")))?Object.entries(j).forEach((([e,t])=>d[k][e]=t.text)):d[k]=j.text;for(let _=k-1;_>=0;_--)d[_]=e({data:d[_],objectCallback:T});function T({value:e,breadcrumbs:t}){return d[k][t]?d[k][t]:e}break;case"array":d[k]=j.map((e=>"object"===i(e)?e.text:e)).filter((e=>null!=e)).join("")}else d[k]=p[E](j)}}let m=i(d[0]),b=d[0];switch(m){case"primitive":if(null==b)return;y[a]=b;break;case"object":if(null==b.text)return;y[a]=b.text;break;case"array":y[a]=b.join("")}}})),s.push(y.join(""))})),"array"===a?s:r?r.reduce(((e,t)=>t(e)),s.join("")):s.join("")}return s?[!0,m]:m}}const c={default:{}};return{build:s,get:function(e,t="default"){return c[t]?c[t][e]?c[t][e]:function(){return`Error: Template "${e}" does not exist in storage "${t}".`}:function(){return`Error: Storage "${t}" does not exist.`}},add:function(e,t,r="default"){let n=t,o=!0;c[r]||(c[r]={}),"function"!=typeof t&&([o,n]=s(t,!0)),o?c[r][e]=n:console.error(`Error: Template "${e}" looks broken and is not added to storage.`)},list:function(e="default"){return c[e]?Object.keys(c[e]):[]},clear:function(){Object.keys(c).forEach((e=>{"default"!=e?delete c[e]:c.default={}}))},remove:function(e,t="default"){return c[t]?c[t][e]?void delete c[t][e]:`Error: Template "${e}" does not exist in storage "${t}".`:`Error: Storage "${t}" does not exist.`}}}));
|
package/package.json
CHANGED
package/rollup.config.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import resolve from '@rollup/plugin-node-resolve'
|
|
2
|
-
import commonjs from '@rollup/plugin-commonjs'
|
|
3
|
-
import terser from '@rollup/plugin-terser';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export default [
|
|
7
|
-
// browser-friendly UMD build
|
|
8
|
-
{
|
|
9
|
-
input: 'src/main.js',
|
|
10
|
-
output: {
|
|
11
|
-
name: 'morph',
|
|
12
|
-
file: 'dist/morph.umd.js',
|
|
13
|
-
format: 'umd',
|
|
14
|
-
globals: {
|
|
15
|
-
'@peter.naydenov/walk': 'walk'
|
|
16
|
-
, '@peter.naydenov/stack': 'stack'
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
external: ['@peter.naydenov/walk'],
|
|
20
|
-
plugins: [
|
|
21
|
-
resolve(), // so Rollup can find `ms`
|
|
22
|
-
commonjs() // so Rollup can convert `ms` to an ES module
|
|
23
|
-
, terser()
|
|
24
|
-
]
|
|
25
|
-
},
|
|
26
|
-
|
|
27
|
-
// CommonJS (for Node) and ES module (for bundlers) build.
|
|
28
|
-
// (We could have three entries in the configuration array
|
|
29
|
-
// instead of two, but it's quicker to generate multiple
|
|
30
|
-
// builds from a single configuration where possible, using
|
|
31
|
-
// an array for the `output` option, where we can specify
|
|
32
|
-
// `file` and `format` for each target)
|
|
33
|
-
{
|
|
34
|
-
input: 'src/main.js',
|
|
35
|
-
external: ['@peter.naydenov/walk', '@peter.naydenov/stack'],
|
|
36
|
-
output: [
|
|
37
|
-
{ file: 'dist/morph.cjs' , format: 'cjs' },
|
|
38
|
-
{ file: 'dist/morph.esm.mjs', format: 'es' }
|
|
39
|
-
],
|
|
40
|
-
plugins: [ terser() ]
|
|
41
|
-
}
|
|
42
|
-
];
|
package/test/01-chop.test.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import chopTemplates from'../src/methods/_chopTemplates.js'
|
|
2
|
-
import { expect } from 'chai';
|
|
3
|
-
|
|
4
|
-
describe ( 't-templates: chop', () => {
|
|
5
|
-
|
|
6
|
-
it ( 'Chop', () => {
|
|
7
|
-
const
|
|
8
|
-
str = 'Hello, {{name:ul,li,a}}! Say: {{shout}}, {{shout}}!'
|
|
9
|
-
, settings = {
|
|
10
|
-
TG_PRX: '{{'
|
|
11
|
-
, TG_SFX: '}}'
|
|
12
|
-
, TG_SIZE_P: 2
|
|
13
|
-
, TG_SIZE_S: 2
|
|
14
|
-
}
|
|
15
|
-
;
|
|
16
|
-
const tpl = chopTemplates ( settings);
|
|
17
|
-
const res = tpl(str);
|
|
18
|
-
|
|
19
|
-
expect(res).to.be.deep.equal ([
|
|
20
|
-
'Hello, ', '{{name:ul,li,a}}', '! Say: ', '{{shout}}', ', ', '{{shout}}', '!'
|
|
21
|
-
])
|
|
22
|
-
}) // it chop
|
|
23
|
-
|
|
24
|
-
}) // Describe
|
package/test/02-build.test.js
DELETED
|
@@ -1,470 +0,0 @@
|
|
|
1
|
-
import morphAPI from '../src/main.js'
|
|
2
|
-
import { expect } from 'chai'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
describe ( 'transformer: build', () => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
it ( 'Simple mustache like placeholders, no actions', () => {
|
|
10
|
-
// spaces inside placeholders are ignored
|
|
11
|
-
const myTpl = {
|
|
12
|
-
template: `Your name is {{ name }}. Your age is {{age}}.`
|
|
13
|
-
}
|
|
14
|
-
const templateFn = morphAPI.build ( myTpl )
|
|
15
|
-
const result = templateFn({
|
|
16
|
-
name: 'Peter'
|
|
17
|
-
, age: 50
|
|
18
|
-
})
|
|
19
|
-
expect ( result ).to.be.equal ( 'Your name is Peter. Your age is 50.' )
|
|
20
|
-
}) // it simple mustache like placeholders, no actions
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
it ( 'Mixing actions', () => {
|
|
24
|
-
// Mix action starts with '[]'. If no name after '[]' it will be like arr.join('').
|
|
25
|
-
// If name, it is the helper function used. In our case it is 'coma'.
|
|
26
|
-
const myTpl = {
|
|
27
|
-
template : `My friends are {{ names : []coma }}.`
|
|
28
|
-
, helpers : {
|
|
29
|
-
coma: (res) => res.join(', ')
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
const templateFn = morphAPI.build ( myTpl );
|
|
33
|
-
const result = templateFn({ names: ['Peter', 'Ivan'] });
|
|
34
|
-
expect ( result ).to.be.equal ( 'My friends are Peter, Ivan.' );
|
|
35
|
-
}) // it mixing actions
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
it ( 'No placeholders', () => {
|
|
40
|
-
const myTpl = {
|
|
41
|
-
template : `My name is Peter.`
|
|
42
|
-
}
|
|
43
|
-
const templateFn = morphAPI.build ( myTpl );
|
|
44
|
-
const result = templateFn(); // No data required
|
|
45
|
-
expect ( result ).to.be.equal ( 'My name is Peter.' );
|
|
46
|
-
}) // it No placeholders
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
it ( 'Data action to change the result', () => {
|
|
51
|
-
const myTpl = {
|
|
52
|
-
// placeholder will be fullfiled with data[job], but data function 'jobPossible' will filter the result
|
|
53
|
-
template : `My job is {{ job : >jobPossible }}.`
|
|
54
|
-
, helpers : {
|
|
55
|
-
jobPossible: (text) => {
|
|
56
|
-
if ( text === 'Software Engineer' ) return 'hidden'
|
|
57
|
-
else return text
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
const templateFn = morphAPI.build ( myTpl );
|
|
62
|
-
const result = templateFn({ job: 'Software Engineer' });
|
|
63
|
-
const result2 = templateFn({ job: 'doctor' });
|
|
64
|
-
|
|
65
|
-
expect ( result ).to.be.equal ( 'My job is hidden.' );
|
|
66
|
-
expect ( result2 ).to.be.equal ( 'My job is doctor.' );
|
|
67
|
-
}) // it data action to change the result
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
it ( 'Keep a placeholder', () => {
|
|
72
|
-
const myTpl = {
|
|
73
|
-
// placeholder will be fullfiled with data[job], but data function 'jobPossible' will filter the result
|
|
74
|
-
template : `My job is {{ job : >jobPossible }}.`
|
|
75
|
-
, helpers : {
|
|
76
|
-
jobPossible: (text) => {
|
|
77
|
-
if ( text === 'Software Engineer' ) return null // null means: Do not render this field
|
|
78
|
-
else return text
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
const templateFn = morphAPI.build ( myTpl );
|
|
83
|
-
const result = templateFn({ job: 'Software Engineer' });
|
|
84
|
-
expect ( result ).to.be.equal ( 'My job is {{ job : >jobPossible }}.' );
|
|
85
|
-
}) // it Keep placeholder
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
it ( 'Long chain with variaty of actions: Data, render, and mixing', () => {
|
|
90
|
-
const myTpl = {
|
|
91
|
-
template: `Hello, {{ name : ul, [], li, >fromList }}! {{ more }}`
|
|
92
|
-
, helpers: {
|
|
93
|
-
fromList: name => (['Peter', 'Ivan'].includes(name) ? name : 'stranger')
|
|
94
|
-
|
|
95
|
-
, ul : `<ul>{{text}}</ul>`
|
|
96
|
-
, li : `<li>{{text}}</li>`
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
const templateFn = morphAPI.build ( myTpl )
|
|
100
|
-
const result = templateFn({
|
|
101
|
-
name: [ 'Peter', 'Stoyan' ]
|
|
102
|
-
, more: `extended version`
|
|
103
|
-
})
|
|
104
|
-
expect ( result ).to.be.equal ( 'Hello, <ul><li>Peter</li><li>stranger</li></ul>! extended version' )
|
|
105
|
-
}) // it Long chain with variaty of actions
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
it ( 'Data action on array of objects', () => {
|
|
110
|
-
const myTpl = {
|
|
111
|
-
template: `My friends: {{ friends : ul, [], li, >people }}`
|
|
112
|
-
, helpers: {
|
|
113
|
-
li: `<li>{{name}}: {{state}}</li>`,
|
|
114
|
-
ul: `<ul>{{text}}</ul>`,
|
|
115
|
-
people: (res) => {
|
|
116
|
-
if ( res.age < 30 ) res.state = 'young'
|
|
117
|
-
else res.state = 'old'
|
|
118
|
-
return res
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
const templateFn = morphAPI.build ( myTpl )
|
|
123
|
-
const result = templateFn({
|
|
124
|
-
friends: [
|
|
125
|
-
{ name: 'Peter', age: 30 }
|
|
126
|
-
, { name: 'Ivan', age: 25 }
|
|
127
|
-
, { name: 'Stoyan', age: 35 }
|
|
128
|
-
]
|
|
129
|
-
})
|
|
130
|
-
expect ( result ).to.be.equal ( 'My friends: <ul><li>Peter: old</li><li>Ivan: young</li><li>Stoyan: old</li></ul>' )
|
|
131
|
-
}) // it data action on array of objects
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
it ( 'Data array', () => {
|
|
136
|
-
// If input data is an array, we render each element with the template
|
|
137
|
-
const myTpl = {
|
|
138
|
-
template: `My name is {{ name }}. My age is {{ age }}.`
|
|
139
|
-
}
|
|
140
|
-
const templateFn = morphAPI.build ( myTpl )
|
|
141
|
-
const result = templateFn([
|
|
142
|
-
{ name: 'Peter', age: 30 }
|
|
143
|
-
, { name: 'Ivan', age: 25 }
|
|
144
|
-
, { name: 'Stoyan', age: 35 }
|
|
145
|
-
])
|
|
146
|
-
// Result is array of rendered templates
|
|
147
|
-
expect ( result ).to.have.length ( 3 )
|
|
148
|
-
expect ( result[0] ).to.be.equal ( 'My name is Peter. My age is 30.' )
|
|
149
|
-
expect ( result[1] ).to.be.equal ( 'My name is Ivan. My age is 25.' )
|
|
150
|
-
expect ( result[2] ).to.be.equal ( 'My name is Stoyan. My age is 35.' )
|
|
151
|
-
}) // it data array
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
it ( 'Use all data: @all, @root', () => { // *** Address full data to placeholder -> @all
|
|
156
|
-
// Both are equivalent: @all === @root
|
|
157
|
-
const myTpl = {
|
|
158
|
-
template : `My name is {{ name }}. My web page is {{ @all : a, >morphWeb }}. Contact me on {{ @root : a , >morphMail }}.`
|
|
159
|
-
, helpers : {
|
|
160
|
-
a : `<a href="{{link}}">{{text}}</a>`
|
|
161
|
-
, morphWeb : ( data ) => {
|
|
162
|
-
data.link = data.web
|
|
163
|
-
data.text = data.web
|
|
164
|
-
return data
|
|
165
|
-
}
|
|
166
|
-
, morphMail: ( data ) => {
|
|
167
|
-
data.link = data.email
|
|
168
|
-
data.text = 'e-mail'
|
|
169
|
-
return data
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
const templateFn = morphAPI.build ( myTpl )
|
|
174
|
-
const result = templateFn({
|
|
175
|
-
name : 'Peter'
|
|
176
|
-
, web : 'example.com'
|
|
177
|
-
, email : 'peter@example.com'
|
|
178
|
-
})
|
|
179
|
-
expect ( result ).to.be.equal ( 'My name is Peter. My web page is <a href="example.com">example.com</a>. Contact me on <a href="peter@example.com">e-mail</a>.' )
|
|
180
|
-
}) // it use all data @all
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
it ( 'Ignore rendering if data is null', () => {
|
|
185
|
-
// Ignore rendering [] lines that have missing data
|
|
186
|
-
const myTpl = {
|
|
187
|
-
template : `People and their jobs: {{ jobList : ul, [], li, >jobItems }}`
|
|
188
|
-
, helpers : {
|
|
189
|
-
ul : `<ul>{{text}}</ul>`
|
|
190
|
-
, li : `<li>{{name}} - {{job}}</li>`
|
|
191
|
-
, jobItems : ( data ) => { // It's a data function
|
|
192
|
-
// If data-function returns null, it will be ignored in template render
|
|
193
|
-
if ( !data.name || !data.job ) return null
|
|
194
|
-
else return data
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
};
|
|
198
|
-
const data = {
|
|
199
|
-
jobList: [
|
|
200
|
-
{name: 'Peter', job: 'Software Engineer'}
|
|
201
|
-
, {name: 'Ivan' } // No job - ignored in template render
|
|
202
|
-
, {name: 'Stoyan', job: 'designer' }
|
|
203
|
-
]
|
|
204
|
-
};
|
|
205
|
-
const templateFn = morphAPI.build ( myTpl );
|
|
206
|
-
const result = templateFn(data);
|
|
207
|
-
expect ( result ).to.be.equal ( 'People and their jobs: <ul><li>Peter - Software Engineer</li><li>Stoyan - designer</li></ul>' )
|
|
208
|
-
|
|
209
|
-
}) // it Ignore rendering if data is null
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
it ( 'Ignore rendering fields that have no data', () => {
|
|
214
|
-
const myTpl = {
|
|
215
|
-
template : `My name is {{ name }}.`
|
|
216
|
-
|
|
217
|
-
};
|
|
218
|
-
const templateFn = morphAPI.build ( myTpl );
|
|
219
|
-
const result = templateFn({ person: 'Peter' });
|
|
220
|
-
expect ( result ).to.be.equal ( 'My name is {{ name }}.' )
|
|
221
|
-
}) // it Ignore rendering fields that have no data
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
it ( 'How to hide a placeholder', () => {
|
|
226
|
-
// Hide a placeholder - provide an empty string
|
|
227
|
-
const myTpl = {
|
|
228
|
-
template : `My name is {{ name }}.{{ extraData}}`
|
|
229
|
-
}
|
|
230
|
-
const templateFn = morphAPI.build ( myTpl );
|
|
231
|
-
const result = templateFn({
|
|
232
|
-
name: 'Peter'
|
|
233
|
-
, extraData: '' // Provide an empty string to hide a placeholder
|
|
234
|
-
});
|
|
235
|
-
expect ( result ).to.be.equal ( 'My name is Peter.' )
|
|
236
|
-
}) // it how to hide a placeholder
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
it ( 'Data as null or undefined', () => {
|
|
241
|
-
// If data is null or undefined, should return the template without any changes
|
|
242
|
-
const myTpl = {
|
|
243
|
-
template : `My name is {{ name }}.{{ extraData}}`
|
|
244
|
-
}
|
|
245
|
-
const templateFn = morphAPI.build ( myTpl );
|
|
246
|
-
const result = templateFn( null );
|
|
247
|
-
expect ( result ).to.be.equal ( myTpl.template )
|
|
248
|
-
}) // it data as null or undefined
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
it ( 'Sequence of render processes with object', () => {
|
|
253
|
-
// Write result of render to field 'text' and preserve other existing fields
|
|
254
|
-
const myTpl = {
|
|
255
|
-
template : `Here is - {{ website: a, setText }}.`
|
|
256
|
-
, helpers : {
|
|
257
|
-
a : `<a href="{{link}}">{{text}}</a>`
|
|
258
|
-
, setText : `{{about}}: {{domain}}`
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
const templateFn = morphAPI.build ( myTpl );
|
|
262
|
-
const result = templateFn({
|
|
263
|
-
website : {
|
|
264
|
-
domain: `example.com`
|
|
265
|
-
, about : `My portfolio`
|
|
266
|
-
, link : `http://example.com`
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
expect ( result ).to.be.equal ( 'Here is - <a href="http://example.com">My portfolio: example.com</a>.' )
|
|
270
|
-
}) // it sequence of render processes with object
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
it ( 'Action only', () => {
|
|
275
|
-
// Use helper functions to insert dynamic data from programming environment(state, variable, etc.)
|
|
276
|
-
// Templates that are using actions only, don't need a input data object. It's a dynamic data.
|
|
277
|
-
const myState = 'active'
|
|
278
|
-
const myTpl = {
|
|
279
|
-
template: `Profile {{ : state }}.`
|
|
280
|
-
, helpers: {
|
|
281
|
-
state: () => myState
|
|
282
|
-
}
|
|
283
|
-
};
|
|
284
|
-
const templateFn = morphAPI.build ( myTpl );
|
|
285
|
-
const result = templateFn();
|
|
286
|
-
expect ( result ).to.be.equal ( 'Profile active.' )
|
|
287
|
-
}) // it action only
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
it ( 'Mixing a string', () => {
|
|
292
|
-
// Providing a string to a mixing function should not break the result.
|
|
293
|
-
const myTpl = {
|
|
294
|
-
template: `My name is {{ : [], >name }}`
|
|
295
|
-
, helpers: {
|
|
296
|
-
name: ( data ) => data.name
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
const templateFn = morphAPI.build ( myTpl );
|
|
300
|
-
const result = templateFn({ name: 'Stoyan'});
|
|
301
|
-
expect ( result ).to.be.equal ( 'My name is Stoyan' )
|
|
302
|
-
}) // it mixing a string
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
it ( 'Broken template', () => {
|
|
307
|
-
// If template is broken, the result should be a string, representation of the error.
|
|
308
|
-
const myTpl = {
|
|
309
|
-
template : `My {{ {{ welcome }}`
|
|
310
|
-
};
|
|
311
|
-
const templateFn = morphAPI.build ( myTpl );
|
|
312
|
-
const result = templateFn();
|
|
313
|
-
expect ( result ).to.be.equal ( 'Error: Nested placeholders. Close placeholder before open new one.' )
|
|
314
|
-
}) // it broken template
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
it ( 'Data only - object. Default field is "text"', () => {
|
|
319
|
-
// If provided data is object - default field is 'text'
|
|
320
|
-
const myTpl = {
|
|
321
|
-
template : `My name is {{ person }}.`
|
|
322
|
-
};
|
|
323
|
-
const templateFn = morphAPI.build ( myTpl );
|
|
324
|
-
const result = templateFn({ person: { text: 'Ivan', age: 25 }});
|
|
325
|
-
expect ( result ).to.be.equal ( 'My name is Ivan.' )
|
|
326
|
-
})
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
it ( 'Data only - array. Should render first element', () => {
|
|
331
|
-
// If provided data is array - default field is the first element of the array
|
|
332
|
-
const myTpl = {
|
|
333
|
-
template : `My name is {{ person }}.`
|
|
334
|
-
};
|
|
335
|
-
const templateFn = morphAPI.build ( myTpl );
|
|
336
|
-
const result = templateFn({ person: [ 'John', 'Milen', 'Vladislav' ]});
|
|
337
|
-
expect ( result ).to.be.equal ( 'My name is John.' )
|
|
338
|
-
})
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
it ( 'Auto mixing array results', () => {
|
|
343
|
-
// Auto mix if in the end of the action-list the result is still an array
|
|
344
|
-
const myTpl = {
|
|
345
|
-
template: `My friends are {{ friendsList: li }}.`
|
|
346
|
-
, helpers : {
|
|
347
|
-
li: `<li>{{ text }}</li>`
|
|
348
|
-
}
|
|
349
|
-
};
|
|
350
|
-
const templateFn = morphAPI.build ( myTpl );
|
|
351
|
-
const result = templateFn({ friendsList: [ 'John', 'Milen', 'Vladislav' ]});
|
|
352
|
-
expect ( result ).to.be.equal ( 'My friends are <li>John</li><li>Milen</li><li>Vladislav</li>.' )
|
|
353
|
-
})
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
it ( 'Nested templates', () => {
|
|
358
|
-
// Use helper functions to render other templates
|
|
359
|
-
|
|
360
|
-
const secondaryTpl = { // Template for nesting
|
|
361
|
-
template : `My friends are {{ names }}.`
|
|
362
|
-
}
|
|
363
|
-
const secTemplateFn = morphAPI.build ( secondaryTpl );
|
|
364
|
-
|
|
365
|
-
const myTpl = { // Top level template
|
|
366
|
-
template : `My name is {{ name }}. {{ friends: friendListing, []coma }}`
|
|
367
|
-
, helpers: {
|
|
368
|
-
friendListing: ( d ) => {
|
|
369
|
-
return secTemplateFn ({ names : d }) // Nested template render
|
|
370
|
-
}
|
|
371
|
-
, coma: ( res ) => res.join(', ')
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
const templateFn = morphAPI.build ( myTpl );
|
|
375
|
-
const result = templateFn({
|
|
376
|
-
name : 'Peter'
|
|
377
|
-
, friends: [ 'John', 'Milen', 'Vladislav' ]
|
|
378
|
-
});
|
|
379
|
-
expect ( result ).to.be.equal ( 'My name is Peter. My friends are John, Milen, Vladislav.' )
|
|
380
|
-
}) // it nested templates
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
it ( 'List - Data deep object', () => {
|
|
385
|
-
const myTpl = {
|
|
386
|
-
template : `My list: {{ list: ul , [], li, #, line }}.`
|
|
387
|
-
, helpers: {
|
|
388
|
-
line: `{{ name }} - {{ age }}`
|
|
389
|
-
, ul: `<ul>{{ text }}</ul>`
|
|
390
|
-
, li: `<li>{{ text }}</li>`
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
};
|
|
394
|
-
const data = {
|
|
395
|
-
list : [
|
|
396
|
-
'John'
|
|
397
|
-
, {
|
|
398
|
-
name: 'Milen'
|
|
399
|
-
, age: 25
|
|
400
|
-
}
|
|
401
|
-
, 'Vladislav'
|
|
402
|
-
, {
|
|
403
|
-
name: 'Stoyan'
|
|
404
|
-
, age: 30}
|
|
405
|
-
]
|
|
406
|
-
};
|
|
407
|
-
const templateFn = morphAPI.build ( myTpl );
|
|
408
|
-
const result = templateFn ( data );
|
|
409
|
-
expect ( result ).to.be.equal ( 'My list: <ul><li>John</li><li>Milen - 25</li><li>Vladislav</li><li>Stoyan - 30</li></ul>.' )
|
|
410
|
-
}) // it list - data deep object
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
it ( 'Object - Data deep object', () => {
|
|
415
|
-
const myTpl = {
|
|
416
|
-
template : `Profile: {{ me: ul , [], li, #, line }}.`
|
|
417
|
-
, helpers: {
|
|
418
|
-
line: `({{ height}}cm,{{ weight}}kg)`
|
|
419
|
-
, ul: `<ul>{{ text }}</ul>`
|
|
420
|
-
, li: `<li>{{ name }} - {{stats}}</li>`
|
|
421
|
-
}
|
|
422
|
-
};
|
|
423
|
-
const data = {
|
|
424
|
-
me : {
|
|
425
|
-
name: 'Peter'
|
|
426
|
-
, stats : {
|
|
427
|
-
age: 50
|
|
428
|
-
, height: 180
|
|
429
|
-
, weight: 66
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
};
|
|
433
|
-
const templateFn = morphAPI.build ( myTpl );
|
|
434
|
-
const result = templateFn ( data );
|
|
435
|
-
expect ( result ).to.be.equal ( 'Profile: <ul><li>Peter - (180cm,66kg)</li></ul>.' )
|
|
436
|
-
}) // it object - data deep object
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
it ( 'Use extra renders: "+" ', () => {
|
|
441
|
-
let touch = false;
|
|
442
|
-
const myTpl = {
|
|
443
|
-
template : `Profile: {{ me: +line }}.`
|
|
444
|
-
, helpers: {
|
|
445
|
-
line: ( x ) => {
|
|
446
|
-
expect ( x ).to.have.property ( 'stats' )
|
|
447
|
-
expect ( x ).to.have.property ( 'name' )
|
|
448
|
-
const { height, weight } = x.stats;
|
|
449
|
-
touch = true
|
|
450
|
-
return `${x.name} - (${height}cm,${weight}kg)`
|
|
451
|
-
} // line helper
|
|
452
|
-
} // helpers
|
|
453
|
-
};
|
|
454
|
-
const data = {
|
|
455
|
-
me : {
|
|
456
|
-
name: 'Peter'
|
|
457
|
-
, stats : {
|
|
458
|
-
age: 50
|
|
459
|
-
, height: 180
|
|
460
|
-
, weight: 66
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
};
|
|
464
|
-
const templateFn = morphAPI.build ( myTpl );
|
|
465
|
-
const result = templateFn ( data );
|
|
466
|
-
expect ( result ).to.be.equal ( 'Profile: Peter - (180cm,66kg).' )
|
|
467
|
-
expect ( touch ).to.be.true
|
|
468
|
-
}) // it use extra renders "+"
|
|
469
|
-
|
|
470
|
-
}) // Describe
|
package/test/03-storage.test.js
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import morph from '../src/main.js'
|
|
2
|
-
import { expect } from 'chai'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
describe ( 'morph: storage', () => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
it ( 'Add template to default storage', () => {
|
|
10
|
-
const myTpl = {
|
|
11
|
-
template : `My name is {{ name }}.`
|
|
12
|
-
};
|
|
13
|
-
morph.add ( 'myTpl', morph.build ( myTpl ) );
|
|
14
|
-
const result = morph.get ( 'myTpl' )({ name: 'Peter' })
|
|
15
|
-
expect ( result ).to.be.equal ( 'My name is Peter.' )
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
it ( 'Add template definition to default storage', () => {
|
|
21
|
-
morph.clear ()
|
|
22
|
-
const myTpl = {
|
|
23
|
-
template : `My name is {{ name }}.`
|
|
24
|
-
};
|
|
25
|
-
// Can we check if the template is already in the storage?
|
|
26
|
-
morph.add ( 'myName', myTpl );
|
|
27
|
-
const result = morph.get ( 'myName' )({ name: 'Peter' })
|
|
28
|
-
expect ( result ).to.be.equal ( 'My name is Peter.' )
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
it ( 'Wrong template description', () => {
|
|
34
|
-
//
|
|
35
|
-
morph.clear ()
|
|
36
|
-
console.error = ( str ) => { // Override console.error to avoid console output
|
|
37
|
-
expect ( str ).to.be.equal ( 'Error: Template "fake" looks broken and is not added to storage.' )
|
|
38
|
-
}
|
|
39
|
-
const fakeTpl = { a: 12, b: 'Hello' };
|
|
40
|
-
morph.add ( 'fake', fakeTpl );
|
|
41
|
-
}) // it wrong template description
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
it ( 'Add component to default storage', () => {
|
|
46
|
-
morph.clear ()
|
|
47
|
-
const myTpl = { template: `My name is {{ name }}.` };
|
|
48
|
-
const myTplFn = morph.build ( myTpl );
|
|
49
|
-
morph.add ( 'myTpl', myTplFn );
|
|
50
|
-
const result = morph.get ( 'myTpl' )({ name: 'Peter' })
|
|
51
|
-
expect ( result ).to.be.equal ( 'My name is Peter.' )
|
|
52
|
-
}) // it add component to default storage
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
it ( 'Add template definition to custom storage', () => {
|
|
57
|
-
// Using a custom named storage if preffer to organize templates somehow
|
|
58
|
-
morph.clear () // Clear the storage from previous tests
|
|
59
|
-
const myTpl = { template: `My name is {{ name }}.` };
|
|
60
|
-
morph.add ( 'myName', myTpl, 'hidden' ); // Provide a custom storage name as 3rd argument
|
|
61
|
-
|
|
62
|
-
let result = morph.get ('myName')({ name: 'Peter' });
|
|
63
|
-
// result of morph.get() is a function that returns a error.
|
|
64
|
-
// Error will popup as a rendering result
|
|
65
|
-
|
|
66
|
-
expect ( result ).to.be.equal ( 'Error: Template "myName" does not exist in storage "default".' )
|
|
67
|
-
result = morph.get ('myName', 'hidden')({ name: 'Peter' })
|
|
68
|
-
expect ( result ).to.be.equal ( 'My name is Peter.' )
|
|
69
|
-
|
|
70
|
-
let list = morph.list ();
|
|
71
|
-
expect ( list ).to.have.length ( 0 )
|
|
72
|
-
|
|
73
|
-
list = morph.list ('hidden');
|
|
74
|
-
expect ( list ).to.have.length ( 1 )
|
|
75
|
-
expect ( list[0] ).to.be.equal ( 'myName' )
|
|
76
|
-
}) // it add template definition to custom storage
|
|
77
|
-
|
|
78
|
-
}) // describe
|
package/test/04-commands.js
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import morph from '../src/main.js'
|
|
2
|
-
import { expect } from 'chai'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
describe ( 'morph: commands', () => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
it ( 'Request a template', () => {
|
|
11
|
-
// Command 'raw'
|
|
12
|
-
const myTpl = { template : `My name is {{ name }}.` };
|
|
13
|
-
morph.add ( 'myName', myTpl );
|
|
14
|
-
const result = morph.get ( 'myName' )('raw')
|
|
15
|
-
expect ( result ).to.be.equal ( 'My name is {{ name }}.' )
|
|
16
|
-
}) // it request a template
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
it ( 'Request a handshake', () => {
|
|
21
|
-
let demo = { name: 'Stoyan' }
|
|
22
|
-
const myTpl = {
|
|
23
|
-
template : `My name is {{ name }}.`
|
|
24
|
-
, handshake : demo
|
|
25
|
-
};
|
|
26
|
-
morph.add ( 'myName', myTpl );
|
|
27
|
-
const result = morph.get ( 'myName' )('handshake')
|
|
28
|
-
expect ( result ).to.be.deep.equal ( demo )
|
|
29
|
-
}) // it request a handshake
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
it ( 'Request a demo', () => {
|
|
34
|
-
// Render a template with the handshake
|
|
35
|
-
let demo = { name: 'Stoyan' }
|
|
36
|
-
const myTpl = {
|
|
37
|
-
template : `My name is {{ name }}.`
|
|
38
|
-
, handshake : demo
|
|
39
|
-
};
|
|
40
|
-
morph.add ( 'myName', myTpl );
|
|
41
|
-
const result = morph.get ( 'myName' )('demo')
|
|
42
|
-
expect ( result ).to.be.equal ( 'My name is Stoyan.' )
|
|
43
|
-
}) // it request a demo
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
it ( 'Wrong command to component', () => {
|
|
49
|
-
// Commands other than 'raw', 'handshake' and 'demo' should return an error.
|
|
50
|
-
let demo = { name: 'Stoyan' }
|
|
51
|
-
const myTpl = {
|
|
52
|
-
template : `My name is {{ name }}.`
|
|
53
|
-
, handshake : demo
|
|
54
|
-
};
|
|
55
|
-
morph.add ( 'myName', myTpl );
|
|
56
|
-
const result = morph.get ( 'myName' )('fake')
|
|
57
|
-
expect ( result ).to.be.equal ( 'Error: Wrong command "fake". Available commands: raw, demo, handshake, placeholders.' )
|
|
58
|
-
}) // it wrong command to component
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
it ( 'See placeholders', () => {
|
|
62
|
-
let demo = { name: 'Stoyan', age: 30 }
|
|
63
|
-
const myTpl = {
|
|
64
|
-
template : `My name is {{ name }}. Age {{ age }}.`
|
|
65
|
-
, handshake : demo
|
|
66
|
-
};
|
|
67
|
-
morph.add ( 'myName', myTpl );
|
|
68
|
-
const result = morph.get ( 'myName' )('placeholders')
|
|
69
|
-
expect ( result ).to.be.equal ( '{{ name }}, {{ age }}' )
|
|
70
|
-
}) // it see placeholders
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}) // describe
|
package/test/05-data.test.js
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import morph from '../src/main.js'
|
|
2
|
-
import { expect } from 'chai'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
describe ( 'morph: Data', () => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
it ( 'Using string literals in helpers', () => {
|
|
11
|
-
const myTpl = {
|
|
12
|
-
template : `My name is {{ person: hello }}.`
|
|
13
|
-
, helpers : {
|
|
14
|
-
hello: ({name, age}) => {
|
|
15
|
-
return `${name}o. Age is ${age}`
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
const templateFn = morph.build ( myTpl );
|
|
20
|
-
const result = templateFn({
|
|
21
|
-
person: {
|
|
22
|
-
name: 'Robert'
|
|
23
|
-
, age: 30
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
});
|
|
27
|
-
expect ( result ).to.be.equal ( 'My name is Roberto. Age is 30.' )
|
|
28
|
-
}) // it using string literals in helpers
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
it ( 'Helper returns null', () => {
|
|
33
|
-
const myTpl = {
|
|
34
|
-
template : `My name is {{ person: hello }}.`
|
|
35
|
-
, helpers : {
|
|
36
|
-
hello: ({name, age}) => null
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
const templateFn = morph.build ( myTpl );
|
|
40
|
-
const result = templateFn({
|
|
41
|
-
person: {
|
|
42
|
-
name: 'Robert'
|
|
43
|
-
, age: 30
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
});
|
|
47
|
-
expect ( result ).to.be.equal ( 'My name is {{ person: hello }}.' )
|
|
48
|
-
}) // it helper returns null
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
it ( 'Conditional rendering with string literals', () => {
|
|
53
|
-
// Conditional rendering mean that helper rendering could be called
|
|
54
|
-
// if data coresponds to some condition.
|
|
55
|
-
// Returning null means: do not render this data
|
|
56
|
-
const myTpl = {
|
|
57
|
-
template : "Hello, I'm {{ persons: []coma, ?web, hello }}"
|
|
58
|
-
, helpers : {
|
|
59
|
-
hello: ( data ) => {
|
|
60
|
-
const { name, age } = data;
|
|
61
|
-
if ( age < 28 ) return null
|
|
62
|
-
else return `${name} - ${age} years old`
|
|
63
|
-
}
|
|
64
|
-
, coma: (res) => res // Coma is a mixing helper
|
|
65
|
-
.filter ( x => x != null) // filter is required to remove cancelled renders
|
|
66
|
-
.map ( x => x.text )
|
|
67
|
-
.join ( ', ' )
|
|
68
|
-
, a : `<a href="{{href}}">{{text}}</a>`
|
|
69
|
-
, web: ( d ) => {
|
|
70
|
-
if ( d.href ) return 'a' // response 'a' means: render this data with helper 'a'
|
|
71
|
-
else return null // response 'null' in conditional render means: do not render
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
const templateFn = morph.build ( myTpl );
|
|
76
|
-
const result = templateFn({
|
|
77
|
-
persons: [
|
|
78
|
-
{ name: 'Robert' , age: 30, href: 'http://robert.com' }
|
|
79
|
-
, { name: 'John' , age: 64 }
|
|
80
|
-
, { name: 'Edward' , age: 21, href: 'http://edward.com' }
|
|
81
|
-
, { name: 'Bob' , age: 34 , href: 'http://bob.com' }
|
|
82
|
-
]
|
|
83
|
-
});
|
|
84
|
-
expect ( result ).to.be.equal ( `Hello, I'm <a href="http://robert.com">Robert - 30 years old</a>, John - 64 years old, <a href="http://bob.com">Bob - 34 years old</a>` )
|
|
85
|
-
}) // it conditional rendering with string literals
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
it ( 'Post process functions', () => {
|
|
90
|
-
const myTpl = {
|
|
91
|
-
template : `The template:`
|
|
92
|
-
}
|
|
93
|
-
const
|
|
94
|
-
post1 = ( data ) => `${data} >post1`
|
|
95
|
-
, post2 = ( data ) => `${data} >post2`
|
|
96
|
-
, post3 = ( data ) => `${data} >post3`
|
|
97
|
-
;
|
|
98
|
-
const templateFn = morph.build ( myTpl );
|
|
99
|
-
const result = templateFn ( {}, post1, post2, post3 );
|
|
100
|
-
expect ( result ).to.be.equal ( `The template: >post1 >post2 >post3` )
|
|
101
|
-
}) // it post process functions
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
it ( 'Read data from external state', () => {
|
|
106
|
-
const state = {
|
|
107
|
-
name: 'Robert'
|
|
108
|
-
, age: 30
|
|
109
|
-
, job: 'software developer'
|
|
110
|
-
}
|
|
111
|
-
const myTpl = {
|
|
112
|
-
template : `Hello from {{ :name }}. I'm {{ :age }} years old {{ :job }}`
|
|
113
|
-
, helpers : {
|
|
114
|
-
name: ( data ) => state.name
|
|
115
|
-
, age: ( data ) => state.age
|
|
116
|
-
, job: ( data ) => state.job
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
const templateFn = morph.build ( myTpl );
|
|
120
|
-
const result = templateFn();
|
|
121
|
-
expect ( result ).to.be.equal ( `Hello from Robert. I'm 30 years old software developer` )
|
|
122
|
-
}) // it read data from external state
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
it ( 'Function arguments - data only', () => {
|
|
127
|
-
const state = {
|
|
128
|
-
name: 'Robert'
|
|
129
|
-
, age: 30
|
|
130
|
-
, job: 'software developer'
|
|
131
|
-
}
|
|
132
|
-
const myTpl = {
|
|
133
|
-
template : `Hello from {{ name }}. I'm {{ age }} years old {{ job }}`
|
|
134
|
-
}
|
|
135
|
-
const templateFn = morph.build ( myTpl );
|
|
136
|
-
const result = templateFn({
|
|
137
|
-
name: () => state.name
|
|
138
|
-
, age: () => state.age
|
|
139
|
-
, job: () => state.job
|
|
140
|
-
});
|
|
141
|
-
expect ( result ).to.be.equal ( `Hello from Robert. I'm 30 years old software developer` )
|
|
142
|
-
}) // it function arguments - data only
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
it ( 'Function arguments with actions', () => {
|
|
147
|
-
const state = {
|
|
148
|
-
name: 'Robert'
|
|
149
|
-
, age: 30
|
|
150
|
-
, job: 'software developer'
|
|
151
|
-
}
|
|
152
|
-
const myTpl = {
|
|
153
|
-
template : `Hello from {{ name }}. I'm {{ age: extraAge }} years old {{ job }}`
|
|
154
|
-
, helpers : {
|
|
155
|
-
extraAge: ( data ) => data+3
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
const templateFn = morph.build ( myTpl );
|
|
159
|
-
const result = templateFn({
|
|
160
|
-
name: () => state.name
|
|
161
|
-
, age: () => state.age
|
|
162
|
-
, job: () => state.job
|
|
163
|
-
});
|
|
164
|
-
expect ( result ).to.be.equal ( `Hello from Robert. I'm 33 years old software developer` )
|
|
165
|
-
}) // it function arguments with actions
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}) // describe
|