@flesh-and-blood/search 4.2.7 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/filters.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Foiling, Hero, Rarity, Release, Treatment } from "@flesh-and-blood/types";
2
- import { SearchIndex } from "./searchIndex.js";
2
+ import { CatalogueIndex } from "./searchIndex.js";
3
3
  export interface AppliedFilter {
4
4
  filterToPropertyMapping: FilterToPropertyMapping;
5
5
  values: string[];
@@ -123,7 +123,7 @@ export declare const filtersToCardPropertyMappings: {
123
123
  x: FilterToPropertyMapping;
124
124
  year: FilterToPropertyMapping;
125
125
  };
126
- export declare const getKeywordsAndAppliedFiltersFromText: (text: string, index: SearchIndex, additionalHeroes?: Hero[], additionalSets?: Release[], today?: string) => {
126
+ export declare const getKeywordsAndAppliedFiltersFromText: (text: string, index: CatalogueIndex, additionalHeroes?: Hero[], additionalSets?: Release[], today?: string) => {
127
127
  appliedFilters: AppliedFilter[];
128
128
  attributes: {
129
129
  artists: string[];
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- var fr=Object.create;var J=Object.defineProperty;var gr=Object.getOwnPropertyDescriptor;var hr=Object.getOwnPropertyNames;var br=Object.getPrototypeOf,yr=Object.prototype.hasOwnProperty;var mr=(e,r)=>{for(var t in r)J(e,t,{get:r[t],enumerable:!0})},Ie=(e,r,t,a)=>{if(r&&typeof r=="object"||typeof r=="function")for(let i of hr(r))!yr.call(e,i)&&i!==t&&J(e,i,{get:()=>r[i],enumerable:!(a=gr(r,i))||a.enumerable});return e};var Cr=(e,r,t)=>(t=e!=null?fr(br(e)):{},Ie(r||!e||!e.__esModule?J(t,"default",{value:e,enumerable:!0}):t,e)),Mr=e=>Ie(J({},"__esModule",{value:!0}),e);var Ct={};mr(Ct,{FilterProperty:()=>Ee,MARKUP:()=>ue,PUNCTUATION:()=>g,RARITY_VALUES_MAPPING:()=>we,abbreviations:()=>fe,availableExclusions:()=>lr,availableModifiers:()=>nr,buildSearchIndex:()=>Me,default:()=>dr,filterCard:()=>ur,filtersToCardPropertyMappings:()=>ke,getAbbreviation:()=>Q,getAbbreviationByCard:()=>Fr,getCardsByName:()=>te,getCardsByReferencedCardIdentifier:()=>Ce,getCardsReferencedBy:()=>ae,getCardsReferencing:()=>ie,getCleanText:()=>q,getExcludedMetaFilters:()=>he,getKeywordsAndAppliedFiltersFromText:()=>Le,getMetaFilters:()=>ge,getNormalizedText:()=>_,getOtherPitches:()=>Nr,getReferencedCards:()=>Dr,getTextWithoutMarkup:()=>j,getTokensReferencedByCards:()=>Or,multiWordShorthands:()=>ye,shorthands:()=>be,singleWordShorthands:()=>me});module.exports=Mr(Ct);var le=require("@flesh-and-blood/types"),Be=Cr(require("fuse.js"),1);var g=/[!"#$%&'’(),./:;<=>?@[\]^_`|~]/g,ue=/\*/g;var l=require("@flesh-and-blood/types");var Q=e=>fe.find(({abbreviations:r})=>r.find(t=>t.toLowerCase()===e)),Fr=e=>fe.find(({card:r})=>r.toLowerCase()===e.name.toLowerCase()),fe=[{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 T=require("@flesh-and-blood/types");var Ee=(a=>(a.BannedFormats="bannedFormats",a.LegalFormats="legalFormats",a.LegalHeroes="legalHeroes",a))(Ee||{}),re=Array.from(Array(50).keys()).map(e=>`${e}`),vr=[{format:T.Format.ClassicConstructed,nicknames:["cc","classic"]},{format:T.Format.LivingLegend,nicknames:["cc ll","classic constructed ll","ll cc","ll","living legend"]},{format:T.Format.SilverAge,nicknames:["sage"]},{format:T.Format.GoldenAge,nicknames:["gage"]},{format:T.Format.UltimatePitFight,nicknames:["upf"]}],Ar=Object.values(T.Format).map(e=>{let r=vr.find(({format:a})=>a===e),t=e.toLowerCase().replaceAll(g,"");return r?{...r,format:t}:{format:t}}),Tr=[{hero:T.Hero.DataDoll,nicknames:["data","datadoll"]},{hero:T.Hero.Dorinthea,nicknames:["dori"]},{hero:T.Hero.Genis,nicknames:["genis"]},{hero:T.Hero.GravyBones,nicknames:["gravy"]},{hero:T.Hero.Iyslander,nicknames:["islander"]}],Sr=Object.values(T.Hero).map(e=>{let r=Tr.find(({hero:a})=>a===e),t=e.toLowerCase().replaceAll(g,"");return r?{...r,hero:t}:{hero:t}}),X=["common","rare","super rare","majestic","legendary","fabled"],xr=(e,r,t,a)=>{let i=[];if(!r)i.push(...e);else for(let s of e)switch(r){case">=":{let o=!1;for(let n of X)o?i.push(n):n===s&&(o=!0,i.push(n));break}case">":{let o=!1;for(let n of X)o?i.push(n):n===s&&(o=!0);break}case"<=":{let o=!1;for(let n of X.slice().reverse())o?i.push(n):n===s&&(o=!0,i.push(n));break}case"<":{let o=!1;for(let n of X.slice().reverse())o?i.push(n):n===s&&(o=!0);break}default:break}return{filterToPropertyMapping:{nestedProperty:"rarity",property:"printings",isArray:!0},isExcluded:t,isOptional:a,isOr:!0,values:i}},Ne=(e,r,t,a,i)=>{let s=a.map(u=>({hero:u.toLowerCase().replaceAll(g,"")})),o=[],n=[],c=[];for(let u of e){let p=Ar.find(({format:b,nicknames:m})=>b===u||!!m&&m.includes(u));if(p)n.push(p.format);else{let b=Sr.find(({hero:m,nicknames:v})=>m===u||!!v&&v.includes(u))||s.find(({hero:m})=>m===u);b&&c.push(b.hero)}}let h=i||"legalFormats";return n.length>0&&o.push({filterToPropertyMapping:{property:h,isArray:!0},values:n,isOr:!0,isExcluded:r,isOptional:t}),c.length>0&&o.push({filterToPropertyMapping:{property:"legalHeroes",isArray:!0},values:c,isOr:!0,isExcluded:r,isOptional:t}),o},Pr=(e,r,t,a)=>Ne(e,r,t,a,"bannedFormats"),ge=(e,r,t,a,i,s)=>{let o=[];return Lr(t)?o.push(...Ne(a,e,r,s)):Rr(t)?o.push(...Pr(a,e,r,s)):Er(t)&&o.push(xr(a,i,e,r)),o},z=[{filterToPropertyMapping:{property:"cost",isNumber:!0},isExcluded:!0,values:re},{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"]}],O=[{filterToPropertyMapping:{property:"defense",isNumber:!0},isExcluded:!0,values:re},{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"]}],Z=[{filterToPropertyMapping:{property:"pitch",isNumber:!0},isExcluded:!0,values:re},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["equipment","hero","placeholder","token","weapon"]},{filterToPropertyMapping:{property:"isCardBack",isBoolean:!0},isExcluded:!0,values:["true"]}],G=[{filterToPropertyMapping:{property:"power",isNumber:!0},isExcluded:!0,values:re},{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"]}],ee=[{filterToPropertyMapping:{property:"talents",isArray:!0},isExcluded:!0,values:Object.values(T.Talent).map(e=>e.toLowerCase())}],wr={"!co":z,"-co":z,"!cost":z,"-cost":z,"!color":z,"-color":z,"!b":O,"-b":O,"!block":O,"-block":O,"!d":O,"-d":O,"!def":O,"-def":O,"!defense":O,"-defense":O,"!pitch":Z,"-pitch":Z,"!p":Z,"-p":Z,"!attack":G,"-attack":G,"!power":G,"-power":G,"!pwr":G,"-pwr":G,"!pow":G,"-pow":G,"!talents":ee,"-talents":ee,"!tal":ee,"-tal":ee},he=e=>{let r=[],t=wr[e];return t&&r.push(...t),r},kr=["l","legal","hero"],Lr=e=>kr.includes(e),Br=["banned"],Rr=e=>Br.includes(e),Ir=["r","rarity"],Er=e=>Ir.includes(e);var I=require("@flesh-and-blood/types"),be=[{description:"Attack actions",expanded:["st:attack"],filters:{subtypes:[I.Subtype.Attack]},isCardProperty:!1,shorthands:["AA"]},{description:"Arcane barrier",expanded:['k:"arcane barrier"'],filters:{keywords:[I.Keyword.ArcaneBarrier]},isCardProperty:!1,shorthands:["AB"]},{description:"Attack reactions",expanded:['t:"attack reaction"'],filters:{types:[I.Type.AttackReaction]},isCardProperty:!1,shorthands:["AR"]},{description:"Defense reactions",expanded:['t:"defense reaction"'],filters:{types:[I.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:[I.Keyword.GoAgain]},isCardProperty:!1,shorthands:["GA"]},{description:"Non-attack actions",expanded:["t:action","st:non-attack"],filters:{subtypes:[I.Subtype.NonAttack],types:[I.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:[I.Keyword.Spellvoid]},isCardProperty:!1,shorthands:["SV"]}],ye=be.filter(({shorthands:e})=>e.some(r=>r.includes(" "))).map(e=>({...e,shorthands:e.shorthands.filter(r=>r.includes(" ")).map(r=>r.toLowerCase()).sort((r,t)=>t.length-r.length)})),me=be.filter(({shorthands:e})=>e.some(r=>!r.includes(" "))).map(e=>({...e,shorthands:e.shorthands.filter(r=>!r.includes(" ")).map(r=>r.toLowerCase()).sort((r,t)=>t.length-r.length)}));var q=e=>_(e.toLowerCase().trim().replace(g,"")),_=e=>e.normalize("NFD").replace(/\p{Diacritic}/gu,""),j=e=>e.replace(ue,"");var Nr=(e,r)=>{let t=[];if(e)for(let a of r){let i=a.name===e.name,s=a.cardIdentifier!==e.cardIdentifier,o=a.pitch!==e.pitch;i&&s&&o&&t.push(a)}return t},Dr=(e,r)=>{let t=new Set(e?.referencedCards),a=[];for(let i of r)t.has(i.cardIdentifier)&&a.push(i);return a},Ce=e=>{let r=new Map;for(let t of e)for(let a of t.referencedCards||[]){let i=r.get(a);i?i.push(t):r.set(a,[t])}return r},Or=(e,r)=>{let t=new Set;for(let i of e)for(let s of i.createdExtras||[])t.add(s);let a=[];for(let i of r)t.has(i.cardIdentifier)&&a.push(i);return a};var Me=e=>{let r=new Map,t=new Map,a=[],i=new Map,s=0;for(let o of e){r.set(o.cardIdentifier,o),t.set(o.cardIdentifier,s),s++;let n=q(o.name),c=i.get(n);c?c.push(o):(i.set(n,[o]),a.push(n))}return{cards:e,cardByCardIdentifier:r,corpusPositionByCardIdentifier:t,cleanedNames:a,pitchCycleByCleanedName:i,referencingCardsByCardIdentifier:Ce(e)}},Fe=(e,r)=>e.pitchCycleByCleanedName.get(q(r.name))||[],te=(e,r)=>{let t=q(r),a=e.pitchCycleByCleanedName.get(t);if(!a){let i=e.cleanedNames.find(s=>s.includes(t));i&&(a=e.pitchCycleByCleanedName.get(i))}return a||[]},De=(e,r)=>{let t=new Map;for(let i of r)for(let s of Fe(e,i))t.set(s.cardIdentifier,s);let a=({cardIdentifier:i})=>e.corpusPositionByCardIdentifier.get(i)||0;return[...t.values()].sort((i,s)=>a(i)-a(s))},ie=(e,r)=>{let t=[];for(let a of Fe(e,r))t.push(...e.referencingCardsByCardIdentifier.get(a.cardIdentifier)||[]);return De(e,t)},ae=(e,r)=>{let t=[];for(let a of Fe(e,r))for(let i of a.referencedCards||[]){let s=e.cardByCardIdentifier.get(i);s&&t.push(s)}return De(e,t)};var nr=[">=",">","<=","<"],lr=["!","-"],Hr={property:"arcane",specialProperty:"specialArcane",isNumber:!0,partialMatch:!0},ve={property:"artists",isArray:!0,partialMatch:!0},Oe={property:"n/a",isMeta:!0},He={property:"bonds",isArray:!0},Vr={property:"cardIdentifier",isString:!0,isNormalized:!0},Ve=(e,{isAnd:r,isExcluded:t,isOptional:a,modifier:i})=>({filterToPropertyMapping:Vr,values:[...e],valuesSet:e,isAnd:r,isOr:!0,modifier:i,isExcluded:t,isOptional:a}),Gr={property:"n/a"},Ge={property:"classes",isArray:!0,partialMatch:!0},We={property:"cost",specialProperty:"specialCost",isNumber:!0,partialMatch:!0},$={property:"defense",specialProperty:"specialDefense",isNumber:!0},Ue={property:"flows",isArray:!0},Ke={nestedProperty:"foiling",property:"printings",isArray:!0},ze={property:"fusions",isArray:!0},je={property:"intellect",isNumber:!0},qe={property:"keywords",isArray:!0},Ae={property:"n/a",isMeta:!0},_e={property:"life",specialProperty:"specialLife",isNumber:!0},Pe={property:"meta",isArray:!0},$e={property:"name",isString:!0,partialMatch:!0},Te={property:"pitch",isNumber:!0},Ye={property:"firstReleaseDate",isDate:!0},se={property:"power",specialProperty:"specialPower",isNumber:!0},Wr={property:"setIdentifiers",isArray:!0,partialMatch:!0},Je={property:"n/a",isMeta:!0},Ur={property:"n/a"},Kr={property:"n/a"},Qe={property:"sets",isArray:!0,partialMatch:!0},Se={property:"shorthands",isArray:!0,partialMatch:!0},oe={property:"specializations",isArray:!0,partialMatch:!0},Xe={property:"subtypes",isArray:!0},Ze={property:"types",isArray:!0},er={property:"talents",isArray:!0},zr={property:"functionalText",hasMarkup:!0,isString:!0,partialMatch:!0},jr={property:"traits",isArray:!0,partialMatch:!0},qr={property:"typeText",isString:!0,partialMatch:!0},ne={nestedProperty:"treatments",property:"printings",isArray:!0,isNestedPropertyArray:!0},_r={property:"firstReleaseDate",isString:!0,partialMatch:!0},ke={arcane:Hr,a:ve,artist:ve,art:ve,attack:se,b:$,block:$,banned:Oe,bond:He,bonds:He,c:Ge,class:Ge,chain:Gr,co:We,cost:We,color:Te,d:$,def:$,defense:$,flow:Ue,flows:Ue,f:ze,fusion:ze,foil:Ke,foiling:Ke,i:je,intellect:je,is:Pe,k:qe,keyword:qe,l:Ae,legal:Ae,hero:Ae,li:_e,life:_e,meta:Pe,n:$e,name:$e,p:Te,pitch:Te,pwr:se,pow:se,power:se,print:Wr,r:Je,rarity:Je,referencedby:Ur,references:Kr,rf:Oe,s:Qe,set:Qe,short:Se,shorthand:Se,shorthands:Se,sp:oe,spec:oe,specialization:oe,specializations:oe,st:Xe,subtype:Xe,t:Ze,type:Ze,tal:er,talent:er,text:zr,trait:jr,treat:ne,treatment:ne,var:ne,variation:ne,x:qr,year:_r},$r=[{text:l.Release.ClassicBattlesRhinarDorinthea.toLowerCase(),override:l.Release.ClassicBattlesRhinarDorinthea.toLowerCase().replaceAll(g,"")}],Yr=e=>{let r=[],t=e.replaceAll("\u201D",'"');for(let{text:i,override:s}of $r)t.includes(i)&&(t=t.replace(i,s));if(Q(t)?.card)r.push(t);else{let i=t.split(/[ ]+/),s="",o=0;for(let n of i)o===2&&(r.push(s.trim().replaceAll('"',"")),s="",o=0),o<2&&n.split('"').length===2?(s+=" "+n,o++):o===0&&s===""?r.push(n):o===1&&(s+=" "+n);o===2&&(r.push(s.trim().replaceAll('"',"")),s="",o=0)}return r},Jr=20,Le=(e,r,t=[],a=[],i=it())=>{let s=e.trim().toLowerCase();for(let{expanded:S,shorthands:x}of ye)for(let d of x)if(s.includes(d)){s=s.replace(d,S.join(" "));break}for(let[S,x]of Object.entries(l.setToSetIdentifierMappings))s.includes(S.toLowerCase())&&(s=s.replace(S.toLowerCase(),x[0]));let o=Yr(s),n=[];for(let S of o){let x=me.find(({shorthands:d})=>d.includes(S));x&&!x.isCardProperty?n.push(...x.expanded):n.push(S)}let c=[],h=[],u=[],p=[],b=!1,m=[],v=[],B=[],W=[];for(let S of n)if(pt(S)){let[x,d]=S.split(":"),{modifier:E,values:f,isAnd:y,isOr:P}=lt(d),{filterKey:M,isExcluded:w,isOptional:L,isMeta:pe}=ct(x),U=!1;if(pe){if(["rarity","r"].includes(M)){let H=nt(f);w||(v=[...H]),f=H.map(F=>F.toLowerCase())}["legal","l","hero"].includes(M),c.push(...ge(w,L,M,f,E,t))}else{if(["chain"].includes(M)){let F=new Set,k=[],N=new Set,D=A=>{F.add(A.cardIdentifier),N.has(A.name)||(N.add(A.name),k.push(A))},K=A=>{A.types.includes(l.Type.Hero)||D(A)};for(let A of f)if(A)for(let R of te(r,A))D(R);let V=0;for(let A of k){if(V>Jr)break;for(let de of ae(r,A))K(de);if(V===0)for(let de of ie(r,A))K(de);V++}c.push(Ve(F,{isAnd:y,isExcluded:w,isOptional:L,modifier:E})),U=!0}else if(["referencedby","references"].includes(M)){let F=["referencedby"].includes(M),k=new Set;for(let N of f)if(N)for(let D of te(r,N)){let K=F?ae(r,D):ie(r,D);for(let V of K)k.add(V.cardIdentifier)}c.push(Ve(k,{isAnd:y,isExcluded:w,isOptional:L,modifier:E})),U=!0}else if(["art","artist"].includes(M))h=f;else if(["print","prints","printing","printings"].includes(M))m=f;else if(["is","meta"].includes(M)){let F=[],k=[],N=[],D=[];for(let R of f)et.includes(R)?F.push(R):rt.includes(R)?k.push(R):tt.includes(R)?N.push(R):D.push(R);F.length>0&&(c.push({filterToPropertyMapping:Pe,values:[l.Meta.Reprint.toLowerCase().replaceAll(g,"")],isAnd:y,isOr:P,isExcluded:!w,isOptional:L}),U=D.length===0);let K=k.length>0;K&&c.push({filterToPropertyMapping:Ye,values:[i],isAnd:y,isOr:P,isExcluded:w,isOptional:L});let V=N.length>0;V&&c.push({filterToPropertyMapping:Ye,values:[i],isAnd:y,isOr:P,isExcluded:!w,isOptional:L}),(K||V)&&(U=D.length===0);let A=at(D);f=A.map(R=>R.toLowerCase().replaceAll(g,"")),A.includes(l.Meta.Expansion)&&!w&&(b=!0)}else["foiling","foil"].includes(M)?(p=st(f),f=p.map(F=>F.toLowerCase())):["treat","treatment","var","variation"].includes(M)?(W=ot(f),f=W.map(F=>F.toLowerCase())):["set","s"].includes(M)?(B=Qr(f,a),f=B.map(F=>F.toLowerCase().replaceAll(g,""))):["pitch","p","color"].includes(M)&&(f=Zr(f));let H=ke[M];H&&!U&&c.push({filterToPropertyMapping:H,values:H.hasMarkup?f.map(F=>j(F)):f,isAnd:y,isOr:P,modifier:E,isExcluded:w,isOptional:L})}}else if(S){let x=Q(S)?.card,d=he(S);x?u.push(`"${x.toLowerCase().replace(g,"")}"`):d&&d.length>0?c.push(...d):u.push(S.replace(g,""))}return{appliedFilters:c,attributes:{artists:h,foilings:p,isExpansionSlot:b,prints:m,rarities:v,releases:B,treatments:W},keywords:u}},Qr=(e,r=[])=>{let t=[];for(let a of e)t.push(...Xr(a,r));return t},Xr=(e,r=[])=>{let t=[],a=Object.values(l.Release).find(i=>i.toLowerCase().replaceAll(g,"")===e);if(a&&t.push(a),t.length===0){let i=l.setIdentifierToSetMappings[e];i&&t.push(i)}if(t.length===0){let i=Object.values(l.Release).filter(s=>s.toLowerCase().includes(e));i.length>0&&t.push(...i)}if(t.length===0){let i=r.find(s=>s.toLowerCase().replaceAll(g,"")===e);i&&t.push(i)}return t},xe={purple:4,blue:3,yellow:2,red:1,white:0},Zr=e=>{let r=[];for(let t of e)xe[t]||xe[t]===0?r.push(xe[t].toString()):r.push(t);return r},et=["unique"],rt=["preview","spoiler","unreleased"],tt=["released"],it=()=>{let e=new Date,r=`${e.getMonth()+1}`.padStart(2,"0"),t=`${e.getDate()}`.padStart(2,"0");return`${e.getFullYear()}-${r}-${t}`},rr={dual:l.Meta.DualClass,exp:l.Meta.Expansion,expansion:l.Meta.Expansion,expansionSlot:l.Meta.Expansion,rainbow:l.Meta.Rainbow,reprint:l.Meta.Reprint,reprints:l.Meta.Reprint},at=e=>{let r=[];for(let t of e)rr[t]?r.push(rr[t]):l.Meta[t]&&r.push(l.Meta[t]);if(e.length>0&&r.length===0){for(let t of Object.values(l.Meta))for(let a of e)if(t.toLowerCase().includes(a)){r.push(t);break}}return r},tr={r:l.Foiling.Rainbow,rf:l.Foiling.Rainbow,rainbow:l.Foiling.Rainbow,c:l.Foiling.Cold,cf:l.Foiling.Cold,cold:l.Foiling.Cold,g:l.Foiling.Gold,gf:l.Foiling.Gold,gold:l.Foiling.Gold},st=e=>{let r=[];for(let t of e)tr[t]&&r.push(tr[t]);return r},ir={...Object.values(l.Treatment).reduce((e,r)=>(e[r.toLowerCase()]=r,e),{}),aa:l.Treatment.AA,alt:l.Treatment.AA,"alt art":l.Treatment.AA,ab:l.Treatment.AB,"alt border":l.Treatment.AB,at:l.Treatment.AT,"alt text":l.Treatment.AT,ea:l.Treatment.EA,extended:l.Treatment.EA,"extended art":l.Treatment.EA,fa:l.Treatment.FA,full:l.Treatment.FA,"full art":l.Treatment.FA},ot=e=>{let r=[];for(let t of e)ir[t]?r.push(ir[t]):l.Treatment[t.toUpperCase()]&&r.push(l.Treatment[t.toUpperCase()]);return r},we={b:l.Rarity.Basic,c:l.Rarity.Common,f:l.Rarity.Fabled,l:l.Rarity.Legendary,m:l.Rarity.Majestic,p:l.Rarity.Promo,r:l.Rarity.Rare,s:l.Rarity.SuperRare,t:l.Rarity.Token,v:l.Rarity.Marvel},nt=e=>{let r=[];for(let t of e)we[t]?r.push(we[t]):r.push(t);return r},lt=e=>{let r=[],t,a,i=nr.find(s=>e.includes(s));if(i){let[,s]=e.split(i);ar(s)?(t=!0,r.push(...s.trim().split("+").map(o=>o.replace(g,"")))):sr(s)?(a=!0,r.push(...s.trim().split(",").map(o=>o.replace(g,"")))):r.push(s.trim().replace(g,""))}else ar(e)?(t=!0,r.push(...e.trim().split("+").map(s=>s.replace(g,"")))):sr(e)?(a=!0,r.push(...e.trim().split(",").map(s=>s.replace(g,"")))):e.startsWith('"')&&e.endsWith('"')?r.push(e.trim().replaceAll('"',"").replace(g,"")):r.push(e.trim().replace(g,""));return{modifier:i,values:r,isAnd:t,isOr:a}},ct=e=>{let r=dt(e);if(r){let[,t]=e.split(r);return{filterKey:t,isExcluded:!0,isOptional:!1,isMeta:or(t)}}else return{filterKey:e,isExcluded:!1,isOptional:!1,isMeta:or(e)}},pt=e=>e.indexOf(":")>=0,ar=e=>e.indexOf("+")>=0,sr=e=>e.indexOf(",")>=0,or=e=>!!ke[e]?.isMeta,dt=e=>lr.find(r=>e.includes(r))?.slice(0,1);var C=require("@flesh-and-blood/types"),cr={artists:["Hoodwill"],cardIdentifier:"fangs-a-lot-blue",classes:[C.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:[C.Hero.Kayo,C.Hero.Levia,C.Hero.Rhinar],printings:[{artists:["Hoodwill"],identifier:"FNG000",image:"FNG000",print:"FNG000",rarity:C.Rarity.Rare,set:C.Release.Promos},{artists:["Hoodwill"],identifier:"FNG000",image:"FNG000_Marvel",print:`FNG000-${C.Treatment.FA}`,rarity:C.Rarity.Marvel,set:C.Release.Promos,treatment:C.Treatment.FA}],name:"Fangs A Lot",rarities:[C.Rarity.Rare,C.Rarity.Marvel],rarity:C.Rarity.Rare,sets:[C.Release.Promos],setIdentifiers:["FNG000"],specialImage:"FNG000_Marvel",subtypes:[C.Subtype.Attack],types:[C.Type.Action],typeText:"Generic Action - Attack"},pr=[{keyword:cr.name.toLowerCase(),card:cr}];var Re=class{constructor(r,t=[],a=[],i=!1){this.log=(r,...t)=>{this.debug&&console.log(r,...t)};this.search=(r,t)=>{let a,{appliedFilters:i,attributes:s,keywords:o}=Le(r,this.index,this.additionalHeroes,this.additionalSets),n=o.join(" "),c=t?pr.filter(d=>d.keyword===n):[];if(c.length>0?a=c.map(({card:d})=>d):o.length?a=this.fuse.search(n).map(d=>d.item):a=[...this.cards],i.length&&(a=a.filter(d=>d&&ur(d,i))),o.length===0){let d="";if(s.releases.length===1)try{let y=s.releases[0];d=le.setToSetIdentifierMappings[y][0].toUpperCase()}catch(y){console.error("Error getting set identifier from search",y)}if(!d&&s.prints.length===1)try{let y=s.prints[0];le.setIdentifierToSetMappings[y]&&(d=y.toUpperCase())}catch(y){console.error("Error getting set identifier from search",y)}d?a.sort((y,P)=>{let M=y.setIdentifiers.find(L=>L.includes(d))?.replace(d,""),w=P.setIdentifiers.find(L=>L.includes(d))?.replace(d,"");return M&&w?M.localeCompare(w):-1}):a.sort((y,P)=>y.name===P.name?`${y.pitch}`.localeCompare(`${P.pitch}`):y.name.localeCompare(P.name))}else{let d=[],E=[],f=o.map(y=>y.toLowerCase().replace(g,"")).join(" ");for(let y of a)y.name.toLowerCase().replace(g,"")===f?d.push(y):E.push(y);a=[...d,...E]}let h,{artists:u,isExpansionSlot:p,foilings:b,prints:m,rarities:v,releases:B,treatments:W}=s;(u.length>0||p||b.length>0||m.length>0||v.length>0||B.length>0||W.length>0)&&(h=a.map(d=>{let E=d.printings.filter(f=>{let y=!!f.image,P=u.length===0||u.some(k=>f.artists.find(N=>N.replace(g,"").toLowerCase().includes(k))),M=!p||p===f.isExpansionSlot,w=b.length===0||b.includes(f.foiling),L=m.length===0||m.some(k=>f.identifier.includes(k.toUpperCase())),pe=v.length===0||v.includes(f.rarity),U=B.length===0||B.includes(f.set),H=W.length===0||f.treatments?.some(k=>W.includes(k));return y&&P&&M&&w&&L&&pe&&U&&H});return{...d,matchingPrintings:E}}));let x=h?.length>0?h:a;return{appliedFilters:i,attributes:s,keywords:o,searchResults:x}};let s={getFn:(o,n)=>{let c=Be.default.config.getFn(o,n);if(c){if(Array.isArray(c))return c.map(h=>_(h.replace(g,"")));{let h=_(c).replace(g,"");return n.includes("functionalText")?j(h):h}}else return c},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};this.additionalHeroes=t,this.additionalSets=a,this.cards=[...r],this.debug=i,this.fuse=new Be.default([...r],s),this.index=Me(this.cards)}},dr=Re,ur=(e,r)=>{let t=!0,a=!1;for(let i of r){let s=i.isOptional,{isNumber:o,isString:n,isArray:c,isBoolean:h,isDate:u}=i.filterToPropertyMapping;if(o){let p=ut(e,i);s?p&&(a=!0):t=t&&p}else if(n){let p=ft(e,i);s?p&&(a=!0):t=t&&p}else if(c){let p=gt(e,i,r);s?p&&(a=!0):t=t&&p}else if(h){let p=ht(e,i);s?p&&(a=!0):t=t&&p}else if(u){let p=bt(e,i);s?p&&(a=!0):t=t&&p}}return t},ut=(e,r)=>{if(Y(r,e)){let{values:t,modifier:a,isExcluded:i,filterToPropertyMapping:{partialMatch:s}}=r,o=ce(e,r);if(o!=null&&!isNaN(o))if(o=parseInt(o),a)switch(a){case">=":{let n=t?.some(c=>o>=parseInt(c));return i?!n:n}case">":{let n=t?.some(c=>o>parseInt(c));return i?!n:n}case"<=":{let n=t?.some(c=>o<=parseInt(c));return i?!n:n}case"<":{let n=t?.some(c=>o<parseInt(c));return i?!n:n}default:return!1}else{let n=t?.some(c=>o===parseInt(c));return i?!n:n}else{let n=mt(e,r)?.toLowerCase(),c=s?t?.some(h=>n?.includes(h)):t?.some(h=>n===h);return i?!c:c}}else return!0},ft=(e,r)=>{if(Y(r,e)){let{values:t,valuesSet:a,isAnd:i,isExcluded:s,filterToPropertyMapping:{hasMarkup:o,isNormalized:n,partialMatch:c}}=r,h=ce(e,r),u=n?h:h?.replaceAll(g,"").toLowerCase(),p=o&&u?j(u):u;if(c){let b=i?t?.every(m=>p?.includes(m)):t?.some(m=>p?.includes(m));return s?!b:b}else{let b;return i?b=t?.every(m=>p===m):a?b=a.has(p):b=t?.some(m=>p===m),s?!b:b}}else return!0},gt=(e,r,t)=>{if(Y(r,e)){let{values:a,isAnd:i,isExcluded:s,filterToPropertyMapping:{partialMatch:o}}=r,n=yt(e,r,t).map(c=>c?.replaceAll(g,""));if(o){let c=i?a.every(u=>n?.some(p=>p?.toLowerCase().includes(u))):a.some(u=>n?.some(p=>p?.toLowerCase().includes(u))),h=n.length===0;return s?!c||h:c}else{let c=i?a.every(h=>n?.some(u=>u?.toLowerCase()===h)):a.some(h=>n?.some(u=>u?.toLowerCase()===h));return s?!c:c}}else return!0},ht=(e,r)=>{if(Y(r,e)){let{isExcluded:t}=r,a=ce(e,r);return t?!a:a}else return!0},bt=(e,r)=>{if(Y(r,e)){let{values:t,isExcluded:a}=r,i=ce(e,r),s=t?.some(o=>i>o);return a?!s:s}else return!0},ce=(e,r)=>{let{filterToPropertyMapping:t}=r;return e[t.property]},yt=(e,r,t)=>{let{filterToPropertyMapping:{isNestedPropertyArray:a,nestedProperty:i,property:s}}=r,o=e[s]||[],n=[],c=Object.keys(e.legalOverrides||{}).length>0,h=r.filterToPropertyMapping.property==="legalHeroes",u=t.find(({filterToPropertyMapping:b})=>b.property==="legalFormats");if(c&&h&&!!u){let b=new Set;for(let{format:m,heroes:v}of e.legalOverrides||[])if(u.values.includes(m.toLowerCase()))for(let B of v)b.add(B);n=Array.from(b)}if(n.length===0)if(i){let b=new Set;for(let m of o)if(a){let v=m[i]||[];for(let B of v)b.add(B)}else{let v=m[i];v&&b.add(v)}n=Array.from(b)}else n=o;return n},mt=(e,r)=>{let{filterToPropertyMapping:t}=r;return e[t.specialProperty]},Y=({cardTypes:e},{types:r,subtypes:t})=>!e||e?.some(a=>r.map(i=>i.toLowerCase()).includes(a.toLowerCase())||t.map(i=>i.toLowerCase()).includes(a.toLowerCase()));0&&(module.exports={FilterProperty,MARKUP,PUNCTUATION,RARITY_VALUES_MAPPING,abbreviations,availableExclusions,availableModifiers,buildSearchIndex,filterCard,filtersToCardPropertyMappings,getAbbreviation,getAbbreviationByCard,getCardsByName,getCardsByReferencedCardIdentifier,getCardsReferencedBy,getCardsReferencing,getCleanText,getExcludedMetaFilters,getKeywordsAndAppliedFiltersFromText,getMetaFilters,getNormalizedText,getOtherPitches,getReferencedCards,getTextWithoutMarkup,getTokensReferencedByCards,multiWordShorthands,shorthands,singleWordShorthands});
1
+ var hr=Object.create;var Q=Object.defineProperty;var br=Object.getOwnPropertyDescriptor;var yr=Object.getOwnPropertyNames;var mr=Object.getPrototypeOf,Cr=Object.prototype.hasOwnProperty;var Mr=(e,r)=>{for(var t in r)Q(e,t,{get:r[t],enumerable:!0})},Re=(e,r,t,a)=>{if(r&&typeof r=="object"||typeof r=="function")for(let i of yr(r))!Cr.call(e,i)&&i!==t&&Q(e,i,{get:()=>r[i],enumerable:!(a=br(r,i))||a.enumerable});return e};var Fr=(e,r,t)=>(t=e!=null?hr(mr(e)):{},Re(r||!e||!e.__esModule?Q(t,"default",{value:e,enumerable:!0}):t,e)),Sr=e=>Re(Q({},"__esModule",{value:!0}),e);var Tt={};Mr(Tt,{FilterProperty:()=>Le,MARKUP:()=>fe,PUNCTUATION:()=>y,RARITY_VALUES_MAPPING:()=>we,abbreviations:()=>ge,availableExclusions:()=>cr,availableModifiers:()=>dr,default:()=>fr,filterCard:()=>gr,filtersToCardPropertyMappings:()=>ke,getAbbreviation:()=>X,getAbbreviationByCard:()=>vr,getCardsByName:()=>ae,getCardsByReferencedCardIdentifier:()=>vt,getCardsReferencedBy:()=>se,getCardsReferencing:()=>ie,getCatalogueIndex:()=>Me,getCleanText:()=>_,getExcludedMetaFilters:()=>be,getKeywordsAndAppliedFiltersFromText:()=>Ie,getMetaFilters:()=>he,getNormalizedText:()=>$,getOtherPitches:()=>Ft,getReferencedCards:()=>St,getTextWithoutMarkup:()=>q,getTokensReferencedByCards:()=>At,multiWordShorthands:()=>me,shorthands:()=>ye,singleWordShorthands:()=>Ce});module.exports=Sr(Tt);var de=require("@flesh-and-blood/types"),Be=Fr(require("fuse.js"),1);var y=/[!"#$%&'’(),./:;<=>?@[\]^_`|~]/g,fe=/\*/g;var l=require("@flesh-and-blood/types");var X=e=>ge.find(({abbreviations:r})=>r.find(t=>t.toLowerCase()===e)),vr=e=>ge.find(({card:r})=>r.toLowerCase()===e.name.toLowerCase()),ge=[{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 k=require("@flesh-and-blood/types");var Le=(a=>(a.BannedFormats="bannedFormats",a.LegalFormats="legalFormats",a.LegalHeroes="legalHeroes",a))(Le||{}),te=Array.from(Array(50).keys()).map(e=>`${e}`),Ar=[{format:k.Format.ClassicConstructed,nicknames:["cc","classic"]},{format:k.Format.LivingLegend,nicknames:["cc ll","classic constructed ll","ll cc","ll","living legend"]},{format:k.Format.SilverAge,nicknames:["sage"]},{format:k.Format.GoldenAge,nicknames:["gage"]},{format:k.Format.UltimatePitFight,nicknames:["upf"]}],Tr=Object.values(k.Format).map(e=>{let r=Ar.find(({format:a})=>a===e),t=e.toLowerCase().replaceAll(y,"");return r?{...r,format:t}:{format:t}}),xr=[{hero:k.Hero.DataDoll,nicknames:["data","datadoll"]},{hero:k.Hero.Dorinthea,nicknames:["dori"]},{hero:k.Hero.Genis,nicknames:["genis"]},{hero:k.Hero.GravyBones,nicknames:["gravy"]},{hero:k.Hero.Iyslander,nicknames:["islander"]}],Pr=Object.values(k.Hero).map(e=>{let r=xr.find(({hero:a})=>a===e),t=e.toLowerCase().replaceAll(y,"");return r?{...r,hero:t}:{hero:t}}),Z=["common","rare","super rare","majestic","legendary","fabled"],wr=(e,r,t,a)=>{let i=[];if(!r)i.push(...e);else for(let s of e)switch(r){case">=":{let o=!1;for(let n of Z)o?i.push(n):n===s&&(o=!0,i.push(n));break}case">":{let o=!1;for(let n of Z)o?i.push(n):n===s&&(o=!0);break}case"<=":{let o=!1;for(let n of Z.slice().reverse())o?i.push(n):n===s&&(o=!0,i.push(n));break}case"<":{let o=!1;for(let n of Z.slice().reverse())o?i.push(n):n===s&&(o=!0);break}default:break}return{filterToPropertyMapping:{nestedProperty:"rarity",property:"printings",isArray:!0},isExcluded:t,isOptional:a,isOr:!0,values:i}},Ee=(e,r,t,a,i)=>{let s=a.map(h=>({hero:h.toLowerCase().replaceAll(y,"")})),o=[],n=[],c=[];for(let h of e){let g=Tr.find(({format:b,nicknames:C})=>b===h||!!C&&C.includes(h));if(g)n.push(g.format);else{let b=Pr.find(({hero:C,nicknames:A})=>C===h||!!A&&A.includes(h))||s.find(({hero:C})=>C===h);b&&c.push(b.hero)}}let F=i||"legalFormats";return n.length>0&&o.push({filterToPropertyMapping:{property:F,isArray:!0},values:n,isOr:!0,isExcluded:r,isOptional:t}),c.length>0&&o.push({filterToPropertyMapping:{property:"legalHeroes",isArray:!0},values:c,isOr:!0,isExcluded:r,isOptional:t}),o},kr=(e,r,t,a)=>Ee(e,r,t,a,"bannedFormats"),he=(e,r,t,a,i,s)=>{let o=[];return Br(t)?o.push(...Ee(a,e,r,s)):Lr(t)?o.push(...kr(a,e,r,s)):Nr(t)&&o.push(wr(a,i,e,r)),o},j=[{filterToPropertyMapping:{property:"cost",isNumber:!0},isExcluded:!0,values:te},{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"]}],O=[{filterToPropertyMapping:{property:"defense",isNumber:!0},isExcluded:!0,values:te},{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"]}],ee=[{filterToPropertyMapping:{property:"pitch",isNumber:!0},isExcluded:!0,values:te},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["equipment","hero","placeholder","token","weapon"]},{filterToPropertyMapping:{property:"isCardBack",isBoolean:!0},isExcluded:!0,values:["true"]}],W=[{filterToPropertyMapping:{property:"power",isNumber:!0},isExcluded:!0,values:te},{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"]}],re=[{filterToPropertyMapping:{property:"talents",isArray:!0},isExcluded:!0,values:Object.values(k.Talent).map(e=>e.toLowerCase())}],Ir={"!co":j,"-co":j,"!cost":j,"-cost":j,"!color":j,"-color":j,"!b":O,"-b":O,"!block":O,"-block":O,"!d":O,"-d":O,"!def":O,"-def":O,"!defense":O,"-defense":O,"!pitch":ee,"-pitch":ee,"!p":ee,"-p":ee,"!attack":W,"-attack":W,"!power":W,"-power":W,"!pwr":W,"-pwr":W,"!pow":W,"-pow":W,"!talents":re,"-talents":re,"!tal":re,"-tal":re},be=e=>{let r=[],t=Ir[e];return t&&r.push(...t),r},Dr=["l","legal","hero"],Br=e=>Dr.includes(e),Rr=["banned"],Lr=e=>Rr.includes(e),Er=["r","rarity"],Nr=e=>Er.includes(e);var L=require("@flesh-and-blood/types"),ye=[{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"]}],me=ye.filter(({shorthands:e})=>e.some(r=>r.includes(" "))).map(e=>({...e,shorthands:e.shorthands.filter(r=>r.includes(" ")).map(r=>r.toLowerCase()).sort((r,t)=>t.length-r.length)})),Ce=ye.filter(({shorthands:e})=>e.some(r=>!r.includes(" "))).map(e=>({...e,shorthands:e.shorthands.filter(r=>!r.includes(" ")).map(r=>r.toLowerCase()).sort((r,t)=>t.length-r.length)}));var _=e=>$(e.toLowerCase().trim().replace(y,"")),$=e=>e.normalize("NFD").replace(/\p{Diacritic}/gu,""),q=e=>e.replace(fe,"");var z=require("@flesh-and-blood/types");var Ne=new WeakMap,Oe=(e,r)=>{let t=new Map;for(let a of e)for(let i of r(a)||[]){let s=t.get(i);s?s.push(a):t.set(i,[a])}return t},Or=e=>{let r=new Map;for(let t of e){let a=t.types.includes(z.Type.Hero)&&!t.isCardBack,i=a?z.CardRole.Hero:(0,z.getCardRole)(t);if(a||i!==z.CardRole.Hero){let o=r.get(i);o?o.push(t):r.set(i,[t])}}return r},Hr=e=>{let r,t,a,i,s=()=>{if(!r){let f=new Map,d=new Map,M=[],p=new Map,u=0;for(let S of e){f.set(S.cardIdentifier,S),d.set(S.cardIdentifier,u),u++;let m=_(S.name),x=p.get(m);x?x.push(S):(p.set(m,[S]),M.push(m))}r={cardByCardIdentifier:f,corpusPositionByCardIdentifier:d,cleanedNames:M,pitchCycleByCleanedName:p}}return r},o=f=>{let{corpusPositionByCardIdentifier:d}=s(),M=({cardIdentifier:p})=>d.get(p)||0;return[...f].sort((p,u)=>M(p)-M(u))},n=f=>s().cardByCardIdentifier.get(f),c=f=>{let{cardByCardIdentifier:d}=s(),M=[];for(let p of f||[]){let u=d.get(p);u&&M.push(u)}return o(M)},F=f=>{let{pitchCycleByCleanedName:d}=s(),M=n(f);return M?d.get(_(M.name))||[]:[]},h=f=>{let{cleanedNames:d,pitchCycleByCleanedName:M}=s(),p=_(f),u=M.get(p);if(!u){let S=d.find(m=>m.includes(p));S&&(u=M.get(S))}return u||[]},g=f=>c(n(f)?.oppositeSideCardIdentifiers),b=f=>c(n(f)?.referencedCards),C=f=>(t||(t=Oe(e,({referencedCards:d})=>d)),t.get(f)||[]),A=f=>c(n(f)?.createdExtras);return{cards:e,getCard:n,getPitchCycle:F,getCardsByName:h,getOppositeSide:g,getReferences:b,getReferencedBy:C,getCreates:A,getCreatedBy:f=>(a||(a=Oe(e,({createdExtras:d})=>d)),a.get(f)||[]),getCreatedClosure:f=>{let d=new Map,M=new Set,p=[...f];for(let u of p)if(!M.has(u)){M.add(u);for(let m of A(u))d.set(m.cardIdentifier,m),p.push(m.cardIdentifier)}return o([...d.values()])},getByRole:f=>(i||(i=Or(e)),i.get(f)||[]),getCardsInCorpusOrder:o}},Me=e=>{let r=Ne.get(e);return r||(r=Hr(e),Ne.set(e,r)),r},Fe=(e,r)=>e.getPitchCycle(r.cardIdentifier),ae=(e,r)=>e.getCardsByName(r),He=(e,r)=>{let t=new Map;for(let a of r)for(let i of Fe(e,a))t.set(i.cardIdentifier,i);return e.getCardsInCorpusOrder([...t.values()])},ie=(e,r)=>{let t=[];for(let a of Fe(e,r))t.push(...e.getReferencedBy(a.cardIdentifier));return He(e,t)},se=(e,r)=>{let t=[];for(let a of Fe(e,r))t.push(...e.getReferences(a.cardIdentifier));return He(e,t)};var dr=[">=",">","<=","<"],cr=["!","-"],Vr={property:"arcane",specialProperty:"specialArcane",isNumber:!0,partialMatch:!0},Se={property:"artists",isArray:!0,partialMatch:!0},Ve={property:"n/a",isMeta:!0},Ge={property:"bonds",isArray:!0},Gr={property:"cardIdentifier",isString:!0,isNormalized:!0},We=(e,{isAnd:r,isExcluded:t,isOptional:a,modifier:i})=>({filterToPropertyMapping:Gr,values:[...e],valuesSet:e,isAnd:r,isOr:!0,modifier:i,isExcluded:t,isOptional:a}),Wr={property:"n/a"},Ue={property:"classes",isArray:!0,partialMatch:!0},Ke={property:"cost",specialProperty:"specialCost",isNumber:!0,partialMatch:!0},Y={property:"defense",specialProperty:"specialDefense",isNumber:!0},ze={property:"flows",isArray:!0},je={nestedProperty:"foiling",property:"printings",isArray:!0},qe={property:"fusions",isArray:!0},_e={property:"intellect",isNumber:!0},$e={property:"keywords",isArray:!0},ve={property:"n/a",isMeta:!0},Ye={property:"life",specialProperty:"specialLife",isNumber:!0},Pe={property:"meta",isArray:!0},Je={property:"name",isString:!0,partialMatch:!0},Ae={property:"pitch",isNumber:!0},Qe={property:"firstReleaseDate",isDate:!0},oe={property:"power",specialProperty:"specialPower",isNumber:!0},Ur={property:"setIdentifiers",isArray:!0,partialMatch:!0},Xe={property:"n/a",isMeta:!0},Kr={property:"n/a"},zr={property:"n/a"},Ze={property:"sets",isArray:!0,partialMatch:!0},Te={property:"shorthands",isArray:!0,partialMatch:!0},ne={property:"specializations",isArray:!0,partialMatch:!0},er={property:"subtypes",isArray:!0},rr={property:"types",isArray:!0},tr={property:"talents",isArray:!0},jr={property:"functionalText",hasMarkup:!0,isString:!0,partialMatch:!0},qr={property:"traits",isArray:!0,partialMatch:!0},_r={property:"typeText",isString:!0,partialMatch:!0},le={nestedProperty:"treatments",property:"printings",isArray:!0,isNestedPropertyArray:!0},$r={property:"firstReleaseDate",isString:!0,partialMatch:!0},ke={arcane:Vr,a:Se,artist:Se,art:Se,attack:oe,b:Y,block:Y,banned:Ve,bond:Ge,bonds:Ge,c:Ue,class:Ue,chain:Wr,co:Ke,cost:Ke,color:Ae,d:Y,def:Y,defense:Y,flow:ze,flows:ze,f:qe,fusion:qe,foil:je,foiling:je,i:_e,intellect:_e,is:Pe,k:$e,keyword:$e,l:ve,legal:ve,hero:ve,li:Ye,life:Ye,meta:Pe,n:Je,name:Je,p:Ae,pitch:Ae,pwr:oe,pow:oe,power:oe,print:Ur,r:Xe,rarity:Xe,referencedby:Kr,references:zr,rf:Ve,s:Ze,set:Ze,short:Te,shorthand:Te,shorthands:Te,sp:ne,spec:ne,specialization:ne,specializations:ne,st:er,subtype:er,t:rr,type:rr,tal:tr,talent:tr,text:jr,trait:qr,treat:le,treatment:le,var:le,variation:le,x:_r,year:$r},Yr=[{text:l.Release.ClassicBattlesRhinarDorinthea.toLowerCase(),override:l.Release.ClassicBattlesRhinarDorinthea.toLowerCase().replaceAll(y,"")}],Jr=e=>{let r=[],t=e.replaceAll("\u201D",'"');for(let{text:i,override:s}of Yr)t.includes(i)&&(t=t.replace(i,s));if(X(t)?.card)r.push(t);else{let i=t.split(/[ ]+/),s="",o=0;for(let n of i)o===2&&(r.push(s.trim().replaceAll('"',"")),s="",o=0),o<2&&n.split('"').length===2?(s+=" "+n,o++):o===0&&s===""?r.push(n):o===1&&(s+=" "+n);o===2&&(r.push(s.trim().replaceAll('"',"")),s="",o=0)}return r},Qr=20,Ie=(e,r,t=[],a=[],i=it())=>{let s=e.trim().toLowerCase();for(let{expanded:P,shorthands:f}of me)for(let d of f)if(s.includes(d)){s=s.replace(d,P.join(" "));break}for(let[P,f]of Object.entries(l.setToSetIdentifierMappings))s.includes(P.toLowerCase())&&(s=s.replace(P.toLowerCase(),f[0]));let o=Jr(s),n=[];for(let P of o){let f=Ce.find(({shorthands:d})=>d.includes(P));f&&!f.isCardProperty?n.push(...f.expanded):n.push(P)}let c=[],F=[],h=[],g=[],b=!1,C=[],A=[],D=[],H=[];for(let P of n)if(pt(P)){let[f,d]=P.split(":"),{modifier:M,values:p,isAnd:u,isOr:S}=dt(d),{filterKey:m,isExcluded:x,isOptional:B,isMeta:pe}=ct(f),U=!1;if(pe){if(["rarity","r"].includes(m)){let V=lt(p);x||(A=[...V]),p=V.map(T=>T.toLowerCase())}["legal","l","hero"].includes(m),c.push(...he(x,B,m,p,M,t))}else{if(["chain"].includes(m)){let T=new Set,I=[],E=new Set,N=w=>{T.add(w.cardIdentifier),E.has(w.name)||(E.add(w.name),I.push(w))},K=w=>{w.types.includes(l.Type.Hero)||N(w)};for(let w of p)if(w)for(let R of ae(r,w))N(R);let G=0;for(let w of I){if(G>Qr)break;for(let ue of se(r,w))K(ue);if(G===0)for(let ue of ie(r,w))K(ue);G++}c.push(We(T,{isAnd:u,isExcluded:x,isOptional:B,modifier:M})),U=!0}else if(["referencedby","references"].includes(m)){let T=["referencedby"].includes(m),I=new Set;for(let E of p)if(E)for(let N of ae(r,E)){let K=T?se(r,N):ie(r,N);for(let G of K)I.add(G.cardIdentifier)}c.push(We(I,{isAnd:u,isExcluded:x,isOptional:B,modifier:M})),U=!0}else if(["art","artist"].includes(m))F=p;else if(["print","prints","printing","printings"].includes(m))C=p;else if(["is","meta"].includes(m)){let T=[],I=[],E=[],N=[];for(let R of p)rt.includes(R)?T.push(R):tt.includes(R)?I.push(R):at.includes(R)?E.push(R):N.push(R);T.length>0&&(c.push({filterToPropertyMapping:Pe,values:[l.Meta.Reprint.toLowerCase().replaceAll(y,"")],isAnd:u,isOr:S,isExcluded:!x,isOptional:B}),U=N.length===0);let K=I.length>0;K&&c.push({filterToPropertyMapping:Qe,values:[i],isAnd:u,isOr:S,isExcluded:x,isOptional:B});let G=E.length>0;G&&c.push({filterToPropertyMapping:Qe,values:[i],isAnd:u,isOr:S,isExcluded:!x,isOptional:B}),(K||G)&&(U=N.length===0);let w=st(N);p=w.map(R=>R.toLowerCase().replaceAll(y,"")),w.includes(l.Meta.Expansion)&&!x&&(b=!0)}else["foiling","foil"].includes(m)?(g=ot(p),p=g.map(T=>T.toLowerCase())):["treat","treatment","var","variation"].includes(m)?(H=nt(p),p=H.map(T=>T.toLowerCase())):["set","s"].includes(m)?(D=Xr(p,a),p=D.map(T=>T.toLowerCase().replaceAll(y,""))):["pitch","p","color"].includes(m)&&(p=et(p));let V=ke[m];V&&!U&&c.push({filterToPropertyMapping:V,values:V.hasMarkup?p.map(T=>q(T)):p,isAnd:u,isOr:S,modifier:M,isExcluded:x,isOptional:B})}}else if(P){let f=X(P)?.card,d=be(P);f?h.push(`"${f.toLowerCase().replace(y,"")}"`):d&&d.length>0?c.push(...d):h.push(P.replace(y,""))}return{appliedFilters:c,attributes:{artists:F,foilings:g,isExpansionSlot:b,prints:C,rarities:A,releases:D,treatments:H},keywords:h}},Xr=(e,r=[])=>{let t=[];for(let a of e)t.push(...Zr(a,r));return t},Zr=(e,r=[])=>{let t=[],a=Object.values(l.Release).find(i=>i.toLowerCase().replaceAll(y,"")===e);if(a&&t.push(a),t.length===0){let i=l.setIdentifierToSetMappings[e];i&&t.push(i)}if(t.length===0){let i=Object.values(l.Release).filter(s=>s.toLowerCase().includes(e));i.length>0&&t.push(...i)}if(t.length===0){let i=r.find(s=>s.toLowerCase().replaceAll(y,"")===e);i&&t.push(i)}return t},xe={purple:4,blue:3,yellow:2,red:1,white:0},et=e=>{let r=[];for(let t of e)xe[t]||xe[t]===0?r.push(xe[t].toString()):r.push(t);return r},rt=["unique"],tt=["preview","spoiler","unreleased"],at=["released"],it=()=>{let e=new Date,r=`${e.getMonth()+1}`.padStart(2,"0"),t=`${e.getDate()}`.padStart(2,"0");return`${e.getFullYear()}-${r}-${t}`},ar={dual:l.Meta.DualClass,exp:l.Meta.Expansion,expansion:l.Meta.Expansion,expansionSlot:l.Meta.Expansion,rainbow:l.Meta.Rainbow,reprint:l.Meta.Reprint,reprints:l.Meta.Reprint},st=e=>{let r=[];for(let t of e)ar[t]?r.push(ar[t]):l.Meta[t]&&r.push(l.Meta[t]);if(e.length>0&&r.length===0){for(let t of Object.values(l.Meta))for(let a of e)if(t.toLowerCase().includes(a)){r.push(t);break}}return r},ir={r:l.Foiling.Rainbow,rf:l.Foiling.Rainbow,rainbow:l.Foiling.Rainbow,c:l.Foiling.Cold,cf:l.Foiling.Cold,cold:l.Foiling.Cold,g:l.Foiling.Gold,gf:l.Foiling.Gold,gold:l.Foiling.Gold},ot=e=>{let r=[];for(let t of e)ir[t]&&r.push(ir[t]);return r},sr={...Object.values(l.Treatment).reduce((e,r)=>(e[r.toLowerCase()]=r,e),{}),aa:l.Treatment.AA,alt:l.Treatment.AA,"alt art":l.Treatment.AA,ab:l.Treatment.AB,"alt border":l.Treatment.AB,at:l.Treatment.AT,"alt text":l.Treatment.AT,ea:l.Treatment.EA,extended:l.Treatment.EA,"extended art":l.Treatment.EA,fa:l.Treatment.FA,full:l.Treatment.FA,"full art":l.Treatment.FA},nt=e=>{let r=[];for(let t of e)sr[t]?r.push(sr[t]):l.Treatment[t.toUpperCase()]&&r.push(l.Treatment[t.toUpperCase()]);return r},we={b:l.Rarity.Basic,c:l.Rarity.Common,f:l.Rarity.Fabled,l:l.Rarity.Legendary,m:l.Rarity.Majestic,p:l.Rarity.Promo,r:l.Rarity.Rare,s:l.Rarity.SuperRare,t:l.Rarity.Token,v:l.Rarity.Marvel},lt=e=>{let r=[];for(let t of e)we[t]?r.push(we[t]):r.push(t);return r},dt=e=>{let r=[],t,a,i=dr.find(s=>e.includes(s));if(i){let[,s]=e.split(i);or(s)?(t=!0,r.push(...s.trim().split("+").map(o=>o.replace(y,"")))):nr(s)?(a=!0,r.push(...s.trim().split(",").map(o=>o.replace(y,"")))):r.push(s.trim().replace(y,""))}else or(e)?(t=!0,r.push(...e.trim().split("+").map(s=>s.replace(y,"")))):nr(e)?(a=!0,r.push(...e.trim().split(",").map(s=>s.replace(y,"")))):e.startsWith('"')&&e.endsWith('"')?r.push(e.trim().replaceAll('"',"").replace(y,"")):r.push(e.trim().replace(y,""));return{modifier:i,values:r,isAnd:t,isOr:a}},ct=e=>{let r=ut(e);if(r){let[,t]=e.split(r);return{filterKey:t,isExcluded:!0,isOptional:!1,isMeta:lr(t)}}else return{filterKey:e,isExcluded:!1,isOptional:!1,isMeta:lr(e)}},pt=e=>e.indexOf(":")>=0,or=e=>e.indexOf("+")>=0,nr=e=>e.indexOf(",")>=0,lr=e=>!!ke[e]?.isMeta,ut=e=>cr.find(r=>e.includes(r))?.slice(0,1);var v=require("@flesh-and-blood/types"),pr={artists:["Hoodwill"],cardIdentifier:"fangs-a-lot-blue",classes:[v.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:[v.Hero.Kayo,v.Hero.Levia,v.Hero.Rhinar],printings:[{artists:["Hoodwill"],identifier:"FNG000",image:"FNG000",print:"FNG000",rarity:v.Rarity.Rare,set:v.Release.Promos},{artists:["Hoodwill"],identifier:"FNG000",image:"FNG000_Marvel",print:`FNG000-${v.Treatment.FA}`,rarity:v.Rarity.Marvel,set:v.Release.Promos,treatment:v.Treatment.FA}],name:"Fangs A Lot",rarities:[v.Rarity.Rare,v.Rarity.Marvel],rarity:v.Rarity.Rare,sets:[v.Release.Promos],setIdentifiers:["FNG000"],specialImage:"FNG000_Marvel",subtypes:[v.Subtype.Attack],types:[v.Type.Action],typeText:"Generic Action - Attack"},ur=[{keyword:pr.name.toLowerCase(),card:pr}];var ft={getFn:(e,r)=>{let t=Be.default.config.getFn(e,r),a=t;if(Array.isArray(t))a=t.map(i=>$(i.replace(y,"")));else if(t){let i=$(t).replace(y,"");a=r.includes("functionalText")?q(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},De=class{constructor(r,t=[],a=[],i=!1){this.getFuse=()=>(this.fuse||(this.fuse=new Be.default(this.cards,ft)),this.fuse);this.log=(r,...t)=>{this.debug&&console.log(r,...t)};this.search=(r,t)=>{let a,{appliedFilters:i,attributes:s,keywords:o}=Ie(r,this.index,this.additionalHeroes,this.additionalSets),n=o.join(" "),c=t?ur.filter(d=>d.keyword===n):[];if(c.length>0?a=c.map(({card:d})=>d):o.length?a=this.getFuse().search(n).map(d=>d.item):a=[...this.cards],i.length&&(a=a.filter(d=>d&&gr(d,i))),o.length===0){let d="";if(s.releases.length===1)try{let u=s.releases[0];d=de.setToSetIdentifierMappings[u][0].toUpperCase()}catch(u){console.error("Error getting set identifier from search",u)}if(!d&&s.prints.length===1)try{let u=s.prints[0];de.setIdentifierToSetMappings[u]&&(d=u.toUpperCase())}catch(u){console.error("Error getting set identifier from search",u)}d?a.sort((u,S)=>{let m=u.setIdentifiers.find(B=>B.includes(d))?.replace(d,""),x=S.setIdentifiers.find(B=>B.includes(d))?.replace(d,"");return m&&x?m.localeCompare(x):-1}):a.sort((u,S)=>u.name===S.name?`${u.pitch}`.localeCompare(`${S.pitch}`):u.name.localeCompare(S.name))}else{let d=[],M=[],p=o.map(u=>u.toLowerCase().replace(y,"")).join(" ");for(let u of a)u.name.toLowerCase().replace(y,"")===p?d.push(u):M.push(u);a=[...d,...M]}let F,{artists:h,isExpansionSlot:g,foilings:b,prints:C,rarities:A,releases:D,treatments:H}=s;(h.length>0||g||b.length>0||C.length>0||A.length>0||D.length>0||H.length>0)&&(F=a.map(d=>{let M=d.printings.filter(p=>{let u=!!p.image,S=h.length===0||h.some(I=>p.artists.find(E=>E.replace(y,"").toLowerCase().includes(I))),m=!g||g===p.isExpansionSlot,x=b.length===0||b.includes(p.foiling),B=C.length===0||C.some(I=>p.identifier.includes(I.toUpperCase())),pe=A.length===0||A.includes(p.rarity),U=D.length===0||D.includes(p.set),V=H.length===0||p.treatments?.some(I=>H.includes(I));return u&&S&&m&&x&&B&&pe&&U&&V});return{...d,matchingPrintings:M}}));let f=F?.length>0?F:a;return{appliedFilters:i,attributes:s,keywords:o,searchResults:f}};let s=Array.isArray(t)?{additionalHeroes:t,additionalSets:a,debug:i}:t;this.additionalHeroes=s.additionalHeroes||[],this.additionalSets=s.additionalSets||[],this.cards=[...r],this.debug=s.debug||!1,this.index=s.index||Me(r)}},fr=De,gr=(e,r)=>{let t=!0,a=!1;for(let i of r){let s=i.isOptional,{isNumber:o,isString:n,isArray:c,isBoolean:F,isDate:h}=i.filterToPropertyMapping;if(o){let g=gt(e,i);s?g&&(a=!0):t=t&&g}else if(n){let g=ht(e,i);s?g&&(a=!0):t=t&&g}else if(c){let g=bt(e,i,r);s?g&&(a=!0):t=t&&g}else if(F){let g=yt(e,i);s?g&&(a=!0):t=t&&g}else if(h){let g=mt(e,i);s?g&&(a=!0):t=t&&g}}return t},gt=(e,r)=>{if(J(r,e)){let{values:t,modifier:a,isExcluded:i,filterToPropertyMapping:{partialMatch:s}}=r,o=ce(e,r);if(o!=null&&!isNaN(o))if(o=parseInt(o),a)switch(a){case">=":{let n=t?.some(c=>o>=parseInt(c));return i?!n:n}case">":{let n=t?.some(c=>o>parseInt(c));return i?!n:n}case"<=":{let n=t?.some(c=>o<=parseInt(c));return i?!n:n}case"<":{let n=t?.some(c=>o<parseInt(c));return i?!n:n}default:return!1}else{let n=t?.some(c=>o===parseInt(c));return i?!n:n}else{let n=Mt(e,r)?.toLowerCase(),c=s?t?.some(F=>n?.includes(F)):t?.some(F=>n===F);return i?!c:c}}else return!0},ht=(e,r)=>{if(J(r,e)){let{values:t,valuesSet:a,isAnd:i,isExcluded:s,filterToPropertyMapping:{hasMarkup:o,isNormalized:n,partialMatch:c}}=r,F=ce(e,r),h=n?F:F?.replaceAll(y,"").toLowerCase(),g=o&&h?q(h):h;if(c){let b=i?t?.every(C=>g?.includes(C)):t?.some(C=>g?.includes(C));return s?!b:b}else{let b;return i?b=t?.every(C=>g===C):a?b=a.has(g):b=t?.some(C=>g===C),s?!b:b}}else return!0},bt=(e,r,t)=>{if(J(r,e)){let{values:a,isAnd:i,isExcluded:s,filterToPropertyMapping:{partialMatch:o}}=r,n=Ct(e,r,t).map(c=>c?.replaceAll(y,""));if(o){let c=i?a.every(h=>n?.some(g=>g?.toLowerCase().includes(h))):a.some(h=>n?.some(g=>g?.toLowerCase().includes(h))),F=n.length===0;return s?!c||F:c}else{let c=i?a.every(F=>n?.some(h=>h?.toLowerCase()===F)):a.some(F=>n?.some(h=>h?.toLowerCase()===F));return s?!c:c}}else return!0},yt=(e,r)=>{if(J(r,e)){let{isExcluded:t}=r,a=ce(e,r);return t?!a:a}else return!0},mt=(e,r)=>{if(J(r,e)){let{values:t,isExcluded:a}=r,i=ce(e,r),s=t?.some(o=>i>o);return a?!s:s}else return!0},ce=(e,r)=>{let{filterToPropertyMapping:t}=r;return e[t.property]},Ct=(e,r,t)=>{let{filterToPropertyMapping:{isNestedPropertyArray:a,nestedProperty:i,property:s}}=r,o=e[s]||[],n=[],c=Object.keys(e.legalOverrides||{}).length>0,F=r.filterToPropertyMapping.property==="legalHeroes",h=t.find(({filterToPropertyMapping:b})=>b.property==="legalFormats");if(c&&F&&!!h){let b=new Set;for(let{format:C,heroes:A}of e.legalOverrides||[])if(h.values.includes(C.toLowerCase()))for(let D of A)b.add(D);n=Array.from(b)}if(n.length===0)if(i){let b=new Set;for(let C of o)if(a){let A=C[i]||[];for(let D of A)b.add(D)}else{let A=C[i];A&&b.add(A)}n=Array.from(b)}else n=o;return n},Mt=(e,r)=>{let{filterToPropertyMapping:t}=r;return e[t.specialProperty]},J=({cardTypes:e},{types:r,subtypes:t})=>!e||e?.some(a=>r.map(i=>i.toLowerCase()).includes(a.toLowerCase())||t.map(i=>i.toLowerCase()).includes(a.toLowerCase()));var Ft=(e,r)=>{let t=[];if(e)for(let a of r){let i=a.name===e.name,s=a.cardIdentifier!==e.cardIdentifier,o=a.pitch!==e.pitch;i&&s&&o&&t.push(a)}return t},St=(e,r)=>{let t=new Set(e?.referencedCards),a=[];for(let i of r)t.has(i.cardIdentifier)&&a.push(i);return a},vt=e=>{let r=new Map;for(let t of e)for(let a of t.referencedCards||[]){let i=r.get(a);i?i.push(t):r.set(a,[t])}return r},At=(e,r)=>{let t=new Set;for(let i of e)for(let s of i.createdExtras||[])t.add(s);let a=[];for(let i of r)t.has(i.cardIdentifier)&&a.push(i);return a};0&&(module.exports={FilterProperty,MARKUP,PUNCTUATION,RARITY_VALUES_MAPPING,abbreviations,availableExclusions,availableModifiers,filterCard,filtersToCardPropertyMappings,getAbbreviation,getAbbreviationByCard,getCardsByName,getCardsByReferencedCardIdentifier,getCardsReferencedBy,getCardsReferencing,getCatalogueIndex,getCleanText,getExcludedMetaFilters,getKeywordsAndAppliedFiltersFromText,getMetaFilters,getNormalizedText,getOtherPitches,getReferencedCards,getTextWithoutMarkup,getTokensReferencedByCards,multiWordShorthands,shorthands,singleWordShorthands});
package/dist/search.d.ts CHANGED
@@ -1,8 +1,23 @@
1
1
  import { Card, DoubleSidedCard, Foiling, Hero, Printing, Release, Treatment } from "@flesh-and-blood/types";
2
2
  import { AppliedFilter } from "./filters.js";
3
+ import { CatalogueIndex } from "./searchIndex.js";
3
4
  export interface SearchCard extends DoubleSidedCard {
4
5
  matchingPrintings?: Printing[];
5
6
  }
7
+ export interface SearchOptions {
8
+ additionalHeroes?: Hero[];
9
+ additionalSets?: Release[];
10
+ debug?: boolean;
11
+ /**
12
+ * The catalogue the parser resolves names and relations against. A pool
13
+ * searched out of a larger catalogue shares the catalogue's index, so a
14
+ * relation is answered from every card that carries it while the search still
15
+ * answers with the pool alone. Left out, the corpus is its own catalogue.
16
+ * The pool must be a subset of the catalogue the index was built over: a pool
17
+ * card the catalogue does not hold resolves to nothing, with no error.
18
+ */
19
+ index?: CatalogueIndex;
20
+ }
6
21
  export interface SearchResults {
7
22
  appliedFilters: AppliedFilter[];
8
23
  keywords: string[];
@@ -22,7 +37,9 @@ declare class Search {
22
37
  private debug;
23
38
  private fuse;
24
39
  private index;
40
+ constructor(cards: DoubleSidedCard[], options?: SearchOptions);
25
41
  constructor(cards: DoubleSidedCard[], additionalHeroes?: Hero[], additionalSets?: Release[], debug?: boolean);
42
+ private getFuse;
26
43
  log: (message?: any, ...optionalParams: any[]) => void;
27
44
  search: (text: string, includeMemes?: boolean) => SearchResults;
28
45
  }
package/dist/search.js CHANGED
@@ -10,9 +10,44 @@ import {
10
10
  import { memes } from "./memes.js";
11
11
  import { getNormalizedText, getTextWithoutMarkup } from "./helpers.js";
12
12
  import { FilterProperty } from "./metaFilters.js";
13
- import { buildSearchIndex } from "./searchIndex.js";
13
+ import { getCatalogueIndex } from "./searchIndex.js";
14
+ const searchOptions = {
15
+ getFn: (obj, path) => {
16
+ const value = Fuse.config.getFn(obj, path);
17
+ let normalizedValue = value;
18
+ if (Array.isArray(value)) {
19
+ normalizedValue = value.map(
20
+ (val) => getNormalizedText(val.replace(PUNCTUATION, ""))
21
+ );
22
+ } else if (value) {
23
+ const text = getNormalizedText(value).replace(PUNCTUATION, "");
24
+ normalizedValue = path.includes("functionalText") ? getTextWithoutMarkup(text) : text;
25
+ }
26
+ return normalizedValue;
27
+ },
28
+ ignoreLocation: true,
29
+ includeScore: true,
30
+ keys: [
31
+ { name: "name", weight: 10 },
32
+ { name: "functionalText", weight: 6 },
33
+ { name: "shorthands", weight: 4 },
34
+ { name: "setIdentifiers", weight: 2 },
35
+ { name: "traits", weight: 4 },
36
+ { name: "typeText", weight: 6 }
37
+ ],
38
+ threshold: 0.15,
39
+ useExtendedSearch: true
40
+ };
14
41
  class Search {
15
- constructor(cards, additionalHeroes = [], additionalSets = [], debug = false) {
42
+ constructor(cards, additionalHeroesOrOptions = [], additionalSets = [], debug = false) {
43
+ // Scoring the corpus is the costly half of a search, so a catalogue that is
44
+ // only ever filtered never pays to index it.
45
+ this.getFuse = () => {
46
+ if (!this.fuse) {
47
+ this.fuse = new Fuse(this.cards, searchOptions);
48
+ }
49
+ return this.fuse;
50
+ };
16
51
  this.log = (message, ...optionalParams) => {
17
52
  if (this.debug) {
18
53
  console.log(message, ...optionalParams);
@@ -31,7 +66,7 @@ class Search {
31
66
  if (matchingMemes.length > 0) {
32
67
  results = matchingMemes.map(({ card }) => card);
33
68
  } else if (keywords.length) {
34
- results = this.fuse.search(keyword).map((result) => result.item);
69
+ results = this.getFuse().search(keyword).map((result) => result.item);
35
70
  } else {
36
71
  results = [...this.cards];
37
72
  }
@@ -135,42 +170,12 @@ class Search {
135
170
  searchResults
136
171
  };
137
172
  };
138
- const searchOptions = {
139
- getFn: (obj, path) => {
140
- const value = Fuse.config.getFn(obj, path);
141
- if (!value) {
142
- return value;
143
- } else if (Array.isArray(value)) {
144
- return value.map(
145
- (val) => getNormalizedText(val.replace(PUNCTUATION, ""))
146
- );
147
- } else {
148
- const text = getNormalizedText(value).replace(
149
- PUNCTUATION,
150
- ""
151
- );
152
- return path.includes("functionalText") ? getTextWithoutMarkup(text) : text;
153
- }
154
- },
155
- ignoreLocation: true,
156
- includeScore: true,
157
- keys: [
158
- { name: "name", weight: 10 },
159
- { name: "functionalText", weight: 6 },
160
- { name: "shorthands", weight: 4 },
161
- { name: "setIdentifiers", weight: 2 },
162
- { name: "traits", weight: 4 },
163
- { name: "typeText", weight: 6 }
164
- ],
165
- threshold: 0.15,
166
- useExtendedSearch: true
167
- };
168
- this.additionalHeroes = additionalHeroes;
169
- this.additionalSets = additionalSets;
173
+ const options = Array.isArray(additionalHeroesOrOptions) ? { additionalHeroes: additionalHeroesOrOptions, additionalSets, debug } : additionalHeroesOrOptions;
174
+ this.additionalHeroes = options.additionalHeroes || [];
175
+ this.additionalSets = options.additionalSets || [];
170
176
  this.cards = [...cards];
171
- this.debug = debug;
172
- this.fuse = new Fuse([...cards], searchOptions);
173
- this.index = buildSearchIndex(this.cards);
177
+ this.debug = options.debug || false;
178
+ this.index = options.index || getCatalogueIndex(cards);
174
179
  }
175
180
  }
176
181
  var search_default = Search;
@@ -1,26 +1,54 @@
1
- import { Card, DoubleSidedCard } from "@flesh-and-blood/types";
1
+ import { Card, CardRole, DoubleSidedCard } from "@flesh-and-blood/types";
2
2
  /**
3
- * Lookups over a corpus, built once per `Search` instance. Every relation is
4
- * keyed at the name level: a reference is between Cards, so a reference to or
5
- * from one pitch counts for every pitch of that card.
3
+ * Everything a corpus can be asked about its cards: lookups, the relations the
4
+ * cards carry, and what each card is for. Every relation is identifier-level,
5
+ * so a card named at one pitch answers for that pitch alone; widening a
6
+ * relation to the whole name is the reader's rule rather than the corpus's.
7
+ * Every list is the index's own, shared across reads and never copied, so a
8
+ * reader that needs to reorder or grow one works on a copy.
6
9
  */
7
- export interface SearchIndex {
8
- cards: DoubleSidedCard[];
9
- cardByCardIdentifier: Map<string, DoubleSidedCard>;
10
- /** Corpus order, for restoring it after a lookup returns cards out of order. */
11
- corpusPositionByCardIdentifier: Map<string, number>;
12
- /** Distinct cleaned names, in the order the corpus first carries them. */
13
- cleanedNames: string[];
14
- pitchCycleByCleanedName: Map<string, DoubleSidedCard[]>;
15
- referencingCardsByCardIdentifier: Map<string, DoubleSidedCard[]>;
10
+ export interface CatalogueIndex {
11
+ cards: readonly DoubleSidedCard[];
12
+ getCard: (cardIdentifier: string) => DoubleSidedCard | undefined;
13
+ /** Every pitch of the card's name, the card itself among them. */
14
+ getPitchCycle: (cardIdentifier: string) => readonly DoubleSidedCard[];
15
+ /**
16
+ * Every pitch of the named card. An exact name wins; failing that the first
17
+ * name the corpus carries containing the text answers, so a fragment
18
+ * resolves to one card.
19
+ */
20
+ getCardsByName: (name: string) => readonly DoubleSidedCard[];
21
+ /** The cards the card is printed on the back of. */
22
+ getOppositeSide: (cardIdentifier: string) => readonly DoubleSidedCard[];
23
+ /** The cards the card names. */
24
+ getReferences: (cardIdentifier: string) => readonly DoubleSidedCard[];
25
+ /** The cards naming the card. */
26
+ getReferencedBy: (cardIdentifier: string) => readonly DoubleSidedCard[];
27
+ /** The extras the card brings into play. */
28
+ getCreates: (cardIdentifier: string) => readonly DoubleSidedCard[];
29
+ /** The cards bringing the card into play. */
30
+ getCreatedBy: (cardIdentifier: string) => readonly DoubleSidedCard[];
31
+ /**
32
+ * What the cards bring into play, what those creations create, and on down
33
+ * the chain. A card joins the answer only when something the walk reaches
34
+ * creates it, so a card asked about appears only if the chain circles back
35
+ * to it.
36
+ */
37
+ getCreatedClosure: (cardIdentifiers: string[]) => readonly DoubleSidedCard[];
38
+ getByRole: (role: CardRole) => readonly DoubleSidedCard[];
39
+ /** The cards handed in, as a new array in the order the corpus holds them. */
40
+ getCardsInCorpusOrder: (cardsToOrder: readonly DoubleSidedCard[]) => DoubleSidedCard[];
16
41
  }
17
- export declare const buildSearchIndex: (cards: DoubleSidedCard[]) => SearchIndex;
18
42
  /**
19
- * Every pitch of the named card. An exact name wins; failing that the first
20
- * name containing the text answers, so a fragment resolves to one card.
43
+ * The index for a corpus, one per array, so everything reading the same cards
44
+ * shares its maps. Each map is built the first time a read asks for it. The
45
+ * array is treated as immutable from that first read on: a caller that changes
46
+ * which cards the catalogue holds builds a new array.
21
47
  */
22
- export declare const getCardsByName: (index: SearchIndex, name: string) => DoubleSidedCard[];
48
+ export declare const getCatalogueIndex: (cards: DoubleSidedCard[]) => CatalogueIndex;
49
+ /** {@link CatalogueIndex.getCardsByName}, as a free function over an index. */
50
+ export declare const getCardsByName: (index: CatalogueIndex, name: string) => readonly DoubleSidedCard[];
23
51
  /** The cards naming the card, at every pitch of both. */
24
- export declare const getCardsReferencing: (index: SearchIndex, card: Card) => DoubleSidedCard[];
52
+ export declare const getCardsReferencing: (index: CatalogueIndex, card: Card) => DoubleSidedCard[];
25
53
  /** The cards the card names, at every pitch of both. */
26
- export declare const getCardsReferencedBy: (index: SearchIndex, card: Card) => DoubleSidedCard[];
54
+ export declare const getCardsReferencedBy: (index: CatalogueIndex, card: Card) => DoubleSidedCard[];
@@ -1,85 +1,210 @@
1
+ import {
2
+ CardRole,
3
+ getCardRole,
4
+ Type
5
+ } from "@flesh-and-blood/types";
1
6
  import { getCleanText } from "./helpers.js";
2
- import { getCardsByReferencedCardIdentifier } from "./related.js";
3
- const buildSearchIndex = (cards) => {
4
- const cardByCardIdentifier = /* @__PURE__ */ new Map();
5
- const corpusPositionByCardIdentifier = /* @__PURE__ */ new Map();
6
- const cleanedNames = [];
7
- const pitchCycleByCleanedName = /* @__PURE__ */ new Map();
8
- let corpusPosition = 0;
7
+ const catalogueIndexByCards = /* @__PURE__ */ new WeakMap();
8
+ const getNamingCardsByNamedCardIdentifier = (cards, getNamedCardIdentifiers) => {
9
+ const namingCardsByNamedCardIdentifier = /* @__PURE__ */ new Map();
10
+ for (const card of cards) {
11
+ for (const namedCardIdentifier of getNamedCardIdentifiers(card) || []) {
12
+ const namingCards = namingCardsByNamedCardIdentifier.get(namedCardIdentifier);
13
+ if (namingCards) {
14
+ namingCards.push(card);
15
+ } else {
16
+ namingCardsByNamedCardIdentifier.set(namedCardIdentifier, [card]);
17
+ }
18
+ }
19
+ }
20
+ return namingCardsByNamedCardIdentifier;
21
+ };
22
+ const getCardsByRole = (cards) => {
23
+ const cardsByRole = /* @__PURE__ */ new Map();
9
24
  for (const card of cards) {
10
- cardByCardIdentifier.set(card.cardIdentifier, card);
11
- corpusPositionByCardIdentifier.set(card.cardIdentifier, corpusPosition);
12
- corpusPosition++;
13
- const cleanedName = getCleanText(card.name);
14
- const pitchCycle = pitchCycleByCleanedName.get(cleanedName);
15
- if (pitchCycle) {
16
- pitchCycle.push(card);
17
- } else {
18
- pitchCycleByCleanedName.set(cleanedName, [card]);
19
- cleanedNames.push(cleanedName);
25
+ const isPickableHero = card.types.includes(Type.Hero) && !card.isCardBack;
26
+ const role = isPickableHero ? CardRole.Hero : getCardRole(card);
27
+ const hasBucket = isPickableHero || role !== CardRole.Hero;
28
+ if (hasBucket) {
29
+ const cardsInRole = cardsByRole.get(role);
30
+ if (cardsInRole) {
31
+ cardsInRole.push(card);
32
+ } else {
33
+ cardsByRole.set(role, [card]);
34
+ }
20
35
  }
21
36
  }
37
+ return cardsByRole;
38
+ };
39
+ const getNewCatalogueIndex = (cards) => {
40
+ let cardLookups;
41
+ let referencingCardsByCardIdentifier;
42
+ let creatingCardsByCardIdentifier;
43
+ let cardsByRole;
44
+ const getCardLookups = () => {
45
+ if (!cardLookups) {
46
+ const cardByCardIdentifier = /* @__PURE__ */ new Map();
47
+ const corpusPositionByCardIdentifier = /* @__PURE__ */ new Map();
48
+ const cleanedNames = [];
49
+ const pitchCycleByCleanedName = /* @__PURE__ */ new Map();
50
+ let corpusPosition = 0;
51
+ for (const card of cards) {
52
+ cardByCardIdentifier.set(card.cardIdentifier, card);
53
+ corpusPositionByCardIdentifier.set(card.cardIdentifier, corpusPosition);
54
+ corpusPosition++;
55
+ const cleanedName = getCleanText(card.name);
56
+ const pitchCycle = pitchCycleByCleanedName.get(cleanedName);
57
+ if (pitchCycle) {
58
+ pitchCycle.push(card);
59
+ } else {
60
+ pitchCycleByCleanedName.set(cleanedName, [card]);
61
+ cleanedNames.push(cleanedName);
62
+ }
63
+ }
64
+ cardLookups = {
65
+ cardByCardIdentifier,
66
+ corpusPositionByCardIdentifier,
67
+ cleanedNames,
68
+ pitchCycleByCleanedName
69
+ };
70
+ }
71
+ return cardLookups;
72
+ };
73
+ const getCardsInCorpusOrder = (cardsToOrder) => {
74
+ const { corpusPositionByCardIdentifier } = getCardLookups();
75
+ const getCorpusPosition = ({ cardIdentifier }) => corpusPositionByCardIdentifier.get(cardIdentifier) || 0;
76
+ return [...cardsToOrder].sort(
77
+ (first, second) => getCorpusPosition(first) - getCorpusPosition(second)
78
+ );
79
+ };
80
+ const getCard = (cardIdentifier) => getCardLookups().cardByCardIdentifier.get(cardIdentifier);
81
+ const getNamedCards = (cardIdentifiers) => {
82
+ const { cardByCardIdentifier } = getCardLookups();
83
+ const namedCards = [];
84
+ for (const cardIdentifier of cardIdentifiers || []) {
85
+ const namedCard = cardByCardIdentifier.get(cardIdentifier);
86
+ if (namedCard) {
87
+ namedCards.push(namedCard);
88
+ }
89
+ }
90
+ return getCardsInCorpusOrder(namedCards);
91
+ };
92
+ const getPitchCycle = (cardIdentifier) => {
93
+ const { pitchCycleByCleanedName } = getCardLookups();
94
+ const card = getCard(cardIdentifier);
95
+ return card ? pitchCycleByCleanedName.get(getCleanText(card.name)) || [] : [];
96
+ };
97
+ const getCardsByName2 = (name) => {
98
+ const { cleanedNames, pitchCycleByCleanedName } = getCardLookups();
99
+ const cleanedName = getCleanText(name);
100
+ let pitchCycle = pitchCycleByCleanedName.get(cleanedName);
101
+ if (!pitchCycle) {
102
+ const containingName = cleanedNames.find(
103
+ (candidate) => candidate.includes(cleanedName)
104
+ );
105
+ if (containingName) {
106
+ pitchCycle = pitchCycleByCleanedName.get(containingName);
107
+ }
108
+ }
109
+ return pitchCycle || [];
110
+ };
111
+ const getOppositeSide = (cardIdentifier) => getNamedCards(getCard(cardIdentifier)?.oppositeSideCardIdentifiers);
112
+ const getReferences = (cardIdentifier) => getNamedCards(getCard(cardIdentifier)?.referencedCards);
113
+ const getReferencedBy = (cardIdentifier) => {
114
+ if (!referencingCardsByCardIdentifier) {
115
+ referencingCardsByCardIdentifier = getNamingCardsByNamedCardIdentifier(
116
+ cards,
117
+ ({ referencedCards }) => referencedCards
118
+ );
119
+ }
120
+ return referencingCardsByCardIdentifier.get(cardIdentifier) || [];
121
+ };
122
+ const getCreates = (cardIdentifier) => getNamedCards(getCard(cardIdentifier)?.createdExtras);
123
+ const getCreatedBy = (cardIdentifier) => {
124
+ if (!creatingCardsByCardIdentifier) {
125
+ creatingCardsByCardIdentifier = getNamingCardsByNamedCardIdentifier(
126
+ cards,
127
+ ({ createdExtras }) => createdExtras
128
+ );
129
+ }
130
+ return creatingCardsByCardIdentifier.get(cardIdentifier) || [];
131
+ };
132
+ const getCreatedClosure = (cardIdentifiers) => {
133
+ const createdCardByCardIdentifier = /* @__PURE__ */ new Map();
134
+ const expandedCardIdentifiers = /* @__PURE__ */ new Set();
135
+ const cardIdentifiersToExpand = [...cardIdentifiers];
136
+ for (const cardIdentifier of cardIdentifiersToExpand) {
137
+ const isAlreadyExpanded = expandedCardIdentifiers.has(cardIdentifier);
138
+ if (!isAlreadyExpanded) {
139
+ expandedCardIdentifiers.add(cardIdentifier);
140
+ for (const createdCard of getCreates(cardIdentifier)) {
141
+ createdCardByCardIdentifier.set(
142
+ createdCard.cardIdentifier,
143
+ createdCard
144
+ );
145
+ cardIdentifiersToExpand.push(createdCard.cardIdentifier);
146
+ }
147
+ }
148
+ }
149
+ return getCardsInCorpusOrder([...createdCardByCardIdentifier.values()]);
150
+ };
151
+ const getByRole = (role) => {
152
+ if (!cardsByRole) {
153
+ cardsByRole = getCardsByRole(cards);
154
+ }
155
+ return cardsByRole.get(role) || [];
156
+ };
22
157
  return {
23
158
  cards,
24
- cardByCardIdentifier,
25
- corpusPositionByCardIdentifier,
26
- cleanedNames,
27
- pitchCycleByCleanedName,
28
- referencingCardsByCardIdentifier: getCardsByReferencedCardIdentifier(cards)
159
+ getCard,
160
+ getPitchCycle,
161
+ getCardsByName: getCardsByName2,
162
+ getOppositeSide,
163
+ getReferences,
164
+ getReferencedBy,
165
+ getCreates,
166
+ getCreatedBy,
167
+ getCreatedClosure,
168
+ getByRole,
169
+ getCardsInCorpusOrder
29
170
  };
30
171
  };
31
- const getPitchCycle = (index, card) => index.pitchCycleByCleanedName.get(getCleanText(card.name)) || [];
32
- const getCardsByName = (index, name) => {
33
- const cleanedName = getCleanText(name);
34
- let pitchCycle = index.pitchCycleByCleanedName.get(cleanedName);
35
- if (!pitchCycle) {
36
- const containingName = index.cleanedNames.find(
37
- (candidate) => candidate.includes(cleanedName)
38
- );
39
- if (containingName) {
40
- pitchCycle = index.pitchCycleByCleanedName.get(containingName);
41
- }
172
+ const getCatalogueIndex = (cards) => {
173
+ let catalogueIndex = catalogueIndexByCards.get(cards);
174
+ if (!catalogueIndex) {
175
+ catalogueIndex = getNewCatalogueIndex(cards);
176
+ catalogueIndexByCards.set(cards, catalogueIndex);
42
177
  }
43
- return pitchCycle || [];
178
+ return catalogueIndex;
44
179
  };
180
+ const getPitchCycleOfCard = (index, card) => index.getPitchCycle(card.cardIdentifier);
181
+ const getCardsByName = (index, name) => index.getCardsByName(name);
45
182
  const getCardsWithPitchSiblings = (index, cards) => {
46
183
  const cardByCardIdentifier = /* @__PURE__ */ new Map();
47
184
  for (const card of cards) {
48
- for (const pitch of getPitchCycle(index, card)) {
185
+ for (const pitch of getPitchCycleOfCard(index, card)) {
49
186
  cardByCardIdentifier.set(pitch.cardIdentifier, pitch);
50
187
  }
51
188
  }
52
- const getCorpusPosition = ({ cardIdentifier }) => index.corpusPositionByCardIdentifier.get(cardIdentifier) || 0;
53
- return [...cardByCardIdentifier.values()].sort(
54
- (first, second) => getCorpusPosition(first) - getCorpusPosition(second)
55
- );
189
+ return index.getCardsInCorpusOrder([...cardByCardIdentifier.values()]);
56
190
  };
57
191
  const getCardsReferencing = (index, card) => {
58
192
  const referencingCards = [];
59
- for (const pitch of getPitchCycle(index, card)) {
60
- referencingCards.push(
61
- ...index.referencingCardsByCardIdentifier.get(pitch.cardIdentifier) || []
62
- );
193
+ for (const pitch of getPitchCycleOfCard(index, card)) {
194
+ referencingCards.push(...index.getReferencedBy(pitch.cardIdentifier));
63
195
  }
64
196
  return getCardsWithPitchSiblings(index, referencingCards);
65
197
  };
66
198
  const getCardsReferencedBy = (index, card) => {
67
199
  const referencedCards = [];
68
- for (const pitch of getPitchCycle(index, card)) {
69
- for (const referencedCardIdentifier of pitch.referencedCards || []) {
70
- const referencedCard = index.cardByCardIdentifier.get(
71
- referencedCardIdentifier
72
- );
73
- if (referencedCard) {
74
- referencedCards.push(referencedCard);
75
- }
76
- }
200
+ for (const pitch of getPitchCycleOfCard(index, card)) {
201
+ referencedCards.push(...index.getReferences(pitch.cardIdentifier));
77
202
  }
78
203
  return getCardsWithPitchSiblings(index, referencedCards);
79
204
  };
80
205
  export {
81
- buildSearchIndex,
82
206
  getCardsByName,
83
207
  getCardsReferencedBy,
84
- getCardsReferencing
208
+ getCardsReferencing,
209
+ getCatalogueIndex
85
210
  };
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": "4.2.7",
4
+ "version": "5.0.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "main": "dist/index.cjs",
@@ -43,11 +43,11 @@
43
43
  "fuse.js": "^6.6.2"
44
44
  },
45
45
  "peerDependencies": {
46
- "@flesh-and-blood/types": "^4.0.0"
46
+ "@flesh-and-blood/types": "^5.0.0"
47
47
  },
48
48
  "devDependencies": {
49
- "@flesh-and-blood/cards": "^4.2.7",
50
- "@flesh-and-blood/types": "^4.1.1",
49
+ "@flesh-and-blood/cards": "^5.0.0",
50
+ "@flesh-and-blood/types": "^5.0.0",
51
51
  "@types/jest": "^29.5.11",
52
52
  "@types/node": "^20.10.5",
53
53
  "esbuild": "^0.19.10",
@@ -77,5 +77,5 @@
77
77
  "FAB",
78
78
  "FABTCG"
79
79
  ],
80
- "gitHead": "deafba2a831bdabfd1b157096eb11fb847bd6471"
80
+ "gitHead": "5289eeebf7551e40f1c012514d628573c617a6a1"
81
81
  }