cmpstr 3.2.2 → 3.3.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.
Files changed (86) hide show
  1. package/dist/CmpStr.esm.js +2149 -1721
  2. package/dist/CmpStr.esm.min.js +2 -2
  3. package/dist/CmpStr.umd.js +2028 -1604
  4. package/dist/CmpStr.umd.min.js +2 -2
  5. package/dist/cjs/CmpStr.cjs +100 -51
  6. package/dist/cjs/CmpStrAsync.cjs +35 -18
  7. package/dist/cjs/index.cjs +1 -1
  8. package/dist/cjs/metric/Cosine.cjs +1 -1
  9. package/dist/cjs/metric/DamerauLevenshtein.cjs +1 -1
  10. package/dist/cjs/metric/DiceSorensen.cjs +1 -1
  11. package/dist/cjs/metric/Hamming.cjs +1 -1
  12. package/dist/cjs/metric/Jaccard.cjs +1 -1
  13. package/dist/cjs/metric/JaroWinkler.cjs +1 -1
  14. package/dist/cjs/metric/LCS.cjs +1 -1
  15. package/dist/cjs/metric/Levenshtein.cjs +1 -1
  16. package/dist/cjs/metric/Metric.cjs +40 -22
  17. package/dist/cjs/metric/NeedlemanWunsch.cjs +1 -1
  18. package/dist/cjs/metric/QGram.cjs +1 -1
  19. package/dist/cjs/metric/SmithWaterman.cjs +1 -1
  20. package/dist/cjs/phonetic/Caverphone.cjs +1 -1
  21. package/dist/cjs/phonetic/Cologne.cjs +1 -1
  22. package/dist/cjs/phonetic/Metaphone.cjs +1 -1
  23. package/dist/cjs/phonetic/Phonetic.cjs +27 -15
  24. package/dist/cjs/phonetic/Soundex.cjs +1 -1
  25. package/dist/cjs/root.cjs +4 -2
  26. package/dist/cjs/utils/DeepMerge.cjs +102 -97
  27. package/dist/cjs/utils/DiffChecker.cjs +1 -1
  28. package/dist/cjs/utils/Errors.cjs +22 -19
  29. package/dist/cjs/utils/Filter.cjs +59 -24
  30. package/dist/cjs/utils/HashTable.cjs +44 -29
  31. package/dist/cjs/utils/Normalizer.cjs +57 -28
  32. package/dist/cjs/utils/OptionsValidator.cjs +211 -0
  33. package/dist/cjs/utils/Pool.cjs +27 -13
  34. package/dist/cjs/utils/Profiler.cjs +41 -27
  35. package/dist/cjs/utils/Registry.cjs +5 -5
  36. package/dist/cjs/utils/StructuredData.cjs +83 -53
  37. package/dist/cjs/utils/TextAnalyzer.cjs +1 -1
  38. package/dist/esm/CmpStr.mjs +101 -52
  39. package/dist/esm/CmpStrAsync.mjs +35 -18
  40. package/dist/esm/index.mjs +1 -1
  41. package/dist/esm/metric/Cosine.mjs +1 -1
  42. package/dist/esm/metric/DamerauLevenshtein.mjs +1 -1
  43. package/dist/esm/metric/DiceSorensen.mjs +1 -1
  44. package/dist/esm/metric/Hamming.mjs +1 -1
  45. package/dist/esm/metric/Jaccard.mjs +1 -1
  46. package/dist/esm/metric/JaroWinkler.mjs +1 -1
  47. package/dist/esm/metric/LCS.mjs +1 -1
  48. package/dist/esm/metric/Levenshtein.mjs +1 -1
  49. package/dist/esm/metric/Metric.mjs +40 -22
  50. package/dist/esm/metric/NeedlemanWunsch.mjs +1 -1
  51. package/dist/esm/metric/QGram.mjs +1 -1
  52. package/dist/esm/metric/SmithWaterman.mjs +1 -1
  53. package/dist/esm/phonetic/Caverphone.mjs +1 -1
  54. package/dist/esm/phonetic/Cologne.mjs +1 -1
  55. package/dist/esm/phonetic/Metaphone.mjs +1 -1
  56. package/dist/esm/phonetic/Phonetic.mjs +30 -15
  57. package/dist/esm/phonetic/Soundex.mjs +1 -1
  58. package/dist/esm/root.mjs +3 -3
  59. package/dist/esm/utils/DeepMerge.mjs +103 -94
  60. package/dist/esm/utils/DiffChecker.mjs +1 -1
  61. package/dist/esm/utils/Errors.mjs +22 -19
  62. package/dist/esm/utils/Filter.mjs +59 -24
  63. package/dist/esm/utils/HashTable.mjs +44 -29
  64. package/dist/esm/utils/Normalizer.mjs +57 -28
  65. package/dist/esm/utils/OptionsValidator.mjs +210 -0
  66. package/dist/esm/utils/Pool.mjs +27 -13
  67. package/dist/esm/utils/Profiler.mjs +41 -27
  68. package/dist/esm/utils/Registry.mjs +5 -5
  69. package/dist/esm/utils/StructuredData.mjs +83 -53
  70. package/dist/esm/utils/TextAnalyzer.mjs +1 -1
  71. package/dist/types/CmpStr.d.ts +22 -15
  72. package/dist/types/CmpStrAsync.d.ts +3 -0
  73. package/dist/types/index.d.ts +3 -3
  74. package/dist/types/metric/Metric.d.ts +9 -9
  75. package/dist/types/phonetic/Phonetic.d.ts +4 -3
  76. package/dist/types/root.d.ts +3 -2
  77. package/dist/types/utils/DeepMerge.d.ts +80 -58
  78. package/dist/types/utils/Errors.d.ts +25 -8
  79. package/dist/types/utils/Filter.d.ts +4 -1
  80. package/dist/types/utils/HashTable.d.ts +12 -11
  81. package/dist/types/utils/Normalizer.d.ts +2 -1
  82. package/dist/types/utils/OptionsValidator.d.ts +193 -0
  83. package/dist/types/utils/Profiler.d.ts +9 -28
  84. package/dist/types/utils/StructuredData.d.ts +3 -0
  85. package/dist/types/utils/Types.d.ts +13 -1
  86. package/package.json +14 -5
@@ -1,7 +1,7 @@
1
1
  /**
2
- * CmpStr v3.2.2 build-bb61120-260311
2
+ * CmpStr v3.3.0 build-3699f85-260318
3
3
  * This is a lightweight, fast and well performing library for calculating string similarity.
4
4
  * (c) 2023-2026 Paul Köhler @komed3 / MIT License
5
5
  * Visit https://github.com/komed3/cmpstr and https://npmjs.org/package/cmpstr
6
6
  */
