@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 +2 -2
- package/dist/index.cjs +1 -1
- package/dist/search.d.ts +17 -0
- package/dist/search.js +43 -38
- package/dist/searchIndex.d.ts +47 -19
- package/dist/searchIndex.js +179 -54
- package/package.json +5 -5
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 {
|
|
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:
|
|
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 {
|
|
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,
|
|
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.
|
|
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
|
|
139
|
-
|
|
140
|
-
|
|
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.
|
|
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;
|
package/dist/searchIndex.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
|
8
|
-
cards: DoubleSidedCard[];
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
*
|
|
20
|
-
*
|
|
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
|
|
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:
|
|
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:
|
|
54
|
+
export declare const getCardsReferencedBy: (index: CatalogueIndex, card: Card) => DoubleSidedCard[];
|
package/dist/searchIndex.js
CHANGED
|
@@ -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
|
-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
|
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
|
|
185
|
+
for (const pitch of getPitchCycleOfCard(index, card)) {
|
|
49
186
|
cardByCardIdentifier.set(pitch.cardIdentifier, pitch);
|
|
50
187
|
}
|
|
51
188
|
}
|
|
52
|
-
|
|
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
|
|
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
|
|
69
|
-
|
|
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
|
+
"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": "^
|
|
46
|
+
"@flesh-and-blood/types": "^5.0.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@flesh-and-blood/cards": "^
|
|
50
|
-
"@flesh-and-blood/types": "^
|
|
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": "
|
|
80
|
+
"gitHead": "5289eeebf7551e40f1c012514d628573c617a6a1"
|
|
81
81
|
}
|