stringweaver 1.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/Bundle/index.min.js +6 -0
- package/LICENSE +21 -0
- package/README.md +5 -0
- package/index.js +11 -0
- package/package.json +29 -0
- package/src/Factories/interpolateFactory.js +125 -0
- package/src/Factories/randomStringFactory.js +87 -0
- package/src/Factories/regExpFromMultilineStringFactory.js +35 -0
- package/src/extensions.js +144 -0
- package/src/genericMethods.js +163 -0
- package/src/instanceMethods.js +197 -0
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/*© KooiInc 2025-2030*/
|
|
2
|
+
var D=le();function le(e=""){return e=e?.constructor===String?e:"",function(s,...p){return j(s,$(p))};function t(s,p){return p&&e.length>0?String(e):`{${s}}`}function r(s){return s?.constructor===String||s?.constructor===Number&&!Number.isNaN(s)}function o(s,p){let b=s in p;return b&&r(p[s])?String(p[s]):t(s,b)}function n(s){return(...p)=>{let b=p.find(g=>g.key);return o(b?b.key:"_",s)}}function i(s,p){return s.replace(/\{(?<key>[a-z_\d]+)}/gim,n(p))}function c(s){let p=[];return Object.entries(s).forEach(([b,g])=>{g.forEach((A,u)=>(p[u]??={},p[u][b]=A))}),p}function y(s){return s.length===1&&Object.values(s[0]).every(Array.isArray)}function $(s){return y(s)?c(s[0]):s}function j(s,p){return p?.length?p.filter(b=>b).map(b=>b?.constructor===Object?i(s,b):"").join(""):s}}var{randomString:H,uuid4:F}=ie();function ie(){let e=g(),t=()=>e?[...crypto.getRandomValues(new Uint32Array(1))].shift()/2**32:Math.random(),r=({min:l=0,max:a=Number.MAX_SAFE_INTEGER}={})=>Math.floor(t()*(a-l+1)+l),o=(l=0,a=10,d)=>(d||[])instanceof Function?[...Array(a)].map((w,x)=>l+x).map(d):[...Array(a)].map((w,x)=>l+x),n=l=>String.fromCharCode(l),i="!?@#$%^&*=+_;-".split(""),c=RegExp(`[${i.map(l=>`\\${l}`).join("")}]`,"g"),y=l=>{let a=l.length;for(;a--;){let d=r({max:a});[l[a],l[d]]=[l[d],l[a]]}return l},$=y(o(65,26,n)),j=y(o(97,26,n)),p={UCLC:y($.concat(j)),UC:$,LC:j,Nrs:y(o()),Sym:y(i)},b=l=>Object.entries(l).reduce((a,[d,w])=>w?[...a,...p[d]]:a,j);function g(){try{return window&&"crypto"in window}catch{return!1}}function A(){return e&&crypto.randomUUID?crypto.randomUUID():[...new Uint8Array(16)].map(l=>r({max:255})).map((l,a)=>`${(a===8?l&63|128:a===6?l&15|64:l).toString(16).padStart(2,"0")}${~[3,5,7,9].indexOf(a)?"-":""}`).join("")}function u(l,a,d){return/[a-z]/i.test(l)&&(a&&d?/\d/.test(l)&&c.test(l):a?/\d/.test(l):d?c.test(l):!0)}function m(l){let a=[...l],d=a.findIndex(w=>/[a-z]/i.test(w));return[a[0],a[d]]=[a[d],a[0]],a.join("")}function S({len:l=12,includeUppercase:a=!0,includeNumbers:d,includeSymbols:w,startAlphabetic:x}={}){l=l<6?6:l;let O=y(b({UC:a,Nrs:d,Sym:w}));for(;O.length<l;)O=[...O,...y(O)];let v=O.slice(0,l).join("");if(!(d||w))return v;for(let G=0;G<O.length;G+=1)if(v=O.slice(G,G+l).join(""),u(v,d,w))return x&&!/^[a-z]/i.test(v)?m(v):v;return S({len:l,includeUppercase:a,includeNumbers:d,includeSymbols:w,startAlphabetic:x})}return{randomString:S,uuid4:A}}var _=ae;function ae(e,...t){t=e.raw?t:[t];try{return se(e,...t)}catch(r){let o=T();return`Error creating Regular Expression from string "${e.raw||e}" with flags ${o}
|
|
3
|
+
RegExp error message: "${r.message}"`}}function T(...e){return e.length>0?Array.isArray(e.slice(-1))?e.pop().join(""):e.join(""):""}function se(e,...t){let r=T(...t);t=[];let o=e.raw||[e];return new RegExp((t.length&&o.reduce((n,i,c)=>n.concat(t[c-1]||"").concat(i),"")||o?.join("")).split(`
|
|
4
|
+
`).map(n=>n.replace(/\s|\/\/.*$/g,"").trim().replace(/(@s!)/g," ")).join(""),r)}function z(e,...t){return e.raw?String.raw({raw:e},...t):e}function f(e){return e?.value||e?.constructor===String&&e||""}function ge(e,t,r){return e===String&&r?t?.constructor!==U&&t?.constructor!==e:t?.constructor!==e}function E(e,t,r=!0){return Array.isArray(t)&&t.length>0&&!t.find(o=>ge(e,o,r))}function L(e){return e?.constructor===Number&&!Number.isNaN(e)}function B(e){return/wrap\(|undo.*/i.test(e.toString())}function fe(){let e=C(pe());return e.value.split(/\n/).concat(Object.entries(Object.getOwnPropertyDescriptors(e)).map(([t,r])=>t==="quote"?"quote (Object. See [constructor].quoteInfo)":`${t} (${t==="value"?"getter/setter":t==="clone"?"chainable getter":t in String.prototype?"method, String override":r.value&&r.value.constructor===Function?B(r.value)?`chainable method${t in R?" *custom*":""}`:"method":r.value?"property":r.get?B(r.get)?`chainable getter${t in R?" *custom*":""}`:"getter":"-"})`).sort((t,r)=>t.localeCompare(r)))}function k(e,t){return Object.defineProperties(e,{constructor:{get(){return e},enumerable:!1},format:{value(r,...o){return C(r).format(...o)}},addCustom:{value({name:r,method:o,enumerable:n=!1,isGetter:i=!1}={}){if(C``[r])return console.error(`addCustom: the property "${r}" exists and can not be redefined`);r?.constructor===String&&o?.constructor===Function&&o.length>0&&(t[r]={method:o,enumerable:n,isGetter:i})}},info:{get(){return fe()}},keys:{get(){return Object.keys(Object.getOwnPropertyDescriptors(C``)).sort((r,o)=>r.localeCompare(o)).map(r=>!/constructor|toString|valueOf/.test(r)&&r in t?`${r} *custom*`:r)}},quoteInfo:{get(){let r={...N()};return delete r.re,Object.entries(r).sort((o,n)=>o[0].localeCompare(n[0])).reduce((o,[n,i])=>{let c=i.constructor===Function?"(start:string[, end:string])":` (${i.join(" [instance value] ")})`;return[...o,`[instance].quote.${n}${c}`]},[])}},uuid4:{get(){return F()}},randomString:{value:function({len:r,includeUppercase:o,includeNumbers:n,includeSymbols:i,startAlphabetic:c}={}){return C(H({len:r,includeUppercase:o,includeNumbers:n,includeSymbols:i,startAlphabetic:c}))}},regExp:{value:_}}),e}function M(e,t){return new RegExp(e.replace(/\p{S}|\p{P}/gu,r=>`\\${r}`),t)}function pe(){return atob`Rm9yIHRoZSByZWNvcmQ6CltjbV0gY2hhaW5hYmxlIGdldHRlcnMvbWV0aG9kcyBtb2RpZnkgdGhlIGluc3RhbmNlIHN0cmluZwpbY21dIGluZGV4T2Ygb3ZlcnJpZGVzIHJldHVybiBbdW5kZWZpbmVkXSBpZiBub3RoaW5nIHdhcyBmb3VuZCAoc28gb25lIGNhbiB1c2UgW2xhc3RJXWluZGV4T2YoW3NvbWUgc3RyaW5nIHZhbHVlXSkgPz8gMApbY21dIGluY2x1ZGVzIGluZm9ybWF0aW9uIGZvciBjdXN0b20gbWV0aG9kcy9nZXR0ZXJzIGlmIGFwcGxpY2FibGU=`.replace(/\[cm\]/g,"\u2714")}function N(){let t={backtick:["`","`"],bracket:["{","}"],curlyDoubleInward:["\u201D","\u201C"],curlyDouble:["\u201C","\u201D"],curlyDoubleEqual:["\u201C","\u201C"],curlyLHDouble:["\u201E","\u201D"],curlyLHDoubleInward:["\u201E","\u201C"],curlyLHSingle:["\u201A","\u2019"],curlyLHSingleInward:["\u201A","\u2018"],curlySingle:["\u201B","\u2019"],curlySingleEqual:["\u201B","\u201B"],curlySingleInward:["\u2019","\u201B"],custom:(o,n)=>(o=f(o),n=f(n),[f(o),n.length?n:o]),double:['"','"'],guillemets:["\xAB","\xBB"],guillemetsInward:["\xBB","\xAB"],guillemetsSingle:["\u2039","\u203A"],guillemetsSingleInward:["\u203A","\u2039"],single:["'","'"],squareBrackets:["[","]"]},r=Object.values(t).filter(o=>Array.isArray(o)).map(o=>o.map(n=>`\\${n}`).join("")).join("");return t.re=RegExp(`^[${r}]|[${r}]$`,"g"),t}var h=N();function I(e,t,r){return e=f(e),e.length>0?t(e):r||e}function V(e,...t){return I(e,()=>`${D(e,...t)}`)}function W(e){return I(e,()=>`${e[0].toUpperCase()}${e.slice(1)}`)}function P(e,t,r){return!t&&!r?e:([t,r]=E(String,[t,r??""])?[t,r]:["",""],`${t}${e}${r||t}`)}function Y(e){return I(e,()=>e.replace(/\s/g,"").replace(/[A-Z]/g,t=>`-${t.toLowerCase()}`).replace(/-{2,}/g,"-").replace(/[^a-z-]/g,"").replace(/^-|-$/,""))}function X(e){return I(e,()=>e.replace(/\s/g,"").replace(/[A-Z]/g,t=>`_${t.toLowerCase()}`).replace(/_{2,}/g,"_").replace(/[^a-z_]/g,"").replace(/^_|_$/,""))}function J(e){return I(e,()=>[...e.toLowerCase()].slice(1).reduce((t,r)=>t+(/\p{L}|[-']/u.test(t.at(-1))?r.toLowerCase():r.toUpperCase()),e[0].toUpperCase()))}function Q(e){return I(e,()=>e.toLowerCase().trim().split(/[- ]/).filter(t=>t&&t.length>0).map((t,r)=>r>0&&`${W(t)}`||t).join(""))}function K(e,{at:t,html:r=!1,wordBoundary:o=!1}={}){return I(e,()=>{if(e.length<=t)return e;let n=e.slice(0,t-1),i=r?"…":"...",c=o?[...n.matchAll(/\p{Pe}|\p{Z}/gu)].at(-1)?.index??n.length:n.length;return(o?n.slice(0,c+1).trim():n)+i})}function Z(e,t){return I(e,()=>{let r=e.split(/\n/).map(o=>o.trim().replace(/\s{2,}/g," "));return t?r.join(`
|
|
5
|
+
`):r.filter(o=>o.length>0).join(`
|
|
6
|
+
`)})}function ee(e,{replacements:t={},caseSensitive:r=!1}={}){e=f(e);let o=Object.entries(t).flat(),n=E(String,o)&&r?.constructor===Boolean,i=`g${r?"":"i"}`;if(n&&(o=o.map(c=>f(c)).filter(c=>o.length>0),o.length))for(;o.length;){let[c,y]=[o.shift(),o.shift()],$=M(c,i);e=e.replace($,y)}return e}function te(e,t,r){e=f(e),r=L(r)?r:0;let o=e.indexOf(t,r||0);return o<0?void 0:o}function re(e,t,r){e=f(e),r=L(r)?r:e.length;let o=e.lastIndexOf(t,r);return o<0?void 0:o}function q(e,{value:t,values:r,at:o=0}={}){e=f(e),o=L(o)?o:0;let n=f(r);return r=f(t).length?t:n.length?n:E(String,r)?r.map(i=>f(i)).join(""):[],r.length<=1?e:e.length===0?`${r}${e}`:`${e.slice(0,o)}${r}${e.slice(o)}`}function ne(e,...t){return t=E(String,t)&&t,t?q(f(e),{values:t,at:0}):f(e)}function oe(e,...t){return t=E(String,t)&&t,t&&t.length>0?`${f(e)}`.concat(t.join("")):f(e)}function ue(e,t){return{value:{get backtick(){return e.enclose(...h.backtick)},get bracket(){return e.enclose(...h.bracket)},get curlyDouble(){return e.enclose(...h.curlyDouble)},get curlyDoubleInward(){return e.enclose(...h.curlyDoubleInward)},get curlyDoubleEqual(){return e.enclose(...h.curlyDoubleEqual)},get curlyLHDoubleInward(){return e.enclose(...h.curlyLHDoubleInward)},get curlyLHSingle(){return e.enclose(...h.curlyLHSingle)},get curlyLHSingleInward(){return e.enclose(...h.curlyLHSingleInward)},get curlySingle(){return e.enclose(...h.curlySingle)},get curlySingleEqual(){return e.enclose(...h.curlySingleEqual)},get curlySingleInward(){return e.enclose(...h.curlySingleInward)},custom(r,o){return e.enclose(r,o??r)},get double(){return e.enclose(...h.double)},get guillemets(){return e.enclose(...h.guillemets)},get guillemetsInward(){return e.enclose(...h.guillemetsInward)},get guillemetsSingle(){return e.enclose(...h.guillemetsSingle)},get guillemetsSingleInward(){return e.enclose(...h.guillemetsSingleInward)},get remove(){return t(`${e.value.replace(h.re,"")}`)},get single(){return e.enclose(...h.single)},get squareBrackets(){return e.enclose(...h.squareBrackets)}},enumerable:!1}}var ce=me;function me({initialstring:e,customMethods:t}={}){let r={},o=new Proxy(r,y(r)),n=e?.constructor===String?e:"",i=[n],c=!1;return Object.defineProperties(r,{append:{value(...u){return g(oe(n,...u))},enumerable:c},enclose:{value(u,m){return g(P(n,u,m))},enumerable:c},format:{value(...u){return g(V(n,...u))},enumerable:c},indexOf:{value(u){return te(n,u)},enumerable:c},interpolate:{value(...u){return g(V(n,...u))},enumerable:c},insert:{value({value:u,values:m,at:S}={}){return g(q(n,{value:u,values:m,at:S}))},enumerable:c},lastIndexOf:{value(u){return re(n,u)},enumerable:c},prefix:{value(...u){return g(ne(n,...u))},enumerable:c},replaceWords:{value({caseSensitive:u=!1,replacements:m={}}={}){return g(ee(n,{replacements:m,caseSensitive:u}))},enumerable:c},toString:{value(){return n},enumerable:c},truncate:{value({at:u,html:m=!1,wordBoundary:S=!1}={}){return g(K(n,{at:u,html:m,wordBoundary:S}))},enumerable:c},valueOf:{value(){return n},enumerable:c},undoLast:{value(u){return p(u)},enumerable:c},camelCase:{get(){return g(Q(f(n)))},enumerable:c},clone:{get(){return $()},enumerable:c},constructor:{get(){return C.constructor},enumerable:c},kebabCase:{get(){return g(Y(f(n)))},enumerable:c},firstUp:{get(){return g(W(f(n)))},enumerable:c},history:{get(){return i},set(u){i=u},enumerable:c},quote:ue(o,g),snakeCase:{get(){return g(X(f(n)))}},trimAll:{get(){return g(Z(n))},enumerable:c},trimAllKeepLF:{get(){return g(Z(n,!0))},enumerable:c},undoAll:{get(){return s()},enumerable:c},undo:{get(){return b()},enumerable:c},wordsUCFirst:{get(){return g(J(f(n)))},enumerable:c},value:{get(){return n},set(u){n=f(u).length?u:n,i.push(n)},enumerable:c}}),A(t),Object.freeze(o);function y(u){return{get(m,S){return S in u?u[S]:S in String.prototype?j(S):void 0}}}function $(){let u=C(n);return u.history=[...i],u}function j(u){return n[u]instanceof Function?function(...m){let S=n[u](...m);return S?.constructor===String?g(n[u](...m)):S}:n[u]}function s(){for(;i.length>1;)i.pop();return n=i.at(-1),g(n,!1)}function p(u){if(!L(u))return g(n,!1);let m=i.length;return u>=m||u<1?(i=i.slice(0,1),n=i.at(-1),g(i.at(-1),!1)):(i=i.slice(0,m-u),n=i.at(-1),g(n,!1))}function b(){return i.length===1?g(i[0]):(i.pop(),n=i.at(-1),g(n,!1))}function g(u,m=!0){return n!==u&&m&&i.push(u),n=u,o}function A(u){Object.entries(u).forEach(([m,S])=>{let{enumerable:l,method:a,isGetter:d}=S;Object.defineProperty(r,m,d?{get(){return g(a(o).value)},enumerable:l}:{value(...x){return g(a(o,...x).value)},enumerable:l})})}}var R={},C=k(U,R);function U(e,...t){return ce({initialstring:z(e,...t),customMethods:R})}export{U as CustomStringConstructor,R as customMethods,C as default};
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Renzo Kooi
|
|
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.
|
package/README.md
ADDED
package/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import createInstance from "./src/extensions.js";
|
|
2
|
+
import { resolveTemplateString as resolveString, createExtendedCTOR } from "./src/genericMethods.js";
|
|
3
|
+
|
|
4
|
+
const customMethods = {};
|
|
5
|
+
const defaultStringCTOR = createExtendedCTOR(CustomStringConstructor, customMethods);
|
|
6
|
+
|
|
7
|
+
export {defaultStringCTOR as default, CustomStringConstructor, customMethods};
|
|
8
|
+
|
|
9
|
+
function CustomStringConstructor(str, ...args) {
|
|
10
|
+
return createInstance({initialstring: resolveString(str, ...args), customMethods});
|
|
11
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "stringweaver",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"private": false,
|
|
6
|
+
"main": "./index.js",
|
|
7
|
+
"description": "A JS stringbuilder utility",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"JS",
|
|
10
|
+
"ES20xx",
|
|
11
|
+
"String",
|
|
12
|
+
"Stringbuilder",
|
|
13
|
+
"String",
|
|
14
|
+
"Utilities",
|
|
15
|
+
"Classfree Object Oriented"
|
|
16
|
+
],
|
|
17
|
+
"author": "KooiInc",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/KooiInc/js-stringweaver"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"esbuild": "latest"
|
|
25
|
+
},
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/KooiInc/js-stringweaver/issues"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
const defaultInterpolator = interpolateFactory();
|
|
2
|
+
export {defaultInterpolator as default, interpolateFactory};
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Factory function to create an interpolate function with a default replacer.
|
|
6
|
+
* @param {string} defaultReplacer - Default value to use for missing tokens.
|
|
7
|
+
* @returns {Function} - The interpolation function.
|
|
8
|
+
*/
|
|
9
|
+
function interpolateFactory(defaultReplacer = "") {
|
|
10
|
+
defaultReplacer = defaultReplacer?.constructor === String ? defaultReplacer : "";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Main interpolation function.
|
|
14
|
+
* @param {string} str - The string with placeholders.
|
|
15
|
+
* @param {...object} tokens - Objects containing replacement values.
|
|
16
|
+
* @returns {string} - The interpolated string.
|
|
17
|
+
*/
|
|
18
|
+
return function(str, ...tokens) {
|
|
19
|
+
return interpolate(str, processTokens(tokens));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Handle invalid keys by returning the default replacer or the key in braces.
|
|
24
|
+
* @param {string} key - The placeholder key.
|
|
25
|
+
* @param {boolean} keyExists - Flag indicating if the key exists in the token.
|
|
26
|
+
* @returns {string} - The replacement value.
|
|
27
|
+
*/
|
|
28
|
+
function invalidate(key, keyExists) {
|
|
29
|
+
if (keyExists && defaultReplacer.length > 0) {
|
|
30
|
+
return String(defaultReplacer);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return `{${key}}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* determine if [value] is a String or Number
|
|
38
|
+
* @param {any} value
|
|
39
|
+
* @returns {boolean}
|
|
40
|
+
*/
|
|
41
|
+
function isStringOrNumber(value ) {
|
|
42
|
+
return value?.constructor === String || value?.constructor === Number && !Number.isNaN(value);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get the replacement value for a key from the token.
|
|
47
|
+
* @param {string} key - The placeholder key.
|
|
48
|
+
* @param {object} token - The token object containing replacement values.
|
|
49
|
+
* @returns {string} - The replacement value.
|
|
50
|
+
*/
|
|
51
|
+
function replacement(key, token) {
|
|
52
|
+
const isValid = key in token;
|
|
53
|
+
return isValid && isStringOrNumber(token[key]) ? String(token[key]) : invalidate(key, isValid);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Create a lambda function for replacing placeholders in the string.
|
|
58
|
+
* @param {object<string, string>} token - The token object containing replacement values.
|
|
59
|
+
* @returns {Function} - The replacer lambda function.
|
|
60
|
+
*/
|
|
61
|
+
function getReplacerLambda(token) {
|
|
62
|
+
return (...args) => {
|
|
63
|
+
const replacementObject = args.find(a => a.key);
|
|
64
|
+
return replacement((replacementObject ? replacementObject.key : `_`), token);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Replace placeholders in the string with values from the token.
|
|
70
|
+
* @param {string} str - The string with placeholders.
|
|
71
|
+
* @param {object} token - The token object containing replacement values.
|
|
72
|
+
* @returns {string} - The interpolated string.
|
|
73
|
+
*/
|
|
74
|
+
function replace(str, token) {
|
|
75
|
+
return str.replace(/\{(?<key>[a-z_\d]+)}/gim, getReplacerLambda(token));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Convert token object to array of token Objects
|
|
80
|
+
* when it's values are arrays of values.
|
|
81
|
+
* @param {object} tokenObject - The token object containing arrays of values.
|
|
82
|
+
* @returns {object[]} - Array of token objects.
|
|
83
|
+
*/
|
|
84
|
+
function convertTokensFromArrayValues(tokenObject) {
|
|
85
|
+
const converted = [];
|
|
86
|
+
|
|
87
|
+
Object.entries(tokenObject).forEach(([key, value]) => {
|
|
88
|
+
value.forEach((v, i) => (converted[i] ??= {}, converted[i][key] = v));
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
return converted;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Check if single token and its values are arrays.
|
|
96
|
+
* @param {object[]} tokens - The tokens to check.
|
|
97
|
+
* @returns {boolean} - True if tokens contains one Object
|
|
98
|
+
* and all it's values are of type Array.
|
|
99
|
+
*/
|
|
100
|
+
function isMultiLineWithArrays(tokens) {
|
|
101
|
+
return tokens.length === 1 && Object.values(tokens[0]).every(Array.isArray);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Process tokens to handle multi-line formats.
|
|
106
|
+
* @param {object[]} tokens - The tokens to process.
|
|
107
|
+
* @returns {object[]} - Processed tokens.
|
|
108
|
+
*/
|
|
109
|
+
function processTokens(tokens) {
|
|
110
|
+
return isMultiLineWithArrays(tokens) ? convertTokensFromArrayValues(tokens[0]) : tokens;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Interpolate the string with the given tokens.
|
|
115
|
+
* @param {string} str - The string with placeholders.
|
|
116
|
+
* @param {object[]} tokens - The tokens containing replacement values.
|
|
117
|
+
* @returns {string} - The interpolated string.
|
|
118
|
+
*/
|
|
119
|
+
function interpolate(str, tokens) {
|
|
120
|
+
return !tokens?.length ? str : tokens
|
|
121
|
+
.filter(token => token)
|
|
122
|
+
.map(token => token?.constructor === Object ? replace(str, token) : ``)
|
|
123
|
+
.join(``);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const { randomString, uuid4 } = randomStringGeneratorFactory();
|
|
2
|
+
export { randomString as default, randomString, uuid4 };
|
|
3
|
+
|
|
4
|
+
function randomStringGeneratorFactory() {
|
|
5
|
+
const hasCrypto = checkBrowserCrypto();
|
|
6
|
+
const getRandomValue = () => hasCrypto
|
|
7
|
+
? [...crypto.getRandomValues(new Uint32Array(1))].shift() / 2**32
|
|
8
|
+
: Math.random();
|
|
9
|
+
const randomNr = ({min = 0, max = Number.MAX_SAFE_INTEGER} = {}) =>
|
|
10
|
+
Math.floor( getRandomValue() * (max - min + 1) + min );
|
|
11
|
+
const range = (start = 0, len = 10, reMap) => (reMap || []) instanceof Function
|
|
12
|
+
? [...Array(len)].map((_, i) => start + i).map(reMap)
|
|
13
|
+
: [...Array(len)].map((_, i) => start + i);
|
|
14
|
+
const map2Chrs = v => String.fromCharCode(v);
|
|
15
|
+
const symbols = `!?@#$%^&*=+_;-`.split(``);
|
|
16
|
+
const symRE = RegExp(`[${symbols.map(v => `\\${v}`).join(``)}]`, `g`);
|
|
17
|
+
const shuffle = array => {
|
|
18
|
+
let i = array.length;
|
|
19
|
+
while (i--) {
|
|
20
|
+
const ri = randomNr( { max: i } );
|
|
21
|
+
[array[i], array[ri]] = [array[ri], array[i]];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return array;
|
|
25
|
+
};
|
|
26
|
+
const UC = shuffle(range(65, 26, map2Chrs));
|
|
27
|
+
const LC = shuffle(range(97, 26, map2Chrs));
|
|
28
|
+
const UCLC = shuffle(UC.concat(LC));
|
|
29
|
+
const allChars = { UCLC, UC, LC, Nrs: shuffle(range()), Sym: shuffle(symbols), };
|
|
30
|
+
const getChars2Use = use => Object.entries(use)
|
|
31
|
+
.reduce( (acc, [key, value]) => value ? [...acc, ...allChars[key]] : acc, LC );
|
|
32
|
+
|
|
33
|
+
function checkBrowserCrypto() {
|
|
34
|
+
try { return window && `crypto` in window }
|
|
35
|
+
catch(_) { return false; }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function uuid4() {
|
|
39
|
+
// Note: randomUUID only in secure context (https)
|
|
40
|
+
return hasCrypto && crypto.randomUUID
|
|
41
|
+
? crypto.randomUUID()
|
|
42
|
+
: [...new Uint8Array(16)]
|
|
43
|
+
.map(_ => randomNr({max: 255}))
|
|
44
|
+
.map( (v, i) => `${
|
|
45
|
+
(i === 8 ? v & 0b00111111 | 0b10000000 : i === 6 ? v & 0b00001111 | 0b01000000 : v)
|
|
46
|
+
.toString(16).padStart(2, `0`)}${~[3,5,7,9].indexOf(i) ? `-` : ``}` )
|
|
47
|
+
.join(``);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function strTest(strFound, numbers, symbols) {
|
|
51
|
+
return /[a-z]/i.test(strFound) && (
|
|
52
|
+
numbers && symbols ? /\d/.test(strFound) && symRE.test(strFound)
|
|
53
|
+
: numbers ? /\d/.test(strFound)
|
|
54
|
+
: symbols ? symRE.test(strFound)
|
|
55
|
+
: true);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function alphaSwap(strFound) {
|
|
59
|
+
const chars = [...strFound];
|
|
60
|
+
const idx = chars.findIndex(v => /[a-z]/i.test(v));
|
|
61
|
+
[chars[0], chars[idx]] = [chars[idx], chars[0]];
|
|
62
|
+
return chars.join(``);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function randomString( {len = 12, includeUppercase = true, includeNumbers, includeSymbols, startAlphabetic} = {} ) {
|
|
66
|
+
len = len < 6 ? 6 : len;
|
|
67
|
+
let chrs2Use = shuffle( getChars2Use( { UC: includeUppercase, Nrs: includeNumbers, Sym: includeSymbols } ) );
|
|
68
|
+
|
|
69
|
+
while (chrs2Use.length < len) { chrs2Use = [...chrs2Use, ...shuffle(chrs2Use)]; }
|
|
70
|
+
|
|
71
|
+
let strFound = chrs2Use.slice(0, len).join(``);
|
|
72
|
+
|
|
73
|
+
if (!(includeNumbers || includeSymbols)) { return strFound; }
|
|
74
|
+
|
|
75
|
+
for (let i = 0; i < chrs2Use.length; i += 1) {
|
|
76
|
+
strFound = chrs2Use.slice(i, i + len).join(``);
|
|
77
|
+
|
|
78
|
+
if (strTest(strFound, includeNumbers, includeSymbols)) {
|
|
79
|
+
return startAlphabetic && !/^[a-z]/i.test(strFound) ? alphaSwap(strFound) : strFound;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return randomString({len, includeUppercase, includeNumbers, includeSymbols, startAlphabetic});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return { randomString, uuid4 };
|
|
87
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {resolveTemplateString} from "../genericMethods.js";
|
|
2
|
+
|
|
3
|
+
export default createRegExp
|
|
4
|
+
|
|
5
|
+
function createRegExp(str, ...args) {
|
|
6
|
+
args = !str.raw ? [args] : args;
|
|
7
|
+
try {
|
|
8
|
+
return regExp(str, ...args);
|
|
9
|
+
} catch (err) {
|
|
10
|
+
const flags = resolveFlags();
|
|
11
|
+
const raw = str.raw || str;
|
|
12
|
+
return `Error creating Regular Expression from string "${raw}" with flags ${flags}` +
|
|
13
|
+
`\nRegExp error message: "${err.message}"`;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function resolveFlags(...args) {
|
|
18
|
+
return args.length > 0
|
|
19
|
+
? Array.isArray(args.slice(-1))
|
|
20
|
+
? args.pop().join(``) : args.join(``) : ``;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function regExp(regexStr, ...args) {
|
|
24
|
+
const flags = resolveFlags(...args);
|
|
25
|
+
args = [];
|
|
26
|
+
const raw = regexStr.raw || [regexStr];
|
|
27
|
+
|
|
28
|
+
return new RegExp(
|
|
29
|
+
(args.length &&
|
|
30
|
+
raw.reduce( (a, v, i ) => a.concat(args[i-1] || ``).concat(v), ``) ||
|
|
31
|
+
raw?.join(``))
|
|
32
|
+
.split(`\n`)
|
|
33
|
+
.map( line => line.replace(/\s|\/\/.*$/g, ``).trim().replace(/(@s!)/g, ` `) )
|
|
34
|
+
.join(``), flags);
|
|
35
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import {
|
|
2
|
+
format, ucFirst, truncate, trimAll, replaceWords,
|
|
3
|
+
indexOf, lastIndexOf, insert, append, prefix,
|
|
4
|
+
getStringValue, quotGetters, surroundWith,
|
|
5
|
+
toCamelcase, wordsFirstUp, toDashedNotation, toSnakeCase,
|
|
6
|
+
} from "./instanceMethods.js";
|
|
7
|
+
|
|
8
|
+
import {xString as $S, isNumber} from "./genericMethods.js";
|
|
9
|
+
export default instanceCreator;
|
|
10
|
+
|
|
11
|
+
function instanceCreator({initialstring, customMethods} = {}) {
|
|
12
|
+
let customStringExtensions = { };
|
|
13
|
+
let instance = new Proxy(customStringExtensions, getTraps(customStringExtensions));
|
|
14
|
+
let actualValue = initialstring?.constructor === String ? initialstring : ``;
|
|
15
|
+
let history = [actualValue];
|
|
16
|
+
const enumerable = false;
|
|
17
|
+
|
|
18
|
+
Object.defineProperties(customStringExtensions, {
|
|
19
|
+
append: { value(...strings) { return wrap(append(actualValue, ...strings)); }, enumerable },
|
|
20
|
+
enclose: { value(start, end) { return wrap(surroundWith(actualValue, start, end)); }, enumerable },
|
|
21
|
+
format: { value(...tokens) { return wrap(format(actualValue, ...tokens)); }, enumerable },
|
|
22
|
+
indexOf: { value(str) { return indexOf(actualValue, str); }, enumerable },
|
|
23
|
+
interpolate: { value(...tokens) { return wrap(format(actualValue, ...tokens)); }, enumerable },
|
|
24
|
+
insert: { value({ value, values, at } = {}) {
|
|
25
|
+
return wrap(insert(actualValue, { value, values, at }));
|
|
26
|
+
}, enumerable
|
|
27
|
+
},
|
|
28
|
+
lastIndexOf: { value(str) { return lastIndexOf(actualValue, str); }, enumerable },
|
|
29
|
+
prefix: { value(...strings) { return wrap(prefix(actualValue, ...strings)); }, enumerable },
|
|
30
|
+
replaceWords: { value({caseSensitive = false, replacements = {}} = {}) {
|
|
31
|
+
return wrap(replaceWords(actualValue, {replacements, caseSensitive}));
|
|
32
|
+
}, enumerable },
|
|
33
|
+
toString: { value() { return actualValue; }, enumerable },
|
|
34
|
+
truncate: { value({at, html = false, wordBoundary = false} = {}) {
|
|
35
|
+
return wrap(truncate(actualValue, {at, html, wordBoundary})); }, enumerable },
|
|
36
|
+
valueOf: { value() { return actualValue; }, enumerable },
|
|
37
|
+
undoLast: { value(nSteps) { return undoSteps(nSteps); }, enumerable },
|
|
38
|
+
|
|
39
|
+
camelCase: { get() { return wrap(toCamelcase(getStringValue(actualValue))); }, enumerable },
|
|
40
|
+
clone: { get() { return clone(); }, enumerable },
|
|
41
|
+
constructor: { get() { return $S.constructor; }, enumerable },
|
|
42
|
+
kebabCase: { get() { return wrap(toDashedNotation(getStringValue(actualValue))); }, enumerable },
|
|
43
|
+
firstUp: { get() { return wrap(ucFirst(getStringValue(actualValue))); }, enumerable },
|
|
44
|
+
history: {
|
|
45
|
+
get() { return history; },
|
|
46
|
+
set(value) { history = value; },
|
|
47
|
+
enumerable },
|
|
48
|
+
quote: quotGetters(instance, wrap),
|
|
49
|
+
snakeCase: { get() { return wrap(toSnakeCase(getStringValue(actualValue))); } },
|
|
50
|
+
trimAll: { get() { return wrap(trimAll(actualValue)); }, enumerable },
|
|
51
|
+
trimAllKeepLF: { get() { return wrap(trimAll(actualValue, true)); }, enumerable },
|
|
52
|
+
undoAll: { get() { return undoAll(); }, enumerable },
|
|
53
|
+
undo: { get() { return undoLast(); }, enumerable },
|
|
54
|
+
wordsUCFirst: { get() { return wrap(wordsFirstUp(getStringValue(actualValue))); }, enumerable },
|
|
55
|
+
value: {
|
|
56
|
+
get() { return actualValue; },
|
|
57
|
+
set(value) {
|
|
58
|
+
actualValue = getStringValue(value).length ? value : actualValue;
|
|
59
|
+
history.push(actualValue);
|
|
60
|
+
}, enumerable },
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
injectCustomMethods(customMethods);
|
|
64
|
+
|
|
65
|
+
return Object.freeze(instance);
|
|
66
|
+
|
|
67
|
+
function getTraps(extensions) {
|
|
68
|
+
return {
|
|
69
|
+
get( target, key ) {
|
|
70
|
+
return key in extensions
|
|
71
|
+
? extensions[key]
|
|
72
|
+
: key in String.prototype
|
|
73
|
+
? wrapNative(key)
|
|
74
|
+
: undefined;
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function clone() {
|
|
80
|
+
const newInstance = $S(actualValue);
|
|
81
|
+
newInstance.history = [...history];
|
|
82
|
+
return newInstance;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function wrapNative(key) {
|
|
86
|
+
return actualValue[key] instanceof Function
|
|
87
|
+
? function(...args) {
|
|
88
|
+
const result = actualValue[key](...args);
|
|
89
|
+
return result?.constructor === String ? wrap(actualValue[key](...args)) : result;
|
|
90
|
+
} : actualValue[key];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function undoAll() {
|
|
94
|
+
while(history.length > 1) { history.pop(); }
|
|
95
|
+
actualValue = history.at(-1);
|
|
96
|
+
return wrap(actualValue, false);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function undoSteps(steps) {
|
|
100
|
+
if (!isNumber(steps)) {
|
|
101
|
+
return wrap(actualValue, false);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const historyLen = history.length;
|
|
105
|
+
|
|
106
|
+
if (steps >= historyLen || steps < 1) {
|
|
107
|
+
history = history.slice(0, 1);
|
|
108
|
+
actualValue = history.at(-1);
|
|
109
|
+
return wrap(history.at(-1), false);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
history = history.slice(0, historyLen - steps);
|
|
113
|
+
|
|
114
|
+
actualValue = history.at(-1);
|
|
115
|
+
return wrap(actualValue, false);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function undoLast() {
|
|
119
|
+
if (history.length === 1) {
|
|
120
|
+
return wrap(history[0]);
|
|
121
|
+
}
|
|
122
|
+
history.pop();
|
|
123
|
+
actualValue = history.at(-1);
|
|
124
|
+
return wrap(actualValue, false);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function wrap(result, pushHistory = true) {
|
|
128
|
+
const changed = actualValue !== result;
|
|
129
|
+
changed && pushHistory && history.push(result);
|
|
130
|
+
actualValue = result;
|
|
131
|
+
return instance;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function injectCustomMethods(customMethods) {
|
|
135
|
+
Object.entries(customMethods).forEach(([methodName, methodContainer]) => {
|
|
136
|
+
const {enumerable, method, isGetter} = methodContainer;
|
|
137
|
+
const descriptor = isGetter
|
|
138
|
+
? { get() { return wrap(method(instance).value); }, enumerable }
|
|
139
|
+
: { value(...args) { return wrap(method(instance, ...args).value); }, enumerable, };
|
|
140
|
+
|
|
141
|
+
Object.defineProperty(customStringExtensions, methodName, descriptor);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import xString, {CustomStringConstructor, customMethods} from "../index.js";
|
|
2
|
+
import {default as randomString, uuid4} from "./Factories/randomStringFactory.js";
|
|
3
|
+
import createRegExp from "./Factories/regExpFromMultilineStringFactory.js";
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
createExtendedCTOR,
|
|
7
|
+
resolveTemplateString,
|
|
8
|
+
xString,
|
|
9
|
+
isNumber,
|
|
10
|
+
isArrayOf,
|
|
11
|
+
defineQuotingStyles,
|
|
12
|
+
getStringValue,
|
|
13
|
+
escapeRE,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
function resolveTemplateString(str, ...args) {
|
|
17
|
+
return str.raw ? String.raw({ raw: str }, ...args) : str;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getStringValue(string) {
|
|
21
|
+
return string?.value || (string?.constructor === String && string) || ``;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function checkType(type, item, includeInstances) {
|
|
25
|
+
return type === String && includeInstances
|
|
26
|
+
? item?.constructor !== CustomStringConstructor && item?.constructor !== type
|
|
27
|
+
: item?.constructor !== type;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function isArrayOf(type, value, includeInstances = true) {
|
|
31
|
+
return Array.isArray(value) && value.length > 0 && !value.find(v => checkType(type, v, includeInstances));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function isNumber(value) {
|
|
35
|
+
return value?.constructor === Number && !Number.isNaN(value);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function isMutating(descriptor) {
|
|
39
|
+
return /wrap\(|undo.*/i.test(descriptor.toString())
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getSWInformation() {
|
|
43
|
+
const firstLines = xString(decode());
|
|
44
|
+
return firstLines.value.split(/\n/).concat(
|
|
45
|
+
Object.entries(Object.getOwnPropertyDescriptors(firstLines))
|
|
46
|
+
.map(([key, descriptr]) => {
|
|
47
|
+
if (key === `quote`) { return `quote (Object. See [constructor].quoteInfo)`; }
|
|
48
|
+
return `${key} (${
|
|
49
|
+
key === `value`
|
|
50
|
+
? `getter/setter`
|
|
51
|
+
: key === `clone`
|
|
52
|
+
? `chainable getter`
|
|
53
|
+
: key in String.prototype
|
|
54
|
+
? `method, String override`
|
|
55
|
+
: descriptr.value && descriptr.value.constructor === Function
|
|
56
|
+
? (isMutating(descriptr.value)
|
|
57
|
+
? `chainable method${key in customMethods ? ` *custom*` : ``}` : `method`)
|
|
58
|
+
: descriptr.value
|
|
59
|
+
? `property`
|
|
60
|
+
: descriptr.get ? (isMutating(descriptr.get)
|
|
61
|
+
? `chainable getter${key in customMethods ? ` *custom*` : ``}`
|
|
62
|
+
: `getter`) : `-`})`; })
|
|
63
|
+
.sort( (a,b) => a.localeCompare(b) )
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function createExtendedCTOR(ctor, customMethods) {
|
|
68
|
+
Object.defineProperties(ctor, {
|
|
69
|
+
constructor: {
|
|
70
|
+
get() { return ctor; },
|
|
71
|
+
enumerable: false,
|
|
72
|
+
},
|
|
73
|
+
format: {
|
|
74
|
+
value(str, ...tokens) {
|
|
75
|
+
return xString(str).format(...tokens);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
addCustom: {
|
|
79
|
+
value( { name, method, enumerable = false, isGetter = false } = {} ) {
|
|
80
|
+
if (xString``[name]) {
|
|
81
|
+
return console.error(`addCustom: the property "${name}" exists and can not be redefined`);
|
|
82
|
+
}
|
|
83
|
+
if (name?.constructor === String && method?.constructor === Function && method.length > 0) {
|
|
84
|
+
customMethods[name] = {method, enumerable, isGetter};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
info: {
|
|
89
|
+
get() { return getSWInformation(); }
|
|
90
|
+
},
|
|
91
|
+
keys: {
|
|
92
|
+
get() {
|
|
93
|
+
return Object.keys(Object.getOwnPropertyDescriptors(xString``)).sort( (a,b) => a.localeCompare(b) )
|
|
94
|
+
.map(v => !/constructor|toString|valueOf/.test(v) && v in customMethods ? `${v} *custom*` : v);
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
quoteInfo: {
|
|
98
|
+
get() {
|
|
99
|
+
const qStyles = {...defineQuotingStyles()};
|
|
100
|
+
delete qStyles.re;
|
|
101
|
+
return Object.entries(qStyles)
|
|
102
|
+
.sort( (a,b) => a[0].localeCompare(b[0]) )
|
|
103
|
+
.reduce((acc, [k, v]) => {
|
|
104
|
+
const val = v.constructor === Function ? `(start:string[, end:string])` : ` (${v.join(` [instance value] `)})`;
|
|
105
|
+
return [...acc, `[instance].quote.${k}${val}`];
|
|
106
|
+
}, []);
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
uuid4: {
|
|
110
|
+
get() { return uuid4(); }
|
|
111
|
+
},
|
|
112
|
+
randomString: {
|
|
113
|
+
value: function({len, includeUppercase, includeNumbers, includeSymbols, startAlphabetic} = {}) {
|
|
114
|
+
return xString(randomString({len, includeUppercase, includeNumbers, includeSymbols, startAlphabetic}));
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
regExp: { value: createRegExp }
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
return ctor;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function escapeRE(reString, modifiers) {
|
|
124
|
+
return new RegExp(reString.replace(/\p{S}|\p{P}/gu, a => `\\${a}`), modifiers);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function decode() {
|
|
128
|
+
return atob`Rm9yIHRoZSByZWNvcmQ6CltjbV0gY2hhaW5hYmxlIGdldHRlcnMvbWV0aG9kcyBtb2RpZnkgdGhlIGluc3RhbmNlIHN0cmluZwpbY21dIGluZGV4T2Ygb3ZlcnJpZGVzIHJldHVybiBbdW5kZWZpbmVkXSBpZiBub3RoaW5nIHdhcyBmb3VuZCAoc28gb25lIGNhbiB1c2UgW2xhc3RJXWluZGV4T2YoW3NvbWUgc3RyaW5nIHZhbHVlXSkgPz8gMApbY21dIGluY2x1ZGVzIGluZm9ybWF0aW9uIGZvciBjdXN0b20gbWV0aG9kcy9nZXR0ZXJzIGlmIGFwcGxpY2FibGU=`.replace(/\[cm\]/g, `\u2714`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function defineQuotingStyles() {
|
|
132
|
+
// see https://en.wikipedia.org/wiki/Quotation_mark
|
|
133
|
+
const custom = (start, end) => {
|
|
134
|
+
start = getStringValue(start);
|
|
135
|
+
end = getStringValue(end);
|
|
136
|
+
return [getStringValue(start), end.length ? end : start];
|
|
137
|
+
}
|
|
138
|
+
const quots = {
|
|
139
|
+
backtick: ["`", "`"],
|
|
140
|
+
bracket: [`{`, `}`],
|
|
141
|
+
curlyDoubleInward: [`”`, `“`],
|
|
142
|
+
curlyDouble: [`“`, `”`],
|
|
143
|
+
curlyDoubleEqual: [`“`, `“`],
|
|
144
|
+
curlyLHDouble: [`„`, `”`],
|
|
145
|
+
curlyLHDoubleInward: [`„`, `“`],
|
|
146
|
+
curlyLHSingle: [`‚`, `’`],
|
|
147
|
+
curlyLHSingleInward: [`‚`, `‘`],
|
|
148
|
+
curlySingle: [`‛`, `’`],
|
|
149
|
+
curlySingleEqual: [`‛`, `‛`],
|
|
150
|
+
curlySingleInward: [`’`, `‛`],
|
|
151
|
+
custom,
|
|
152
|
+
double: [`"`, `"`],
|
|
153
|
+
guillemets: [`«`, `»`],
|
|
154
|
+
guillemetsInward: [`»`, `«`],
|
|
155
|
+
guillemetsSingle: [`‹`, `›`],
|
|
156
|
+
guillemetsSingleInward: [`›`, `‹`],
|
|
157
|
+
single: [`'`, `'`],
|
|
158
|
+
squareBrackets: [`[`, `]`],
|
|
159
|
+
};
|
|
160
|
+
const regExpValues = Object.values(quots).filter(v => Array.isArray(v)).map(v => v.map(v => `\\${v}`).join(``)).join('');
|
|
161
|
+
quots.re = RegExp(`^[${regExpValues}]|[${regExpValues}]$`, "g");
|
|
162
|
+
return quots;
|
|
163
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import interpolate from "./Factories/interpolateFactory.js";
|
|
2
|
+
|
|
3
|
+
import {isArrayOf, isNumber, defineQuotingStyles, getStringValue, escapeRE} from "./genericMethods.js";
|
|
4
|
+
const quotingStyles = defineQuotingStyles();
|
|
5
|
+
|
|
6
|
+
export {
|
|
7
|
+
format, ucFirst, truncate, trimAll, replaceWords,
|
|
8
|
+
indexOf, lastIndexOf, insert, append,
|
|
9
|
+
isNumber, prefix, getStringValue, toCamelcase,
|
|
10
|
+
wordsFirstUp, toDashedNotation, quotGetters,
|
|
11
|
+
surroundWith, defineQuotingStyles, toSnakeCase,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function checkAndRun(string, fn, or) {
|
|
15
|
+
string = getStringValue(string);
|
|
16
|
+
return string.length > 0 ? fn(string) : or || string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function format(string, ...tokens) {
|
|
20
|
+
return checkAndRun(string, () => `${interpolate(string, ...tokens)}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function ucFirst(string) {
|
|
24
|
+
return checkAndRun(string, () => `${string[0].toUpperCase()}${string.slice(1)}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function surroundWith(string, start, end) {
|
|
28
|
+
if (!start && !end) {
|
|
29
|
+
return string;
|
|
30
|
+
}
|
|
31
|
+
[start, end] = isArrayOf(String, [start, end ?? ``]) ? [start, end] : [``, ``];
|
|
32
|
+
return `${start}${string}${end || start}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function toDashedNotation(string) {
|
|
36
|
+
return checkAndRun(string, () =>
|
|
37
|
+
string
|
|
38
|
+
.replace(/\s/g, '')
|
|
39
|
+
.replace(/[A-Z]/g, a => `-${a.toLowerCase()}`)
|
|
40
|
+
.replace(/-{2,}/g, `-`)
|
|
41
|
+
.replace(/[^a-z-]/g, ``)
|
|
42
|
+
.replace(/^-|-$/, ``)
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function toSnakeCase(string) {
|
|
47
|
+
return checkAndRun(string, () =>
|
|
48
|
+
string
|
|
49
|
+
.replace(/\s/g, '')
|
|
50
|
+
.replace(/[A-Z]/g, a => `_${a.toLowerCase()}`)
|
|
51
|
+
.replace(/_{2,}/g, `_`)
|
|
52
|
+
.replace(/[^a-z_]/g, ``)
|
|
53
|
+
.replace(/^_|_$/, ``)
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function wordsFirstUp(string) {
|
|
58
|
+
return checkAndRun(string, () => [...string.toLowerCase()].slice(1).reduce( (acc, v) =>
|
|
59
|
+
acc + ( !/\p{L}|[-']/u.test(acc.at(-1)) ? v.toUpperCase() : v.toLowerCase() ),
|
|
60
|
+
string[0].toUpperCase()
|
|
61
|
+
));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function toCamelcase(string) {
|
|
65
|
+
return checkAndRun(string, () =>
|
|
66
|
+
string.toLowerCase()
|
|
67
|
+
.trim()
|
|
68
|
+
.split(/[- ]/)
|
|
69
|
+
.filter(l => l && l.length > 0)
|
|
70
|
+
.map( (str, i) => i > 0 && `${ucFirst(str)}`|| str)
|
|
71
|
+
.join(``)
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function truncate(string, {at, html = false, wordBoundary = false} = {} ) {
|
|
76
|
+
return checkAndRun(string, () => {
|
|
77
|
+
if (string.length <= at) { return string; }
|
|
78
|
+
|
|
79
|
+
const subString = string.slice(0, at - 1);
|
|
80
|
+
const endwith = html ? "…" : `...`;
|
|
81
|
+
const boundary = wordBoundary
|
|
82
|
+
? [...subString.matchAll(/\p{Pe}|\p{Z}/gu)].at(-1)?.index ?? subString.length
|
|
83
|
+
: subString.length;
|
|
84
|
+
|
|
85
|
+
return (wordBoundary
|
|
86
|
+
? subString.slice(0, boundary+1).trim()
|
|
87
|
+
: subString) + endwith;
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function trimAll(string, keepLines) {
|
|
93
|
+
return checkAndRun(string, () => {
|
|
94
|
+
const lines = string
|
|
95
|
+
.split(/\n/)
|
|
96
|
+
.map(line => line.trim().replace(/\s{2,}/g, ` `));
|
|
97
|
+
return keepLines ? lines.join('\n') : lines.filter(l => l.length > 0).join(`\n`);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function replaceWords(string, { replacements = {}, caseSensitive = false} = {}) {
|
|
102
|
+
string = getStringValue(string);
|
|
103
|
+
let replacements2Array = Object.entries(replacements).flat();
|
|
104
|
+
const cando = isArrayOf(String, replacements2Array) && caseSensitive?.constructor === Boolean;
|
|
105
|
+
const modifiers = `g${!caseSensitive ? 'i' : ''}`;
|
|
106
|
+
|
|
107
|
+
if (cando) {
|
|
108
|
+
replacements2Array = replacements2Array.map(v => getStringValue(v)).filter(v => replacements2Array.length > 0);
|
|
109
|
+
|
|
110
|
+
if (replacements2Array.length) {
|
|
111
|
+
while (replacements2Array.length) {
|
|
112
|
+
const [initial, replacement] = [replacements2Array.shift(), replacements2Array.shift()];
|
|
113
|
+
const re = escapeRE(initial, modifiers);
|
|
114
|
+
string = string.replace(re, replacement);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// SEE https://youtu.be/99Zacm7SsWQ?t=2101
|
|
123
|
+
function indexOf(string, findMe, fromIndex) {
|
|
124
|
+
string = getStringValue(string);
|
|
125
|
+
fromIndex = isNumber(fromIndex) ? fromIndex : 0;
|
|
126
|
+
const index = string.indexOf(findMe, fromIndex || 0);
|
|
127
|
+
return index < 0 ? undefined : index;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function lastIndexOf(string, findMe, beforeIndex) {
|
|
131
|
+
string = getStringValue(string);
|
|
132
|
+
beforeIndex = isNumber(beforeIndex) ? beforeIndex : string.length;
|
|
133
|
+
const index = string.lastIndexOf(findMe, beforeIndex);
|
|
134
|
+
return index < 0 ? undefined : index;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function insert(string, { value, values, at = 0 } = {}) {
|
|
138
|
+
string = getStringValue(string);
|
|
139
|
+
at = isNumber(at) ? at : 0;
|
|
140
|
+
const valuesMaybeValue = getStringValue(values);
|
|
141
|
+
values = getStringValue(value).length
|
|
142
|
+
? value
|
|
143
|
+
: valuesMaybeValue.length
|
|
144
|
+
? valuesMaybeValue
|
|
145
|
+
: isArrayOf(String, values)
|
|
146
|
+
? values.map(v => getStringValue(v)).join(``)
|
|
147
|
+
: [];
|
|
148
|
+
|
|
149
|
+
return values.length <= 1
|
|
150
|
+
? string
|
|
151
|
+
: string.length === 0
|
|
152
|
+
? `${values}${string}`
|
|
153
|
+
: `${string.slice(0, at)}${values}${string.slice(at)}`;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function prefix(string, ...strings) {
|
|
157
|
+
strings = isArrayOf(String, strings) && strings;
|
|
158
|
+
return strings ? insert(getStringValue(string), {values: strings, at: 0}) : getStringValue(string);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function append(string, ...strings2Append) {
|
|
162
|
+
strings2Append = isArrayOf(String, strings2Append) && strings2Append;
|
|
163
|
+
|
|
164
|
+
if (strings2Append && strings2Append.length > 0) {
|
|
165
|
+
return `${getStringValue(string)}`.concat(strings2Append.join(``))
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return getStringValue(string);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function quotGetters(instance, wrap) {
|
|
172
|
+
return {
|
|
173
|
+
value: {
|
|
174
|
+
get backtick() { return instance.enclose(...quotingStyles.backtick); },
|
|
175
|
+
get bracket() { return instance.enclose(...quotingStyles.bracket); },
|
|
176
|
+
get curlyDouble() { return instance.enclose(...quotingStyles.curlyDouble); },
|
|
177
|
+
get curlyDoubleInward() { return instance.enclose(...quotingStyles.curlyDoubleInward); },
|
|
178
|
+
get curlyDoubleEqual() { return instance.enclose(...quotingStyles.curlyDoubleEqual); },
|
|
179
|
+
get curlyLHDoubleInward() { return instance.enclose(...quotingStyles.curlyLHDoubleInward); },
|
|
180
|
+
get curlyLHSingle() { return instance.enclose(...quotingStyles.curlyLHSingle); },
|
|
181
|
+
get curlyLHSingleInward() { return instance.enclose(...quotingStyles.curlyLHSingleInward); },
|
|
182
|
+
get curlySingle() { return instance.enclose(...quotingStyles.curlySingle); },
|
|
183
|
+
get curlySingleEqual() { return instance.enclose(...quotingStyles.curlySingleEqual); },
|
|
184
|
+
get curlySingleInward() { return instance.enclose(...quotingStyles.curlySingleInward); },
|
|
185
|
+
custom(start, end) { return instance.enclose(...[start, end ?? start]); },
|
|
186
|
+
get double() { return instance.enclose(...quotingStyles.double); },
|
|
187
|
+
get guillemets() { return instance.enclose(...quotingStyles.guillemets); },
|
|
188
|
+
get guillemetsInward() { return instance.enclose(...quotingStyles.guillemetsInward); },
|
|
189
|
+
get guillemetsSingle() { return instance.enclose(...quotingStyles.guillemetsSingle); },
|
|
190
|
+
get guillemetsSingleInward() { return instance.enclose(...quotingStyles.guillemetsSingleInward); },
|
|
191
|
+
get remove() { return wrap(`${instance.value.replace(quotingStyles.re, ``)}`); },
|
|
192
|
+
get single() { return instance.enclose(...quotingStyles.single); },
|
|
193
|
+
get squareBrackets() { return instance.enclose(...quotingStyles.squareBrackets); },
|
|
194
|
+
},
|
|
195
|
+
enumerable: false
|
|
196
|
+
};
|
|
197
|
+
}
|