@peter.naydenov/morph 0.0.4 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Changelog.md +9 -0
- package/Migration.guide.md +41 -1
- package/README.md +13 -5
- package/dist/morph.cjs +1 -1
- package/dist/morph.esm.mjs +1 -1
- package/dist/morph.umd.js +1 -1
- package/package.json +4 -4
- package/src/main.js +76 -25
- package/src/methods/build.js +57 -14
- package/src/methods/render.js +13 -2
package/Changelog.md
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
## Release History
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
### 1.0.1 (2025-01-08)
|
|
5
|
+
- [x] Fix: Render functions are not receiving dependencies;
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### 1.0.0 (2024-12-28)
|
|
10
|
+
- [x] Change of addressing templates and stores;
|
|
11
|
+
- [ ] Bug: Render functions are not receiving dependencies;
|
|
12
|
+
|
|
4
13
|
|
|
5
14
|
### 0.0.4 (2017-12-24)
|
|
6
15
|
- [x] Dependency update. @peter.naydenov/walk 5.0.1;
|
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:
|
|
@@ -201,7 +201,15 @@ When input data is array, the result will be an array. Result for each element w
|
|
|
201
201
|
|
|
202
202
|
Learn more about how actions work in the section 'helper functions' below.
|
|
203
203
|
|
|
204
|
+
## Helper Functions
|
|
204
205
|
|
|
206
|
+
Helpers are templates and functions that are used by actions to decorate the data. Helper functions can be used in templates as actions. Action type explains what to expect from the helper function.
|
|
207
|
+
|
|
208
|
+
- `Render functions` should return a string - the data that will replace the placeholder.
|
|
209
|
+
- `Data functions` are created to manipulate the data. Expectation is to return data, that will continue to be used by other actions.
|
|
210
|
+
- `Mixing functions` should merge data in a single data result that will be used by other actions.
|
|
211
|
+
- `Extended render functions` will return a string like regular render functions, but will receive a deep branch of requested data;
|
|
212
|
+
- `Conditional render functions` could return null, that means: ignore this action. The result could be also a string: the name of other helper function that will render the data.
|
|
205
213
|
|
|
206
214
|
|
|
207
215
|
|
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={},...o){const i=s(r),u=[];if("null"===i)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"!==i&&(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 j of y){let{type:k,name:x,level:g}=j,_=b[g],w=s(_);switch(k){case"route":switch(w){case"array":_.forEach(((e,t)=>{if(null==e)return;const r=s(e),a=p[x](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(_,x,p,{...l,...n});break;case"primitive":b[g]=c(_,x,p,{...l,...n})}break;case"data":switch(w){case"array":_.forEach(((e,t)=>_[t]=e instanceof Function?p[x](e()):p[x](e)));break;case"object":case"primitive":b[g]=p[x](_);break;case"function":b[g]=p[x](_())}break;case"render":const T="function"==typeof p[x];switch(w){case"array":T?_.forEach(((e,t)=>{if(null==e)return;const r=s(e),a=p[x](e,{...l,...n});null==a&&(_[t]=null),"object"===r?e.text=a:_[t]=a})):_.forEach(((e,t)=>{if(null==e)return;const r=s(e),a=c(e,x,p,{...l,...n});null==a&&(_[t]=null),"object"===r?e.text=a:_[t]=a}));break;case"primitive":b[g]=c(_,x,p,{...l,...n});break;case"object":Object.keys(_).find((e=>e.includes("/")))?Object.entries(_).forEach((([e,t])=>t.text=c(t,x,p,{...l,...n}))):_.text=c(_,x,p,{...l,...n})}break;case"extendedRender":"function"==typeof p[x]&&(b[g]=p[x](b[0]));break;case"mix":if(""===x)switch(w){case"object":Object.keys(_).find((e=>e.includes("/")))?Object.entries(_).forEach((([e,t])=>b[g][e]=t.text)):b[g]=_.text;for(let O=g-1;O>=0;O--)b[O]=e({data:b[O],objectCallback:S});function S({value:e,breadcrumbs:t}){return b[g][t]?b[g][t]:e}break;case"array":b[g]=_.map((e=>"object"===s(e)?e.text:e)).filter((e=>null!=e)).join("")}else b[g]=p[x](_)}}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":const G=s(v[0]);m[i]="object"===G?v.map((e=>e.text)).join(""):v.join("")}}})),u.push(m.join(""))})),"array"===i?u:o?o.reduce(((e,t)=>"function"!=typeof t?e:t(e,{...l,...n})),u.join("")):u.join("")}return i?[!0,y]:y}}const l={default:{}};const u={build:i,get:function(e){const[t,r="default"]=e;return l[r]?l[r][t]?l[r][t]:function(){return`Error: Template "${t}" does not exist in storage "${r}".`}:function(){return`Error: Storage "${r}" does not exist.`}},add:function(e,t,...r){const[n,a="default"]=e;let o=t,s=!0;if(l[a]||(l[a]={}),"function"!=typeof t){let e=i(t,!0,...r);s=e[0],o=e[1]}s?l[a][n]=o:console.error(`Error: Template "${n}" looks broken and is not added to storage.`)},list:function(e=["default"]){return e.map((e=>l[e]?Object.keys(l[e]):[])).flat()},clear:function(){Object.keys(l).forEach((e=>{"default"!=e?delete l[e]:l.default={}}))},remove:function(e){const[t,r="default"]=e;return l[r]?l[r][t]?void delete l[r][t]:`Error: Template "${t}" does not exist in storage "${r}".`:`Error: Storage "${r}" does not exist.`}};module.exports=u;
|
package/dist/morph.esm.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"@peter.naydenov/walk";import t from"@peter.naydenov/stack";function r(e){return function t(r){const{TG_PRX:a,TG_SFX:o,TG_SIZE_P:s,TG_SIZE_S: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={},...o){const i=s(r),u=[];if("null"===i)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"!==i&&(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 v of y){let{type:k,name:x,level:g}=v,_=b[g],w=s(_);switch(k){case"route":switch(w){case"array":_.forEach(((e,t)=>{if(null==e)return;const r=s(e),a=p[x](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(_,x,p,{...l,...n});break;case"primitive":b[g]=c(_,x,p,{...l,...n})}break;case"data":switch(w){case"array":_.forEach(((e,t)=>_[t]=e instanceof Function?p[x](e()):p[x](e)));break;case"object":case"primitive":b[g]=p[x](_);break;case"function":b[g]=p[x](_())}break;case"render":const T="function"==typeof p[x];switch(w){case"array":T?_.forEach(((e,t)=>{if(null==e)return;const r=s(e),a=p[x](e,{...l,...n});null==a&&(_[t]=null),"object"===r?e.text=a:_[t]=a})):_.forEach(((e,t)=>{if(null==e)return;const r=s(e),a=c(e,x,p,{...l,...n});null==a&&(_[t]=null),"object"===r?e.text=a:_[t]=a}));break;case"primitive":b[g]=c(_,x,p,{...l,...n});break;case"object":Object.keys(_).find((e=>e.includes("/")))?Object.entries(_).forEach((([e,t])=>t.text=c(t,x,p,{...l,...n}))):_.text=c(_,x,p,{...l,...n})}break;case"extendedRender":"function"==typeof p[x]&&(b[g]=p[x](b[0]));break;case"mix":if(""===x)switch(w){case"object":Object.keys(_).find((e=>e.includes("/")))?Object.entries(_).forEach((([e,t])=>b[g][e]=t.text)):b[g]=_.text;for(let O=g-1;O>=0;O--)b[O]=e({data:b[O],objectCallback:S});function S({value:e,breadcrumbs:t}){return b[g][t]?b[g][t]:e}break;case"array":b[g]=_.map((e=>"object"===s(e)?e.text:e)).filter((e=>null!=e)).join("")}else b[g]=p[x](_)}}let E=s(b[0]),j=b[0];switch(E){case"primitive":if(null==j)return;m[i]=j;break;case"object":if(null==j.text)return;m[i]=j.text;break;case"array":const G=s(j[0]);m[i]="object"===G?j.map((e=>e.text)).join(""):j.join("")}}})),u.push(m.join(""))})),"array"===i?u:o?o.reduce(((e,t)=>"function"!=typeof t?e:t(e,{...l,...n})),u.join("")):u.join("")}return i?[!0,y]:y}}const l={default:{}};const u={build:i,get:function(e){const[t,r="default"]=e;return l[r]?l[r][t]?l[r][t]:function(){return`Error: Template "${t}" does not exist in storage "${r}".`}:function(){return`Error: Storage "${r}" does not exist.`}},add:function(e,t,...r){const[n,a="default"]=e;let o=t,s=!0;if(l[a]||(l[a]={}),"function"!=typeof t){let e=i(t,!0,...r);s=e[0],o=e[1]}s?l[a][n]=o:console.error(`Error: Template "${n}" looks broken and is not added to storage.`)},list:function(e=["default"]){return e.map((e=>l[e]?Object.keys(l[e]):[])).flat()},clear:function(){Object.keys(l).forEach((e=>{"default"!=e?delete l[e]:l.default={}}))},remove:function(e){const[t,r="default"]=e;return l[r]?l[r][t]?void delete l[r][t]:`Error: Template "${t}" does not exist in storage "${r}".`:`Error: Storage "${r}" does not exist.`}};export{u as default};
|
package/dist/morph.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@peter.naydenov/walk")):"function"==typeof define&&define.amd?define(["@peter.naydenov/walk"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).morph=t(e.walk)}(this,(function(e){"use strict";function t(e){return function t(
|
|
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(r){const{TG_PRX:o,TG_SFX:a,TG_SIZE_P:i,TG_SIZE_S:s}=e;let c,l,u,f=[];if("string"!=typeof r)return n("notAString");if(0==r.length)return[];if(c=r.indexOf(o),0<c&&f.push(r.slice(0,c)),-1==c)return f.push(r),f;{if(u=r.indexOf(o,c+i),l=r.indexOf(a),-1==l)return n("missingClosing");if(l<c)return n("closedBeforeOpened");if(l+=s,-1!=u&&u<l)return n("newBeforeClosed");f.push(r.slice(c,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 r(t){const n={};let r=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 r=o.split("/").length-1,isNaN(e)||(a=!0),n[r]||(n[r]=a?[]:{}),"root"===e?n[r]=t:a?n[r].push(t):n[r][o]=t,t}}),{dataDeepLevel:r,nestedData:n}}function*o(e,t){let n=function(e={}){let t=[],{type:n,limit:r,onLimit:o}=Object.assign({},{type:"FIFO",limit:!1,onLimit:"update"},e),a="LIFO"===n.toUpperCase(),i=!1;function s(e=1,n=0){let r=[];return n>0&&Array.from({length:n}).map((()=>t.pop())),1==e?t.pop():(Array.from({length:e}).map((()=>{let e=t.pop();null!=e&&r.push(e)})),r)}function c(e=1,n=0){let r=[],o=t.length-n;return e>1&&Array.from({length:e}).map((()=>{null!=t[o-1]&&r.push(t[o-1]),o--})),1==e?t[t.length-1]:r}function l(){}return l.prototype={pull:s,pullReverse:function(e=1,t=0){let n=s(e,t);return n instanceof Array?n.reverse():n},peek:c,peekReverse:function(e=1,t=0){const n=c(e,t);return n instanceof Array?n.reverse():n},getSize:()=>t.length,isEmpty:()=>0==t.length,reset:()=>(t=[],!0),debug:()=>[...t]},l.prototype.push=a?function(e){const n=e instanceof Array,a=n?e.length:1;let c=!1;if("full"!==o||!i){if(r&&n&&a>r&&(e=e.slice(0,-a+r)),r){const a=(n?e.length:1)+t.length;a>=r&&"full"===o&&(e=e.slice(0,-(a-r))),a>=r&&"update"===o&&(c=s(a-r))}return t=e instanceof Array?t.concat(e):t.concat([e]),i=!!r&&t.length===r,c||void 0}}:function(e){const n=e instanceof Array,a=n?e.length:1;let c=!1;if("full"!==o||!i){if(r&&n&&a>r&&(e=e.slice(a-r)),r){const a=(n?e.length:1)+t.length;a>=r&&"full"===o&&(e=e.slice(0,-(a-r))),a>=r&&"update"===o&&(c=s(a-r))}return t=n?e.reduce(((e,t)=>[t,...e]),t):[e].reduce(((e,t)=>[t,...e]),t),i=!!r&&t.length===r,c||void 0}},new l}({type:"LIFO"});for(let r=0;r<=t;r++)n.push(e[r]);for(;n&&!n.isEmpty();){let e=yield n.pull();e&&n.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,n,r,...o){e instanceof Object&&Object.entries(e).forEach((([t,n])=>{n instanceof Object&&(e[t]=n.text)}));const i="function"==typeof r[n];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),i?r[n](e,...o):function(e,n){if(null==n)return null;const r=t(a)(e),o=a;return r.forEach(((e,t)=>{if(e.includes(o.TG_PRX)){const a=e.replace(o.TG_PRX,"").replace(o.TG_SFX,"").trim();n[a]&&(r[t]=n[a])}})),r.join("")}(r[n],e)}function c(n,c=!1,l={}){const{hasError:u,placeholders:f,chop:p,helpers:d,handshake:h}=function(e){const{template:n,helpers:r={},handshake:o}=e,{TG_PRX:i,TG_SFX:s,TG_SIZE_P:c,TG_SIZE_S:l}=a,u=[];let f=null;const p=t(a)(n);return"string"==typeof p?f=p:p.forEach(((e,t)=>{const n=RegExp(i+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?"+s,"g");if(e.includes(i)){const o=n.exec(e);u.push({index:t,data:(r=o[1],r||null),action:o[2]?o[2].split(",").map((e=>e.trim())):null})}var r})),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||!!r[e]||(f=`Error: Missing helper: ${e}`,!1))))})),{hasError:f,placeholders:u,chop:p,helpers:r,handshake:o}}(n);if(u){function y(){return u}return c?[!1,y]:y}{let m=structuredClone(p);function b(t={},n={},...a){const c=i(t),u=[];if("null"===c)return m.join("");if("string"==typeof t)switch(t){case"raw":return m.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=>m[e.index])).join(", ");default:return`Error: Wrong command "${t}". Available commands: raw, demo, handshake, placeholders.`}return"array"!==c&&(t=[t]),t.forEach((t=>{f.forEach((a=>{const{index:c,data:u,action:f}=a;if(!f&&u){const p=t[u];switch(i(p)){case"function":return void(m[c]=p());case"primitive":return void(m[c]=p);case"array":return void("primitive"===i(p[0])&&(m[c]=p[0]));case"object":return void(p.text&&(m[c]=p.text))}}else{const{dataDeepLevel:h,nestedData:y}=r("@all"===u||null===u||"@root"===u?t:t[u]),b=o(function(e,t=10){let n={},r=0,o=[...e],a=0;do{n[a]=[],a++}while(a<=t);return o.every((e=>"#"===e?(r++,!(r>t)):e.startsWith("?")?(n[r].push({type:"route",name:e.replace("?",""),level:r}),!0):e.startsWith("+")?(n[r].push({type:"extendedRender",name:e.replace("+",""),level:r}),!0):e.startsWith("[]")?(n[r].push({type:"mix",name:e.replace("[]",""),level:r}),!0):e.startsWith(">")?(n[r].push({type:"data",name:e.replace(">",""),level:r}),!0):(""===e||n[r].push({type:"render",name:e,level:r}),!0))),n}(f,h),h);for(let E of b){let{type:j,name:k,level:x}=E,w=y[x],T=i(w);switch(j){case"route":switch(T){case"array":w.forEach(((e,t)=>{if(null==e)return;const r=i(e),o=d[k](e);null!=o&&("object"===r?w[t].text=s(e,o,d,{...l,...n}):w[t]=s(e,o,d,{...l,...n}))}));break;case"object":w.text=s(w,k,d,{...l,...n});break;case"primitive":y[x]=s(w,k,d,{...l,...n})}break;case"data":switch(T){case"array":w.forEach(((e,t)=>w[t]=e instanceof Function?d[k](e()):d[k](e)));break;case"object":case"primitive":y[x]=d[k](w);break;case"function":y[x]=d[k](w())}break;case"render":const _="function"==typeof d[k];switch(T){case"array":_?w.forEach(((e,t)=>{if(null==e)return;const r=i(e),o=d[k](e,{...l,...n});null==o&&(w[t]=null),"object"===r?e.text=o:w[t]=o})):w.forEach(((e,t)=>{if(null==e)return;const r=i(e),o=s(e,k,d,{...l,...n});null==o&&(w[t]=null),"object"===r?e.text=o:w[t]=o}));break;case"primitive":y[x]=s(w,k,d,{...l,...n});break;case"object":Object.keys(w).find((e=>e.includes("/")))?Object.entries(w).forEach((([e,t])=>t.text=s(t,k,d,{...l,...n}))):w.text=s(w,k,d,{...l,...n})}break;case"extendedRender":"function"==typeof d[k]&&(y[x]=d[k](y[0]));break;case"mix":if(""===k)switch(T){case"object":Object.keys(w).find((e=>e.includes("/")))?Object.entries(w).forEach((([e,t])=>y[x][e]=t.text)):y[x]=w.text;for(let S=x-1;S>=0;S--)y[S]=e({data:y[S],objectCallback:O});function O({value:e,breadcrumbs:t}){return y[x][t]?y[x][t]:e}break;case"array":y[x]=w.map((e=>"object"===i(e)?e.text:e)).filter((e=>null!=e)).join("")}else y[x]=d[k](w)}}let g=i(y[0]),v=y[0];switch(g){case"primitive":if(null==v)return;m[c]=v;break;case"object":if(null==v.text)return;m[c]=v.text;break;case"array":const G=i(v[0]);m[c]="object"===G?v.map((e=>e.text)).join(""):v.join("")}}})),u.push(m.join(""))})),"array"===c?u:a?a.reduce(((e,t)=>"function"!=typeof t?e:t(e,{...l,...n})),u.join("")):u.join("")}return c?[!0,b]:b}}const l={default:{}};return{build:c,get:function(e){const[t,n="default"]=e;return l[n]?l[n][t]?l[n][t]:function(){return`Error: Template "${t}" does not exist in storage "${n}".`}:function(){return`Error: Storage "${n}" does not exist.`}},add:function(e,t,...n){const[r,o="default"]=e;let a=t,i=!0;if(l[o]||(l[o]={}),"function"!=typeof t){let e=c(t,!0,...n);i=e[0],a=e[1]}i?l[o][r]=a:console.error(`Error: Template "${r}" looks broken and is not added to storage.`)},list:function(e=["default"]){return e.map((e=>l[e]?Object.keys(l[e]):[])).flat()},clear:function(){Object.keys(l).forEach((e=>{"default"!=e?delete l[e]:l.default={}}))},remove:function(e){const[t,n="default"]=e;return l[n]?l[n][t]?void delete l[n][t]:`Error: Template "${t}" does not exist in storage "${n}".`:`Error: Storage "${n}" 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": "
|
|
4
|
+
"version": "1.0.1",
|
|
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/*",
|
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,29 @@ 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
|
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {Array} tupleResult
|
|
22
|
+
* @property {boolean} 0 - Indicates success (true) or failure (false).
|
|
23
|
+
* @property {function} 1 - The rendering function or an error function.
|
|
24
|
+
*/
|
|
14
25
|
|
|
15
|
-
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
*
|
|
30
|
+
* @param {Template} tpl - template definition;
|
|
31
|
+
* @param {boolean} [extra] - Optional. How to receive the answer - faslse:as a string(answer) or tuple[success, answer];
|
|
32
|
+
* @param {object} [buildDependencies] - Optional. External dependencies injected;
|
|
33
|
+
* @returns {function|tupleResult} - rendering function
|
|
34
|
+
*/
|
|
35
|
+
function build ( tpl, extra=false, buildDependencies={} ) {
|
|
16
36
|
const { hasError, placeholders, chop, helpers, handshake } = _readTemplate ( tpl );
|
|
17
37
|
if ( hasError ) {
|
|
18
38
|
function fail () { return hasError }
|
|
@@ -22,7 +42,23 @@ import walk from '@peter.naydenov/walk'
|
|
|
22
42
|
let cuts = structuredClone ( chop );
|
|
23
43
|
// *** Template recognition complete. Start building the rendering function -->
|
|
24
44
|
|
|
25
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Function to render a template with data.
|
|
47
|
+
* @param {Object} [d={}] - The data to render with. If string, it's a command.
|
|
48
|
+
* @param {Object} [dependencies={}] - The dependencies to use for the rendering.
|
|
49
|
+
* @param {...any} args - The postprocessing functions to apply to the result.
|
|
50
|
+
* @returns {string|string[]} The rendered template.
|
|
51
|
+
* @description
|
|
52
|
+
* If 'd' is a string, it's a command. The available commands are:
|
|
53
|
+
* - 'raw' - returns the original template with placeholders
|
|
54
|
+
* - 'demo' - renders the template with the handshake data
|
|
55
|
+
* - 'handshake' - returns a copy of the handshake data
|
|
56
|
+
* - 'placeholders' - returns the placeholders as a comma separated string
|
|
57
|
+
* 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.
|
|
58
|
+
* The function returns the rendered template.
|
|
59
|
+
* If 'args' are provided, they are applied to the result in order.
|
|
60
|
+
*/
|
|
61
|
+
function success ( d={}, dependencies={}, ...args ) {
|
|
26
62
|
const
|
|
27
63
|
topLevelType = _defineDataType ( d )
|
|
28
64
|
, endData = []
|
|
@@ -98,15 +134,15 @@ import walk from '@peter.naydenov/walk'
|
|
|
98
134
|
const dType = _defineDataType ( d )
|
|
99
135
|
const routeName = helpers[name]( d );
|
|
100
136
|
if ( routeName == null ) return
|
|
101
|
-
if ( dType === 'object' ) theData[i]['text'] = render ( d, routeName, helpers )
|
|
102
|
-
else theData[i] = render ( d, routeName, helpers )
|
|
137
|
+
if ( dType === 'object' ) theData[i]['text'] = render ( d, routeName, helpers, {...buildDependencies, ...dependencies} )
|
|
138
|
+
else theData[i] = render ( d, routeName, helpers, {...buildDependencies, ...dependencies} )
|
|
103
139
|
})
|
|
104
140
|
break
|
|
105
141
|
case 'object':
|
|
106
|
-
theData['text'] = render ( theData,
|
|
142
|
+
theData['text'] = render ( theData, name, helpers, {...buildDependencies, ...dependencies} )
|
|
107
143
|
break
|
|
108
144
|
case 'primitive':
|
|
109
|
-
nestedData[level] = render ( theData,
|
|
145
|
+
nestedData[level] = render ( theData, name, helpers, {...buildDependencies, ...dependencies} )
|
|
110
146
|
break
|
|
111
147
|
}
|
|
112
148
|
break
|
|
@@ -134,7 +170,7 @@ import walk from '@peter.naydenov/walk'
|
|
|
134
170
|
if ( isRenderFunction ) theData.forEach ( (d,i) => {
|
|
135
171
|
if ( d == null ) return
|
|
136
172
|
const dType = _defineDataType ( d );
|
|
137
|
-
const text = helpers[name]( d );
|
|
173
|
+
const text = helpers[name]( d, {...buildDependencies, ...dependencies} );
|
|
138
174
|
if ( text == null ) theData[i] = null
|
|
139
175
|
if ( dType === 'object' ) d['text'] = text
|
|
140
176
|
else theData[i] = text
|
|
@@ -143,7 +179,7 @@ import walk from '@peter.naydenov/walk'
|
|
|
143
179
|
if ( d == null ) return
|
|
144
180
|
const
|
|
145
181
|
dType = _defineDataType ( d )
|
|
146
|
-
, text = render ( d, name, helpers )
|
|
182
|
+
, text = render ( d, name, helpers, {...buildDependencies, ...dependencies} )
|
|
147
183
|
;
|
|
148
184
|
if ( text == null ) theData[i] = null
|
|
149
185
|
if ( dType === 'object' ) d['text'] = text
|
|
@@ -151,12 +187,12 @@ import walk from '@peter.naydenov/walk'
|
|
|
151
187
|
})
|
|
152
188
|
break
|
|
153
189
|
case 'primitive':
|
|
154
|
-
nestedData[level] = render ( theData, name, helpers )
|
|
190
|
+
nestedData[level] = render ( theData, name, helpers, {...buildDependencies, ...dependencies} )
|
|
155
191
|
break
|
|
156
192
|
case 'object':
|
|
157
193
|
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 )
|
|
194
|
+
if ( kTest ) Object.entries( theData ).forEach( ([k,v]) => v['text'] = render ( v, name, helpers, {...buildDependencies, ...dependencies} ) )
|
|
195
|
+
else theData['text'] = render ( theData, name, helpers, {...buildDependencies, ...dependencies} )
|
|
160
196
|
break
|
|
161
197
|
} // switch renderDataType
|
|
162
198
|
break;
|
|
@@ -202,6 +238,7 @@ import walk from '@peter.naydenov/walk'
|
|
|
202
238
|
break
|
|
203
239
|
}
|
|
204
240
|
} // for step of actSetup
|
|
241
|
+
|
|
205
242
|
let accType = _defineDataType ( nestedData[0] )
|
|
206
243
|
let fineData = nestedData[0]
|
|
207
244
|
|
|
@@ -215,16 +252,22 @@ import walk from '@peter.naydenov/walk'
|
|
|
215
252
|
cuts[index] = fineData['text']
|
|
216
253
|
break
|
|
217
254
|
case 'array':
|
|
218
|
-
|
|
255
|
+
const aType = _defineDataType ( fineData[0] )
|
|
256
|
+
if ( aType === 'object' ) cuts[index] = fineData.map ( x => x.text ).join ( '')
|
|
257
|
+
else cuts[index] = fineData.join ( '' )
|
|
219
258
|
break
|
|
220
259
|
} // switch accType
|
|
221
260
|
} // else other
|
|
222
|
-
}) // forEach placeholders
|
|
261
|
+
}) // forEach placeholders
|
|
223
262
|
endData.push ( cuts.join ( '' ))
|
|
224
263
|
}) // forEach d
|
|
225
264
|
|
|
226
265
|
if ( topLevelType === 'array' ) return endData
|
|
227
|
-
|
|
266
|
+
// Execute postprocess functions
|
|
267
|
+
if (args) return args.reduce ( (acc, fn) => {
|
|
268
|
+
if ( typeof fn !== 'function' ) return acc
|
|
269
|
+
return fn ( acc, {...buildDependencies,...dependencies} )
|
|
270
|
+
}, endData.join ( '' ) )
|
|
228
271
|
else return endData.join ( '' )
|
|
229
272
|
|
|
230
273
|
} // 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
|
|