@peter.naydenov/morph 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Changelog.md ADDED
@@ -0,0 +1,7 @@
1
+ ## Release History
2
+
3
+ ### 1.0.0 (2017-11-30)
4
+
5
+ - [x] Initial code;
6
+ - [x] Test package;
7
+ - [x] Documentation;
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Peter Naydenov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ # Migration Guides
2
+
3
+ No migration guide available yet
package/README.md ADDED
@@ -0,0 +1,207 @@
1
+ # Morph (@peter.naydenov/morph)
2
+ **Experimental stage. Not tested well yet.**
3
+
4
+ ![version](https://img.shields.io/github/package-json/v/peterNaydenov/morph)
5
+ ![license](https://img.shields.io/github/license/peterNaydenov/morph)
6
+ ![GitHub issues](https://img.shields.io/github/issues/peterNaydenov/morph)
7
+ ![GitHub top language](https://img.shields.io/github/languages/top/peterNaydenov/morph)
8
+ ![npm package minimized gzipped size (select exports)](https://img.shields.io/bundlejs/size/%40peter.naydenov%2Fmorph)
9
+
10
+
11
+
12
+ ## General Information
13
+
14
+ `Morph` has a logic-less template syntax. Placeholders are places surrounded by double curly braces `{{ }}` and they represents the pleces where the data will be inserted.
15
+
16
+ Engine is text based, so it can be used for HTML, CSS, config files, source code, etc.
17
+ Some features of Morph:
18
+ - Simple logic-less template syntax;
19
+ - Builtin storage;
20
+ - Powerfull action system for data decoration;
21
+ - Nesting templates as part of the action system;
22
+ - Partial rendering (render only available data);
23
+ - Option to connect templates to external data sources;
24
+ - Post process plugin mechanism;
25
+
26
+
27
+
28
+
29
+
30
+ ## Installation
31
+
32
+ ```
33
+ npm install @peter.naydenov/morph
34
+ ```
35
+
36
+ Morph can be used in browser and node.js.
37
+ ```js
38
+ import morph from "@peter.naydenov/morph"
39
+ // Morpho supports also require:
40
+ // const morph = require("@peter.naydenov/morph")
41
+ ```
42
+
43
+
44
+
45
+
46
+
47
+ ## Basic Usage
48
+
49
+ ```js
50
+ import morph from "@peter.naydenov/morph"
51
+
52
+ const myTemplateDescription = {
53
+ template: `Hello, {{name}}!` // simple template - a string with a placeholder
54
+ }
55
+ const myTemplate = morph.build ( myTemplateDescription ); // myTemplate is a render function
56
+ const htmlBlock = myTemplate ( { name: 'Peter' } ) // Provide data to the render function and get the result
57
+ // htmlBlock === 'Hello, Peter!'
58
+ ```
59
+
60
+ Morph contains also a builtin template storage. Instead of creating variable for each template, we can use the storage.
61
+
62
+ ```js
63
+ morph.add ( 'myTemplate', myTemplateDescription ) // add template to the storage. Automatically builds the render function
64
+ const htmlBlock = morph.get ( 'myTemplate' )({ name: 'Peter' }) // get template from the storage and render it
65
+ ```
66
+
67
+ Let's see a more complex example before we go into details:
68
+ ```js
69
+ const myTemplateDescription = {
70
+ template: `Hello, {{ person : a, >getReady }}! Your age is {{ person : >getAge}}.`
71
+ , helpers: {
72
+ getReady: (person) => {
73
+ return {
74
+ text: person.name
75
+ , href: person.web
76
+ }
77
+ }
78
+ , a: `<a href="{{href}}">{{text}}</a>`
79
+ , getAge: (person) => person.age
80
+ }
81
+ }
82
+ const myTemplate = morph.build ( myTemplateDescription );
83
+ const htmlBlock = myTemplate ( { person: {
84
+ name: 'Peter'
85
+ , age : 40
86
+ , web : 'example.com'
87
+ }
88
+ })
89
+ // htmlBlock === Hello, <a href="example.com">Peter</a>! Your age is 40.
90
+ ```
91
+
92
+
93
+
94
+
95
+
96
+ ## Template structure
97
+ Templates are objects with tree properties: `template`, `helpers`, and `handshake`:
98
+ ```js
99
+ const myTemplateDescription = {
100
+ template: `` // (required) Template string
101
+ , helpers: {
102
+ // (optional) Functions and templates used by actions to decorate the data
103
+ }
104
+ , handshake: {
105
+ // (optional) Example data used to render the template.
106
+ }
107
+ }
108
+ ```
109
+ `Template` is a string with placeholders where we render our external data. It's a skeleton of the template. Placeholders are the dynamic parts of the template.
110
+
111
+ Helpers are a extra templates or functions needed for rendering the template. Example:
112
+ ```js
113
+ const myTemplateDescription = {
114
+ template: `
115
+ <h1>{{title}}</h1>
116
+ <ul>
117
+ {{list:li,a}}
118
+ </ul>
119
+ `
120
+ , helpers: {
121
+ a: `<a href="{{href}}">{{text}}</a>`,
122
+ li: `<li>{{text}}</li>`
123
+ }
124
+ , handshake: {
125
+ title: 'My title'
126
+ , list: [
127
+ { text: 'Item 1', href: 'item1.com' }
128
+ , { text: 'Item 2', href: 'item2.com' }
129
+ , { text: 'Item 3', href: 'item3.com' }
130
+ ]
131
+ }
132
+ }
133
+ ```
134
+ Helpers will be discussed in details in next documentation section - 'Helper Functions'.
135
+
136
+
137
+
138
+
139
+
140
+ ## Placeholders
141
+
142
+ Template placeholders can contain data-source and actions separated by ':'. Data-source is a field of the data object used for the placeholder. Actions describe how the data should be decorated. Action is a list of operations separated by comma. Result from the first action is going as a argument to the second and so on. Executetion of actions is from right to left. Actions are optional.
143
+
144
+ ```js
145
+ `{{ name : act2, act1 }}`
146
+ // placeholder should take data from field 'name', execute 'act1' and 'act2' over it
147
+ // actions are separated by ',' and are executed from right to left
148
+
149
+ `{{ list : li, a }}`
150
+ // take data from 'list' and render each element first with 'a' then with 'li' actions
151
+
152
+ `{{ name }}` // render data from 'name'. Only data is provided to this placeholder
153
+ `{{ :someAction}}` // no data, but the result of the action will fill the placeholder
154
+ `{{ @all : someAction }}` // provide all the data to the action 'someAction'
155
+ ```
156
+
157
+
158
+
159
+ ## Actions
160
+
161
+ Actions are concise representations of a sequence of function calls. Some functions pertain to `data` manipulation, others to `rendering`, and some to `mixing`. We use a prefix system for enhanced readability and maintainability.
162
+
163
+ - `Render` functions are most used so they don't have any prefix;
164
+ - `Data` functions start with '>';
165
+ - `Mixing` functions start with '[]';
166
+ - `Conditional render` actions start with '?';
167
+ - `Extended render` start with '+';
168
+
169
+ Here are some examples:
170
+ ```js
171
+ `
172
+ {{ : li }} // example for render actions
173
+ {{ : >setup}} // example for data actions
174
+ {{ friends : []coma }} // example for mixing action
175
+ {{ list : ul, [], li, a}} // example with render and mixing actions
176
+ `
177
+ // NOTE: See that mixing function has no name after the prefix.
178
+ // Anonymous mixing is a build in function that will do -> resultList.join ( '' )
179
+ // The data will be rendered with 'a', then with 'li'
180
+ // then all 'li' elements will be merged and will be provided to 'ul'
181
+ ```
182
+
183
+ When input data is array, the result will be an array. Result for each element will stay separated until come the mixing function.
184
+
185
+ Learn more about how actions work in the section 'helper functions' below.
186
+
187
+
188
+
189
+
190
+
191
+
192
+ ## Links
193
+ - [Release history](Changelog.md)
194
+ - [ Migration guide ](https://github.com/PeterNaydenov/morph/blob/master/Migration.guide.md)
195
+
196
+
197
+
198
+ ## Credits
199
+ '@peter.naydenov/morph' was created and supported by Peter Naydenov.
200
+
201
+ ## License
202
+ '@peter.naydenov/morph' is released under the MIT License.
203
+
204
+
205
+
206
+
207
+
package/dist/morph.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";var e=require("@peter.naydenov/walk"),t=require("@peter.naydenov/stack");function r(e){return function t(r){const{TG_PRX:a,TG_SFX:o,TG_SIZE_P:s,TG_SIZE_S:c}=e;let i,l,u,f=[];if("string"!=typeof r)return n("notAString");if(0==r.length)return[];if(i=r.indexOf(a),0<i&&f.push(r.slice(0,i)),-1==i)return f.push(r),f;{if(u=r.indexOf(a,i+s),l=r.indexOf(o),-1==l)return n("missingClosing");if(l<i)return n("closedBeforeOpened");if(l+=c,-1!=u&&u<l)return n("newBeforeClosed");f.push(r.slice(i,l));let e=t(r.slice(l));return f.concat(e)}}}function n(e){switch(e){case"notAString":return"Error: Template is not a string.";case"missingClosing":return"Error: Placeholder with missing closing tag.";case"closedBeforeOpened":return"Error: Placeholder closing tag without starting one.";case"newBeforeClosed":return"Error: Nested placeholders. Close placeholder before open new one.";default:return"Error: Unknown template error."}}function a(t){const r={};let n=0;if(t instanceof Function)return{dataDeepLevel:0,nestedData:[t()]};if(null==t)return{dataDeepLevel:0,nestedData:[null]};if("string"==typeof t)return{dataDeepLevel:0,nestedData:[t]};return e({data:t,objectCallback:function({key:e,value:t,breadcrumbs:a}){let o=!1;return n=a.split("/").length-1,isNaN(e)||(o=!0),r[n]||(r[n]=o?[]:{}),"root"===e?r[n]=t:o?r[n].push(t):r[n][a]=t,t}}),{dataDeepLevel:n,nestedData:r}}var o={TG_PRX:"{{",TG_SFX:"}}",TG_SIZE_P:2,TG_SIZE_S:2};function s(e){return null==e?"null":"string"==typeof e||"number"==typeof e||"boolean"==typeof e?"primitive":"function"==typeof e?"function":e instanceof Array?"array":e instanceof Object?"object":void 0}function c(e,t,n){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text)}));const a="function"==typeof n[t];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),a?n[t](e):function(e,t){if(null==t)return null;const n=r(o)(e),a=o;return n.forEach(((e,r)=>{if(e.includes(a.TG_PRX)){const o=e.replace(a.TG_PRX,"").replace(a.TG_SFX,"").trim();t[o]&&(n[r]=t[o])}})),n.join("")}(n[t],e)}function i(n){const{hasError:i,placeholders:l,chop:u,helpers:f,handshake:d}=function(e){const{template:t,helpers:n,handshake:a}=e,{TG_PRX:s,TG_SFX:c,TG_SIZE_P:i,TG_SIZE_S:l}=o,u=[];let f=null;const d=r(o)(t);return"string"==typeof d?f=d:d.forEach(((e,t)=>{const r=RegExp(s+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?"+c,"g");if(e.includes(s)){const a=r.exec(e);u.push({index:t,data:(n=a[1],n||null),action:a[2]?a[2].split(",").map((e=>e.trim())):null})}var n})),u.forEach((e=>{e.action&&e.action.every((e=>"#"===e||(e.startsWith("?")&&(e=e.replace("?","")),e.startsWith("+")&&(e=e.replace("+","")),e.startsWith("[]")&&(e=e.replace("[]","")),e.startsWith(">")&&(e=e.replace(">","")),""===e||!!n[e]||(f=`Error: Missing helper: ${e}`,!1))))})),{hasError:f,placeholders:u,chop:d,helpers:n,handshake:a}}(n);if(i)return function(){return i};{let r=structuredClone(u);return function(n={},...o){const i=s(n),u=[];if("null"===i)return r.join("");if("string"==typeof n)switch(n){case"raw":return r.join("");case"demo":if(!d)return"Error: No handshake data.";n=d;break;case"handshake":return d?structuredClone(d):"Error: No handshake data.";case"placeholders":return l.map((e=>r[e.index])).join(", ");default:return`Error: Wrong command "${n}". Available commands: raw, demo, handshake, placeholders.`}return"array"!==i&&(n=[n]),n.forEach((n=>{l.forEach((o=>{const{index:i,data:l,action:u}=o;if(!u&&l){const d=n[l];switch(s(d)){case"function":return void(r[i]=d());case"primitive":return void(r[i]=d);case"array":return void("primitive"===s(d[0])&&(r[i]=d[0]));case"object":return void(d.text&&(r[i]=d.text))}}else{const{dataDeepLevel:p,nestedData:h}=a("@all"===l||null===l||"@root"===l?n:n[l]),b=function*(e,r){let n=t({type:"LIFO"});for(let t=0;t<=r;t++)n.push(e[t]);for(;n&&!n.isEmpty();){let e=yield n.pull();e&&n.push(e)}}(function(e,t=10){let r={},n=0,a=[...e],o=0;do{r[o]=[],o++}while(o<=t);return a.every((e=>"#"===e?(n++,!(n>t)):e.startsWith("?")?(r[n].push({type:"route",name:e.replace("?",""),level:n}),!0):e.startsWith("+")?(r[n].push({type:"extendedRender",name:e.replace("+",""),level:n}),!0):e.startsWith("[]")?(r[n].push({type:"mix",name:e.replace("[]",""),level:n}),!0):e.startsWith(">")?(r[n].push({type:"data",name:e.replace(">",""),level:n}),!0):(""===e||r[n].push({type:"render",name:e,level:n}),!0))),r}(u,p),p);for(let E of b){let{type:v,name:k,level:j}=E,x=h[j],g=s(x);switch(v){case"route":switch(g){case"array":x.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=f[k](e);null!=n&&("object"===r?x[t].text=c(e,n,f):x[t]=c(e,n,f))}));break;case"object":x.text=c(x,routeName,f);break;case"primitive":h[j]=c(x,routeName,f)}break;case"data":switch(g){case"array":x.forEach(((e,t)=>x[t]=e instanceof Function?f[k](e()):f[k](e)));break;case"object":case"primitive":h[j]=f[k](x);break;case"function":h[j]=f[k](x())}break;case"render":const _="function"==typeof f[k];switch(g){case"array":_?x.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=f[k](e);null==n&&(x[t]=null),"object"===r?e.text=n:x[t]=n})):x.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=c(e,k,f);null==n&&(x[t]=null),"object"===r?e.text=n:x[t]=n}));break;case"primitive":h[j]=c(x,k,f);break;case"object":Object.keys(x).find((e=>e.includes("/")))?Object.entries(x).forEach((([e,t])=>t.text=c(t,k,f))):x.text=c(x,k,f)}break;case"extendedRender":"function"==typeof f[k]&&(h[j]=f[k](h[0]));break;case"mix":if(""===k)switch(g){case"object":Object.keys(x).find((e=>e.includes("/")))?Object.entries(x).forEach((([e,t])=>h[j][e]=t.text)):h[j]=x.text;for(let T=j-1;T>=0;T--)h[T]=e({data:h[T],objectCallback:w});function w({value:e,breadcrumbs:t}){return h[j][t]?h[j][t]:e}break;case"array":h[j]=x.map((e=>"object"===s(e)?e.text:e)).filter((e=>null!=e)).join("")}else h[j]=f[k](x)}}let m=s(h[0]),y=h[0];switch(m){case"primitive":if(null==y)return;r[i]=y;break;case"object":if(null==y.text)return;r[i]=y.text;break;case"array":r[i]=y.join("")}}})),u.push(r.join(""))})),"array"===i?u:o?o.reduce(((e,t)=>t(e)),u.join("")):u.join("")}}}const l={default:{}};const u={build:i,get:function(e,t="default"){return l[t]?l[t][e]?l[t][e]:function(){return`Error: Template "${e}" does not exist in storage "${t}".`}:function(){return`Error: Storage "${t}" does not exist.`}},add:function(e,t,r="default"){let n=t;l[r]||(l[r]={}),"function"!=typeof t&&(n=i(t)),"success"===n.name?l[r][e]=n:console.error(`Error: Template "${e}" looks broken and is not added to storage.`)},list:function(e="default"){return l[e]?Object.keys(l[e]):[]},clear:function(){Object.keys(l).forEach((e=>{"default"!=e?delete l[e]:l.default={}}))},remove:function(e,t="default"){return l[t]?l[t][e]?void delete l[t][e]:`Error: Template "${e}" does not exist in storage "${t}".`:`Error: Storage "${t}" does not exist.`}};module.exports=u;
@@ -0,0 +1 @@
1
+ import e from"@peter.naydenov/walk";import t from"@peter.naydenov/stack";function r(e){return function t(r){const{TG_PRX:a,TG_SFX:o,TG_SIZE_P:s,TG_SIZE_S:c}=e;let i,l,u,f=[];if("string"!=typeof r)return n("notAString");if(0==r.length)return[];if(i=r.indexOf(a),0<i&&f.push(r.slice(0,i)),-1==i)return f.push(r),f;{if(u=r.indexOf(a,i+s),l=r.indexOf(o),-1==l)return n("missingClosing");if(l<i)return n("closedBeforeOpened");if(l+=c,-1!=u&&u<l)return n("newBeforeClosed");f.push(r.slice(i,l));let e=t(r.slice(l));return f.concat(e)}}}function n(e){switch(e){case"notAString":return"Error: Template is not a string.";case"missingClosing":return"Error: Placeholder with missing closing tag.";case"closedBeforeOpened":return"Error: Placeholder closing tag without starting one.";case"newBeforeClosed":return"Error: Nested placeholders. Close placeholder before open new one.";default:return"Error: Unknown template error."}}function a(t){const r={};let n=0;if(t instanceof Function)return{dataDeepLevel:0,nestedData:[t()]};if(null==t)return{dataDeepLevel:0,nestedData:[null]};if("string"==typeof t)return{dataDeepLevel:0,nestedData:[t]};return e({data:t,objectCallback:function({key:e,value:t,breadcrumbs:a}){let o=!1;return n=a.split("/").length-1,isNaN(e)||(o=!0),r[n]||(r[n]=o?[]:{}),"root"===e?r[n]=t:o?r[n].push(t):r[n][a]=t,t}}),{dataDeepLevel:n,nestedData:r}}var o={TG_PRX:"{{",TG_SFX:"}}",TG_SIZE_P:2,TG_SIZE_S:2};function s(e){return null==e?"null":"string"==typeof e||"number"==typeof e||"boolean"==typeof e?"primitive":"function"==typeof e?"function":e instanceof Array?"array":e instanceof Object?"object":void 0}function c(e,t,n){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text)}));const a="function"==typeof n[t];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),a?n[t](e):function(e,t){if(null==t)return null;const n=r(o)(e),a=o;return n.forEach(((e,r)=>{if(e.includes(a.TG_PRX)){const o=e.replace(a.TG_PRX,"").replace(a.TG_SFX,"").trim();t[o]&&(n[r]=t[o])}})),n.join("")}(n[t],e)}function i(n){const{hasError:i,placeholders:l,chop:u,helpers:f,handshake:d}=function(e){const{template:t,helpers:n,handshake:a}=e,{TG_PRX:s,TG_SFX:c,TG_SIZE_P:i,TG_SIZE_S:l}=o,u=[];let f=null;const d=r(o)(t);return"string"==typeof d?f=d:d.forEach(((e,t)=>{const r=RegExp(s+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?"+c,"g");if(e.includes(s)){const a=r.exec(e);u.push({index:t,data:(n=a[1],n||null),action:a[2]?a[2].split(",").map((e=>e.trim())):null})}var n})),u.forEach((e=>{e.action&&e.action.every((e=>"#"===e||(e.startsWith("?")&&(e=e.replace("?","")),e.startsWith("+")&&(e=e.replace("+","")),e.startsWith("[]")&&(e=e.replace("[]","")),e.startsWith(">")&&(e=e.replace(">","")),""===e||!!n[e]||(f=`Error: Missing helper: ${e}`,!1))))})),{hasError:f,placeholders:u,chop:d,helpers:n,handshake:a}}(n);if(i)return function(){return i};{let r=structuredClone(u);return function(n={},...o){const i=s(n),u=[];if("null"===i)return r.join("");if("string"==typeof n)switch(n){case"raw":return r.join("");case"demo":if(!d)return"Error: No handshake data.";n=d;break;case"handshake":return d?structuredClone(d):"Error: No handshake data.";case"placeholders":return l.map((e=>r[e.index])).join(", ");default:return`Error: Wrong command "${n}". Available commands: raw, demo, handshake, placeholders.`}return"array"!==i&&(n=[n]),n.forEach((n=>{l.forEach((o=>{const{index:i,data:l,action:u}=o;if(!u&&l){const d=n[l];switch(s(d)){case"function":return void(r[i]=d());case"primitive":return void(r[i]=d);case"array":return void("primitive"===s(d[0])&&(r[i]=d[0]));case"object":return void(d.text&&(r[i]=d.text))}}else{const{dataDeepLevel:p,nestedData:h}=a("@all"===l||null===l||"@root"===l?n:n[l]),b=function*(e,r){let n=t({type:"LIFO"});for(let t=0;t<=r;t++)n.push(e[t]);for(;n&&!n.isEmpty();){let e=yield n.pull();e&&n.push(e)}}(function(e,t=10){let r={},n=0,a=[...e],o=0;do{r[o]=[],o++}while(o<=t);return a.every((e=>"#"===e?(n++,!(n>t)):e.startsWith("?")?(r[n].push({type:"route",name:e.replace("?",""),level:n}),!0):e.startsWith("+")?(r[n].push({type:"extendedRender",name:e.replace("+",""),level:n}),!0):e.startsWith("[]")?(r[n].push({type:"mix",name:e.replace("[]",""),level:n}),!0):e.startsWith(">")?(r[n].push({type:"data",name:e.replace(">",""),level:n}),!0):(""===e||r[n].push({type:"render",name:e,level:n}),!0))),r}(u,p),p);for(let E of b){let{type:v,name:k,level:j}=E,x=h[j],g=s(x);switch(v){case"route":switch(g){case"array":x.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=f[k](e);null!=n&&("object"===r?x[t].text=c(e,n,f):x[t]=c(e,n,f))}));break;case"object":x.text=c(x,routeName,f);break;case"primitive":h[j]=c(x,routeName,f)}break;case"data":switch(g){case"array":x.forEach(((e,t)=>x[t]=e instanceof Function?f[k](e()):f[k](e)));break;case"object":case"primitive":h[j]=f[k](x);break;case"function":h[j]=f[k](x())}break;case"render":const _="function"==typeof f[k];switch(g){case"array":_?x.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=f[k](e);null==n&&(x[t]=null),"object"===r?e.text=n:x[t]=n})):x.forEach(((e,t)=>{if(null==e)return;const r=s(e),n=c(e,k,f);null==n&&(x[t]=null),"object"===r?e.text=n:x[t]=n}));break;case"primitive":h[j]=c(x,k,f);break;case"object":Object.keys(x).find((e=>e.includes("/")))?Object.entries(x).forEach((([e,t])=>t.text=c(t,k,f))):x.text=c(x,k,f)}break;case"extendedRender":"function"==typeof f[k]&&(h[j]=f[k](h[0]));break;case"mix":if(""===k)switch(g){case"object":Object.keys(x).find((e=>e.includes("/")))?Object.entries(x).forEach((([e,t])=>h[j][e]=t.text)):h[j]=x.text;for(let T=j-1;T>=0;T--)h[T]=e({data:h[T],objectCallback:w});function w({value:e,breadcrumbs:t}){return h[j][t]?h[j][t]:e}break;case"array":h[j]=x.map((e=>"object"===s(e)?e.text:e)).filter((e=>null!=e)).join("")}else h[j]=f[k](x)}}let m=s(h[0]),y=h[0];switch(m){case"primitive":if(null==y)return;r[i]=y;break;case"object":if(null==y.text)return;r[i]=y.text;break;case"array":r[i]=y.join("")}}})),u.push(r.join(""))})),"array"===i?u:o?o.reduce(((e,t)=>t(e)),u.join("")):u.join("")}}}const l={default:{}};const u={build:i,get:function(e,t="default"){return l[t]?l[t][e]?l[t][e]:function(){return`Error: Template "${e}" does not exist in storage "${t}".`}:function(){return`Error: Storage "${t}" does not exist.`}},add:function(e,t,r="default"){let n=t;l[r]||(l[r]={}),"function"!=typeof t&&(n=i(t)),"success"===n.name?l[r][e]=n:console.error(`Error: Template "${e}" looks broken and is not added to storage.`)},list:function(e="default"){return l[e]?Object.keys(l[e]):[]},clear:function(){Object.keys(l).forEach((e=>{"default"!=e?delete l[e]:l.default={}}))},remove:function(e,t="default"){return l[t]?l[t][e]?void delete l[t][e]:`Error: Template "${e}" does not exist in storage "${t}".`:`Error: Storage "${t}" does not exist.`}};export{u as default};
@@ -0,0 +1 @@
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@peter.naydenov/walk")):"function"==typeof define&&define.amd?define(["@peter.naydenov/walk"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).morph=t(e.walk)}(this,(function(e){"use strict";function t(e){return function t(n){const{TG_PRX:o,TG_SFX:a,TG_SIZE_P:i,TG_SIZE_S:s}=e;let l,c,u,f=[];if("string"!=typeof n)return r("notAString");if(0==n.length)return[];if(l=n.indexOf(o),0<l&&f.push(n.slice(0,l)),-1==l)return f.push(n),f;{if(u=n.indexOf(o,l+i),c=n.indexOf(a),-1==c)return r("missingClosing");if(c<l)return r("closedBeforeOpened");if(c+=s,-1!=u&&u<c)return r("newBeforeClosed");f.push(n.slice(l,c));let e=t(n.slice(c));return f.concat(e)}}}function r(e){switch(e){case"notAString":return"Error: Template is not a string.";case"missingClosing":return"Error: Placeholder with missing closing tag.";case"closedBeforeOpened":return"Error: Placeholder closing tag without starting one.";case"newBeforeClosed":return"Error: Nested placeholders. Close placeholder before open new one.";default:return"Error: Unknown template error."}}function n(t){const r={};let n=0;if(t instanceof Function)return{dataDeepLevel:0,nestedData:[t()]};if(null==t)return{dataDeepLevel:0,nestedData:[null]};if("string"==typeof t)return{dataDeepLevel:0,nestedData:[t]};return e({data:t,objectCallback:function({key:e,value:t,breadcrumbs:o}){let a=!1;return n=o.split("/").length-1,isNaN(e)||(a=!0),r[n]||(r[n]=a?[]:{}),"root"===e?r[n]=t:a?r[n].push(t):r[n][o]=t,t}}),{dataDeepLevel:n,nestedData:r}}function*o(e,t){let r=function(e={}){let t=[],{type:r,limit:n,onLimit:o}=Object.assign({},{type:"FIFO",limit:!1,onLimit:"update"},e),a="LIFO"===r.toUpperCase(),i=!1;function s(e=1,r=0){let n=[];return r>0&&Array.from({length:r}).map((()=>t.pop())),1==e?t.pop():(Array.from({length:e}).map((()=>{let e=t.pop();null!=e&&n.push(e)})),n)}function l(e=1,r=0){let n=[],o=t.length-r;return e>1&&Array.from({length:e}).map((()=>{null!=t[o-1]&&n.push(t[o-1]),o--})),1==e?t[t.length-1]:n}function c(){}return c.prototype={pull:s,pullReverse:function(e=1,t=0){let r=s(e,t);return r instanceof Array?r.reverse():r},peek:l,peekReverse:function(e=1,t=0){const r=l(e,t);return r instanceof Array?r.reverse():r},getSize:()=>t.length,isEmpty:()=>0==t.length,reset:()=>(t=[],!0),debug:()=>[...t]},c.prototype.push=a?function(e){const r=e instanceof Array,a=r?e.length:1;let l=!1;if("full"!==o||!i){if(n&&r&&a>n&&(e=e.slice(0,-a+n)),n){const a=(r?e.length:1)+t.length;a>=n&&"full"===o&&(e=e.slice(0,-(a-n))),a>=n&&"update"===o&&(l=s(a-n))}return t=e instanceof Array?t.concat(e):t.concat([e]),i=!!n&&t.length===n,l||void 0}}:function(e){const r=e instanceof Array,a=r?e.length:1;let l=!1;if("full"!==o||!i){if(n&&r&&a>n&&(e=e.slice(a-n)),n){const a=(r?e.length:1)+t.length;a>=n&&"full"===o&&(e=e.slice(0,-(a-n))),a>=n&&"update"===o&&(l=s(a-n))}return t=r?e.reduce(((e,t)=>[t,...e]),t):[e].reduce(((e,t)=>[t,...e]),t),i=!!n&&t.length===n,l||void 0}},new c}({type:"LIFO"});for(let n=0;n<=t;n++)r.push(e[n]);for(;r&&!r.isEmpty();){let e=yield r.pull();e&&r.push(e)}}var a={TG_PRX:"{{",TG_SFX:"}}",TG_SIZE_P:2,TG_SIZE_S:2};function i(e){return null==e?"null":"string"==typeof e||"number"==typeof e||"boolean"==typeof e?"primitive":"function"==typeof e?"function":e instanceof Array?"array":e instanceof Object?"object":void 0}function s(e,r,n){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text)}));const o="function"==typeof n[r];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),o?n[r](e):function(e,r){if(null==r)return null;const n=t(a)(e),o=a;return n.forEach(((e,t)=>{if(e.includes(o.TG_PRX)){const a=e.replace(o.TG_PRX,"").replace(o.TG_SFX,"").trim();r[a]&&(n[t]=r[a])}})),n.join("")}(n[r],e)}function l(r){const{hasError:l,placeholders:c,chop:u,helpers:f,handshake:p}=function(e){const{template:r,helpers:n,handshake:o}=e,{TG_PRX:i,TG_SFX:s,TG_SIZE_P:l,TG_SIZE_S:c}=a,u=[];let f=null;const p=t(a)(r);return"string"==typeof p?f=p:p.forEach(((e,t)=>{const r=RegExp(i+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?"+s,"g");if(e.includes(i)){const o=r.exec(e);u.push({index:t,data:(n=o[1],n||null),action:o[2]?o[2].split(",").map((e=>e.trim())):null})}var n})),u.forEach((e=>{e.action&&e.action.every((e=>"#"===e||(e.startsWith("?")&&(e=e.replace("?","")),e.startsWith("+")&&(e=e.replace("+","")),e.startsWith("[]")&&(e=e.replace("[]","")),e.startsWith(">")&&(e=e.replace(">","")),""===e||!!n[e]||(f=`Error: Missing helper: ${e}`,!1))))})),{hasError:f,placeholders:u,chop:p,helpers:n,handshake:o}}(r);if(l)return function(){return l};{let t=structuredClone(u);return function(r={},...a){const l=i(r),u=[];if("null"===l)return t.join("");if("string"==typeof r)switch(r){case"raw":return t.join("");case"demo":if(!p)return"Error: No handshake data.";r=p;break;case"handshake":return p?structuredClone(p):"Error: No handshake data.";case"placeholders":return c.map((e=>t[e.index])).join(", ");default:return`Error: Wrong command "${r}". Available commands: raw, demo, handshake, placeholders.`}return"array"!==l&&(r=[r]),r.forEach((r=>{c.forEach((a=>{const{index:l,data:c,action:u}=a;if(!u&&c){const p=r[c];switch(i(p)){case"function":return void(t[l]=p());case"primitive":return void(t[l]=p);case"array":return void("primitive"===i(p[0])&&(t[l]=p[0]));case"object":return void(p.text&&(t[l]=p.text))}}else{const{dataDeepLevel:d,nestedData:h}=n("@all"===c||null===c||"@root"===c?r:r[c]),m=o(function(e,t=10){let r={},n=0,o=[...e],a=0;do{r[a]=[],a++}while(a<=t);return o.every((e=>"#"===e?(n++,!(n>t)):e.startsWith("?")?(r[n].push({type:"route",name:e.replace("?",""),level:n}),!0):e.startsWith("+")?(r[n].push({type:"extendedRender",name:e.replace("+",""),level:n}),!0):e.startsWith("[]")?(r[n].push({type:"mix",name:e.replace("[]",""),level:n}),!0):e.startsWith(">")?(r[n].push({type:"data",name:e.replace(">",""),level:n}),!0):(""===e||r[n].push({type:"render",name:e,level:n}),!0))),r}(u,d),d);for(let g of m){let{type:v,name:E,level:k}=g,j=h[k],x=i(j);switch(v){case"route":switch(x){case"array":j.forEach(((e,t)=>{if(null==e)return;const r=i(e),n=f[E](e);null!=n&&("object"===r?j[t].text=s(e,n,f):j[t]=s(e,n,f))}));break;case"object":j.text=s(j,routeName,f);break;case"primitive":h[k]=s(j,routeName,f)}break;case"data":switch(x){case"array":j.forEach(((e,t)=>j[t]=e instanceof Function?f[E](e()):f[E](e)));break;case"object":case"primitive":h[k]=f[E](j);break;case"function":h[k]=f[E](j())}break;case"render":const w="function"==typeof f[E];switch(x){case"array":w?j.forEach(((e,t)=>{if(null==e)return;const r=i(e),n=f[E](e);null==n&&(j[t]=null),"object"===r?e.text=n:j[t]=n})):j.forEach(((e,t)=>{if(null==e)return;const r=i(e),n=s(e,E,f);null==n&&(j[t]=null),"object"===r?e.text=n:j[t]=n}));break;case"primitive":h[k]=s(j,E,f);break;case"object":Object.keys(j).find((e=>e.includes("/")))?Object.entries(j).forEach((([e,t])=>t.text=s(t,E,f))):j.text=s(j,E,f)}break;case"extendedRender":"function"==typeof f[E]&&(h[k]=f[E](h[0]));break;case"mix":if(""===E)switch(x){case"object":Object.keys(j).find((e=>e.includes("/")))?Object.entries(j).forEach((([e,t])=>h[k][e]=t.text)):h[k]=j.text;for(let _=k-1;_>=0;_--)h[_]=e({data:h[_],objectCallback:T});function T({value:e,breadcrumbs:t}){return h[k][t]?h[k][t]:e}break;case"array":h[k]=j.map((e=>"object"===i(e)?e.text:e)).filter((e=>null!=e)).join("")}else h[k]=f[E](j)}}let y=i(h[0]),b=h[0];switch(y){case"primitive":if(null==b)return;t[l]=b;break;case"object":if(null==b.text)return;t[l]=b.text;break;case"array":t[l]=b.join("")}}})),u.push(t.join(""))})),"array"===l?u:a?a.reduce(((e,t)=>t(e)),u.join("")):u.join("")}}}const c={default:{}};return{build:l,get:function(e,t="default"){return c[t]?c[t][e]?c[t][e]:function(){return`Error: Template "${e}" does not exist in storage "${t}".`}:function(){return`Error: Storage "${t}" does not exist.`}},add:function(e,t,r="default"){let n=t;c[r]||(c[r]={}),"function"!=typeof t&&(n=l(t)),"success"===n.name?c[r][e]=n:console.error(`Error: Template "${e}" looks broken and is not added to storage.`)},list:function(e="default"){return c[e]?Object.keys(c[e]):[]},clear:function(){Object.keys(c).forEach((e=>{"default"!=e?delete c[e]:c.default={}}))},remove:function(e,t="default"){return c[t]?c[t][e]?void delete c[t][e]:`Error: Template "${e}" does not exist in storage "${t}".`:`Error: Storage "${t}" does not exist.`}}}));
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@peter.naydenov/morph",
3
+ "description": "Template engine",
4
+ "version": "0.0.1",
5
+ "license": "MIT",
6
+ "author": "Peter Naydenov",
7
+ "main": "./dist/morph.umd.js",
8
+ "type": "module",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/morph.esm.mjs",
12
+ "require": "./dist/morph.cjs",
13
+ "default": "./dist/morph.umd.js"
14
+ },
15
+ "./package.json": "./package.json",
16
+ "./dist/*": "./dist/*",
17
+ "./src/*": "./src/*"
18
+ },
19
+ "scripts": {
20
+ "test": "mocha test",
21
+ "cover": "c8 mocha",
22
+ "build": "rollup -c"
23
+ },
24
+ "dependencies": {
25
+ "@peter.naydenov/stack": "^3.0.0",
26
+ "@peter.naydenov/walk": "^5.0.0"
27
+ },
28
+ "devDependencies": {
29
+ "@rollup/plugin-commonjs": "^28.0.0",
30
+ "@rollup/plugin-node-resolve": "^15.3.0",
31
+ "@rollup/plugin-terser": "^0.4.4",
32
+ "c8": "^10.1.2",
33
+ "chai": "5.1.2",
34
+ "mocha": "10.8.2",
35
+ "rollup": "^4.27.4"
36
+ },
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/PeterNaydenov/morph.git"
40
+ },
41
+ "c8": {
42
+ "include": [
43
+ "src/**/*.js"
44
+ ],
45
+ "exclude": [
46
+ "node_modules",
47
+ "test"
48
+ ],
49
+ "reporter": [
50
+ "lcov",
51
+ "text-summary"
52
+ ]
53
+ },
54
+ "keywords": [
55
+ "template",
56
+ "engine",
57
+ "string",
58
+ "function"
59
+ ]
60
+
61
+ }
@@ -0,0 +1,42 @@
1
+ import resolve from '@rollup/plugin-node-resolve'
2
+ import commonjs from '@rollup/plugin-commonjs'
3
+ import terser from '@rollup/plugin-terser';
4
+
5
+
6
+ export default [
7
+ // browser-friendly UMD build
8
+ {
9
+ input: 'src/main.js',
10
+ output: {
11
+ name: 'morph',
12
+ file: 'dist/morph.umd.js',
13
+ format: 'umd',
14
+ globals: {
15
+ '@peter.naydenov/walk': 'walk'
16
+ , '@peter.naydenov/stack': 'stack'
17
+ }
18
+ },
19
+ external: ['@peter.naydenov/walk'],
20
+ plugins: [
21
+ resolve(), // so Rollup can find `ms`
22
+ commonjs() // so Rollup can convert `ms` to an ES module
23
+ , terser()
24
+ ]
25
+ },
26
+
27
+ // CommonJS (for Node) and ES module (for bundlers) build.
28
+ // (We could have three entries in the configuration array
29
+ // instead of two, but it's quicker to generate multiple
30
+ // builds from a single configuration where possible, using
31
+ // an array for the `output` option, where we can specify
32
+ // `file` and `format` for each target)
33
+ {
34
+ input: 'src/main.js',
35
+ external: ['@peter.naydenov/walk', '@peter.naydenov/stack'],
36
+ output: [
37
+ { file: 'dist/morph.cjs' , format: 'cjs' },
38
+ { file: 'dist/morph.esm.mjs', format: 'es' }
39
+ ],
40
+ plugins: [ terser() ]
41
+ }
42
+ ];
package/src/main.js ADDED
@@ -0,0 +1,100 @@
1
+ /***
2
+ * Morph (@peter.naydenov/morph)
3
+ *
4
+ * Text based template engine
5
+ *
6
+ *
7
+ * History notes:
8
+ * - Idea was born on October 28th, 2024.
9
+ * - Published on GitHub for first time: November 30th, 2024
10
+ *
11
+ */
12
+
13
+
14
+ import build from "./methods/build.js"
15
+
16
+
17
+
18
+ const storage = { default: {}};
19
+
20
+
21
+
22
+ function get ( prop, strName='default' ) {
23
+ if ( !storage[strName] ) {
24
+ return function () {
25
+ return `Error: Storage "${strName}" does not exist.`
26
+ }
27
+ }
28
+ if ( !storage[strName][prop] ) {
29
+ return function () {
30
+ return `Error: Template "${prop}" does not exist in storage "${strName}".`
31
+ }
32
+ }
33
+ return storage[strName][prop]
34
+ } // get func.
35
+
36
+
37
+
38
+ function add ( name, tplfn, strName='default' ) {
39
+ let fn = tplfn;
40
+ if( !storage[strName] ) storage[strName] = {}
41
+ if ( typeof tplfn !== 'function' ) fn = build ( tplfn );
42
+ if ( fn.name === 'success' ) storage[strName][name] = fn
43
+ else console.error ( `Error: Template "${name}" looks broken and is not added to storage.` )
44
+ } // add func.
45
+
46
+
47
+
48
+ function list ( strName='default' ) {
49
+ if ( !storage[strName] ) return []
50
+ return Object.keys ( storage[strName] )
51
+ } // list func.
52
+
53
+
54
+
55
+ function clear ( ) {
56
+ const keys = Object.keys ( storage )
57
+ keys.forEach ( key => {
58
+ if ( key != 'default' ) delete storage[key]
59
+ else storage['default'] = {}
60
+ })
61
+ } // clear func.
62
+
63
+
64
+
65
+ function remove ( name, strName='default' ) {
66
+ if ( !storage[strName] ) return `Error: Storage "${strName}" does not exist.`
67
+ if ( !storage[strName][name] ) return `Error: Template "${name}" does not exist in storage "${strName}".`
68
+ delete storage[strName][name]
69
+ } // remove func.
70
+
71
+
72
+
73
+ const morphAPI = {
74
+ // Engine API
75
+ /**
76
+ *
77
+ * build -
78
+ * add - register a component to component storage
79
+ * get - get a component from component storage
80
+ * list - list all components in component storage
81
+ * clear - clear all templates in component storage
82
+ * remove - remove a template from component storage
83
+ *
84
+ * shine - extra step to remove all non used placeholders and <rs> tags
85
+ *
86
+ */
87
+ build // build a component from template description
88
+ , get // get a component from component storage
89
+ , add // add a component to component storage
90
+ , list // list all components in component storage
91
+ , clear // clear all templates in component storage
92
+ , remove // remove a template from component storage
93
+ } // morphAPI
94
+
95
+ // TODO: How to change render templates on condition?
96
+ // - Use compiled versions of simile templates
97
+
98
+ export default morphAPI
99
+
100
+
@@ -0,0 +1,19 @@
1
+ import stack from "@peter.naydenov/stack"
2
+
3
+
4
+
5
+ function* _actionSupply ( act, level ) {
6
+ let action = stack ({ type:'LIFO' });
7
+ for ( let i=0; i<=level; i++ ) {
8
+ action.push ( act[i] )
9
+ }
10
+ while ( action && !action.isEmpty () ) {
11
+ let newAct = yield action.pull ()
12
+ if ( newAct ) action.push ( newAct )
13
+ }
14
+ } // _actionSupply func.
15
+
16
+
17
+ export default _actionSupply
18
+
19
+
@@ -0,0 +1,60 @@
1
+ function _chopTemplate ( settings ) {
2
+ return function _chopTemplate ( text ) {
3
+ const { TG_PRX, TG_SFX, TG_SIZE_P, TG_SIZE_S } = settings;
4
+ let
5
+ start // placeholder start
6
+ , end // placeholder end
7
+ , checkPoint // check
8
+ , res = [] // template result array
9
+ ;
10
+
11
+ if ( typeof(text) != 'string' ) return showError( 'notAString' ) // Template is not a string
12
+ if ( text.length == 0 ) return []
13
+
14
+ start = text.indexOf ( TG_PRX )
15
+ if ( 0 < start ) res.push ( text.slice(0, start) )
16
+ if ( -1 == start ) {
17
+ res.push( text )
18
+ return res;
19
+ }
20
+ else {
21
+ checkPoint = text.indexOf ( TG_PRX, start+TG_SIZE_P )
22
+ end = text.indexOf( TG_SFX )
23
+
24
+ if ( end == -1 ) return showError('missingClosing') // Placeholder with missing closing tags
25
+ if ( end < start ) return showError('closedBeforeOpened') // Placeholder closing tags without starting ones
26
+ else end += TG_SIZE_S
27
+
28
+ if ( checkPoint != -1 && checkPoint < end ) {
29
+ return showError('newBeforeClosed') // New placeholder before first ends
30
+ }
31
+
32
+ res.push( text.slice(start,end) )
33
+ let nextText = text.slice (end)
34
+ let additional = _chopTemplate ( nextText )
35
+ return res.concat ( additional )
36
+ }
37
+ }} // chopTemplate func.
38
+
39
+
40
+
41
+ function showError (type) {
42
+ switch (type) {
43
+ case 'notAString':
44
+ return `Error: Template is not a string.`
45
+ case 'missingClosing':
46
+ return `Error: Placeholder with missing closing tag.`
47
+ case 'closedBeforeOpened':
48
+ return `Error: Placeholder closing tag without starting one.`
49
+ case 'newBeforeClosed':
50
+ return `Error: Nested placeholders. Close placeholder before open new one.`
51
+ default:
52
+ return `Error: Unknown template error.`
53
+ }
54
+ } // showError func.
55
+
56
+
57
+
58
+ export default _chopTemplate
59
+
60
+
@@ -0,0 +1,32 @@
1
+ import walk from '@peter.naydenov/walk'
2
+
3
+
4
+
5
+ function _defineData ( d ) {
6
+ const nestedData = {};
7
+ let dataDeepLevel = 0;
8
+
9
+ if ( d instanceof Function ) return { dataDeepLevel:0, nestedData:[d()] }
10
+ if ( d == null ) return { dataDeepLevel:0, nestedData:[ null ] }
11
+ if ( typeof d === 'string' ) return { dataDeepLevel:0, nestedData:[d] }
12
+
13
+ function findObjects ({key, value, breadcrumbs}) {
14
+ let isArray = false;
15
+ dataDeepLevel = breadcrumbs.split('/').length -1;
16
+ if ( !isNaN(key) ) isArray = true
17
+ if ( !nestedData[dataDeepLevel] ) nestedData[dataDeepLevel] = isArray? [] : {}
18
+ if ( key === 'root' ) nestedData[dataDeepLevel] = value
19
+ else if ( isArray ) nestedData[dataDeepLevel].push ( value )
20
+ else nestedData[dataDeepLevel][breadcrumbs] = value
21
+ return value
22
+ } // step func.
23
+
24
+ walk ({ data:d, objectCallback:findObjects })
25
+ return { dataDeepLevel, nestedData }
26
+ } // _defineData func.
27
+
28
+
29
+
30
+ export default _defineData
31
+
32
+
@@ -0,0 +1,16 @@
1
+ function _defineDataType ( data ) {
2
+
3
+ if ( data == null ) return 'null'
4
+ if ( typeof data === 'string' ) return 'primitive'
5
+ if ( typeof data === 'number' ) return 'primitive'
6
+ if ( typeof data === 'boolean' ) return 'primitive'
7
+ if ( typeof data === 'function') return 'function'
8
+ if ( data instanceof Array ) return 'array'
9
+ if ( data instanceof Object ) return 'object'
10
+ return undefined
11
+ } // _defineDataType func.
12
+
13
+
14
+ export default _defineDataType
15
+
16
+