7
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).CmpStr={})}(this,function(t){"use strict";class e extends Error{code;meta;cause;when=(new Date).toISOString();constructor(t,e,s,r){super(e),this.name=this.constructor.name,this.code=t,this.meta=s,this.cause=r,"function"==typeof Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}toJSON(){return{name:this.name,code:this.code,message:this.message,meta:this.meta,when:this.when,cause:this.cause instanceof Error?{name:this.cause.name,message:this.cause.message,stack:this.cause.stack}:this.cause}}toString(t=!1){const e=[`${this.name} [${this.code}]`,this.message];if(this.meta&&Object.keys(this.meta).length)try{e.push(JSON.stringify(this.meta))}catch{}return e.join(" - ")+(t&&this.stack?`\nStack Trace:\n${this.stack}`:"")}}class s extends e{constructor(t,e,s){super("E_VALIDATION",t,e,s)}}class r extends e{constructor(t,e,s){super("E_NOT_FOUND",t,e,s)}}class n extends e{constructor(t,e,s){super("E_USAGE",t,e,s)}}class i extends e{constructor(t,e,s){super("E_INTERNAL",t,e,s)}}class a{static assert(t,e,s){if(!t)throw new n(e,s)}static create(t,s,r){if(t instanceof e)throw t;throw new i(s,r,t)}static format(t){return t instanceof e?t.toString():t instanceof Error?`${t.name}: ${t.message}`:String(t)}static wrap(t,e,s){try{return t()}catch(t){throw new i(e,s,t)}}static async wrapAsync(t,e,s){try{return await t()}catch(t){throw new i(e,s,t)}}}var o=Object.freeze({__proto__:null,CmpStrError:e,CmpStrInternalError:i,CmpStrNotFoundError:r,CmpStrUsageError:n,CmpStrValidationError:s,ErrorUtil:a});const c=/\[(\d+)]/g,l=new Map;function h(t){let e=l.get(t);if(e)return e;const s=t.replace(c,".$1").split(".").map(t=>{const e=Number(t);return Number.isInteger(e)&&String(e)===t?e:t});return l.set(t,s),s}function p(t,e,s){let r=t;for(const t of h(e)){if(null==r||!(t in r))return s;r=r[t]}return r}function u(t,e,s){if(""===e)return s;const r=h(e);if(void 0!==t&&("object"!=typeof t||null===t))throw new n(`Cannot set property <${r[0]}> of <${JSON.stringify(t)}>`,{path:r[0],target:t});const i=t??("number"==typeof r[0]?[]:Object.create(null));let a=i;for(let t=0;t<r.length-1;t++){const e=r[t];let s=a[e];if(null!=s&&"object"!=typeof s)throw new n(`Cannot set property <${r[t+1]}> of <${JSON.stringify(s)}>`,{path:r.slice(0,t+2),value:s});null==s&&(s=a[e]="number"==typeof r[t+1]?[]:Object.create(null)),a=s}return a[r[r.length-1]]=s,i}function d(t=Object.create(null),e=Object.create(null),s=!1){const r=t??Object.create(null);return Object.keys(e).forEach(t=>{const n=e[t];if((s||void 0!==n)&&"__proto__"!==t&&"constructor"!==t)if(null===n||"object"!=typeof n||Array.isArray(n))r[t]=n;else{const e=r[t];r[t]=d(null===e||"object"!=typeof e||Array.isArray(e)?Object.create(null):e,n,s)}}),r}function g(t,e,s=!1){const r=h(e),n=(t,e=0)=>{const i=r[e];if(!t||"object"!=typeof t)return!1;if(e===r.length-1)return delete t[i];if(!n(t[i],e+1))return!1;if(!s){const e=t[i];"object"==typeof e&&(Array.isArray(e)&&e.every(t=>null==t)||!Array.isArray(e)&&0===Object.keys(e).length)&&delete t[i]}return!0};return n(t),t}var m=Object.freeze({__proto__:null,get:p,has:function(t,e){let s=t;for(const t of h(e)){if(null==s||!(t in s))return!1;s=s[t]}return!0},merge:d,rmv:g,set:u});class f{a;b;options;entries=[];grouped=[];diffRun=!1;constructor(t,e,s={}){this.a=t,this.b=e,this.options={mode:"word",caseInsensitive:!1,contextLines:1,groupedLines:!0,expandLines:!1,showChangeMagnitude:!0,maxMagnitudeSymbols:5,lineBreak:"\n",...s},this.computeDiff()}text2lines(){const t=this.a.trim().split(/\r?\n/),e=this.b.trim().split(/\r?\n/);return{linesA:t,linesB:e,maxLen:Math.max(t.length,e.length)}}tokenize(t){switch(this.options.mode){case"line":return[t];case"word":return t.split(/\s+/)}}concat(t){return t.join("word"===this.options.mode?" ":"")}computeDiff(){if(this.diffRun)return;const{linesA:t,linesB:e,maxLen:s}=this.text2lines();for(let r=0;r<s;r++)this.lineDiff(t[r]||"",e[r]||"",r);this.findGroups(),this.diffRun=!0}lineDiff(t,e,s){const{mode:r,caseInsensitive:n}=this.options,i=Math.max(t.length,e.length);let a=t,o=e;n&&(a=t.toLowerCase(),o=e.toLowerCase());let c=[],l=0,h=0;switch(r){case"line":a!==o&&(c.push({posA:0,posB:0,del:t,ins:e,size:e.length-t.length}),l=t.length,h=e.length);break;case"word":c=this.preciseDiff(t,a,e,o);for(const t of c)l+=t.del.length,h+=t.ins.length}c.length&&this.entries.push({line:s,diffs:c,delSize:l,insSize:h,baseLen:i,totalSize:h-l,magnitude:this.magnitude(l,h,i)})}preciseDiff(t,e,s,r){const n=t=>t.reduce((e,s,r)=>(e.push(r?e[r-1]+t[r-1].length+1:0),e),[]),i=this.tokenize(t),a=this.tokenize(s),o=this.tokenize(e),c=this.tokenize(r),l=o.length,h=c.length,p=n(i),u=n(a),d=[];let g=0,m=0;for(;g<l&&m<h;)if(o[g]===c[m]){let t=1;for(;g+t<l&&m+t<h&&o[g+t]===c[m+t];)t++;d.push({ai:g,bi:m,len:t}),g+=t,m+=t}else{let t=!1;for(let e=1;e<=3&&!t;e++)g+e<l&&o[g+e]===c[m]?(d.push({ai:g+e,bi:m,len:1}),g+=e+1,m+=1,t=!0):m+e<h&&o[g]===c[m+e]&&(d.push({ai:g,bi:m+e,len:1}),g+=1,m+=e+1,t=!0);t||(g++,m++)}const f=[];let y=0,w=0;for(const t of d){if(y<t.ai||w<t.bi){const e=i.slice(y,t.ai),s=a.slice(w,t.bi);f.push({posA:p[y]??0,posB:u[w]??0,del:this.concat(e),ins:this.concat(s),size:s.join("").length-e.join("").length})}y=t.ai+t.len,w=t.bi+t.len}if(y<l||w<h){const t=i.slice(y),e=a.slice(w);f.push({posA:p[y]??0,posB:u[w]??0,del:this.concat(t),ins:this.concat(e),size:e.join("").length-t.join("").length})}return f.filter(t=>t.del.length>0||t.ins.length>0)}findGroups(){const{contextLines:t}=this.options,e=(t,e,s)=>{const[r,n,i,a]=["delSize","insSize","totalSize","baseLen"].map(e=>t.reduce((t,s)=>t+s[e],0));this.grouped.push({start:e,end:s,delSize:r,insSize:n,totalSize:i,line:t[0].line,entries:t,magnitude:this.magnitude(r,n,a)})};let s=[],r=0,n=0;for(const i of this.entries){const a=Math.max(0,i.line-t),o=i.line+t;!s.length||a<=n+1?(s.length||(r=a),n=Math.max(n,o),s.push(i)):(e(s,r,n),s=[i],r=a,n=o)}s.length&&e(s,r,n)}magnitude(t,e,s){const{maxMagnitudeSymbols:r}=this.options,n=t+e;if(0===n||0===s)return"";const i=Math.min(r,Math.max(Math.round(n/s*r),1)),a=Math.round(e/n*i),o=i-a;return"+".repeat(a)+"-".repeat(o)}output(t){const{mode:e,contextLines:s,groupedLines:r,expandLines:n,showChangeMagnitude:i,lineBreak:a}=this.options,{linesA:o,linesB:c,maxLen:l}=this.text2lines(),h=Math.max(4,l.toString().length),p=(e,s)=>t?`[${s}m${e}`:e,u=e=>t?`${e}`:`-[${e}]`,d=e=>t?`${e}`:`+[${e}]`,g=(t,e,s,r)=>{r&&m(r);for(let r=t;r<=e;r++)f(r,s??r);w.push("")},m=t=>{var e;w.push(`${" ".repeat(h)} ${e=`@@ -${t.line+1},${t.delSize} +${t.line+1},${t.insSize} @@`,p(e,"36")} ${i?(t=>p(t,"33"))(t.magnitude):""}`)},f=(t,e)=>{if(o[t]||c[t]){const r=this.entries.find(e=>e.line===t),n=(t+1).toString().padStart(h," ");r&&e===t?(w.push(`${n} ${s=`- ${y(o[t],r.diffs,"del")}`,p(s,"31")}`),w.push(`${" ".repeat(h)} ${(t=>p(t,"32"))(`+ ${y(c[t],r.diffs,"ins")}`)}`)):w.push(`${n} ${(t=>p(t,"90"))(o[t])}`)}var s},y=(t,s,r)=>{if(!s.length||"line"===e)return t;let n="",i=0;for(const e of s){const s="del"===r?e.posA:e.posB,a="del"===r?e.del:e.ins;a&&(s>i&&(n+=t.slice(i,s)),n+="del"===r?u(a):d(a),i=s+a.length)}return n+t.slice(i)};let w=[""];switch(!0){case n:g(0,l);break;case r:for(const t of this.grouped)g(t.start,t.end,void 0,t);break;default:for(const t of this.entries)g(t.line-s,t.line+s,t.line,t)}return w.join(a)}getStructuredDiff=()=>this.entries;getGroupedDiff=()=>this.grouped;getASCIIDiff=()=>this.output(!1);getCLIDiff=()=>this.output(!0)}class y{static filters=new Map;static pipeline=new Map;static getPipeline(t){return a.wrap(()=>{const e=y.pipeline.get(t);if(e)return e;const s=y.filters.get(t);if(!s)return t=>t;const r=Array.from(s.values()).filter(t=>t.active).sort((t,e)=>t.priority-e.priority).map(t=>t.fn),n=t=>r.reduce((t,e)=>e(t),t);return y.pipeline.set(t,n),n},`Error compiling filter pipeline for hook <${t}>`,{hook:t})}static has(t,e){return!!y.filters.get(t)?.has(e)}static add(t,e,s,r={}){return a.wrap(()=>{const{priority:n=10,active:i=!0,overrideable:a=!0}=r,o=y.filters.get(t)??new Map,c=o.get(e);return!(c&&!c.overrideable||(o.set(e,{id:e,fn:s,priority:n,active:i,overrideable:a}),y.filters.set(t,o),y.pipeline.delete(t),0))},`Error adding filter <${e}> to hook <${t}>`,{hook:t,id:e,opt:r})}static remove(t,e){y.pipeline.delete(t);const s=y.filters.get(t);return!!s&&s.delete(e)}static pause(t,e){y.pipeline.delete(t);const s=y.filters.get(t)?.get(e);return!(!s||(s.active=!1,0))}static resume(t,e){y.pipeline.delete(t);const s=y.filters.get(t)?.get(e);return!(!s||(s.active=!0,0))}static list(t,e=!1){const s=y.filters.get(t);if(!s)return[];const r=[];for(const t of s.values())e&&!t.active||r.push(t.id);return r}static apply(t,e){return a.wrap(()=>{const s=y.getPipeline(t);return Array.isArray(e)?e.map(s):s(e)},`Error applying filters for hook <${t}>`,{hook:t,input:e})}static async applyAsync(t,e){return a.wrapAsync(async()=>{const s=y.getPipeline(t);return Array.isArray(e)?Promise.all(e.map(s)):Promise.resolve(s(e))},`Error applying filters for hook <${t}>`,{hook:t,input:e})}static clear(t){y.pipeline.clear(),t?y.filters.delete(t):y.filters.clear()}static clearPipeline(){y.pipeline.clear()}}class w{static FNV_PRIME=16777619;static HASH_OFFSET=2166136261;static fastFNV1a(t){const e=t.length;let s=this.HASH_OFFSET;const r=Math.floor(e/4);for(let e=0;e<r;e++){const r=4*e;s^=t.charCodeAt(r)|t.charCodeAt(r+1)<<8|t.charCodeAt(r+2)<<16|t.charCodeAt(r+3)<<24,s=Math.imul(s,this.FNV_PRIME)}const n=e%4;if(n>0){const e=4*r;for(let r=0;r<n;r++)s^=t.charCodeAt(e+r),s=Math.imul(s,this.FNV_PRIME)}return s^=s>>>16,s*=2246822507,s^=s>>>13,s*=3266489909,s^=s>>>16,s>>>0}}class b{LRU;static MAX_LEN=2048;static TABLE_SIZE=1e4;table=new Map;constructor(t=!0){this.LRU=t}key(t,e,s=!1){for(const t of e)if(t.length>b.MAX_LEN)return!1;const r=e.map(t=>w.fastFNV1a(t));return[t,...s?r.sort():r].join("-")}has=t=>this.table.has(t);get=t=>this.table.get(t);set(t,e,s=!0){if(!s&&this.table.has(t))return!1;for(;!this.table.has(t)&&this.table.size>=b.TABLE_SIZE;){if(!this.LRU)return!1;this.table.delete(this.table.keys().next().value)}return this.table.set(t,e),!0}delete=t=>this.table.delete(t);clear=()=>this.table.clear();size=()=>this.table.size}class A{static pipeline=new Map;static cache=new b;static REGEX={whitespace:/\s+/g,doubleChars:/(.)\1+/g,specialChars:/[^\p{L}\p{N}\s]/gu,nonLetters:/[^\p{L}]/gu,nonNumbers:/\p{N}/gu};static canonicalFlags(t){return Array.from(new Set(t)).sort().join("")}static getPipeline(t){return a.wrap(()=>{if(A.pipeline.has(t))return A.pipeline.get(t);const{REGEX:e}=A,s=[["d",t=>t.normalize("NFD")],["i",t=>t.toLowerCase()],["k",t=>t.replace(e.nonLetters,"")],["n",t=>t.replace(e.nonNumbers,"")],["r",t=>t.replace(e.doubleChars,"$1")],["s",t=>t.replace(e.specialChars,"")],["t",t=>t.trim()],["u",t=>t.normalize("NFC")],["w",t=>t.replace(e.whitespace," ")],["x",t=>t.normalize("NFKC")]].filter(([e])=>t.includes(e)).map(([,t])=>t),r=t=>s.reduce((t,e)=>e(t),t);return A.pipeline.set(t,r),r},`Failed to create normalization pipeline for flags: ${t}`,{flags:t})}static normalize(t,e){return a.wrap(()=>{if(!e||"string"!=typeof e||!t)return t;if(e=this.canonicalFlags(e),Array.isArray(t))return t.map(t=>A.normalize(t,e));const s=A.cache.key(e,[t]);if(s&&A.cache.has(s))return A.cache.get(s);const r=A.getPipeline(e)(t);return s&&A.cache.set(s,r),r},`Failed to normalize input with flags: ${e}`,{input:t,flags:e})}static async normalizeAsync(t,e){return await a.wrapAsync(async()=>e&&"string"==typeof e&&t?await(Array.isArray(t)?Promise.all(t.map(t=>A.normalize(t,e))):Promise.resolve(A.normalize(t,e))):t,`Failed to asynchronously normalize input with flags: ${e}`,{input:t,flags:e})}static clear(){A.pipeline.clear(),A.cache.clear()}}class x{active;static ENV;static instance;nowFn;memFn;store=new Set;totalTime=0;totalMem=0;static detectEnv(){"undefined"!=typeof process?x.ENV="nodejs":"undefined"!=typeof performance?x.ENV="browser":x.ENV="unknown"}static getInstance(t){return x.ENV||x.detectEnv(),x.instance||=new x(t)}constructor(t=!1){switch(this.active=t,x.ENV){case"nodejs":this.nowFn=()=>Number(process.hrtime.bigint())/1e6,this.memFn=()=>process.memoryUsage().heapUsed;break;case"browser":this.nowFn=()=>performance.now(),this.memFn=()=>performance.memory?.usedJSHeapSize??0;break;default:this.nowFn=()=>Date.now(),this.memFn=()=>0}}now=()=>this.nowFn();mem=()=>this.memFn();profile(t,e){const s=this.now(),r=this.mem(),n=t(),i=this.now()-s,a=this.mem()-r;return this.store.add({time:i,mem:a,res:n,meta:e}),this.totalTime+=i,this.totalMem+=a,n}enable=()=>{this.active=!0};disable=()=>{this.active=!1};clear(){this.store.clear(),this.totalTime=0,this.totalMem=0}run(t,e={}){return this.active?this.profile(t,e):t()}async runAsync(t,e={}){return this.active?this.profile(async()=>await t(),e):await t()}getAll=()=>[...this.store];getLast=()=>this.getAll().pop();getTotal=()=>({time:this.totalTime,mem:this.totalMem});services=Object.freeze({enable:this.enable.bind(this),disable:this.disable.bind(this),clear:this.clear.bind(this),report:this.getAll.bind(this),last:this.getLast.bind(this),total:this.getTotal.bind(this)})}const S=Object.create(null),v=Object.create(null);function k(t,e){a.assert(!(t in S||t in v),`Registry <${t}> already exists / overwriting is forbidden`,{registry:t});const s=Object.create(null),n=Object.freeze({add(r,n,i=!1){a.assert("string"==typeof r&&r.length>0,"Class name must be a non-empty string",{registry:t,name:r}),a.assert("function"==typeof n,"Class must be a constructor function",{registry:t,class:n}),a.assert(n.prototype instanceof e,`Class must extend <${t}>`,{registry:t,class:n}),a.assert(i||!(r in s),`Class <${r}> already exists / use <update=true> to overwrite`,{registry:t,name:r}),s[r]=n},remove(t){delete s[t]},has:t=>t in s,list:()=>Object.keys(s),get:e=>(a.assert("string"==typeof e&&e.length>0,"Class name must be a non-empty string",{registry:t,name:e}),a.assert(e in s,`Class <${e}> not registered for <${t}>`,{registry:t,name:e}),s[e])});return S[t]=n,v[t]=(e,...s)=>function(t,e,...s){return e=function(t,e){if(!(t in S))throw new r(`Registry <${t}> does not exist`,{registry:t});return"string"==typeof e?S[t]?.get(e):e}(t,e),a.wrap(()=>new e(...s),`Failed to create instance of class <${e.name??e}> from registry <${t}>`,{registry:t,class:e,args:s})}(t,e,...s),n}class z{maxSize;buffers=[];pointer=0;constructor(t){this.maxSize=t}acquire(t,e){return a.wrap(()=>{const s=this.buffers.length;for(let r=0;r<s;r++){const n=this.pointer+r&s-1,i=this.buffers[n];if(i.size>=t&&(e||i.size===t))return this.pointer=n+1&s-1,i}return null},`Failed to acquire buffer of size >= ${t} from pool`,{minSize:t,allowOversize:e})}release(t){a.wrap(()=>{this.buffers.length<this.maxSize?this.buffers.push(t):(this.buffers[this.pointer]=t,this.pointer=(this.pointer+1)%this.maxSize)},"Failed to release buffer back to pool",{item:t})}clear(){this.buffers=[],this.pointer=0}}class C{static CONFIG={int32:{type:"int32",maxSize:64,maxItemSize:2048,allowOversize:!0},"number[]":{type:"number[]",maxSize:16,maxItemSize:1024,allowOversize:!1},"string[]":{type:"string[]",maxSize:2,maxItemSize:1024,allowOversize:!1},set:{type:"set",maxSize:8,maxItemSize:0,allowOversize:!1},map:{type:"map",maxSize:8,maxItemSize:0,allowOversize:!1}};static POOLS={int32:new z(64),"number[]":new z(16),"string[]":new z(2),set:new z(8),map:new z(8)};static allocate(t,e){switch(t){case"int32":return new Int32Array(e);case"number[]":return new Float64Array(e);case"string[]":return new Array(e);case"set":return new Set;case"map":return new Map}}static acquire(t,e){const s=this.CONFIG[t];if(!s)throw new n(`Unsupported pool type <${t}>`,{type:t});if(e>s.maxItemSize)return this.allocate(t,e);const r=this.POOLS[t].acquire(e,s.allowOversize);return r?"int32"===t?r.buffer.subarray(0,e):r.buffer:this.allocate(t,e)}static acquireMany(t,e){return e.map(e=>this.acquire(t,e))}static release(t,e,s){const r=this.CONFIG[t];if(!r)throw new n(`Unsupported pool type <${t}>`,{type:t});s<=r.maxItemSize&&this.POOLS[t].release({buffer:e,size:s})}}class M{data;key;static create(t,e){return new M(t,e)}constructor(t,e){this.data=t,this.key=e}extractFrom(t,e){const s=C.acquire("string[]",t.length);for(let r=0;r<t.length;r++){const n=t[r][e];s[r]="string"==typeof n?n:String(n??"")}return s}extract=()=>this.extractFrom(this.data,this.key);isMetricResult(t){return"object"==typeof t&&null!==t&&"a"in t&&"b"in t&&"res"in t}isCmpStrResult(t){return"object"==typeof t&&null!==t&&"source"in t&&"target"in t&&"match"in t}normalizeResults(t){if(!Array.isArray(t)||0===t.length)return[];const e=t[0];let r=[];if(this.isMetricResult(e))r=t;else{if(!this.isCmpStrResult(e))throw new s("Unsupported result format for StructuredData normalization.");r=t.map(t=>({metric:"unknown",a:t.source,b:t.target,res:t.match,raw:t.raw}))}return r.map((t,e)=>({...t,__idx:e}))}rebuild(t,e,s,r,n){const i=new Map;for(let t=0;t<s.length;t++){const e=s[t];i.has(e)||i.set(e,[]),i.get(e).push(t)}const a=new Array(t.length),o=new Map;let c=0;for(let l=0;l<t.length;l++){const h=t[l];if(r&&0===h.res)continue;const p=h.b||"",u=i.get(p);let d;if(u&&u.length>0){const t=o.get(p)??0;o.set(p,t+1),d=u[t%u.length]}else d=h.__idx??l;if(d<0||d>=e.length)continue;const g=e[d],m=s[d]||p;a[c++]=n?g:{obj:g,key:this.key,result:{source:h.a,target:m,match:h.res},...h.raw?{raw:h.raw}:null}}return a.length=c,a}sort(t,e){if(!e||t.length<=1)return t;const s="asc"===e;return t.sort((t,e)=>s?t.res-e.res:e.res-t.res)}finalizeLookup(t,e,s){return this.rebuild(this.sort(this.normalizeResults(t),s?.sort),this.data,e,s?.removeZero,s?.objectsOnly)}performLookup(t,e,s){return a.wrap(()=>this.finalizeLookup(t(),e,s),"StructuredData lookup failed",{key:this.key})}async performLookupAsync(t,e,s){return await a.wrapAsync(async()=>this.finalizeLookup(await t(),e,s),"StructuredData async lookup failed",{key:this.key})}lookup(t,e,s){const r=this.extract();try{return this.performLookup(()=>t(e,r,s),r,s)}finally{C.release("string[]",r,r.length)}}async lookupAsync(t,e,s){const r=this.extract();try{return await this.performLookupAsync(()=>t(e,r,s),r,s)}finally{C.release("string[]",r,r.length)}}lookupPairs(t,e,s,r){const n=this.extract(),i=this.extractFrom(e,s);try{return this.performLookup(()=>t(n,i,r),n,r)}finally{C.release("string[]",n,n.length),C.release("string[]",i,i.length)}}async lookupPairsAsync(t,e,s,r){const n=this.extract(),i=this.extractFrom(e,s);try{return await this.performLookupAsync(()=>t(n,i,r),n,r)}finally{C.release("string[]",n,n.length),C.release("string[]",i,i.length)}}}class O{static REGEX={number:/\d/,sentence:/(?<=[.!?])\s+/,word:/\p{L}+/gu,nonWord:/[^\p{L}]/gu,vowelGroup:/[aeiouy]+/g,letter:/\p{L}/gu,ucLetter:/\p{Lu}/gu};text;words=[];sentences=[];charFrequency=new Map;wordHistogram=new Map;syllableCache=new Map;syllableStats;constructor(t){this.text=t.trim(),this.tokenize(),this.computeFrequencies()}tokenize(){let t;const e=this.text.toLowerCase();for(;null!==(t=O.REGEX.word.exec(e));)this.words.push(t[0]);this.sentences=this.text.split(O.REGEX.sentence).filter(Boolean)}computeFrequencies(){for(const t of this.text)this.charFrequency.set(t,(this.charFrequency.get(t)??0)+1);for(const t of this.words)this.wordHistogram.set(t,(this.wordHistogram.get(t)??0)+1)}estimateSyllables(t){const e=t.normalize("NFC").toLowerCase().replace(O.REGEX.nonWord,"");if(this.syllableCache.has(e))return this.syllableCache.get(e);const s=e.match(O.REGEX.vowelGroup),r=s?s.length:1;return this.syllableCache.set(e,r),r}computeSyllableStats(){return this.syllableStats||=(()=>{const t=this.words.map(t=>this.estimateSyllables(t)).sort((t,e)=>t-e),e=t.reduce((t,e)=>t+e,0),s=t.filter(t=>1===t).length,r=t.length?t.length%2==0?(t[t.length/2-1]+t[t.length/2])/2:t[Math.floor(t.length/2)]:0;return{total:e,mono:s,perWord:t,avg:t.length?e/t.length:0,median:r}})()}getLength=()=>this.text.length;getWordCount=()=>this.words.length;getSentenceCount=()=>this.sentences.length;getAvgWordLength(){return this.words.length?this.words.join("").length/this.words.length:0}getAvgSentenceLength(){return this.sentences.length?this.words.length/this.sentences.length:0}getWordHistogram(){return Object.fromEntries(this.wordHistogram)}getMostCommonWords(t=5){return[...this.wordHistogram.entries()].sort((t,e)=>e[1]-t[1]).slice(0,t).map(t=>t[0])}getHapaxLegomena(){return[...this.wordHistogram.entries()].filter(([,t])=>1===t).map(t=>t[0])}hasNumbers=()=>O.REGEX.number.test(this.text);getUpperCaseRatio(){const t=this.text.match(O.REGEX.letter)||[],e=this.text.match(O.REGEX.ucLetter)?.length||0;return t.length?e/t.length:0}getCharFrequency(){return Object.fromEntries(this.charFrequency)}getUnicodeCodepoints(){const t={};for(const[e,s]of this.charFrequency){const r=e.charCodeAt(0).toString(16).padStart(4,"0").toUpperCase();t[r]=(t[r]||0)+s}return t}getLongWordRatio(t=7){let e=0;for(const s of this.words)s.length>=t&&e++;return this.words.length?e/this.words.length:0}getShortWordRatio(t=3){let e=0;for(const s of this.words)s.length<=t&&e++;return this.words.length?e/this.words.length:0}getSyllablesCount(){return this.computeSyllableStats().total}getMonosyllabicWordCount(){return this.computeSyllableStats().mono}getMinSyllablesWordCount(t){return this.computeSyllableStats().perWord.filter(e=>e>=t).length}getMaxSyllablesWordCount(t){return this.computeSyllableStats().perWord.filter(e=>e<=t).length}getAvgSyllablesPerWord(){return this.computeSyllableStats().avg}getMedianSyllablesPerWord(){return this.computeSyllableStats().median}getHonoresR(){try{return 100*Math.log(this.words.length)/(1-this.getHapaxLegomena().length/(this.wordHistogram.size??1))}catch{return 0}}getReadingTime(t=200){return this.words.length/(t??1)}getReadabilityScore(t="flesch"){const e=this.words.length||1,s=e/(this.sentences.length||1),r=(this.getSyllablesCount()||1)/e;switch(t){case"flesch":return 206.835-1.015*s-84.6*r;case"fleschde":return 180-s-58.5*r;case"kincaid":return.39*s+11.8*r-15.59}}getLIXScore(){const t=this.words.length||1;return t/(this.sentences.length||1)+this.getLongWordRatio()*t/t*100}getWSTFScore(){const t=this.words.length||1,e=this.getMinSyllablesWordCount(3)/t*100,s=this.getAvgSentenceLength(),r=100*this.getLongWordRatio();return[.1935*e+.1672*s+.1297*r-this.getMonosyllabicWordCount()/t*100*.0327-.875,.2007*e+.1682*s+.1373*r-2.779,.2963*e+.1905*s-1.1144,.2744*e+.2656*s-1.693]}}const E=x.getInstance();class j{static cache=new b;metric;a;b;origA=[];origB=[];options;optKey;symmetric;results;static clear=()=>this.cache.clear();static swap=(t,e,s,r)=>s>r?[e,t,r,s]:[t,e,s,r];static clamp=t=>Math.max(0,Math.min(1,t));constructor(t,e,s,r={},n=!1){this.metric=t,this.a=Array.isArray(e)?e:[e],this.b=Array.isArray(s)?s:[s],a.assert(this.a.length>0&&this.b.length>0,"Inputs <a> and <b> must not be empty",{a:this.a,b:this.b}),this.options=r,this.optKey=w.fastFNV1a(JSON.stringify(r,Object.keys(r).sort())).toString(),this.symmetric=n}preCompute(t,e,s,r){return t===e?{res:1}:0==s||0==r||s<2&&r<2?{res:0}:void 0}compute(t,e,s,r,n){throw new i("Method compute() must be overridden in a subclass")}runSingle(t,e){return a.wrap(()=>{let s=String(this.a[t]),r=s,n=String(this.b[e]),i=n,a=r.length,o=i.length,c=this.preCompute(r,i,a,o);return c||(c=E.run(()=>{this.symmetric&&([r,i,a,o]=j.swap(r,i,a,o));const t=j.cache.key(this.metric,[r,i],this.symmetric)+this.optKey;return j.cache.get(t||"")??(()=>{const e=this.compute(r,i,a,o,Math.max(a,o));return t&&j.cache.set(t,e),e})()})),{metric:this.metric,a:this.origA[t]??s,b:this.origB[e]??n,...c}},`Failed to compute metric for inputs at indices a[${t}] and b[${e}]`,{i:t,j:e})}async runSingleAsync(t,e){return Promise.resolve(this.runSingle(t,e))}runBatch(){const t=[];for(let e=0;e<this.a.length;e++)for(let s=0;s<this.b.length;s++)t.push(this.runSingle(e,s));this.results=t}async runBatchAsync(){const t=[];for(let e=0;e<this.a.length;e++)for(let s=0;s<this.b.length;s++)t.push(await this.runSingleAsync(e,s));this.results=t}runPairwise(){const t=[];for(let e=0;e<this.a.length;e++)t.push(this.runSingle(e,e));this.results=t}async runPairwiseAsync(){const t=[];for(let e=0;e<this.a.length;e++)t.push(await this.runSingleAsync(e,e));this.results=t}setOriginal(t,e){return t&&(this.origA=Array.isArray(t)?t:[t]),e&&(this.origB=Array.isArray(e)?e:[e]),this}isBatch=()=>this.a.length>1||this.b.length>1;isSingle=()=>!this.isBatch();isPairwise(t=!1){return!(!this.isBatch()||this.a.length!==this.b.length)||!t&&(()=>{throw new n("Mode <pairwise> requires arrays of equal length",{a:this.a,b:this.b})})()}isSymmetrical=()=>this.symmetric;whichMode=t=>t??this.options?.mode??"default";clear=()=>this.results=void 0;run(t,e=!0){switch(e&&this.clear(),this.whichMode(t)){case"default":if(this.isSingle()){this.results=this.runSingle(0,0);break}case"batch":this.runBatch();break;case"single":this.results=this.runSingle(0,0);break;case"pairwise":this.isPairwise()&&this.runPairwise();break;default:throw new i(`Unsupported mode <${t}>`)}}async runAsync(t,e=!0){switch(e&&this.clear(),this.whichMode(t)){case"default":if(this.isSingle()){this.results=await this.runSingleAsync(0,0);break}case"batch":await this.runBatchAsync();break;case"single":this.results=await this.runSingleAsync(0,0);break;case"pairwise":this.isPairwise()&&await this.runPairwiseAsync();break;default:throw new i(`Unsupported async mode <${t}>`)}}getMetricName=()=>this.metric;getResults(){return a.assert(void 0!==this.results,"run() must be called before getResults()"),this.results}}const L=k("metric",j);L.add("cosine",class extends j{constructor(t,e,s={}){super("cosine",t,e,s,!0)}_termFreq(t,e){const s=t.split(e),r=C.acquire("map",s.length);for(const t of s)r.set(t,(r.get(t)||0)+1);return r}compute(t,e){const{delimiter:s=" "}=this.options,r=this._termFreq(t,s),n=this._termFreq(e,s);try{let t=0,e=0,s=0;for(const[s,i]of r)t+=i*(n.get(s)||0),e+=i*i;for(const t of n.values())s+=t*t;return e=Math.sqrt(e),s=Math.sqrt(s),{res:e&&s?j.clamp(t/(e*s)):0,raw:{dotProduct:t,magnitudeA:e,magnitudeB:s}}}finally{C.release("map",r,r.size),C.release("map",n,n.size)}}}),L.add("damerau",class extends j{constructor(t,e,s={}){super("damerau",t,e,s,!0)}compute(t,e,s,r,n){const i=s+1,[a,o,c]=C.acquireMany("int32",[i,i,i]);try{for(let t=0;t<=s;t++)o[t]=t;for(let n=1;n<=r;n++){c[0]=n;const r=e.charCodeAt(n-1);for(let i=1;i<=s;i++){const s=t.charCodeAt(i-1),l=s===r?0:1;let h=Math.min(c[i-1]+1,o[i]+1,o[i-1]+l);i>1&&n>1&&s===e.charCodeAt(n-2)&&r===t.charCodeAt(i-2)&&(h=Math.min(h,a[i-2]+l)),c[i]=h}a.set(o),o.set(c)}const i=o[s];return{res:0===n?1:j.clamp(1-i/n),raw:{dist:i,maxLen:n}}}finally{C.release("int32",a,i),C.release("int32",o,i),C.release("int32",c,i)}}}),L.add("dice",class extends j{constructor(t,e,s={}){super("dice",t,e,s,!0)}_bigrams(t){const e=t.length-1,s=C.acquire("set",e);for(let r=0;r<e;r++)s.add(t.substring(r,r+2));return s}compute(t,e){const s=this._bigrams(t),r=this._bigrams(e),n=s.size,i=r.size;try{let t=0;for(const e of s)r.has(e)&&t++;const e=n+i;return{res:0===e?1:j.clamp(2*t/e),raw:{intersection:t,size:e}}}finally{C.release("set",s,n),C.release("set",r,i)}}}),L.add("hamming",class extends j{constructor(t,e,s={}){super("hamming",t,e,s,!0)}compute(t,e,s,r,i){if(s!==r){if(void 0===this.options.pad)throw new n(`Strings must be of equal length for Hamming Distance, a=${s} and b=${r} given, use option.pad for automatic adjustment`,{a:s,b:r});s<i&&(t=t.padEnd(i,this.options.pad)),r<i&&(e=e.padEnd(i,this.options.pad)),s=r=i}let a=0;for(let r=0;r<s;r++)t[r]!==e[r]&&a++;return{res:0===s?1:j.clamp(1-a/s),raw:{dist:a}}}}),L.add("jaccard",class extends j{constructor(t,e,s={}){super("jaccard",t,e,s,!0)}compute(t,e,s,r){const[n,i]=C.acquireMany("set",[s,r]);try{for(const e of t)n.add(e);for(const t of e)i.add(t);let s=0;for(const t of n)i.has(t)&&s++;const r=n.size+i.size-s;return{res:0===r?1:j.clamp(s/r),raw:{intersection:s,union:r}}}finally{C.release("set",n,s),C.release("set",i,r)}}}),L.add("jaroWinkler",class extends j{constructor(t,e,s={}){super("jaroWinkler",t,e,s,!0)}compute(t,e,s,r){const[n,i]=C.acquireMany("int32",[s,r]);try{for(let t=0;t<s;t++)n[t]=0;for(let t=0;t<r;t++)i[t]=0;const a=Math.max(0,Math.floor(r/2)-1);let o=0;for(let c=0;c<s;c++){const s=Math.max(0,c-a),l=Math.min(c+a+1,r);for(let r=s;r<l;r++)if(!i[r]&&t[c]===e[r]){n[c]=1,i[r]=1,o++;break}}let c=0,l=0,h=0,p=0;if(o>0){let a=0;for(let r=0;r<s;r++)if(n[r]){for(;!i[a];)a++;t[r]!==e[a]&&c++,a++}c/=2,l=(o/s+o/r+(o-c)/o)/3;for(let n=0;n<Math.min(4,s,r)&&t[n]===e[n];n++)h++;p=l+.1*h*(1-l)}return{res:j.clamp(p),raw:{matchWindow:a,matches:o,transpos:c,jaro:l,prefix:h}}}finally{C.release("int32",n,s),C.release("int32",i,r)}}}),L.add("lcs",class extends j{constructor(t,e,s={}){super("lcs",t,e,s,!0)}compute(t,e,s,r,n){const i=s+1,[a,o]=C.acquireMany("int32",[i,i]);try{for(let t=0;t<=s;t++)a[t]=0;for(let n=1;n<=r;n++){o[0]=0;const r=e.charCodeAt(n-1);for(let e=1;e<=s;e++)t.charCodeAt(e-1)===r?o[e]=a[e-1]+1:o[e]=Math.max(a[e],o[e-1]);a.set(o)}const i=a[s];return{res:0===n?1:j.clamp(i/n),raw:{lcs:i,maxLen:n}}}finally{C.release("int32",a,i),C.release("int32",o,i)}}}),L.add("levenshtein",class extends j{constructor(t,e,s={}){super("levenshtein",t,e,s,!0)}compute(t,e,s,r,n){const i=s+1,[a,o]=C.acquireMany("int32",[i,i]);try{for(let t=0;t<=s;t++)a[t]=t;for(let n=1;n<=r;n++){o[0]=n;const r=e.charCodeAt(n-1);for(let e=1;e<=s;e++){const s=t.charCodeAt(e-1)===r?0:1;o[e]=Math.min(o[e-1]+1,a[e]+1,a[e-1]+s)}a.set(o)}const i=a[s];return{res:0===n?1:j.clamp(1-i/n),raw:{dist:i,maxLen:n}}}finally{C.release("int32",a,i),C.release("int32",o,i)}}}),L.add("needlemanWunsch",class extends j{constructor(t,e,s={}){super("needlemanWunsch",t,e,s,!0)}compute(t,e,s,r,n){const{match:i=1,mismatch:a=-1,gap:o=-1}=this.options,c=s+1,[l,h]=C.acquireMany("int32",[c,c]);try{l[0]=0;for(let t=1;t<=s;t++)l[t]=l[t-1]+o;for(let n=1;n<=r;n++){h[0]=l[0]+o;const r=e.charCodeAt(n-1);for(let e=1;e<=s;e++){const s=t.charCodeAt(e-1)===r?i:a;h[e]=Math.max(l[e-1]+s,l[e]+o,h[e-1]+o)}l.set(h)}const c=l[s],p=n*i;return{res:0===p?0:j.clamp(c/p),raw:{score:c,denum:p}}}finally{C.release("int32",l,c),C.release("int32",h,c)}}}),L.add("qGram",class extends j{constructor(t,e,s={}){super("qGram",t,e,s,!0)}_qGrams(t,e){const s=Math.max(0,t.length-e+1),r=C.acquire("set",s);for(let n=0;n<s;n++)r.add(t.slice(n,n+e));return r}compute(t,e){const{q:s=2}=this.options,r=this._qGrams(t,s),n=this._qGrams(e,s),i=r.size,a=n.size;try{let t=0;for(const e of r)n.has(e)&&t++;const e=Math.max(i,a);return{res:0===e?1:j.clamp(t/e),raw:{intersection:t,size:e}}}finally{C.release("set",r,i),C.release("set",n,a)}}}),L.add("smithWaterman",class extends j{constructor(t,e,s={}){super("smithWaterman",t,e,s,!0)}compute(t,e,s,r){const{match:n=2,mismatch:i=-1,gap:a=-2}=this.options,o=s+1,[c,l]=C.acquireMany("int32",[o,o]);let h=0;try{for(let t=0;t<=s;t++)c[t]=0;for(let o=1;o<=r;o++){l[0]=0;const r=e.charCodeAt(o-1);for(let e=1;e<=s;e++){const s=t.charCodeAt(e-1)===r?n:i;l[e]=Math.max(0,c[e-1]+s,c[e]+a,l[e-1]+a),l[e]>h&&(h=l[e])}c.set(l)}const o=Math.min(s*n,r*n);return{res:0===o?0:j.clamp(h/o),raw:{score:h,denum:o}}}finally{C.release("int32",c,o),C.release("int32",l,o)}}});const $=x.getInstance();class F{static cache=new b;static default;algo;options;optKey;map;static clear=()=>this.cache.clear();constructor(t,e={}){const s=this.constructor.default??{},n=e.map??s.map;if(!n)throw new r("No mapping specified for phonetic algorithm",{algo:t});const i=q.get(t,n);if(void 0===i)throw new r(`Requested mapping <${n}> is not declared`,{algo:t,mapId:n});this.options=d(d(s,i.options??{}),e),this.optKey=w.fastFNV1a(JSON.stringify(this.options,Object.keys(this.options).sort())).toString(),this.algo=t,this.map=i}applyPattern(t){const{patterns:e=[]}=this.map;if(!e||!e.length)return t;for(const{pattern:s,replace:r,all:n=!1}of e)t=t[n?"replaceAll":"replace"](s,r);return t}applyRules(t,e,s,r){const{ruleset:n=[]}=this.map;if(!n||!n.length)return;const i=s[e-1]||"",a=s[e-2]||"",o=s[e+1]||"",c=s[e+2]||"";for(const l of n)if((!l.char||l.char===t)&&("start"!==l.position||0===e)&&("middle"!==l.position||0!==e&&e!==r-1)&&("end"!==l.position||e===r)&&(!l.prev||l.prev.includes(i))&&(!l.prevNot||!l.prevNot.includes(i))&&(!l.prev2||l.prev2.includes(a))&&(!l.prev2Not||!l.prev2Not.includes(a))&&(!l.next||l.next.includes(o))&&(!l.nextNot||!l.nextNot.includes(o))&&(!l.next2||l.next2.includes(c))&&(!l.next2Not||!l.next2Not.includes(c))&&(!l.leading||l.leading.includes(s.slice(0,l.leading.length).join("")))&&(!l.trailing||l.trailing.includes(s.slice(-l.trailing.length).join("")))&&(!l.match||l.match.every((t,r)=>s[e+r]===t)))return l.code}encode(t){const{map:e={},ignore:s=[]}=this.map;t=this.applyPattern(t);const r=this.word2Chars(t),n=r.length;let i="",a=null;for(let t=0;t<n;t++){const o=r[t];if(s.includes(o))continue;const c=this.mapChar(o,t,r,n,a,e);if(void 0!==c&&(i+=c,a=c,this.exitEarly(i,t)))break}return this.adjustCode(i,r)}mapChar(t,e,s,r,n,i){const{dedupe:a=!0,fallback:o}=this.options,c=this.applyRules(t,e,s,r)??i[t]??o;return a&&c===n?void 0:c}equalLen(t){const{length:e=-1,pad:s="0"}=this.options;return-1===e?t:(t+s.repeat(e)).slice(0,e)}word2Chars=t=>t.toLowerCase().split("");exitEarly(t,e){const{length:s=-1}=this.options;return s>0&&t.length>=s}adjustCode(t,e){return t}loop(t){return a.wrap(()=>{const e=[];for(const s of t){const t=F.cache.key(this.algo,[s])+this.optKey,r=F.cache.get(t||"")??(()=>{const e=this.encode(s);return t&&F.cache.set(t,e),e})();r&&r.length&&e.push(this.equalLen(r))}return e},"Failed to generate phonetic index",{algo:this.algo,words:t})}async loopAsync(t){return a.wrapAsync(async()=>{const e=[];for(const s of t){const t=F.cache.key(this.algo,[s])+this.optKey,r=await Promise.resolve(F.cache.get(t||"")??(()=>{const e=this.encode(s);return t&&F.cache.set(t,e),e})());r&&r.length&&e.push(this.equalLen(r))}return e},"Failed to generate phonetic index asynchronously",{algo:this.algo,words:t})}getAlgoName=()=>this.algo;getIndex(t){const{delimiter:e=" "}=this.options;return $.run(()=>this.loop(t.split(e).filter(Boolean)).filter(Boolean))}async getIndexAsync(t){const{delimiter:e=" "}=this.options;return(await $.runAsync(async()=>await this.loopAsync(t.split(e).filter(Boolean)))).filter(Boolean)}}const N=k("phonetic",F),q=(()=>{const t=Object.create(null),e=e=>t[e]||=Object.create(null);return Object.freeze({add(t,s,r,n=!1){const i=e(t);a.assert(!(!s||s in i)||n,`Entry <${s}> already exists / use <update=true> to overwrite`,{algo:t,id:s}),i[s]=r},remove(t,s){delete e(t)[s]},has:(t,s)=>s in e(t),get:(t,s)=>e(t)[s],list:t=>Object.keys(e(t))})})();class R extends F{static REGEX={uppercase:/[^A-Z]/gi};static default={map:"en2",delimiter:" ",length:-1,pad:"",dedupe:!1};constructor(t={}){super("caverphone",t)}encode(t){return t=t.replace(R.REGEX.uppercase,"").toLowerCase(),super.encode(t)}mapChar=t=>t;adjustCode=t=>t.toUpperCase()}N.add("caverphone",R),q.add("caverphone","en1",{options:{length:6,pad:"1"},map:{},patterns:[{pattern:/^(c|r|t|en)ough/,replace:"$1ou2f"},{pattern:/^gn/,replace:"2n"},{pattern:/mb$/,replace:"m2"},{pattern:/cq/g,replace:"2q"},{pattern:/c(e|i|y)/g,replace:"s$1"},{pattern:/tch/g,replace:"2ch"},{pattern:/[cqx]/g,replace:"k"},{pattern:/v/g,replace:"f"},{pattern:/dg/g,replace:"2g"},{pattern:/ti(a|o)/g,replace:"si$1"},{pattern:/d/g,replace:"t"},{pattern:/ph/g,replace:"fh"},{pattern:/b/g,replace:"p"},{pattern:/sh/g,replace:"s2"},{pattern:/z/g,replace:"s"},{pattern:/^[aeiou]/,replace:"A"},{pattern:/[aeiou]/g,replace:"3"},{pattern:/3gh3/g,replace:"3kh3"},{pattern:/gh/g,replace:"22"},{pattern:/g/g,replace:"k"},{pattern:/s+/g,replace:"S"},{pattern:/t+/g,replace:"T"},{pattern:/p+/g,replace:"P"},{pattern:/k+/g,replace:"K"},{pattern:/f+/g,replace:"F"},{pattern:/m+/g,replace:"M"},{pattern:/n+/g,replace:"N"},{pattern:/j/g,replace:"y"},{pattern:/l3/g,replace:"L3"},{pattern:/r3/g,replace:"R3"},{pattern:/w3/g,replace:"W3"},{pattern:/y3/g,replace:"Y3"},{pattern:/ly/g,replace:"Ly"},{pattern:/ry/g,replace:"Ry"},{pattern:/wy/g,replace:"Wy"},{pattern:/wh3/g,replace:"Wh3"},{pattern:/why/g,replace:"Why"},{pattern:/^h/,replace:"A"},{pattern:/[hlrwy23]/g,replace:""}]}),q.add("caverphone","en2",{options:{length:10,pad:"1"},map:{},patterns:[{pattern:/e$/,replace:""},{pattern:/^(c|r|t|en|tr)ough/,replace:"$1ou2f"},{pattern:/^gn/,replace:"2n"},{pattern:/mb$/,replace:"m2"},{pattern:/cq/g,replace:"2q"},{pattern:/c(e|i|y)/g,replace:"s$1"},{pattern:/tch/g,replace:"2ch"},{pattern:/[cqx]/g,replace:"k"},{pattern:/v/g,replace:"f"},{pattern:/dg/g,replace:"2g"},{pattern:/ti(a|o)/g,replace:"si$1"},{pattern:/d/g,replace:"t"},{pattern:/ph/g,replace:"fh"},{pattern:/b/g,replace:"p"},{pattern:/sh/g,replace:"s2"},{pattern:/z/g,replace:"s"},{pattern:/^[aeiou]/,replace:"A"},{pattern:/[aeiou]/g,replace:"3"},{pattern:/j/g,replace:"y"},{pattern:/^y3/,replace:"Y3"},{pattern:/^y/,replace:"A"},{pattern:/y/g,replace:"3"},{pattern:/3gh3/g,replace:"3kh3"},{pattern:/gh/g,replace:"22"},{pattern:/g/g,replace:"k"},{pattern:/s+/g,replace:"S"},{pattern:/t+/g,replace:"T"},{pattern:/p+/g,replace:"P"},{pattern:/k+/g,replace:"K"},{pattern:/f+/g,replace:"F"},{pattern:/m+/g,replace:"M"},{pattern:/n+/g,replace:"N"},{pattern:/l3/g,replace:"L3"},{pattern:/r3/g,replace:"R3"},{pattern:/w3/g,replace:"W3"},{pattern:/wh3/g,replace:"Wh3"},{pattern:/[lrw]$/,replace:"3"},{pattern:/^h/,replace:"A"},{pattern:/3$/,replace:"A"},{pattern:/[hlrw23]/g,replace:""}]}),N.add("cologne",class extends F{static default={map:"default",delimiter:" ",length:-1,dedupe:!0};constructor(t={}){super("cologne",t)}adjustCode(t){return t.slice(0,1)+t.slice(1).replaceAll("0","")}}),q.add("cologne","default",{map:{a:"0","ä":"0",e:"0",i:"0",j:"0",o:"0","ö":"0",u:"0","ü":"0",y:"0",b:"1",p:"1",d:"2",t:"2",f:"3",v:"3",w:"3",g:"4",k:"4",q:"4",l:"5",m:"6",n:"6",r:"7",c:"8",s:"8","ß":"8",z:"8",x:"48"},ignore:["h"],ruleset:[{char:"p",next:["h"],code:"3"},{char:"c",position:"start",next:["a","h","k","l","o","q","r","u","x"],code:"4"},{char:"c",next:["a","h","k","o","q","u","x"],prevNot:["s","z"],code:"4"},{char:"d",next:["c","s","z"],code:"8"},{char:"t",next:["c","s","z"],code:"8"},{char:"x",prev:["c","k","q"],code:"8"}]});class P extends F{static REGEX={adjacent:/([A-BD-Z])\1+/gi,vowel:/[AEIOU]/g};static default={map:"en90",delimiter:" ",length:-1,pad:"",dedupe:!1};constructor(t={}){super("metaphone",t)}encode(t){return t=t.replace(P.REGEX.adjacent,(t,e)=>"C"===e?t:e),super.encode(t)}adjustCode(t){return t.slice(0,1)+t.slice(1).replace(P.REGEX.vowel,"")}}N.add("metaphone",P),q.add("metaphone","en90",{map:{a:"A",b:"B",c:"K",d:"T",e:"E",f:"F",g:"K",h:"H",i:"I",j:"J",k:"K",l:"L",m:"M",n:"N",o:"O",p:"P",q:"K",r:"R",s:"S",t:"T",u:"U",v:"F",w:"W",x:"KS",y:"Y",z:"S"},ruleset:[{char:"a",position:"start",next:["e"],code:""},{char:"g",position:"start",next:["n"],code:""},{char:"k",position:"start",next:["n"],code:""},{char:"p",position:"start",next:["n"],code:""},{char:"w",position:"start",next:["r"],code:""},{char:"b",position:"end",prev:["m"],code:""},{char:"c",next:["h"],prevNot:["s"],code:"X"},{char:"c",next:["i"],next2:["a"],code:"X"},{char:"c",next:["e","i","y"],code:"S"},{char:"d",next:["g"],next2:["e","i","y"],code:"J"},{char:"g",next:["h"],next2Not:["","a","e","i","o","u"],code:""},{char:"g",trailing:"n",code:""},{char:"g",trailing:"ned",code:""},{char:"g",next:["e","i","y"],prevNot:["g"],code:"J"},{char:"h",prev:["a","e","i","o","u"],nextNot:["a","e","i","o","u"],code:""},{char:"h",prev:["c","g","p","s","t"],code:""},{char:"k",prev:["c"],code:""},{char:"p",next:["h"],code:"F"},{char:"s",next:["h"],code:"X"},{char:"s",next:["i"],next2:["a","o"],code:"X"},{char:"t",next:["i"],next2:["a","o"],code:"X"},{char:"t",next:["h"],code:"0"},{char:"t",next:["c"],next2:["h"],code:""},{char:"w",nextNot:["a","e","i","o","u"],code:""},{char:"h",leading:"w",code:""},{char:"x",position:"start",code:"S"},{char:"y",nextNot:["a","e","i","o","u"],code:""}]}),N.add("soundex",class extends F{static default={map:"en",delimiter:" ",length:4,pad:"0",dedupe:!0};constructor(t={}){super("soundex",t)}adjustCode(t,e){return e[0].toUpperCase()+t.slice(1).replaceAll("0","")}}),q.add("soundex","en",{map:{a:"0",e:"0",h:"0",i:"0",o:"0",u:"0",w:"0",y:"0",b:"1",f:"1",p:"1",v:"1",c:"2",g:"2",j:"2",k:"2",q:"2",s:"2",x:"2",z:"2",d:"3",t:"3",l:"4",m:"5",n:"5",r:"6"}}),q.add("soundex","de",{map:{a:"0","ä":"0",e:"0",h:"0",i:"0",j:"0",o:"0","ö":"0",u:"0","ü":"0",y:"0",b:"1",f:"1",p:"1",v:"1",w:"1",c:"2",g:"2",k:"2",q:"2",s:"2","ß":"2",x:"2",z:"2",d:"3",t:"3",l:"4",m:"5",n:"5",r:"6"},ruleset:[{char:"c",next:["h"],code:"7"}]});const I=x.getInstance();class _{static filter={has:y.has,add:y.add,remove:y.remove,pause:y.pause,resume:y.resume,list:y.list,clear:y.clear};static metric={add:L.add,remove:L.remove,has:L.has,list:L.list};static phonetic={add:N.add,remove:N.remove,has:N.has,list:N.list,map:{add:q.add,remove:q.remove,has:q.has,list:q.list}};static profiler=I.services;static clearCache={normalizer:A.clear,filter:y.clearPipeline,metric:j.clear,phonetic:F.clear};static analyze=t=>new O(t);static diff=(t,e,s)=>new f(t,e,s);static create(t){return new _(t)}options=Object.create(null);constructor(t){t&&("string"==typeof t?this.setSerializedOptions(t):this.setOptions(t))}assert(t,e){switch(t){case"metric":if(!_.metric.has(e))throw new r("CmpStr <metric> must be set, call .setMetric(), use CmpStr.metric.list() for available metrics",{metric:e});break;case"phonetic":if(!_.phonetic.has(e))throw new r("CmpStr <phonetic> must be set, call .setPhonetic(), use CmpStr.phonetic.list() for available phonetic algorithms",{phonetic:e});break;default:throw new i(`Cmpstr condition <${t}> unknown`)}}assertMany(...t){for(const[e,s]of t)this.assert(e,s)}resolveOptions(t){return d({...this.options??Object.create(null)},t)}normalize(t,e){return A.normalize(t,e??this.options.flags??"")}filter(t,e){return y.apply(e,t)}prepare(t,e){const{flags:s,processors:r}=e??this.options;return s?.length&&(t=this.normalize(t,s)),t=this.filter(t,"input"),r?.phonetic&&(t=this.index(t,r.phonetic)),t}postProcess(t,e){return e?.removeZero&&Array.isArray(t)&&(t=t.filter(t=>t.res>0)),t}index(t,{algo:e,opt:s}){this.assert("phonetic",e);const r=v.phonetic(e,s),n=s?.delimiter??" ";return Array.isArray(t)?t.map(t=>r.getIndex(t).join(n)):r.getIndex(t).join(n)}structured(t,e){return M.create(t,e)}compute(t,e,s,r,n,i){return a.wrap(()=>{const a=this.resolveOptions(s);this.assert("metric",a.metric);const o=i?t:this.prepare(t,a),c=i?e:this.prepare(e,a);if(a.safeEmpty&&(Array.isArray(o)&&0===o.length||Array.isArray(c)&&0===c.length||""===o||""===c))return[];const l=v.metric(a.metric,o,c,a.opt);"prep"!==a.output&&l.setOriginal(t,e),l.run(r);const h=this.postProcess(l.getResults(),a);return this.output(h,n??a.raw)},`Failed to compute metric <${s?.metric??this.options.metric}> for the given inputs`,{a:t,b:e,options:s})}output(t,e){return a.wrap(()=>e??this.options.raw?t:Array.isArray(t)?t.map(t=>({source:t.a,target:t.b,match:t.res})):{source:t.a,target:t.b,match:t.res},"Failed to resolve output format for the metric result",{result:t,raw:e})}clone=()=>Object.assign(Object.create(Object.getPrototypeOf(this)),this);reset(){for(const t in this.options)delete this.options[t];return this}setOptions(t){return this.options=t,this}mergeOptions(t){return d(this.options,t),this}setSerializedOptions(t){return a.wrap(()=>(this.options=JSON.parse(t),this),"Failed to parse serialized options, invalid JSON string",{opt:t})}setOption(t,e){return u(this.options,t,e),this}rmvOption(t){return g(this.options,t),this}setRaw=t=>this.setOption("raw",t);setMetric=t=>this.setOption("metric",t);setFlags=t=>this.setOption("flags",t);rmvFlags=()=>this.rmvOption("flags");setProcessors=t=>this.setOption("processors",t);rmvProcessors=()=>this.rmvOption("processors");getOptions=()=>this.options;getSerializedOptions=()=>JSON.stringify(this.options);getOption=t=>p(this.options,t);test(t,e,s){return this.compute(t,e,s,"single")}compare(t,e,s){return this.compute(t,e,s,"single",!0).res}batchTest(t,e,s){return this.compute(t,e,s,"batch")}batchSorted(t,e,s="desc",r){return this.output(this.compute(t,e,r,"batch",!0).sort((t,e)=>"asc"===s?t.res-e.res:e.res-t.res),r?.raw??this.options.raw)}pairs(t,e,s){return this.compute(t,e,s,"pairwise")}match(t,e,s,r){return this.output(this.compute(t,e,r,"batch",!0).filter(t=>t.res>=s).sort((t,e)=>e.res-t.res),r?.raw??this.options.raw)}closest(t,e,s=1,r){return this.batchSorted(t,e,"desc",r).slice(0,s)}furthest(t,e,s=1,r){return this.batchSorted(t,e,"asc",r).slice(0,s)}search(t,e,s,r){const n=this.resolveOptions({flags:s,processors:r}),i=this.prepare(t,n),a=this.prepare(e,n);return e.filter((t,e)=>a[e].includes(i))}matrix(t,e){return(t=this.prepare(t,this.resolveOptions(e))).map(e=>this.compute(e,t,void 0,"batch",!0,!0).map(t=>t.res??0))}phoneticIndex(t,e,s){const{algo:r,opt:n}=this.options.processors?.phonetic??{};return this.index(t,{algo:e??r,opt:s??n})}structuredLookup(t,e,s,r){return this.structured(e,s).lookup((t,e,s)=>this.batchTest(t,e,s),t,r)}structuredMatch(t,e,s,r,n){return this.structured(e,s).lookup((t,e,s)=>this.match(t,e,r,s),t,{...n,sort:"desc"})}structuredClosest(t,e,s,r=1,n){return this.structured(e,s).lookup((t,e,s)=>this.closest(t,e,r,s),t,{...n,sort:"desc"})}structuredFurthest(t,e,s,r=1,n){return this.structured(e,s).lookup((t,e,s)=>this.furthest(t,e,r,s),t,{...n,sort:"asc"})}structuredPairs(t,e,s,r,n){return this.structured(t,e).lookupPairs((t,e,s)=>this.pairs(t,e,s),s,r,n)}}class W extends _{static create(t){return new W(t)}constructor(t){super(t)}async normalizeAsync(t,e){return A.normalizeAsync(t,e??this.options.flags??"")}async filterAsync(t,e){return y.applyAsync(e,t)}async prepareAsync(t,e){const{flags:s,processors:r}=e??this.options;return s?.length&&(t=await this.normalizeAsync(t,s)),t=await this.filterAsync(t,"input"),r?.phonetic&&(t=await this.indexAsync(t,r.phonetic)),t}async indexAsync(t,{algo:e,opt:s}){this.assert("phonetic",e);const r=v.phonetic(e,s),n=s?.delimiter??" ";return Array.isArray(t)?Promise.all(t.map(t=>r.getIndexAsync(t).then(t=>t.join(n)))):r.getIndexAsync(t).then(t=>t.join(n))}async computeAsync(t,e,s,r,n,i){return a.wrapAsync(async()=>{const a=this.resolveOptions(s);this.assert("metric",a.metric);const o=i?t:await this.prepareAsync(t,a),c=i?e:await this.prepareAsync(e,a);if(a.safeEmpty&&(Array.isArray(o)&&0===o.length||Array.isArray(c)&&0===c.length||""===o||""===c))return[];const l=v.metric(a.metric,o,c,a.opt);"prep"!==a.output&&l.setOriginal(t,e),await l.runAsync(r);const h=this.postProcess(l.getResults(),a);return this.output(h,n??a.raw)},`Failed to compute metric <${s?.metric??this.options.metric}> for the given inputs`,{a:t,b:e,opt:s})}async testAsync(t,e,s){return this.computeAsync(t,e,s,"single")}async compareAsync(t,e,s){return(await this.computeAsync(t,e,s,"single",!0)).res}async batchTestAsync(t,e,s){return this.computeAsync(t,e,s,"batch")}async batchSortedAsync(t,e,s="desc",r){const n=await this.computeAsync(t,e,r,"batch",!0);return this.output(n.sort((t,e)=>"asc"===s?t.res-e.res:e.res-t.res),r?.raw??this.options.raw)}async pairsAsync(t,e,s){return this.computeAsync(t,e,s,"pairwise")}async matchAsync(t,e,s,r){const n=await this.computeAsync(t,e,r,"batch",!0);return this.output(n.filter(t=>t.res>=s).sort((t,e)=>e.res-t.res),r?.raw??this.options.raw)}async closestAsync(t,e,s=1,r){return(await this.batchSortedAsync(t,e,"desc",r)).slice(0,s)}async furthestAsync(t,e,s=1,r){return(await this.batchSortedAsync(t,e,"asc",r)).slice(0,s)}async searchAsync(t,e,s,r){const n=this.resolveOptions({flags:s,processors:r}),i=await this.prepareAsync(t,n),a=await this.prepareAsync(e,n);return e.filter((t,e)=>a[e].includes(i))}async matrixAsync(t,e){return t=await this.prepareAsync(t,this.resolveOptions(e)),Promise.all(t.map(async e=>await this.computeAsync(e,t,void 0,"batch",!0,!0).then(t=>t.map(t=>t.res??0))))}async phoneticIndexAsync(t,e,s){const{algo:r,opt:n}=this.options.processors?.phonetic??{};return this.indexAsync(t,{algo:e??r,opt:s??n})}async structuredLookupAsync(t,e,s,r){return await this.structured(e,s).lookupAsync((t,e,s)=>this.batchTestAsync(t,e,s),t,r)}async structuredMatchAsync(t,e,s,r,n){return await this.structured(e,s).lookupAsync((t,e,s)=>this.matchAsync(t,e,r,s),t,{...n,sort:"desc"})}async structuredClosestAsync(t,e,s,r=1,n){return await this.structured(e,s).lookupAsync((t,e,s)=>this.closestAsync(t,e,r,s),t,{...n,sort:"desc"})}async structuredFurthestAsync(t,e,s,r=1,n){return await this.structured(e,s).lookupAsync((t,e,s)=>this.furthestAsync(t,e,r,s),t,{...n,sort:"asc"})}async structuredPairsAsync(t,e,s,r,n){return await this.structured(t,e).lookupPairsAsync((t,e,s)=>this.pairsAsync(t,e,s),s,r,n)}}t.CmpStr=_,t.CmpStrAsync=W,t.CmpStrError=o,t.DeepMerge=m,t.DiffChecker=f,t.Filter=y,t.HashTable=b,t.Hasher=w,t.Metric=j,t.MetricRegistry=L,t.Normalizer=A,t.Phonetic=F,t.PhoneticMappingRegistry=q,t.PhoneticRegistry=N,t.Pool=C,t.Profiler=x,t.StructuredData=M,t.TextAnalyzer=O});
7
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).CmpStr={})}(this,function(t){"use strict";class e extends Error{code;meta;when=(new Date).toISOString();constructor(t,e,r,s){super(e,void 0!==s?{cause:s}:void 0),this.name=this.constructor.name,this.code=t,this.meta=r,"function"==typeof Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}format(t=!1){const e=[`${this.name} [${this.code}]`,this.message];if(this.meta)for(const t in this.meta){e.push(JSON.stringify(this.meta));break}return e.join(" - ")+(t&&this.stack?`\nStack Trace:\n${this.stack}`:"")}toString(){return this.format(!1)}toJSON(t=!1){return{name:this.name,code:this.code,message:this.message,meta:this.meta,when:this.when,cause:this.cause instanceof Error?{name:this.cause.name,message:this.cause.message,stack:t&&this.cause.stack}:this.cause}}}class r extends e{constructor(t,e,r){super("E_VALIDATION",t,e,r)}}class s extends e{constructor(t,e,r){super("E_NOT_FOUND",t,e,r)}}class n extends e{constructor(t,e,r){super("E_USAGE",t,e,r)}}class a extends e{constructor(t,e,r){super("E_INTERNAL",t,e,r)}}class i{static assert(t,e,r){if(!t)throw new n(e,r)}static rethrow(t,r,s){if(t instanceof e)throw t;throw new a(r,s,t)}static format(t){return t instanceof e?t.toString():t instanceof Error?`${t.name}: ${t.message}`:String(t)}static wrap(t,r,s){try{return t()}catch(t){if(t instanceof e)throw t;throw new a(r,s,t)}}static async wrapAsync(t,r,s){try{return await t()}catch(t){if(t instanceof e)throw t;throw new a(r,s,t)}}}var o=Object.freeze({__proto__:null,CmpStrError:e,CmpStrInternalError:a,CmpStrNotFoundError:s,CmpStrUsageError:n,CmpStrValidationError:r,ErrorUtil:i});class c{static BRACKET_PATTERN=/\[(\d+)]/g;static PATH_CACHE=new Map;static walk(t,e){let r=t;for(let t=0;t<e.length;t++){const s=e[t];if(null==r||!(s in r))return{exists:!1};r=r[s]}return{exists:!0,value:r}}static parse(t){const e=c.PATH_CACHE.get(t);if(e)return e;const r=t.replace(c.BRACKET_PATTERN,".$1").split(".").map(t=>{const e=Number(t);return Number.isInteger(e)&&String(e)===t?e:t});return c.PATH_CACHE.size>2e3&&c.PATH_CACHE.clear(),c.PATH_CACHE.set(t,r),r}static has(t,e){return c.walk(t,c.parse(e)).exists}static get(t,e,r){const s=c.walk(t,c.parse(e));return s.exists?s.value:r}static set(t,e,r){if(""===e)return r;const s=c.parse(e);i.assert(void 0===t||"object"==typeof t&&null!==t,`Cannot set property <${s[0]}> of <${JSON.stringify(t)}>`,{path:s[0],target:t});const n=t??("number"==typeof s[0]?[]:Object.create(null));let a=n;for(let t=0;t<s.length-1;t++){const e=s[t];let r=a[e];i.assert(null==r||"object"==typeof r,`Cannot set property <${s[t+1]}> of <${JSON.stringify(r)}>`,{path:s.slice(0,t+2),value:r}),null==r&&(r=a[e]="number"==typeof s[t+1]?[]:Object.create(null)),a=r}return a[s[s.length-1]]=r,n}static rmv(t,e,r=!1){const s=c.parse(e),n=(t,e=0)=>{const a=s[e];if(!t||"object"!=typeof t)return!1;if(e===s.length-1)return delete t[a];if(!n(t[a],e+1))return!1;if(!r){const e=t[a];let r=!0;if("object"==typeof e)if(Array.isArray(e)){for(let t=0;t<e.length;t++)if(null!=e[t]){r=!1;break}}else r=!1;r&&delete t[a]}return!0};return n(t),t}static merge(t=Object.create(null),e=Object.create(null),r=!1){const s=t??Object.create(null);for(const t in e){const n=e[t];if((r||void 0!==n)&&"__proto__"!==t&&"constructor"!==t)if(null===n||"object"!=typeof n||Array.isArray(n))s[t]=n;else{const e=s[t];s[t]=c.merge(null===e||"object"!=typeof e||Array.isArray(e)?Object.create(null):e,n,r)}}return s}}class l{a;b;options;entries=[];grouped=[];diffRun=!1;constructor(t,e,r={}){this.a=t,this.b=e,this.options={mode:"word",caseInsensitive:!1,contextLines:1,groupedLines:!0,expandLines:!1,showChangeMagnitude:!0,maxMagnitudeSymbols:5,lineBreak:"\n",...r},this.computeDiff()}text2lines(){const t=this.a.trim().split(/\r?\n/),e=this.b.trim().split(/\r?\n/);return{linesA:t,linesB:e,maxLen:Math.max(t.length,e.length)}}tokenize(t){switch(this.options.mode){case"line":return[t];case"word":return t.split(/\s+/)}}concat(t){return t.join("word"===this.options.mode?" ":"")}computeDiff(){if(this.diffRun)return;const{linesA:t,linesB:e,maxLen:r}=this.text2lines();for(let s=0;s<r;s++)this.lineDiff(t[s]||"",e[s]||"",s);this.findGroups(),this.diffRun=!0}lineDiff(t,e,r){const{mode:s,caseInsensitive:n}=this.options,a=Math.max(t.length,e.length);let i=t,o=e;n&&(i=t.toLowerCase(),o=e.toLowerCase());let c=[],l=0,h=0;switch(s){case"line":i!==o&&(c.push({posA:0,posB:0,del:t,ins:e,size:e.length-t.length}),l=t.length,h=e.length);break;case"word":c=this.preciseDiff(t,i,e,o);for(const t of c)l+=t.del.length,h+=t.ins.length}c.length&&this.entries.push({line:r,diffs:c,delSize:l,insSize:h,baseLen:a,totalSize:h-l,magnitude:this.magnitude(l,h,a)})}preciseDiff(t,e,r,s){const n=t=>t.reduce((e,r,s)=>(e.push(s?e[s-1]+t[s-1].length+1:0),e),[]),a=this.tokenize(t),i=this.tokenize(r),o=this.tokenize(e),c=this.tokenize(s),l=o.length,h=c.length,p=n(a),u=n(i),d=[];let g=0,m=0;for(;g<l&&m<h;)if(o[g]===c[m]){let t=1;for(;g+t<l&&m+t<h&&o[g+t]===c[m+t];)t++;d.push({ai:g,bi:m,len:t}),g+=t,m+=t}else{let t=!1;for(let e=1;e<=3&&!t;e++)g+e<l&&o[g+e]===c[m]?(d.push({ai:g+e,bi:m,len:1}),g+=e+1,m+=1,t=!0):m+e<h&&o[g]===c[m+e]&&(d.push({ai:g,bi:m+e,len:1}),g+=1,m+=e+1,t=!0);t||(g++,m++)}const f=[];let y=0,w=0;for(const t of d){if(y<t.ai||w<t.bi){const e=a.slice(y,t.ai),r=i.slice(w,t.bi);f.push({posA:p[y]??0,posB:u[w]??0,del:this.concat(e),ins:this.concat(r),size:r.join("").length-e.join("").length})}y=t.ai+t.len,w=t.bi+t.len}if(y<l||w<h){const t=a.slice(y),e=i.slice(w);f.push({posA:p[y]??0,posB:u[w]??0,del:this.concat(t),ins:this.concat(e),size:e.join("").length-t.join("").length})}return f.filter(t=>t.del.length>0||t.ins.length>0)}findGroups(){const{contextLines:t}=this.options,e=(t,e,r)=>{const[s,n,a,i]=["delSize","insSize","totalSize","baseLen"].map(e=>t.reduce((t,r)=>t+r[e],0));this.grouped.push({start:e,end:r,delSize:s,insSize:n,totalSize:a,line:t[0].line,entries:t,magnitude:this.magnitude(s,n,i)})};let r=[],s=0,n=0;for(const a of this.entries){const i=Math.max(0,a.line-t),o=a.line+t;!r.length||i<=n+1?(r.length||(s=i),n=Math.max(n,o),r.push(a)):(e(r,s,n),r=[a],s=i,n=o)}r.length&&e(r,s,n)}magnitude(t,e,r){const{maxMagnitudeSymbols:s}=this.options,n=t+e;if(0===n||0===r)return"";const a=Math.min(s,Math.max(Math.round(n/r*s),1)),i=Math.round(e/n*a),o=a-i;return"+".repeat(i)+"-".repeat(o)}output(t){const{mode:e,contextLines:r,groupedLines:s,expandLines:n,showChangeMagnitude:a,lineBreak:i}=this.options,{linesA:o,linesB:c,maxLen:l}=this.text2lines(),h=Math.max(4,l.toString().length),p=(e,r)=>t?`[${r}m${e}`:e,u=e=>t?`${e}`:`-[${e}]`,d=e=>t?`${e}`:`+[${e}]`,g=(t,e,r,s)=>{s&&m(s);for(let s=t;s<=e;s++)f(s,r??s);w.push("")},m=t=>{var e;w.push(`${" ".repeat(h)} ${e=`@@ -${t.line+1},${t.delSize} +${t.line+1},${t.insSize} @@`,p(e,"36")} ${a?(t=>p(t,"33"))(t.magnitude):""}`)},f=(t,e)=>{if(o[t]||c[t]){const s=this.entries.find(e=>e.line===t),n=(t+1).toString().padStart(h," ");s&&e===t?(w.push(`${n} ${r=`- ${y(o[t],s.diffs,"del")}`,p(r,"31")}`),w.push(`${" ".repeat(h)} ${(t=>p(t,"32"))(`+ ${y(c[t],s.diffs,"ins")}`)}`)):w.push(`${n} ${(t=>p(t,"90"))(o[t])}`)}var r},y=(t,r,s)=>{if(!r.length||"line"===e)return t;let n="",a=0;for(const e of r){const r="del"===s?e.posA:e.posB,i="del"===s?e.del:e.ins;i&&(r>a&&(n+=t.slice(a,r)),n+="del"===s?u(i):d(i),a=r+i.length)}return n+t.slice(a)};let w=[""];switch(!0){case n:g(0,l);break;case s:for(const t of this.grouped)g(t.start,t.end,void 0,t);break;default:for(const t of this.entries)g(t.line-r,t.line+r,t.line,t)}return w.join(i)}getStructuredDiff=()=>this.entries;getGroupedDiff=()=>this.grouped;getASCIIDiff=()=>this.output(!1);getCLIDiff=()=>this.output(!0)}class h{static IDENTITY=t=>t;static filters=new Map;static pipeline=new Map;static getPipeline(t,e=!1){return i.wrap(()=>{if(!e){const e=h.pipeline.get(t);if(e)return e}const r=h.filters.get(t);if(!r)return h.pipeline.set(t,h.IDENTITY),h.IDENTITY;const s=[];for(const t of r.values())t.active&&s.push(t);s.sort((t,e)=>t.priority-e.priority);const n=0===s.length?h.IDENTITY:t=>{let e=t;for(let t=0;t<s.length;t++)e=s[t].fn(e);return e};return h.pipeline.set(t,n),n},`Error compiling filter pipeline for hook <${t}>`,{hook:t})}static has(t,e){return!!h.filters.get(t)?.has(e)}static add(t,e,r,s={}){return i.wrap(()=>{const{priority:n=10,active:a=!0,overrideable:i=!0}=s,o=h.filters.get(t)??new Map,c=o.get(e);return!(c&&!c.overrideable||(c&&c.fn===r&&c.priority===n&&c.active===a||(o.set(e,{id:e,fn:r,priority:n,active:a,overrideable:i}),h.filters.set(t,o),h.getPipeline(t,!0)),0))},`Error adding filter <${e}> to hook <${t}>`,{hook:t,id:e,opt:s})}static remove(t,e){const r=h.filters.get(t);return!(!r||!r.delete(e)||(h.getPipeline(t,!0),0))}static pause(t,e){const r=h.filters.get(t);if(!r)return!1;const s=r.get(e);return!(!s||!s.active||(s.active=!1,h.getPipeline(t,!0),0))}static resume(t,e){const r=h.filters.get(t);if(!r)return!1;const s=r.get(e);return!(!s||s.active||(s.active=!0,h.getPipeline(t,!0),0))}static list(t,e=!1){const r=h.filters.get(t);if(!r)return[];const s=[];for(const t of r.values())e&&!t.active||s.push(t.id);return s}static apply(t,e){return i.wrap(()=>{const r=h.getPipeline(t);if("string"==typeof e)return r(e);const s=e,n=new Array(s.length);for(let t=0;t<s.length;t++)n[t]=r(s[t]);return n},`Error applying filters for hook <${t}>`,{hook:t,input:e})}static async applyAsync(t,e){return i.wrapAsync(async()=>{const r=h.getPipeline(t);if("string"==typeof e)return Promise.resolve(r(e));const s=e,n=new Array(s.length);for(let t=0;t<s.length;t++)n[t]=Promise.resolve(r(s[t]));return Promise.all(n)},`Error applying filters for hook <${t}>`,{hook:t,input:e})}static clear(t){h.clearPipeline(),t?h.filters.delete(t):h.filters.clear()}static clearPipeline(){h.pipeline.clear()}}class p{static FNV_PRIME=16777619;static HASH_OFFSET=2166136261;static fastFNV1a(t){const e=t.length,r=-4&e;let s=this.HASH_OFFSET,n=0;for(;n<r;n+=4)s^=t.charCodeAt(n)|t.charCodeAt(n+1)<<8|t.charCodeAt(n+2)<<16|t.charCodeAt(n+3)<<24,s=Math.imul(s,this.FNV_PRIME);for(;n<e;n++)s^=t.charCodeAt(n),s=Math.imul(s,this.FNV_PRIME);return s^=s>>>16,s*=2246822507,s^=s>>>13,s*=3266489909,s^=s>>>16,s>>>0}}class u{FIFO;maxSize;static MAX_LEN=2048;table=new Map;constructor(t=!0,e=1e4){this.FIFO=t,this.maxSize=e}key(t,e,r=!1){const s=e.length,n=new Array(s);for(let t=0;t<s;t++){const r=e[t];if(r.length>u.MAX_LEN)return!1;n[t]=p.fastFNV1a(r)}r&&n.sort((t,e)=>t-e);let a=t;for(let t=0;t<n.length;t++)a+="-"+n[t];return a}has(t){return this.table.has(t)}get(t){return this.table.get(t)}set(t,e,r=!0){if(!r&&this.table.has(t))return!1;if(!this.table.has(t)&&this.table.size>=this.maxSize){if(!this.FIFO)return!1;this.table.delete(this.table.keys().next().value)}return this.table.set(t,e),!0}delete(t){return this.table.delete(t)}clear(){this.table.clear()}size(){return this.table.size}}class d{static pipeline=new Map;static cache=new u;static REGEX={whitespace:/\s+/g,doubleChars:/(.)\1+/g,specialChars:/[^\p{L}\p{N}\s]/gu,nonLetters:/[^\p{L}]/gu,nonNumbers:/\p{N}/gu};static canonicalFlags(t){return Array.from(new Set(t)).sort().join("")}static getPipeline(t){return i.wrap(()=>{const e=d.pipeline.get(t);if(e)return e;const{REGEX:r}=d,s=[];for(let e=0;e<t.length;e++)switch(t[e]){case"d":s.push(t=>t.normalize("NFD"));break;case"i":s.push(t=>t.toLowerCase());break;case"k":s.push(t=>t.replace(r.nonLetters,""));break;case"n":s.push(t=>t.replace(r.nonNumbers,""));break;case"r":s.push(t=>t.replace(r.doubleChars,"$1"));break;case"s":s.push(t=>t.replace(r.specialChars,""));break;case"t":s.push(t=>t.trim());break;case"u":s.push(t=>t.normalize("NFC"));break;case"w":s.push(t=>t.replace(r.whitespace," "));break;case"x":s.push(t=>t.normalize("NFKC"))}const n=t=>{let e=t;for(let t=0;t<s.length;t++)e=s[t](e);return e};return d.pipeline.set(t,n),n},`Failed to create normalization pipeline for flags: ${t}`,{flags:t})}static normalize(t,e,r){return i.wrap(()=>{if(!e||"string"!=typeof e||!t)return t;e=r??this.canonicalFlags(e);const s=d.getPipeline(e),n=t=>{const r=d.cache.key(e,[t]);if(r&&d.cache.has(r))return d.cache.get(r);const n=s(t);return r&&d.cache.set(r,n),n};return Array.isArray(t)?t.map(n):n(t)},`Failed to normalize input with flags: ${e}`,{input:t,flags:e})}static async normalizeAsync(t,e){return await i.wrapAsync(async()=>e&&"string"==typeof e&&t?await(Array.isArray(t)?Promise.all(t.map(t=>d.normalize(t,e))):Promise.resolve(d.normalize(t,e))):t,`Failed to asynchronously normalize input with flags: ${e}`,{input:t,flags:e})}static clear(){d.pipeline.clear(),d.cache.clear()}}class g{maxSize;buffers=[];pointer=0;constructor(t){this.maxSize=t}acquire(t,e){return i.wrap(()=>{const r=this.buffers,s=r.length;for(let n=0;n<s;n++){const a=(this.pointer+n)%s,i=r[a],o=i.size;if(o>=t&&(e||o===t))return this.pointer=(a+1)%s,i}return null},`Failed to acquire buffer of size >= ${t} from pool`,{minSize:t,allowOversize:e})}release(t){i.wrap(()=>{const e=this.buffers;e.length<this.maxSize?e.push(t):(e[this.pointer]=t,this.pointer=(this.pointer+1)%this.maxSize)},"Failed to release buffer back to pool",{item:t})}clear(){this.buffers=[],this.pointer=0}}class m{static CONFIG={int32:{type:"int32",maxSize:64,maxItemSize:2048,allowOversize:!0},"arr[]":{type:"arr[]",maxSize:4,maxItemSize:1024,allowOversize:!1},"number[]":{type:"number[]",maxSize:16,maxItemSize:1024,allowOversize:!1},"string[]":{type:"string[]",maxSize:2,maxItemSize:1024,allowOversize:!1},set:{type:"set",maxSize:8,maxItemSize:0,allowOversize:!1},map:{type:"map",maxSize:8,maxItemSize:0,allowOversize:!1}};static POOLS={int32:new g(64),"arr[]":new g(4),"number[]":new g(16),"string[]":new g(2),set:new g(8),map:new g(8)};static allocate(t,e){switch(t){case"int32":return new Int32Array(e);case"arr[]":case"string[]":return new Array(e);case"number[]":return new Float64Array(e);case"set":return new Set;case"map":return new Map}}static acquire(t,e){const r=this.CONFIG[t];if(!r)throw new n(`Unsupported pool type <${t}>`,{type:t});if(e>r.maxItemSize)return this.allocate(t,e);const s=this.POOLS[t].acquire(e,r.allowOversize);return s?"int32"===t?s.buffer.subarray(0,e):s.buffer:this.allocate(t,e)}static acquireMany(t,e){const r=new Array(e.length);for(let s=0;s<e.length;s++)r[s]=this.acquire(t,e[s]);return r}static release(t,e,r){const s=this.CONFIG[t];if(!s)throw new n(`Unsupported pool type <${t}>`,{type:t});r<=s.maxItemSize&&this.POOLS[t].release({buffer:e,size:r})}}class f{active;static ENV;static instance;nowFn;memFn;store=[];last;totalTime=0;totalMem=0;static detectEnv(){"undefined"!=typeof process&&process.versions?.node?f.ENV="nodejs":"undefined"!=typeof performance?f.ENV="browser":f.ENV="unknown"}static getInstance(t){return f.ENV||f.detectEnv(),f.instance||=new f(t)}constructor(t=!1){switch(this.active=t,f.ENV){case"nodejs":this.nowFn=()=>1e-6*Number(process.hrtime.bigint()),this.memFn=()=>process.memoryUsage().heapUsed;break;case"browser":this.nowFn=()=>performance.now(),this.memFn=()=>performance.memory?.usedJSHeapSize??0;break;default:this.nowFn=()=>Date.now(),this.memFn=()=>0}}storeRes(t){this.store.push(this.last=t),this.totalTime+=t.time,this.totalMem+=t.mem}enable(){this.active=!0}disable(){this.active=!1}clear(){this.store.length=0,this.last=void 0,this.totalTime=0,this.totalMem=0}run(t,e={}){if(!this.active)return t();const r=this.nowFn(),s=this.memFn(),n=t(),a=this.nowFn()-r,i=this.memFn()-s;return this.storeRes({time:a,mem:i,res:n,meta:e}),n}async runAsync(t,e={}){if(!this.active)return t();const r=this.nowFn(),s=this.memFn(),n=await t(),a=this.nowFn()-r,i=this.memFn()-s;return this.storeRes({time:a,mem:i,res:n,meta:e}),n}getAll(){return[...this.store]}getLast(){return this.last}getTotal(){return{time:this.totalTime,mem:this.totalMem}}services=Object.freeze({enable:this.enable.bind(this),disable:this.disable.bind(this),clear:this.clear.bind(this),report:this.getAll.bind(this),last:this.getLast.bind(this),total:this.getTotal.bind(this)})}const y=Object.create(null),w=Object.create(null);function b(t,e){i.assert(!(t in y||t in w),`Registry <${t}> already exists / overwriting is forbidden`,{registry:t});const r=Object.create(null),n=Object.freeze({add(s,n,a=!1){i.assert("string"==typeof s&&s.length>0,"Class name must be a non-empty string",{registry:t,name:s}),i.assert("function"==typeof n,"Class must be a constructor function",{registry:t,class:n}),i.assert(n.prototype instanceof e,`Class must extend <${t}>`,{registry:t,class:n}),i.assert(a||!(s in r),`Class <${s}> already exists / use <update=true> to overwrite`,{registry:t,name:s}),r[s]=n},remove(t){delete r[t]},has:t=>t in r,list:()=>Object.keys(r),get:e=>(i.assert("string"==typeof e&&e.length>0,"Class name must be a non-empty string",{registry:t,name:e}),i.assert(e in r,`Class <${e}> not registered for <${t}>`,{registry:t,name:e}),r[e])});return y[t]=n,w[t]=(e,...r)=>function(t,e,...r){const n=function(t,e){if(!(t in y))throw new s(`Registry <${t}> does not exist`,{registry:t});return"string"==typeof e?y[t].get(e):e}(t,e);return i.wrap(()=>new n(...r),`Failed to create instance of class <${n.name??e}> from registry <${t}>`,{registry:t,class:e,args:r})}(t,e,...r),n}const A=f.getInstance();class v{static cache=new u;metric;a;b;origA=[];origB=[];options;optKey;symmetric;results;static clear(){this.cache.clear()}static swap(t,e,r,s){return r>s?[e,t,s,r]:[t,e,r,s]}static clamp(t){return Math.max(0,Math.min(1,t))}constructor(t,e,r,s={},n=!1){this.metric=t,this.a=Array.isArray(e)?e:[e],this.b=Array.isArray(r)?r:[r],i.assert(this.a.length>0&&this.b.length>0,"Inputs <a> and <b> must not be empty",{a:this.a,b:this.b}),this.options=s,this.optKey=p.fastFNV1a(JSON.stringify(s,Object.keys(s).sort())).toString(),this.symmetric=n}preCompute(t,e,r,s){return t===e?{res:1}:0==r||0==s||r<2&&s<2?{res:0}:void 0}compute(t,e,r,s,n){throw new a("Method compute() must be overridden in a subclass")}runSingle(t,e){return i.wrap(()=>{let r=String(this.a[t]),s=r,n=String(this.b[e]),a=n,i=s.length,o=a.length,c=this.preCompute(s,a,i,o);return c||(c=A.run(()=>{this.symmetric&&([s,a,i,o]=v.swap(s,a,i,o));let t=v.cache.key(this.metric,[s,a],this.symmetric);return t&&(t+=this.optKey),v.cache.get(t||"")??(()=>{const e=i>o?i:o,r=this.compute(s,a,i,o,e);return t&&v.cache.set(t,r),r})()})),{metric:this.metric,a:this.origA.length>t?this.origA[t]:r,b:this.origB.length>e?this.origB[e]:n,...c}},`Failed to compute metric for inputs at indices a[${t}] and b[${e}]`,{i:t,j:e})}async runSingleAsync(t,e){return Promise.resolve(this.runSingle(t,e))}runBatch(){const t=[];for(let e=0;e<this.a.length;e++)for(let r=0;r<this.b.length;r++)t.push(this.runSingle(e,r));this.results=t}async runBatchAsync(){const t=[];for(let e=0;e<this.a.length;e++)for(let r=0;r<this.b.length;r++)t.push(this.runSingleAsync(e,r));this.results=await Promise.all(t)}runPairwise(){const t=[];for(let e=0;e<this.a.length;e++)t.push(this.runSingle(e,e));this.results=t}async runPairwiseAsync(){const t=[];for(let e=0;e<this.a.length;e++)t.push(this.runSingleAsync(e,e));this.results=await Promise.all(t)}setOriginal(t,e){return t&&(this.origA=Array.isArray(t)?t:[t]),e&&(this.origB=Array.isArray(e)?e:[e]),this}isBatch(){return this.a.length>1||this.b.length>1}isSingle(){return!this.isBatch()}isPairwise(t=!1){return!(!this.isBatch()||this.a.length!==this.b.length)||!t&&(()=>{throw new n("Mode <pairwise> requires arrays of equal length",{a:this.a,b:this.b})})()}isSymmetrical(){return this.symmetric}whichMode(t){return t??this.options.mode??"default"}clear(){this.results=void 0}run(t,e=!0){switch(e&&this.clear(),this.whichMode(t)){case"default":if(this.isSingle()){this.results=this.runSingle(0,0);break}case"batch":this.runBatch();break;case"single":this.results=this.runSingle(0,0);break;case"pairwise":this.isPairwise()&&this.runPairwise();break;default:throw new a(`Unsupported mode <${t}>`)}}async runAsync(t,e=!0){switch(e&&this.clear(),this.whichMode(t)){case"default":if(this.isSingle()){this.results=await this.runSingleAsync(0,0);break}case"batch":await this.runBatchAsync();break;case"single":this.results=await this.runSingleAsync(0,0);break;case"pairwise":this.isPairwise()&&await this.runPairwiseAsync();break;default:throw new a(`Unsupported async mode <${t}>`)}}getMetricName(){return this.metric}getResults(){return i.assert(void 0!==this.results,"run() must be called before getResults()"),this.results}}const S=b("metric",v);S.add("cosine",class extends v{constructor(t,e,r={}){super("cosine",t,e,r,!0)}_termFreq(t,e){const r=t.split(e),s=m.acquire("map",r.length);for(const t of r)s.set(t,(s.get(t)||0)+1);return s}compute(t,e){const{delimiter:r=" "}=this.options,s=this._termFreq(t,r),n=this._termFreq(e,r);try{let t=0,e=0,r=0;for(const[r,a]of s)t+=a*(n.get(r)||0),e+=a*a;for(const t of n.values())r+=t*t;return e=Math.sqrt(e),r=Math.sqrt(r),{res:e&&r?v.clamp(t/(e*r)):0,raw:{dotProduct:t,magnitudeA:e,magnitudeB:r}}}finally{m.release("map",s,s.size),m.release("map",n,n.size)}}}),S.add("damerau",class extends v{constructor(t,e,r={}){super("damerau",t,e,r,!0)}compute(t,e,r,s,n){const a=r+1,[i,o,c]=m.acquireMany("int32",[a,a,a]);try{for(let t=0;t<=r;t++)o[t]=t;for(let n=1;n<=s;n++){c[0]=n;const s=e.charCodeAt(n-1);for(let a=1;a<=r;a++){const r=t.charCodeAt(a-1),l=r===s?0:1;let h=Math.min(c[a-1]+1,o[a]+1,o[a-1]+l);a>1&&n>1&&r===e.charCodeAt(n-2)&&s===t.charCodeAt(a-2)&&(h=Math.min(h,i[a-2]+l)),c[a]=h}i.set(o),o.set(c)}const a=o[r];return{res:0===n?1:v.clamp(1-a/n),raw:{dist:a,maxLen:n}}}finally{m.release("int32",i,a),m.release("int32",o,a),m.release("int32",c,a)}}}),S.add("dice",class extends v{constructor(t,e,r={}){super("dice",t,e,r,!0)}_bigrams(t){const e=t.length-1,r=m.acquire("set",e);for(let s=0;s<e;s++)r.add(t.substring(s,s+2));return r}compute(t,e){const r=this._bigrams(t),s=this._bigrams(e),n=r.size,a=s.size;try{let t=0;for(const e of r)s.has(e)&&t++;const e=n+a;return{res:0===e?1:v.clamp(2*t/e),raw:{intersection:t,size:e}}}finally{m.release("set",r,n),m.release("set",s,a)}}}),S.add("hamming",class extends v{constructor(t,e,r={}){super("hamming",t,e,r,!0)}compute(t,e,r,s,a){if(r!==s){if(void 0===this.options.pad)throw new n(`Strings must be of equal length for Hamming Distance, a=${r} and b=${s} given, use option.pad for automatic adjustment`,{a:r,b:s});r<a&&(t=t.padEnd(a,this.options.pad)),s<a&&(e=e.padEnd(a,this.options.pad)),r=s=a}let i=0;for(let s=0;s<r;s++)t[s]!==e[s]&&i++;return{res:0===r?1:v.clamp(1-i/r),raw:{dist:i}}}}),S.add("jaccard",class extends v{constructor(t,e,r={}){super("jaccard",t,e,r,!0)}compute(t,e,r,s){const[n,a]=m.acquireMany("set",[r,s]);try{for(const e of t)n.add(e);for(const t of e)a.add(t);let r=0;for(const t of n)a.has(t)&&r++;const s=n.size+a.size-r;return{res:0===s?1:v.clamp(r/s),raw:{intersection:r,union:s}}}finally{m.release("set",n,r),m.release("set",a,s)}}}),S.add("jaroWinkler",class extends v{constructor(t,e,r={}){super("jaroWinkler",t,e,r,!0)}compute(t,e,r,s){const[n,a]=m.acquireMany("int32",[r,s]);try{for(let t=0;t<r;t++)n[t]=0;for(let t=0;t<s;t++)a[t]=0;const i=Math.max(0,Math.floor(s/2)-1);let o=0;for(let c=0;c<r;c++){const r=Math.max(0,c-i),l=Math.min(c+i+1,s);for(let s=r;s<l;s++)if(!a[s]&&t[c]===e[s]){n[c]=1,a[s]=1,o++;break}}let c=0,l=0,h=0,p=0;if(o>0){let i=0;for(let s=0;s<r;s++)if(n[s]){for(;!a[i];)i++;t[s]!==e[i]&&c++,i++}c/=2,l=(o/r+o/s+(o-c)/o)/3;for(let n=0;n<Math.min(4,r,s)&&t[n]===e[n];n++)h++;p=l+.1*h*(1-l)}return{res:v.clamp(p),raw:{matchWindow:i,matches:o,transpos:c,jaro:l,prefix:h}}}finally{m.release("int32",n,r),m.release("int32",a,s)}}}),S.add("lcs",class extends v{constructor(t,e,r={}){super("lcs",t,e,r,!0)}compute(t,e,r,s,n){const a=r+1,[i,o]=m.acquireMany("int32",[a,a]);try{for(let t=0;t<=r;t++)i[t]=0;for(let n=1;n<=s;n++){o[0]=0;const s=e.charCodeAt(n-1);for(let e=1;e<=r;e++)t.charCodeAt(e-1)===s?o[e]=i[e-1]+1:o[e]=Math.max(i[e],o[e-1]);i.set(o)}const a=i[r];return{res:0===n?1:v.clamp(a/n),raw:{lcs:a,maxLen:n}}}finally{m.release("int32",i,a),m.release("int32",o,a)}}}),S.add("levenshtein",class extends v{constructor(t,e,r={}){super("levenshtein",t,e,r,!0)}compute(t,e,r,s,n){const a=r+1,[i,o]=m.acquireMany("int32",[a,a]);try{for(let t=0;t<=r;t++)i[t]=t;for(let n=1;n<=s;n++){o[0]=n;const s=e.charCodeAt(n-1);for(let e=1;e<=r;e++){const r=t.charCodeAt(e-1)===s?0:1;o[e]=Math.min(o[e-1]+1,i[e]+1,i[e-1]+r)}i.set(o)}const a=i[r];return{res:0===n?1:v.clamp(1-a/n),raw:{dist:a,maxLen:n}}}finally{m.release("int32",i,a),m.release("int32",o,a)}}}),S.add("needlemanWunsch",class extends v{constructor(t,e,r={}){super("needlemanWunsch",t,e,r,!0)}compute(t,e,r,s,n){const{match:a=1,mismatch:i=-1,gap:o=-1}=this.options,c=r+1,[l,h]=m.acquireMany("int32",[c,c]);try{l[0]=0;for(let t=1;t<=r;t++)l[t]=l[t-1]+o;for(let n=1;n<=s;n++){h[0]=l[0]+o;const s=e.charCodeAt(n-1);for(let e=1;e<=r;e++){const r=t.charCodeAt(e-1)===s?a:i;h[e]=Math.max(l[e-1]+r,l[e]+o,h[e-1]+o)}l.set(h)}const c=l[r],p=n*a;return{res:0===p?0:v.clamp(c/p),raw:{score:c,denum:p}}}finally{m.release("int32",l,c),m.release("int32",h,c)}}}),S.add("qGram",class extends v{constructor(t,e,r={}){super("qGram",t,e,r,!0)}_qGrams(t,e){const r=Math.max(0,t.length-e+1),s=m.acquire("set",r);for(let n=0;n<r;n++)s.add(t.slice(n,n+e));return s}compute(t,e){const{q:r=2}=this.options,s=this._qGrams(t,r),n=this._qGrams(e,r),a=s.size,i=n.size;try{let t=0;for(const e of s)n.has(e)&&t++;const e=Math.max(a,i);return{res:0===e?1:v.clamp(t/e),raw:{intersection:t,size:e}}}finally{m.release("set",s,a),m.release("set",n,i)}}}),S.add("smithWaterman",class extends v{constructor(t,e,r={}){super("smithWaterman",t,e,r,!0)}compute(t,e,r,s){const{match:n=2,mismatch:a=-1,gap:i=-2}=this.options,o=r+1,[c,l]=m.acquireMany("int32",[o,o]);let h=0;try{for(let t=0;t<=r;t++)c[t]=0;for(let o=1;o<=s;o++){l[0]=0;const s=e.charCodeAt(o-1);for(let e=1;e<=r;e++){const r=t.charCodeAt(e-1)===s?n:a;l[e]=Math.max(0,c[e-1]+r,c[e]+i,l[e-1]+i),l[e]>h&&(h=l[e])}c.set(l)}const o=Math.min(r*n,s*n);return{res:0===o?0:v.clamp(h/o),raw:{score:h,denum:o}}}finally{m.release("int32",c,o),m.release("int32",l,o)}}});const x=f.getInstance();class O{static cache=new u;static default;algo;options;optKey;map;ignoreSet;static clear(){this.cache.clear()}constructor(t,e={}){const r=this.constructor.default??{},n=e.map??r.map;if(!n)throw new s("No mapping specified for phonetic algorithm",{algo:t});const a=C.get(t,n);if(void 0===a)throw new s(`Requested mapping <${n}> is not declared`,{algo:t,mapId:n});this.options=c.merge(c.merge(r,a.options??{}),e),this.optKey=p.fastFNV1a(JSON.stringify(this.options,Object.keys(this.options).sort())).toString(),this.algo=t,this.map=a,this.ignoreSet=new Set(a.ignore??[])}applyPattern(t){const{patterns:e=[]}=this.map;if(!e.length)return t;for(const{pattern:r,replace:s,all:n=!1}of e)t=n?t.replaceAll(r,s):t.replace(r,s);return t}applyRules(t,e,r,s){const{ruleset:n=[]}=this.map;if(!n.length)return;const a=r[e-1]||"",i=r[e-2]||"",o=r[e+1]||"",c=r[e+2]||"",l=r.join("");for(const h of n)if((!h.char||h.char===t)&&("start"!==h.position||0===e)&&("middle"!==h.position||0!==e&&e!==s-1)&&("end"!==h.position||e===s-1)&&(!h.prev||h.prev.includes(a))&&(!h.prevNot||!h.prevNot.includes(a))&&(!h.prev2||h.prev2.includes(i))&&(!h.prev2Not||!h.prev2Not.includes(i))&&(!h.next||h.next.includes(o))&&(!h.nextNot||!h.nextNot.includes(o))&&(!h.next2||h.next2.includes(c))&&(!h.next2Not||!h.next2Not.includes(c))&&(!h.leading||h.leading.includes(l.slice(0,h.leading.length)))&&(!h.trailing||h.trailing.includes(l.slice(-h.trailing.length)))&&(!h.match||h.match.every((t,s)=>r[e+s]===t)))return h.code}encode(t){const{map:e={}}=this.map;t=this.applyPattern(t);const r=this.word2Chars(t),s=r.length;let n="",a=null;for(let t=0;t<s;t++){const i=r[t];if(this.ignoreSet.has(i))continue;const o=this.mapChar(i,t,r,s,a,e);if(void 0!==o&&(n+=o,a=o,this.exitEarly(n,t)))break}return this.adjustCode(n,r)}mapChar(t,e,r,s,n,a){const{dedupe:i=!0,fallback:o}=this.options,c=this.applyRules(t,e,r,s)??a[t]??o;return i&&c===n?void 0:c}equalLen(t){const{length:e=-1,pad:r="0"}=this.options;return-1===e?t:(t+r.repeat(e)).slice(0,e)}word2Chars(t){return Array.from(t.toLowerCase())}exitEarly(t,e){const{length:r=-1}=this.options;return r>0&&t.length>=r}adjustCode(t,e){return t}loop(t){return i.wrap(()=>{const e=[];for(const r of t){let t=O.cache.key(this.algo,[r]);t&&(t+=this.optKey);const s=O.cache.get(t||"")??(()=>{const e=this.encode(r);return t&&O.cache.set(t,e),e})();s&&s.length&&e.push(this.equalLen(s))}return e},"Failed to generate phonetic index",{algo:this.algo,words:t})}async loopAsync(t){return i.wrapAsync(async()=>{const e=[];for(const r of t){const t=O.cache.key(this.algo,[r])+this.optKey,s=await Promise.resolve(O.cache.get(t||"")??(()=>{const e=this.encode(r);return t&&O.cache.set(t,e),e})());s&&s.length&&e.push(this.equalLen(s))}return e},"Failed to generate phonetic index asynchronously",{algo:this.algo,words:t})}getAlgoName(){return this.algo}getIndex(t){const{delimiter:e=" "}=this.options;return x.run(()=>this.loop(t.split(e).filter(Boolean)).filter(Boolean))}async getIndexAsync(t){const{delimiter:e=" "}=this.options;return(await x.runAsync(async()=>await this.loopAsync(t.split(e).filter(Boolean)))).filter(Boolean)}}const k=b("phonetic",O),C=(()=>{const t=Object.create(null),e=e=>t[e]||=Object.create(null);return Object.freeze({add(t,r,s,n=!1){const a=e(t);i.assert(!(!r||r in a)||n,`Entry <${r}> already exists / use <update=true> to overwrite`,{algo:t,id:r}),a[r]=s},remove(t,r){delete e(t)[r]},has:(t,r)=>r in e(t),get:(t,r)=>e(t)[r],list:t=>Object.keys(e(t))})})();class E extends O{static REGEX={uppercase:/[^A-Z]/gi};static default={map:"en2",delimiter:" ",length:-1,pad:"",dedupe:!1};constructor(t={}){super("caverphone",t)}encode(t){return t=t.replace(E.REGEX.uppercase,"").toLowerCase(),super.encode(t)}mapChar=t=>t;adjustCode=t=>t.toUpperCase()}k.add("caverphone",E),C.add("caverphone","en1",{options:{length:6,pad:"1"},map:{},patterns:[{pattern:/^(c|r|t|en)ough/,replace:"$1ou2f"},{pattern:/^gn/,replace:"2n"},{pattern:/mb$/,replace:"m2"},{pattern:/cq/g,replace:"2q"},{pattern:/c(e|i|y)/g,replace:"s$1"},{pattern:/tch/g,replace:"2ch"},{pattern:/[cqx]/g,replace:"k"},{pattern:/v/g,replace:"f"},{pattern:/dg/g,replace:"2g"},{pattern:/ti(a|o)/g,replace:"si$1"},{pattern:/d/g,replace:"t"},{pattern:/ph/g,replace:"fh"},{pattern:/b/g,replace:"p"},{pattern:/sh/g,replace:"s2"},{pattern:/z/g,replace:"s"},{pattern:/^[aeiou]/,replace:"A"},{pattern:/[aeiou]/g,replace:"3"},{pattern:/3gh3/g,replace:"3kh3"},{pattern:/gh/g,replace:"22"},{pattern:/g/g,replace:"k"},{pattern:/s+/g,replace:"S"},{pattern:/t+/g,replace:"T"},{pattern:/p+/g,replace:"P"},{pattern:/k+/g,replace:"K"},{pattern:/f+/g,replace:"F"},{pattern:/m+/g,replace:"M"},{pattern:/n+/g,replace:"N"},{pattern:/j/g,replace:"y"},{pattern:/l3/g,replace:"L3"},{pattern:/r3/g,replace:"R3"},{pattern:/w3/g,replace:"W3"},{pattern:/y3/g,replace:"Y3"},{pattern:/ly/g,replace:"Ly"},{pattern:/ry/g,replace:"Ry"},{pattern:/wy/g,replace:"Wy"},{pattern:/wh3/g,replace:"Wh3"},{pattern:/why/g,replace:"Why"},{pattern:/^h/,replace:"A"},{pattern:/[hlrwy23]/g,replace:""}]}),C.add("caverphone","en2",{options:{length:10,pad:"1"},map:{},patterns:[{pattern:/e$/,replace:""},{pattern:/^(c|r|t|en|tr)ough/,replace:"$1ou2f"},{pattern:/^gn/,replace:"2n"},{pattern:/mb$/,replace:"m2"},{pattern:/cq/g,replace:"2q"},{pattern:/c(e|i|y)/g,replace:"s$1"},{pattern:/tch/g,replace:"2ch"},{pattern:/[cqx]/g,replace:"k"},{pattern:/v/g,replace:"f"},{pattern:/dg/g,replace:"2g"},{pattern:/ti(a|o)/g,replace:"si$1"},{pattern:/d/g,replace:"t"},{pattern:/ph/g,replace:"fh"},{pattern:/b/g,replace:"p"},{pattern:/sh/g,replace:"s2"},{pattern:/z/g,replace:"s"},{pattern:/^[aeiou]/,replace:"A"},{pattern:/[aeiou]/g,replace:"3"},{pattern:/j/g,replace:"y"},{pattern:/^y3/,replace:"Y3"},{pattern:/^y/,replace:"A"},{pattern:/y/g,replace:"3"},{pattern:/3gh3/g,replace:"3kh3"},{pattern:/gh/g,replace:"22"},{pattern:/g/g,replace:"k"},{pattern:/s+/g,replace:"S"},{pattern:/t+/g,replace:"T"},{pattern:/p+/g,replace:"P"},{pattern:/k+/g,replace:"K"},{pattern:/f+/g,replace:"F"},{pattern:/m+/g,replace:"M"},{pattern:/n+/g,replace:"N"},{pattern:/l3/g,replace:"L3"},{pattern:/r3/g,replace:"R3"},{pattern:/w3/g,replace:"W3"},{pattern:/wh3/g,replace:"Wh3"},{pattern:/[lrw]$/,replace:"3"},{pattern:/^h/,replace:"A"},{pattern:/3$/,replace:"A"},{pattern:/[hlrw23]/g,replace:""}]}),k.add("cologne",class extends O{static default={map:"default",delimiter:" ",length:-1,dedupe:!0};constructor(t={}){super("cologne",t)}adjustCode(t){return t.slice(0,1)+t.slice(1).replaceAll("0","")}}),C.add("cologne","default",{map:{a:"0","ä":"0",e:"0",i:"0",j:"0",o:"0","ö":"0",u:"0","ü":"0",y:"0",b:"1",p:"1",d:"2",t:"2",f:"3",v:"3",w:"3",g:"4",k:"4",q:"4",l:"5",m:"6",n:"6",r:"7",c:"8",s:"8","ß":"8",z:"8",x:"48"},ignore:["h"],ruleset:[{char:"p",next:["h"],code:"3"},{char:"c",position:"start",next:["a","h","k","l","o","q","r","u","x"],code:"4"},{char:"c",next:["a","h","k","o","q","u","x"],prevNot:["s","z"],code:"4"},{char:"d",next:["c","s","z"],code:"8"},{char:"t",next:["c","s","z"],code:"8"},{char:"x",prev:["c","k","q"],code:"8"}]});class z extends O{static REGEX={adjacent:/([A-BD-Z])\1+/gi,vowel:/[AEIOU]/g};static default={map:"en90",delimiter:" ",length:-1,pad:"",dedupe:!1};constructor(t={}){super("metaphone",t)}encode(t){return t=t.replace(z.REGEX.adjacent,(t,e)=>"C"===e?t:e),super.encode(t)}adjustCode(t){return t.slice(0,1)+t.slice(1).replace(z.REGEX.vowel,"")}}k.add("metaphone",z),C.add("metaphone","en90",{map:{a:"A",b:"B",c:"K",d:"T",e:"E",f:"F",g:"K",h:"H",i:"I",j:"J",k:"K",l:"L",m:"M",n:"N",o:"O",p:"P",q:"K",r:"R",s:"S",t:"T",u:"U",v:"F",w:"W",x:"KS",y:"Y",z:"S"},ruleset:[{char:"a",position:"start",next:["e"],code:""},{char:"g",position:"start",next:["n"],code:""},{char:"k",position:"start",next:["n"],code:""},{char:"p",position:"start",next:["n"],code:""},{char:"w",position:"start",next:["r"],code:""},{char:"b",position:"end",prev:["m"],code:""},{char:"c",next:["h"],prevNot:["s"],code:"X"},{char:"c",next:["i"],next2:["a"],code:"X"},{char:"c",next:["e","i","y"],code:"S"},{char:"d",next:["g"],next2:["e","i","y"],code:"J"},{char:"g",next:["h"],next2Not:["","a","e","i","o","u"],code:""},{char:"g",trailing:"n",code:""},{char:"g",trailing:"ned",code:""},{char:"g",next:["e","i","y"],prevNot:["g"],code:"J"},{char:"h",prev:["a","e","i","o","u"],nextNot:["a","e","i","o","u"],code:""},{char:"h",prev:["c","g","p","s","t"],code:""},{char:"k",prev:["c"],code:""},{char:"p",next:["h"],code:"F"},{char:"s",next:["h"],code:"X"},{char:"s",next:["i"],next2:["a","o"],code:"X"},{char:"t",next:["i"],next2:["a","o"],code:"X"},{char:"t",next:["h"],code:"0"},{char:"t",next:["c"],next2:["h"],code:""},{char:"w",nextNot:["a","e","i","o","u"],code:""},{char:"h",leading:"w",code:""},{char:"x",position:"start",code:"S"},{char:"y",nextNot:["a","e","i","o","u"],code:""}]}),k.add("soundex",class extends O{static default={map:"en",delimiter:" ",length:4,pad:"0",dedupe:!0};constructor(t={}){super("soundex",t)}adjustCode(t,e){return e[0].toUpperCase()+t.slice(1).replaceAll("0","")}}),C.add("soundex","en",{map:{a:"0",e:"0",h:"0",i:"0",o:"0",u:"0",w:"0",y:"0",b:"1",f:"1",p:"1",v:"1",c:"2",g:"2",j:"2",k:"2",q:"2",s:"2",x:"2",z:"2",d:"3",t:"3",l:"4",m:"5",n:"5",r:"6"}}),C.add("soundex","de",{map:{a:"0","ä":"0",e:"0",h:"0",i:"0",j:"0",o:"0","ö":"0",u:"0","ü":"0",y:"0",b:"1",f:"1",p:"1",v:"1",w:"1",c:"2",g:"2",k:"2",q:"2",s:"2","ß":"2",x:"2",z:"2",d:"3",t:"3",l:"4",m:"5",n:"5",r:"6"},ruleset:[{char:"c",next:["h"],code:"7"}]});class M{static ALLOWED_FLAGS=new Set(["d","u","x","w","t","r","s","k","n","i"]);static ALLOWED_OUTPUT=new Set(["orig","prep"]);static ALLOWED_MODES=new Set(["default","batch","single","pairwise"]);static ALLOWED_SORT=new Set(["asc","desc"]);static PROCESSORS={phonetic:t=>{t&&(M.validatePhoneticName(t.algo),M.validatePhoneticOptions(t.opt))}};static METRIC_OPT_MAP={mode:t=>M.validateMode(t),delimiter:t=>M.validateString(t,"opt.delimiter"),pad:t=>M.validateString(t,"opt.pad"),q:t=>M.validateNumber(t,"opt.q"),match:t=>M.validateNumber(t,"opt.match"),mismatch:t=>M.validateNumber(t,"opt.mismatch"),gap:t=>M.validateNumber(t,"opt.gap")};static PHONETIC_OPT_MAP={map:t=>M.validateString(t,"processors.phonetic.opt.map"),delimiter:t=>M.validateString(t,"processors.phonetic.opt.delimiter"),length:t=>M.validateNumber(t,"processors.phonetic.opt.length"),pad:t=>M.validateString(t,"processors.phonetic.opt.pad"),dedupe:t=>M.validateBoolean(t,"processors.phonetic.opt.dedupe"),fallback:t=>M.validateString(t,"processors.phonetic.opt.fallback")};static CMPSTR_OPT_MAP={raw:t=>M.validateBoolean(t,"raw"),removeZero:t=>M.validateBoolean(t,"removeZero"),safeEmpty:t=>M.validateBoolean(t,"safeEmpty"),flags:t=>M.validateFlags(t),metric:t=>M.validateMetricName(t),output:t=>M.validateOutput(t),opt:t=>M.validateMetricOptions(t),processors:t=>M.validateProcessors(t),sort:t=>M.validateSort(t,"sort"),objectsOnly:t=>M.validateBoolean(t,"objectsOnly")};static set2string(t){return Array.from(t).join(" | ")}static validateType(t,e,s){if(void 0!==t&&(typeof t!==s||"number"===s&&Number.isNaN(t)))throw new r(`Invalid option <${e}>: expected ${s}`,{name:e,value:t})}static validateEnum(t,e,s){if(void 0!==t&&("string"!=typeof t||!s.has(t)))throw new r(`Invalid option <${e}>: expected ${M.set2string(s)}`,{name:e,value:t})}static validateMap(t,e){if(t)for(const s in t){const n=e[s];if(!n)throw new r(`Invalid option <${s}>`,{option:s,value:e[s]});n(t[s])}}static validateRegistryName(t,e,s,n,a){if(void 0!==t){if("string"!=typeof t||0===t.length)throw new r(`Invalid option <${e}>: expected non-empty string`,{name:e,value:t});if(!n(t))throw new r(`${s} <${t}> is not registered`,{name:e,value:t,available:a()})}}static validateBoolean(t,e){M.validateType(t,e,"boolean")}static validateNumber(t,e){M.validateType(t,e,"number")}static validateString(t,e){M.validateType(t,e,"string")}static validateFlags(t){if(void 0!==t){if("string"!=typeof t)throw new r("Invalid option <flags>: expected string",{flags:t});for(let e=0;e<t.length;e++){const s=t[e];if(!M.ALLOWED_FLAGS.has(s))throw new r(`Invalid normalization flag <${s}> in <flags>: expected ${M.set2string(M.ALLOWED_FLAGS)}`,{flags:t,invalid:s})}}}static validateOutput(t){M.validateEnum(t,"output",M.ALLOWED_OUTPUT)}static validateMode(t){M.validateEnum(t,"mode",M.ALLOWED_MODES)}static validateSort(t,e){void 0!==t&&"boolean"!=typeof t&&M.validateEnum(t,e,M.ALLOWED_SORT)}static validateMetricName(t){M.validateRegistryName(t,"metric","Comparison metric",S.has,S.list)}static validatePhoneticName(t){M.validateRegistryName(t,"phonetic","Phonetic algorithm",k.has,k.list)}static validateMetricOptions(t){M.validateMap(t,M.METRIC_OPT_MAP)}static validatePhoneticOptions(t){M.validateMap(t,M.PHONETIC_OPT_MAP)}static validateProcessors(t){if(t)for(const e in t){const s=M.PROCESSORS[e];if(!s)throw new r(`Invalid processor type <${e}> in <processors>: expected ${Object.keys(M.PROCESSORS).join(" | ")}`,{processors:t,invalid:e});s(t[e])}}static validateOptions(t){M.validateMap(t,M.CMPSTR_OPT_MAP)}}class P{data;key;static SORT_ASC=(t,e)=>t.res-e.res;static SORT_DESC=(t,e)=>e.res-t.res;static create(t,e){return new P(t,e)}constructor(t,e){this.data=t,this.key=e}extractFrom(t,e){const r=t.length,s=new Array(r);for(let n=0;n<r;n++){const r=t[n][e];s[n]=null!=r?String(r):""}return s}extract(){return this.extractFrom(this.data,this.key)}isMetricResult(t){return"object"==typeof t&&null!==t&&"a"in t&&"b"in t&&"res"in t}isCmpStrResult(t){return"object"==typeof t&&null!==t&&"source"in t&&"target"in t&&"match"in t}normalizeResults(t){if(!Array.isArray(t)||0===t.length)return[];const e=t[0];let s=new Array(t.length);if(this.isMetricResult(e)){const e=t;for(let t=0;t<e.length;t++)s[t]={...e[t],__idx:t}}else{if(!this.isCmpStrResult(e))throw new r("Unsupported result format for StructuredData normalization.");{const e=t;for(let t=0;t<e.length;t++){const r=e[t];s[t]={metric:"unknown",a:r.source,b:r.target,res:r.match,raw:r.raw,__idx:t}}}}return s}rebuild(t,e,r,s,n){const a=r.length,i=t.length,o=m.acquire("map",a),c=m.acquire("map",i),l=new Array(i);o.clear(),c.clear();try{for(let t=0;t<a;t++){const e=r[t];let s=o.get(e);s||(s=[],o.set(e,s)),s.push(t)}let h=0;for(let a=0;a<i;a++){const i=t[a];if(s&&0===i.res)continue;const p=i.b||"",u=o.get(p);let d;if(u&&u.length>0){const t=c.get(p)??0;c.set(p,t+1),d=u[t%u.length]}else d=i.__idx??a;if(d<0||d>=e.length)continue;const g=e[d],m=r[d]||p;l[h++]=n?g:{obj:g,key:this.key,result:{source:i.a,target:m,match:i.res},...i.raw?{raw:i.raw}:null}}return l.length=h,l}finally{m.release("map",o,a),m.release("map",c,i)}}sort(t,e){return!e||t.length<=1?t:t.sort("asc"===e?P.SORT_ASC:P.SORT_DESC)}finalizeLookup(t,e,r){return this.rebuild(this.sort(this.normalizeResults(t),r?.sort),this.data,e,r?.removeZero,r?.objectsOnly)}performLookup(t,e,r){return i.wrap(()=>this.finalizeLookup(t(),e,r),"StructuredData lookup failed",{key:this.key})}async performLookupAsync(t,e,r){return await i.wrapAsync(async()=>this.finalizeLookup(await t(),e,r),"StructuredData async lookup failed",{key:this.key})}lookup(t,e,r){const s=this.extract();try{return this.performLookup(()=>t(e,s,r),s,r)}finally{m.release("string[]",s,s.length)}}async lookupAsync(t,e,r){const s=this.extract();try{return await this.performLookupAsync(()=>t(e,s,r),s,r)}finally{m.release("string[]",s,s.length)}}lookupPairs(t,e,r,s){const n=this.extract(),a=this.extractFrom(e,r);try{return this.performLookup(()=>t(n,a,s),n,s)}finally{m.release("string[]",n,n.length),m.release("string[]",a,a.length)}}async lookupPairsAsync(t,e,r,s){const n=this.extract(),a=this.extractFrom(e,r);try{return await this.performLookupAsync(()=>t(n,a,s),n,s)}finally{m.release("string[]",n,n.length),m.release("string[]",a,a.length)}}}class N{static REGEX={number:/\d/,sentence:/(?<=[.!?])\s+/,word:/\p{L}+/gu,nonWord:/[^\p{L}]/gu,vowelGroup:/[aeiouy]+/g,letter:/\p{L}/gu,ucLetter:/\p{Lu}/gu};text;words=[];sentences=[];charFrequency=new Map;wordHistogram=new Map;syllableCache=new Map;syllableStats;constructor(t){this.text=t.trim(),this.tokenize(),this.computeFrequencies()}tokenize(){let t;const e=this.text.toLowerCase();for(;null!==(t=N.REGEX.word.exec(e));)this.words.push(t[0]);this.sentences=this.text.split(N.REGEX.sentence).filter(Boolean)}computeFrequencies(){for(const t of this.text)this.charFrequency.set(t,(this.charFrequency.get(t)??0)+1);for(const t of this.words)this.wordHistogram.set(t,(this.wordHistogram.get(t)??0)+1)}estimateSyllables(t){const e=t.normalize("NFC").toLowerCase().replace(N.REGEX.nonWord,"");if(this.syllableCache.has(e))return this.syllableCache.get(e);const r=e.match(N.REGEX.vowelGroup),s=r?r.length:1;return this.syllableCache.set(e,s),s}computeSyllableStats(){return this.syllableStats||=(()=>{const t=this.words.map(t=>this.estimateSyllables(t)).sort((t,e)=>t-e),e=t.reduce((t,e)=>t+e,0),r=t.filter(t=>1===t).length,s=t.length?t.length%2==0?(t[t.length/2-1]+t[t.length/2])/2:t[Math.floor(t.length/2)]:0;return{total:e,mono:r,perWord:t,avg:t.length?e/t.length:0,median:s}})()}getLength=()=>this.text.length;getWordCount=()=>this.words.length;getSentenceCount=()=>this.sentences.length;getAvgWordLength(){return this.words.length?this.words.join("").length/this.words.length:0}getAvgSentenceLength(){return this.sentences.length?this.words.length/this.sentences.length:0}getWordHistogram(){return Object.fromEntries(this.wordHistogram)}getMostCommonWords(t=5){return[...this.wordHistogram.entries()].sort((t,e)=>e[1]-t[1]).slice(0,t).map(t=>t[0])}getHapaxLegomena(){return[...this.wordHistogram.entries()].filter(([,t])=>1===t).map(t=>t[0])}hasNumbers=()=>N.REGEX.number.test(this.text);getUpperCaseRatio(){const t=this.text.match(N.REGEX.letter)||[],e=this.text.match(N.REGEX.ucLetter)?.length||0;return t.length?e/t.length:0}getCharFrequency(){return Object.fromEntries(this.charFrequency)}getUnicodeCodepoints(){const t={};for(const[e,r]of this.charFrequency){const s=e.charCodeAt(0).toString(16).padStart(4,"0").toUpperCase();t[s]=(t[s]||0)+r}return t}getLongWordRatio(t=7){let e=0;for(const r of this.words)r.length>=t&&e++;return this.words.length?e/this.words.length:0}getShortWordRatio(t=3){let e=0;for(const r of this.words)r.length<=t&&e++;return this.words.length?e/this.words.length:0}getSyllablesCount(){return this.computeSyllableStats().total}getMonosyllabicWordCount(){return this.computeSyllableStats().mono}getMinSyllablesWordCount(t){return this.computeSyllableStats().perWord.filter(e=>e>=t).length}getMaxSyllablesWordCount(t){return this.computeSyllableStats().perWord.filter(e=>e<=t).length}getAvgSyllablesPerWord(){return this.computeSyllableStats().avg}getMedianSyllablesPerWord(){return this.computeSyllableStats().median}getHonoresR(){try{return 100*Math.log(this.words.length)/(1-this.getHapaxLegomena().length/(this.wordHistogram.size??1))}catch{return 0}}getReadingTime(t=200){return this.words.length/(t??1)}getReadabilityScore(t="flesch"){const e=this.words.length||1,r=e/(this.sentences.length||1),s=(this.getSyllablesCount()||1)/e;switch(t){case"flesch":return 206.835-1.015*r-84.6*s;case"fleschde":return 180-r-58.5*s;case"kincaid":return.39*r+11.8*s-15.59}}getLIXScore(){const t=this.words.length||1;return t/(this.sentences.length||1)+this.getLongWordRatio()*t/t*100}getWSTFScore(){const t=this.words.length||1,e=this.getMinSyllablesWordCount(3)/t*100,r=this.getAvgSentenceLength(),s=100*this.getLongWordRatio();return[.1935*e+.1672*r+.1297*s-this.getMonosyllabicWordCount()/t*100*.0327-.875,.2007*e+.1682*r+.1373*s-2.779,.2963*e+.1905*r-1.1144,.2744*e+.2656*r-1.693]}}const L=f.getInstance();class F{static filter={has:h.has,add:h.add,remove:h.remove,pause:h.pause,resume:h.resume,list:h.list,clear:h.clear};static metric={add:S.add,remove:S.remove,has:S.has,list:S.list};static phonetic={add:k.add,remove:k.remove,has:k.has,list:k.list,map:{add:C.add,remove:C.remove,has:C.has,list:C.list}};static profiler=L.services;static clearCache={normalizer:d.clear,filter:h.clearPipeline,metric:v.clear,phonetic:O.clear};static analyze=t=>new N(t);static diff=(t,e,r)=>new l(t,e,r);static create(t){return new F(t)}options=Object.create(null);constructor(t){t&&("string"==typeof t?this.setSerializedOptions(t):this.setOptions(t))}assert(t,e){switch(t){default:throw new a(`Cmpstr condition <${t}> unknown`);case"metric":M.validateMetricName(e);break;case"phonetic":M.validatePhoneticName(e)}}assertMany(...t){for(const[e,r]of t)this.assert(e,r)}resolveOptions(t){const e=c.merge({...this.options??Object.create(null)},t);return M.validateOptions(e),e}normalize(t,e){return d.normalize(t,e??this.options.flags??"")}filter(t,e){return h.apply(e,t)}prepare(t,e){const{flags:r,processors:s}=e??this.options;return r?.length&&(t=this.normalize(t,r)),t=this.filter(t,"input"),s?.phonetic&&(t=this.index(t,s.phonetic)),t}postProcess(t,e){return Array.isArray(t)&&e?.removeZero&&(t=t.filter(t=>t.res>0)),t}index(t,{algo:e,opt:r}){this.assert("phonetic",e);const s=w.phonetic(e,r),n=r?.delimiter??" ";return Array.isArray(t)?t.map(t=>s.getIndex(t).join(n)):s.getIndex(t).join(n)}structured(t,e){return P.create(t,e)}compute(t,e,r,s,n,a){const o=this.resolveOptions(r);return this.assert("metric",o.metric),i.wrap(()=>{const r=a?t:this.prepare(t,o),i=a?e:this.prepare(e,o);if(o.safeEmpty&&(Array.isArray(r)&&0===r.length||Array.isArray(i)&&0===i.length||""===r||""===i))return[];const c=w.metric(o.metric,r,i,o.opt);"prep"!==o.output&&c.setOriginal(t,e),c.run(s);const l=this.postProcess(c.getResults(),o);return this.output(l,n??o.raw)},`Failed to compute metric <${o.metric}> for the given inputs`,{a:t,b:e,options:r})}output(t,e){return i.wrap(()=>e??this.options.raw?t:Array.isArray(t)?t.map(t=>({source:t.a,target:t.b,match:t.res})):{source:t.a,target:t.b,match:t.res},"Failed to resolve output format for the metric result",{result:t,raw:e})}clone(){const t=Object.assign(Object.create(Object.getPrototypeOf(this)),this);return t.options=c.merge(Object.create(null),this.options),t}reset(){return this.options=Object.create(null),this}setOptions(t){return M.validateOptions(t),this.options=t,this}mergeOptions(t){return c.merge(this.options,t),M.validateOptions(this.options),this}setSerializedOptions(t){try{const e=JSON.parse(t);return M.validateOptions(e),this.options=e,this}catch(e){if(e instanceof SyntaxError)throw new r("Failed to parse serialized options, invalid JSON string",{opt:t,error:e instanceof Error?e.message:String(e)});throw e}}setOption(t,e){return c.set(this.options,t,e),M.validateOptions(this.options),this}rmvOption(t){return c.rmv(this.options,t),this}setRaw(t){return this.setOption("raw",t)}setMetric(t){return this.setOption("metric",t)}setFlags(t){return this.setOption("flags",t)}rmvFlags(){return this.rmvOption("flags")}setProcessors(t){return this.setOption("processors",t)}rmvProcessors(){return this.rmvOption("processors")}getOptions(){return this.options}getSerializedOptions(){return JSON.stringify(this.options)}getOption(t){return c.get(this.options,t)}test(t,e,r){return this.compute(t,e,r,"single")}compare(t,e,r){return this.compute(t,e,r,"single",!0).res}batchTest(t,e,r){return this.compute(t,e,r,"batch")}batchSorted(t,e,r="desc",s){return this.output(this.compute(t,e,s,"batch",!0).sort((t,e)=>"asc"===r?t.res-e.res:e.res-t.res),s?.raw??this.options.raw)}pairs(t,e,r){return this.compute(t,e,r,"pairwise")}match(t,e,r,s){return this.output(this.compute(t,e,s,"batch",!0).filter(t=>t.res>=r).sort((t,e)=>e.res-t.res),s?.raw??this.options.raw)}closest(t,e,r=1,s){return this.batchSorted(t,e,"desc",s).slice(0,r)}furthest(t,e,r=1,s){return this.batchSorted(t,e,"asc",s).slice(0,r)}search(t,e,r,s){const n=this.resolveOptions({flags:r,processors:s}),a=this.prepare(t,n),i=this.prepare(e,n),o=[];for(let t=0,r=i.length;t<r;t++)i[t].includes(a)&&o.push(e[t]);return o}matrix(t,e){const r=this.resolveOptions(e),s=this.prepare(t,r),n=s.length,a=Array.from({length:n},()=>new Array(n).fill(0));for(let t=0;t<n;t++)for(let e=t;e<n;e++)if(t===e)a[t][e]=1;else{const n=this.compute(s[t],s[e],r,"single",!0,!0).res;a[t][e]=n,a[e][t]=n}return a}phoneticIndex(t,e,r){const{algo:s,opt:n}=this.options.processors?.phonetic??{};return this.index(t,{algo:e??s,opt:r??n})}structuredLookup(t,e,r,s){return this.structured(e,r).lookup((t,e,r)=>this.batchTest(t,e,r),t,s)}structuredMatch(t,e,r,s,n){return this.structured(e,r).lookup((t,e,r)=>this.match(t,e,s,r),t,{...n,sort:"desc"})}structuredClosest(t,e,r,s=1,n){return this.structured(e,r).lookup((t,e,r)=>this.closest(t,e,s,r),t,{...n,sort:"desc"})}structuredFurthest(t,e,r,s=1,n){return this.structured(e,r).lookup((t,e,r)=>this.furthest(t,e,s,r),t,{...n,sort:"asc"})}structuredPairs(t,e,r,s,n){return this.structured(t,e).lookupPairs((t,e,r)=>this.pairs(t,e,r),r,s,n)}}class $ extends F{static create(t){return new $(t)}constructor(t){super(t)}async normalizeAsync(t,e){return d.normalizeAsync(t,e??this.options.flags??"")}async filterAsync(t,e){return h.applyAsync(e,t)}async prepareAsync(t,e){const{flags:r,processors:s}=e??this.options;return r?.length&&(t=await this.normalizeAsync(t,r)),t=await this.filterAsync(t,"input"),s?.phonetic&&(t=await this.indexAsync(t,s.phonetic)),t}async indexAsync(t,{algo:e,opt:r}){this.assert("phonetic",e);const s=w.phonetic(e,r),n=r?.delimiter??" ";return Array.isArray(t)?Promise.all(t.map(t=>s.getIndexAsync(t).then(t=>t.join(n)))):s.getIndexAsync(t).then(t=>t.join(n))}async computeAsync(t,e,r,s,n,a){const o=this.resolveOptions(r);return this.assert("metric",o.metric),i.wrapAsync(async()=>{const r=a?t:await this.prepareAsync(t,o),i=a?e:await this.prepareAsync(e,o);if(o.safeEmpty&&(Array.isArray(r)&&0===r.length||Array.isArray(i)&&0===i.length||""===r||""===i))return[];const c=w.metric(o.metric,r,i,o.opt);"prep"!==o.output&&c.setOriginal(t,e),await c.runAsync(s);const l=this.postProcess(c.getResults(),o);return this.output(l,n??o.raw)},`Failed to compute metric <${r?.metric??this.options.metric}> for the given inputs`,{a:t,b:e,opt:r})}async testAsync(t,e,r){return this.computeAsync(t,e,r,"single")}async compareAsync(t,e,r){return(await this.computeAsync(t,e,r,"single",!0)).res}async batchTestAsync(t,e,r){return this.computeAsync(t,e,r,"batch")}async batchSortedAsync(t,e,r="desc",s){const n=await this.computeAsync(t,e,s,"batch",!0);return this.output(n.sort((t,e)=>"asc"===r?t.res-e.res:e.res-t.res),s?.raw??this.options.raw)}async pairsAsync(t,e,r){return this.computeAsync(t,e,r,"pairwise")}async matchAsync(t,e,r,s){const n=await this.computeAsync(t,e,s,"batch",!0);return this.output(n.filter(t=>t.res>=r).sort((t,e)=>e.res-t.res),s?.raw??this.options.raw)}async closestAsync(t,e,r=1,s){return(await this.batchSortedAsync(t,e,"desc",s)).slice(0,r)}async furthestAsync(t,e,r=1,s){return(await this.batchSortedAsync(t,e,"asc",s)).slice(0,r)}async searchAsync(t,e,r,s){const n=this.resolveOptions({flags:r,processors:s}),a=await this.prepareAsync(t,n),i=await this.prepareAsync(e,n),o=[];for(let t=0;t<i.length;t++)i[t].includes(a)&&o.push(e[t]);return o}async matrixAsync(t,e){const r=this.resolveOptions(e),s=await this.prepareAsync(t,r),n=s.length,a=Array.from({length:n},()=>new Array(n).fill(0));for(let t=0;t<n;t++)await Promise.all(Array.from({length:n-t},(e,r)=>t+r).map(async e=>{if(t===e)a[t][e]=1;else{const n=(await this.computeAsync(s[t],s[e],r,"single",!0,!0)).res;a[t][e]=n,a[e][t]=n}}));return a}async phoneticIndexAsync(t,e,r){const{algo:s,opt:n}=this.options.processors?.phonetic??{};return this.indexAsync(t,{algo:e??s,opt:r??n})}async structuredLookupAsync(t,e,r,s){return await this.structured(e,r).lookupAsync((t,e,r)=>this.batchTestAsync(t,e,r),t,s)}async structuredMatchAsync(t,e,r,s,n){return await this.structured(e,r).lookupAsync((t,e,r)=>this.matchAsync(t,e,s,r),t,{...n,sort:"desc"})}async structuredClosestAsync(t,e,r,s=1,n){return await this.structured(e,r).lookupAsync((t,e,r)=>this.closestAsync(t,e,s,r),t,{...n,sort:"desc"})}async structuredFurthestAsync(t,e,r,s=1,n){return await this.structured(e,r).lookupAsync((t,e,r)=>this.furthestAsync(t,e,s,r),t,{...n,sort:"asc"})}async structuredPairsAsync(t,e,r,s,n){return await this.structured(t,e).lookupPairsAsync((t,e,r)=>this.pairsAsync(t,e,r),r,s,n)}}t.CmpStr=F,t.CmpStrAsync=$,t.CmpStrError=o,t.DeepMerge=c,t.DiffChecker=l,t.Filter=h,t.HashTable=u,t.Hasher=p,t.Metric=v,t.MetricRegistry=S,t.Normalizer=d,t.OptionsValidator=M,t.Phonetic=O,t.PhoneticMappingRegistry=C,t.PhoneticRegistry=k,t.Pool=m,t.Profiler=f,t.StructuredData=P,t.TextAnalyzer=N});
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 by Paul Köhler @komed3 / MIT License
1
+ // CmpStr v3.3.0 build-3699f85-260318 by Paul Köhler @komed3 / MIT License
2
2
  'use strict';
