@flesh-and-blood/search 5.2.8 → 5.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,7 +20,7 @@ const searcher = new Searcher(cards);
20
20
  const { searchResults } = searcher.search("rhinar go again");
21
21
  ```
22
22
 
23
- - `new Searcher(cards, additionalHeroes?, additionalSets?, debug?)`
23
+ - `new Searcher(cards, additionalHeroes?, additionalSets?)`
24
24
  - `.search(text)` → `SearchResults`: `{ searchResults: SearchCard[], appliedFilters, keywords, attributes }`
25
25
 
26
26
  Data-only modules are available as subpath imports (handy for lazy-loaded UI like a search-bar dropdown):
@@ -40,8 +40,8 @@ import { shorthands } from "@flesh-and-blood/search/shorthands";
40
40
  ## Working with this project
41
41
 
42
42
  ```bash
43
- npm run build # build:esm (per-file ESM) + build:cjs (bundled) + tsc declarations + jest
44
- npm test # jest
43
+ npm run build # build:esm (per-file ESM) + build:cjs (bundled) + tsc declarations
44
+ npm test # vitest
45
45
  ```
46
46
 
47
47
  Uses `@flesh-and-blood/cards` (`file:../cards`) as a dev dependency for tests.
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var Ht=Object.create;var ie=Object.defineProperty;var Qt=Object.getOwnPropertyDescriptor;var jt=Object.getOwnPropertyNames;var Kt=Object.getPrototypeOf,Ut=Object.prototype.hasOwnProperty;var Gt=(e,t)=>{for(var r in t)ie(e,r,{get:t[r],enumerable:!0})},$e=(e,t,r,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of jt(t))!Ut.call(e,i)&&i!==r&&ie(e,i,{get:()=>t[i],enumerable:!(a=Qt(t,i))||a.enumerable});return e};var Wt=(e,t,r)=>(r=e!=null?Ht(Kt(e)):{},$e(t||!e||!e.__esModule?ie(r,"default",{value:e,enumerable:!0}):r,e)),_t=e=>$e(ie({},"__esModule",{value:!0}),e);var Ea={};Gt(Ea,{FilterCategory:()=>l,FilterKind:()=>b,FilterProperty:()=>j,MARKUP:()=>Ce,NO_CARD_PROPERTY:()=>D,PUNCTUATION:()=>P,RARITY_VALUES_MAPPING:()=>Le,abbreviations:()=>Re,aliasesByFilterCategory:()=>z,availableExclusions:()=>H,availableModifiers:()=>Ae,default:()=>Nt,filterCard:()=>Lt,filtersToCardPropertyMappings:()=>$,getAbbreviation:()=>ce,getAbbreviationByCard:()=>ir,getCardsByName:()=>ue,getCardsReferencedBy:()=>fe,getCardsReferencing:()=>ge,getCatalogueIndex:()=>we,getCleanText:()=>G,getEscapedForRegExp:()=>_,getExcludedMetaFilters:()=>ke,getFilterCategory:()=>J,getFilterMapping:()=>de,getFilterTokenSpansForKey:()=>na,getFilterValue:()=>He,getIncompleteFilterToken:()=>De,getIsExcludedToken:()=>oa,getIsValueInFilterVocabulary:()=>Pe,getKeywordsAndAppliedFiltersFromText:()=>wa,getMetaFilterResolution:()=>Z,getMetaFilters:()=>pr,getNormalizedFilterValue:()=>w,getNormalizedText:()=>q,getParsedQuery:()=>te,getQueryFilterToken:()=>he,getQueryTokenSpans:()=>ye,getQuotedValue:()=>da,getResolvedFilterKey:()=>Oe,getSuggestedFilterKey:()=>Se,getTextWithoutMarkup:()=>W,getTokensReferencedByCards:()=>Va,getUnquotedValue:()=>me,getValuePartsFromFilterValue:()=>Vt,getValuesFromFilterValue:()=>Qe,multiWordShorthands:()=>Ke,shorthands:()=>je,singleWordShorthands:()=>Ue});module.exports=_t(Ea);var be=require("@flesh-and-blood/types"),_e=Wt(require("fuse.js"),1);var P=/[!"#$%&'’(),./:;<=>?@[\]^_`|~]/g,Ce=/\*/g;var C=require("@flesh-and-blood/types");var G=e=>q(e.toLowerCase().trim().replace(P,"")),q=e=>e.normalize("NFD").replace(/\p{Diacritic}/gu,""),w=e=>e.toLowerCase().replace(P,""),W=e=>e.replace(Ce,""),_=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");var l={Arcane:"arcane",Artist:"artist",Banned:"banned",Bond:"bond",Chain:"chain",Class:"class",Cost:"cost",Defense:"defense",Flow:"flow",Foiling:"foiling",Fusion:"fusion",Intellect:"intellect",Is:"is",Keyword:"keyword",Legal:"legal",Life:"life",Name:"name",Pitch:"pitch",Power:"power",Print:"print",Rarity:"rarity",ReferencedBy:"referencedby",References:"references",Set:"set",Shorthand:"shorthand",Specialization:"specialization",Subtype:"subtype",Talent:"talent",Text:"text",Trait:"trait",Treatment:"treatment",Type:"type",TypeText:"typetext",Year:"year"},b={Comparator:"comparator",ExactMatch:"exactMatch",PartialMatch:"partialMatch"},Ae=[">=",">","<=","<"],H=["!","-"],D="n/a",pt=[...Object.values(C.Format),...Object.values(C.Hero)],$t={category:l.Arcane,canonicalAlias:"arcane",kind:b.Comparator,property:"arcane",specialProperty:"specialArcane",isNumber:!0,partialMatch:!0},Fe={category:l.Artist,canonicalAlias:"art",kind:b.PartialMatch,property:"artists",isArray:!0,partialMatch:!0},ze={category:l.Banned,canonicalAlias:"banned",kind:b.ExactMatch,vocabulary:pt,property:D,isMeta:!0},Ye={category:l.Bond,canonicalAlias:"bond",kind:b.ExactMatch,vocabulary:Object.values(C.Bond),property:"bonds",isArray:!0},zt={category:l.Chain,canonicalAlias:"chain",kind:b.PartialMatch,property:D},qe={category:l.Class,canonicalAlias:"c",kind:b.PartialMatch,vocabulary:Object.values(C.Class),property:"classes",isArray:!0,partialMatch:!0},Xe={category:l.Cost,canonicalAlias:"co",kind:b.Comparator,property:"cost",specialProperty:"specialCost",isNumber:!0,partialMatch:!0},X={category:l.Defense,canonicalAlias:"d",kind:b.Comparator,property:"defense",specialProperty:"specialDefense",isNumber:!0},Je={category:l.Flow,canonicalAlias:"flow",kind:b.ExactMatch,vocabulary:Object.values(C.Flow),property:"flows",isArray:!0},Ze={category:l.Foiling,canonicalAlias:"foil",kind:b.ExactMatch,vocabulary:Object.values(C.Foiling),nestedProperty:"foiling",property:"printings",isArray:!0},et={category:l.Fusion,canonicalAlias:"f",kind:b.ExactMatch,vocabulary:Object.values(C.Fusion),property:"fusions",isArray:!0},tt={category:l.Intellect,canonicalAlias:"i",kind:b.Comparator,property:"intellect",isNumber:!0},rt={category:l.Keyword,canonicalAlias:"k",kind:b.ExactMatch,vocabulary:Object.values(C.Keyword),property:"keywords",isArray:!0},ve={category:l.Legal,canonicalAlias:"l",kind:b.ExactMatch,vocabulary:pt,property:D,isMeta:!0},at={category:l.Life,canonicalAlias:"li",kind:b.Comparator,property:"life",specialProperty:"specialLife",isNumber:!0},it={category:l.Is,canonicalAlias:"is",kind:b.ExactMatch,vocabulary:Object.values(C.Meta),property:"meta",isArray:!0},st={category:l.Name,canonicalAlias:"name",kind:b.PartialMatch,property:"name",isString:!0,partialMatch:!0},Te={category:l.Pitch,canonicalAlias:"p",kind:b.Comparator,property:"pitch",isNumber:!0},se={category:l.Power,canonicalAlias:"pwr",kind:b.Comparator,property:"power",specialProperty:"specialPower",isNumber:!0},oe={category:l.Print,canonicalAlias:"print",kind:b.PartialMatch,property:"setIdentifiers",isArray:!0,partialMatch:!0},ot={category:l.Rarity,canonicalAlias:"r",kind:b.ExactMatch,vocabulary:Object.values(C.Rarity),property:D,isMeta:!0},Yt={category:l.ReferencedBy,canonicalAlias:"referencedby",kind:b.PartialMatch,property:D},qt={category:l.References,canonicalAlias:"references",kind:b.PartialMatch,property:D},nt={category:l.Set,canonicalAlias:"s",kind:b.PartialMatch,vocabulary:Object.values(C.Release),property:"sets",isArray:!0,partialMatch:!0},Me={category:l.Shorthand,canonicalAlias:"short",kind:b.PartialMatch,vocabulary:Object.values(C.Shorthand),property:"shorthands",isArray:!0,partialMatch:!0},ne={category:l.Specialization,canonicalAlias:"sp",kind:b.PartialMatch,vocabulary:Object.values(C.Hero),property:"specializations",isArray:!0,partialMatch:!0},lt={category:l.Subtype,canonicalAlias:"st",kind:b.ExactMatch,vocabulary:Object.values(C.Subtype),property:"subtypes",isArray:!0},dt={category:l.Type,canonicalAlias:"t",kind:b.ExactMatch,vocabulary:Object.values(C.Type),property:"types",isArray:!0},xe={category:l.Talent,canonicalAlias:"tal",kind:b.ExactMatch,vocabulary:Object.values(C.Talent),property:"talents",isArray:!0},Xt={category:l.Text,canonicalAlias:"text",kind:b.PartialMatch,property:"functionalText",hasMarkup:!0,isString:!0,partialMatch:!0},Jt={category:l.Trait,canonicalAlias:"trait",kind:b.PartialMatch,vocabulary:Object.values(C.Trait),property:"traits",isArray:!0,partialMatch:!0},ct={category:l.TypeText,canonicalAlias:"x",kind:b.PartialMatch,property:"typeText",isString:!0,partialMatch:!0},le={category:l.Treatment,canonicalAlias:"treatment",kind:b.ExactMatch,vocabulary:Object.values(C.Treatment),nestedProperty:"treatments",property:"printings",isArray:!0,isNestedPropertyArray:!0},Zt={category:l.Year,canonicalAlias:"year",kind:b.PartialMatch,property:"firstReleaseDate",isString:!0,partialMatch:!0},$={arcane:$t,a:Fe,artist:Fe,art:Fe,attack:se,b:X,block:X,banned:ze,bond:Ye,bonds:Ye,c:qe,class:qe,chain:zt,co:Xe,cost:Xe,color:Te,d:X,def:X,defense:X,flow:Je,flows:Je,f:et,fusion:et,foil:Ze,foiling:Ze,i:tt,intellect:tt,is:it,k:rt,keyword:rt,l:ve,legal:ve,hero:ve,li:at,life:at,meta:it,n:st,name:st,p:Te,pitch:Te,pwr:se,pow:se,power:se,print:oe,printing:oe,printings:oe,prints:oe,r:ot,rarity:ot,referencedby:Yt,references:qt,rf:ze,s:nt,set:nt,short:Me,shorthand:Me,shorthands:Me,sp:ne,spec:ne,specialization:ne,specializations:ne,st:lt,subtype:lt,t:dt,type:dt,tal:xe,talent:xe,talents:xe,text:Xt,trait:Jt,treat:le,treatment:le,var:le,variation:le,x:ct,typetext:ct,year:Zt},er=new Map(Object.entries($)),de=e=>er.get(e.toLowerCase()),J=e=>de(e)?.category,tr=()=>{let e=Object.create(null);for(let[t,{category:r}]of Object.entries($)){let a=e[r];a?a.push(t):e[r]=[t]}return e},z=tr(),rr=()=>{let e=new Map,t=new Set,r=Object.values($);for(let a of r){let{vocabulary:i}=a;if(i&&!t.has(a)){t.add(a);for(let s of i){let o=w(s),n=e.get(o);n?n.push(a):e.set(o,[a])}}}return e},ut=rr(),Pe=(e,t)=>!!ut.get(w(t))?.some(r=>r.category===e),ar=(e,t)=>{let r=[],a=!0;for(let i of t){let s=(ut.get(w(i))||[]).filter(o=>o.category!==e);r=a?s:r.filter(o=>s.includes(o)),a=!1}return r},Se=(e,t)=>{let r=ar(e,t),[a]=r;return r.length===1?a.canonicalAlias:void 0};var ee=require("@flesh-and-blood/types");var ce=e=>Re.find(({abbreviations:t})=>t.find(r=>r.toLowerCase()===e)),ir=e=>Re.find(({card:t})=>t.toLowerCase()===e.name.toLowerCase()),Re=[{abbreviations:["10k"],card:"10,000 Year Reunion"},{abbreviations:["Pajamas","PJs"],card:"Alluvion Constellas"},{abbreviations:["Slippy","Arakni Slipped Through the Cracks","Arakni, Slipped Through the Cracks"],card:"Arakni, 5L!p3d 7hRu 7h3 cR4X"},{abbreviations:["Dullcap"],card:"Arcanite Skullcap"},{abbreviations:["ALS"],card:"Arc Light Sentinel"},{abbreviations:["AoW"],card:"Art of War"},{abbreviations:["BBD"],card:"Barraging Beatdown"},{abbreviations:["BBS"],card:"Big Blue Sky"},{abbreviations:["Starvo"],card:"Bravo, Star of the Show"},{abbreviations:["BEB"],card:"Bull's Eye Bracers"},{abbreviations:["BLW"],card:"Be Like Water"},{abbreviations:["BoJ"],card:"Balance of Justice"},{abbreviations:["BOHH"],card:"Blood on Her Hands"},{abbreviations:["BRB"],card:"Bloodrush Bellow"},{abbreviations:["Breezies"],card:"Breeze Rider Boots"},{abbreviations:["BTA"],card:"Burn Them All"},{abbreviations:["CStrike","C-Strike","C Strike"],card:"Celestial Cataclysm"},{abbreviations:["CBelly"],card:"Cerebellum Processor"},{abbreviations:["CLF"],card:"Channel Lake Frigid"},{abbreviations:["CLV"],card:"Channel Lightning Valley"},{abbreviations:["CMH"],card:"Channel Mount Heroic"},{abbreviations:["CMI"],card:"Channel Mount Isen"},{abbreviations:["CMT"],card:"Channel the Millennium Tree"},{abbreviations:["CnC","C&C"],card:"Command and Conquer"},{abbreviations:["Sea and Sea"],card:"Conqueror of the High Seas"},{abbreviations:["CYB"],card:"Count Your Blessings"},{abbreviations:["Cat","Kitty"],card:"Crouching Tiger"},{abbreviations:["CoD"],card:"Crown of Dominion"},{abbreviations:["CoP"],card:"Crown of Providence"},{abbreviations:["CtW"],card:"Crush the Weak"},{abbreviations:["DD"],card:"Death Dealer"},{abbreviations:["DnD"],card:"Devotion Never Dies"},{abbreviations:["DIO"],card:"Dash I/O"},{abbreviations:["EBTT"],card:"Even Bigger Than That!"},{abbreviations:["NewNigma"],card:"Enigma, New Moon"},{abbreviations:["EPot","E Pot"],card:"Energy Potion"},{abbreviations:["EStrike","E-Strike","E Strike"],card:"Enlightened Strike"},{abbreviations:["FFS"],card:"Fyendal's Fighting Spirit"},{abbreviations:["FoN"],card:"Force of Nature"},{abbreviations:["Frosty","\u{1F976}","\u{1F9CA}","\u2744\uFE0F"],card:"Frostbite"},{abbreviations:["Yum yum"],card:"Fruits of the Forest"},{abbreviations:["GnT"],card:"Give and Take"},{abbreviations:["Habibi"],card:"Hanabi Blaster"},{abbreviations:["HMH"],card:"Hope Merchant's Hood"},{abbreviations:["HoI"],card:"Heart of Ice"},{abbreviations:["Pumpkin"],card:"Jack-o'-lantern"},{abbreviations:["RKO","Cheato"],card:"Kayo, Underhanded Cheat"},{abbreviations:["KKBB"],card:"Knick Knack Bric-a-brac"},{abbreviations:["BStrike"],card:"Levels of Enlightenment"},{abbreviations:["LAG","Twominaris"],card:"Luminaris, Angel's Glow"},{abbreviations:["LCF","Newminaris"],card:"Luminaris, Celestial Fury"},{abbreviations:["LDE"],card:"Last Ditch Effort"},{abbreviations:["LtC"],card:"Lead the Charge"},{abbreviations:["LNW"],card:"Leave No Witnesses"},{abbreviations:["LFaL","L4aL"],card:"Life for a Life"},{abbreviations:["LiT"],card:"Lost in Thought"},{abbreviations:["MMB"],card:"Mage Master Boots"},{abbreviations:["MaxV"],card:"Maximum Velocity"},{abbreviations:["MoM"],card:"Mask of Momentum"},{abbreviations:["MoPL"],card:"Mask of the Pouncing Lynx"},{abbreviations:["MnG"],card:"Meat and Greet"},{abbreviations:["Cake","\u{1F382}"],card:"Ninth Blade of the Blood Oath"},{abbreviations:["PoM"],card:"Peace of Mind"},{abbreviations:["P-Bone"],card:"Performance Bonus"},{abbreviations:["PF","\u{1F525}"],card:"Phoenix Flame"},{abbreviations:["PtW"],card:"Poison the Well"},{abbreviations:["Thanos","Infinity Gauntlet"],card:"Polarity Reversal Script"},{abbreviations:["DPot","D Pot"],card:"Potion of D\xE9j\xE0 Vu"},{abbreviations:["Ponder Run"],card:"Premeditate"},{abbreviations:["Qi Unbound"],card:"Qi Unleashed"},{abbreviations:["RitL"],card:"Red in the Ledger"},{abbreviations:["Cats","Ghost cat","Ghost cats"],card:"Restless Coalescence"},{abbreviations:["Eugene"],card:"Rhinar, Reckless Rampage",isHidden:!0},{abbreviations:["SSGB"],card:"Sandscour Greatbow"},{abbreviations:["SSP"],card:"Sand Sketched Plan"},{abbreviations:["SFaS","S4aS"],card:"Scar for a Scar"},{abbreviations:["Tyler"],card:"Scurv, Stowaway",isHidden:!0},{abbreviations:["SWOMB"],card:"Shifting Winds of the Mystic Beast"},{abbreviations:["Snaps"],card:"Snapdragon Scalers"},{abbreviations:["SWK"],card:"Spinning Wheel Kick"},{abbreviations:["SFTL"],card:"Swing Fist, Think Later"},{abbreviations:["TTT"],card:"Take the Tempo"},{abbreviations:["Ultron"],card:"Teklovossen, the Mechropotent"},{abbreviations:["ToS"],card:"Test of Strength"},{abbreviations:["TAYG"],card:"That All You Got?"},{abbreviations:["TROM"],card:"This Round's on Me"},{abbreviations:["3oak"],card:"Three of a Kind"},{abbreviations:["Pox Malone","Post Malone"],card:"Virulent Touch"},{abbreviations:["Cast Homes"],card:"Visit Goldmane Estate"},{abbreviations:["Frosty Hammer"],card:"Winter's Wail"},{abbreviations:["Wreckless Wing"],card:"War Cry of Bellona"},{abbreviations:["ZTS"],card:"Zero to Sixty"}];var c=require("@flesh-and-blood/types");var S=require("@flesh-and-blood/types");var j={BannedFormats:"bannedFormats",LegalFormats:"legalFormats",LegalHeroes:"legalHeroes"},pe=Array.from(Array(50).keys()).map(e=>`${e}`),sr=[{format:S.Format.ClassicConstructed,nicknames:["cc","classic"]},{format:S.Format.LivingLegend,nicknames:["cc ll","classic constructed ll","ll cc","ll","living legend"]},{format:S.Format.SilverAge,nicknames:["sage"]},{format:S.Format.GoldenAge,nicknames:["gage"]},{format:S.Format.UltimatePitFight,nicknames:["upf"]}],or=Object.values(S.Format).map(e=>{let t=sr.find(({format:a})=>a===e),r=e.toLowerCase().replaceAll(P,"");return t?{...t,format:r}:{format:r}}),nr=[{hero:S.Hero.DataDoll,nicknames:["data","datadoll"]},{hero:S.Hero.Dorinthea,nicknames:["dori"]},{hero:S.Hero.Genis,nicknames:["genis"]},{hero:S.Hero.GravyBones,nicknames:["gravy"]},{hero:S.Hero.Iyslander,nicknames:["islander"]}],lr=Object.values(S.Hero).map(e=>{let t=nr.find(({hero:a})=>a===e),r=e.toLowerCase().replaceAll(P,"");return t?{...t,hero:r}:{hero:r}}),gt=["common","rare","super rare","majestic","legendary","fabled"],dr=({modifier:e,value:t})=>{let r=[],a=e==="<"||e==="<=",i=e===">="||e==="<=",s=a?[...gt].reverse():gt,o=!1;for(let n of s)o?r.push(n):n===t&&(o=!0,i&&r.push(n));return r},cr=(e,t)=>{let r=[];for(let a of e)a.modifier?r.push(...dr(a)):r.push(a.value);return{filterToPropertyMapping:{nestedProperty:"rarity",property:"printings",isArray:!0},isExcluded:t,isOr:!0,values:r}},ft=(e,t,r,a)=>{let i=r.map(d=>({hero:d.toLowerCase().replaceAll(P,"")})),s=[],o=[],n=[],p=[];for(let{value:d}of e){let u=or.find(({format:y,nicknames:h})=>y===d||!!h&&h.includes(d));if(u)o.push(u.format);else{let y=lr.find(({hero:h,nicknames:v})=>h===d||!!v&&v.includes(d))||i.find(({hero:h})=>h===d);y?n.push(y.hero):p.push(d)}}return o.length>0&&s.push({filterToPropertyMapping:{property:a,isArray:!0},values:o,isOr:!0,isExcluded:t}),n.length>0&&s.push({filterToPropertyMapping:{property:j.LegalHeroes,isArray:!0},values:n,isOr:!0,isExcluded:t}),{appliedFilters:s,unresolvedValues:p}},Z=(e,t,{additionalHeroes:r=[],isExcluded:a=!1}={})=>{let i=J(e),s={appliedFilters:[],unresolvedValues:[]};return i===l.Legal?s=ft(t,a,r,j.LegalFormats):i===l.Banned?s=ft(t,a,r,j.BannedFormats):i===l.Rarity&&(s={appliedFilters:[cr(t,a)],unresolvedValues:[]}),s},pr=(e,t,r,a,i,s)=>Z(r,a.map(o=>({modifier:i,value:o})),{additionalHeroes:s,isExcluded:e}).appliedFilters,ur=[{filterToPropertyMapping:{property:"cost",isNumber:!0},isExcluded:!0,values:pe},{filterToPropertyMapping:{property:"specialCost",isString:!0,partialMatch:!0},isExcluded:!0,values:["*","x"]},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["equipment","hero","placeholder","token","weapon"]}],gr=[{filterToPropertyMapping:{property:"defense",isNumber:!0},isExcluded:!0,values:pe},{filterToPropertyMapping:{property:"specialDefense",isString:!0,partialMatch:!0},isExcluded:!0,values:["*","x"]},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["hero","placeholder","token","weapon"]}],fr=[{filterToPropertyMapping:{property:"pitch",isNumber:!0},isExcluded:!0,values:pe},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["equipment","hero","placeholder","token","weapon"]},{filterToPropertyMapping:{property:"isCardBack",isBoolean:!0},isExcluded:!0,values:["true"]}],yr=[{filterToPropertyMapping:{property:"power",isNumber:!0},isExcluded:!0,values:pe},{filterToPropertyMapping:{property:"specialPower",isString:!0,partialMatch:!0},isExcluded:!0,values:["*","x"]},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["equipment","hero","placeholder","token"]}],hr=[{filterToPropertyMapping:{property:"talents",isArray:!0},isExcluded:!0,values:Object.values(S.Talent).map(e=>e.toLowerCase())}],mr=[{filterToPropertyMapping:{property:"classes",isArray:!0},isExcluded:!0,values:Object.values(S.Class).map(e=>e.toLowerCase())}],br=[{category:l.Class,filters:mr},{category:l.Cost,filters:ur},{category:l.Defense,filters:gr},{category:l.Pitch,filters:fr},{category:l.Power,filters:yr},{category:l.Talent,filters:hr}],Cr=()=>{let e=new Map;for(let{category:t,filters:r}of br)for(let a of z[t])for(let i of H)e.set(`${i}${a}`,r);return e},Fr=Cr(),ke=e=>{let t=[],r=Fr.get(e);return r&&t.push(...r),t};var K=require("@flesh-and-blood/types");var yt=new WeakMap,Q=Object.freeze([]),vr=Number.MAX_SAFE_INTEGER,ht=(e,t)=>{let r=new Map;for(let a of e)for(let i of t(a)||[]){let s=r.get(i);s?s.push(a):r.set(i,[a])}return r},Tr=e=>{let t=new Map;for(let r of e){let a=r.types.includes(K.Type.Hero)&&!r.isCardBack,i=a?K.CardRole.Hero:(0,K.getCardRole)(r);if(a||i!==K.CardRole.Hero){let o=t.get(i);o?o.push(r):t.set(i,[r])}}return t},Mr=e=>{let t,r,a,i,s,o=()=>{if(!t){let g=new Map,f=new Map,m=[],T=new Map,M=0;for(let R of e){g.set(R.cardIdentifier,R),f.set(R.cardIdentifier,M),M++;let k=G(R.name),U=T.get(k);U?U.push(R):(T.set(k,[R]),m.push(k))}t={cardByCardIdentifier:g,corpusPositionByCardIdentifier:f,cleanedNames:m,pitchCycleByCleanedName:T}}return t},n=g=>{let{corpusPositionByCardIdentifier:f}=o(),m=({cardIdentifier:T})=>f.get(T)??vr;return[...g].sort((T,M)=>m(T)-m(M))},p=g=>o().cardByCardIdentifier.get(g),d=g=>{let{cardByCardIdentifier:f}=o(),m=[];for(let T of g||[]){let M=f.get(T);M&&m.push(M)}return n(m)},u=g=>{let f=new Map;return m=>{let T=f.get(m);if(!T){let M=p(m),R=d(M&&g(M)),k=R.length>0;T=k?R:Q,k&&f.set(m,T)}return T}},y=g=>{let{pitchCycleByCleanedName:f}=o(),m=p(g);return m?f.get(G(m.name))??Q:Q},h=g=>{let{cleanedNames:f,pitchCycleByCleanedName:m}=o(),T=G(g),M=m.get(T);if(!M&&T.length>0){let k=f.find(U=>U.includes(T));k&&(M=m.get(k))}return M??Q},v=g=>{let{pitchCycleByCleanedName:f}=o();return f.get(G(g))??Q},I=()=>{if(!s){let g=new Set;for(let f of e)for(let m of f.artists)g.add(m);s=[...g].sort((f,m)=>f.localeCompare(m,"en",{sensitivity:"base"}))}return s},V=u(({oppositeSideCardIdentifiers:g})=>g),A=u(({referencedCards:g})=>g),E=g=>(r||(r=ht(e,({referencedCards:f})=>f)),r.get(g)??Q),L=u(({createdExtras:g})=>g);return{cards:e,getCard:p,getPitchCycle:y,getCardsByName:h,getCardsByExactName:v,getArtists:I,getOppositeSide:V,getReferences:A,getReferencedBy:E,getCreates:L,getCreatedBy:g=>(a||(a=ht(e,({createdExtras:f})=>f)),a.get(g)??Q),getCreatedClosure:g=>{let f=new Map,m=new Set,T=[...g];for(let M of T)if(!m.has(M)){m.add(M);for(let k of L(M))f.set(k.cardIdentifier,k),T.push(k.cardIdentifier)}return n([...f.values()])},getByRole:g=>(i||(i=Tr(e)),i.get(g)??Q),getCardsInCorpusOrder:n}},we=e=>{let t=yt.get(e);return t||(t=Mr(e),yt.set(e,t)),t},Ve=(e,t)=>e.getPitchCycle(t.cardIdentifier),ue=(e,t)=>e.getCardsByName(t),mt=(e,t)=>{let r=new Map;for(let a of t)for(let i of Ve(e,a))r.set(i.cardIdentifier,i);return e.getCardsInCorpusOrder([...r.values()])},ge=(e,t)=>{let r=[];for(let a of Ve(e,t))r.push(...e.getReferencedBy(a.cardIdentifier));return mt(e,r)},fe=(e,t)=>{let r=[];for(let a of Ve(e,t))r.push(...e.getReferences(a.cardIdentifier));return mt(e,r)};var xr=e=>{let[t]=e,r=t?.modifier;return e.every(({modifier:i})=>i===r)?r:void 0},Ie=({filterValues:e,isAnd:t,isExcluded:r,mapping:a})=>{let i=[];for(let{value:s}of e)i.push(a.hasMarkup?W(s):s);return{filterToPropertyMapping:a,filterValues:e,isAnd:t,isExcluded:r,isOr:!t&&i.length>1,modifier:xr(e),values:i}},vt=({isAnd:e,isExcluded:t,mapping:r},a)=>({filterToPropertyMapping:r,isAnd:e,isExcluded:t,isOr:!e&&a.length>1,values:a}),Ar=({category:e,filterValues:t,mapping:r})=>{let a=[];if(r.kind===b.ExactMatch&&!!r.vocabulary)for(let{value:s}of t)Pe(e,s)||a.push(s);return a},Pr=e=>({appliedFilters:[Ie(e)],unresolvedValues:Ar(e)}),Be=({isExcluded:e},t,r)=>e?void 0:{[t]:r},Tt=(e,t)=>({appliedFilters:[Ie(e)],attributes:Be(e,t,e.filterValues.map(({value:r})=>r)),unresolvedValues:[]}),Sr=e=>Tt(e,"artists"),Rr=e=>Tt(e,"prints"),Ne=(e,t,r)=>{let a=[],i=[],s=[];for(let{value:o}of e.filterValues){let n=r(o);if(n.length>0)for(let p of n)a.push(p),i.push(w(p));else s.push(o)}return{appliedFilters:[vt(e,i)],attributes:Be(e,t,a),canonicalValues:i,unresolvedValues:s}},kr=new Map(Object.entries({purple:4,blue:3,yellow:2,red:1,white:0})),wr=e=>{let t=[],r=[];for(let{modifier:a,value:i}of e.filterValues){let s=kr.get(i),o=s===void 0?i:`${s}`;t.push({modifier:a,value:o}),r.push(o)}return{appliedFilters:[Ie({...e,filterValues:t})],canonicalValues:r,unresolvedValues:[]}},Ee=new Map;for(let e of Object.values(c.Release)){let t=w(e),r=Ee.get(t);if(r===void 0)Ee.set(t,e);else throw new Error(`${r} and ${e} are one name as a filter reads it, so a set filter naming it could reach either`)}var bt=(e,t)=>{let r=e.get(t);return r?[r]:[]},Vr=(e,t)=>{let r=[()=>bt(Ee,e),()=>bt(c.setIdentifierToSetMappings,e),()=>Object.values(c.Release).filter(i=>i.toLowerCase().includes(e)),()=>{let i=t.find(s=>w(s)===e);return i?[i]:[]}],a=[];for(let i of r)a.length===0&&a.push(...i());return a},Er=(e,{additionalSets:t})=>Ne(e,"releases",r=>Vr(r,t)),Ir=new Map(Object.entries({r:c.Foiling.Rainbow,rf:c.Foiling.Rainbow,rainbow:c.Foiling.Rainbow,c:c.Foiling.Cold,cf:c.Foiling.Cold,cold:c.Foiling.Cold,g:c.Foiling.Gold,gf:c.Foiling.Gold,gold:c.Foiling.Gold})),Br=e=>{let t=Ir.get(e);return t?[t]:[]},Nr=e=>Ne(e,"foilings",Br),Mt=new Map(Object.entries({aa:c.Treatment.AA,alt:c.Treatment.AA,"alt art":c.Treatment.AA,ab:c.Treatment.AB,"alt border":c.Treatment.AB,at:c.Treatment.AT,"alt text":c.Treatment.AT,ea:c.Treatment.EA,extended:c.Treatment.EA,"extended art":c.Treatment.EA,fa:c.Treatment.FA,full:c.Treatment.FA,"full art":c.Treatment.FA}));for(let e of Object.values(c.Treatment))Mt.set(e.toLowerCase(),e);var Lr=new Map(Object.entries(c.Treatment)),Or=e=>{let t=Mt.get(e)||Lr.get(e.toUpperCase());return t?[t]:[]},Dr=e=>Ne(e,"treatments",Or),Le=new Map(Object.entries({b:c.Rarity.Basic,c:c.Rarity.Common,f:c.Rarity.Fabled,l:c.Rarity.Legendary,m:c.Rarity.Majestic,p:c.Rarity.Promo,r:c.Rarity.Rare,s:c.Rarity.SuperRare,t:c.Rarity.Token,v:c.Rarity.Marvel})),Hr=e=>Le.get(e)||Object.values(c.Rarity).find(t=>t.toLowerCase()===e),Qr=(e,{additionalHeroes:t})=>{let r=[],a=[],i=[],s=[];for(let{modifier:n,value:p}of e.filterValues){let d=Hr(p);d?(r.push(d),a.push(d.toLowerCase()),i.push({modifier:n,value:d.toLowerCase()})):(s.push(p),i.push({modifier:n,value:p}))}let{appliedFilters:o}=Z(e.key,i,{additionalHeroes:t,isExcluded:e.isExcluded});return{appliedFilters:o,attributes:Be(e,"rarities",r),canonicalValues:a,unresolvedValues:s}},Ct=({filterValues:e,isExcluded:t,key:r},{additionalHeroes:a})=>{let{appliedFilters:i,unresolvedValues:s}=Z(r,e,{additionalHeroes:a,isExcluded:t}),o=[];for(let{values:n}of i)o.push(...n);return{appliedFilters:i,canonicalValues:o,unresolvedValues:s}},jr=["unique"],Kr=["preview","spoiler","unreleased"],Ur=["released"],Ft={property:"firstReleaseDate",isDate:!0},Gr=new Map(Object.entries({dual:c.Meta.DualClass,exp:c.Meta.Expansion,expansion:c.Meta.Expansion,rainbow:c.Meta.Rainbow,reprint:c.Meta.Reprint,reprints:c.Meta.Reprint})),Wr=e=>{let t=[],r=[];for(let i of e){let s=Gr.get(i);s?t.push(s):r.push(i)}let a=[];if(t.length===0){let i=new Set;for(let s of Object.values(c.Meta)){let o=!1;for(let n of r)s.toLowerCase().includes(n)&&(o=!0,i.add(n));o&&t.push(s)}for(let s of r)i.has(s)||a.push(s)}else a.push(...r);return{unresolvedValues:a,values:t}},_r=(e,{today:t})=>{let{filterValues:r,isAnd:a,isExcluded:i}=e,s=[],o=[],n=[],p=[],d=[];for(let{value:A}of r)jr.includes(A)?o.push(A):Kr.includes(A)?n.push(A):Ur.includes(A)?p.push(A):d.push(A);let u=!a&&r.length>1;o.length>0&&s.push({filterToPropertyMapping:$.is,values:[w(c.Meta.Reprint)],isAnd:a,isOr:u,isExcluded:!i}),n.length>0&&s.push({filterToPropertyMapping:Ft,values:[t],isAnd:a,isOr:u,isExcluded:i}),p.length>0&&s.push({filterToPropertyMapping:Ft,values:[t],isAnd:a,isOr:u,isExcluded:!i});let{unresolvedValues:y,values:h}=Wr(d),v=[...o,...n,...p,...h.map(w)];(d.length>0||s.length===0)&&s.push(vt(e,h.map(w)));let V=h.includes(c.Meta.Expansion)&&!i;return{appliedFilters:s,attributes:V?{isExpansionSlot:V}:void 0,canonicalValues:v,unresolvedValues:y}},$r={property:"cardIdentifier",isString:!0,isNormalized:!0},zr=20,Yr=(e,t)=>{let r=new Set,a=[],i=new Set,s=[],o=d=>{r.add(d.cardIdentifier),i.has(d.name)||(i.add(d.name),a.push(d))},n=d=>{d.types.includes(c.Type.Hero)||o(d)};for(let d of t){let u=ue(e,d);for(let y of u)o(y);u.length===0&&s.push(d)}let p=0;for(;p<a.length&&p<=zr;){let d=a[p];for(let y of fe(e,d))n(y);if(p===0)for(let y of ge(e,d))n(y);p++}return{cardIdentifiers:r,unresolvedValues:s}},xt=(e,t,r)=>{let a=new Set;for(let i of ue(e,t)){let s=r?fe(e,i):ge(e,i);for(let o of s)a.add(o.cardIdentifier)}return a},qr=(e,t)=>{let r=new Set,[a=new Set,...i]=e;if(t)for(let s of a)i.every(n=>n.has(s))&&r.add(s);else for(let s of e)for(let o of s)r.add(o);return r},At=(e,t)=>({filterToPropertyMapping:$r,values:[...e],valuesSet:e,isExcluded:t,isOr:!0}),Pt=({filterValues:e,isAnd:t,isExcluded:r},a)=>{let i=[],s=[];for(let{value:o}of e){let n=a(o);i.push(n),n.size===0&&s.push(o)}return{appliedFilters:[At(qr(i,t),r)],unresolvedValues:s}},Xr=(e,{index:t})=>{let{cardIdentifiers:r,unresolvedValues:a}=Yr(t,e.filterValues.map(({value:i})=>i));return{appliedFilters:[At(r,e.isExcluded)],unresolvedValues:a}},Jr=(e,{index:t})=>Pt(e,r=>xt(t,r,!0)),Zr=(e,{index:t})=>Pt(e,r=>xt(t,r,!1)),ea=new Map([[l.Artist,Sr],[l.Banned,Ct],[l.Chain,Xr],[l.Foiling,Nr],[l.Is,_r],[l.Legal,Ct],[l.Pitch,wr],[l.Print,Rr],[l.Rarity,Qr],[l.ReferencedBy,Jr],[l.References,Zr],[l.Set,Er],[l.Treatment,Dr]]),St=(e,t)=>(ea.get(e.category)||Pr)(e,t);var kt=H.map(_).join(""),ta=/(?:[^\s"]+|"[^"]*(?:"|$))+/g,ra=new RegExp(`^([${kt}])?([A-Za-z]+):(.+)$`),aa=new RegExp(`^([${kt}])?([A-Za-z]+):$`),ia=",",Rt="+",sa='"',wt=e=>{let t=[],r=!1,a="",i=!1;for(let s of e)s===sa?(i=!i,a+=s):!i&&(s===ia||s===Rt)?(r=r||s===Rt,a&&t.push(a),a=""):a+=s;return a&&t.push(a),{isAndList:r,parts:t}},ye=e=>{let t=[];for(let r of e.matchAll(ta))t.push({end:r.index+r[0].length,start:r.index,token:r[0]});return t},oa=e=>H.some(t=>e.startsWith(t)),he=e=>{let t=e.match(ra),r;if(t){let[,a,i,s]=t;r={isAndList:wt(s).isAndList,isExcluded:!!a,key:i,valueText:s}}return r},De=e=>{let t=e.match(aa),r;return t&&(r={isAndList:!1,isExcluded:!!t[1],key:t[2],valueText:""}),r},He=e=>{let t=e.trim(),r=Ae.find(a=>t.startsWith(a));return{modifier:r,value:r?t.slice(r.length).trim():t}},Oe=e=>J(e)??e.toLowerCase(),na=(e,t)=>{let r=Oe(t),a=[];for(let{end:i,start:s,token:o}of ye(e)){let n=he(o);n&&Oe(n.key)===r&&a.push({...n,end:i,start:s,token:o})}return a},Vt=e=>wt(e).parts,me=e=>e.replace(/^"|"$/g,""),Qe=e=>{let t=[];for(let r of Vt(e)){let a=me(r);a&&t.push(a)}return t},la=/[\s,:+"]/,da=e=>{let t=e.replaceAll('"',"");return la.test(e)?`"${t}"`:t};var N=require("@flesh-and-blood/types"),je=[{description:"Attack actions",expanded:["st:attack"],filters:{subtypes:[N.Subtype.Attack]},isCardProperty:!1,shorthands:["AA"]},{description:"Arcane barrier",expanded:['k:"arcane barrier"'],filters:{keywords:[N.Keyword.ArcaneBarrier]},isCardProperty:!1,shorthands:["AB"]},{description:"Attack reactions",expanded:['t:"attack reaction"'],filters:{types:[N.Type.AttackReaction]},isCardProperty:!1,shorthands:["AR"]},{description:"Defense reactions",expanded:['t:"defense reaction"'],filters:{types:[N.Type.DefenseReaction]},isCardProperty:!1,shorthands:["DR"]},{description:"Gain life",expanded:["gain {h}"],filters:{functionalText:"gain {h}"},isCardProperty:!1,shorthands:["Gain life","Gains life"]},{description:"Go again",expanded:['k:"go again"'],filters:{keywords:[N.Keyword.GoAgain]},isCardProperty:!1,shorthands:["GA"]},{description:"Non-attack actions",expanded:["t:action","st:non-attack"],filters:{subtypes:[N.Subtype.NonAttack],types:[N.Type.Action]},isCardProperty:!1,shorthands:["NAA"]},{description:"Plus defense",expanded:["+ {d}"],filters:{functionalText:"+ {d}"},isCardProperty:!1,shorthands:["Pump defense","Pumps defense","Buff defense","Buffs defense"]},{description:"Spellvoid",expanded:['k:"spellvoid"'],filters:{keywords:[N.Keyword.Spellvoid]},isCardProperty:!1,shorthands:["SV"]}],Ke=je.filter(({shorthands:e})=>e.some(t=>t.includes(" "))).map(e=>({...e,shorthands:e.shorthands.filter(t=>t.includes(" ")).map(t=>t.toLowerCase()).sort((t,r)=>r.length-t.length)})),Ue=je.filter(({shorthands:e})=>e.some(t=>!t.includes(" "))).map(e=>({...e,shorthands:e.shorthands.filter(t=>!t.includes(" ")).map(t=>t.toLowerCase()).sort((t,r)=>r.length-t.length)}));var ca=["\u201C","\u201D"],pa=[{text:ee.Release.ClassicBattlesRhinarDorinthea.toLowerCase(),override:ee.Release.ClassicBattlesRhinarDorinthea.toLowerCase().replaceAll(P,"")}],Ge=new Map([...ee.setToSetIdentifierMappings].map(([e,t])=>[e.toLowerCase(),t])),ua=[...z[l.Set],...z[l.Print]],ga=H.map(_).join(""),fa=[...Ge.keys()].sort((e,t)=>t.length-e.length).map(_).join("|"),ya=new RegExp(`(?<=^|\\s)([${ga}]?(?:${ua.join("|")}):(?:[^\\s]*[,+])?"?)(${fa})(?="?(?:[,+]|\\s|$))`,"g"),ha=(e,t)=>{let r=e.trim().toLowerCase();for(let s of ca)r=r.replaceAll(s,'"');for(let{expanded:s,shorthands:o}of Ke)for(let n of o)if(r.includes(n)){r=r.replace(n,s.join(" "));break}r=r.replace(ya,(s,o,n)=>{let p=Ge.get(n);return p?`${o}${p[0]}`:s});let a=Ge.get(r),i=t.getCardsByExactName(r).length>0;a&&!i&&(r=`set:${a[0]}`);for(let{override:s,text:o}of pa)r.includes(o)&&(r=r.replace(o,s));return{isWholeQueryAbbreviation:!!ce(r)?.card,text:r}},ma=e=>{let t=Ue.find(({shorthands:a})=>a.includes(e)),r=!!t&&!t.isCardProperty;return{isExpanded:r,tokens:r?t.expanded:[e]}},ba=({isWholeQueryAbbreviation:e,text:t})=>{let r=[],a=e?[{end:t.length,start:0,token:t}]:ye(t);for(let{end:i,start:s,token:o}of a){let{isExpanded:n,tokens:p}=ma(o);for(let d of p)r.push({end:i,isExpanded:n,start:s,token:d})}return r},Ca=e=>{let t=[];for(let r of e){let{modifier:a,value:i}=He(r),s=w(i);s&&t.push({modifier:a,value:s})}return t},Fa=(e,t,r)=>{let a={key:e,reason:"value",values:r},i=Se(t,r);return i&&(a.suggestedKey=i),a},va=()=>{let e=new Date,t=`${e.getMonth()+1}`.padStart(2,"0"),r=`${e.getDate()}`.padStart(2,"0");return`${e.getFullYear()}-${t}-${r}`},te=(e,t,{additionalHeroes:r=[],additionalSets:a=[],today:i=va()}={})=>{let s=ha(e,t),o={additionalHeroes:r,additionalSets:a,index:t,today:i},n=[],p={artists:[],foilings:[],isExpansionSlot:!1,prints:[],rarities:[],releases:[],treatments:[]},d=[],u=[],y=[];for(let h of ba(s)){let v=he(h.token)||De(h.token);if(v){let{isAndList:I,isExcluded:V,key:A,valueText:E}=v,L=de(A),O=L?.category,F=Qe(E),B=Ca(F),g={...h,canonicalValues:B.map(({value:f})=>f),category:O,filterValues:B,isAnd:I,isExcluded:V,isFilter:!0,isResolved:!0,key:A};if(F.length>0)if(L&&O){let f=F;if(B.length>0){let m=St({category:O,filterValues:B,isAnd:g.isAnd,isExcluded:V,key:A,mapping:L},o);n.push(...m.appliedFilters),m.canonicalValues&&(g.canonicalValues=m.canonicalValues),m.attributes&&Object.assign(p,m.attributes),f=m.unresolvedValues}f.length>0&&(g.isResolved=!1,y.push(Fa(A,O,f)))}else g.isResolved=!1,y.push({key:A,reason:"key",values:[]});u.push(g)}else{let{end:I,start:V,token:A}=h;u.push({end:I,isFilter:!1,start:V,token:A});let E=me(h.token),L=ce(E)?.card,O=ke(E);L?d.push(`"${L.toLowerCase().replace(P,"")}"`):O.length>0?n.push(...O):E&&d.push(E.replace(P,""))}}return{appliedFilters:n,attributes:p,keywords:d,nodes:u,text:s.text,unresolvedFilters:y}};var x=require("@flesh-and-blood/types"),Et={artists:["Hoodwill"],cardIdentifier:"fangs-a-lot-blue",classes:[x.Class.Generic],defaultImage:"FNG000",firstReleaseDate:"2022-06-02",functionalText:"If Fangs A Lot is put into your banished zone from your graveyard, instead put it into your hand.",legalFormats:[],legalHeroes:[x.Hero.Kayo,x.Hero.Levia,x.Hero.Rhinar],printings:[{artists:["Hoodwill"],identifier:"FNG000",image:"FNG000",print:"FNG000",rarity:x.Rarity.Rare,set:x.Release.Promos},{artists:["Hoodwill"],identifier:"FNG000",image:"FNG000_Marvel",print:`FNG000-${x.Treatment.FA}`,rarity:x.Rarity.Marvel,set:x.Release.Promos,treatments:[x.Treatment.FA]}],name:"Fangs A Lot",rarities:[x.Rarity.Rare,x.Rarity.Marvel],rarity:x.Rarity.Rare,sets:[x.Release.Promos],setIdentifiers:["FNG000"],specialImage:"FNG000_Marvel",subtypes:[x.Subtype.Attack],types:[x.Type.Action],typeText:"Generic Action - Attack"},It=[{keyword:Et.name.toLowerCase(),card:Et}];var Ta={getFn:(e,t)=>{let r=_e.default.config.getFn(e,t),a=r;if(Array.isArray(r))a=r.map(i=>q(i.replace(P,"")));else if(r){let i=q(r).replace(P,"");a=t.includes("functionalText")?W(i):i}return a},ignoreLocation:!0,includeScore:!0,keys:[{name:"name",weight:10},{name:"functionalText",weight:6},{name:"shorthands",weight:4},{name:"setIdentifiers",weight:2},{name:"traits",weight:4},{name:"typeText",weight:6}],threshold:.15,useExtendedSearch:!0},We=class{constructor(t,r=[],a=[],i=!1){this.getFuse=()=>(this.fuse||(this.fuse=new _e.default(this.cards,Ta)),this.fuse);this.log=(t,...r)=>{this.debug&&console.log(t,...r)};this.search=(t,r)=>{let a,{appliedFilters:i,attributes:s,keywords:o,unresolvedFilters:n}=te(t,this.index,{additionalHeroes:this.additionalHeroes,additionalSets:this.additionalSets}),p=o.join(" "),d=r?It.filter(F=>F.keyword===p):[];if(d.length>0?a=d.map(({card:F})=>F):o.length?a=this.getFuse().search(p).map(F=>F.item):a=[...this.cards],i.length&&(a=a.filter(F=>F&&Lt(F,i))),o.length===0){let F="";if(s.releases.length===1){let f=be.setToSetIdentifierMappings.get(s.releases[0]);f?.length&&(F=f[0].toUpperCase())}if(!F&&s.prints.length===1){let f=s.prints[0];be.setIdentifierToSetMappings.has(f)&&(F=f.toUpperCase())}F?a.sort((f,m)=>{let T=f.setIdentifiers.find(R=>R.includes(F))?.replace(F,""),M=m.setIdentifiers.find(R=>R.includes(F))?.replace(F,"");return T&&M?T.localeCompare(M):-1}):a.sort((f,m)=>f.name===m.name?`${f.pitch}`.localeCompare(`${m.pitch}`):f.name.localeCompare(m.name))}else{let F=[],B=[],g=o.map(f=>f.toLowerCase().replace(P,"")).join(" ");for(let f of a)f.name.toLowerCase().replace(P,"")===g?F.push(f):B.push(f);a=[...F,...B]}let u=[],{artists:y,isExpansionSlot:h,foilings:v,prints:I,rarities:V,releases:A,treatments:E}=s;(y.length>0||h||v.length>0||I.length>0||V.length>0||A.length>0||E.length>0)&&(u=a.map(F=>{let B=F.printings.filter(g=>{let f=!!g.image,m=y.length===0||y.some(Y=>g.artists.find(Dt=>Dt.replace(P,"").toLowerCase().includes(Y))),T=!h||h===g.isExpansionSlot,M=v.length===0||!!g.foiling&&v.includes(g.foiling),R=I.length===0||I.some(Y=>g.identifier.includes(Y.toUpperCase())),k=V.length===0||V.includes(g.rarity),U=A.length===0||A.includes(g.set),Ot=E.length===0||g.treatments?.some(Y=>E.includes(Y));return f&&m&&T&&M&&R&&k&&U&&Ot});return{...F,matchingPrintings:B}}));let O=u.length>0?u:a;return{appliedFilters:i,attributes:s,keywords:o,searchResults:O,unresolvedFilters:n}};let s=Array.isArray(r)?{additionalHeroes:r,additionalSets:a,debug:i}:r;this.additionalHeroes=s.additionalHeroes||[],this.additionalSets=s.additionalSets||[],this.cards=[...t],this.debug=s.debug||!1,this.index=s.index||we(t)}},Nt=We,Lt=(e,t)=>{let r=!0;for(let a of t){let{isNumber:i,isString:s,isArray:o,isBoolean:n,isDate:p}=a.filterToPropertyMapping;a.isOptional||(i?r=r&&Ma(e,a):s?r=r&&xa(e,a):o?r=r&&Aa(e,a,t):n?r=r&&Pa(e,a):p&&(r=r&&Sa(e,a)))}return r},Bt=(e,t,r)=>{let a=parseInt(t),i;switch(r){case">=":i=e>=a;break;case">":i=e>a;break;case"<=":i=e<=a;break;case"<":i=e<a;break;default:i=e===a}return i},Ma=(e,t)=>{let{filterValues:r,values:a,modifier:i,isExcluded:s,filterToPropertyMapping:{partialMatch:o}}=t,n=!0;if(ae(t,e)){let p=re(e,t),d;if(p!=null&&!isNaN(p)){let u=parseInt(p);d=r?r.some(({modifier:y,value:h})=>Bt(u,h,y)):a.some(y=>Bt(u,y,i))}else{let u=ka(e,t)?.toLowerCase();d=o?a.some(y=>!!u?.includes(y)):a.some(y=>u===y)}n=s?!d:d}return n},xa=(e,t)=>{if(ae(t,e)){let{values:r,valuesSet:a,isAnd:i,isExcluded:s,filterToPropertyMapping:{hasMarkup:o,isNormalized:n,partialMatch:p}}=t,d=re(e,t),u=n?d:d?.replaceAll(P,"").toLowerCase(),y=o&&u?W(u):u;if(p){let h=i?r?.every(v=>y?.includes(v)):r?.some(v=>y?.includes(v));return s?!h:h}else{let h;return i?h=r?.every(v=>y===v):a?h=a.has(y):h=r?.some(v=>y===v),s?!h:h}}else return!0},Aa=(e,t,r)=>{if(ae(t,e)){let{values:a,isAnd:i,isExcluded:s,filterToPropertyMapping:{partialMatch:o}}=t,n=Ra(e,t,r).map(p=>p?.replaceAll(P,""));if(o){let p=i?a.every(u=>n?.some(y=>y?.toLowerCase().includes(u))):a.some(u=>n?.some(y=>y?.toLowerCase().includes(u))),d=n.length===0;return s?!p||d:p}else{let p=i?a.every(d=>n?.some(u=>u?.toLowerCase()===d)):a.some(d=>n?.some(u=>u?.toLowerCase()===d));return s?!p:p}}else return!0},Pa=(e,t)=>{if(ae(t,e)){let{isExcluded:r}=t,a=re(e,t);return r?!a:a}else return!0},Sa=(e,t)=>{if(ae(t,e)){let{values:r,isExcluded:a}=t,i=re(e,t),s=r?.some(o=>i>o);return a?!s:s}else return!0},re=(e,t)=>{let{filterToPropertyMapping:{property:r}}=t,a;return r!==D&&(a=e[r]),a},Ra=(e,t,r)=>{let{filterToPropertyMapping:{isNestedPropertyArray:a,nestedProperty:i}}=t,s=[],o=Object.keys(e.legalOverrides||{}).length>0,n=t.filterToPropertyMapping.property===j.LegalHeroes,p=r.find(({filterToPropertyMapping:u})=>u.property===j.LegalFormats);if(o&&n&&!!p){let u=new Set;for(let{format:y,heroes:h}of e.legalOverrides||[])if(p.values.includes(y.toLowerCase()))for(let v of h)u.add(v);s=Array.from(u)}if(s.length===0)if(i){let u=new Set;for(let y of e.printings){let h=y[i];if(a){if(Array.isArray(h))for(let v of h)u.add(v)}else h&&typeof h=="string"&&u.add(h)}s=Array.from(u)}else{let u=re(e,t);if(Array.isArray(u))for(let y of u)typeof y=="string"&&s.push(y)}return s},ka=(e,t)=>{let{filterToPropertyMapping:{specialProperty:r}}=t,a;return r&&(a=e[r]),a},ae=({cardTypes:e},{types:t,subtypes:r})=>!e||e?.some(a=>t.map(i=>i.toLowerCase()).includes(a.toLowerCase())||r.map(i=>i.toLowerCase()).includes(a.toLowerCase()));var wa=(e,t,r=[],a=[],i)=>{let{appliedFilters:s,attributes:o,keywords:n}=te(e,t,{additionalHeroes:r,additionalSets:a,today:i});return{appliedFilters:s,attributes:o,keywords:n}};var Va=(e,t)=>{let r=new Set;for(let i of e)for(let s of i.createdExtras||[])r.add(s);let a=[];for(let i of t)r.has(i.cardIdentifier)&&a.push(i);return a};0&&(module.exports={FilterCategory,FilterKind,FilterProperty,MARKUP,NO_CARD_PROPERTY,PUNCTUATION,RARITY_VALUES_MAPPING,abbreviations,aliasesByFilterCategory,availableExclusions,availableModifiers,filterCard,filtersToCardPropertyMappings,getAbbreviation,getAbbreviationByCard,getCardsByName,getCardsReferencedBy,getCardsReferencing,getCatalogueIndex,getCleanText,getEscapedForRegExp,getExcludedMetaFilters,getFilterCategory,getFilterMapping,getFilterTokenSpansForKey,getFilterValue,getIncompleteFilterToken,getIsExcludedToken,getIsValueInFilterVocabulary,getKeywordsAndAppliedFiltersFromText,getMetaFilterResolution,getMetaFilters,getNormalizedFilterValue,getNormalizedText,getParsedQuery,getQueryFilterToken,getQueryTokenSpans,getQuotedValue,getResolvedFilterKey,getSuggestedFilterKey,getTextWithoutMarkup,getTokensReferencedByCards,getUnquotedValue,getValuePartsFromFilterValue,getValuesFromFilterValue,multiWordShorthands,shorthands,singleWordShorthands});
1
+ "use strict";var Kt=Object.create;var le=Object.defineProperty;var _t=Object.getOwnPropertyDescriptor;var $t=Object.getOwnPropertyNames;var zt=Object.getPrototypeOf,Gt=Object.prototype.hasOwnProperty;var Wt=(e,t)=>{for(var r in t)le(e,r,{get:t[r],enumerable:!0})},Ye=(e,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of $t(t))!Gt.call(e,a)&&a!==r&&le(e,a,{get:()=>t[a],enumerable:!(s=_t(t,a))||s.enumerable});return e};var Yt=(e,t,r)=>(r=e!=null?Kt(zt(e)):{},Ye(t||!e||!e.__esModule?le(r,"default",{value:e,enumerable:!0}):r,e)),qt=e=>Ye(le({},"__esModule",{value:!0}),e);var Ls={};Wt(Ls,{FilterCategory:()=>l,FilterKind:()=>m,FilterProperty:()=>G,MARKUP:()=>Me,NO_CARD_PROPERTY:()=>K,PUNCTUATION:()=>k,RARITY_VALUES_MAPPING:()=>De,aliasesByFilterCategory:()=>J,availableExclusions:()=>_,availableModifiers:()=>Se,default:()=>Ht,filterCard:()=>jt,filtersToCardPropertyMappings:()=>Z,getCardsByName:()=>ye,getCardsReferencedBy:()=>Ce,getCardsReferencing:()=>me,getCatalogueIndex:()=>we,getCleanText:()=>B,getEscapedForRegExp:()=>X,getExcludedMetaFilters:()=>Ie,getFilterCategory:()=>re,getFilterMapping:()=>ge,getFilterTokenSpansForKey:()=>us,getFilterValue:()=>je,getIncompleteFilterToken:()=>He,getIsExcludedToken:()=>ps,getIsValueInFilterVocabulary:()=>ke,getKeywordsAndAppliedFiltersFromText:()=>Bs,getMetaFilterResolution:()=>se,getMetaFilters:()=>fr,getNormalizedFilterValue:()=>V,getNormalizedText:()=>z,getParsedQuery:()=>ie,getQueryFilterToken:()=>Fe,getQueryTokenSpans:()=>he,getQuotedValue:()=>fs,getResolvedFilterKey:()=>Qe,getSuggestedFilterKey:()=>Ve,getTextWithoutMarkup:()=>q,getTokensReferencedByCards:()=>Os,getUnquotedValue:()=>Te,getValuePartsFromFilterValue:()=>Ot,getValuesFromFilterValue:()=>Ue,multiWordShorthands:()=>_e,shorthands:()=>Ke,singleWordShorthands:()=>$e});module.exports=qt(Ls);var xe=require("@flesh-and-blood/types"),We=Yt(require("fuse.js"),1);var k=/[!"#$%&'’(),./:;<=>?@[\]^_`|~]/g,Me=/\*/g;var T=require("@flesh-and-blood/types");var B=e=>z(e.toLowerCase().trim().replace(k,"")),z=e=>e.normalize("NFD").replace(/\p{Diacritic}/gu,""),V=e=>e.toLowerCase().replace(k,""),q=e=>e.replace(Me,""),X=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");var l={Arcane:"arcane",Artist:"artist",Banned:"banned",Bond:"bond",Chain:"chain",Class:"class",Cost:"cost",Defense:"defense",Flow:"flow",Foiling:"foiling",Fusion:"fusion",Intellect:"intellect",Is:"is",Keyword:"keyword",Legal:"legal",Life:"life",Name:"name",Pitch:"pitch",Power:"power",Print:"print",Rarity:"rarity",ReferencedBy:"referencedby",References:"references",Set:"set",Shorthand:"shorthand",Specialization:"specialization",Subtype:"subtype",Talent:"talent",Text:"text",Trait:"trait",Treatment:"treatment",Type:"type",TypeText:"typetext",Year:"year"},m={Comparator:"comparator",ExactMatch:"exactMatch",PartialMatch:"partialMatch"},Se=[">=",">","<=","<"],_=["!","-"],K="n/a",gt=[...Object.values(T.Format),...Object.values(T.Hero)],Xt={category:l.Arcane,canonicalAlias:"arcane",kind:m.Comparator,property:"arcane",specialProperty:"specialArcane",isNumber:!0,partialMatch:!0},be={category:l.Artist,canonicalAlias:"art",kind:m.PartialMatch,property:"artists",isArray:!0,partialMatch:!0},qe={category:l.Banned,canonicalAlias:"banned",kind:m.ExactMatch,vocabulary:gt,property:K,isMeta:!0},Xe={category:l.Bond,canonicalAlias:"bond",kind:m.ExactMatch,vocabulary:Object.values(T.Bond),property:"bonds",isArray:!0},Zt={category:l.Chain,canonicalAlias:"chain",kind:m.PartialMatch,property:K},Ze={category:l.Class,canonicalAlias:"c",kind:m.PartialMatch,vocabulary:Object.values(T.Class),property:"classes",isArray:!0,partialMatch:!0},Je={category:l.Cost,canonicalAlias:"co",kind:m.Comparator,property:"cost",specialProperty:"specialCost",isNumber:!0,partialMatch:!0},te={category:l.Defense,canonicalAlias:"d",kind:m.Comparator,property:"defense",specialProperty:"specialDefense",isNumber:!0},et={category:l.Flow,canonicalAlias:"flow",kind:m.ExactMatch,vocabulary:Object.values(T.Flow),property:"flows",isArray:!0},tt={category:l.Foiling,canonicalAlias:"foil",kind:m.ExactMatch,vocabulary:Object.values(T.Foiling),nestedProperty:"foiling",property:"printings",isArray:!0},rt={category:l.Fusion,canonicalAlias:"f",kind:m.ExactMatch,vocabulary:Object.values(T.Fusion),property:"fusions",isArray:!0},st={category:l.Intellect,canonicalAlias:"i",kind:m.Comparator,property:"intellect",isNumber:!0},at={category:l.Keyword,canonicalAlias:"k",kind:m.ExactMatch,vocabulary:Object.values(T.Keyword),property:"keywords",isArray:!0},Ae={category:l.Legal,canonicalAlias:"l",kind:m.ExactMatch,vocabulary:gt,property:K,isMeta:!0},it={category:l.Life,canonicalAlias:"li",kind:m.Comparator,property:"life",specialProperty:"specialLife",isNumber:!0},nt={category:l.Is,canonicalAlias:"is",kind:m.ExactMatch,vocabulary:Object.values(T.Meta),property:"meta",isArray:!0},ot={category:l.Name,canonicalAlias:"name",kind:m.PartialMatch,property:"name",isString:!0,partialMatch:!0},Pe={category:l.Pitch,canonicalAlias:"p",kind:m.Comparator,property:"pitch",isNumber:!0},de={category:l.Power,canonicalAlias:"pwr",kind:m.Comparator,property:"power",specialProperty:"specialPower",isNumber:!0},ce={category:l.Print,canonicalAlias:"print",kind:m.PartialMatch,property:"setIdentifiers",isArray:!0,partialMatch:!0},lt={category:l.Rarity,canonicalAlias:"r",kind:m.ExactMatch,vocabulary:Object.values(T.Rarity),property:K,isMeta:!0},Jt={category:l.ReferencedBy,canonicalAlias:"referencedby",kind:m.PartialMatch,property:K},er={category:l.References,canonicalAlias:"references",kind:m.PartialMatch,property:K},dt={category:l.Set,canonicalAlias:"s",kind:m.PartialMatch,vocabulary:Object.values(T.Release),property:"sets",isArray:!0,partialMatch:!0},ve={category:l.Shorthand,canonicalAlias:"short",kind:m.PartialMatch,vocabulary:Object.values(T.Shorthand),property:"shorthands",isArray:!0,partialMatch:!0},pe={category:l.Specialization,canonicalAlias:"sp",kind:m.PartialMatch,vocabulary:Object.values(T.Hero),property:"specializations",isArray:!0,partialMatch:!0},ct={category:l.Subtype,canonicalAlias:"st",kind:m.ExactMatch,vocabulary:Object.values(T.Subtype),property:"subtypes",isArray:!0},pt={category:l.Type,canonicalAlias:"t",kind:m.ExactMatch,vocabulary:Object.values(T.Type),property:"types",isArray:!0},Re={category:l.Talent,canonicalAlias:"tal",kind:m.ExactMatch,vocabulary:Object.values(T.Talent),property:"talents",isArray:!0},tr={category:l.Text,canonicalAlias:"text",kind:m.PartialMatch,property:"functionalText",hasMarkup:!0,isString:!0,partialMatch:!0},rr={category:l.Trait,canonicalAlias:"trait",kind:m.PartialMatch,vocabulary:Object.values(T.Trait),property:"traits",isArray:!0,partialMatch:!0},ut={category:l.TypeText,canonicalAlias:"x",kind:m.PartialMatch,property:"typeText",isString:!0,partialMatch:!0},ue={category:l.Treatment,canonicalAlias:"treatment",kind:m.ExactMatch,vocabulary:Object.values(T.Treatment),nestedProperty:"treatments",property:"printings",isArray:!0,isNestedPropertyArray:!0},sr={category:l.Year,canonicalAlias:"year",kind:m.PartialMatch,property:"firstReleaseDate",isString:!0,partialMatch:!0},Z={arcane:Xt,a:be,artist:be,art:be,attack:de,b:te,block:te,banned:qe,bond:Xe,bonds:Xe,c:Ze,class:Ze,chain:Zt,co:Je,cost:Je,color:Pe,d:te,def:te,defense:te,flow:et,flows:et,f:rt,fusion:rt,foil:tt,foiling:tt,i:st,intellect:st,is:nt,k:at,keyword:at,l:Ae,legal:Ae,hero:Ae,li:it,life:it,meta:nt,n:ot,name:ot,p:Pe,pitch:Pe,pwr:de,pow:de,power:de,print:ce,printing:ce,printings:ce,prints:ce,r:lt,rarity:lt,referencedby:Jt,references:er,rf:qe,s:dt,set:dt,short:ve,shorthand:ve,shorthands:ve,sp:pe,spec:pe,specialization:pe,specializations:pe,st:ct,subtype:ct,t:pt,type:pt,tal:Re,talent:Re,talents:Re,text:tr,trait:rr,treat:ue,treatment:ue,var:ue,variation:ue,x:ut,typetext:ut,year:sr},ar=new Map(Object.entries(Z)),ge=e=>ar.get(e.toLowerCase()),re=e=>ge(e)?.category,ir=()=>{let e=Object.create(null);for(let[t,{category:r}]of Object.entries(Z)){let s=e[r];s?s.push(t):e[r]=[t]}return e},J=ir(),nr=()=>{let e=new Map,t=new Set,r=Object.values(Z);for(let s of r){let{vocabulary:a}=s;if(a&&!t.has(s)){t.add(s);for(let i of a){let n=V(i),o=e.get(n);o?o.push(s):e.set(n,[s])}}}return e},ft=nr(),ke=(e,t)=>!!ft.get(V(t))?.some(r=>r.category===e),or=(e,t)=>{let r=[],s=!0;for(let a of t){let i=(ft.get(V(a))||[]).filter(n=>n.category!==e);r=s?i:r.filter(n=>i.includes(n)),s=!1}return r},Ve=(e,t)=>{let r=or(e,t),[s]=r;return r.length===1?s.canonicalAlias:void 0};var ae=require("@flesh-and-blood/types");var d=require("@flesh-and-blood/types");var E=require("@flesh-and-blood/types");var G={BannedFormats:"bannedFormats",LegalFormats:"legalFormats",LegalHeroes:"legalHeroes"},fe=Array.from(Array(50).keys()).map(e=>`${e}`),lr=[{format:E.Format.ClassicConstructed,nicknames:["cc","classic"]},{format:E.Format.LivingLegend,nicknames:["cc ll","classic constructed ll","ll cc","ll","living legend"]},{format:E.Format.SilverAge,nicknames:["sage"]},{format:E.Format.GoldenAge,nicknames:["gage"]},{format:E.Format.UltimatePitFight,nicknames:["upf"]}],dr=Object.values(E.Format).map(e=>{let t=lr.find(({format:s})=>s===e),r=e.toLowerCase().replaceAll(k,"");return t?{...t,format:r}:{format:r}}),cr=Object.values(E.Hero).map(B),yt=e=>e.replaceAll(" ",""),pr=(e,t)=>{let r=yt(e),s,a=[];for(let n of t){let o=yt(n);o===r?s=n:o.startsWith(r)&&a.push(n)}let i=a.length===1;return s??(i?a[0]:void 0)},mt=["common","rare","super rare","majestic","legendary","fabled"],ur=({modifier:e,value:t})=>{let r=[],s=e==="<"||e==="<=",a=e===">="||e==="<=",i=s?[...mt].reverse():mt,n=!1;for(let o of i)n?r.push(o):o===t&&(n=!0,a&&r.push(o));return r},gr=(e,t)=>{let r=[];for(let s of e)s.modifier?r.push(...ur(s)):r.push(s.value);return{filterToPropertyMapping:{nestedProperty:"rarity",property:"printings",isArray:!0},isExcluded:t,isOr:!0,values:r}},Ct=(e,t,r,s)=>{let a=new Set([...cr,...r.map(B)]),i=[],n=[],o=[],c=[];for(let{value:p}of e){let g=dr.find(({format:f,nicknames:C})=>f===p||!!C&&C.includes(p));if(g)n.push(g.format);else{let f=pr(p,a);f?o.push(f):c.push(p)}}return n.length>0&&i.push({filterToPropertyMapping:{property:s,isArray:!0},values:n,isOr:!0,isExcluded:t}),o.length>0&&i.push({filterToPropertyMapping:{property:G.LegalHeroes,isArray:!0},values:o,isOr:!0,isExcluded:t}),{appliedFilters:i,unresolvedValues:c}},se=(e,t,{additionalHeroes:r=[],isExcluded:s=!1}={})=>{let a=re(e),i={appliedFilters:[],unresolvedValues:[]};return a===l.Legal?i=Ct(t,s,r,G.LegalFormats):a===l.Banned?i=Ct(t,s,r,G.BannedFormats):a===l.Rarity&&(i={appliedFilters:[gr(t,s)],unresolvedValues:[]}),i},fr=(e,t,r,s,a,i)=>se(r,s.map(n=>({modifier:a,value:n})),{additionalHeroes:i,isExcluded:e}).appliedFilters,yr=[{filterToPropertyMapping:{property:"cost",isNumber:!0},isExcluded:!0,values:fe},{filterToPropertyMapping:{property:"specialCost",isString:!0,partialMatch:!0},isExcluded:!0,values:["*","x"]},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["equipment","hero","placeholder","token","weapon"]}],mr=[{filterToPropertyMapping:{property:"defense",isNumber:!0},isExcluded:!0,values:fe},{filterToPropertyMapping:{property:"specialDefense",isString:!0,partialMatch:!0},isExcluded:!0,values:["*","x"]},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["hero","placeholder","token","weapon"]}],Cr=[{filterToPropertyMapping:{property:"pitch",isNumber:!0},isExcluded:!0,values:fe},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["equipment","hero","placeholder","token","weapon"]},{filterToPropertyMapping:{property:"isCardBack",isBoolean:!0},isExcluded:!0,values:["true"]}],hr=[{filterToPropertyMapping:{property:"power",isNumber:!0},isExcluded:!0,values:fe},{filterToPropertyMapping:{property:"specialPower",isString:!0,partialMatch:!0},isExcluded:!0,values:["*","x"]},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["equipment","hero","placeholder","token"]}],Fr=[{filterToPropertyMapping:{property:"talents",isArray:!0},isExcluded:!0,values:Object.values(E.Talent).map(e=>e.toLowerCase())}],Tr=[{filterToPropertyMapping:{property:"classes",isArray:!0},isExcluded:!0,values:Object.values(E.Class).map(e=>e.toLowerCase())}],xr=[{category:l.Class,filters:Tr},{category:l.Cost,filters:yr},{category:l.Defense,filters:mr},{category:l.Pitch,filters:Cr},{category:l.Power,filters:hr},{category:l.Talent,filters:Fr}],Mr=()=>{let e=new Map;for(let{category:t,filters:r}of xr)for(let s of J[t])for(let a of _)e.set(`${a}${s}`,r);return e},br=Mr(),Ie=e=>{let t=[],r=br.get(e);return r&&t.push(...r),t};var W=require("@flesh-and-blood/types");var Ar=3,Pr=e=>{let t=z(e.toLowerCase()).replace(/[^a-z\s-]/g,""),r=new Set;for(let s of[/[\s-]+/,/\s+/]){let a="";for(let i of t.split(s)){let n=i.replaceAll("-","");n&&(a+=n[0])}a.length>=Ar&&r.add(a)}return[...r]},ht=e=>B(e).replaceAll("-",""),Ft=(e,t,r)=>{let s=e.get(t);s?s.push(r):e.set(t,[r])},Tt=new WeakMap,j=Object.freeze([]),vr=Number.MAX_SAFE_INTEGER,xt=(e,t)=>{let r=new Map;for(let s of e)for(let a of t(s)||[]){let i=r.get(a);i?i.push(s):r.set(a,[s])}return r},Rr=e=>{let t=new Map;for(let r of e){let s=r.types.includes(W.Type.Hero)&&!r.isCardBack,a=s?W.CardRole.Hero:(0,W.getCardRole)(r);if(s||a!==W.CardRole.Hero){let n=t.get(a);n?n.push(r):t.set(a,[r])}}return t},Sr=e=>{let t,r,s,a,i,n,o,c=()=>{if(!t){let u=new Map,y=new Map,h=[],F=new Map,M=0;for(let w of e){u.set(w.cardIdentifier,w),y.set(w.cardIdentifier,M),M++;let S=B(w.name),Y=F.get(S);Y?Y.push(w):(F.set(S,[w]),h.push(S))}t={cardByCardIdentifier:u,corpusPositionByCardIdentifier:y,cleanedNames:h,pitchCycleByCleanedName:F}}return t},p=u=>{let{corpusPositionByCardIdentifier:y}=c(),h=({cardIdentifier:F})=>y.get(F)??vr;return[...u].sort((F,M)=>h(F)-h(M))},g=u=>c().cardByCardIdentifier.get(u),f=u=>{let{cardByCardIdentifier:y}=c(),h=[];for(let F of u||[]){let M=y.get(F);M&&h.push(M)}return p(h)},C=u=>{let y=new Map;return h=>{let F=y.get(h);if(!F){let M=g(h),w=f(M&&u(M)),S=w.length>0;F=S?w:j,S&&y.set(h,F)}return F}},b=u=>{let{pitchCycleByCleanedName:y}=c(),h=g(u);return h?y.get(B(h.name))??j:j},D=u=>{let{cleanedNames:y,pitchCycleByCleanedName:h}=c(),F=B(u),M=h.get(F);if(!M&&F.length>0){let S=y.find(Y=>Y.includes(F));S&&(M=h.get(S))}return M??j},I=u=>{let{pitchCycleByCleanedName:y}=c();return y.get(B(u))??j},P=u=>{if(!n){n=new Map;for(let y of e)for(let h of y.nicknames??[])Ft(n,ht(h),y)}return n.get(ht(u))??j},O=u=>{if(!o){o=new Map;for(let y of e)for(let h of Pr(y.name))Ft(o,h,y)}return o.get(u)??j},N=()=>{if(!i){let u=new Set;for(let y of e)for(let h of y.artists)u.add(h);i=[...u].sort((y,h)=>y.localeCompare(h,"en",{sensitivity:"base"}))}return i},Q=C(({oppositeSideCardIdentifiers:u})=>u),U=C(({referencedCards:u})=>u),$=u=>(r||(r=xt(e,({referencedCards:y})=>y)),r.get(u)??j),H=C(({createdExtras:u})=>u);return{cards:e,getCard:g,getPitchCycle:b,getCardsByName:D,getCardsByExactName:I,getCardsByNickname:P,getCardsByInitials:O,getArtists:N,getOppositeSide:Q,getReferences:U,getReferencedBy:$,getCreates:H,getCreatedBy:u=>(s||(s=xt(e,({createdExtras:y})=>y)),s.get(u)??j),getCreatedClosure:u=>{let y=new Map,h=new Set,F=[...u];for(let M of F)if(!h.has(M)){h.add(M);for(let S of H(M))y.set(S.cardIdentifier,S),F.push(S.cardIdentifier)}return p([...y.values()])},getByRole:u=>(a||(a=Rr(e)),a.get(u)??j),getCardsInCorpusOrder:p}},we=e=>{let t=Tt.get(e);return t||(t=Sr(e),Tt.set(e,t)),t},Ee=(e,t)=>e.getPitchCycle(t.cardIdentifier),ye=(e,t)=>e.getCardsByName(t),Mt=(e,t)=>{let r=new Map;for(let s of t)for(let a of Ee(e,s))r.set(a.cardIdentifier,a);return e.getCardsInCorpusOrder([...r.values()])},me=(e,t)=>{let r=[];for(let s of Ee(e,t))r.push(...e.getReferencedBy(s.cardIdentifier));return Mt(e,r)},Ce=(e,t)=>{let r=[];for(let s of Ee(e,t))r.push(...e.getReferences(s.cardIdentifier));return Mt(e,r)};var kr=e=>{let[t]=e,r=t?.modifier;return e.every(({modifier:a})=>a===r)?r:void 0},Be=({filterValues:e,isAnd:t,isExcluded:r,mapping:s})=>{let a=[];for(let{value:i}of e)a.push(s.hasMarkup?q(i):i);return{filterToPropertyMapping:s,filterValues:e,isAnd:t,isExcluded:r,isOr:!t&&a.length>1,modifier:kr(e),values:a}},vt=({isAnd:e,isExcluded:t,mapping:r},s)=>({filterToPropertyMapping:r,isAnd:e,isExcluded:t,isOr:!e&&s.length>1,values:s}),Vr=({category:e,filterValues:t,mapping:r})=>{let s=[];if(r.kind===m.ExactMatch&&!!r.vocabulary)for(let{value:i}of t)ke(e,i)||s.push(i);return s},Ir=e=>({appliedFilters:[Be(e)],unresolvedValues:Vr(e)}),Oe=({isExcluded:e},t,r)=>e?void 0:{[t]:r},Rt=(e,t)=>({appliedFilters:[Be(e)],attributes:Oe(e,t,e.filterValues.map(({value:r})=>r)),unresolvedValues:[]}),wr=e=>Rt(e,"artists"),Er=e=>Rt(e,"prints"),Le=(e,t,r)=>{let s=[],a=[],i=[];for(let{value:n}of e.filterValues){let o=r(n);if(o.length>0)for(let c of o)s.push(c),a.push(V(c));else i.push(n)}return{appliedFilters:[vt(e,a)],attributes:Oe(e,t,s),canonicalValues:a,unresolvedValues:i}},Nr=new Map(Object.entries({purple:4,blue:3,yellow:2,red:1,white:0})),Br=e=>{let t=[],r=[];for(let{modifier:s,value:a}of e.filterValues){let i=Nr.get(a),n=i===void 0?a:`${i}`;t.push({modifier:s,value:n}),r.push(n)}return{appliedFilters:[Be({...e,filterValues:t})],canonicalValues:r,unresolvedValues:[]}},Ne=new Map;for(let e of Object.values(d.Release)){let t=V(e),r=Ne.get(t);if(r===void 0)Ne.set(t,e);else throw new Error(`${r} and ${e} are one name as a filter reads it, so a set filter naming it could reach either`)}var bt=(e,t)=>{let r=e.get(t);return r?[r]:[]},Or=(e,t)=>{let r=[()=>bt(Ne,e),()=>bt(d.setIdentifierToSetMappings,e),()=>Object.values(d.Release).filter(a=>a.toLowerCase().includes(e)),()=>{let a=t.find(i=>V(i)===e);return a?[a]:[]}],s=[];for(let a of r)s.length===0&&s.push(...a());return s},Lr=(e,{additionalSets:t})=>Le(e,"releases",r=>Or(r,t)),Dr=new Map(Object.entries({r:d.Foiling.Rainbow,rf:d.Foiling.Rainbow,rainbow:d.Foiling.Rainbow,c:d.Foiling.Cold,cf:d.Foiling.Cold,cold:d.Foiling.Cold,g:d.Foiling.Gold,gf:d.Foiling.Gold,gold:d.Foiling.Gold})),Qr=e=>{let t=Dr.get(e);return t?[t]:[]},Hr=e=>Le(e,"foilings",Qr),St=new Map(Object.entries({aa:d.Treatment.AA,alt:d.Treatment.AA,"alt art":d.Treatment.AA,ab:d.Treatment.AB,"alt border":d.Treatment.AB,at:d.Treatment.AT,"alt text":d.Treatment.AT,ea:d.Treatment.EA,extended:d.Treatment.EA,"extended art":d.Treatment.EA,fa:d.Treatment.FA,full:d.Treatment.FA,"full art":d.Treatment.FA}));for(let e of Object.values(d.Treatment))St.set(e.toLowerCase(),e);var jr=new Map(Object.entries(d.Treatment)),Ur=e=>{let t=St.get(e)||jr.get(e.toUpperCase());return t?[t]:[]},Kr=e=>Le(e,"treatments",Ur),De=new Map(Object.entries({b:d.Rarity.Basic,c:d.Rarity.Common,f:d.Rarity.Fabled,l:d.Rarity.Legendary,m:d.Rarity.Majestic,p:d.Rarity.Promo,r:d.Rarity.Rare,s:d.Rarity.SuperRare,t:d.Rarity.Token,v:d.Rarity.Marvel})),_r=e=>De.get(e)||Object.values(d.Rarity).find(t=>t.toLowerCase()===e),$r=(e,{additionalHeroes:t})=>{let r=[],s=[],a=[],i=[];for(let{modifier:o,value:c}of e.filterValues){let p=_r(c);p?(r.push(p),s.push(p.toLowerCase()),a.push({modifier:o,value:p.toLowerCase()})):(i.push(c),a.push({modifier:o,value:c}))}let{appliedFilters:n}=se(e.key,a,{additionalHeroes:t,isExcluded:e.isExcluded});return{appliedFilters:n,attributes:Oe(e,"rarities",r),canonicalValues:s,unresolvedValues:i}},At=({filterValues:e,isExcluded:t,key:r},{additionalHeroes:s})=>{let{appliedFilters:a,unresolvedValues:i}=se(r,e,{additionalHeroes:s,isExcluded:t}),n=[];for(let{values:o}of a)n.push(...o);return{appliedFilters:a,canonicalValues:n,unresolvedValues:i}},zr=["unique"],Gr=["preview","spoiler","unreleased"],Wr=["released"],Pt={property:"firstReleaseDate",isDate:!0},Yr=new Map(Object.entries({dual:d.Meta.DualClass,exp:d.Meta.Expansion,expansion:d.Meta.Expansion,rainbow:d.Meta.Rainbow,reprint:d.Meta.Reprint,reprints:d.Meta.Reprint})),qr=e=>{let t=[],r=[];for(let a of e){let i=Yr.get(a);i?t.push(i):r.push(a)}let s=[];if(t.length===0){let a=new Set;for(let i of Object.values(d.Meta)){let n=!1;for(let o of r)i.toLowerCase().includes(o)&&(n=!0,a.add(o));n&&t.push(i)}for(let i of r)a.has(i)||s.push(i)}else s.push(...r);return{unresolvedValues:s,values:t}},Xr=(e,{today:t})=>{let{filterValues:r,isAnd:s,isExcluded:a}=e,i=[],n=[],o=[],c=[],p=[];for(let{value:P}of r)zr.includes(P)?n.push(P):Gr.includes(P)?o.push(P):Wr.includes(P)?c.push(P):p.push(P);let g=!s&&r.length>1;n.length>0&&i.push({filterToPropertyMapping:Z.is,values:[V(d.Meta.Reprint)],isAnd:s,isOr:g,isExcluded:!a}),o.length>0&&i.push({filterToPropertyMapping:Pt,values:[t],isAnd:s,isOr:g,isExcluded:a}),c.length>0&&i.push({filterToPropertyMapping:Pt,values:[t],isAnd:s,isOr:g,isExcluded:!a});let{unresolvedValues:f,values:C}=qr(p),b=[...n,...o,...c,...C.map(V)];(p.length>0||i.length===0)&&i.push(vt(e,C.map(V)));let I=C.includes(d.Meta.Expansion)&&!a;return{appliedFilters:i,attributes:I?{isExpansionSlot:I}:void 0,canonicalValues:b,unresolvedValues:f}},Zr={property:"cardIdentifier",isString:!0,isNormalized:!0},Jr=20,es=(e,t)=>{let r=new Set,s=[],a=new Set,i=[],n=p=>{r.add(p.cardIdentifier),a.has(p.name)||(a.add(p.name),s.push(p))},o=p=>{p.types.includes(d.Type.Hero)||n(p)};for(let p of t){let g=ye(e,p);for(let f of g)n(f);g.length===0&&i.push(p)}let c=0;for(;c<s.length&&c<=Jr;){let p=s[c];for(let f of Ce(e,p))o(f);if(c===0)for(let f of me(e,p))o(f);c++}return{cardIdentifiers:r,unresolvedValues:i}},kt=(e,t,r)=>{let s=new Set;for(let a of ye(e,t)){let i=r?Ce(e,a):me(e,a);for(let n of i)s.add(n.cardIdentifier)}return s},ts=(e,t)=>{let r=new Set,[s=new Set,...a]=e;if(t)for(let i of s)a.every(o=>o.has(i))&&r.add(i);else for(let i of e)for(let n of i)r.add(n);return r},Vt=(e,t)=>({filterToPropertyMapping:Zr,values:[...e],valuesSet:e,isExcluded:t,isOr:!0}),It=({filterValues:e,isAnd:t,isExcluded:r},s)=>{let a=[],i=[];for(let{value:n}of e){let o=s(n);a.push(o),o.size===0&&i.push(n)}return{appliedFilters:[Vt(ts(a,t),r)],unresolvedValues:i}},rs=(e,{index:t})=>{let{cardIdentifiers:r,unresolvedValues:s}=es(t,e.filterValues.map(({value:a})=>a));return{appliedFilters:[Vt(r,e.isExcluded)],unresolvedValues:s}},ss=(e,{index:t})=>It(e,r=>kt(t,r,!0)),as=(e,{index:t})=>It(e,r=>kt(t,r,!1)),is=new Map([[l.Artist,wr],[l.Banned,At],[l.Chain,rs],[l.Foiling,Hr],[l.Is,Xr],[l.Legal,At],[l.Pitch,Br],[l.Print,Er],[l.Rarity,$r],[l.ReferencedBy,ss],[l.References,as],[l.Set,Lr],[l.Treatment,Kr]]),wt=(e,t)=>(is.get(e.category)||Ir)(e,t);var Nt=_.map(X).join(""),ns=/(?:[^\s"]+|"[^"]*(?:"|$))+/g,os=new RegExp(`^([${Nt}])?([A-Za-z]+):(.+)$`),ls=new RegExp(`^([${Nt}])?([A-Za-z]+):$`),ds=",",Et="+",cs='"',Bt=e=>{let t=[],r=!1,s="",a=!1;for(let i of e)i===cs?(a=!a,s+=i):!a&&(i===ds||i===Et)?(r=r||i===Et,s&&t.push(s),s=""):s+=i;return s&&t.push(s),{isAndList:r,parts:t}},he=e=>{let t=[];for(let r of e.matchAll(ns))t.push({end:r.index+r[0].length,start:r.index,token:r[0]});return t},ps=e=>_.some(t=>e.startsWith(t)),Fe=e=>{let t=e.match(os),r;if(t){let[,s,a,i]=t;r={isAndList:Bt(i).isAndList,isExcluded:!!s,key:a,valueText:i}}return r},He=e=>{let t=e.match(ls),r;return t&&(r={isAndList:!1,isExcluded:!!t[1],key:t[2],valueText:""}),r},je=e=>{let t=e.trim(),r=Se.find(s=>t.startsWith(s));return{modifier:r,value:r?t.slice(r.length).trim():t}},Qe=e=>re(e)??e.toLowerCase(),us=(e,t)=>{let r=Qe(t),s=[];for(let{end:a,start:i,token:n}of he(e)){let o=Fe(n);o&&Qe(o.key)===r&&s.push({...o,end:a,start:i,token:n})}return s},Ot=e=>Bt(e).parts,Te=e=>e.replace(/^"|"$/g,""),Ue=e=>{let t=[];for(let r of Ot(e)){let s=Te(r);s&&t.push(s)}return t},gs=/[\s,:+"]/,fs=e=>{let t=e.replaceAll('"',"");return gs.test(e)?`"${t}"`:t};var L=require("@flesh-and-blood/types"),Ke=[{description:"Attack actions",expanded:["st:attack"],filters:{subtypes:[L.Subtype.Attack]},isCardProperty:!1,shorthands:["AA"]},{description:"Arcane barrier",expanded:['k:"arcane barrier"'],filters:{keywords:[L.Keyword.ArcaneBarrier]},isCardProperty:!1,shorthands:["AB"]},{description:"Attack reactions",expanded:['t:"attack reaction"'],filters:{types:[L.Type.AttackReaction]},isCardProperty:!1,shorthands:["AR"]},{description:"Defense reactions",expanded:['t:"defense reaction"'],filters:{types:[L.Type.DefenseReaction]},isCardProperty:!1,shorthands:["DR"]},{description:"Gain life",expanded:["gain {h}"],filters:{functionalText:"gain {h}"},isCardProperty:!1,shorthands:["Gain life","Gains life"]},{description:"Go again",expanded:['k:"go again"'],filters:{keywords:[L.Keyword.GoAgain]},isCardProperty:!1,shorthands:["GA"]},{description:"Non-attack actions",expanded:["t:action","st:non-attack"],filters:{subtypes:[L.Subtype.NonAttack],types:[L.Type.Action]},isCardProperty:!1,shorthands:["NAA"]},{description:"Plus defense",expanded:["+ {d}"],filters:{functionalText:"+ {d}"},isCardProperty:!1,shorthands:["Pump defense","Pumps defense","Buff defense","Buffs defense"]},{description:"Spellvoid",expanded:['k:"spellvoid"'],filters:{keywords:[L.Keyword.Spellvoid]},isCardProperty:!1,shorthands:["SV"]}],_e=Ke.filter(({shorthands:e})=>e.some(t=>t.includes(" "))).map(e=>({...e,shorthands:e.shorthands.filter(t=>t.includes(" ")).map(t=>t.toLowerCase()).sort((t,r)=>r.length-t.length)})),$e=Ke.filter(({shorthands:e})=>e.some(t=>!t.includes(" "))).map(e=>({...e,shorthands:e.shorthands.filter(t=>!t.includes(" ")).map(t=>t.toLowerCase()).sort((t,r)=>r.length-t.length)}));var ys=["\u201C","\u201D"],ms=[{text:ae.Release.ClassicBattlesRhinarDorinthea.toLowerCase(),override:ae.Release.ClassicBattlesRhinarDorinthea.toLowerCase().replaceAll(k,"")}],ze=new Map([...ae.setToSetIdentifierMappings].map(([e,t])=>[e.toLowerCase(),t])),Cs=[...J[l.Set],...J[l.Print]],hs=_.map(X).join(""),Fs=[...ze.keys()].sort((e,t)=>t.length-e.length).map(X).join("|"),Ts=new RegExp(`(?<=^|\\s)([${hs}]?(?:${Cs.join("|")}):(?:[^\\s]*[,+])?"?)(${Fs})(?="?(?:[,+]|\\s|$))`,"g"),xs=(e,t)=>{let r=e.trim().toLowerCase();for(let i of ys)r=r.replaceAll(i,'"');for(let{expanded:i,shorthands:n}of _e)for(let o of n)if(r.includes(o)){r=r.replace(o,i.join(" "));break}r=r.replace(Ts,(i,n,o)=>{let c=ze.get(o);return c?`${n}${c[0]}`:i});let s=ze.get(r),a=t.getCardsByExactName(r).length>0;s&&!a&&(r=`set:${s[0]}`);for(let{override:i,text:n}of ms)r.includes(n)&&(r=r.replace(n,i));return r},Ms=e=>{let t=$e.find(({shorthands:s})=>s.includes(e)),r=!!t&&!t.isCardProperty;return{isExpanded:r,tokens:r?t.expanded:[e]}},bs=e=>{let t=[];for(let{end:r,start:s,token:a}of he(e)){let{isExpanded:i,tokens:n}=Ms(a);for(let o of n)t.push({end:r,isExpanded:i,start:s,token:o})}return t},As=e=>{let t=[];for(let r of e){let{modifier:s,value:a}=je(r),i=V(a);i&&t.push({modifier:s,value:i})}return t},Ps=(e,t,r)=>{let s={key:e,reason:"value",values:r},a=Ve(t,r);return a&&(s.suggestedKey=a),s},vs=()=>{let e=new Date,t=`${e.getMonth()+1}`.padStart(2,"0"),r=`${e.getDate()}`.padStart(2,"0");return`${e.getFullYear()}-${t}-${r}`},ie=(e,t,{additionalHeroes:r=[],additionalSets:s=[],today:a=vs()}={})=>{let i=xs(e,t),n={additionalHeroes:r,additionalSets:s,index:t,today:a},o=[],c={artists:[],foilings:[],isExpansionSlot:!1,prints:[],rarities:[],releases:[],treatments:[]},p=[],g=[],f=[];for(let C of bs(i)){let b=Fe(C.token)||He(C.token);if(b){let{isAndList:D,isExcluded:I,key:P,valueText:O}=b,N=ge(P),Q=N?.category,U=Ue(O),$=As(U),H={...C,canonicalValues:$.map(({value:x})=>x),category:Q,filterValues:$,isAnd:D,isExcluded:I,isFilter:!0,isResolved:!0,key:P};if(U.length>0)if(N&&Q){let x=U;if($.length>0){let v=wt({category:Q,filterValues:$,isAnd:H.isAnd,isExcluded:I,key:P,mapping:N},n);o.push(...v.appliedFilters),v.canonicalValues&&(H.canonicalValues=v.canonicalValues),v.attributes&&Object.assign(c,v.attributes),x=v.unresolvedValues}x.length>0&&(H.isResolved=!1,f.push(Ps(P,Q,x)))}else H.isResolved=!1,f.push({key:P,reason:"key",values:[]});g.push(H)}else{let{end:D,start:I,token:P}=C;g.push({end:D,isFilter:!1,start:I,token:P});let O=Te(C.token),N=Ie(O);N.length>0?o.push(...N):O&&p.push(O.replace(k,""))}}return{appliedFilters:o,attributes:c,keywords:p,nodes:g,text:i,unresolvedFilters:f}};var A=require("@flesh-and-blood/types"),Lt={artists:["Hoodwill"],cardIdentifier:"fangs-a-lot-blue",classes:[A.Class.Generic],defaultImage:"FNG000",firstReleaseDate:"2022-06-02",functionalText:"If Fangs A Lot is put into your banished zone from your graveyard, instead put it into your hand.",legalFormats:[],legalHeroes:[A.Hero.Kayo,A.Hero.Levia,A.Hero.Rhinar],printings:[{artists:["Hoodwill"],identifier:"FNG000",image:"FNG000",print:"FNG000",rarity:A.Rarity.Rare,set:A.Release.Promos},{artists:["Hoodwill"],identifier:"FNG000",image:"FNG000_Marvel",print:`FNG000-${A.Treatment.FA}`,rarity:A.Rarity.Marvel,set:A.Release.Promos,treatments:[A.Treatment.FA]}],name:"Fangs A Lot",rarities:[A.Rarity.Rare,A.Rarity.Marvel],rarity:A.Rarity.Rare,sets:[A.Release.Promos],setIdentifiers:["FNG000"],specialImage:"FNG000_Marvel",subtypes:[A.Subtype.Attack],types:[A.Type.Action],typeText:"Generic Action - Attack"},Dt=[{keyword:Lt.name.toLowerCase(),card:Lt}];var Rs={getFn:(e,t)=>{let r=We.default.config.getFn(e,t),s=r;if(Array.isArray(r))s=r.map(a=>{let i=typeof a=="string"?a:a.v;return z(i.replace(k,""))});else if(r){let a=z(r).replace(k,"");s=t.includes("functionalText")?q(a):a}return s},ignoreLocation:!0,includeScore:!0,keys:[{name:"name",weight:10},{name:"functionalText",weight:6},{name:"shorthands",weight:4},{name:"setIdentifiers",weight:2},{name:"traits",weight:4},{name:"typeText",weight:6}],threshold:.15,useExtendedSearch:!0},Ge=class{constructor(t,r=[],s=[]){this.getFuse=()=>(this.fuse||(this.fuse=new We.default(this.cards,Rs)),this.fuse);this.getPoolCards=t=>{this.poolCardByCardIdentifier||(this.poolCardByCardIdentifier=new Map(this.cards.map(s=>[s.cardIdentifier,s])));let r=[];for(let{cardIdentifier:s}of t){let a=this.poolCardByCardIdentifier.get(s);a&&r.push(a)}return r};this.search=(t,r)=>{let s,a,{appliedFilters:i,attributes:n,keywords:o,unresolvedFilters:c}=ie(t,this.index,{additionalHeroes:this.additionalHeroes,additionalSets:this.additionalSets}),p=o.join(" "),g=r?Dt.filter(x=>x.keyword===p):[],f=x=>i.length>0?x.filter(v=>v&&jt(v,i)):x;if(g.length>0)s=f(g.map(({card:x})=>x));else if(o.length){let x=B(p),v=this.getPoolCards(this.index.getCardsByNickname(x)),R=new Map;for(let F of[...this.getPoolCards(this.index.getCardsByExactName(x)),...v])R.set(F.cardIdentifier,F);let u=this.getFuse().search(p).map(F=>F.item).filter(({cardIdentifier:F})=>!R.has(F));s=f([...R.values(),...u]),s.some(F=>v.includes(F))&&(a={kind:"nickname",text:x}),s.length===0&&o.length===1&&(s=f(this.getPoolCards(this.index.getCardsByInitials(x))),s.length>0&&(a={kind:"initials",text:x}))}else s=f([...this.cards]);if(!(o.length>0&&a?.kind!=="initials")){let x="";if(n.releases.length===1){let u=xe.setToSetIdentifierMappings.get(n.releases[0]);u?.length&&(x=u[0].toUpperCase())}if(!x&&n.prints.length===1){let u=n.prints[0];xe.setIdentifierToSetMappings.has(u)&&(x=u.toUpperCase())}x?s.sort((u,y)=>{let h=u.setIdentifiers.find(M=>M.includes(x))?.replace(x,""),F=y.setIdentifiers.find(M=>M.includes(x))?.replace(x,"");return h&&F?h.localeCompare(F):-1}):s.sort((u,y)=>u.name===y.name?`${u.pitch}`.localeCompare(`${y.pitch}`):u.name.localeCompare(y.name))}let b=[],{artists:D,isExpansionSlot:I,foilings:P,prints:O,rarities:N,releases:Q,treatments:U}=n;(D.length>0||I||P.length>0||O.length>0||N.length>0||Q.length>0||U.length>0)&&(b=s.map(x=>{let v=x.printings.filter(R=>{let u=!!R.image,y=D.length===0||D.some(ee=>R.artists.find(Ut=>Ut.replace(k,"").toLowerCase().includes(ee))),h=!I||I===R.isExpansionSlot,F=P.length===0||!!R.foiling&&P.includes(R.foiling),M=O.length===0||O.some(ee=>R.identifier.includes(ee.toUpperCase())),w=N.length===0||N.includes(R.rarity),S=Q.length===0||Q.includes(R.set),Y=U.length===0||R.treatments?.some(ee=>U.includes(ee));return u&&y&&h&&F&&M&&w&&S&&Y});return{...x,matchingPrintings:v}}));let H=b.length>0?b:s;return{alias:a,appliedFilters:i,attributes:n,keywords:o,searchResults:H,unresolvedFilters:c}};let a=Array.isArray(r)?{additionalHeroes:r,additionalSets:s}:r;this.additionalHeroes=a.additionalHeroes||[],this.additionalSets=a.additionalSets||[],this.cards=[...t],this.index=a.index||we(t)}},Ht=Ge,jt=(e,t)=>{let r=!0;for(let s of t){let{isNumber:a,isString:i,isArray:n,isBoolean:o,isDate:c}=s.filterToPropertyMapping;s.isOptional||(a?r=r&&Ss(e,s):i?r=r&&ks(e,s):n?r=r&&Vs(e,s,t):o?r=r&&Is(e,s):c&&(r=r&&ws(e,s)))}return r},Qt=(e,t,r)=>{let s=parseInt(t),a;switch(r){case">=":a=e>=s;break;case">":a=e>s;break;case"<=":a=e<=s;break;case"<":a=e<s;break;default:a=e===s}return a},Ss=(e,t)=>{let{filterValues:r,values:s,modifier:a,isExcluded:i,filterToPropertyMapping:{partialMatch:n}}=t,o=!0;if(oe(t,e)){let c=ne(e,t),p;if(c!=null&&!isNaN(c)){let g=parseInt(c);p=r?r.some(({modifier:f,value:C})=>Qt(g,C,f)):s.some(f=>Qt(g,f,a))}else{let g=Ns(e,t)?.toLowerCase();p=n?s.some(f=>!!g?.includes(f)):s.some(f=>g===f)}o=i?!p:p}return o},ks=(e,t)=>{if(oe(t,e)){let{values:r,valuesSet:s,isAnd:a,isExcluded:i,filterToPropertyMapping:{hasMarkup:n,isNormalized:o,partialMatch:c}}=t,p=ne(e,t),g=o?p:p?.replaceAll(k,"").toLowerCase(),f=n&&g?q(g):g;if(c){let C=a?r?.every(b=>f?.includes(b)):r?.some(b=>f?.includes(b));return i?!C:C}else{let C;return a?C=r?.every(b=>f===b):s?C=s.has(f):C=r?.some(b=>f===b),i?!C:C}}else return!0},Vs=(e,t,r)=>{if(oe(t,e)){let{values:s,isAnd:a,isExcluded:i,filterToPropertyMapping:{partialMatch:n}}=t,o=Es(e,t,r).map(c=>c?.replaceAll(k,""));if(n){let c=a?s.every(g=>o?.some(f=>f?.toLowerCase().includes(g))):s.some(g=>o?.some(f=>f?.toLowerCase().includes(g))),p=o.length===0;return i?!c||p:c}else{let c=a?s.every(p=>o?.some(g=>g?.toLowerCase()===p)):s.some(p=>o?.some(g=>g?.toLowerCase()===p));return i?!c:c}}else return!0},Is=(e,t)=>{if(oe(t,e)){let{isExcluded:r}=t,s=ne(e,t);return r?!s:s}else return!0},ws=(e,t)=>{if(oe(t,e)){let{values:r,isExcluded:s}=t,a=ne(e,t),i=r?.some(n=>a>n);return s?!i:i}else return!0},ne=(e,t)=>{let{filterToPropertyMapping:{property:r}}=t,s;return r!==K&&(s=e[r]),s},Es=(e,t,r)=>{let{filterToPropertyMapping:{isNestedPropertyArray:s,nestedProperty:a}}=t,i=[],n=Object.keys(e.legalOverrides||{}).length>0,o=t.filterToPropertyMapping.property===G.LegalHeroes,c=r.find(({filterToPropertyMapping:g})=>g.property===G.LegalFormats);if(n&&o&&!!c){let g=new Set;for(let{format:f,heroes:C}of e.legalOverrides||[])if(c.values.includes(f.toLowerCase()))for(let b of C)g.add(b);i=Array.from(g)}if(i.length===0)if(a){let g=new Set;for(let f of e.printings){let C=f[a];if(s){if(Array.isArray(C))for(let b of C)g.add(b)}else C&&typeof C=="string"&&g.add(C)}i=Array.from(g)}else{let g=ne(e,t);if(Array.isArray(g))for(let f of g)typeof f=="string"&&i.push(f)}return i},Ns=(e,t)=>{let{filterToPropertyMapping:{specialProperty:r}}=t,s;return r&&(s=e[r]),s},oe=({cardTypes:e},{types:t,subtypes:r})=>!e||e?.some(s=>t.map(a=>a.toLowerCase()).includes(s.toLowerCase())||r.map(a=>a.toLowerCase()).includes(s.toLowerCase()));var Bs=(e,t,r=[],s=[],a)=>{let{appliedFilters:i,attributes:n,keywords:o}=ie(e,t,{additionalHeroes:r,additionalSets:s,today:a});return{appliedFilters:i,attributes:n,keywords:o}};var Os=(e,t)=>{let r=new Set;for(let a of e)for(let i of a.createdExtras||[])r.add(i);let s=[];for(let a of t)r.has(a.cardIdentifier)&&s.push(a);return s};0&&(module.exports={FilterCategory,FilterKind,FilterProperty,MARKUP,NO_CARD_PROPERTY,PUNCTUATION,RARITY_VALUES_MAPPING,aliasesByFilterCategory,availableExclusions,availableModifiers,filterCard,filtersToCardPropertyMappings,getCardsByName,getCardsReferencedBy,getCardsReferencing,getCatalogueIndex,getCleanText,getEscapedForRegExp,getExcludedMetaFilters,getFilterCategory,getFilterMapping,getFilterTokenSpansForKey,getFilterValue,getIncompleteFilterToken,getIsExcludedToken,getIsValueInFilterVocabulary,getKeywordsAndAppliedFiltersFromText,getMetaFilterResolution,getMetaFilters,getNormalizedFilterValue,getNormalizedText,getParsedQuery,getQueryFilterToken,getQueryTokenSpans,getQuotedValue,getResolvedFilterKey,getSuggestedFilterKey,getTextWithoutMarkup,getTokensReferencedByCards,getUnquotedValue,getValuePartsFromFilterValue,getValuesFromFilterValue,multiWordShorthands,shorthands,singleWordShorthands});
package/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  export { default } from "./search.js";
2
- export * from "./abbreviations.js";
3
2
  export * from "./constants.js";
4
3
  export * from "./filterMappings.js";
5
4
  export * from "./filters.js";
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { default as default2 } from "./search.js";
2
- export * from "./abbreviations.js";
3
2
  export * from "./constants.js";
4
3
  export * from "./filterMappings.js";
5
4
  export * from "./filters.js";
@@ -1,5 +1,6 @@
1
1
  import { Class, Format, Hero, Talent } from "@flesh-and-blood/types";
2
2
  import { PUNCTUATION } from "./constants.js";
3
+ import { getCleanText } from "./helpers.js";
3
4
  import {
4
5
  aliasesByFilterCategory,
5
6
  availableExclusions,
@@ -47,37 +48,23 @@ const formatMappings = Object.values(Format).map((format) => {
47
48
  const cleanFormat = format.toLowerCase().replaceAll(PUNCTUATION, "");
48
49
  return withNicknames ? { ...withNicknames, format: cleanFormat } : { format: cleanFormat };
49
50
  });
50
- const nicknameHeroMappings = [
51
- {
52
- hero: Hero.DataDoll,
53
- nicknames: ["data", "datadoll"]
54
- },
55
- {
56
- hero: Hero.Dorinthea,
57
- nicknames: ["dori"]
58
- },
59
- {
60
- hero: Hero.Genis,
61
- nicknames: ["genis"]
62
- },
63
- {
64
- hero: Hero.GravyBones,
65
- nicknames: ["gravy"]
66
- },
67
- {
68
- hero: Hero.Iyslander,
69
- nicknames: ["islander"]
51
+ const cleanHeroes = Object.values(Hero).map(getCleanText);
52
+ const getTextWithoutSpaces = (text) => text.replaceAll(" ", "");
53
+ const getMatchingHero = (value, heroes) => {
54
+ const valueWithoutSpaces = getTextWithoutSpaces(value);
55
+ let wholeNameMatch;
56
+ const heroesStartingWithValue = [];
57
+ for (const hero of heroes) {
58
+ const heroWithoutSpaces = getTextWithoutSpaces(hero);
59
+ if (heroWithoutSpaces === valueWithoutSpaces) {
60
+ wholeNameMatch = hero;
61
+ } else if (heroWithoutSpaces.startsWith(valueWithoutSpaces)) {
62
+ heroesStartingWithValue.push(hero);
63
+ }
70
64
  }
71
- ];
72
- const heroMappings = Object.values(
73
- Hero
74
- ).map((hero) => {
75
- const withNicknames = nicknameHeroMappings.find(
76
- ({ hero: nicknameHero }) => nicknameHero === hero
77
- );
78
- const cleanHero = hero.toLowerCase().replaceAll(PUNCTUATION, "");
79
- return withNicknames ? { ...withNicknames, hero: cleanHero } : { hero: cleanHero };
80
- });
65
+ const hasOneHeroStartingWithValue = heroesStartingWithValue.length === 1;
66
+ return wholeNameMatch ?? (hasOneHeroStartingWithValue ? heroesStartingWithValue[0] : void 0);
67
+ };
81
68
  const rankedRarity = [
82
69
  "common",
83
70
  "rare",
@@ -128,9 +115,10 @@ const getRarityFilter = (values, isExcluded) => {
128
115
  };
129
116
  };
130
117
  const getLegalityFilters = (values, isExcluded, additionalHeroes, formatProperty) => {
131
- const cleanAdditionalHeroes = additionalHeroes.map((hero) => ({
132
- hero: hero.toLowerCase().replaceAll(PUNCTUATION, "")
133
- }));
118
+ const knownHeroes = /* @__PURE__ */ new Set([
119
+ ...cleanHeroes,
120
+ ...additionalHeroes.map(getCleanText)
121
+ ]);
134
122
  const appliedFilters = [];
135
123
  const formats = [];
136
124
  const heroes = [];
@@ -143,12 +131,9 @@ const getLegalityFilters = (values, isExcluded, additionalHeroes, formatProperty
143
131
  if (matchingFormat) {
144
132
  formats.push(matchingFormat.format);
145
133
  } else {
146
- const matchingHero = heroMappings.find(({ hero, nicknames }) => {
147
- const isAMatch = hero === value || !!nicknames && nicknames.includes(value);
148
- return isAMatch;
149
- }) || cleanAdditionalHeroes.find(({ hero }) => hero === value);
134
+ const matchingHero = getMatchingHero(value, knownHeroes);
150
135
  if (matchingHero) {
151
- heroes.push(matchingHero.hero);
136
+ heroes.push(matchingHero);
152
137
  } else {
153
138
  unresolvedValues.push(value);
154
139
  }
@@ -2,7 +2,6 @@ import {
2
2
  Release,
3
3
  setToSetIdentifierMappings
4
4
  } from "@flesh-and-blood/types";
5
- import { getAbbreviation } from "./abbreviations.js";
6
5
  import { PUNCTUATION } from "./constants.js";
7
6
  import {
8
7
  aliasesByFilterCategory,
@@ -55,7 +54,7 @@ const setNameInSetFilterPattern = new RegExp(
55
54
  )}):(?:[^\\s]*[,+])?"?)(${setNamesLongestFirst})(?="?(?:[,+]|\\s|$))`,
56
55
  "g"
57
56
  );
58
- const getPreparedQuery = (text, index) => {
57
+ const getPreparedText = (text, index) => {
59
58
  let preparedText = text.trim().toLowerCase();
60
59
  for (const smartQuote of SMART_DOUBLE_QUOTES) {
61
60
  preparedText = preparedText.replaceAll(smartQuote, '"');
@@ -85,12 +84,7 @@ const getPreparedQuery = (text, index) => {
85
84
  preparedText = preparedText.replace(punctuatedName, override);
86
85
  }
87
86
  }
88
- return {
89
- // A query that is nothing but a card's abbreviation names that card whole,
90
- // so its own spaces and commas are not separators.
91
- isWholeQueryAbbreviation: !!getAbbreviation(preparedText)?.card,
92
- text: preparedText
93
- };
87
+ return preparedText;
94
88
  };
95
89
  const getExpandedTokens = (token) => {
96
90
  const matchingShorthand = singleWordShorthands.find(
@@ -102,13 +96,9 @@ const getExpandedTokens = (token) => {
102
96
  tokens: isExpanded ? matchingShorthand.expanded : [token]
103
97
  };
104
98
  };
105
- const getQueryTermSpans = ({
106
- isWholeQueryAbbreviation,
107
- text
108
- }) => {
99
+ const getQueryTermSpans = (text) => {
109
100
  const termSpans = [];
110
- const tokenSpans = isWholeQueryAbbreviation ? [{ end: text.length, start: 0, token: text }] : getQueryTokenSpans(text);
111
- for (const { end, start, token } of tokenSpans) {
101
+ for (const { end, start, token } of getQueryTokenSpans(text)) {
112
102
  const { isExpanded, tokens } = getExpandedTokens(token);
113
103
  for (const expandedToken of tokens) {
114
104
  termSpans.push({ end, isExpanded, start, token: expandedToken });
@@ -146,7 +136,7 @@ const getParsedQuery = (text, index, {
146
136
  additionalSets = [],
147
137
  today = getTodayAsReleaseDate()
148
138
  } = {}) => {
149
- const preparedQuery = getPreparedQuery(text, index);
139
+ const preparedText = getPreparedText(text, index);
150
140
  const context = {
151
141
  additionalHeroes,
152
142
  additionalSets,
@@ -166,7 +156,7 @@ const getParsedQuery = (text, index, {
166
156
  const keywords = [];
167
157
  const nodes = [];
168
158
  const unresolvedFilters = [];
169
- for (const termSpan of getQueryTermSpans(preparedQuery)) {
159
+ for (const termSpan of getQueryTermSpans(preparedText)) {
170
160
  const filterToken = getQueryFilterToken(termSpan.token) || getIncompleteFilterToken(termSpan.token);
171
161
  if (filterToken) {
172
162
  const { isAndList, isExcluded, key, valueText } = filterToken;
@@ -225,13 +215,8 @@ const getParsedQuery = (text, index, {
225
215
  const { end, start, token } = termSpan;
226
216
  nodes.push({ end, isFilter: false, start, token });
227
217
  const freeText = getUnquotedValue(termSpan.token);
228
- const abbreviatedCard = getAbbreviation(freeText)?.card;
229
218
  const excludedMetaFilters = getExcludedMetaFilters(freeText);
230
- if (abbreviatedCard) {
231
- keywords.push(
232
- `"${abbreviatedCard.toLowerCase().replace(PUNCTUATION, "")}"`
233
- );
234
- } else if (excludedMetaFilters.length > 0) {
219
+ if (excludedMetaFilters.length > 0) {
235
220
  appliedFilters.push(...excludedMetaFilters);
236
221
  } else if (freeText) {
237
222
  keywords.push(freeText.replace(PUNCTUATION, ""));
@@ -243,7 +228,7 @@ const getParsedQuery = (text, index, {
243
228
  attributes,
244
229
  keywords,
245
230
  nodes,
246
- text: preparedQuery.text,
231
+ text: preparedText,
247
232
  unresolvedFilters
248
233
  };
249
234
  };
package/dist/search.d.ts CHANGED
@@ -8,7 +8,6 @@ export interface SearchCard extends DoubleSidedCard {
8
8
  export interface SearchOptions {
9
9
  additionalHeroes?: Hero[];
10
10
  additionalSets?: Release[];
11
- debug?: boolean;
12
11
  /**
13
12
  * The catalogue the parser resolves names and relations against. A pool
14
13
  * searched out of a larger catalogue shares the catalogue's index, so a
@@ -19,7 +18,14 @@ export interface SearchOptions {
19
18
  */
20
19
  index?: CatalogueIndex;
21
20
  }
21
+ /** How the free text named cards other than by their names. */
22
+ export interface SearchAlias {
23
+ kind: "nickname" | "initials";
24
+ text: string;
25
+ }
22
26
  export interface SearchResults {
27
+ /** Set when the free text was a nickname or the initials of the cards found. */
28
+ alias?: SearchAlias;
23
29
  appliedFilters: AppliedFilter[];
24
30
  keywords: string[];
25
31
  attributes: QueryAttributes;
@@ -34,13 +40,17 @@ declare class Search {
34
40
  private additionalHeroes;
35
41
  private additionalSets;
36
42
  private cards;
37
- private debug;
38
43
  private fuse;
39
44
  private index;
45
+ private poolCardByCardIdentifier;
40
46
  constructor(cards: DoubleSidedCard[], options?: SearchOptions);
41
- constructor(cards: DoubleSidedCard[], additionalHeroes?: Hero[], additionalSets?: Release[], debug?: boolean);
47
+ constructor(cards: DoubleSidedCard[], additionalHeroes?: Hero[], additionalSets?: Release[]);
42
48
  private getFuse;
43
- log: (message?: unknown, ...optionalParams: unknown[]) => void;
49
+ /**
50
+ * The pool's own copies of index cards, dropping any the pool lacks, so a pool
51
+ * searched out of a larger catalogue returns its cards alone.
52
+ */
53
+ private getPoolCards;
44
54
  search: (text: string, includeMemes?: boolean) => SearchResults;
45
55
  }
46
56
  export default Search;
package/dist/search.js CHANGED
@@ -11,7 +11,11 @@ import {
11
11
  getParsedQuery
12
12
  } from "./queryParse.js";
13
13
  import { memes } from "./memes.js";
14
- import { getNormalizedText, getTextWithoutMarkup } from "./helpers.js";
14
+ import {
15
+ getCleanText,
16
+ getNormalizedText,
17
+ getTextWithoutMarkup
18
+ } from "./helpers.js";
15
19
  import { FilterProperty } from "./metaFilters.js";
16
20
  import { getCatalogueIndex } from "./searchIndex.js";
17
21
  const searchOptions = {
@@ -19,9 +23,10 @@ const searchOptions = {
19
23
  const value = Fuse.config.getFn(obj, path);
20
24
  let normalizedValue = value;
21
25
  if (Array.isArray(value)) {
22
- normalizedValue = value.map(
23
- (val) => getNormalizedText(val.replace(PUNCTUATION, ""))
24
- );
26
+ normalizedValue = value.map((item) => {
27
+ const text = typeof item === "string" ? item : item.v;
28
+ return getNormalizedText(text.replace(PUNCTUATION, ""));
29
+ });
25
30
  } else if (value) {
26
31
  const text = getNormalizedText(value).replace(PUNCTUATION, "");
27
32
  normalizedValue = path.includes("functionalText") ? getTextWithoutMarkup(text) : text;
@@ -42,7 +47,7 @@ const searchOptions = {
42
47
  useExtendedSearch: true
43
48
  };
44
49
  class Search {
45
- constructor(cards, additionalHeroesOrOptions = [], additionalSets = [], debug = false) {
50
+ constructor(cards, additionalHeroesOrOptions = [], additionalSets = []) {
46
51
  // Scoring the corpus is the costly half of a search, so a catalogue that is
47
52
  // only ever filtered never pays to index it.
48
53
  this.getFuse = () => {
@@ -51,32 +56,78 @@ class Search {
51
56
  }
52
57
  return this.fuse;
53
58
  };
54
- this.log = (message, ...optionalParams) => {
55
- if (this.debug) {
56
- console.log(message, ...optionalParams);
59
+ /**
60
+ * The pool's own copies of index cards, dropping any the pool lacks, so a pool
61
+ * searched out of a larger catalogue returns its cards alone.
62
+ */
63
+ this.getPoolCards = (indexCards) => {
64
+ if (!this.poolCardByCardIdentifier) {
65
+ this.poolCardByCardIdentifier = new Map(
66
+ this.cards.map((card) => [card.cardIdentifier, card])
67
+ );
68
+ }
69
+ const poolCards = [];
70
+ for (const { cardIdentifier } of indexCards) {
71
+ const poolCard = this.poolCardByCardIdentifier.get(cardIdentifier);
72
+ if (poolCard) {
73
+ poolCards.push(poolCard);
74
+ }
57
75
  }
76
+ return poolCards;
58
77
  };
59
78
  this.search = (text, includeMemes) => {
60
79
  let results;
80
+ let alias;
61
81
  const { appliedFilters, attributes, keywords, unresolvedFilters } = getParsedQuery(text, this.index, {
62
82
  additionalHeroes: this.additionalHeroes,
63
83
  additionalSets: this.additionalSets
64
84
  });
65
85
  const keyword = keywords.join(" ");
66
86
  const matchingMemes = includeMemes ? memes.filter((meme) => meme.keyword === keyword) : [];
87
+ const getFilteredCards = (cardsToFilter) => appliedFilters.length > 0 ? cardsToFilter.filter(
88
+ (card) => card && filterCard(card, appliedFilters)
89
+ ) : cardsToFilter;
67
90
  if (matchingMemes.length > 0) {
68
- results = matchingMemes.map(({ card }) => card);
91
+ results = getFilteredCards(matchingMemes.map(({ card }) => card));
69
92
  } else if (keywords.length) {
70
- results = this.getFuse().search(keyword).map((result) => result.item);
71
- } else {
72
- results = [...this.cards];
73
- }
74
- if (appliedFilters.length) {
75
- results = results.filter(
76
- (card) => card && filterCard(card, appliedFilters)
93
+ const freeText = getCleanText(keyword);
94
+ const nicknamedCards = this.getPoolCards(
95
+ this.index.getCardsByNickname(freeText)
96
+ );
97
+ const namedCardByCardIdentifier = /* @__PURE__ */ new Map();
98
+ for (const card of [
99
+ ...this.getPoolCards(this.index.getCardsByExactName(freeText)),
100
+ ...nicknamedCards
101
+ ]) {
102
+ namedCardByCardIdentifier.set(card.cardIdentifier, card);
103
+ }
104
+ const textMatches = this.getFuse().search(keyword).map((result) => result.item).filter(
105
+ ({ cardIdentifier }) => !namedCardByCardIdentifier.has(cardIdentifier)
77
106
  );
107
+ results = getFilteredCards([
108
+ ...namedCardByCardIdentifier.values(),
109
+ ...textMatches
110
+ ]);
111
+ const hasNicknamedResult = results.some(
112
+ (card) => nicknamedCards.includes(card)
113
+ );
114
+ if (hasNicknamedResult) {
115
+ alias = { kind: "nickname", text: freeText };
116
+ }
117
+ const canFallBackToInitials = results.length === 0 && keywords.length === 1;
118
+ if (canFallBackToInitials) {
119
+ results = getFilteredCards(
120
+ this.getPoolCards(this.index.getCardsByInitials(freeText))
121
+ );
122
+ if (results.length > 0) {
123
+ alias = { kind: "initials", text: freeText };
124
+ }
125
+ }
126
+ } else {
127
+ results = getFilteredCards([...this.cards]);
78
128
  }
79
- if (keywords.length === 0) {
129
+ const isRankedByText = keywords.length > 0 && alias?.kind !== "initials";
130
+ if (!isRankedByText) {
80
131
  let setIdentifierToSortBy = "";
81
132
  const shouldSortByRelease = attributes.releases.length === 1;
82
133
  if (shouldSortByRelease) {
@@ -105,18 +156,6 @@ class Search {
105
156
  (c1, c2) => c1.name === c2.name ? `${c1.pitch}`.localeCompare(`${c2.pitch}`) : c1.name.localeCompare(c2.name)
106
157
  );
107
158
  }
108
- } else {
109
- const nameMatches = [];
110
- const nonMatches = [];
111
- const potentialCardName = keywords.map((keyword2) => keyword2.toLowerCase().replace(PUNCTUATION, "")).join(" ");
112
- for (const card of results) {
113
- if (card.name.toLowerCase().replace(PUNCTUATION, "") === potentialCardName) {
114
- nameMatches.push(card);
115
- } else {
116
- nonMatches.push(card);
117
- }
118
- }
119
- results = [...nameMatches, ...nonMatches];
120
159
  }
121
160
  let searchResultsWithMatchingPrinting = [];
122
161
  const {
@@ -159,6 +198,7 @@ class Search {
159
198
  }
160
199
  const searchResults = searchResultsWithMatchingPrinting.length > 0 ? searchResultsWithMatchingPrinting : results;
161
200
  return {
201
+ alias,
162
202
  appliedFilters,
163
203
  attributes,
164
204
  keywords,
@@ -166,11 +206,10 @@ class Search {
166
206
  unresolvedFilters
167
207
  };
168
208
  };
169
- const options = Array.isArray(additionalHeroesOrOptions) ? { additionalHeroes: additionalHeroesOrOptions, additionalSets, debug } : additionalHeroesOrOptions;
209
+ const options = Array.isArray(additionalHeroesOrOptions) ? { additionalHeroes: additionalHeroesOrOptions, additionalSets } : additionalHeroesOrOptions;
170
210
  this.additionalHeroes = options.additionalHeroes || [];
171
211
  this.additionalSets = options.additionalSets || [];
172
212
  this.cards = [...cards];
173
- this.debug = options.debug || false;
174
213
  this.index = options.index || getCatalogueIndex(cards);
175
214
  }
176
215
  }
@@ -26,6 +26,13 @@ export interface CatalogueIndex<CardType extends DoubleSidedCard = DoubleSidedCa
26
26
  * a fragment of a name the corpus carries finds nothing.
27
27
  */
28
28
  getCardsByExactName: (name: string) => readonly CardType[];
29
+ /** Every card carrying the nickname, matched whole, hyphens ignored. */
30
+ getCardsByNickname: (nickname: string) => readonly CardType[];
31
+ /**
32
+ * Every card whose name has the initials, in corpus order, counting a
33
+ * hyphenated word both as one word and as the words the hyphens join.
34
+ */
35
+ getCardsByInitials: (initials: string) => readonly CardType[];
29
36
  /**
30
37
  * Every artist the corpus credits, each once, ordered by the `en` locale
31
38
  * ignoring case and diacritics so a browser and a server agree on the list.
@@ -3,7 +3,37 @@ import {
3
3
  getCardRole,
4
4
  Type
5
5
  } from "@flesh-and-blood/types";
6
- import { getCleanText } from "./helpers.js";
6
+ import { getCleanText, getNormalizedText } from "./helpers.js";
7
+ const MINIMUM_INITIALS_LENGTH = 3;
8
+ const getInitialsOfName = (name) => {
9
+ const letters = getNormalizedText(name.toLowerCase()).replace(
10
+ /[^a-z\s-]/g,
11
+ ""
12
+ );
13
+ const initialsOfName = /* @__PURE__ */ new Set();
14
+ for (const wordBreak of [/[\s-]+/, /\s+/]) {
15
+ let initials = "";
16
+ for (const word of letters.split(wordBreak)) {
17
+ const wordLetters = word.replaceAll("-", "");
18
+ if (wordLetters) {
19
+ initials += wordLetters[0];
20
+ }
21
+ }
22
+ if (initials.length >= MINIMUM_INITIALS_LENGTH) {
23
+ initialsOfName.add(initials);
24
+ }
25
+ }
26
+ return [...initialsOfName];
27
+ };
28
+ const getNicknameKey = (nickname) => getCleanText(nickname).replaceAll("-", "");
29
+ const addToCardList = (cardsByKey, key, card) => {
30
+ const cardsForKey = cardsByKey.get(key);
31
+ if (cardsForKey) {
32
+ cardsForKey.push(card);
33
+ } else {
34
+ cardsByKey.set(key, [card]);
35
+ }
36
+ };
7
37
  const catalogueIndexByCards = /* @__PURE__ */ new WeakMap();
8
38
  const noCards = Object.freeze([]);
9
39
  const strayCorpusPosition = Number.MAX_SAFE_INTEGER;
@@ -44,6 +74,8 @@ const getNewCatalogueIndex = (cards) => {
44
74
  let creatingCardsByCardIdentifier;
45
75
  let cardsByRole;
46
76
  let artists;
77
+ let cardsByNicknameKey;
78
+ let cardsByInitials;
47
79
  const getCardLookups = () => {
48
80
  if (!cardLookups) {
49
81
  const cardByCardIdentifier = /* @__PURE__ */ new Map();
@@ -132,6 +164,28 @@ const getNewCatalogueIndex = (cards) => {
132
164
  const { pitchCycleByCleanedName } = getCardLookups();
133
165
  return pitchCycleByCleanedName.get(getCleanText(name)) ?? noCards;
134
166
  };
167
+ const getCardsByNickname = (nickname) => {
168
+ if (!cardsByNicknameKey) {
169
+ cardsByNicknameKey = /* @__PURE__ */ new Map();
170
+ for (const card of cards) {
171
+ for (const cardNickname of card.nicknames ?? []) {
172
+ addToCardList(cardsByNicknameKey, getNicknameKey(cardNickname), card);
173
+ }
174
+ }
175
+ }
176
+ return cardsByNicknameKey.get(getNicknameKey(nickname)) ?? noCards;
177
+ };
178
+ const getCardsByInitials = (initials) => {
179
+ if (!cardsByInitials) {
180
+ cardsByInitials = /* @__PURE__ */ new Map();
181
+ for (const card of cards) {
182
+ for (const initialsOfName of getInitialsOfName(card.name)) {
183
+ addToCardList(cardsByInitials, initialsOfName, card);
184
+ }
185
+ }
186
+ }
187
+ return cardsByInitials.get(initials) ?? noCards;
188
+ };
135
189
  const getArtists = () => {
136
190
  if (!artists) {
137
191
  const creditedArtists = /* @__PURE__ */ new Set();
@@ -202,6 +256,8 @@ const getNewCatalogueIndex = (cards) => {
202
256
  getPitchCycle,
203
257
  getCardsByName: getCardsByName2,
204
258
  getCardsByExactName,
259
+ getCardsByNickname,
260
+ getCardsByInitials,
205
261
  getArtists,
206
262
  getOppositeSide,
207
263
  getReferences,
@@ -15,7 +15,6 @@ export declare const shorthands: {
15
15
  shorthands: string[];
16
16
  }[];
17
17
  export declare const multiWordShorthands: {
18
- shorthands: string[];
19
18
  description: string;
20
19
  expanded: string[];
21
20
  filters: {
@@ -28,9 +27,9 @@ export declare const multiWordShorthands: {
28
27
  types?: Type[];
29
28
  };
30
29
  isCardProperty: boolean;
30
+ shorthands: string[];
31
31
  }[];
32
32
  export declare const singleWordShorthands: {
33
- shorthands: string[];
34
33
  description: string;
35
34
  expanded: string[];
36
35
  filters: {
@@ -43,4 +42,5 @@ export declare const singleWordShorthands: {
43
42
  types?: Type[];
44
43
  };
45
44
  isCardProperty: boolean;
45
+ shorthands: string[];
46
46
  }[];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@flesh-and-blood/search",
3
3
  "description": "TypeScript search engine for Flesh and Blood cards",
4
- "version": "5.2.8",
4
+ "version": "5.3.1",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "main": "dist/index.cjs",
@@ -31,30 +31,28 @@
31
31
  "build": "npm run build:esm && npm run build:cjs",
32
32
  "build:esm": "esbuild src/*.ts --outdir=dist --format=esm --platform=neutral --target=es2020",
33
33
  "build:cjs": "esbuild src/index.ts --outfile=dist/index.cjs --bundle --minify --format=cjs --platform=node --target=es2020 --external:@flesh-and-blood/types --external:fuse.js",
34
- "postbuild": "tsc --declaration && npm test",
35
- "test": "jest",
36
- "test:specific": "jest -t 'Matching printing from treatment'",
34
+ "postbuild": "tsc --declaration",
35
+ "test": "vitest run",
36
+ "test:specific": "vitest run -t 'Matching printing from treatment'",
37
+ "update:snapshots": "vitest run -u",
37
38
  "typecheck": "tsc -p tsconfig.typecheck.json",
38
- "full": "npm i && npm run build",
39
+ "full": "npm run build && npm test",
39
40
  "prepublish": "npm run full",
40
41
  "prepublishOnly": "npm run typecheck"
41
42
  },
42
43
  "dependencies": {
43
- "fuse.js": "^6.6.2"
44
+ "fuse.js": "^7.5.0"
44
45
  },
45
46
  "peerDependencies": {
46
47
  "@flesh-and-blood/types": "^5.0.0"
47
48
  },
48
49
  "devDependencies": {
49
- "@flesh-and-blood/cards": "^5.2.8",
50
- "@flesh-and-blood/types": "^5.2.1",
51
- "@types/jest": "^29.5.11",
52
- "@types/node": "^20.10.5",
53
- "esbuild": "^0.19.10",
54
- "esbuild-jest": "^0.5.0",
55
- "jest": "^29.7.0",
56
- "ts-node": "^10.9.2",
57
- "typescript": "^5.7.3"
50
+ "@flesh-and-blood/cards": "^5.3.1",
51
+ "@flesh-and-blood/types": "^5.3.0",
52
+ "@types/node": "^26.6.3",
53
+ "esbuild": "^0.28.2",
54
+ "typescript": "^7.0.2",
55
+ "vitest": "^5.0.3"
58
56
  },
59
57
  "files": [
60
58
  "/dist"
@@ -77,5 +75,5 @@
77
75
  "FAB",
78
76
  "FABTCG"
79
77
  ],
80
- "gitHead": "187092ef142bbe4745d62913e194024feeffb289"
78
+ "gitHead": "43349d8a88ac6e277f32c20b5cf36f373efb45e5"
81
79
  }
@@ -1,9 +0,0 @@
1
- import { Card } from "@flesh-and-blood/types";
2
- export interface Abbreviation {
3
- abbreviations: string[];
4
- card: string;
5
- isHidden?: boolean;
6
- }
7
- export declare const getAbbreviation: (abbreviation: string) => Abbreviation | undefined;
8
- export declare const getAbbreviationByCard: (c: Card) => Abbreviation | undefined;
9
- export declare const abbreviations: Abbreviation[];
@@ -1,385 +0,0 @@
1
- const getAbbreviation = (abbreviation) => {
2
- return abbreviations.find(
3
- ({ abbreviations: abbreviations2 }) => abbreviations2.find((a) => a.toLowerCase() === abbreviation)
4
- );
5
- };
6
- const getAbbreviationByCard = (c) => {
7
- return abbreviations.find(
8
- ({ card }) => card.toLowerCase() === c.name.toLowerCase()
9
- );
10
- };
11
- const abbreviations = [
12
- {
13
- abbreviations: ["10k"],
14
- card: "10,000 Year Reunion"
15
- },
16
- {
17
- abbreviations: ["Pajamas", "PJs"],
18
- card: "Alluvion Constellas"
19
- },
20
- {
21
- abbreviations: [
22
- "Slippy",
23
- "Arakni Slipped Through the Cracks",
24
- "Arakni, Slipped Through the Cracks"
25
- ],
26
- card: "Arakni, 5L!p3d 7hRu 7h3 cR4X"
27
- },
28
- {
29
- abbreviations: ["Dullcap"],
30
- card: "Arcanite Skullcap"
31
- },
32
- {
33
- abbreviations: ["ALS"],
34
- card: "Arc Light Sentinel"
35
- },
36
- {
37
- abbreviations: ["AoW"],
38
- card: "Art of War"
39
- },
40
- {
41
- abbreviations: ["BBD"],
42
- card: "Barraging Beatdown"
43
- },
44
- {
45
- abbreviations: ["BBS"],
46
- card: "Big Blue Sky"
47
- },
48
- {
49
- abbreviations: ["Starvo"],
50
- card: "Bravo, Star of the Show"
51
- },
52
- {
53
- abbreviations: ["BEB"],
54
- card: "Bull's Eye Bracers"
55
- },
56
- {
57
- abbreviations: ["BLW"],
58
- card: "Be Like Water"
59
- },
60
- {
61
- abbreviations: ["BoJ"],
62
- card: "Balance of Justice"
63
- },
64
- {
65
- abbreviations: ["BOHH"],
66
- card: "Blood on Her Hands"
67
- },
68
- {
69
- abbreviations: ["BRB"],
70
- card: "Bloodrush Bellow"
71
- },
72
- {
73
- abbreviations: ["Breezies"],
74
- card: "Breeze Rider Boots"
75
- },
76
- {
77
- abbreviations: ["BTA"],
78
- card: "Burn Them All"
79
- },
80
- {
81
- abbreviations: ["CStrike", "C-Strike", "C Strike"],
82
- card: "Celestial Cataclysm"
83
- },
84
- { abbreviations: ["CBelly"], card: "Cerebellum Processor" },
85
- {
86
- abbreviations: ["CLF"],
87
- card: "Channel Lake Frigid"
88
- },
89
- {
90
- abbreviations: ["CLV"],
91
- card: "Channel Lightning Valley"
92
- },
93
- {
94
- abbreviations: ["CMH"],
95
- card: "Channel Mount Heroic"
96
- },
97
- {
98
- abbreviations: ["CMI"],
99
- card: "Channel Mount Isen"
100
- },
101
- {
102
- abbreviations: ["CMT"],
103
- card: "Channel the Millennium Tree"
104
- },
105
- {
106
- abbreviations: ["CnC", "C&C"],
107
- card: "Command and Conquer"
108
- },
109
- {
110
- abbreviations: ["Sea and Sea"],
111
- card: "Conqueror of the High Seas"
112
- },
113
- {
114
- abbreviations: ["CYB"],
115
- card: "Count Your Blessings"
116
- },
117
- {
118
- abbreviations: ["Cat", "Kitty"],
119
- card: "Crouching Tiger"
120
- },
121
- {
122
- abbreviations: ["CoD"],
123
- card: "Crown of Dominion"
124
- },
125
- {
126
- abbreviations: ["CoP"],
127
- card: "Crown of Providence"
128
- },
129
- {
130
- abbreviations: ["CtW"],
131
- card: "Crush the Weak"
132
- },
133
- {
134
- abbreviations: ["DD"],
135
- card: "Death Dealer"
136
- },
137
- {
138
- abbreviations: ["DnD"],
139
- card: "Devotion Never Dies"
140
- },
141
- {
142
- abbreviations: ["DIO"],
143
- card: "Dash I/O"
144
- },
145
- {
146
- abbreviations: ["EBTT"],
147
- card: "Even Bigger Than That!"
148
- },
149
- {
150
- abbreviations: ["NewNigma"],
151
- card: "Enigma, New Moon"
152
- },
153
- {
154
- abbreviations: ["EPot", "E Pot"],
155
- card: "Energy Potion"
156
- },
157
- {
158
- abbreviations: ["EStrike", "E-Strike", "E Strike"],
159
- card: "Enlightened Strike"
160
- },
161
- {
162
- abbreviations: ["FFS"],
163
- card: "Fyendal's Fighting Spirit"
164
- },
165
- {
166
- abbreviations: ["FoN"],
167
- card: "Force of Nature"
168
- },
169
- {
170
- abbreviations: ["Frosty", "\u{1F976}", "\u{1F9CA}", "\u2744\uFE0F"],
171
- card: "Frostbite"
172
- },
173
- {
174
- abbreviations: ["Yum yum"],
175
- card: "Fruits of the Forest"
176
- },
177
- {
178
- abbreviations: ["GnT"],
179
- card: "Give and Take"
180
- },
181
- { abbreviations: ["Habibi"], card: "Hanabi Blaster" },
182
- {
183
- abbreviations: ["HMH"],
184
- card: "Hope Merchant's Hood"
185
- },
186
- {
187
- abbreviations: ["HoI"],
188
- card: "Heart of Ice"
189
- },
190
- {
191
- abbreviations: ["Pumpkin"],
192
- card: "Jack-o'-lantern"
193
- },
194
- {
195
- abbreviations: ["RKO", "Cheato"],
196
- card: "Kayo, Underhanded Cheat"
197
- },
198
- {
199
- abbreviations: ["KKBB"],
200
- card: "Knick Knack Bric-a-brac"
201
- },
202
- {
203
- abbreviations: ["BStrike"],
204
- card: "Levels of Enlightenment"
205
- },
206
- {
207
- abbreviations: ["LAG", "Twominaris"],
208
- card: "Luminaris, Angel's Glow"
209
- },
210
- {
211
- abbreviations: ["LCF", "Newminaris"],
212
- card: "Luminaris, Celestial Fury"
213
- },
214
- {
215
- abbreviations: ["LDE"],
216
- card: "Last Ditch Effort"
217
- },
218
- {
219
- abbreviations: ["LtC"],
220
- card: "Lead the Charge"
221
- },
222
- {
223
- abbreviations: ["LNW"],
224
- card: "Leave No Witnesses"
225
- },
226
- {
227
- abbreviations: ["LFaL", "L4aL"],
228
- card: "Life for a Life"
229
- },
230
- {
231
- abbreviations: ["LiT"],
232
- card: "Lost in Thought"
233
- },
234
- {
235
- abbreviations: ["MMB"],
236
- card: "Mage Master Boots"
237
- },
238
- {
239
- abbreviations: ["MaxV"],
240
- card: "Maximum Velocity"
241
- },
242
- {
243
- abbreviations: ["MoM"],
244
- card: "Mask of Momentum"
245
- },
246
- {
247
- abbreviations: ["MoPL"],
248
- card: "Mask of the Pouncing Lynx"
249
- },
250
- {
251
- abbreviations: ["MnG"],
252
- card: "Meat and Greet"
253
- },
254
- {
255
- abbreviations: ["Cake", "\u{1F382}"],
256
- card: "Ninth Blade of the Blood Oath"
257
- },
258
- {
259
- abbreviations: ["PoM"],
260
- card: "Peace of Mind"
261
- },
262
- {
263
- abbreviations: ["P-Bone"],
264
- card: "Performance Bonus"
265
- },
266
- {
267
- abbreviations: ["PF", "\u{1F525}"],
268
- card: "Phoenix Flame"
269
- },
270
- {
271
- abbreviations: ["PtW"],
272
- card: "Poison the Well"
273
- },
274
- {
275
- abbreviations: ["Thanos", "Infinity Gauntlet"],
276
- card: "Polarity Reversal Script"
277
- },
278
- {
279
- abbreviations: ["DPot", "D Pot"],
280
- card: "Potion of D\xE9j\xE0 Vu"
281
- },
282
- {
283
- abbreviations: ["Ponder Run"],
284
- card: "Premeditate"
285
- },
286
- {
287
- abbreviations: ["Qi Unbound"],
288
- card: "Qi Unleashed"
289
- },
290
- {
291
- abbreviations: ["RitL"],
292
- card: "Red in the Ledger"
293
- },
294
- {
295
- abbreviations: ["Cats", "Ghost cat", "Ghost cats"],
296
- card: "Restless Coalescence"
297
- },
298
- {
299
- abbreviations: ["Eugene"],
300
- card: "Rhinar, Reckless Rampage",
301
- isHidden: true
302
- },
303
- {
304
- abbreviations: ["SSGB"],
305
- card: "Sandscour Greatbow"
306
- },
307
- {
308
- abbreviations: ["SSP"],
309
- card: "Sand Sketched Plan"
310
- },
311
- {
312
- abbreviations: ["SFaS", "S4aS"],
313
- card: "Scar for a Scar"
314
- },
315
- {
316
- abbreviations: ["Tyler"],
317
- card: "Scurv, Stowaway",
318
- isHidden: true
319
- },
320
- {
321
- abbreviations: ["SWOMB"],
322
- card: "Shifting Winds of the Mystic Beast"
323
- },
324
- {
325
- abbreviations: ["Snaps"],
326
- card: "Snapdragon Scalers"
327
- },
328
- {
329
- abbreviations: ["SWK"],
330
- card: "Spinning Wheel Kick"
331
- },
332
- {
333
- abbreviations: ["SFTL"],
334
- card: "Swing Fist, Think Later"
335
- },
336
- {
337
- abbreviations: ["TTT"],
338
- card: "Take the Tempo"
339
- },
340
- {
341
- abbreviations: ["Ultron"],
342
- card: "Teklovossen, the Mechropotent"
343
- },
344
- {
345
- abbreviations: ["ToS"],
346
- card: "Test of Strength"
347
- },
348
- {
349
- abbreviations: ["TAYG"],
350
- card: "That All You Got?"
351
- },
352
- {
353
- abbreviations: ["TROM"],
354
- card: "This Round's on Me"
355
- },
356
- {
357
- abbreviations: ["3oak"],
358
- card: "Three of a Kind"
359
- },
360
- {
361
- abbreviations: ["Pox Malone", "Post Malone"],
362
- card: "Virulent Touch"
363
- },
364
- {
365
- abbreviations: ["Cast Homes"],
366
- card: "Visit Goldmane Estate"
367
- },
368
- {
369
- abbreviations: ["Frosty Hammer"],
370
- card: "Winter's Wail"
371
- },
372
- {
373
- abbreviations: ["Wreckless Wing"],
374
- card: "War Cry of Bellona"
375
- },
376
- {
377
- abbreviations: ["ZTS"],
378
- card: "Zero to Sixty"
379
- }
380
- ];
381
- export {
382
- abbreviations,
383
- getAbbreviation,
384
- getAbbreviationByCard
385
- };