cmpstr
Version:
CmpStr is a lightweight, fast and well performing package for calculating string similarity
8 lines (7 loc) • 49.1 kB
JavaScript
/**
* CmpStr v3.2.2 build-bb61120-260311
* This is a lightweight, fast and well performing library for calculating string similarity.
* (c) 2023-2026 Paul Köhler @komed3 / MIT License
* Visit https://github.com/komed3/cmpstr and https://npmjs.org/package/cmpstr
*/
class t 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 e extends t{constructor(t,e,s){super("E_VALIDATION",t,e,s)}}class s extends t{constructor(t,e,s){super("E_NOT_FOUND",t,e,s)}}class r extends t{constructor(t,e,s){super("E_USAGE",t,e,s)}}class n extends t{constructor(t,e,s){super("E_INTERNAL",t,e,s)}}class i{static assert(t,e,s){if(!t)throw new r(e,s)}static create(e,s,r){if(e instanceof t)throw e;throw new n(s,r,e)}static format(e){return e instanceof t?e.toString():e instanceof Error?`${e.name}: ${e.message}`:String(e)}static wrap(t,e,s){try{return t()}catch(t){throw new n(e,s,t)}}static async wrapAsync(t,e,s){try{return await t()}catch(t){throw new n(e,s,t)}}}var a=Object.freeze({__proto__:null,CmpStrError:t,CmpStrInternalError:n,CmpStrNotFoundError:s,CmpStrUsageError:r,CmpStrValidationError:e,ErrorUtil:i});const o=/\[(\d+)]/g,c=new Map;function l(t){let e=c.get(t);if(e)return e;const s=t.replace(o,".$1").split(".").map(t=>{const e=Number(t);return Number.isInteger(e)&&String(e)===t?e:t});return c.set(t,s),s}function h(t,e,s){let r=t;for(const t of l(e)){if(null==r||!(t in r))return s;r=r[t]}return r}function p(t,e,s){if(""===e)return s;const n=l(e);if(void 0!==t&&("object"!=typeof t||null===t))throw new r(`Cannot set property <${n[0]}> of <${JSON.stringify(t)}>`,{path:n[0],target:t});const i=t??("number"==typeof n[0]?[]:Object.create(null));let a=i;for(let t=0;t<n.length-1;t++){const e=n[t];let s=a[e];if(null!=s&&"object"!=typeof s)throw new r(`Cannot set property <${n[t+1]}> of <${JSON.stringify(s)}>`,{path:n.slice(0,t+2),value:s});null==s&&(s=a[e]="number"==typeof n[t+1]?[]:Object.create(null)),a=s}return a[n[n.length-1]]=s,i}function u(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]=u(null===e||"object"!=typeof e||Array.isArray(e)?Object.create(null):e,n,s)}}),r}function d(t,e,s=!1){const r=l(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 g=Object.freeze({__proto__:null,get:h,has:function(t,e){let s=t;for(const t of l(e)){if(null==s||!(t in s))return!1;s=s[t]}return!0},merge:u,rmv:d,set:p});class m{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}[0m`:e,u=e=>t?`[37;41m${e}[31;49m`:`-[${e}]`,d=e=>t?`[37;42m${e}[32;49m`:`+[${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 f{static filters=new Map;static pipeline=new Map;static getPipeline(t){return i.wrap(()=>{const e=f.pipeline.get(t);if(e)return e;const s=f.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 f.pipeline.set(t,n),n},`Error compiling filter pipeline for hook <${t}>`,{hook:t})}static has(t,e){return!!f.filters.get(t)?.has(e)}static add(t,e,s,r={}){return i.wrap(()=>{const{priority:n=10,active:i=!0,overrideable:a=!0}=r,o=f.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}),f.filters.set(t,o),f.pipeline.delete(t),0))},`Error adding filter <${e}> to hook <${t}>`,{hook:t,id:e,opt:r})}static remove(t,e){f.pipeline.delete(t);const s=f.filters.get(t);return!!s&&s.delete(e)}static pause(t,e){f.pipeline.delete(t);const s=f.filters.get(t)?.get(e);return!(!s||(s.active=!1,0))}static resume(t,e){f.pipeline.delete(t);const s=f.filters.get(t)?.get(e);return!(!s||(s.active=!0,0))}static list(t,e=!1){const s=f.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 i.wrap(()=>{const s=f.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 i.wrapAsync(async()=>{const s=f.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){f.pipeline.clear(),t?f.filters.delete(t):f.filters.clear()}static clearPipeline(){f.pipeline.clear()}}class y{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 w{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>w.MAX_LEN)return!1;const r=e.map(t=>y.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>=w.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 b{static pipeline=new Map;static cache=new w;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(()=>{if(b.pipeline.has(t))return b.pipeline.get(t);const{REGEX:e}=b,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 b.pipeline.set(t,r),r},`Failed to create normalization pipeline for flags: ${t}`,{flags:t})}static normalize(t,e){return i.wrap(()=>{if(!e||"string"!=typeof e||!t)return t;if(e=this.canonicalFlags(e),Array.isArray(t))return t.map(t=>b.normalize(t,e));const s=b.cache.key(e,[t]);if(s&&b.cache.has(s))return b.cache.get(s);const r=b.getPipeline(e)(t);return s&&b.cache.set(s,r),r},`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=>b.normalize(t,e))):Promise.resolve(b.normalize(t,e))):t,`Failed to asynchronously normalize input with flags: ${e}`,{input:t,flags:e})}static clear(){b.pipeline.clear(),b.cache.clear()}}class A{active;static ENV;static instance;nowFn;memFn;store=new Set;totalTime=0;totalMem=0;static detectEnv(){"undefined"!=typeof process?A.ENV="nodejs":"undefined"!=typeof performance?A.ENV="browser":A.ENV="unknown"}static getInstance(t){return A.ENV||A.detectEnv(),A.instance||=new A(t)}constructor(t=!1){switch(this.active=t,A.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 x=Object.create(null),S=Object.create(null);function v(t,e){i.assert(!(t in x||t in S),`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 x[t]=n,S[t]=(e,...r)=>function(t,e,...r){return e=function(t,e){if(!(t in x))throw new s(`Registry <${t}> does not exist`,{registry:t});return"string"==typeof e?x[t]?.get(e):e}(t,e),i.wrap(()=>new e(...r),`Failed to create instance of class <${e.name??e}> from registry <${t}>`,{registry:t,class:e,args:r})}(t,e,...r),n}class k{maxSize;buffers=[];pointer=0;constructor(t){this.maxSize=t}acquire(t,e){return i.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){i.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 z{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 k(64),"number[]":new k(16),"string[]":new k(2),set:new k(8),map:new k(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 r(`Unsupported pool type <${t}>`,{type:t});if(e>s.maxItemSize)return this.allocate(t,e);const n=this.POOLS[t].acquire(e,s.allowOversize);return n?"int32"===t?n.buffer.subarray(0,e):n.buffer:this.allocate(t,e)}static acquireMany(t,e){return e.map(e=>this.acquire(t,e))}static release(t,e,s){const n=this.CONFIG[t];if(!n)throw new r(`Unsupported pool type <${t}>`,{type:t});s<=n.maxItemSize&&this.POOLS[t].release({buffer:e,size:s})}}class C{data;key;static create(t,e){return new C(t,e)}constructor(t,e){this.data=t,this.key=e}extractFrom(t,e){const s=z.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 s=t[0];let r=[];if(this.isMetricResult(s))r=t;else{if(!this.isCmpStrResult(s))throw new e("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 i.wrap(()=>this.finalizeLookup(t(),e,s),"StructuredData lookup failed",{key:this.key})}async performLookupAsync(t,e,s){return await i.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{z.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{z.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{z.release("string[]",n,n.length),z.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{z.release("string[]",n,n.length),z.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 M=A.getInstance();class E{static cache=new w;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],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=r,this.optKey=y.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,i){throw new n("Method compute() must be overridden in a subclass")}runSingle(t,e){return i.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=M.run(()=>{this.symmetric&&([r,i,a,o]=E.swap(r,i,a,o));const t=E.cache.key(this.metric,[r,i],this.symmetric)+this.optKey;return E.cache.get(t||"")??(()=>{const e=this.compute(r,i,a,o,Math.max(a,o));return t&&E.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 r("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 n(`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 n(`Unsupported async mode <${t}>`)}}getMetricName=()=>this.metric;getResults(){return i.assert(void 0!==this.results,"run() must be called before getResults()"),this.results}}const j=v("metric",E);j.add("cosine",class extends E{constructor(t,e,s={}){super("cosine",t,e,s,!0)}_termFreq(t,e){const s=t.split(e),r=z.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?E.clamp(t/(e*s)):0,raw:{dotProduct:t,magnitudeA:e,magnitudeB:s}}}finally{z.release("map",r,r.size),z.release("map",n,n.size)}}}),j.add("damerau",class extends E{constructor(t,e,s={}){super("damerau",t,e,s,!0)}compute(t,e,s,r,n){const i=s+1,[a,o,c]=z.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:E.clamp(1-i/n),raw:{dist:i,maxLen:n}}}finally{z.release("int32",a,i),z.release("int32",o,i),z.release("int32",c,i)}}}),j.add("dice",class extends E{constructor(t,e,s={}){super("dice",t,e,s,!0)}_bigrams(t){const e=t.length-1,s=z.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:E.clamp(2*t/e),raw:{intersection:t,size:e}}}finally{z.release("set",s,n),z.release("set",r,i)}}}),j.add("hamming",class extends E{constructor(t,e,s={}){super("hamming",t,e,s,!0)}compute(t,e,s,n,i){if(s!==n){if(void 0===this.options.pad)throw new r(`Strings must be of equal length for Hamming Distance, a=${s} and b=${n} given, use option.pad for automatic adjustment`,{a:s,b:n});s<i&&(t=t.padEnd(i,this.options.pad)),n<i&&(e=e.padEnd(i,this.options.pad)),s=n=i}let a=0;for(let r=0;r<s;r++)t[r]!==e[r]&&a++;return{res:0===s?1:E.clamp(1-a/s),raw:{dist:a}}}}),j.add("jaccard",class extends E{constructor(t,e,s={}){super("jaccard",t,e,s,!0)}compute(t,e,s,r){const[n,i]=z.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:E.clamp(s/r),raw:{intersection:s,union:r}}}finally{z.release("set",n,s),z.release("set",i,r)}}}),j.add("jaroWinkler",class extends E{constructor(t,e,s={}){super("jaroWinkler",t,e,s,!0)}compute(t,e,s,r){const[n,i]=z.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:E.clamp(p),raw:{matchWindow:a,matches:o,transpos:c,jaro:l,prefix:h}}}finally{z.release("int32",n,s),z.release("int32",i,r)}}}),j.add("lcs",class extends E{constructor(t,e,s={}){super("lcs",t,e,s,!0)}compute(t,e,s,r,n){const i=s+1,[a,o]=z.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:E.clamp(i/n),raw:{lcs:i,maxLen:n}}}finally{z.release("int32",a,i),z.release("int32",o,i)}}}),j.add("levenshtein",class extends E{constructor(t,e,s={}){super("levenshtein",t,e,s,!0)}compute(t,e,s,r,n){const i=s+1,[a,o]=z.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:E.clamp(1-i/n),raw:{dist:i,maxLen:n}}}finally{z.release("int32",a,i),z.release("int32",o,i)}}}),j.add("needlemanWunsch",class extends E{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]=z.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:E.clamp(c/p),raw:{score:c,denum:p}}}finally{z.release("int32",l,c),z.release("int32",h,c)}}}),j.add("qGram",class extends E{constructor(t,e,s={}){super("qGram",t,e,s,!0)}_qGrams(t,e){const s=Math.max(0,t.length-e+1),r=z.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:E.clamp(t/e),raw:{intersection:t,size:e}}}finally{z.release("set",r,i),z.release("set",n,a)}}}),j.add("smithWaterman",class extends E{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]=z.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:E.clamp(h/o),raw:{score:h,denum:o}}}finally{z.release("int32",c,o),z.release("int32",l,o)}}});const L=A.getInstance();class ${static cache=new w;static default;algo;options;optKey;map;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 i=N.get(t,n);if(void 0===i)throw new s(`Requested mapping <${n}> is not declared`,{algo:t,mapId:n});this.options=u(u(r,i.options??{}),e),this.optKey=y.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 i.wrap(()=>{const e=[];for(const s of t){const t=$.cache.key(this.algo,[s])+this.optKey,r=$.cache.get(t||"")??(()=>{const e=this.encode(s);return t&&$.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 i.wrapAsync(async()=>{const e=[];for(const s of t){const t=$.cache.key(this.algo,[s])+this.optKey,r=await Promise.resolve($.cache.get(t||"")??(()=>{const e=this.encode(s);return t&&$.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 L.run(()=>this.loop(t.split(e).filter(Boolean)).filter(Boolean))}async getIndexAsync(t){const{delimiter:e=" "}=this.options;return(await L.runAsync(async()=>await this.loopAsync(t.split(e).filter(Boolean)))).filter(Boolean)}}const F=v("phonetic",$),N=(()=>{const t=Object.create(null),e=e=>t[e]||=Object.create(null);return Object.freeze({add(t,s,r,n=!1){const a=e(t);i.assert(!(!s||s in a)||n,`Entry <${s}> already exists / use <update=true> to overwrite`,{algo:t,id:s}),a[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 q extends ${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(q.REGEX.uppercase,"").toLowerCase(),super.encode(t)}mapChar=t=>t;adjustCode=t=>t.toUpperCase()}F.add("caverphone",q),N.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:""}]}),N.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:""}]}),F.add("cologne",class extends ${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","")}}),N.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 R extends ${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(R.REGEX.adjacent,(t,e)=>"C"===e?t:e),super.encode(t)}adjustCode(t){return t.slice(0,1)+t.slice(1).replace(R.REGEX.vowel,"")}}F.add("metaphone",R),N.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:""}]}),F.add("soundex",class extends ${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","")}}),N.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"}}),N.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 P=A.getInstance();class I{static filter={has:f.has,add:f.add,remove:f.remove,pause:f.pause,resume:f.resume,list:f.list,clear:f.clear};static metric={add:j.add,remove:j.remove,has:j.has,list:j.list};static phonetic={add:F.add,remove:F.remove,has:F.has,list:F.list,map:{add:N.add,remove:N.remove,has:N.has,list:N.list}};static profiler=P.services;static clearCache={normalizer:b.clear,filter:f.clearPipeline,metric:E.clear,phonetic:$.clear};static analyze=t=>new O(t);static diff=(t,e,s)=>new m(t,e,s);static create(t){return new I(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(!I.metric.has(e))throw new s("CmpStr <metric> must be set, call .setMetric(), use CmpStr.metric.list() for available metrics",{metric:e});break;case"phonetic":if(!I.phonetic.has(e))throw new s("CmpStr <phonetic> must be set, call .setPhonetic(), use CmpStr.phonetic.list() for available phonetic algorithms",{phonetic:e});break;default:throw new n(`Cmpstr condition <${t}> unknown`)}}assertMany(...t){for(const[e,s]of t)this.assert(e,s)}resolveOptions(t){return u({...this.options??Object.create(null)},t)}normalize(t,e){return b.normalize(t,e??this.options.flags??"")}filter(t,e){return f.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=S.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 C.create(t,e)}compute(t,e,s,r,n,a){return i.wrap(()=>{const i=this.resolveOptions(s);this.assert("metric",i.metric);const o=a?t:this.prepare(t,i),c=a?e:this.prepare(e,i);if(i.safeEmpty&&(Array.isArray(o)&&0===o.length||Array.isArray(c)&&0===c.length||""===o||""===c))return[];const l=S.metric(i.metric,o,c,i.opt);"prep"!==i.output&&l.setOriginal(t,e),l.run(r);const h=this.postProcess(l.getResults(),i);return this.output(h,n??i.raw)},`Failed to compute metric <${s?.metric??this.options.metric}> for the given inputs`,{a:t,b:e,options:s})}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=()=>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 u(this.options,t),this}setSerializedOptions(t){return i.wrap(()=>(this.options=JSON.parse(t),this),"Failed to parse serialized options, invalid JSON string",{opt:t})}setOption(t,e){return p(this.options,t,e),this}rmvOption(t){return d(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=>h(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 _ extends I{static create(t){return new _(t)}constructor(t){super(t)}async normalizeAsync(t,e){return b.normalizeAsync(t,e??this.options.flags??"")}async filterAsync(t,e){return f.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=S.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,a){return i.wrapAsync(async()=>{const i=this.resolveOptions(s);this.assert("metric",i.metric);const o=a?t:await this.prepareAsync(t,i),c=a?e:await this.prepareAsync(e,i);if(i.safeEmpty&&(Array.isArray(o)&&0===o.length||Array.isArray(c)&&0===c.length||""===o||""===c))return[];const l=S.metric(i.metric,o,c,i.opt);"prep"!==i.output&&l.setOriginal(t,e),await l.runAsync(r);const h=this.postProcess(l.getResults(),i);return this.output(h,n??i.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)}}export{I as CmpStr,_ as CmpStrAsync,a as CmpStrError,g as DeepMerge,m as DiffChecker,f as Filter,w as HashTable,y as Hasher,E as Metric,j as MetricRegistry,b as Normalizer,$ as Phonetic,N as PhoneticMappingRegistry,F as PhoneticRegistry,z as Pool,A as Profiler,C as StructuredData,O as TextAnalyzer};