3
3
 
4
4
  var DeepMerge = require('./utils/DeepMerge.cjs');
@@ -6,6 +6,7 @@ var DiffChecker = require('./utils/DiffChecker.cjs');
6
6
  var Errors = require('./utils/Errors.cjs');
7
7
  var Filter = require('./utils/Filter.cjs');
8
8
  var Normalizer = require('./utils/Normalizer.cjs');
9
+ var OptionsValidator = require('./utils/OptionsValidator.cjs');
9
10
  var Profiler = require('./utils/Profiler.cjs');
10
11
  var Registry = require('./utils/Registry.cjs');
11
12
  var StructuredData = require('./utils/StructuredData.cjs');
@@ -78,33 +79,28 @@ class CmpStr {
78
79
  }
79
80
  assert(cond, test) {
80
81
  switch (cond) {
81
- case 'metric':
82
- if (!CmpStr.metric.has(test))
83
- throw new Errors.CmpStrNotFoundError(
84
- `CmpStr <metric> must be set, call .setMetric(), ` +
85
- `use CmpStr.metric.list() for available metrics`,
86
- { metric: test }
87
- );
88
- break;
89
- case 'phonetic':
90
- if (!CmpStr.phonetic.has(test))
91
- throw new Errors.CmpStrNotFoundError(
92
- `CmpStr <phonetic> must be set, call .setPhonetic(), ` +
93
- `use CmpStr.phonetic.list() for available phonetic algorithms`,
94
- { phonetic: test }
95
- );
96
- break;
97
82
  default:
98
83
  throw new Errors.CmpStrInternalError(
99
84
  `Cmpstr condition <${cond}> unknown`
100
85
  );
86
+ case 'metric':
87
+ OptionsValidator.OptionsValidator.validateMetricName(test);
88
+ break;
89
+ case 'phonetic':
90
+ OptionsValidator.OptionsValidator.validatePhoneticName(test);
91
+ break;
101
92
  }
102
93
  }
