sjabloon 0.4.0 → 0.4.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # sjabloon
2
2
 
3
- A tiny, CSP-safe template engine for JavaScript. **~0.8KB min+gzip (~2KB with [xprsn](https://www.npmjs.com/package/xprsn)), one dependency.**
3
+ A tiny, CSP-safe template engine for JavaScript. **~1.2KB min+gzip (~2.5KB with [xprsn](https://www.npmjs.com/package/xprsn)), one dependency.**
4
4
 
5
5
  [![NPM version](https://img.shields.io/npm/v/sjabloon.svg)](https://www.npmjs.com/package/sjabloon)
6
6
  [![Build Status](https://github.com/robinvdvleuten/sjabloon/actions/workflows/test.yml/badge.svg)](https://github.com/robinvdvleuten/sjabloon/actions/workflows/test.yml)
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- var t=require("xprsn");function r(t,r){(null==r||r>t.length)&&(r=t.length);for(var e=0,n=Array(r);e<r;e++)n[e]=t[e];return n}function e(t,e){var n="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(n)return(n=n.call(t)).next.bind(n);if(Array.isArray(t)||(n=function(t,e){if(t){if("string"==typeof t)return r(t,e);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?r(t,e):void 0}}(t))||e&&t&&"number"==typeof t.length){n&&(t=n);var a=0;return function(){return a>=t.length?{done:!0}:{done:!1,value:t[a++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var n,a,i,u,o,l,c,f={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},s=function(t){return String(t).replace(/[&<>"']/g,function(t){return f[t]})},h=/\{\{\{(-)?\s*([\s\S]*?)\s*(-)?\}\}\}|\{\{(-)?\s*([\s\S]*?)\s*(-)?\}\}/,g=function(t){throw SyntaxError(t)},p=function(t,r){return t.map(function(t){return t(r)}).join("")},v=function(t,r){return e=d(t),function(t){var n;return r(null!=(n=e(t))?n:"")};var e},d=function(r){for(var n,a=t.compile(r,i),u=e(a.names);!(n=u()).done;){var f=n.value;o.has(f)||l.add(f)}for(var s,h=e(a.functions);!(s=h()).done;)c.add(s.value);return a},m=function(t){var r=y(["#elif","#else","/if"]),e=u.startsWith("#elif ")?[m(d(u.slice(6)))]:"#else"===u?y(["/if"]):[];return function(n){return p(t(n)?r:e,n)}},y=function(t){for(var r,e,i=[],l=function(){if(null!=e.text)i.push((x=e.text,function(){return x}));else if(null!=e.raw)i.push(v(e.raw,String));else{if(t.includes(e.tag.split(" ")[0]))return u=e.tag,{v:i};if("!"===e.tag[0]);else if(e.tag.startsWith("#if "))i.push(m(d(e.tag.slice(4))));else if(e.tag.startsWith("#each ")){var r=/^#each ([\s\S]+) as (\w+)(?:\s*,\s*(\w+))?$/.exec(e.tag)||g("Bad {{"+e.tag+"}}"),n=d(r[1]),a=r[2],l=r[3],c=function(){var t=[].slice.call(arguments).filter(function(t){return t&&!o.has(t)});return t.forEach(function(t){return o.add(t)}),function(){return t.forEach(function(t){return o.delete(t)})}}(a,l,"loop"),f=y(["#else","/each"]);c();var h="#else"===u?y(["/each"]):[];i.push(function(t){var r,e=(r=n(t),Array.isArray(r)?r.map(function(t,r){return[t,r]}):r&&"object"==typeof r?Object.keys(r).map(function(t){return[r[t],t]}):[]);return e.length?e.map(function(r,n){var i=r[0],u=r[1],o=Object.create(t);return o[a]=i,l&&(o[l]=u),o["@"]=i,o.loop={index:n+1,index0:n,first:!n,last:n===e.length-1,length:e.length},p(f,o)}).join(""):p(h,t)})}else"#"===e.tag[0]||"/"===e.tag[0]?g("Unexpected {{"+e.tag+"}}"):i.push(v(e.tag,s))}var x};e=n[a++];)if(r=l())return r.v;return t.length&&g("Missing {{"+t[t.length-1]+"}}"),i};function x(t,r){i=r,o=new Set(["$","@"]),l=new Set,c=new Set,n=[];for(var e=String(t).split(h),u=0;u<e.length&&(e[u]&&n.push({text:e[u]}),!(u+1>=e.length));u+=7){var f=null!=e[u+2],s=f?{raw:e[u+2]}:{tag:e[u+5]};s.l="-"===e[u+(f?1:4)],s.r="-"===e[u+(f?3:6)],n.push(s)}n.forEach(function(t,r){var e,a;t.l&&null!=(e=n[r-1])&&e.text&&(n[r-1].text=n[r-1].text.replace(/\s+$/,"")),t.r&&null!=(a=n[r+1])&&a.text&&(n[r+1].text=n[r+1].text.replace(/^\s+/,""))}),a=0;var g=y([]),v=function(t,r){t=t||{};var e=Object.create(t);return e.$=r?r.root:t,r?"item"in r&&(e["@"]=r.item):e["@"]=t,p(g,e)};return v.names=Array.from(l),v.functions=Array.from(c),v}exports.render=function(t,r,e){return x(t,e)(r)},exports.template=x;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("xprsn");const t={"&":`&amp;`,"<":`&lt;`,">":`&gt;`,'"':`&quot;`,"'":`&#39;`},n=e=>String(e).replace(/[&<>"']/g,e=>t[e]),r=/^(?:__proto__|constructor|prototype)$/,i=e=>Array.isArray(e)?e.map((e,t)=>[e,t]):e&&typeof e==`object`?Object.keys(e).map(t=>[e[t],t]):[];let a=e=>{let t=[];for(let n=0,r=1;n<e.length;){let i=e.indexOf(`{{`,n);if(i<0){t.push({text:e.slice(n)});break}i>n&&t.push({text:e.slice(n,i)});let a=e.charCodeAt(i+2)===123,o=i+2+a,s=e.charCodeAt(o)===45,c=-1;if(s&&o++,a&&r&&(c=e.indexOf(`}}}`,o),c<0&&(r=0)),c<0&&(a&&(a=!1,o=i+2,s=e.charCodeAt(o)===45,s&&o++),c=e.indexOf(`}}`,o)),c<0){t.push({text:e.slice(i)});break}let l=c>o&&e.charCodeAt(c-1)===45,u=e.slice(o,l?c-1:c).trim(),d=a?{raw:u}:{tag:u};d.l=s,d.r=l,t.push(d),n=c+2+a}return t},o,s,c,l,u,d,f,p=e=>{throw SyntaxError(e)},m=(e,t)=>e.map(e=>e(t)).join(``),h=(e,t)=>(e=>n=>t(e(n)??``))(_(e)),g=(...e)=>{let t=e.filter(e=>e&&!u.has(e));return t.forEach(e=>u.add(e)),()=>t.forEach(e=>u.delete(e))},_=t=>{let n=(0,e.compile)(t,c);for(let e of n.names)u.has(e)||d.add(e);for(let e of n.functions)f.add(e);return n},v=e=>{let t=y([`#elif`,`#else`,`/if`]),n=l.startsWith(`#elif `)?[v(_(l.slice(6)))]:l===`#else`?y([`/if`]):[];return r=>m(e(r)?t:n,r)},y=e=>{let t=[];for(let a;a=o[s++];)if(a.text!=null)t.push((e=>()=>e)(a.text));else if(a.raw!=null)t.push(h(a.raw,String));else if(e.includes(a.tag.split(` `)[0]))return l=a.tag,t;else if(a.tag[0]!==`!`)if(a.tag.startsWith(`#if `))t.push(v(_(a.tag.slice(4))));else if(a.tag.startsWith(`#each `)){let e=/^#each ([\s\S]+) as (\w+)(?:\s*,\s*(\w+))?$/.exec(a.tag)||p(`Bad {{`+a.tag+`}}`),n=_(e[1]),o=e[2],s=e[3];(r.test(o)||s&&r.test(s))&&p(`Bad {{`+a.tag+`}}`);let c=g(o,s,`loop`),u=y([`#else`,`/each`]);c();let d=l===`#else`?y([`/each`]):[];t.push(e=>{let t=i(n(e));return t.length?t.map(([n,r],i)=>{let a=Object.create(e);return a[o]=n,s&&(a[s]=r),a[`@`]=n,a.loop={index:i+1,index0:i,first:!i,last:i===t.length-1,length:t.length},m(u,a)}).join(``):m(d,e)})}else a.tag[0]===`#`||a.tag[0]===`/`?p(`Unexpected {{`+a.tag+`}}`):t.push(h(a.tag,n));return e.length&&p(`Missing {{`+e[e.length-1]+`}}`),t};function b(e,t){c=t,u=new Set([`$`,`@`]),d=new Set,f=new Set,o=a(String(e)),o.forEach((e,t)=>{e.l&&o[t-1]?.text&&(o[t-1].text=o[t-1].text.trimEnd()),e.r&&o[t+1]?.text&&(o[t+1].text=o[t+1].text.trimStart())}),s=0;let n=y([]),r=(e,t)=>{e||={};let r=Object.create(e);return r.$=t?t.root:e,t?`item`in t&&(r[`@`]=t.item):r[`@`]=e,m(n,r)};return r.names=Array.from(d),r.functions=Array.from(f),r}function x(e,t,n){return b(e,n)(t)}exports.render=x,exports.template=b;
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import{compile as e}from"xprsn";const t={"&":`&amp;`,"<":`&lt;`,">":`&gt;`,'"':`&quot;`,"'":`&#39;`},n=e=>String(e).replace(/[&<>"']/g,e=>t[e]),r=/^(?:__proto__|constructor|prototype)$/,i=e=>Array.isArray(e)?e.map((e,t)=>[e,t]):e&&typeof e==`object`?Object.keys(e).map(t=>[e[t],t]):[];let a=e=>{let t=[];for(let n=0,r=1;n<e.length;){let i=e.indexOf(`{{`,n);if(i<0){t.push({text:e.slice(n)});break}i>n&&t.push({text:e.slice(n,i)});let a=e.charCodeAt(i+2)===123,o=i+2+a,s=e.charCodeAt(o)===45,c=-1;if(s&&o++,a&&r&&(c=e.indexOf(`}}}`,o),c<0&&(r=0)),c<0&&(a&&(a=!1,o=i+2,s=e.charCodeAt(o)===45,s&&o++),c=e.indexOf(`}}`,o)),c<0){t.push({text:e.slice(i)});break}let l=c>o&&e.charCodeAt(c-1)===45,u=e.slice(o,l?c-1:c).trim(),d=a?{raw:u}:{tag:u};d.l=s,d.r=l,t.push(d),n=c+2+a}return t},o,s,c,l,u,d,f,p=e=>{throw SyntaxError(e)},m=(e,t)=>e.map(e=>e(t)).join(``),h=(e,t)=>(e=>n=>t(e(n)??``))(_(e)),g=(...e)=>{let t=e.filter(e=>e&&!u.has(e));return t.forEach(e=>u.add(e)),()=>t.forEach(e=>u.delete(e))},_=t=>{let n=e(t,c);for(let e of n.names)u.has(e)||d.add(e);for(let e of n.functions)f.add(e);return n},v=e=>{let t=y([`#elif`,`#else`,`/if`]),n=l.startsWith(`#elif `)?[v(_(l.slice(6)))]:l===`#else`?y([`/if`]):[];return r=>m(e(r)?t:n,r)},y=e=>{let t=[];for(let a;a=o[s++];)if(a.text!=null)t.push((e=>()=>e)(a.text));else if(a.raw!=null)t.push(h(a.raw,String));else if(e.includes(a.tag.split(` `)[0]))return l=a.tag,t;else if(a.tag[0]!==`!`)if(a.tag.startsWith(`#if `))t.push(v(_(a.tag.slice(4))));else if(a.tag.startsWith(`#each `)){let e=/^#each ([\s\S]+) as (\w+)(?:\s*,\s*(\w+))?$/.exec(a.tag)||p(`Bad {{`+a.tag+`}}`),n=_(e[1]),o=e[2],s=e[3];(r.test(o)||s&&r.test(s))&&p(`Bad {{`+a.tag+`}}`);let c=g(o,s,`loop`),u=y([`#else`,`/each`]);c();let d=l===`#else`?y([`/each`]):[];t.push(e=>{let t=i(n(e));return t.length?t.map(([n,r],i)=>{let a=Object.create(e);return a[o]=n,s&&(a[s]=r),a[`@`]=n,a.loop={index:i+1,index0:i,first:!i,last:i===t.length-1,length:t.length},m(u,a)}).join(``):m(d,e)})}else a.tag[0]===`#`||a.tag[0]===`/`?p(`Unexpected {{`+a.tag+`}}`):t.push(h(a.tag,n));return e.length&&p(`Missing {{`+e[e.length-1]+`}}`),t};function b(e,t){c=t,u=new Set([`$`,`@`]),d=new Set,f=new Set,o=a(String(e)),o.forEach((e,t)=>{e.l&&o[t-1]?.text&&(o[t-1].text=o[t-1].text.trimEnd()),e.r&&o[t+1]?.text&&(o[t+1].text=o[t+1].text.trimStart())}),s=0;let n=y([]),r=(e,t)=>{e||={};let r=Object.create(e);return r.$=t?t.root:e,t?`item`in t&&(r[`@`]=t.item):r[`@`]=e,m(n,r)};return r.names=Array.from(d),r.functions=Array.from(f),r}function x(e,t,n){return b(e,n)(t)}export{x as render,b as template};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sjabloon",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Tiny, CSP-safe template engine for JavaScript, powered by xprsn expressions. No eval, no new Function.",
5
5
  "repository": "robinvdvleuten/sjabloon",
6
6
  "license": "MIT",
@@ -11,16 +11,14 @@
11
11
  },
12
12
  "type": "module",
13
13
  "source": "src/index.js",
14
- "main": "./dist/index.cjs",
15
- "module": "./dist/index.module.js",
16
- "unpkg": "./dist/index.umd.js",
17
- "types": "./index.d.ts",
14
+ "main": "dist/index.cjs",
15
+ "module": "dist/index.js",
16
+ "types": "index.d.ts",
18
17
  "exports": {
19
18
  ".": {
20
19
  "types": "./index.d.ts",
21
- "import": "./dist/index.module.js",
22
- "require": "./dist/index.cjs",
23
- "default": "./dist/index.module.js"
20
+ "import": "./dist/index.js",
21
+ "require": "./dist/index.cjs"
24
22
  }
25
23
  },
26
24
  "files": [
@@ -28,11 +26,31 @@
28
26
  "src",
29
27
  "index.d.ts"
30
28
  ],
29
+ "size-limit": [
30
+ {
31
+ "path": "dist/index.js",
32
+ "limit": "1.25 kB"
33
+ },
34
+ {
35
+ "path": "dist/index.cjs",
36
+ "limit": "1.25 kB"
37
+ }
38
+ ],
31
39
  "scripts": {
32
- "build": "microbundle --no-sourcemap",
40
+ "bench": "node bench/index.js",
41
+ "build": "tsdown",
42
+ "fuzz": "npm run fuzz:prepare && run-s fuzz:compile fuzz:render fuzz:structured",
43
+ "fuzz:prepare": "node -e \"for (const x of ['compile','render','structured']) require('fs').mkdirSync('.fuzz-corpus/'+x,{recursive:true})\"",
44
+ "fuzz:compile": "NODE_OPTIONS=--disallow-code-generation-from-strings jazzer fuzz/compile.fuzz.js -i src/ --customHooks fuzz/hooks.js --disableBugDetectors='command-injection|path-traversal|ssrf' --sync .fuzz-corpus/compile fuzz/corpus/compile -- -max_total_time=60 -use_value_profile=1 -dict=fuzz/sjabloon.dict -artifact_prefix=fuzz/",
45
+ "fuzz:render": "NODE_OPTIONS=--disallow-code-generation-from-strings jazzer fuzz/render.fuzz.js -i src/ --customHooks fuzz/hooks.js --disableBugDetectors='command-injection|path-traversal|ssrf' --sync .fuzz-corpus/render fuzz/corpus/render -- -max_total_time=60 -use_value_profile=1 -dict=fuzz/sjabloon.dict -artifact_prefix=fuzz/",
46
+ "fuzz:structured": "NODE_OPTIONS=--disallow-code-generation-from-strings jazzer fuzz/structured.fuzz.js -i src/ --customHooks fuzz/hooks.js --disableBugDetectors='command-injection|path-traversal|ssrf' --sync .fuzz-corpus/structured fuzz/corpus/structured -- -max_total_time=60 -use_value_profile=1 -dict=fuzz/sjabloon.dict -artifact_prefix=fuzz/",
47
+ "fuzz:regression": "run-s fuzz:regression:compile fuzz:regression:render fuzz:regression:structured",
48
+ "fuzz:regression:compile": "NODE_OPTIONS=--disallow-code-generation-from-strings jazzer fuzz/compile.fuzz.js -i src/ --customHooks fuzz/hooks.js --disableBugDetectors='command-injection|path-traversal|ssrf' --sync --mode=regression fuzz/corpus/compile -- -artifact_prefix=fuzz/",
49
+ "fuzz:regression:render": "NODE_OPTIONS=--disallow-code-generation-from-strings jazzer fuzz/render.fuzz.js -i src/ --customHooks fuzz/hooks.js --disableBugDetectors='command-injection|path-traversal|ssrf' --sync --mode=regression fuzz/corpus/render -- -artifact_prefix=fuzz/",
50
+ "fuzz:regression:structured": "NODE_OPTIONS=--disallow-code-generation-from-strings jazzer fuzz/structured.fuzz.js -i src/ --customHooks fuzz/hooks.js --disableBugDetectors='command-injection|path-traversal|ssrf' --sync --mode=regression fuzz/corpus/structured -- -artifact_prefix=fuzz/",
33
51
  "prepublishOnly": "npm run build",
34
- "test": "node --disallow-code-generation-from-strings node_modules/tape/bin/tape test/*.test.js",
35
- "bench": "node bench/index.js"
52
+ "size": "size-limit",
53
+ "test": "node --disallow-code-generation-from-strings node_modules/tape/bin/tape test/*.test.js"
36
54
  },
37
55
  "keywords": [
38
56
  "template",
@@ -42,10 +60,15 @@
42
60
  "handlebars"
43
61
  ],
44
62
  "dependencies": {
45
- "xprsn": "^0.4.0"
63
+ "xprsn": "^0.4.1"
46
64
  },
47
65
  "devDependencies": {
48
- "microbundle": "^0.15.1",
49
- "tape": "^5.9.0"
66
+ "@jazzer.js/bug-detectors": "^4.0.0",
67
+ "@jazzer.js/core": "^4.0.0",
68
+ "@size-limit/file": "^12.1.0",
69
+ "npm-run-all": "^4.1.5",
70
+ "size-limit": "^12.1.0",
71
+ "tape": "^5.9.0",
72
+ "tsdown": "^0.22.12"
50
73
  }
51
74
  }
package/src/index.js CHANGED
@@ -7,16 +7,39 @@ import { compile } from 'xprsn';
7
7
 
8
8
  const ESC = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' };
9
9
  const esc = s => String(s).replace(/[&<>"']/g, c => ESC[c]);
10
+ const BLOCKED = /^(?:__proto__|constructor|prototype)$/;
10
11
 
11
12
  // What `#each` walks: [value, key] pairs — array indexes or own object keys.
12
13
  const pairs = lv => Array.isArray(lv) ? lv.map((x, j) => [x, j])
13
14
  : lv && typeof lv === 'object' ? Object.keys(lv).map(k => [lv[k], k])
14
15
  : [];
15
16
 
16
- // Split into [text, rawL, raw, rawR, tagL, tag, tagR, ...] strides of 7.
17
- // The dash captures hug the braces, so `{{ -price }}` stays a unary minus
18
- // while `{{- price -}}` trims the whitespace touching the tag.
19
- const TAGS = /\{\{\{(-)?\s*([\s\S]*?)\s*(-)?\}\}\}|\{\{(-)?\s*([\s\S]*?)\s*(-)?\}\}/;
17
+ // Linear scan into text/tag/raw tokens. Dashes hug braces (`{{- x -}}` trims;
18
+ // `{{ -x }}` stays unary minus). Prefer {{{ }}} over {{ }}. `triple` latches
19
+ // off once }}} is gone so {{{...}}×N does not rescan to EOF (stays O(n)).
20
+ let lex = s => {
21
+ const out = [];
22
+ for (let i = 0, triple = 1; i < s.length; ) {
23
+ const a = s.indexOf('{{', i);
24
+ if (a < 0) { out.push({ text: s.slice(i) }); break; }
25
+ if (a > i) out.push({ text: s.slice(i, a) });
26
+ let raw = s.charCodeAt(a + 2) === 123, p = a + 2 + raw, l = s.charCodeAt(p) === 45, b = -1;
27
+ if (l) p++;
28
+ if (raw && triple) { b = s.indexOf('}}}', p); if (b < 0) triple = 0; }
29
+ if (b < 0) {
30
+ if (raw) { raw = !1; p = a + 2; l = s.charCodeAt(p) === 45; if (l) p++; }
31
+ b = s.indexOf('}}', p);
32
+ }
33
+ if (b < 0) { out.push({ text: s.slice(a) }); break; }
34
+ const r = b > p && s.charCodeAt(b - 1) === 45;
35
+ const body = s.slice(p, r ? b - 1 : b).trim(), t = raw ? { raw: body } : { tag: body };
36
+ t.l = l;
37
+ t.r = r;
38
+ out.push(t);
39
+ i = b + 2 + raw;
40
+ }
41
+ return out;
42
+ };
20
43
 
21
44
  // Shared parser state; parsing is synchronous so this is safe.
22
45
  // `nms` collects free variables, `fnms` the registry functions called.
@@ -75,6 +98,7 @@ let parse = stops => {
75
98
  } else if (t.tag.startsWith('#each ')) {
76
99
  const m = /^#each ([\s\S]+) as (\w+)(?:\s*,\s*(\w+))?$/.exec(t.tag) || err('Bad {{' + t.tag + '}}');
77
100
  const list = cp(m[1]), name = m[2], idx = m[3];
101
+ if (BLOCKED.test(name) || idx && BLOCKED.test(idx)) err('Bad {{' + t.tag + '}}');
78
102
  // `name`, `idx`, and `loop` are engine-bound inside the body, so
79
103
  // exclude them from names there and restore outer bindings after.
80
104
  const restore = scope(name, idx, 'loop');
@@ -137,21 +161,11 @@ export function template(str, funcs) {
137
161
  bound = new Set(['$', '@']);
138
162
  nms = new Set();
139
163
  fnms = new Set();
140
- toks = [];
141
- const parts = String(str).split(TAGS);
142
- for (let j = 0; j < parts.length; j += 7) {
143
- if (parts[j]) toks.push({ text: parts[j] });
144
- if (j + 1 >= parts.length) break;
145
- const raw = parts[j + 2] != null;
146
- const t = raw ? { raw: parts[j + 2] } : { tag: parts[j + 5] };
147
- t.l = parts[j + (raw ? 1 : 4)] === '-';
148
- t.r = parts[j + (raw ? 3 : 6)] === '-';
149
- toks.push(t);
150
- }
164
+ toks = lex(String(str));
151
165
  // `{{-` / `-}}` eat the whitespace touching that side of the tag.
152
166
  toks.forEach((t, k) => {
153
- if (t.l && toks[k - 1]?.text) toks[k - 1].text = toks[k - 1].text.replace(/\s+$/, '');
154
- if (t.r && toks[k + 1]?.text) toks[k + 1].text = toks[k + 1].text.replace(/^\s+/, '');
167
+ if (t.l && toks[k - 1]?.text) toks[k - 1].text = toks[k - 1].text.trimEnd();
168
+ if (t.r && toks[k + 1]?.text) toks[k + 1].text = toks[k + 1].text.trimStart();
155
169
  });
156
170
  i = 0;
157
171
  const nodes = parse([]);
@@ -1 +0,0 @@
1
- import{compile as t}from"xprsn";function r(t,r){(null==r||r>t.length)&&(r=t.length);for(var n=0,e=Array(r);n<r;n++)e[n]=t[n];return e}function n(t,n){var e="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(e)return(e=e.call(t)).next.bind(e);if(Array.isArray(t)||(e=function(t,n){if(t){if("string"==typeof t)return r(t,n);var e={}.toString.call(t).slice(8,-1);return"Object"===e&&t.constructor&&(e=t.constructor.name),"Map"===e||"Set"===e?Array.from(t):"Arguments"===e||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(e)?r(t,n):void 0}}(t))||n&&t&&"number"==typeof t.length){e&&(t=e);var a=0;return function(){return a>=t.length?{done:!0}:{done:!1,value:t[a++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var e,a,i,u,o,l,f,c={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},s=function(t){return String(t).replace(/[&<>"']/g,function(t){return c[t]})},h=/\{\{\{(-)?\s*([\s\S]*?)\s*(-)?\}\}\}|\{\{(-)?\s*([\s\S]*?)\s*(-)?\}\}/,g=function(t){throw SyntaxError(t)},p=function(t,r){return t.map(function(t){return t(r)}).join("")},v=function(t,r){return n=d(t),function(t){var e;return r(null!=(e=n(t))?e:"")};var n},d=function(r){for(var e,a=t(r,i),u=n(a.names);!(e=u()).done;){var c=e.value;o.has(c)||l.add(c)}for(var s,h=n(a.functions);!(s=h()).done;)f.add(s.value);return a},m=function(t){var r=y(["#elif","#else","/if"]),n=u.startsWith("#elif ")?[m(d(u.slice(6)))]:"#else"===u?y(["/if"]):[];return function(e){return p(t(e)?r:n,e)}},y=function(t){for(var r,n,i=[],l=function(){if(null!=n.text)i.push((x=n.text,function(){return x}));else if(null!=n.raw)i.push(v(n.raw,String));else{if(t.includes(n.tag.split(" ")[0]))return u=n.tag,{v:i};if("!"===n.tag[0]);else if(n.tag.startsWith("#if "))i.push(m(d(n.tag.slice(4))));else if(n.tag.startsWith("#each ")){var r=/^#each ([\s\S]+) as (\w+)(?:\s*,\s*(\w+))?$/.exec(n.tag)||g("Bad {{"+n.tag+"}}"),e=d(r[1]),a=r[2],l=r[3],f=function(){var t=[].slice.call(arguments).filter(function(t){return t&&!o.has(t)});return t.forEach(function(t){return o.add(t)}),function(){return t.forEach(function(t){return o.delete(t)})}}(a,l,"loop"),c=y(["#else","/each"]);f();var h="#else"===u?y(["/each"]):[];i.push(function(t){var r,n=(r=e(t),Array.isArray(r)?r.map(function(t,r){return[t,r]}):r&&"object"==typeof r?Object.keys(r).map(function(t){return[r[t],t]}):[]);return n.length?n.map(function(r,e){var i=r[0],u=r[1],o=Object.create(t);return o[a]=i,l&&(o[l]=u),o["@"]=i,o.loop={index:e+1,index0:e,first:!e,last:e===n.length-1,length:n.length},p(c,o)}).join(""):p(h,t)})}else"#"===n.tag[0]||"/"===n.tag[0]?g("Unexpected {{"+n.tag+"}}"):i.push(v(n.tag,s))}var x};n=e[a++];)if(r=l())return r.v;return t.length&&g("Missing {{"+t[t.length-1]+"}}"),i};function x(t,r){i=r,o=new Set(["$","@"]),l=new Set,f=new Set,e=[];for(var n=String(t).split(h),u=0;u<n.length&&(n[u]&&e.push({text:n[u]}),!(u+1>=n.length));u+=7){var c=null!=n[u+2],s=c?{raw:n[u+2]}:{tag:n[u+5]};s.l="-"===n[u+(c?1:4)],s.r="-"===n[u+(c?3:6)],e.push(s)}e.forEach(function(t,r){var n,a;t.l&&null!=(n=e[r-1])&&n.text&&(e[r-1].text=e[r-1].text.replace(/\s+$/,"")),t.r&&null!=(a=e[r+1])&&a.text&&(e[r+1].text=e[r+1].text.replace(/^\s+/,""))}),a=0;var g=y([]),v=function(t,r){t=t||{};var n=Object.create(t);return n.$=r?r.root:t,r?"item"in r&&(n["@"]=r.item):n["@"]=t,p(g,n)};return v.names=Array.from(l),v.functions=Array.from(f),v}function S(t,r,n){return x(t,n)(r)}export{S as render,x as template};
package/dist/index.umd.js DELETED
@@ -1 +0,0 @@
1
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("xprsn")):"function"==typeof define&&define.amd?define(["exports","xprsn"],e):e((t||self).sjabloon={},t.xprsn)}(this,function(t,e){function n(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,r=Array(e);n<e;n++)r[n]=t[n];return r}function r(t,e){var r="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(r)return(r=r.call(t)).next.bind(r);if(Array.isArray(t)||(r=function(t,e){if(t){if("string"==typeof t)return n(t,e);var r={}.toString.call(t).slice(8,-1);return"Object"===r&&t.constructor&&(r=t.constructor.name),"Map"===r||"Set"===r?Array.from(t):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?n(t,e):void 0}}(t))||e&&t&&"number"==typeof t.length){r&&(t=r);var a=0;return function(){return a>=t.length?{done:!0}:{done:!1,value:t[a++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a,i,o,u,l,f,s,c={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},p=function(t){return String(t).replace(/[&<>"']/g,function(t){return c[t]})},h=/\{\{\{(-)?\s*([\s\S]*?)\s*(-)?\}\}\}|\{\{(-)?\s*([\s\S]*?)\s*(-)?\}\}/,g=function(t){throw SyntaxError(t)},d=function(t,e){return t.map(function(t){return t(e)}).join("")},v=function(t,e){return n=m(t),function(t){var r;return e(null!=(r=n(t))?r:"")};var n},m=function(t){for(var n,a=e.compile(t,o),i=r(a.names);!(n=i()).done;){var u=n.value;l.has(u)||f.add(u)}for(var c,p=r(a.functions);!(c=p()).done;)s.add(c.value);return a},y=function(t){var e=x(["#elif","#else","/if"]),n=u.startsWith("#elif ")?[y(m(u.slice(6)))]:"#else"===u?x(["/if"]):[];return function(r){return d(t(r)?e:n,r)}},x=function(t){for(var e,n,r=[],o=function(){if(null!=n.text)r.push((h=n.text,function(){return h}));else if(null!=n.raw)r.push(v(n.raw,String));else{if(t.includes(n.tag.split(" ")[0]))return u=n.tag,{v:r};if("!"===n.tag[0]);else if(n.tag.startsWith("#if "))r.push(y(m(n.tag.slice(4))));else if(n.tag.startsWith("#each ")){var e=/^#each ([\s\S]+) as (\w+)(?:\s*,\s*(\w+))?$/.exec(n.tag)||g("Bad {{"+n.tag+"}}"),a=m(e[1]),i=e[2],o=e[3],f=function(){var t=[].slice.call(arguments).filter(function(t){return t&&!l.has(t)});return t.forEach(function(t){return l.add(t)}),function(){return t.forEach(function(t){return l.delete(t)})}}(i,o,"loop"),s=x(["#else","/each"]);f();var c="#else"===u?x(["/each"]):[];r.push(function(t){var e,n=(e=a(t),Array.isArray(e)?e.map(function(t,e){return[t,e]}):e&&"object"==typeof e?Object.keys(e).map(function(t){return[e[t],t]}):[]);return n.length?n.map(function(e,r){var a=e[0],u=e[1],l=Object.create(t);return l[i]=a,o&&(l[o]=u),l["@"]=a,l.loop={index:r+1,index0:r,first:!r,last:r===n.length-1,length:n.length},d(s,l)}).join(""):d(c,t)})}else"#"===n.tag[0]||"/"===n.tag[0]?g("Unexpected {{"+n.tag+"}}"):r.push(v(n.tag,p))}var h};n=a[i++];)if(e=o())return e.v;return t.length&&g("Missing {{"+t[t.length-1]+"}}"),r};function b(t,e){o=e,l=new Set(["$","@"]),f=new Set,s=new Set,a=[];for(var n=String(t).split(h),r=0;r<n.length&&(n[r]&&a.push({text:n[r]}),!(r+1>=n.length));r+=7){var u=null!=n[r+2],c=u?{raw:n[r+2]}:{tag:n[r+5]};c.l="-"===n[r+(u?1:4)],c.r="-"===n[r+(u?3:6)],a.push(c)}a.forEach(function(t,e){var n,r;t.l&&null!=(n=a[e-1])&&n.text&&(a[e-1].text=a[e-1].text.replace(/\s+$/,"")),t.r&&null!=(r=a[e+1])&&r.text&&(a[e+1].text=a[e+1].text.replace(/^\s+/,""))}),i=0;var p=x([]),g=function(t,e){t=t||{};var n=Object.create(t);return n.$=e?e.root:t,e?"item"in e&&(n["@"]=e.item):n["@"]=t,d(p,n)};return g.names=Array.from(f),g.functions=Array.from(s),g}t.render=function(t,e,n){return b(t,n)(e)},t.template=b});