@peter.naydenov/morph 0.0.3 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Changelog.md +5 -0
- package/Migration.guide.md +41 -1
- package/README.md +5 -5
- package/dist/morph.cjs +1 -1
- package/dist/morph.esm.mjs +1 -1
- package/dist/morph.umd.js +1 -1
- package/package.json +10 -10
- package/src/main.js +76 -25
- package/src/methods/build.js +44 -11
- package/src/methods/render.js +13 -2
package/Changelog.md
CHANGED
package/Migration.guide.md
CHANGED
|
@@ -1,3 +1,43 @@
|
|
|
1
1
|
# Migration Guides
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
## 0.x.x -> 1.x.x
|
|
5
|
+
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
|
+
|
|
7
|
+
```js
|
|
8
|
+
// Add template to default storage
|
|
9
|
+
// Before
|
|
10
|
+
morph.add ( 'myName', myTpl )
|
|
11
|
+
// After
|
|
12
|
+
morph.add ( ['myName'], myTpl )
|
|
13
|
+
|
|
14
|
+
// Add template to named storage
|
|
15
|
+
// Before
|
|
16
|
+
morph.add ( 'myName', myTpl, 'myStorage' )
|
|
17
|
+
// After
|
|
18
|
+
morph.add ( ['myName', 'myStorage'], myTpl )
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Calling the render function has changed. The first argument again is the data, but then we have optional injection object and then comes post processing function.
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
// My injection is new argument
|
|
25
|
+
// Before
|
|
26
|
+
morph.render ( myData, postProcess1, postProcess2, postProcess3 )
|
|
27
|
+
// After
|
|
28
|
+
morph.render ( myData, myInjection, postProcess1, postProcess2, postProcess3 )
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
List method is extended. Now you can pass more then one storage to scan for template names.
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
// Before
|
|
35
|
+
let storage1Templates = morph.list ( 'storage1' )
|
|
36
|
+
let storage2Templates = morph.list ( 'storage2' )
|
|
37
|
+
let all = storage1Templates.concat ( storage2Templates )
|
|
38
|
+
|
|
39
|
+
// After
|
|
40
|
+
let all = morph.list ( ['storage1', 'storage2'] )
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Library is prety well typed now so expect a smooth migration process.
|
package/README.md
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# Morph (@peter.naydenov/morph)
|
|
2
|
-
**Experimental stage. Not tested well yet.**
|
|
3
2
|
|
|
4
3
|

|
|
5
4
|

|
|
@@ -52,8 +51,8 @@ import morph from "@peter.naydenov/morph"
|
|
|
52
51
|
const myTemplateDescription = {
|
|
53
52
|
template: `Hello, {{name}}!` // simple template - a string with a placeholder
|
|
54
53
|
}
|
|
55
|
-
const myTemplate = morph.build ( myTemplateDescription );
|
|
56
|
-
const htmlBlock = myTemplate ( { name: 'Peter' } )
|
|
54
|
+
const myTemplate = morph.build ( myTemplateDescription ); // myTemplate is a render function
|
|
55
|
+
const htmlBlock = myTemplate ( { name: 'Peter' } ) // Provide data to the render function and get the result
|
|
57
56
|
// htmlBlock === 'Hello, Peter!'
|
|
58
57
|
```
|
|
59
58
|
|
|
@@ -61,9 +60,10 @@ Morph contains also a builtin template storage. Instead of creating variable for
|
|
|
61
60
|
|
|
62
61
|
```js
|
|
63
62
|
// add template to the storage. Automatically builds the render function
|
|
64
|
-
|
|
63
|
+
// Array of two elements. 0 - template name, 1 - optional. Storage name. Defaults to 'default'
|
|
64
|
+
morph.add ( ['myTemplate'], myTemplateDescription )
|
|
65
65
|
// get template from the storage and render it
|
|
66
|
-
const htmlBlock = morph.get ( 'myTemplate' )({ name: 'Peter' })
|
|
66
|
+
const htmlBlock = morph.get ( ['myTemplate'] )({ name: 'Peter' })
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
Let's see a more complex example before we go into details:
|
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
|
|
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,...a){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text)}));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,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(u){function b(){return u}return i?[!1,b]:b}{let m=structuredClone(d);function y(r={},...n){const o=s(r),i=[];if("null"===o)return m.join("");if("string"==typeof r)switch(r){case"raw":return m.join("");case"demo":if(!h)return"Error: No handshake data.";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"!==o&&(r=[r]),r.forEach((r=>{f.forEach((o=>{const{index:i,data:u,action:f}=o;if(!f&&u){const d=r[u];switch(s(d)){case"function":return void(m[i]=d());case"primitive":return void(m[i]=d);case"array":return void("primitive"===s(d[0])&&(m[i]=d[0]));case"object":return void(d.text&&(m[i]=d.text))}}else{const{dataDeepLevel:h,nestedData:b}=a("@all"===u||null===u||"@root"===u?r:r[u]),y=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}(f,h),h);for(let k of y){let{type:x,name:g,level:j}=k,_=b[j],w=s(_);switch(x){case"route":switch(w){case"array":_.forEach(((e,t)=>{if(null==e)return;const r=s(e),a=p[g](e);null!=a&&("object"===r?_[t].text=c(e,a,p,...l,...n):_[t]=c(e,a,p,...l,...n))}));break;case"object":_.text=c(_,routeName,p,...l,...n);break;case"primitive":b[j]=c(_,routeName,p,...l,...n)}break;case"data":switch(w){case"array":_.forEach(((e,t)=>_[t]=e instanceof Function?p[g](e()):p[g](e)));break;case"object":case"primitive":b[j]=p[g](_);break;case"function":b[j]=p[g](_())}break;case"render":const T="function"==typeof p[g];switch(w){case"array":T?_.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=p[g](e);null==n&&(_[t]=null),"object"===r?e.text=n:_[t]=n})):_.forEach(((e,t)=>{if(null==e)return;const r=s(e),a=c(e,g,p,...l,...n);null==a&&(_[t]=null),"object"===r?e.text=a:_[t]=a}));break;case"primitive":b[j]=c(_,g,p,...l,...n);break;case"object":Object.keys(_).find((e=>e.includes("/")))?Object.entries(_).forEach((([e,t])=>t.text=c(t,g,p,...l,...n))):_.text=c(_,g,p,...l,...n)}break;case"extendedRender":"function"==typeof p[g]&&(b[j]=p[g](b[0]));break;case"mix":if(""===g)switch(w){case"object":Object.keys(_).find((e=>e.includes("/")))?Object.entries(_).forEach((([e,t])=>b[j][e]=t.text)):b[j]=_.text;for(let O=j-1;O>=0;O--)b[O]=e({data:b[O],objectCallback:S});function S({value:e,breadcrumbs:t}){return b[j][t]?b[j][t]:e}break;case"array":b[j]=_.map((e=>"object"===s(e)?e.text:e)).filter((e=>null!=e)).join("")}else b[j]=p[g](_)}}let E=s(b[0]),v=b[0];switch(E){case"primitive":if(null==v)return;m[i]=v;break;case"object":if(null==v.text)return;m[i]=v.text;break;case"array":m[i]=v.join("")}}})),i.push(m.join(""))})),"array"===o?i:i.join("")}return i?[!0,y]:y}}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="default"],r,...n){let a=r,o=!0;l[strName]||(l[strName]={}),"function"!=typeof r&&([o,a]=i(r,!0,...n)),o?l[strName][e]=a: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
|
|
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,...a){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text)}));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,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(u){function b(){return u}return i?[!1,b]:b}{let m=structuredClone(d);function y(r={},...n){const o=s(r),i=[];if("null"===o)return m.join("");if("string"==typeof r)switch(r){case"raw":return m.join("");case"demo":if(!h)return"Error: No handshake data.";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"!==o&&(r=[r]),r.forEach((r=>{f.forEach((o=>{const{index:i,data:u,action:f}=o;if(!f&&u){const d=r[u];switch(s(d)){case"function":return void(m[i]=d());case"primitive":return void(m[i]=d);case"array":return void("primitive"===s(d[0])&&(m[i]=d[0]));case"object":return void(d.text&&(m[i]=d.text))}}else{const{dataDeepLevel:h,nestedData:b}=a("@all"===u||null===u||"@root"===u?r:r[u]),y=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}(f,h),h);for(let k of y){let{type:x,name:g,level:j}=k,_=b[j],w=s(_);switch(x){case"route":switch(w){case"array":_.forEach(((e,t)=>{if(null==e)return;const r=s(e),a=p[g](e);null!=a&&("object"===r?_[t].text=c(e,a,p,...l,...n):_[t]=c(e,a,p,...l,...n))}));break;case"object":_.text=c(_,routeName,p,...l,...n);break;case"primitive":b[j]=c(_,routeName,p,...l,...n)}break;case"data":switch(w){case"array":_.forEach(((e,t)=>_[t]=e instanceof Function?p[g](e()):p[g](e)));break;case"object":case"primitive":b[j]=p[g](_);break;case"function":b[j]=p[g](_())}break;case"render":const T="function"==typeof p[g];switch(w){case"array":T?_.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=p[g](e);null==n&&(_[t]=null),"object"===r?e.text=n:_[t]=n})):_.forEach(((e,t)=>{if(null==e)return;const r=s(e),a=c(e,g,p,...l,...n);null==a&&(_[t]=null),"object"===r?e.text=a:_[t]=a}));break;case"primitive":b[j]=c(_,g,p,...l,...n);break;case"object":Object.keys(_).find((e=>e.includes("/")))?Object.entries(_).forEach((([e,t])=>t.text=c(t,g,p,...l,...n))):_.text=c(_,g,p,...l,...n)}break;case"extendedRender":"function"==typeof p[g]&&(b[j]=p[g](b[0]));break;case"mix":if(""===g)switch(w){case"object":Object.keys(_).find((e=>e.includes("/")))?Object.entries(_).forEach((([e,t])=>b[j][e]=t.text)):b[j]=_.text;for(let O=j-1;O>=0;O--)b[O]=e({data:b[O],objectCallback:S});function S({value:e,breadcrumbs:t}){return b[j][t]?b[j][t]:e}break;case"array":b[j]=_.map((e=>"object"===s(e)?e.text:e)).filter((e=>null!=e)).join("")}else b[j]=p[g](_)}}let E=s(b[0]),v=b[0];switch(E){case"primitive":if(null==v)return;m[i]=v;break;case"object":if(null==v.text)return;m[i]=v.text;break;case"array":m[i]=v.join("")}}})),i.push(m.join(""))})),"array"===o?i:i.join("")}return i?[!0,y]:y}}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="default"],r,...n){let a=r,o=!0;l[strName]||(l[strName]={}),"function"!=typeof r&&([o,a]=i(r,!0,...n)),o?l[strName][e]=a: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:
|
|
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:s}=e;let l,c,u,f=[];if("string"!=typeof n)return r("notAString");if(0==n.length)return[];if(l=n.indexOf(o),0<l&&f.push(n.slice(0,l)),-1==l)return f.push(n),f;{if(u=n.indexOf(o,l+i),c=n.indexOf(a),-1==c)return r("missingClosing");if(c<l)return r("closedBeforeOpened");if(c+=s,-1!=u&&u<c)return r("newBeforeClosed");f.push(n.slice(l,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 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 l(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:s,pullReverse:function(e=1,t=0){let r=s(e,t);return r instanceof Array?r.reverse():r},peek:l,peekReverse:function(e=1,t=0){const r=l(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 l=!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&&(l=s(a-n))}return t=e instanceof Array?t.concat(e):t.concat([e]),i=!!n&&t.length===n,l||void 0}}:function(e){const r=e instanceof Array,a=r?e.length:1;let l=!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&&(l=s(a-n))}return t=r?e.reduce(((e,t)=>[t,...e]),t):[e].reduce(((e,t)=>[t,...e]),t),i=!!n&&t.length===n,l||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 s(e,r,n,...o){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text)}));const i="function"==typeof n[r];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),i?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 l(r,l=!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:i,TG_SFX:s,TG_SIZE_P:l,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*)?"+s,"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(u){function m(){return u}return l?[!1,m]:m}{let y=structuredClone(p);function b(t={},...r){const a=i(t),l=[];if("null"===a)return y.join("");if("string"==typeof t)switch(t){case"raw":return y.join("");case"demo":if(!h)return"Error: No handshake data.";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"!==a&&(t=[t]),t.forEach((t=>{f.forEach((a=>{const{index:l,data:u,action:f}=a;if(!f&&u){const p=t[u];switch(i(p)){case"function":return void(y[l]=p());case"primitive":return void(y[l]=p);case"array":return void("primitive"===i(p[0])&&(y[l]=p[0]));case"object":return void(p.text&&(y[l]=p.text))}}else{const{dataDeepLevel:h,nestedData:m}=n("@all"===u||null===u||"@root"===u?t:t[u]),b=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}(f,h),h);for(let E of b){let{type:k,name:j,level:x}=E,w=m[x],T=i(w);switch(k){case"route":switch(T){case"array":w.forEach(((e,t)=>{if(null==e)return;const n=i(e),o=d[j](e);null!=o&&("object"===n?w[t].text=s(e,o,d,...c,...r):w[t]=s(e,o,d,...c,...r))}));break;case"object":w.text=s(w,routeName,d,...c,...r);break;case"primitive":m[x]=s(w,routeName,d,...c,...r)}break;case"data":switch(T){case"array":w.forEach(((e,t)=>w[t]=e instanceof Function?d[j](e()):d[j](e)));break;case"object":case"primitive":m[x]=d[j](w);break;case"function":m[x]=d[j](w())}break;case"render":const _="function"==typeof d[j];switch(T){case"array":_?w.forEach(((e,t)=>{if(null==e)return;const r=i(e),n=d[j](e);null==n&&(w[t]=null),"object"===r?e.text=n:w[t]=n})):w.forEach(((e,t)=>{if(null==e)return;const n=i(e),o=s(e,j,d,...c,...r);null==o&&(w[t]=null),"object"===n?e.text=o:w[t]=o}));break;case"primitive":m[x]=s(w,j,d,...c,...r);break;case"object":Object.keys(w).find((e=>e.includes("/")))?Object.entries(w).forEach((([e,t])=>t.text=s(t,j,d,...c,...r))):w.text=s(w,j,d,...c,...r)}break;case"extendedRender":"function"==typeof d[j]&&(m[x]=d[j](m[0]));break;case"mix":if(""===j)switch(T){case"object":Object.keys(w).find((e=>e.includes("/")))?Object.entries(w).forEach((([e,t])=>m[x][e]=t.text)):m[x]=w.text;for(let S=x-1;S>=0;S--)m[S]=e({data:m[S],objectCallback:O});function O({value:e,breadcrumbs:t}){return m[x][t]?m[x][t]:e}break;case"array":m[x]=w.map((e=>"object"===i(e)?e.text:e)).filter((e=>null!=e)).join("")}else m[x]=d[j](w)}}let g=i(m[0]),v=m[0];switch(g){case"primitive":if(null==v)return;y[l]=v;break;case"object":if(null==v.text)return;y[l]=v.text;break;case"array":y[l]=v.join("")}}})),l.push(y.join(""))})),"array"===a?l:l.join("")}return l?[!0,b]:b}}const c={default:{}};return{build:l,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="default"],r,...n){let o=r,a=!0;c[strName]||(c[strName]={}),"function"!=typeof r&&([a,o]=l(r,!0,...n)),a?c[strName][e]=o: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
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peter.naydenov/morph",
|
|
3
3
|
"description": "Template engine",
|
|
4
|
-
"version": "0.0
|
|
4
|
+
"version": "1.0.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Peter Naydenov",
|
|
7
|
-
"main": "
|
|
7
|
+
"main": ".src/main.js",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
-
"import": "./
|
|
11
|
+
"import": "./src/main.js",
|
|
12
12
|
"require": "./dist/morph.cjs",
|
|
13
|
-
"default": "./
|
|
13
|
+
"default": "./src/main.js"
|
|
14
14
|
},
|
|
15
15
|
"./package.json": "./package.json",
|
|
16
16
|
"./dist/*": "./dist/*",
|
|
@@ -23,16 +23,16 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@peter.naydenov/stack": "^3.0.0",
|
|
26
|
-
"@peter.naydenov/walk": "^5.0.
|
|
26
|
+
"@peter.naydenov/walk": "^5.0.1"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@rollup/plugin-commonjs": "^28.0.
|
|
30
|
-
"@rollup/plugin-node-resolve": "^
|
|
29
|
+
"@rollup/plugin-commonjs": "^28.0.2",
|
|
30
|
+
"@rollup/plugin-node-resolve": "^16.0.0",
|
|
31
31
|
"@rollup/plugin-terser": "^0.4.4",
|
|
32
|
-
"c8": "^10.1.
|
|
32
|
+
"c8": "^10.1.3",
|
|
33
33
|
"chai": "5.1.2",
|
|
34
|
-
"mocha": "
|
|
35
|
-
"rollup": "^4.
|
|
34
|
+
"mocha": "11.0.1",
|
|
35
|
+
"rollup": "^4.29.1"
|
|
36
36
|
},
|
|
37
37
|
"repository": {
|
|
38
38
|
"type": "git",
|
package/src/main.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* History notes:
|
|
8
8
|
* - Idea was born on October 28th, 2024.
|
|
9
9
|
* - Published on GitHub for first time: November 30th, 2024
|
|
10
|
+
* - Version 1.0.0: December 28st, 2024
|
|
10
11
|
*
|
|
11
12
|
*/
|
|
12
13
|
|
|
@@ -15,11 +16,26 @@ import build from "./methods/build.js"
|
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
|
|
18
|
-
const storage = {
|
|
19
|
+
const storage = ( () => ({default: {}}) ) ();
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get a template from a storage.
|
|
28
|
+
*
|
|
29
|
+
* @param {string[]} location - The location of the template. Array of two elements.
|
|
30
|
+
* The first element is the name of the template. The second element
|
|
31
|
+
* is optional and is the name of the storage. Defaults to 'default'.
|
|
32
|
+
*
|
|
33
|
+
* @returns {function } The template (a render function) if it exists in the storage.
|
|
34
|
+
* An function that returns an error message if
|
|
35
|
+
* either the storage or template does not exist.
|
|
36
|
+
*/
|
|
37
|
+
function get ( location ) {
|
|
38
|
+
const [prop, strName='default'] = location;
|
|
23
39
|
if ( !storage[strName] ) {
|
|
24
40
|
return function () {
|
|
25
41
|
return `Error: Storage "${strName}" does not exist.`
|
|
@@ -35,25 +51,63 @@ function get ( prop, strName='default' ) {
|
|
|
35
51
|
|
|
36
52
|
|
|
37
53
|
|
|
38
|
-
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Add a template to a storage.
|
|
60
|
+
*
|
|
61
|
+
* If the template is already a function, it is added to the storage.
|
|
62
|
+
* If the template is a template description (an object), it is built and
|
|
63
|
+
* added to the storage.
|
|
64
|
+
* If the template is broken, an error message is printed in the console
|
|
65
|
+
* and the template is not added to the storage.
|
|
66
|
+
*
|
|
67
|
+
* @param {string[]} location - The location to add the template to. Array of two elements.
|
|
68
|
+
* The first element is the name of the template. The second element
|
|
69
|
+
* is optional and is the name of the storage. Defaults to 'default'.
|
|
70
|
+
* @param {object|function} tplfn - The template description or the already built template function.
|
|
71
|
+
* @param {...any} args - Additional arguments to be passed to the build function.
|
|
72
|
+
* Only used if the first argument is a template description.
|
|
73
|
+
*/
|
|
74
|
+
function add ( location, tplfn, ...args ) {
|
|
75
|
+
const [ name, strName='default'] = location
|
|
39
76
|
let fn = tplfn;
|
|
40
77
|
let successBuild = true;
|
|
41
78
|
if( !storage[strName] ) storage[strName] = {}
|
|
42
|
-
if ( typeof tplfn !== 'function' )
|
|
43
|
-
|
|
79
|
+
if ( typeof tplfn !== 'function' ) {
|
|
80
|
+
let r = build ( tplfn, true, ...args )
|
|
81
|
+
successBuild = r[0]
|
|
82
|
+
fn = r[1]
|
|
83
|
+
}
|
|
44
84
|
if ( successBuild ) storage[strName][name] = fn
|
|
45
85
|
else console.error ( `Error: Template "${name}" looks broken and is not added to storage.` )
|
|
46
86
|
} // add func.
|
|
47
87
|
|
|
48
88
|
|
|
49
89
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Returns an array of all the names of the templates in the given storages.
|
|
92
|
+
* No arguments - will return the list of templates in the 'default' storage.
|
|
93
|
+
*
|
|
94
|
+
* @param {string[]} [storageNames=['default']] - The names of the storages to retrieve template names from;
|
|
95
|
+
* @returns {string[]} An array of all the template names in the given storages;
|
|
96
|
+
*/
|
|
97
|
+
function list ( storageNames=['default'] ) {
|
|
98
|
+
let r = storageNames.map ( strName => {
|
|
99
|
+
if ( !storage[strName] ) return []
|
|
100
|
+
else return Object.keys ( storage[strName])
|
|
101
|
+
})
|
|
102
|
+
return r.flat ()
|
|
53
103
|
} // list func.
|
|
54
104
|
|
|
55
105
|
|
|
56
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Clears all templates from the storages.
|
|
109
|
+
* This function deletes all storages. Storage 'default' will be reset to an empty object.
|
|
110
|
+
*/
|
|
57
111
|
function clear ( ) {
|
|
58
112
|
const keys = Object.keys ( storage )
|
|
59
113
|
keys.forEach ( key => {
|
|
@@ -64,28 +118,26 @@ function clear ( ) {
|
|
|
64
118
|
|
|
65
119
|
|
|
66
120
|
|
|
67
|
-
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Removes a template from the storage.
|
|
124
|
+
*
|
|
125
|
+
* @param {string[]} location - The location to remove the template from. Array of two elements.
|
|
126
|
+
* The first element is the name of the template. The second element
|
|
127
|
+
* is optional and is the name of the storage. Defaults to 'default'.
|
|
128
|
+
*
|
|
129
|
+
* @returns {void|string} An error message if the storage or template does not exist.
|
|
130
|
+
*/
|
|
131
|
+
function remove ( location ) {
|
|
132
|
+
const [name, strName='default'] = location;
|
|
68
133
|
if ( !storage[strName] ) return `Error: Storage "${strName}" does not exist.`
|
|
69
134
|
if ( !storage[strName][name] ) return `Error: Template "${name}" does not exist in storage "${strName}".`
|
|
70
135
|
delete storage[strName][name]
|
|
71
136
|
} // remove func.
|
|
72
137
|
|
|
73
138
|
|
|
74
|
-
|
|
139
|
+
// Engine API
|
|
75
140
|
const morphAPI = {
|
|
76
|
-
// Engine API
|
|
77
|
-
/**
|
|
78
|
-
*
|
|
79
|
-
* build -
|
|
80
|
-
* add - register a component to component storage
|
|
81
|
-
* get - get a component from component storage
|
|
82
|
-
* list - list all components in component storage
|
|
83
|
-
* clear - clear all templates in component storage
|
|
84
|
-
* remove - remove a template from component storage
|
|
85
|
-
*
|
|
86
|
-
* shine - extra step to remove all non used placeholders and <rs> tags
|
|
87
|
-
*
|
|
88
|
-
*/
|
|
89
141
|
build // build a component from template description
|
|
90
142
|
, get // get a component from component storage
|
|
91
143
|
, add // add a component to component storage
|
|
@@ -94,8 +146,7 @@ const morphAPI = {
|
|
|
94
146
|
, remove // remove a template from component storage
|
|
95
147
|
} // morphAPI
|
|
96
148
|
|
|
97
|
-
|
|
98
|
-
// - Use compiled versions of simile templates
|
|
149
|
+
|
|
99
150
|
|
|
100
151
|
export default morphAPI
|
|
101
152
|
|
package/src/methods/build.js
CHANGED
|
@@ -10,9 +10,22 @@ import render from './render.js'
|
|
|
10
10
|
|
|
11
11
|
import walk from '@peter.naydenov/walk'
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {Object} Template
|
|
15
|
+
* @property {string} template - Data to be rendered;
|
|
16
|
+
* @property {object} [helpers] - Optional. Object with helper functions or simple templates for this template;
|
|
17
|
+
* @property {object} [handshake] - Optional. Example for data to be rendered with;
|
|
18
|
+
*/
|
|
13
19
|
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
* @param {Template} tpl - template definition;
|
|
24
|
+
* @param {boolean} [extra] - Optional. How to receive the answer - faslse:as a string(answer) or tuple[success, answer];
|
|
25
|
+
* @param {object} [buildDependencies] - Optional. External dependencies injected;
|
|
26
|
+
* @returns {function} - rendering function
|
|
27
|
+
*/
|
|
28
|
+
function build ( tpl, extra=false, buildDependencies={} ) {
|
|
16
29
|
const { hasError, placeholders, chop, helpers, handshake } = _readTemplate ( tpl );
|
|
17
30
|
if ( hasError ) {
|
|
18
31
|
function fail () { return hasError }
|
|
@@ -22,7 +35,23 @@ import walk from '@peter.naydenov/walk'
|
|
|
22
35
|
let cuts = structuredClone ( chop );
|
|
23
36
|
// *** Template recognition complete. Start building the rendering function -->
|
|
24
37
|
|
|
25
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Function to render a template with data.
|
|
40
|
+
* @param {Object} [d={}] - The data to render with. If string, it's a command.
|
|
41
|
+
* @param {Object} [dependencies={}] - The dependencies to use for the rendering.
|
|
42
|
+
* @param {...any} args - The postprocessing functions to apply to the result.
|
|
43
|
+
* @returns {string|string[]} The rendered template.
|
|
44
|
+
* @description
|
|
45
|
+
* If 'd' is a string, it's a command. The available commands are:
|
|
46
|
+
* - 'raw' - returns the original template with placeholders
|
|
47
|
+
* - 'demo' - renders the template with the handshake data
|
|
48
|
+
* - 'handshake' - returns a copy of the handshake data
|
|
49
|
+
* - 'placeholders' - returns the placeholders as a comma separated string
|
|
50
|
+
* If 'd' is an object, it's the data to render with. If it's an array, it's an array of objects to render with.
|
|
51
|
+
* The function returns the rendered template.
|
|
52
|
+
* If 'args' are provided, they are applied to the result in order.
|
|
53
|
+
*/
|
|
54
|
+
function success ( d={}, dependencies={}, ...args ) {
|
|
26
55
|
const
|
|
27
56
|
topLevelType = _defineDataType ( d )
|
|
28
57
|
, endData = []
|
|
@@ -98,15 +127,15 @@ import walk from '@peter.naydenov/walk'
|
|
|
98
127
|
const dType = _defineDataType ( d )
|
|
99
128
|
const routeName = helpers[name]( d );
|
|
100
129
|
if ( routeName == null ) return
|
|
101
|
-
if ( dType === 'object' ) theData[i]['text'] = render ( d, routeName, helpers )
|
|
102
|
-
else theData[i] = render ( d, routeName, helpers )
|
|
130
|
+
if ( dType === 'object' ) theData[i]['text'] = render ( d, routeName, helpers, {...buildDependencies, ...dependencies} )
|
|
131
|
+
else theData[i] = render ( d, routeName, helpers, {...buildDependencies, ...dependencies} )
|
|
103
132
|
})
|
|
104
133
|
break
|
|
105
134
|
case 'object':
|
|
106
|
-
theData['text'] = render ( theData,
|
|
135
|
+
theData['text'] = render ( theData, name, helpers, {...buildDependencies, ...dependencies} )
|
|
107
136
|
break
|
|
108
137
|
case 'primitive':
|
|
109
|
-
nestedData[level] = render ( theData,
|
|
138
|
+
nestedData[level] = render ( theData, name, helpers, {...buildDependencies, ...dependencies} )
|
|
110
139
|
break
|
|
111
140
|
}
|
|
112
141
|
break
|
|
@@ -143,7 +172,7 @@ import walk from '@peter.naydenov/walk'
|
|
|
143
172
|
if ( d == null ) return
|
|
144
173
|
const
|
|
145
174
|
dType = _defineDataType ( d )
|
|
146
|
-
, text = render ( d, name, helpers )
|
|
175
|
+
, text = render ( d, name, helpers, {...buildDependencies, ...dependencies} )
|
|
147
176
|
;
|
|
148
177
|
if ( text == null ) theData[i] = null
|
|
149
178
|
if ( dType === 'object' ) d['text'] = text
|
|
@@ -151,12 +180,12 @@ import walk from '@peter.naydenov/walk'
|
|
|
151
180
|
})
|
|
152
181
|
break
|
|
153
182
|
case 'primitive':
|
|
154
|
-
nestedData[level] = render ( theData, name, helpers )
|
|
183
|
+
nestedData[level] = render ( theData, name, helpers, {...buildDependencies, ...dependencies} )
|
|
155
184
|
break
|
|
156
185
|
case 'object':
|
|
157
186
|
let kTest = Object.keys ( theData ).find ( k => k.includes ( '/' ) ); // Check if keys are breadcrumbs
|
|
158
|
-
if ( kTest ) Object.entries( theData ).forEach( ([k,v]) => v['text'] = render ( v, name, helpers ) )
|
|
159
|
-
else theData['text'] = render ( theData, name, helpers )
|
|
187
|
+
if ( kTest ) Object.entries( theData ).forEach( ([k,v]) => v['text'] = render ( v, name, helpers, {...buildDependencies, ...dependencies} ) )
|
|
188
|
+
else theData['text'] = render ( theData, name, helpers, {...buildDependencies, ...dependencies} )
|
|
160
189
|
break
|
|
161
190
|
} // switch renderDataType
|
|
162
191
|
break;
|
|
@@ -224,7 +253,11 @@ import walk from '@peter.naydenov/walk'
|
|
|
224
253
|
}) // forEach d
|
|
225
254
|
|
|
226
255
|
if ( topLevelType === 'array' ) return endData
|
|
227
|
-
|
|
256
|
+
// Execute postprocess functions
|
|
257
|
+
if (args) return args.reduce ( (acc, fn) => {
|
|
258
|
+
if ( typeof fn !== 'function' ) return acc
|
|
259
|
+
return fn ( acc, {...buildDependencies,...dependencies} )
|
|
260
|
+
}, endData.join ( '' ) )
|
|
228
261
|
else return endData.join ( '' )
|
|
229
262
|
|
|
230
263
|
} // success func.
|
package/src/methods/render.js
CHANGED
|
@@ -2,7 +2,18 @@ import _renderHolder from "./_renderHolder.js"
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* Execute rendering and return the results
|
|
8
|
+
*
|
|
9
|
+
* @param {object|string} theData - Data to be rendered. If it's a string, it's the value of 'text' property.
|
|
10
|
+
* @param {string} name - Name of the render to be executed.
|
|
11
|
+
* @param {object} helpers - Object with helper functions or templates.
|
|
12
|
+
* @param {...any} args - Extra arguments to be passed to the render function.
|
|
13
|
+
*
|
|
14
|
+
* @returns {string} - Rendered string.
|
|
15
|
+
*/
|
|
16
|
+
function render ( theData, name, helpers, ...args ) {
|
|
6
17
|
// *** Executes rendering and return the results
|
|
7
18
|
if ( theData instanceof Object ) { // Make sure all properties are not objects
|
|
8
19
|
Object.entries ( theData ).forEach ( ([key, value]) => {
|
|
@@ -15,7 +26,7 @@ function render ( theData, name, helpers ) {
|
|
|
15
26
|
} // setRenderData func.
|
|
16
27
|
const isRenderFunction = typeof helpers[name] === 'function'; // Render could be a function or template.
|
|
17
28
|
theData = setRenderData ( theData )
|
|
18
|
-
if ( isRenderFunction ) return helpers[name]( theData )
|
|
29
|
+
if ( isRenderFunction ) return helpers[name]( theData, ...args )
|
|
19
30
|
else return _renderHolder ( helpers[name], theData )
|
|
20
31
|
} // render func.
|
|
21
32
|
|