103
94
  assertMany(...cond) {
104
95
  for (const [c, test] of cond) this.assert(c, test);
105
96
  }
106
97
  resolveOptions(opt) {
107
- return DeepMerge.merge({ ...(this.options ?? Object.create(null)) }, opt);
98
+ const merged = DeepMerge.DeepMerge.merge(
99
+ { ...(this.options ?? Object.create(null)) },
100
+ opt
101
+ );
102
+ OptionsValidator.OptionsValidator.validateOptions(merged);
103
+ return merged;
108
104
  }
109
105
  normalize(input, flags) {
110
106
  return Normalizer.Normalizer.normalize(
@@ -123,7 +119,7 @@ class CmpStr {
123
119
  return input;
124
120
  }
125
121
  postProcess(result, opt) {
126
- if (opt?.removeZero && Array.isArray(result))
122
+ if (Array.isArray(result) && opt?.removeZero)
127
123
  result = result.filter((r) => r.res > 0);
128
124
  return result;
129
125
  }
@@ -139,10 +135,10 @@ class CmpStr {
139
135
  return StructuredData.StructuredData.create(data, key);
140
136
  }
141
137
  compute(a, b, opt, mode, raw, skip) {
138
+ const resolved = this.resolveOptions(opt);
139
+ this.assert('metric', resolved.metric);
142
140
  return Errors.ErrorUtil.wrap(
143
141
  () => {
144
- const resolved = this.resolveOptions(opt);
145
- this.assert('metric', resolved.metric);
146
142
  const A = skip ? a : this.prepare(a, resolved);
147
143
  const B = skip ? b : this.prepare(b, resolved);
148
144
  if (
@@ -165,7 +161,7 @@ class CmpStr {
165
161
  const result = this.postProcess(metric.getResults(), resolved);
166
162
  return this.output(result, raw ?? resolved.raw);
167
163
  },
168
- `Failed to compute metric <${opt?.metric ?? this.options.metric}> for the given inputs`,
164
+ `Failed to compute metric <${resolved.metric}> for the given inputs`,
169
165
  { a, b, options: opt }
170
166
  );
171
167
  }
@@ -181,46 +177,79 @@ class CmpStr {
181
177
  { result, raw }
182
178
  );
183
179
  }
184
- clone = () => Object.assign(Object.create(Object.getPrototypeOf(this)), this);
180
+ clone() {
181
+ const inst = Object.assign(
182
+ Object.create(Object.getPrototypeOf(this)),
183
+ this
184
+ );
185
+ inst.options = DeepMerge.DeepMerge.merge(Object.create(null), this.options);
186
+ return inst;
187
+ }
185
188
  reset() {
186
- for (const k in this.options) delete this.options[k];
189
+ this.options = Object.create(null);
187
190
  return this;
188
191
  }
189
192
  setOptions(opt) {
193
+ OptionsValidator.OptionsValidator.validateOptions(opt);
190
194
  this.options = opt;
191
195
  return this;
192
196
  }
193
197
  mergeOptions(opt) {
194
- DeepMerge.merge(this.options, opt);
198
+ DeepMerge.DeepMerge.merge(this.options, opt);
199
+ OptionsValidator.OptionsValidator.validateOptions(this.options);
195
200
  return this;
196
201
  }
197
202
  setSerializedOptions(opt) {
198
- return Errors.ErrorUtil.wrap(
199
- () => {
200
- this.options = JSON.parse(opt);
201
- return this;
202
- },
203
- `Failed to parse serialized options, invalid JSON string`,
204
- { opt }
205
- );
203
+ try {
204
+ const parsed = JSON.parse(opt);
205
+ OptionsValidator.OptionsValidator.validateOptions(parsed);
206
+ this.options = parsed;
207
+ return this;
208
+ } catch (err) {
209
+ if (err instanceof SyntaxError)
210
+ throw new Errors.CmpStrValidationError(
211
+ `Failed to parse serialized options, invalid JSON string`,
212
+ { opt, error: err instanceof Error ? err.message : String(err) }
213
+ );
214
+ throw err;
215
+ }
206
216
  }
207
217
  setOption(path, value) {
208
- DeepMerge.set(this.options, path, value);
218
+ DeepMerge.DeepMerge.set(this.options, path, value);
219
+ OptionsValidator.OptionsValidator.validateOptions(this.options);
209
220
  return this;
210
221
  }
211
222
  rmvOption(path) {
212
- DeepMerge.rmv(this.options, path);
223
+ DeepMerge.DeepMerge.rmv(this.options, path);
213
224
  return this;
214
225
  }
215
- setRaw = (enable) => this.setOption('raw', enable);
216
- setMetric = (name) => this.setOption('metric', name);
217
- setFlags = (flags) => this.setOption('flags', flags);
218
- rmvFlags = () => this.rmvOption('flags');
219
- setProcessors = (opt) => this.setOption('processors', opt);
220
- rmvProcessors = () => this.rmvOption('processors');
221
- getOptions = () => this.options;
222
- getSerializedOptions = () => JSON.stringify(this.options);
223
- getOption = (path) => DeepMerge.get(this.options, path);
226
+ setRaw(enable) {
227
+ return this.setOption('raw', enable);
228
+ }
229
+ setMetric(name) {
230
+ return this.setOption('metric', name);
231
+ }
232
+ setFlags(flags) {
233
+ return this.setOption('flags', flags);
234
+ }
235
+ rmvFlags() {
236
+ return this.rmvOption('flags');
237
+ }
238
+ setProcessors(opt) {
239
+ return this.setOption('processors', opt);
240
+ }
241
+ rmvProcessors() {
242
+ return this.rmvOption('processors');
243
+ }
244
+ getOptions() {
245
+ return this.options;
246
+ }
247
+ getSerializedOptions() {
248
+ return JSON.stringify(this.options);
249
+ }
250
+ getOption(path) {
251
+ return DeepMerge.DeepMerge.get(this.options, path);
252
+ }
224
253
  test(a, b, opt) {
225
254
  return this.compute(a, b, opt, 'single');
226
255
  }
@@ -259,15 +288,35 @@ class CmpStr {
259
288
  const resolved = this.resolveOptions({ flags, processors });
260
289
  const test = this.prepare(needle, resolved);
261
290
  const hstk = this.prepare(haystack, resolved);
262
- return haystack.filter((_, i) => hstk[i].includes(test));
291
+ const out = [];
292
+ for (let i = 0, len = hstk.length; i < len; i++) {
293
+ if (hstk[i].includes(test)) out.push(haystack[i]);
294
+ }
295
+ return out;
263
296
  }
264
297
  matrix(input, opt) {
265
- input = this.prepare(input, this.resolveOptions(opt));
266
- return input.map((a) =>
267
- this.compute(a, input, undefined, 'batch', true, true).map(
268
- (b) => b.res ?? 0
269
- )
270
- );
298
+ const resolved = this.resolveOptions(opt);
299
+ const arr = this.prepare(input, resolved);
300
+ const n = arr.length;
301
+ const out = Array.from({ length: n }, () => new Array(n).fill(0));
302
+ for (let i = 0; i < n; i++)
303
+ for (let j = i; j < n; j++) {
304
+ if (i === j) {
305
+ out[i][j] = 1;
306
+ } else {
307
+ const score = this.compute(
308
+ arr[i],
309
+ arr[j],
310
+ resolved,
311
+ 'single',
312
+ true,
313
+ true
314
+ ).res;
315
+ out[i][j] = score;
316
+ out[j][i] = score;
317
+ }
318
+ }
319
+ return out;
271
320
  }
272
321
  phoneticIndex(input, algo, opt) {
273
322
  const { algo: a, opt: o } = this.options.processors?.phonetic ?? {};
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 by Paul Köhler @komed3 / MIT License
1
+ // CmpStr v3.3.0 build-3699f85-260318 by Paul Köhler @komed3 / MIT License
2
2
  'use strict';
3
3
 
4
4
  var Errors = require('./utils/Errors.cjs');
@@ -44,10 +44,10 @@ class CmpStrAsync extends CmpStr.CmpStr {
44
44
  : phonetic.getIndexAsync(input).then((r) => r.join(delimiter));
45
45
  }
46
46
  async computeAsync(a, b, opt, mode, raw, skip) {
47
+ const resolved = this.resolveOptions(opt);
48
+ this.assert('metric', resolved.metric);
47
49
  return Errors.ErrorUtil.wrapAsync(
48
50
  async () => {
49
- const resolved = this.resolveOptions(opt);
50
- this.assert('metric', resolved.metric);
51
51
  const A = skip ? a : await this.prepareAsync(a, resolved);
52
52
  const B = skip ? b : await this.prepareAsync(b, resolved);
53
53
  if (
@@ -110,23 +110,40 @@ class CmpStrAsync extends CmpStr.CmpStr {
110
110
  const resolved = this.resolveOptions({ flags, processors });
111
111
  const test = await this.prepareAsync(needle, resolved);
112
112
  const hstk = await this.prepareAsync(haystack, resolved);
113
- return haystack.filter((_, i) => hstk[i].includes(test));
113
+ const out = [];
114
+ for (let i = 0; i < hstk.length; i++) {
115
+ if (hstk[i].includes(test)) out.push(haystack[i]);
116
+ }
117
+ return out;
114
118
  }
115
119
  async matrixAsync(input, opt) {
116
- input = await this.prepareAsync(input, this.resolveOptions(opt));
117
- return Promise.all(
118
- input.map(
119
- async (a) =>
120
- await this.computeAsync(
121
- a,
122
- input,
123
- undefined,
124
- 'batch',
125
- true,
126
- true
127
- ).then((r) => r.map((b) => b.res ?? 0))
128
- )
129
- );
120
+ const resolved = this.resolveOptions(opt);
121
+ const arr = await this.prepareAsync(input, resolved);
122
+ const n = arr.length;
123
+ const out = Array.from({ length: n }, () => new Array(n).fill(0));
124
+ for (let i = 0; i < n; i++) {
125
+ await Promise.all(
126
+ Array.from({ length: n - i }, (_, k) => i + k).map(async (j) => {
127
+ if (i === j) {
128
+ out[i][j] = 1;
129
+ } else {
130
+ const score = (
131
+ await this.computeAsync(
132
+ arr[i],
133
+ arr[j],
134
+ resolved,
135
+ 'single',
136
+ true,
137
+ true
138
+ )
139
+ ).res;
140
+ out[i][j] = score;
141
+ out[j][i] = score;
142
+ }
143
+ })
144
+ );
145
+ }
146
+ return out;
130
147
  }
131
148
  async phoneticIndexAsync(input, algo, opt) {
132
149
  const { algo: a, opt: o } = this.options.processors?.phonetic ?? {};
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 by Paul Köhler @komed3 / MIT License
1
+ // CmpStr v3.3.0 build-3699f85-260318 by Paul Köhler @komed3 / MIT License
2
2
  'use strict';
3
3
 
4
4
  var CmpStr = require('./CmpStr.cjs');
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 by Paul Köhler @komed3 / MIT License
1
+ // CmpStr v3.3.0 build-3699f85-260318 by Paul Köhler @komed3 / MIT License
2
2
  'use strict';
3
3
 
4
4
  var Pool = require('../utils/Pool.cjs');
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 by Paul Köhler @komed3 / MIT License
1
+ // CmpStr v3.3.0 build-3699f85-260318 by Paul Köhler @komed3 / MIT License
2
2
  'use strict';
3
3
 
4
4
  var Pool = require('../utils/Pool.cjs');
@@ -1,4 +1,4 @@
1
- // CmpStr v3.2.2 build-bb61120-260311 by Paul Köhler @komed3 / MIT License
1
+ // CmpStr v3.3.0 build-3699f85-260318 by Paul Köhler @komed3 / MIT License
2
2
  'use strict';
3
3
 
4
4
  var Pool = require('../utils/Pool.cjs');