@peter.naydenov/morph 2.1.3 → 3.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 +39 -0
- package/README.md +63 -68
- package/dist/morph.cjs +1 -1
- package/dist/morph.esm.mjs +1 -1
- package/dist/morph.umd.js +1 -1
- package/package.json +3 -3
- package/src/methods/_readTemplate.js +27 -21
- package/src/methods/build.js +75 -45
package/Changelog.md
CHANGED
package/Migration.guide.md
CHANGED
|
@@ -1,6 +1,45 @@
|
|
|
1
1
|
# Migration Guides
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## 2.x.x -> 3.x.x
|
|
5
|
+
The `render` function now takes a command as its first argument. Available commands are: `render`, `debug`, and `snippets`. Other arguments have no changes. Just shifted right. The second argument becomes the data, the third is dependencies, and the fourth is a list of post-processing functions.
|
|
6
|
+
|
|
7
|
+
In version 3.x.x(second argument), the data can be a string, as in version 2.x.x(first argument). The term "command" is no longer used for this argument; instead, it is called "instructions". Available instructions include: `raw`, `demo`, `handshake`, and `placeholders`.
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
// To render the template with internal 'handshake' data
|
|
11
|
+
// Before
|
|
12
|
+
myTemplate ( 'demo' )
|
|
13
|
+
// After 3.x.x
|
|
14
|
+
myTemplate ( 'render', 'demo' )
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
// To show list of placeholders
|
|
18
|
+
// Before
|
|
19
|
+
myTemplate ( 'placeholders' )
|
|
20
|
+
// After 3.x.x
|
|
21
|
+
myTemplate ( 'debug', 'placeholders' )
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
// To see the handshake data
|
|
25
|
+
// Before
|
|
26
|
+
myTemplate ( 'handshake' )
|
|
27
|
+
// After 3.x.x
|
|
28
|
+
myTemplate ( 'debug', 'handshake' )
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
// Functions that don't relay on external data and are called without arguments have no changes
|
|
32
|
+
// Before
|
|
33
|
+
myTemplate ()
|
|
34
|
+
// After 3.x.x
|
|
35
|
+
myTemplate ()
|
|
36
|
+
// command 'render' is by default
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
That's it!
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
4
43
|
## 1.x.x -> 2.x.x
|
|
5
44
|
Modification of data is available only for current placeholder. If you need to remember changes in data, use the new memory action - '^something' where '^' is for memory and 'something' is the name. Memory will make a snapshot of the current data and will be available in helper functions. If you need to provide changes to all placeholders, use overwrite action. It's a snapshot that will be remember as a main data and will be available for all placeholders.
|
|
6
45
|
|
package/README.md
CHANGED
|
@@ -8,13 +8,15 @@
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
## What's new in version
|
|
12
|
-
- Data helper functions modifies the data per placeholder;
|
|
13
|
-
- Arguments for helper functions are named arguments;
|
|
14
|
-
- Memory action introduced - memory is available in helper functions as a named argument;
|
|
15
|
-
- Overwrite action introduced - when change in data should be available for all placeholders;
|
|
16
|
-
- Deep data-sources ( after version 2.1.0 );
|
|
11
|
+
## What's new in version 3.x.x
|
|
17
12
|
|
|
13
|
+
In version 3, you can choose to render only certain placeholders or groups of placeholders from a template. This lets you use templates as collections of reusable templates, so you can extract and use just the parts you need without having to render the whole template. This makes it easier to create and manage reusable template libraries for your project.
|
|
14
|
+
|
|
15
|
+
The `render` function now takes a command as its first argument. Available commands are: `render`, `debug`, and `snippets`. Other arguments have no changes. Just shifted right. The second argument becomes the data, the third is dependencies, and the fourth is a list of post-processing functions.
|
|
16
|
+
|
|
17
|
+
In version 3.x.x, the data is always the second argument. It can be a string, as in version 2.x.x. The term "command" is no longer used for this argument; instead, it is called "instructions". Available instructions include: `raw`, `demo`, `handshake`, and `placeholders`.
|
|
18
|
+
|
|
19
|
+
How to migrate to version 3.x.x, please read the [Migration guide](./Migration.guide.md). Read more about snippets down below.
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
|
|
@@ -73,10 +75,10 @@ const myTemplateDescription = {
|
|
|
73
75
|
name : 'Ivan'
|
|
74
76
|
}
|
|
75
77
|
}
|
|
76
|
-
const myTemplate = morph.build ( myTemplateDescription );
|
|
77
|
-
const htmlBlock = myTemplate ( { name: 'Peter' } )
|
|
78
|
+
const myTemplate = morph.build ( myTemplateDescription ); // myTemplate is a render function
|
|
79
|
+
const htmlBlock = myTemplate ( 'render', { name: 'Peter' } ) // Provide data to the render function and get the result
|
|
78
80
|
// htmlBlock === 'Hello, Peter!'
|
|
79
|
-
const demo = myTemplate ( 'demo' )
|
|
81
|
+
const demo = myTemplate ( 'render', 'demo' )
|
|
80
82
|
// demo === 'Hello, Ivan!'
|
|
81
83
|
```
|
|
82
84
|
|
|
@@ -90,11 +92,11 @@ morph.add ( ['myTemplate'], myTemplateDescription )
|
|
|
90
92
|
const htmlBlock = morph.get ( ['myTemplate'] )({ name: 'Peter' })
|
|
91
93
|
// it's same as text above
|
|
92
94
|
morph.add ( ['myTemplate', 'default'], myTemplateDescription )
|
|
93
|
-
const htmlBlock = morph.get ( ['myTemplate', 'default'] )({ name: 'Peter' })
|
|
95
|
+
const htmlBlock = morph.get ( ['myTemplate', 'default'] )( 'render', { name: 'Peter' })
|
|
94
96
|
// if we use custom storage:
|
|
95
97
|
morph.add ( ['myTemplate', 'hidden'], myTemplateDescription ) // write template in storage 'hidden'
|
|
96
|
-
const htmlBlock = morph.get ( ['myTemplate', 'hidden'] )({ name: 'Peter' }) // render template from 'hidden' storage
|
|
97
|
-
morph.get ( ['myTemplate'] )({ name: 'Peter' }) // call template 'myTemplate' from default storage
|
|
98
|
+
const htmlBlock = morph.get ( ['myTemplate', 'hidden'] )( 'render', { name: 'Peter' }) // render template from 'hidden' storage
|
|
99
|
+
morph.get ( ['myTemplate'] )('render', { name: 'Peter' }) // call template 'myTemplate' from default storage
|
|
98
100
|
// will return error, because default storage does not have template "myTemplate"
|
|
99
101
|
```
|
|
100
102
|
|
|
@@ -117,7 +119,7 @@ const myTemplateDescription = {
|
|
|
117
119
|
}
|
|
118
120
|
}
|
|
119
121
|
const myTemplate = morph.build ( myTemplateDescription );
|
|
120
|
-
const htmlBlock = myTemplate ( { person: {
|
|
122
|
+
const htmlBlock = myTemplate ( 'render', { person: {
|
|
121
123
|
name: 'Peter'
|
|
122
124
|
, age : 40
|
|
123
125
|
, web : 'example.com'
|
|
@@ -198,36 +200,17 @@ Template placeholders can contain data-source and actions separated by ':'. Data
|
|
|
198
200
|
// placeholder should take data from field 'name', execute 'act1' and 'act2' over it
|
|
199
201
|
// actions are separated by ',' and are executed from right to left
|
|
200
202
|
|
|
203
|
+
// placeholder could have a name. It's optional and is in the end of the placeholder definition separated by ':'
|
|
204
|
+
`{{ name : act2, act1 : placeholderName }}`
|
|
205
|
+
// Placeholder names are useful when we want to render only few of them and we preffer to call them by name
|
|
206
|
+
|
|
201
207
|
`{{ list : li, a }}`
|
|
202
208
|
// take data from 'list' and render each element first with 'a' then with 'li' actions
|
|
203
209
|
|
|
204
210
|
`{{ name }}` // render data from 'name'. Only data is provided to this placeholder
|
|
205
211
|
`{{ :someAction}}` // no data, but the result of the action will fill the placeholder
|
|
206
212
|
`{{ @all : someAction }}` // provide all the data to the action 'someAction'
|
|
207
|
-
|
|
208
|
-
### Deep data-sources ( after version 2.1.0 )
|
|
209
|
-
|
|
210
|
-
Setup a deep data-source by using breadcrumbs.
|
|
211
|
-
```js
|
|
212
|
-
const myTpl = {
|
|
213
|
-
template : `Profile: {{ me/stats : line }}.` // data-source will be data.me.stats
|
|
214
|
-
, helpers: {
|
|
215
|
-
line: `({{ height}}cm,{{ weight}}kg)`
|
|
216
|
-
}
|
|
217
|
-
};
|
|
218
|
-
const data = {
|
|
219
|
-
me : {
|
|
220
|
-
name: 'Peter'
|
|
221
|
-
, stats : {
|
|
222
|
-
age: 50
|
|
223
|
-
, height: 180
|
|
224
|
-
, weight: 66
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
};
|
|
228
|
-
const templateFn = morph.build ( myTpl );
|
|
229
|
-
const result = templateFn ( data );
|
|
230
|
-
// ---> Profile: (180cm,66kg).
|
|
213
|
+
`{{:someAction : placeName }}` // action 'someAction' will fullfill content of placeholder and placeholder name will be 'placeName'
|
|
231
214
|
```
|
|
232
215
|
|
|
233
216
|
|
|
@@ -276,40 +259,52 @@ Helpers are templates and functions that are used by actions to decorate the dat
|
|
|
276
259
|
|
|
277
260
|
|
|
278
261
|
|
|
279
|
-
##
|
|
262
|
+
## Commands
|
|
263
|
+
The first argument of the render function is the command. Available commands are: `render`, `debug`, and `snippets`. Default command is `render` so if template doesn't need external information we can call the function without arguments.
|
|
280
264
|
|
|
281
|
-
### Modify root data before start rendering
|
|
282
|
-
Sometimes we need to modify data and modification should be valid for all placeholders. Add in the begining of the template a placeholder like `{{ : blank, ^^, >myModification }}`, where myModification is a helper function that will modify the data, `^^` is overwrite action and `blank` is a render helper function that will return an empty string (placeholder disapears ). Look at the example here:
|
|
283
265
|
|
|
266
|
+
## Snippets
|
|
267
|
+
Snippets are a way to render only specific placeholders instead of always rerendering the entire template. Render function arguments were changed in version 3.x.x to serve this purpose.
|
|
268
|
+
|
|
269
|
+
How to access snippets:
|
|
284
270
|
```js
|
|
285
|
-
const
|
|
286
|
-
template
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
271
|
+
const template = {
|
|
272
|
+
template:`
|
|
273
|
+
<h1>{{title}}</h1>
|
|
274
|
+
<p>{{description}}</p>
|
|
275
|
+
<div class="contact">
|
|
276
|
+
{{ name : setupName : theName }}
|
|
277
|
+
</div>
|
|
278
|
+
<p>{{ tags : +comma : tagList }}</p>
|
|
279
|
+
`,
|
|
280
|
+
helpers: {
|
|
281
|
+
setupName : ( {data} ) => `${data.name} ${data.surname}`,
|
|
282
|
+
comma : ({data}) => data.map ( tag => `<span>${tag}</span>` ).join ( ',' )
|
|
283
|
+
},
|
|
284
|
+
handshake: {
|
|
285
|
+
title : 'Contacts',
|
|
286
|
+
description : 'Contact description text',
|
|
287
|
+
name : { name: 'Ivan', surname: 'Petrov' },
|
|
288
|
+
tags : ['tag1', 'tag2', 'tag3'],
|
|
289
|
+
}
|
|
290
|
+
} // template
|
|
291
|
+
|
|
292
|
+
const fn = morph.build ( template );
|
|
293
|
+
|
|
294
|
+
let res1 = fn ( 'snippets', 'demo' )
|
|
295
|
+
// will return a string with the render results of all placeholders separated by '<~>' string
|
|
296
|
+
// `Contacts<~>Contact description text<~>Ivan Petrov<~><span>tag1</span>,<span>tag2</span>,<span>tag3</span><~>`
|
|
297
|
+
let res2 = fn ( 'snippets:theName', 'demo' )
|
|
298
|
+
// will return a string with the render result of 'name' placeholder. No delimiter because is only one placeholder
|
|
299
|
+
// `Ivan Petrov`
|
|
300
|
+
|
|
301
|
+
let res3 = fn ( 'snippets:theName,tagList', 'demo' )
|
|
302
|
+
// will return a string with the render results of 'name' and 'tags' placeholders separated by '<~>' string
|
|
303
|
+
// `Ivan Petrov<~><span>tag1</span>,<span>tag2</span>,<span>tag3</span>`
|
|
304
|
+
|
|
305
|
+
// snippets can be accessed also with index - starting from 0. Index mean the order of appearance of placeholders in the template.
|
|
306
|
+
let res4 = fn ( 'snippets:2,3', 'demo' )
|
|
307
|
+
// it's the same as res3. Use names or indexes according to your preferences. With indexes placeholder will not need to have a name.
|
|
313
308
|
```
|
|
314
309
|
|
|
315
310
|
|
package/dist/morph.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("@peter.naydenov/walk"),t=require("@peter.naydenov/stack");function r(e){return function t(r){const{TG_PRX:a,TG_SFX:o,TG_SIZE_P:s,TG_SIZE_S:
|
|
1
|
+
"use strict";var e=require("@peter.naydenov/walk"),t=require("@peter.naydenov/stack");function r(e){return function t(r){const{TG_PRX:a,TG_SFX:o,TG_SIZE_P:s,TG_SIZE_S:i}=e;let l,c,u,d=[];if("string"!=typeof r)return n("notAString");if(0==r.length)return[];if(l=r.indexOf(a),0<l&&d.push(r.slice(0,l)),-1==l)return d.push(r),d;{if(u=r.indexOf(a,l+s),c=r.indexOf(o),-1==c)return n("missingClosing");if(c<l)return n("closedBeforeOpened");if(c+=i,-1!=u&&u<c)return n("newBeforeClosed");d.push(r.slice(l,c));let e=t(r.slice(c));return d.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."}}var a={TG_PRX:"{{",TG_SFX:"}}",TG_SIZE_P:2,TG_SIZE_S:2};function o(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,t,n,...o){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text),r instanceof Array&&(e[t]=r[0])}));const s="function"==typeof n[t];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),s?n[t](e,...o):function(e,t){if(null==t)return null;const n=r(a)(e),o=a;return n.forEach(((e,r)=>{if(e.includes(o.TG_PRX)){const a=e.replace(o.TG_PRX,"").replace(o.TG_SFX,"").trim();t.hasOwnProperty(a)&&null!=t[a]&&(n[r]=t[a])}})),n.join("")}(n[t],e)}function i(n,i=!1,l={}){let{hasError:c,placeholders:u,chop:d,helpers:f,handshake:p,snippets:h}=function(e){const{template:t,helpers:n={},handshake:o}=e,{TG_PRX:s,TG_SFX:i}=a,l=[],c={},u="string"==typeof t?t.replace(/<!--[\s\S]*?-->/g,"").replace(/\s{2,}/g," "):t;let d=null;const f=r(a)(u);return"string"==typeof f?d=f:f.forEach(((e,t)=>{const r=RegExp(s+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?(?::\\s*(.*?)\\s*)?"+i,"g");if(e.includes(s)){const a=r.exec(e);if(!a)return;let o={index:t,data:(n=a[1],n||null),action:a[2]?a[2].split(",").map((e=>e.trim())):null,name:a[3]?a[3].trim():null};l.push(o),c[l.length-1]=o,o.name&&(c[o.name]=o)}var n})),l.forEach((e=>{e.action&&e.action.every((e=>"#"===e||"^^"===e||!(!e.startsWith("^")||"^^"===e)||(e.startsWith("?")&&(e=e.replace("?","")),e.startsWith("+")&&(e=e.replace("+","")),e.startsWith("[]")&&(e=e.replace("[]","")),e.startsWith(">")&&(e=e.replace(">","")),""===e||!!n[e]||(d=`Error: Missing helper: ${e}`,!1))))})),{hasError:d,placeholders:l,chop:f,helpers:n,handshake:o,snippets:c}}(n);if(c){function m(){return c}return i?[!1,m]:m}{let b=structuredClone(d);function y(r="render",n={},a={},...i){let c=!1;if(!["render","debug","snippets"].includes(r)&&!r.startsWith("snippets"))return`Error: Wrong command "${r}". Available commands: render, debug, snippets.`;if(r.startsWith("snippets")&&r.includes(":")){c=!0;let e=r.split(":").slice(1)[0].trim().split(",").map((e=>e.trim()));u=e.map((e=>h[e]))}else"snippets"===r&&(c=!0);if("string"==typeof n)switch(n){case"raw":return b.join("");case"demo":if(!p)return"Error: No handshake data.";n=p;break;case"handshake":return p?structuredClone(p):"Error: No handshake data.";case"placeholders":return u.map((e=>b[e.index])).join(", ");default:return`Error: Wrong instruction "${n}". Available instructions: raw, demo, handshake, placeholders.`}const d=[],m={};let y=o(n),g={...l,...a};return n=e({data:n}),"null"===y?b.join(""):("array"!==y&&(n=[n]),"null"===y?b.join(""):(n.forEach((r=>{u.forEach((n=>{const{index:a,data:i,action:l}=n,c=!l&&i,u=structuredClone(m),d={dependencies:g,memory:u};let p=r;if(i&&i.includes("/")?p.hasOwnProperty(i)?p=p[i]:i.split("/").forEach((e=>{p=p.hasOwnProperty(e)?p[e]:[]})):"@all"===i||null===i||"@root"===i?p=r:i&&(p=p[i]),c){switch(o(p)){case"function":return void(b[a]=p());case"primitive":return void(b[a]=p);case"array":return void("primitive"===o(p[0])&&(b[a]=p[0]));case"object":return void(p.text&&(b[a]=p.text))}}else{let{dataDeepLevel:n,nestedData:i}=function(t,r){const n=[];let a=0;if(t instanceof Function)return{dataDeepLevel:0,nestedData:[[t()]]};if(null==t)return{dataDeepLevel:0,nestedData:[null]};if("string"==typeof t)return{dataDeepLevel:0,nestedData:[[t]]};const o=structuredClone(t);return r.includes("#")?(e({data:o,objectCallback:function({key:e,value:t,breadcrumbs:r}){return e===r?(n[0]=[t],t):(a=r.split("/").length-1,n[a]||(n[a]=[]),n[a].push(t),t)}}),{dataDeepLevel:a,nestedData:n}):(n.push([o]),{dataDeepLevel:0,nestedData:n})}(p,l),c=function*(e,r){let n=t({type:"LIFO"});for(let t=0;t<=r;t++)n.push(e[t]);for(;n&&!n.isEmpty();){let e=yield n.pull();e&&n.push(e)}}(function(e,t=10){let r={},n=[...e],a=0,o=0,s=0;n.forEach((e=>{"#"===e&&s++})),s<t&&console.error(`Error: Not enough level markers (#) for data with depth level ${t}. Found ${s} level markers in actions: ${e.join(", ")}`);do{r[o]=[],o++}while(o<=t);return n.every((e=>"#"===e?(a++,!(a>t)):e.startsWith("?")?(r[a].push({type:"route",name:e.replace("?",""),level:a}),!0):e.startsWith("^")&&"^^"!==e?(r[a].push({type:"save",name:e.replace("^",""),level:a}),!0):"^^"===e?(r[a].push({type:"overwrite",name:"none",level:a}),!0):e.startsWith("+")?(r[a].push({type:"extendedRender",name:e.replace("+",""),level:a}),!0):e.startsWith("[]")?(r[a].push({type:"mix",name:e.replace("[]",""),level:a}),!0):e.startsWith(">")?(r[a].push({type:"data",name:e.replace(">",""),level:a}),!0):(""===e||r[a].push({type:"render",name:e,level:a}),!0))),r}(l,n),n);for(let t of c){let{type:n,name:a,level:l}=t;(i[l]||[]).forEach(((t,c)=>{let u=o(t);switch(n){case"route":switch(u){case"array":t.forEach(((e,r)=>{if(null==e)return;const n=o(e),i=f[a]({data:e,...d});null!=i&&("object"===n?t[r].text=s(e,i,f,g):t[r]=s(e,i,f,g))}));break;case"object":t.text=s(t,a,f,g)}break;case"save":m[a]=structuredClone(t);break;case"overwrite":r=structuredClone(t);break;case"data":switch(u){case"array":t.forEach(((e,r)=>t[r]=e instanceof Function?f[a]({data:e(),...d}):f[a]({data:e,...d})));break;case"object":i[l]=[f[a]({data:t,...d})];break;case"function":i[l]=[f[a]({data:t(),...d})];break;case"primitive":i[l]=f[a]({data:t,...d})}break;case"render":const p="function"==typeof f[a];switch(u){case"array":p?t.forEach(((e,r)=>{if(null==e)return;const n=o(e),s=f[a]({data:e,...d});null==s&&(t[r]=null),"object"===n?e.text=s:t[r]=s})):t.forEach(((e,r)=>{if(null==e)return;const n=o(e),i=s(e,a,f,g);null==i?t[r]=null:"object"===n?e.text=i:t[r]=i}));break;case"function":i[l]=f[a]({data:t(),...d});break;case"primitive":i[l]=p?f[a]({data:t,...d}):s(t,a,f,g);break;case"object":p?i[l][c].text=f[a]({data:t,...d}):t.text=s(t,a,f,g)}break;case"extendedRender":"function"==typeof f[a]&&i[0].forEach(((e,t)=>i[0][t]=f[a]({data:e,...d})));break;case"mix":if(""===a)switch(u){case"object":Object.keys(t).find((e=>e.includes("/")))?Object.entries(t).forEach((([e,t])=>i[l][e]=t.text)):i[l]=t.text;for(let b=l-1;b>=0;b--)i[b]=e({data:i[b],objectCallback:h});function h({value:e,breadcrumbs:t}){return i[l][t]?i[l][t]:e}break;case"array":t.forEach(((e,r)=>{if(r>0){let n=o(e);if(null==e)return;t[0]+="object"===n?`${e.text}`:`${e}`,t.toSpliced(r,1)}else{let r=o(e);if(t[0]="",null===r)return;t[0]="object"===r?`${e.text}`:`${e}`}})),t.length=1}else{let y=f[a]({data:t,...d}),v=o(y);switch(t.forEach(((e,r)=>t.splice(r,1))),t.length=0,v){case"primitive":t[0]=y;break;case"array":t.push(...y)}}}}))}if(i instanceof Array&&1===i.length&&i[0]instanceof Array&&(i=i[0]),null==i[0])return;let u=o(i[0]),h=i[0];switch(u){case"primitive":if(null==h)return;b[a]=h;break;case"object":if(null==h.text)return;b[a]=h.text;break;case"array":const e=o(h[0]);b[a]="object"===e?h.map((e=>e.text)).join(""):h.join("")}}})),c?d.push(u.map((e=>b[e.index])).join("<~>")):d.push(b.join(""))})),"array"===y?d:i?i.reduce(((e,t)=>"function"!=typeof t?e:t(e,g)),d.join("")):d.join("")))}return i?[!0,y]:y}}const l={default:{}};const c={build:i,get:function(e){if(!(e instanceof Array))return function(){return'Error: Argument "location" is a string. Should be an array. E.g. ["templateName", "storageName"].'};const[t,r="default"]=e;return l[r]?l[r][t]?l[r][t]:function(){return`Error: Template "${t}" does not exist in storage "${r}".`}:function(){return`Error: Storage "${r}" does not exist.`}},add:function(e,t,...r){const[n,a="default"]=e;if(null==t)return void console.warn(`Warning: Template ${a}/${n} is not added to storage. The template is null.`);let o=t,s=!0;if(l[a]||(l[a]={}),"function"!=typeof t){let e=i(t,!0,...r);s=e[0],o=e[1]}s?l[a][n]=o:console.error(`Error: Template "${n}" looks broken and is not added to storage.`)},list:function(e=["default"]){return e.map((e=>l[e]?Object.keys(l[e]):[])).flat()},clear:function(){Object.keys(l).forEach((e=>{"default"!=e?delete l[e]:l.default={}}))},remove:function(e){const[t,r="default"]=e;return l[r]?l[r][t]?void delete l[r][t]:`Error: Template "${t}" does not exist in storage "${r}".`:`Error: Storage "${r}" does not exist.`}};module.exports=c;
|
package/dist/morph.esm.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"@peter.naydenov/walk";import t from"@peter.naydenov/stack";function r(e){return function t(r){const{TG_PRX:a,TG_SFX:o,TG_SIZE_P:s,TG_SIZE_S:
|
|
1
|
+
import e from"@peter.naydenov/walk";import t from"@peter.naydenov/stack";function r(e){return function t(r){const{TG_PRX:a,TG_SFX:o,TG_SIZE_P:s,TG_SIZE_S:i}=e;let l,c,u,d=[];if("string"!=typeof r)return n("notAString");if(0==r.length)return[];if(l=r.indexOf(a),0<l&&d.push(r.slice(0,l)),-1==l)return d.push(r),d;{if(u=r.indexOf(a,l+s),c=r.indexOf(o),-1==c)return n("missingClosing");if(c<l)return n("closedBeforeOpened");if(c+=i,-1!=u&&u<c)return n("newBeforeClosed");d.push(r.slice(l,c));let e=t(r.slice(c));return d.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."}}var a={TG_PRX:"{{",TG_SFX:"}}",TG_SIZE_P:2,TG_SIZE_S:2};function o(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,t,n,...o){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text),r instanceof Array&&(e[t]=r[0])}));const s="function"==typeof n[t];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),s?n[t](e,...o):function(e,t){if(null==t)return null;const n=r(a)(e),o=a;return n.forEach(((e,r)=>{if(e.includes(o.TG_PRX)){const a=e.replace(o.TG_PRX,"").replace(o.TG_SFX,"").trim();t.hasOwnProperty(a)&&null!=t[a]&&(n[r]=t[a])}})),n.join("")}(n[t],e)}function i(n,i=!1,l={}){let{hasError:c,placeholders:u,chop:d,helpers:f,handshake:p,snippets:h}=function(e){const{template:t,helpers:n={},handshake:o}=e,{TG_PRX:s,TG_SFX:i}=a,l=[],c={},u="string"==typeof t?t.replace(/<!--[\s\S]*?-->/g,"").replace(/\s{2,}/g," "):t;let d=null;const f=r(a)(u);return"string"==typeof f?d=f:f.forEach(((e,t)=>{const r=RegExp(s+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?(?::\\s*(.*?)\\s*)?"+i,"g");if(e.includes(s)){const a=r.exec(e);if(!a)return;let o={index:t,data:(n=a[1],n||null),action:a[2]?a[2].split(",").map((e=>e.trim())):null,name:a[3]?a[3].trim():null};l.push(o),c[l.length-1]=o,o.name&&(c[o.name]=o)}var n})),l.forEach((e=>{e.action&&e.action.every((e=>"#"===e||"^^"===e||!(!e.startsWith("^")||"^^"===e)||(e.startsWith("?")&&(e=e.replace("?","")),e.startsWith("+")&&(e=e.replace("+","")),e.startsWith("[]")&&(e=e.replace("[]","")),e.startsWith(">")&&(e=e.replace(">","")),""===e||!!n[e]||(d=`Error: Missing helper: ${e}`,!1))))})),{hasError:d,placeholders:l,chop:f,helpers:n,handshake:o,snippets:c}}(n);if(c){function m(){return c}return i?[!1,m]:m}{let b=structuredClone(d);function y(r="render",n={},a={},...i){let c=!1;if(!["render","debug","snippets"].includes(r)&&!r.startsWith("snippets"))return`Error: Wrong command "${r}". Available commands: render, debug, snippets.`;if(r.startsWith("snippets")&&r.includes(":")){c=!0;let e=r.split(":").slice(1)[0].trim().split(",").map((e=>e.trim()));u=e.map((e=>h[e]))}else"snippets"===r&&(c=!0);if("string"==typeof n)switch(n){case"raw":return b.join("");case"demo":if(!p)return"Error: No handshake data.";n=p;break;case"handshake":return p?structuredClone(p):"Error: No handshake data.";case"placeholders":return u.map((e=>b[e.index])).join(", ");default:return`Error: Wrong instruction "${n}". Available instructions: raw, demo, handshake, placeholders.`}const d=[],m={};let y=o(n),g={...l,...a};return n=e({data:n}),"null"===y?b.join(""):("array"!==y&&(n=[n]),"null"===y?b.join(""):(n.forEach((r=>{u.forEach((n=>{const{index:a,data:i,action:l}=n,c=!l&&i,u=structuredClone(m),d={dependencies:g,memory:u};let p=r;if(i&&i.includes("/")?p.hasOwnProperty(i)?p=p[i]:i.split("/").forEach((e=>{p=p.hasOwnProperty(e)?p[e]:[]})):"@all"===i||null===i||"@root"===i?p=r:i&&(p=p[i]),c){switch(o(p)){case"function":return void(b[a]=p());case"primitive":return void(b[a]=p);case"array":return void("primitive"===o(p[0])&&(b[a]=p[0]));case"object":return void(p.text&&(b[a]=p.text))}}else{let{dataDeepLevel:n,nestedData:i}=function(t,r){const n=[];let a=0;if(t instanceof Function)return{dataDeepLevel:0,nestedData:[[t()]]};if(null==t)return{dataDeepLevel:0,nestedData:[null]};if("string"==typeof t)return{dataDeepLevel:0,nestedData:[[t]]};const o=structuredClone(t);return r.includes("#")?(e({data:o,objectCallback:function({key:e,value:t,breadcrumbs:r}){return e===r?(n[0]=[t],t):(a=r.split("/").length-1,n[a]||(n[a]=[]),n[a].push(t),t)}}),{dataDeepLevel:a,nestedData:n}):(n.push([o]),{dataDeepLevel:0,nestedData:n})}(p,l),c=function*(e,r){let n=t({type:"LIFO"});for(let t=0;t<=r;t++)n.push(e[t]);for(;n&&!n.isEmpty();){let e=yield n.pull();e&&n.push(e)}}(function(e,t=10){let r={},n=[...e],a=0,o=0,s=0;n.forEach((e=>{"#"===e&&s++})),s<t&&console.error(`Error: Not enough level markers (#) for data with depth level ${t}. Found ${s} level markers in actions: ${e.join(", ")}`);do{r[o]=[],o++}while(o<=t);return n.every((e=>"#"===e?(a++,!(a>t)):e.startsWith("?")?(r[a].push({type:"route",name:e.replace("?",""),level:a}),!0):e.startsWith("^")&&"^^"!==e?(r[a].push({type:"save",name:e.replace("^",""),level:a}),!0):"^^"===e?(r[a].push({type:"overwrite",name:"none",level:a}),!0):e.startsWith("+")?(r[a].push({type:"extendedRender",name:e.replace("+",""),level:a}),!0):e.startsWith("[]")?(r[a].push({type:"mix",name:e.replace("[]",""),level:a}),!0):e.startsWith(">")?(r[a].push({type:"data",name:e.replace(">",""),level:a}),!0):(""===e||r[a].push({type:"render",name:e,level:a}),!0))),r}(l,n),n);for(let t of c){let{type:n,name:a,level:l}=t;(i[l]||[]).forEach(((t,c)=>{let u=o(t);switch(n){case"route":switch(u){case"array":t.forEach(((e,r)=>{if(null==e)return;const n=o(e),i=f[a]({data:e,...d});null!=i&&("object"===n?t[r].text=s(e,i,f,g):t[r]=s(e,i,f,g))}));break;case"object":t.text=s(t,a,f,g)}break;case"save":m[a]=structuredClone(t);break;case"overwrite":r=structuredClone(t);break;case"data":switch(u){case"array":t.forEach(((e,r)=>t[r]=e instanceof Function?f[a]({data:e(),...d}):f[a]({data:e,...d})));break;case"object":i[l]=[f[a]({data:t,...d})];break;case"function":i[l]=[f[a]({data:t(),...d})];break;case"primitive":i[l]=f[a]({data:t,...d})}break;case"render":const p="function"==typeof f[a];switch(u){case"array":p?t.forEach(((e,r)=>{if(null==e)return;const n=o(e),s=f[a]({data:e,...d});null==s&&(t[r]=null),"object"===n?e.text=s:t[r]=s})):t.forEach(((e,r)=>{if(null==e)return;const n=o(e),i=s(e,a,f,g);null==i?t[r]=null:"object"===n?e.text=i:t[r]=i}));break;case"function":i[l]=f[a]({data:t(),...d});break;case"primitive":i[l]=p?f[a]({data:t,...d}):s(t,a,f,g);break;case"object":p?i[l][c].text=f[a]({data:t,...d}):t.text=s(t,a,f,g)}break;case"extendedRender":"function"==typeof f[a]&&i[0].forEach(((e,t)=>i[0][t]=f[a]({data:e,...d})));break;case"mix":if(""===a)switch(u){case"object":Object.keys(t).find((e=>e.includes("/")))?Object.entries(t).forEach((([e,t])=>i[l][e]=t.text)):i[l]=t.text;for(let b=l-1;b>=0;b--)i[b]=e({data:i[b],objectCallback:h});function h({value:e,breadcrumbs:t}){return i[l][t]?i[l][t]:e}break;case"array":t.forEach(((e,r)=>{if(r>0){let n=o(e);if(null==e)return;t[0]+="object"===n?`${e.text}`:`${e}`,t.toSpliced(r,1)}else{let r=o(e);if(t[0]="",null===r)return;t[0]="object"===r?`${e.text}`:`${e}`}})),t.length=1}else{let y=f[a]({data:t,...d}),v=o(y);switch(t.forEach(((e,r)=>t.splice(r,1))),t.length=0,v){case"primitive":t[0]=y;break;case"array":t.push(...y)}}}}))}if(i instanceof Array&&1===i.length&&i[0]instanceof Array&&(i=i[0]),null==i[0])return;let u=o(i[0]),h=i[0];switch(u){case"primitive":if(null==h)return;b[a]=h;break;case"object":if(null==h.text)return;b[a]=h.text;break;case"array":const e=o(h[0]);b[a]="object"===e?h.map((e=>e.text)).join(""):h.join("")}}})),c?d.push(u.map((e=>b[e.index])).join("<~>")):d.push(b.join(""))})),"array"===y?d:i?i.reduce(((e,t)=>"function"!=typeof t?e:t(e,g)),d.join("")):d.join("")))}return i?[!0,y]:y}}const l={default:{}};const c={build:i,get:function(e){if(!(e instanceof Array))return function(){return'Error: Argument "location" is a string. Should be an array. E.g. ["templateName", "storageName"].'};const[t,r="default"]=e;return l[r]?l[r][t]?l[r][t]:function(){return`Error: Template "${t}" does not exist in storage "${r}".`}:function(){return`Error: Storage "${r}" does not exist.`}},add:function(e,t,...r){const[n,a="default"]=e;if(null==t)return void console.warn(`Warning: Template ${a}/${n} is not added to storage. The template is null.`);let o=t,s=!0;if(l[a]||(l[a]={}),"function"!=typeof t){let e=i(t,!0,...r);s=e[0],o=e[1]}s?l[a][n]=o:console.error(`Error: Template "${n}" looks broken and is not added to storage.`)},list:function(e=["default"]){return e.map((e=>l[e]?Object.keys(l[e]):[])).flat()},clear:function(){Object.keys(l).forEach((e=>{"default"!=e?delete l[e]:l.default={}}))},remove:function(e){const[t,r="default"]=e;return l[r]?l[r][t]?void delete l[r][t]:`Error: Template "${t}" does not exist in storage "${r}".`:`Error: Storage "${r}" does not exist.`}};export{c 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:a,TG_SFX:o,TG_SIZE_P:l,TG_SIZE_S:s}=e;let i,c,u,f=[];if("string"!=typeof n)return r("notAString");if(0==n.length)return[];if(i=n.indexOf(a),0<i&&f.push(n.slice(0,i)),-1==i)return f.push(n),f;{if(u=n.indexOf(a,i+l),c=n.indexOf(o),-1==c)return r("missingClosing");if(c<i)return r("closedBeforeOpened");if(c+=s,-1!=u&&u<c)return r("newBeforeClosed");f.push(n.slice(i,c));let e=t(n.slice(c));return f.concat(e)}}}function r(e){switch(e){case"notAString":return"Error: Template is not a string.";case"missingClosing":return"Error: Placeholder with missing closing tag.";case"closedBeforeOpened":return"Error: Placeholder closing tag without starting one.";case"newBeforeClosed":return"Error: Nested placeholders. Close placeholder before open new one.";default:return"Error: Unknown template error."}}function*n(e,t){let r=function(e={}){let t=[],{type:r,limit:n,onLimit:a}=Object.assign({},{type:"FIFO",limit:!1,onLimit:"update"},e),o="LIFO"===r.toUpperCase(),l=!1;function s(e=1,r=0){let n=[];return r>0&&Array.from({length:r}).map((()=>t.pop())),1==e?t.pop():(Array.from({length:e}).map((()=>{let e=t.pop();null!=e&&n.push(e)})),n)}function i(e=1,r=0){let n=[],a=t.length-r;return e>1&&Array.from({length:e}).map((()=>{null!=t[a-1]&&n.push(t[a-1]),a--})),1==e?t[t.length-1]:n}function c(){}return c.prototype={pull:s,pullReverse:function(e=1,t=0){let r=s(e,t);return r instanceof Array?r.reverse():r},peek:i,peekReverse:function(e=1,t=0){const r=i(e,t);return r instanceof Array?r.reverse():r},getSize:()=>t.length,isEmpty:()=>0==t.length,reset:()=>(t=[],!0),debug:()=>[...t]},c.prototype.push=o?function(e){const r=e instanceof Array,o=r?e.length:1;let i=!1;if("full"!==a||!l){if(n&&r&&o>n&&(e=e.slice(0,-o+n)),n){const o=(r?e.length:1)+t.length;o>=n&&"full"===a&&(e=e.slice(0,-(o-n))),o>=n&&"update"===a&&(i=s(o-n))}return t=e instanceof Array?t.concat(e):t.concat([e]),l=!!n&&t.length===n,i||void 0}}:function(e){const r=e instanceof Array,o=r?e.length:1;let i=!1;if("full"!==a||!l){if(n&&r&&o>n&&(e=e.slice(o-n)),n){const o=(r?e.length:1)+t.length;o>=n&&"full"===a&&(e=e.slice(0,-(o-n))),o>=n&&"update"===a&&(i=s(o-n))}return t=r?e.reduce(((e,t)=>[t,...e]),t):[e].reduce(((e,t)=>[t,...e]),t),l=!!n&&t.length===n,i||void 0}},new c}({type:"LIFO"});for(let n=0;n<=t;n++)r.push(e[n]);for(;r&&!r.isEmpty();){let e=yield r.pull();e&&r.push(e)}}var a={TG_PRX:"{{",TG_SFX:"}}",TG_SIZE_P:2,TG_SIZE_S:2};function o(e){return null==e?"null":"string"==typeof e||"number"==typeof e||"boolean"==typeof e?"primitive":"function"==typeof e?"function":e instanceof Array?"array":e instanceof Object?"object":void 0}function l(e,r,n,...o){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text),r instanceof Array&&(e[t]=r[0])}));const l="function"==typeof n[r];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),l?n[r](e,...o):function(e,r){if(null==r)return null;const n=t(a)(e),o=a;return n.forEach(((e,t)=>{if(e.includes(o.TG_PRX)){const a=e.replace(o.TG_PRX,"").replace(o.TG_SFX,"").trim();r.hasOwnProperty(a)&&null!=r[a]&&(n[t]=r[a])}})),n.join("")}(n[r],e)}function s(r,s=!1,i={}){const{hasError:c,placeholders:u,chop:f,helpers:d,handshake:p}=function(e){const{template:r,helpers:n={},handshake:o}=e,{TG_PRX:l,TG_SFX:s}=a,i=[],c="string"==typeof r?r.replace(/<!--[\s\S]*?-->/g,"").replace(/\s{2,}/g," "):r;let u=null;const f=t(a)(c);return"string"==typeof f?u=f:f.forEach(((e,t)=>{const r=RegExp(l+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?"+s,"g");if(e.includes(l)){const a=r.exec(e);i.push({index:t,data:(n=a[1],n||null),action:a[2]?a[2].split(",").map((e=>e.trim())):null})}var n})),i.forEach((e=>{e.action&&e.action.every((e=>"#"===e||"^^"===e||!(!e.startsWith("^")||"^^"===e)||(e.startsWith("?")&&(e=e.replace("?","")),e.startsWith("+")&&(e=e.replace("+","")),e.startsWith("[]")&&(e=e.replace("[]","")),e.startsWith(">")&&(e=e.replace(">","")),""===e||!!n[e]||(u=`Error: Missing helper: ${e}`,!1))))})),{hasError:u,placeholders:i,chop:f,helpers:n,handshake:o}}(r);if(c){function h(){return c}return s?[!1,h]:h}{let y=structuredClone(f);function m(t={},r={},...a){const s=[],c={};let f=o(t),h={...i,...r};if(t=e({data:t}),"null"===f)return y.join("");if("string"==typeof t)switch(t){case"raw":return y.join("");case"demo":if(!p)return"Error: No handshake data.";f=o(t=p);break;case"handshake":return p?structuredClone(p):"Error: No handshake data.";case"placeholders":return u.map((e=>y[e.index])).join(", ");default:return`Error: Wrong command "${t}". Available commands: raw, demo, handshake, placeholders.`}return"array"!==f&&(t=[t]),"null"===f?y.join(""):(t.forEach((t=>{u.forEach((r=>{const{index:a,data:s,action:i}=r,u=!i&&s,f=structuredClone(c),p={dependencies:h,memory:f};let m=t;if(s&&s.includes("/")?s.split("/").forEach((e=>{m=m.hasOwnProperty(e)?m[e]:[]})):"@all"===s||null===s||"@root"===s?m=t:s&&(m=m[s]),u){switch(o(m)){case"function":return void(y[a]=m());case"primitive":return void(y[a]=m);case"array":return void("primitive"===o(m[0])&&(y[a]=m[0]));case"object":return void(m.text&&(y[a]=m.text))}}else{let{dataDeepLevel:r,nestedData:s}=function(t,r){const n=[];let a=0;if(t instanceof Function)return{dataDeepLevel:0,nestedData:[[t()]]};if(null==t)return{dataDeepLevel:0,nestedData:[null]};if("string"==typeof t)return{dataDeepLevel:0,nestedData:[[t]]};const o=structuredClone(t);return r.includes("#")?(e({data:o,objectCallback:function({key:e,value:t,breadcrumbs:r}){return e===r?(n[0]=[t],t):(a=r.split("/").length-1,n[a]||(n[a]=[]),n[a].push(t),t)}}),{dataDeepLevel:a,nestedData:n}):(n.push([o]),{dataDeepLevel:0,nestedData:n})}(m,i),u=n(function(e,t=10){let r={},n=[...e],a=0,o=0,l=0;n.forEach((e=>{"#"===e&&l++})),l<t&&console.error(`Error: Not enough level markers (#) for data with depth level ${t}. Found ${l} level markers in actions: ${e.join(", ")}`);do{r[o]=[],o++}while(o<=t);return n.every((e=>"#"===e?(a++,!(a>t)):e.startsWith("?")?(r[a].push({type:"route",name:e.replace("?",""),level:a}),!0):e.startsWith("^")&&"^^"!==e?(r[a].push({type:"save",name:e.replace("^",""),level:a}),!0):"^^"===e?(r[a].push({type:"overwrite",name:"none",level:a}),!0):e.startsWith("+")?(r[a].push({type:"extendedRender",name:e.replace("+",""),level:a}),!0):e.startsWith("[]")?(r[a].push({type:"mix",name:e.replace("[]",""),level:a}),!0):e.startsWith(">")?(r[a].push({type:"data",name:e.replace(">",""),level:a}),!0):(""===e||r[a].push({type:"render",name:e,level:a}),!0))),r}(i,r),r);for(let r of u){let{type:n,name:a,level:i}=r;(s[i]||[]).forEach(((r,u)=>{let f=o(r);switch(n){case"route":switch(f){case"array":r.forEach(((e,t)=>{if(null==e)return;const n=o(e),s=d[a]({data:e,...p});null!=s&&("object"===n?r[t].text=l(e,s,d,h):r[t]=l(e,s,d,h))}));break;case"object":r.text=l(r,a,d,h)}break;case"save":c[a]=structuredClone(r);break;case"overwrite":t=structuredClone(r);break;case"data":switch(f){case"array":r.forEach(((e,t)=>r[t]=e instanceof Function?d[a]({data:e(),...p}):d[a]({data:e,...p})));break;case"object":s[i]=[d[a]({data:r,...p})];break;case"function":s[i]=[d[a]({data:r(),...p})];break;case"primitive":s[i]=d[a]({data:r,...p})}break;case"render":const y="function"==typeof d[a];switch(f){case"array":y?r.forEach(((e,t)=>{if(null==e)return;const n=o(e),l=d[a]({data:e,...p});null==l&&(r[t]=null),"object"===n?e.text=l:r[t]=l})):r.forEach(((e,t)=>{if(null==e)return;const n=o(e),s=l(e,a,d,h);null==s?r[t]=null:"object"===n?e.text=s:r[t]=s}));break;case"function":s[i]=d[a]({data:r(),...p});break;case"primitive":s[i]=y?d[a]({data:r,...p}):l(r,a,d,h);break;case"object":y?s[i][u].text=d[a]({data:r,...p}):r.text=l(r,a,d,h)}break;case"extendedRender":"function"==typeof d[a]&&s[0].forEach(((e,t)=>s[0][t]=d[a]({data:e,...p})));break;case"mix":if(""===a)switch(f){case"object":Object.keys(r).find((e=>e.includes("/")))?Object.entries(r).forEach((([e,t])=>s[i][e]=t.text)):s[i]=r.text;for(let g=i-1;g>=0;g--)s[g]=e({data:s[g],objectCallback:m});function m({value:e,breadcrumbs:t}){return s[i][t]?s[i][t]:e}break;case"array":r.forEach(((e,t)=>{if(t>0){let n=o(e);if(null==e)return;r[0]+="object"===n?`${e.text}`:`${e}`,r.toSpliced(t,1)}else{let t=o(e);if(r[0]="",null===t)return;r[0]="object"===t?`${e.text}`:`${e}`}})),r.length=1}else{let b=d[a]({data:r,...p}),v=o(b);switch(r.forEach(((e,t)=>r.splice(t,1))),r.length=0,v){case"primitive":r[0]=b;break;case"array":r.push(...b)}}}}))}if(s instanceof Array&&1===s.length&&s[0]instanceof Array&&(s=s[0]),null==s[0])return;let f=o(s[0]),g=s[0];switch(f){case"primitive":if(null==g)return;y[a]=g;break;case"object":if(null==g.text)return;y[a]=g.text;break;case"array":const e=o(g[0]);y[a]="object"===e?g.map((e=>e.text)).join(""):g.join("")}}})),s.push(y.join(""))})),"array"===f?s:a?a.reduce(((e,t)=>"function"!=typeof t?e:t(e,h)),s.join("")):s.join(""))}return s?[!0,m]:m}}const i={default:{}};return{build:s,get:function(e){if(!(e instanceof Array))return function(){return'Error: Argument "location" is a string. Should be an array. E.g. ["templateName", "storageName"].'};const[t,r="default"]=e;return i[r]?i[r][t]?i[r][t]:function(){return`Error: Template "${t}" does not exist in storage "${r}".`}:function(){return`Error: Storage "${r}" does not exist.`}},add:function(e,t,...r){const[n,a="default"]=e;if(null==t)return void console.warn(`Warning: Template ${a}/${n} is not added to storage. The template is null.`);let o=t,l=!0;if(i[a]||(i[a]={}),"function"!=typeof t){let e=s(t,!0,...r);l=e[0],o=e[1]}l?i[a][n]=o:console.error(`Error: Template "${n}" looks broken and is not added to storage.`)},list:function(e=["default"]){return e.map((e=>i[e]?Object.keys(i[e]):[])).flat()},clear:function(){Object.keys(i).forEach((e=>{"default"!=e?delete i[e]:i.default={}}))},remove:function(e){const[t,r="default"]=e;return i[r]?i[r][t]?void delete i[r][t]:`Error: Template "${t}" does not exist in storage "${r}".`:`Error: Storage "${r}" does not exist.`}}}));
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@peter.naydenov/walk")):"function"==typeof define&&define.amd?define(["@peter.naydenov/walk"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).morph=t(e.walk)}(this,(function(e){"use strict";function t(e){return function t(n){const{TG_PRX:a,TG_SFX:o,TG_SIZE_P:s,TG_SIZE_S:i}=e;let l,c,u,f=[];if("string"!=typeof n)return r("notAString");if(0==n.length)return[];if(l=n.indexOf(a),0<l&&f.push(n.slice(0,l)),-1==l)return f.push(n),f;{if(u=n.indexOf(a,l+s),c=n.indexOf(o),-1==c)return r("missingClosing");if(c<l)return r("closedBeforeOpened");if(c+=i,-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(e,t){let r=function(e={}){let t=[],{type:r,limit:n,onLimit:a}=Object.assign({},{type:"FIFO",limit:!1,onLimit:"update"},e),o="LIFO"===r.toUpperCase(),s=!1;function i(e=1,r=0){let n=[];return r>0&&Array.from({length:r}).map((()=>t.pop())),1==e?t.pop():(Array.from({length:e}).map((()=>{let e=t.pop();null!=e&&n.push(e)})),n)}function l(e=1,r=0){let n=[],a=t.length-r;return e>1&&Array.from({length:e}).map((()=>{null!=t[a-1]&&n.push(t[a-1]),a--})),1==e?t[t.length-1]:n}function c(){}return c.prototype={pull:i,pullReverse:function(e=1,t=0){let r=i(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=o?function(e){const r=e instanceof Array,o=r?e.length:1;let l=!1;if("full"!==a||!s){if(n&&r&&o>n&&(e=e.slice(0,-o+n)),n){const o=(r?e.length:1)+t.length;o>=n&&"full"===a&&(e=e.slice(0,-(o-n))),o>=n&&"update"===a&&(l=i(o-n))}return t=e instanceof Array?t.concat(e):t.concat([e]),s=!!n&&t.length===n,l||void 0}}:function(e){const r=e instanceof Array,o=r?e.length:1;let l=!1;if("full"!==a||!s){if(n&&r&&o>n&&(e=e.slice(o-n)),n){const o=(r?e.length:1)+t.length;o>=n&&"full"===a&&(e=e.slice(0,-(o-n))),o>=n&&"update"===a&&(l=i(o-n))}return t=r?e.reduce(((e,t)=>[t,...e]),t):[e].reduce(((e,t)=>[t,...e]),t),s=!!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 o(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),r instanceof Array&&(e[t]=r[0])}));const s="function"==typeof n[r];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),s?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.hasOwnProperty(a)&&null!=r[a]&&(n[t]=r[a])}})),n.join("")}(n[r],e)}function i(r,i=!1,l={}){let{hasError:c,placeholders:u,chop:f,helpers:p,handshake:d,snippets:h}=function(e){const{template:r,helpers:n={},handshake:o}=e,{TG_PRX:s,TG_SFX:i}=a,l=[],c={},u="string"==typeof r?r.replace(/<!--[\s\S]*?-->/g,"").replace(/\s{2,}/g," "):r;let f=null;const p=t(a)(u);return"string"==typeof p?f=p:p.forEach(((e,t)=>{const r=RegExp(s+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?(?::\\s*(.*?)\\s*)?"+i,"g");if(e.includes(s)){const a=r.exec(e);if(!a)return;let o={index:t,data:(n=a[1],n||null),action:a[2]?a[2].split(",").map((e=>e.trim())):null,name:a[3]?a[3].trim():null};l.push(o),c[l.length-1]=o,o.name&&(c[o.name]=o)}var n})),l.forEach((e=>{e.action&&e.action.every((e=>"#"===e||"^^"===e||!(!e.startsWith("^")||"^^"===e)||(e.startsWith("?")&&(e=e.replace("?","")),e.startsWith("+")&&(e=e.replace("+","")),e.startsWith("[]")&&(e=e.replace("[]","")),e.startsWith(">")&&(e=e.replace(">","")),""===e||!!n[e]||(f=`Error: Missing helper: ${e}`,!1))))})),{hasError:f,placeholders:l,chop:p,helpers:n,handshake:o,snippets:c}}(r);if(c){function m(){return c}return i?[!1,m]:m}{let y=structuredClone(f);function g(t="render",r={},a={},...i){let c=!1;if(!["render","debug","snippets"].includes(t)&&!t.startsWith("snippets"))return`Error: Wrong command "${t}". Available commands: render, debug, snippets.`;if(t.startsWith("snippets")&&t.includes(":")){c=!0;let e=t.split(":").slice(1)[0].trim().split(",").map((e=>e.trim()));u=e.map((e=>h[e]))}else"snippets"===t&&(c=!0);if("string"==typeof r)switch(r){case"raw":return y.join("");case"demo":if(!d)return"Error: No handshake data.";r=d;break;case"handshake":return d?structuredClone(d):"Error: No handshake data.";case"placeholders":return u.map((e=>y[e.index])).join(", ");default:return`Error: Wrong instruction "${r}". Available instructions: raw, demo, handshake, placeholders.`}const f=[],m={};let g=o(r),b={...l,...a};return r=e({data:r}),"null"===g?y.join(""):("array"!==g&&(r=[r]),"null"===g?y.join(""):(r.forEach((t=>{u.forEach((r=>{const{index:a,data:i,action:l}=r,c=!l&&i,u=structuredClone(m),f={dependencies:b,memory:u};let d=t;if(i&&i.includes("/")?d.hasOwnProperty(i)?d=d[i]:i.split("/").forEach((e=>{d=d.hasOwnProperty(e)?d[e]:[]})):"@all"===i||null===i||"@root"===i?d=t:i&&(d=d[i]),c){switch(o(d)){case"function":return void(y[a]=d());case"primitive":return void(y[a]=d);case"array":return void("primitive"===o(d[0])&&(y[a]=d[0]));case"object":return void(d.text&&(y[a]=d.text))}}else{let{dataDeepLevel:r,nestedData:i}=function(t,r){const n=[];let a=0;if(t instanceof Function)return{dataDeepLevel:0,nestedData:[[t()]]};if(null==t)return{dataDeepLevel:0,nestedData:[null]};if("string"==typeof t)return{dataDeepLevel:0,nestedData:[[t]]};const o=structuredClone(t);return r.includes("#")?(e({data:o,objectCallback:function({key:e,value:t,breadcrumbs:r}){return e===r?(n[0]=[t],t):(a=r.split("/").length-1,n[a]||(n[a]=[]),n[a].push(t),t)}}),{dataDeepLevel:a,nestedData:n}):(n.push([o]),{dataDeepLevel:0,nestedData:n})}(d,l),c=n(function(e,t=10){let r={},n=[...e],a=0,o=0,s=0;n.forEach((e=>{"#"===e&&s++})),s<t&&console.error(`Error: Not enough level markers (#) for data with depth level ${t}. Found ${s} level markers in actions: ${e.join(", ")}`);do{r[o]=[],o++}while(o<=t);return n.every((e=>"#"===e?(a++,!(a>t)):e.startsWith("?")?(r[a].push({type:"route",name:e.replace("?",""),level:a}),!0):e.startsWith("^")&&"^^"!==e?(r[a].push({type:"save",name:e.replace("^",""),level:a}),!0):"^^"===e?(r[a].push({type:"overwrite",name:"none",level:a}),!0):e.startsWith("+")?(r[a].push({type:"extendedRender",name:e.replace("+",""),level:a}),!0):e.startsWith("[]")?(r[a].push({type:"mix",name:e.replace("[]",""),level:a}),!0):e.startsWith(">")?(r[a].push({type:"data",name:e.replace(">",""),level:a}),!0):(""===e||r[a].push({type:"render",name:e,level:a}),!0))),r}(l,r),r);for(let r of c){let{type:n,name:a,level:l}=r;(i[l]||[]).forEach(((r,c)=>{let u=o(r);switch(n){case"route":switch(u){case"array":r.forEach(((e,t)=>{if(null==e)return;const n=o(e),i=p[a]({data:e,...f});null!=i&&("object"===n?r[t].text=s(e,i,p,b):r[t]=s(e,i,p,b))}));break;case"object":r.text=s(r,a,p,b)}break;case"save":m[a]=structuredClone(r);break;case"overwrite":t=structuredClone(r);break;case"data":switch(u){case"array":r.forEach(((e,t)=>r[t]=e instanceof Function?p[a]({data:e(),...f}):p[a]({data:e,...f})));break;case"object":i[l]=[p[a]({data:r,...f})];break;case"function":i[l]=[p[a]({data:r(),...f})];break;case"primitive":i[l]=p[a]({data:r,...f})}break;case"render":const d="function"==typeof p[a];switch(u){case"array":d?r.forEach(((e,t)=>{if(null==e)return;const n=o(e),s=p[a]({data:e,...f});null==s&&(r[t]=null),"object"===n?e.text=s:r[t]=s})):r.forEach(((e,t)=>{if(null==e)return;const n=o(e),i=s(e,a,p,b);null==i?r[t]=null:"object"===n?e.text=i:r[t]=i}));break;case"function":i[l]=p[a]({data:r(),...f});break;case"primitive":i[l]=d?p[a]({data:r,...f}):s(r,a,p,b);break;case"object":d?i[l][c].text=p[a]({data:r,...f}):r.text=s(r,a,p,b)}break;case"extendedRender":"function"==typeof p[a]&&i[0].forEach(((e,t)=>i[0][t]=p[a]({data:e,...f})));break;case"mix":if(""===a)switch(u){case"object":Object.keys(r).find((e=>e.includes("/")))?Object.entries(r).forEach((([e,t])=>i[l][e]=t.text)):i[l]=r.text;for(let y=l-1;y>=0;y--)i[y]=e({data:i[y],objectCallback:h});function h({value:e,breadcrumbs:t}){return i[l][t]?i[l][t]:e}break;case"array":r.forEach(((e,t)=>{if(t>0){let n=o(e);if(null==e)return;r[0]+="object"===n?`${e.text}`:`${e}`,r.toSpliced(t,1)}else{let t=o(e);if(r[0]="",null===t)return;r[0]="object"===t?`${e.text}`:`${e}`}})),r.length=1}else{let g=p[a]({data:r,...f}),v=o(g);switch(r.forEach(((e,t)=>r.splice(t,1))),r.length=0,v){case"primitive":r[0]=g;break;case"array":r.push(...g)}}}}))}if(i instanceof Array&&1===i.length&&i[0]instanceof Array&&(i=i[0]),null==i[0])return;let u=o(i[0]),h=i[0];switch(u){case"primitive":if(null==h)return;y[a]=h;break;case"object":if(null==h.text)return;y[a]=h.text;break;case"array":const e=o(h[0]);y[a]="object"===e?h.map((e=>e.text)).join(""):h.join("")}}})),c?f.push(u.map((e=>y[e.index])).join("<~>")):f.push(y.join(""))})),"array"===g?f:i?i.reduce(((e,t)=>"function"!=typeof t?e:t(e,b)),f.join("")):f.join("")))}return i?[!0,g]:g}}const l={default:{}};return{build:i,get:function(e){if(!(e instanceof Array))return function(){return'Error: Argument "location" is a string. Should be an array. E.g. ["templateName", "storageName"].'};const[t,r="default"]=e;return l[r]?l[r][t]?l[r][t]:function(){return`Error: Template "${t}" does not exist in storage "${r}".`}:function(){return`Error: Storage "${r}" does not exist.`}},add:function(e,t,...r){const[n,a="default"]=e;if(null==t)return void console.warn(`Warning: Template ${a}/${n} is not added to storage. The template is null.`);let o=t,s=!0;if(l[a]||(l[a]={}),"function"!=typeof t){let e=i(t,!0,...r);s=e[0],o=e[1]}s?l[a][n]=o:console.error(`Error: Template "${n}" looks broken and is not added to storage.`)},list:function(e=["default"]){return e.map((e=>l[e]?Object.keys(l[e]):[])).flat()},clear:function(){Object.keys(l).forEach((e=>{"default"!=e?delete l[e]:l.default={}}))},remove:function(e){const[t,r="default"]=e;return l[r]?l[r][t]?void delete l[r][t]:`Error: Template "${t}" does not exist in storage "${r}".`:`Error: Storage "${r}" does not exist.`}}}));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peter.naydenov/morph",
|
|
3
3
|
"description": "Template engine",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "3.0.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Peter Naydenov",
|
|
7
7
|
"main": "./src/main.js",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"@rollup/plugin-terser": "^0.4.4",
|
|
33
33
|
"c8": "^10.1.3",
|
|
34
34
|
"chai": "5.2.0",
|
|
35
|
-
"mocha": "11.
|
|
36
|
-
"rollup": "^4.
|
|
35
|
+
"mocha": "11.6.0",
|
|
36
|
+
"rollup": "^4.43.0"
|
|
37
37
|
},
|
|
38
38
|
"repository": {
|
|
39
39
|
"type": "git",
|
|
@@ -14,6 +14,7 @@ function _readTemplate ( tpl ) {
|
|
|
14
14
|
{ template, helpers={}, handshake } = tpl
|
|
15
15
|
,{ TG_PRX, TG_SFX, TG_SIZE_P, TG_SIZE_S } = settings
|
|
16
16
|
, placeholders = []
|
|
17
|
+
, snippets = {}
|
|
17
18
|
;
|
|
18
19
|
|
|
19
20
|
// Remove from template all html comments and multiple spaces
|
|
@@ -29,19 +30,23 @@ function _readTemplate ( tpl ) {
|
|
|
29
30
|
else {
|
|
30
31
|
chop.forEach ( (item,i) => {
|
|
31
32
|
const
|
|
32
|
-
// Placeholder contains: Opening tag(TG_PRX), dataName, delimiter(:), list of operations, closing tag(TG_SFX)
|
|
33
|
-
finding = RegExp ( TG_PRX + '\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?' + TG_SFX, 'g' )
|
|
33
|
+
// Placeholder contains: Opening tag(TG_PRX), dataName, delimiter(:), list of operations, placeholder's name, closing tag(TG_SFX)
|
|
34
|
+
finding = RegExp ( TG_PRX + '\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?(?::\\s*(.*?)\\s*)?' + TG_SFX, 'g' )
|
|
34
35
|
, isPlaceholder = item.includes( TG_PRX )
|
|
35
36
|
;
|
|
36
37
|
|
|
37
38
|
if ( isPlaceholder ) {
|
|
38
39
|
const x = finding.exec ( item )
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
if ( !x ) return
|
|
41
|
+
let holder = {
|
|
41
42
|
index: i
|
|
42
43
|
, data : readData ( x[1] )
|
|
43
44
|
, action : x[2] ? x[2].split(',').map ( x => x.trim()) : null
|
|
44
|
-
|
|
45
|
+
, name : x[3] ? x[3].trim() : null
|
|
46
|
+
}
|
|
47
|
+
placeholders.push ( holder )
|
|
48
|
+
snippets[placeholders.length-1] = holder
|
|
49
|
+
if ( holder.name ) snippets[holder.name] = holder
|
|
45
50
|
} // if isPlaceholder
|
|
46
51
|
}) // forEach chop
|
|
47
52
|
} // else error
|
|
@@ -50,22 +55,22 @@ function _readTemplate ( tpl ) {
|
|
|
50
55
|
|
|
51
56
|
// Check helpers - sanity check
|
|
52
57
|
placeholders.forEach ( holder => {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
58
|
+
if ( !holder.action ) return
|
|
59
|
+
holder.action.every ( act => {
|
|
60
|
+
if ( act === '#' ) return true
|
|
61
|
+
if ( act === '^^' ) return true
|
|
62
|
+
if ( act.startsWith('^') && act !== '^^' ) return true
|
|
63
|
+
if ( act.startsWith ( '?' )) act = act.replace ( '?', '' )
|
|
64
|
+
if ( act.startsWith ( '+' )) act = act.replace ( '+', '' )
|
|
65
|
+
if ( act.startsWith ( '[]' )) act = act.replace ( '[]', '' )
|
|
66
|
+
if ( act.startsWith ( '>' )) act = act.replace ( '>', '' )
|
|
67
|
+
if ( act === '' ) return true
|
|
68
|
+
if ( helpers[act] ) return true
|
|
69
|
+
else {
|
|
70
|
+
hasError = `Error: Missing helper: ${act}`
|
|
71
|
+
return false
|
|
72
|
+
}
|
|
73
|
+
}) // every action
|
|
69
74
|
}) // forEach placeholders
|
|
70
75
|
|
|
71
76
|
|
|
@@ -76,6 +81,7 @@ function _readTemplate ( tpl ) {
|
|
|
76
81
|
, chop
|
|
77
82
|
, helpers
|
|
78
83
|
, handshake
|
|
84
|
+
, snippets
|
|
79
85
|
}
|
|
80
86
|
} // _readTemplate func.
|
|
81
87
|
|
package/src/methods/build.js
CHANGED
|
@@ -28,12 +28,13 @@ import walk from '@peter.naydenov/walk'
|
|
|
28
28
|
/**
|
|
29
29
|
*
|
|
30
30
|
* @param {Template} tpl - template definition;
|
|
31
|
-
* @param {boolean} [extra] - Optional. How to receive the answer - false:as a string(answer) or tuple[success, answer];
|
|
31
|
+
* @param {boolean} [extra] - Optional. How to receive the answer - false:as a string(answer) or true: as tuple[success, answer];
|
|
32
32
|
* @param {object} [buildDependencies] - Optional. External dependencies injected;
|
|
33
33
|
* @returns {function|tupleResult} - rendering function
|
|
34
34
|
*/
|
|
35
35
|
function build ( tpl, extra=false, buildDependencies={} ) {
|
|
36
|
-
|
|
36
|
+
let { hasError, placeholders, chop, helpers, handshake, snippets } = _readTemplate ( tpl );
|
|
37
|
+
|
|
37
38
|
if ( hasError ) {
|
|
38
39
|
function fail () { return hasError }
|
|
39
40
|
return extra ? [ false, fail ] : fail
|
|
@@ -41,51 +42,73 @@ function build ( tpl, extra=false, buildDependencies={} ) {
|
|
|
41
42
|
else { // If NO Error:
|
|
42
43
|
let cuts = structuredClone ( chop );
|
|
43
44
|
// *** Template recognition complete. Start building the rendering function -->
|
|
44
|
-
|
|
45
45
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* @
|
|
49
|
-
* @
|
|
50
|
-
* @
|
|
51
|
-
* @
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
46
|
+
* Processes template rendering commands with provided data, dependencies, and optional post-processing functions.
|
|
47
|
+
*
|
|
48
|
+
* @function success
|
|
49
|
+
* @typedef { 'render' | 'debug' | 'snippets' } Command
|
|
50
|
+
* @param {Command} [command='render'] - The command to execute. Supported commands: 'render', 'debug', 'snippets', or 'snippets:<names>'.
|
|
51
|
+
* @param {Object|string} [d={}] - The data object to render, or a string instruction ('raw', 'demo', 'handshake', 'placeholders').
|
|
52
|
+
* @param {Object} [dependencies={}] - Additional dependencies to be merged with internal dependencies.
|
|
53
|
+
* @param {...any} args - Optional post-processing functions to apply to the rendered output.
|
|
54
|
+
* @returns {string|Array[]} The rendered template, snippets, or data depending on the command and input.
|
|
55
|
+
*
|
|
56
|
+
* @throws {Error} If an unsupported command or instruction is provided.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* // Render a template with data
|
|
60
|
+
* success('render', { name: 'Alice' }, { helperFn });
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* // Get raw template
|
|
64
|
+
* success('debug', 'raw');
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* // Render only specific snippets
|
|
68
|
+
* success('snippets:header,footer', { ... });
|
|
60
69
|
*/
|
|
61
|
-
function success ( d={}, dependencies={}, ...args ) {
|
|
70
|
+
function success ( command='render', d={}, dependencies={}, ...args ) {
|
|
71
|
+
let onlySnippets = false;
|
|
72
|
+
if ( ![ 'render', 'debug', 'snippets'].includes ( command ) && !command.startsWith('snippets') ) return `Error: Wrong command "${command}". Available commands: render, debug, snippets.`
|
|
73
|
+
|
|
74
|
+
if ( command.startsWith ( 'snippets') && command.includes ( ':' ) ) {
|
|
75
|
+
onlySnippets = true
|
|
76
|
+
let snippetNames = command.split ( ':' )
|
|
77
|
+
.slice ( 1 )[0]
|
|
78
|
+
.trim()
|
|
79
|
+
.split ( ',' )
|
|
80
|
+
.map ( t => t.trim() )
|
|
81
|
+
placeholders = snippetNames.map ( item => snippets [ item ])
|
|
82
|
+
}
|
|
83
|
+
else if ( command === 'snippets' ) {
|
|
84
|
+
onlySnippets = true
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if ( typeof d === 'string' ) {
|
|
88
|
+
switch ( d ) {
|
|
89
|
+
case 'raw':
|
|
90
|
+
return cuts.join ( '' ) // Original template with placeholders
|
|
91
|
+
case 'demo':
|
|
92
|
+
if ( !handshake ) return `Error: No handshake data.`
|
|
93
|
+
d = handshake // Render with handshake object
|
|
94
|
+
break
|
|
95
|
+
case 'handshake':
|
|
96
|
+
if ( !handshake ) return `Error: No handshake data.`
|
|
97
|
+
return structuredClone (handshake) // return a copy of handshake object
|
|
98
|
+
case 'placeholders':
|
|
99
|
+
return placeholders.map ( h => cuts[h.index] ).join ( ', ')
|
|
100
|
+
default:
|
|
101
|
+
return `Error: Wrong instruction "${d}". Available instructions: raw, demo, handshake, placeholders.`
|
|
102
|
+
}
|
|
103
|
+
} // if d is string
|
|
104
|
+
|
|
62
105
|
const endData = [];
|
|
63
106
|
const memory = {};
|
|
107
|
+
|
|
64
108
|
let topLevelType = _defineDataType ( d );
|
|
65
109
|
let deps = { ...buildDependencies, ...dependencies }
|
|
66
110
|
d = walk ({data:d}) // Creates copy of data to avoid mutation of the original
|
|
67
|
-
|
|
68
111
|
if ( topLevelType === 'null' ) return cuts.join ( '' )
|
|
69
|
-
// Commands : raw, demo, handshake, placeholders
|
|
70
|
-
if ( typeof d === 'string' ) { // 'd' is a string when we want to debug the template
|
|
71
|
-
switch ( d ) {
|
|
72
|
-
case 'raw':
|
|
73
|
-
return cuts.join ( '' ) // Original template with placeholders
|
|
74
|
-
case 'demo':
|
|
75
|
-
if ( !handshake ) return `Error: No handshake data.`
|
|
76
|
-
d = handshake // Render with handshake object
|
|
77
|
-
topLevelType = _defineDataType ( d )
|
|
78
|
-
break
|
|
79
|
-
case 'handshake':
|
|
80
|
-
if ( !handshake ) return `Error: No handshake data.`
|
|
81
|
-
return structuredClone (handshake) // return a copy of handshake object
|
|
82
|
-
case 'placeholders':
|
|
83
|
-
return placeholders.map ( h => cuts[h.index] ).join ( ', ')
|
|
84
|
-
default:
|
|
85
|
-
return `Error: Wrong command "${d}". Available commands: raw, demo, handshake, placeholders.`
|
|
86
|
-
}
|
|
87
|
-
} // if 'd' is string
|
|
88
|
-
|
|
89
112
|
if ( topLevelType !== 'array' ) d = [ d ]
|
|
90
113
|
|
|
91
114
|
// Handle null data case - just return the template without placeholders
|
|
@@ -105,10 +128,15 @@ function build ( tpl, extra=false, buildDependencies={} ) {
|
|
|
105
128
|
|
|
106
129
|
|
|
107
130
|
if ( data && data.includes('/') ) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
131
|
+
if ( info.hasOwnProperty ( data )) {
|
|
132
|
+
info = info[data]
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
data.split('/').forEach ( d => {
|
|
136
|
+
if ( info.hasOwnProperty(d) ) info = info[d]
|
|
137
|
+
else info = []
|
|
138
|
+
})
|
|
139
|
+
}
|
|
112
140
|
} // If data contains '/'
|
|
113
141
|
else if ( data==='@all' || data===null || data==='@root' ) info = dElement
|
|
114
142
|
else if ( data ) info = info[data]
|
|
@@ -325,8 +353,10 @@ function build ( tpl, extra=false, buildDependencies={} ) {
|
|
|
325
353
|
break
|
|
326
354
|
} // switch accType
|
|
327
355
|
} // else other
|
|
328
|
-
}) // forEach placeholders
|
|
329
|
-
|
|
356
|
+
}) // forEach placeholders
|
|
357
|
+
|
|
358
|
+
if ( onlySnippets ) endData.push ( placeholders.map ( x => cuts[x.index] ).join ( '<~>' ) )
|
|
359
|
+
else endData.push ( cuts.join ( '' ))
|
|
330
360
|
}) // forEach d
|
|
331
361
|
|
|
332
362
|
if ( topLevelType === 'array' ) return endData
|