@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 CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
 
4
4
 
5
+ ### 2.2.0 ( 2025-06-06)
6
+ - [x] New: Source property can contains a symbol '/';
7
+
8
+
9
+
5
10
  ### 2.1.3 ( 2025-04-12 )
6
11
  - [x] Fix: Wrong set of arguments for helper functions when data is a primitive value;
7
12
 
@@ -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 2.x.x
12
- - Data helper functions modifies the data per placeholder;
13
- - Arguments for helper functions are named arguments;
14
- - Memory action introduced - memory is available in helper functions as a named argument;
15
- - Overwrite action introduced - when change in data should be available for all placeholders;
16
- - 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 ); // myTemplate is a render function
77
- const htmlBlock = myTemplate ( { name: 'Peter' } ) // Provide data to the render function and get the result
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
- ## Good Practices and Examples
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 myTemplateDescription = {
286
- template: `
287
- {{ : blank, ^^ , >myModification }}
288
- <h1>{{title}}</h1>
289
- {{list: ul,[],li,a}}
290
- `
291
- , helpers: {
292
- myModification : ({data}) => { // Modify original input data
293
- data.list.forEach ( (item,i) => item.count = i )
294
- return data
295
- }
296
- , blank : () => `` // use this helper function to remove the placeholder
297
- , a: `<a href="{{href}}">{{ count }}.{{text}}</a>`
298
- , li: `<li>{{text}}</li>`
299
- , ul: `<ul>{{text}}</ul>`
300
- }
301
- , handshake: {
302
- title: 'My title'
303
- , list: [
304
- { text: 'Item 1', href: 'item1.com' }
305
- , { text: 'Item 2', href: 'item2.com' }
306
- , { text: 'Item 3', href: 'item3.com' }
307
- ]
308
- }
309
- }
310
- const templateFn = morph.build ( myTemplateDescription );
311
- const result = templateFn ( 'demo' );
312
- // result ---> '<h1>My title</h1><ul><li><a href="item1.com">0.Item 1</a></li><li><a href="item2.com">1.Item 2</a></li><li><a href="item3.com">2.Item 3</a></li></ul>'
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:c}=e;let l,i,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),i=r.indexOf(o),-1==i)return n("missingClosing");if(i<l)return n("closedBeforeOpened");if(i+=c,-1!=u&&u<i)return n("newBeforeClosed");d.push(r.slice(l,i));let e=t(r.slice(i));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 c(n,c=!1,l={}){const{hasError:i,placeholders:u,chop:d,helpers:f,handshake:p}=function(e){const{template:t,helpers:n={},handshake:o}=e,{TG_PRX:s,TG_SFX:c}=a,l=[],i="string"==typeof t?t.replace(/<!--[\s\S]*?-->/g,"").replace(/\s{2,}/g," "):t;let u=null;const d=r(a)(i);return"string"==typeof d?u=d:d.forEach(((e,t)=>{const r=RegExp(s+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?"+c,"g");if(e.includes(s)){const a=r.exec(e);l.push({index:t,data:(n=a[1],n||null),action:a[2]?a[2].split(",").map((e=>e.trim())):null})}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]||(u=`Error: Missing helper: ${e}`,!1))))})),{hasError:u,placeholders:l,chop:d,helpers:n,handshake:o}}(n);if(i){function h(){return i}return c?[!1,h]:h}{let b=structuredClone(d);function m(r={},n={},...a){const c=[],i={};let d=o(r),h={...l,...n};if(r=e({data:r}),"null"===d)return b.join("");if("string"==typeof r)switch(r){case"raw":return b.join("");case"demo":if(!p)return"Error: No handshake data.";d=o(r=p);break;case"handshake":return p?structuredClone(p):"Error: No handshake data.";case"placeholders":return u.map((e=>b[e.index])).join(", ");default:return`Error: Wrong command "${r}". Available commands: raw, demo, handshake, placeholders.`}return"array"!==d&&(r=[r]),"null"===d?b.join(""):(r.forEach((r=>{u.forEach((n=>{const{index:a,data:c,action:l}=n,u=!l&&c,d=structuredClone(i),p={dependencies:h,memory:d};let m=r;if(c&&c.includes("/")?c.split("/").forEach((e=>{m=m.hasOwnProperty(e)?m[e]:[]})):"@all"===c||null===c||"@root"===c?m=r:c&&(m=m[c]),u){switch(o(m)){case"function":return void(b[a]=m());case"primitive":return void(b[a]=m);case"array":return void("primitive"===o(m[0])&&(b[a]=m[0]));case"object":return void(m.text&&(b[a]=m.text))}}else{let{dataDeepLevel:n,nestedData:c}=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,l),u=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 u){let{type:n,name:a,level:l}=t;(c[l]||[]).forEach(((t,u)=>{let d=o(t);switch(n){case"route":switch(d){case"array":t.forEach(((e,r)=>{if(null==e)return;const n=o(e),c=f[a]({data:e,...p});null!=c&&("object"===n?t[r].text=s(e,c,f,h):t[r]=s(e,c,f,h))}));break;case"object":t.text=s(t,a,f,h)}break;case"save":i[a]=structuredClone(t);break;case"overwrite":r=structuredClone(t);break;case"data":switch(d){case"array":t.forEach(((e,r)=>t[r]=e instanceof Function?f[a]({data:e(),...p}):f[a]({data:e,...p})));break;case"object":c[l]=[f[a]({data:t,...p})];break;case"function":c[l]=[f[a]({data:t(),...p})];break;case"primitive":c[l]=f[a]({data:t,...p})}break;case"render":const b="function"==typeof f[a];switch(d){case"array":b?t.forEach(((e,r)=>{if(null==e)return;const n=o(e),s=f[a]({data:e,...p});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),c=s(e,a,f,h);null==c?t[r]=null:"object"===n?e.text=c:t[r]=c}));break;case"function":c[l]=f[a]({data:t(),...p});break;case"primitive":c[l]=b?f[a]({data:t,...p}):s(t,a,f,h);break;case"object":b?c[l][u].text=f[a]({data:t,...p}):t.text=s(t,a,f,h)}break;case"extendedRender":"function"==typeof f[a]&&c[0].forEach(((e,t)=>c[0][t]=f[a]({data:e,...p})));break;case"mix":if(""===a)switch(d){case"object":Object.keys(t).find((e=>e.includes("/")))?Object.entries(t).forEach((([e,t])=>c[l][e]=t.text)):c[l]=t.text;for(let y=l-1;y>=0;y--)c[y]=e({data:c[y],objectCallback:m});function m({value:e,breadcrumbs:t}){return c[l][t]?c[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 v=f[a]({data:t,...p}),g=o(v);switch(t.forEach(((e,r)=>t.splice(r,1))),t.length=0,g){case"primitive":t[0]=v;break;case"array":t.push(...v)}}}}))}if(c instanceof Array&&1===c.length&&c[0]instanceof Array&&(c=c[0]),null==c[0])return;let d=o(c[0]),y=c[0];switch(d){case"primitive":if(null==y)return;b[a]=y;break;case"object":if(null==y.text)return;b[a]=y.text;break;case"array":const e=o(y[0]);b[a]="object"===e?y.map((e=>e.text)).join(""):y.join("")}}})),c.push(b.join(""))})),"array"===d?c:a?a.reduce(((e,t)=>"function"!=typeof t?e:t(e,h)),c.join("")):c.join(""))}return c?[!0,m]:m}}const l={default:{}};const i={build:c,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=c(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=i;
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;
@@ -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:l}=e;let c,i,u,f=[];if("string"!=typeof r)return n("notAString");if(0==r.length)return[];if(c=r.indexOf(a),0<c&&f.push(r.slice(0,c)),-1==c)return f.push(r),f;{if(u=r.indexOf(a,c+s),i=r.indexOf(o),-1==i)return n("missingClosing");if(i<c)return n("closedBeforeOpened");if(i+=l,-1!=u&&u<i)return n("newBeforeClosed");f.push(r.slice(c,i));let e=t(r.slice(i));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."}}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 l(n,l=!1,c={}){const{hasError:i,placeholders:u,chop:f,helpers:d,handshake:p}=function(e){const{template:t,helpers:n={},handshake:o}=e,{TG_PRX:s,TG_SFX:l}=a,c=[],i="string"==typeof t?t.replace(/<!--[\s\S]*?-->/g,"").replace(/\s{2,}/g," "):t;let u=null;const f=r(a)(i);return"string"==typeof f?u=f:f.forEach(((e,t)=>{const r=RegExp(s+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?"+l,"g");if(e.includes(s)){const a=r.exec(e);c.push({index:t,data:(n=a[1],n||null),action:a[2]?a[2].split(",").map((e=>e.trim())):null})}var n})),c.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:c,chop:f,helpers:n,handshake:o}}(n);if(i){function h(){return i}return l?[!1,h]:h}{let m=structuredClone(f);function b(r={},n={},...a){const l=[],i={};let f=o(r),h={...c,...n};if(r=e({data:r}),"null"===f)return m.join("");if("string"==typeof r)switch(r){case"raw":return m.join("");case"demo":if(!p)return"Error: No handshake data.";f=o(r=p);break;case"handshake":return p?structuredClone(p):"Error: No handshake data.";case"placeholders":return u.map((e=>m[e.index])).join(", ");default:return`Error: Wrong command "${r}". Available commands: raw, demo, handshake, placeholders.`}return"array"!==f&&(r=[r]),"null"===f?m.join(""):(r.forEach((r=>{u.forEach((n=>{const{index:a,data:l,action:c}=n,u=!c&&l,f=structuredClone(i),p={dependencies:h,memory:f};let b=r;if(l&&l.includes("/")?l.split("/").forEach((e=>{b=b.hasOwnProperty(e)?b[e]:[]})):"@all"===l||null===l||"@root"===l?b=r:l&&(b=b[l]),u){switch(o(b)){case"function":return void(m[a]=b());case"primitive":return void(m[a]=b);case"array":return void("primitive"===o(b[0])&&(m[a]=b[0]));case"object":return void(b.text&&(m[a]=b.text))}}else{let{dataDeepLevel:n,nestedData:l}=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})}(b,c),u=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}(c,n),n);for(let t of u){let{type:n,name:a,level:c}=t;(l[c]||[]).forEach(((t,u)=>{let f=o(t);switch(n){case"route":switch(f){case"array":t.forEach(((e,r)=>{if(null==e)return;const n=o(e),l=d[a]({data:e,...p});null!=l&&("object"===n?t[r].text=s(e,l,d,h):t[r]=s(e,l,d,h))}));break;case"object":t.text=s(t,a,d,h)}break;case"save":i[a]=structuredClone(t);break;case"overwrite":r=structuredClone(t);break;case"data":switch(f){case"array":t.forEach(((e,r)=>t[r]=e instanceof Function?d[a]({data:e(),...p}):d[a]({data:e,...p})));break;case"object":l[c]=[d[a]({data:t,...p})];break;case"function":l[c]=[d[a]({data:t(),...p})];break;case"primitive":l[c]=d[a]({data:t,...p})}break;case"render":const m="function"==typeof d[a];switch(f){case"array":m?t.forEach(((e,r)=>{if(null==e)return;const n=o(e),s=d[a]({data:e,...p});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),l=s(e,a,d,h);null==l?t[r]=null:"object"===n?e.text=l:t[r]=l}));break;case"function":l[c]=d[a]({data:t(),...p});break;case"primitive":l[c]=m?d[a]({data:t,...p}):s(t,a,d,h);break;case"object":m?l[c][u].text=d[a]({data:t,...p}):t.text=s(t,a,d,h)}break;case"extendedRender":"function"==typeof d[a]&&l[0].forEach(((e,t)=>l[0][t]=d[a]({data:e,...p})));break;case"mix":if(""===a)switch(f){case"object":Object.keys(t).find((e=>e.includes("/")))?Object.entries(t).forEach((([e,t])=>l[c][e]=t.text)):l[c]=t.text;for(let y=c-1;y>=0;y--)l[y]=e({data:l[y],objectCallback:b});function b({value:e,breadcrumbs:t}){return l[c][t]?l[c][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 v=d[a]({data:t,...p}),g=o(v);switch(t.forEach(((e,r)=>t.splice(r,1))),t.length=0,g){case"primitive":t[0]=v;break;case"array":t.push(...v)}}}}))}if(l instanceof Array&&1===l.length&&l[0]instanceof Array&&(l=l[0]),null==l[0])return;let f=o(l[0]),y=l[0];switch(f){case"primitive":if(null==y)return;m[a]=y;break;case"object":if(null==y.text)return;m[a]=y.text;break;case"array":const e=o(y[0]);m[a]="object"===e?y.map((e=>e.text)).join(""):y.join("")}}})),l.push(m.join(""))})),"array"===f?l:a?a.reduce(((e,t)=>"function"!=typeof t?e:t(e,h)),l.join("")):l.join(""))}return l?[!0,b]:b}}const c={default:{}};const i={build:l,get:function(e){if(!(e instanceof Array))return function(){return'Error: Argument "location" is a string. Should be an array. E.g. ["templateName", "storageName"].'};const[t,r="default"]=e;return c[r]?c[r][t]?c[r][t]:function(){return`Error: Template "${t}" does not exist in storage "${r}".`}:function(){return`Error: Storage "${r}" does not exist.`}},add:function(e,t,...r){const[n,a="default"]=e;if(null==t)return void console.warn(`Warning: Template ${a}/${n} is not added to storage. The template is null.`);let o=t,s=!0;if(c[a]||(c[a]={}),"function"!=typeof t){let e=l(t,!0,...r);s=e[0],o=e[1]}s?c[a][n]=o:console.error(`Error: Template "${n}" looks broken and is not added to storage.`)},list:function(e=["default"]){return e.map((e=>c[e]?Object.keys(c[e]):[])).flat()},clear:function(){Object.keys(c).forEach((e=>{"default"!=e?delete c[e]:c.default={}}))},remove:function(e){const[t,r="default"]=e;return c[r]?c[r][t]?void delete c[r][t]:`Error: Template "${t}" does not exist in storage "${r}".`:`Error: Storage "${r}" does not exist.`}};export{i as default};
1
+ import e from"@peter.naydenov/walk";import t from"@peter.naydenov/stack";function r(e){return function t(r){const{TG_PRX:a,TG_SFX:o,TG_SIZE_P:s,TG_SIZE_S: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": "2.1.3",
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.1.0",
36
- "rollup": "^4.39.0"
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
- placeholders.push ( {
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
- if ( !holder.action ) return
54
- holder.action.every ( act => {
55
- if ( act === '#' ) return true
56
- if ( act === '^^' ) return true
57
- if ( act.startsWith('^') && act !== '^^' ) return true
58
- if ( act.startsWith ( '?' )) act = act.replace ( '?', '' )
59
- if ( act.startsWith ( '+' )) act = act.replace ( '+', '' )
60
- if ( act.startsWith ( '[]' )) act = act.replace ( '[]', '' )
61
- if ( act.startsWith ( '>' )) act = act.replace ( '>', '' )
62
- if ( act === '' ) return true
63
- if ( helpers[act] ) return true
64
- else {
65
- hasError = `Error: Missing helper: ${act}`
66
- return false
67
- }
68
- }) // every action
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
 
@@ -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
- const { hasError, placeholders, chop, helpers, handshake } = _readTemplate ( tpl );
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
- * 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.
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
- data.split('/').forEach ( d => {
109
- if ( info.hasOwnProperty(d) ) info = info[d]
110
- else info = []
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
- endData.push ( cuts.join ( '' ))
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