@flesh-and-blood/search 5.4.0 → 6.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,19 +14,19 @@ npm i @flesh-and-blood/search @flesh-and-blood/types
14
14
 
15
15
  ```ts
16
16
  import Searcher from "@flesh-and-blood/search";
17
- import { cards } from "@flesh-and-blood/cards";
17
+ import { cards, releases } from "@flesh-and-blood/cards";
18
18
 
19
- const searcher = new Searcher(cards);
19
+ const searcher = new Searcher(cards, { releases });
20
20
  const { searchResults } = searcher.search("rhinar go again");
21
21
  ```
22
22
 
23
- - `new Searcher(cards, additionalHeroes?, additionalSets?)`
23
+ - `new Searcher(cards, { releases, additionalHeroes? })`, or `{ index }` to share a catalogue index
24
+ built with `getCatalogueIndex(cards, releases)`
24
25
  - `.search(text)` → `SearchResults`: `{ searchResults: SearchCard[], appliedFilters, keywords, attributes }`
25
26
 
26
27
  Data-only modules are available as subpath imports (handy for lazy-loaded UI like a search-bar dropdown):
27
28
 
28
29
  ```ts
29
- import { abbreviations } from "@flesh-and-blood/search/abbreviations";
30
30
  import { shorthands } from "@flesh-and-blood/search/shorthands";
31
31
  ```
32
32
 
@@ -34,7 +34,7 @@ import { shorthands } from "@flesh-and-blood/search/shorthands";
34
34
 
35
35
  - Default export: **`Searcher`**, the search engine
36
36
  - Types: `SearchResults`, `SearchCard`
37
- - Data modules (subpath imports): `abbreviations`, `shorthands`, `memes`
37
+ - Data modules (subpath imports): `shorthands`, `memes`
38
38
  - Filter / meta-filter / helper utilities (`filters`, `metaFilters`, `helpers`, `constants`, `related`)
39
39
 
40
40
  ## Working with this project
@@ -1,4 +1,4 @@
1
- export declare const PUNCTUATION: RegExp;
1
+ export { PUNCTUATION } from "@flesh-and-blood/types";
2
2
  /**
3
3
  * The markdown emphasis that wraps keywords in a card's functional text. Kept
4
4
  * out of `PUNCTUATION` because an asterisk is also a printed card value:
package/dist/constants.js CHANGED
@@ -1,4 +1,4 @@
1
- const PUNCTUATION = /[!"#$%&'’(),./:;<=>?@[\]^_`|~]/g;
1
+ import { PUNCTUATION } from "@flesh-and-blood/types";
2
2
  const MARKUP = /\*/g;
3
3
  export {
4
4
  MARKUP,
@@ -1,4 +1,4 @@
1
- import { Bond, Card, Class, Flow, Foiling, Fusion, Hero, Keyword, Meta, Printing, Rarity, Release, Shorthand, Subtype, Talent, Trait, Treatment, Type } from "@flesh-and-blood/types";
1
+ import { Bond, Card, Class, Flow, Foiling, Fusion, Hero, Keyword, Meta, Printing, Rarity, Shorthand, Subtype, Talent, Trait, Treatment, Type } from "@flesh-and-blood/types";
2
2
  /**
3
3
  * Which filter a key names, rather than how it was spelled: every alias of a
4
4
  * filter answers with the one category, and a key naming no filter answers
@@ -611,7 +611,6 @@ export declare const filtersToCardPropertyMappings: {
611
611
  category: "set";
612
612
  canonicalAlias: string;
613
613
  kind: "partialMatch";
614
- vocabulary: Release[];
615
614
  property: "sets";
616
615
  isArray: true;
617
616
  partialMatch: true;
@@ -620,7 +619,6 @@ export declare const filtersToCardPropertyMappings: {
620
619
  category: "set";
621
620
  canonicalAlias: string;
622
621
  kind: "partialMatch";
623
- vocabulary: Release[];
624
622
  property: "sets";
625
623
  isArray: true;
626
624
  partialMatch: true;
@@ -9,7 +9,6 @@ import {
9
9
  Keyword,
10
10
  Meta,
11
11
  Rarity,
12
- Release,
13
12
  Shorthand,
14
13
  Subtype,
15
14
  Talent,
@@ -261,7 +260,6 @@ const setFilter = {
261
260
  category: FilterCategory.Set,
262
261
  canonicalAlias: "s",
263
262
  kind: FilterKind.PartialMatch,
264
- vocabulary: Object.values(Release),
265
263
  property: "sets",
266
264
  isArray: true,
267
265
  partialMatch: true
@@ -26,7 +26,6 @@ export interface FilterTerm {
26
26
  /** What a resolver reads besides the term itself. */
27
27
  export interface FilterResolverContext {
28
28
  additionalHeroes: Hero[];
29
- additionalSets: Release[];
30
29
  index: CatalogueIndex;
31
30
  today: string;
32
31
  }
@@ -2,8 +2,6 @@ import {
2
2
  Foiling,
3
3
  Meta,
4
4
  Rarity,
5
- Release,
6
- setIdentifierToSetMappings,
7
5
  Treatment
8
6
  } from "@flesh-and-blood/types";
9
7
  import {
@@ -127,34 +125,24 @@ const getPitchResolution = (term) => {
127
125
  unresolvedValues: []
128
126
  };
129
127
  };
130
- const releasesByName = /* @__PURE__ */ new Map();
131
- for (const release of Object.values(Release)) {
132
- const name = getNormalizedFilterValue(release);
133
- const releaseWithSameName = releasesByName.get(name);
134
- if (releaseWithSameName === void 0) {
135
- releasesByName.set(name, release);
136
- } else {
137
- throw new Error(
138
- `${releaseWithSameName} and ${release} are one name as a filter reads it, so a set filter naming it could reach either`
139
- );
140
- }
141
- }
142
- const getReleasesFromLookup = (lookup, value) => {
143
- const release = lookup.get(value);
144
- return release ? [release] : [];
145
- };
146
- const getMatchingReleasesFromValue = (value, additionalSets) => {
128
+ const getMatchingReleasesFromValue = (value, index) => {
147
129
  const rungs = [
148
- () => getReleasesFromLookup(releasesByName, value),
149
- () => getReleasesFromLookup(setIdentifierToSetMappings, value),
150
- () => Object.values(Release).filter(
151
- (release) => release.toLowerCase().includes(value)
152
- ),
153
130
  () => {
154
- const additionalSetFromValue = additionalSets.find(
155
- (additionalSet) => getNormalizedFilterValue(additionalSet) === value
156
- );
157
- return additionalSetFromValue ? [additionalSetFromValue] : [];
131
+ const releaseInfo = index.getReleaseByName(value);
132
+ return releaseInfo ? [releaseInfo.release] : [];
133
+ },
134
+ () => {
135
+ const releaseInfo = index.getReleaseBySetIdentifier(value);
136
+ return releaseInfo ? [releaseInfo.release] : [];
137
+ },
138
+ () => {
139
+ const releasesNamingValue = [];
140
+ for (const { release } of index.releases) {
141
+ if (release.toLowerCase().includes(value)) {
142
+ releasesNamingValue.push(release);
143
+ }
144
+ }
145
+ return releasesNamingValue;
158
146
  }
159
147
  ];
160
148
  const releases = [];
@@ -165,10 +153,10 @@ const getMatchingReleasesFromValue = (value, additionalSets) => {
165
153
  }
166
154
  return releases;
167
155
  };
168
- const getSetResolution = (term, { additionalSets }) => getVocabularyResolution(
156
+ const getSetResolution = (term, { index }) => getVocabularyResolution(
169
157
  term,
170
158
  "releases",
171
- (value) => getMatchingReleasesFromValue(value, additionalSets)
159
+ (value) => getMatchingReleasesFromValue(value, index)
172
160
  );
173
161
  const foilingValuesMapping = new Map(
174
162
  Object.entries({
package/dist/filters.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Hero, Release } from "@flesh-and-blood/types";
1
+ import { Hero } from "@flesh-and-blood/types";
2
2
  import type { AppliedFilter } from "./filterMappings.js";
3
3
  import type { QueryAttributes } from "./filterResolvers.js";
4
4
  import { CatalogueIndex } from "./searchIndex.js";
@@ -10,7 +10,7 @@ export { RARITY_VALUES_MAPPING } from "./filterResolvers.js";
10
10
  * themselves as well, for a reader asking what a query means without running
11
11
  * it.
12
12
  */
13
- export declare const getKeywordsAndAppliedFiltersFromText: (text: string, index: CatalogueIndex, additionalHeroes?: Hero[], additionalSets?: Release[], today?: string) => {
13
+ export declare const getKeywordsAndAppliedFiltersFromText: (text: string, index: CatalogueIndex, additionalHeroes?: Hero[], today?: string) => {
14
14
  appliedFilters: AppliedFilter[];
15
15
  attributes: QueryAttributes;
16
16
  keywords: string[];
package/dist/filters.js CHANGED
@@ -1,9 +1,8 @@
1
1
  import { getParsedQuery } from "./queryParse.js";
2
2
  import { RARITY_VALUES_MAPPING } from "./filterResolvers.js";
3
- const getKeywordsAndAppliedFiltersFromText = (text, index, additionalHeroes = [], additionalSets = [], today) => {
3
+ const getKeywordsAndAppliedFiltersFromText = (text, index, additionalHeroes = [], today) => {
4
4
  const { appliedFilters, attributes, keywords } = getParsedQuery(text, index, {
5
5
  additionalHeroes,
6
- additionalSets,
7
6
  today
8
7
  });
9
8
  return { appliedFilters, attributes, keywords };
package/dist/helpers.d.ts CHANGED
@@ -1,11 +1,6 @@
1
+ export { getNormalizedFilterValue } from "@flesh-and-blood/types";
1
2
  export declare const getCleanText: (text: string) => string;
2
3
  export declare const getNormalizedText: (text: string) => string;
3
- /**
4
- * A filter value as a filter reads it, which is how a query's values arrive
5
- * and how the values a filter declares have to be compared against them:
6
- * neither the case nor the punctuation a value was written with is part of it.
7
- */
8
- export declare const getNormalizedFilterValue: (value: string) => string;
9
4
  export declare const getTextWithoutMarkup: (text: string) => string;
10
5
  /**
11
6
  * Text built into a pattern rather than matched by one. A hyphen is escaped
package/dist/helpers.js CHANGED
@@ -1,7 +1,8 @@
1
- import { MARKUP, PUNCTUATION } from "./constants.js";
1
+ import { PUNCTUATION } from "@flesh-and-blood/types";
2
+ import { MARKUP } from "./constants.js";
3
+ import { getNormalizedFilterValue } from "@flesh-and-blood/types";
2
4
  const getCleanText = (text) => getNormalizedText(text.toLowerCase().trim().replace(PUNCTUATION, ""));
3
5
  const getNormalizedText = (text) => text.normalize("NFD").replace(/\p{Diacritic}/gu, "");
4
- const getNormalizedFilterValue = (value) => value.toLowerCase().replace(PUNCTUATION, "");
5
6
  const getTextWithoutMarkup = (text) => text.replace(MARKUP, "");
6
7
  const getEscapedForRegExp = (text) => text.replace(/[.*+?^${}()|[\]\\-]/g, "\\$&");
7
8
  export {
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var Qt=Object.create;var de=Object.defineProperty;var Ht=Object.getOwnPropertyDescriptor;var jt=Object.getOwnPropertyNames;var Ut=Object.getPrototypeOf,Kt=Object.prototype.hasOwnProperty;var _t=(e,t)=>{for(var r in t)de(e,r,{get:t[r],enumerable:!0})},Ye=(e,t,r,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of jt(t))!Kt.call(e,s)&&s!==r&&de(e,s,{get:()=>t[s],enumerable:!(a=Ht(t,s))||a.enumerable});return e};var Gt=(e,t,r)=>(r=e!=null?Qt(Ut(e)):{},Ye(t||!e||!e.__esModule?de(r,"default",{value:e,enumerable:!0}):r,e)),$t=e=>Ye(de({},"__esModule",{value:!0}),e);var wa={};_t(wa,{FilterCategory:()=>l,FilterKind:()=>m,FilterProperty:()=>q,MARKUP:()=>Me,NO_CARD_PROPERTY:()=>K,PUNCTUATION:()=>S,RARITY_VALUES_MAPPING:()=>Oe,aliasesByFilterCategory:()=>te,availableExclusions:()=>z,availableModifiers:()=>ke,default:()=>Ot,filterCard:()=>Lt,filtersToCardPropertyMappings:()=>ee,getCardsByName:()=>Ta,getCatalogueIndex:()=>$e,getCleanText:()=>O,getEscapedForRegExp:()=>J,getExcludedMetaFilters:()=>we,getFilterCategory:()=>ae,getFilterMapping:()=>ye,getFilterTokenSpansForKey:()=>ea,getFilterValue:()=>Qe,getIncompleteFilterToken:()=>De,getIsExcludedToken:()=>Jr,getIsValueInFilterVocabulary:()=>Se,getKeywordsAndAppliedFiltersFromText:()=>Sa,getMetaFilterResolution:()=>se,getMetaFilters:()=>dr,getNormalizedFilterValue:()=>w,getNormalizedText:()=>Y,getParsedQuery:()=>ne,getQueryFilterToken:()=>he,getQueryTokenSpans:()=>Ce,getQuotedValue:()=>ra,getResolvedFilterKey:()=>Le,getSuggestedFilterKey:()=>Ve,getTextWithoutMarkup:()=>Z,getTokensReferencedByCards:()=>Va,getUnquotedValue:()=>Fe,getValuePartsFromFilterValue:()=>Vt,getValuesFromFilterValue:()=>He,multiWordShorthands:()=>Ue,shorthands:()=>je,singleWordShorthands:()=>Ke});module.exports=$t(wa);var xe=require("@flesh-and-blood/types"),We=Gt(require("fuse.js"),1);var S=/[!"#$%&'’(),./:;<=>?@[\]^_`|~]/g,Me=/\*/g;var h=require("@flesh-and-blood/types");var O=e=>Y(e.toLowerCase().trim().replace(S,"")),Y=e=>e.normalize("NFD").replace(/\p{Diacritic}/gu,""),w=e=>e.toLowerCase().replace(S,""),Z=e=>e.replace(Me,""),J=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");var l={Arcane:"arcane",Artist:"artist",Banned:"banned",Bond:"bond",Class:"class",Cost:"cost",CreatedBy:"createdby",Creates:"creates",Defense:"defense",Flow:"flow",Foiling:"foiling",Fusion:"fusion",Intellect:"intellect",Is:"is",Keyword:"keyword",Legal:"legal",Life:"life",Name:"name",Pitch:"pitch",Power:"power",Print:"print",Rarity:"rarity",ReferencedBy:"referencedby",References:"references",Set:"set",Shorthand:"shorthand",Specialization:"specialization",Subtype:"subtype",Talent:"talent",Text:"text",Trait:"trait",Treatment:"treatment",Type:"type",TypeText:"typetext",Year:"year"},m={Comparator:"comparator",ExactMatch:"exactMatch",PartialMatch:"partialMatch"},ke=[">=",">","<=","<"],z=["!","-"],K="n/a",ft=[...Object.values(h.Format),...Object.values(h.Hero)],zt={category:l.Arcane,canonicalAlias:"arcane",kind:m.Comparator,property:"arcane",specialProperty:"specialArcane",isNumber:!0,partialMatch:!0},Ae={category:l.Artist,canonicalAlias:"art",kind:m.PartialMatch,property:"artists",isArray:!0,partialMatch:!0},qe={category:l.Banned,canonicalAlias:"banned",kind:m.ExactMatch,vocabulary:ft,property:K,isMeta:!0},Xe={category:l.Bond,canonicalAlias:"bond",kind:m.ExactMatch,vocabulary:Object.values(h.Bond),property:"bonds",isArray:!0},Ze={category:l.Class,canonicalAlias:"c",kind:m.PartialMatch,vocabulary:Object.values(h.Class),property:"classes",isArray:!0,partialMatch:!0},Je={category:l.Cost,canonicalAlias:"co",kind:m.Comparator,property:"cost",specialProperty:"specialCost",isNumber:!0,partialMatch:!0},et={category:l.CreatedBy,canonicalAlias:"createdby",kind:m.PartialMatch,property:K},tt={category:l.Creates,canonicalAlias:"creates",kind:m.PartialMatch,property:K},re={category:l.Defense,canonicalAlias:"d",kind:m.Comparator,property:"defense",specialProperty:"specialDefense",isNumber:!0},rt={category:l.Flow,canonicalAlias:"flow",kind:m.ExactMatch,vocabulary:Object.values(h.Flow),property:"flows",isArray:!0},at={category:l.Foiling,canonicalAlias:"foil",kind:m.ExactMatch,vocabulary:Object.values(h.Foiling),nestedProperty:"foiling",property:"printings",isArray:!0},st={category:l.Fusion,canonicalAlias:"f",kind:m.ExactMatch,vocabulary:Object.values(h.Fusion),property:"fusions",isArray:!0},it={category:l.Intellect,canonicalAlias:"i",kind:m.Comparator,property:"intellect",isNumber:!0},nt={category:l.Keyword,canonicalAlias:"k",kind:m.ExactMatch,vocabulary:Object.values(h.Keyword),property:"keywords",isArray:!0},be={category:l.Legal,canonicalAlias:"l",kind:m.ExactMatch,vocabulary:ft,property:K,isMeta:!0},ot={category:l.Life,canonicalAlias:"li",kind:m.Comparator,property:"life",specialProperty:"specialLife",isNumber:!0},lt={category:l.Is,canonicalAlias:"is",kind:m.ExactMatch,vocabulary:Object.values(h.Meta),property:"meta",isArray:!0},dt={category:l.Name,canonicalAlias:"name",kind:m.PartialMatch,property:"name",isString:!0,partialMatch:!0},Pe={category:l.Pitch,canonicalAlias:"p",kind:m.Comparator,property:"pitch",isNumber:!0},ce={category:l.Power,canonicalAlias:"pwr",kind:m.Comparator,property:"power",specialProperty:"specialPower",isNumber:!0},pe={category:l.Print,canonicalAlias:"print",kind:m.PartialMatch,property:"setIdentifiers",isArray:!0,partialMatch:!0},ct={category:l.Rarity,canonicalAlias:"r",kind:m.ExactMatch,vocabulary:Object.values(h.Rarity),property:K,isMeta:!0},Wt={category:l.ReferencedBy,canonicalAlias:"referencedby",kind:m.PartialMatch,property:K},Yt={category:l.References,canonicalAlias:"references",kind:m.PartialMatch,property:K},pt={category:l.Set,canonicalAlias:"s",kind:m.PartialMatch,vocabulary:Object.values(h.Release),property:"sets",isArray:!0,partialMatch:!0},ve={category:l.Shorthand,canonicalAlias:"short",kind:m.PartialMatch,vocabulary:Object.values(h.Shorthand),property:"shorthands",isArray:!0,partialMatch:!0},ue={category:l.Specialization,canonicalAlias:"sp",kind:m.PartialMatch,vocabulary:Object.values(h.Hero),property:"specializations",isArray:!0,partialMatch:!0},ut={category:l.Subtype,canonicalAlias:"st",kind:m.ExactMatch,vocabulary:Object.values(h.Subtype),property:"subtypes",isArray:!0},gt={category:l.Type,canonicalAlias:"t",kind:m.ExactMatch,vocabulary:Object.values(h.Type),property:"types",isArray:!0},Re={category:l.Talent,canonicalAlias:"tal",kind:m.ExactMatch,vocabulary:Object.values(h.Talent),property:"talents",isArray:!0},qt={category:l.Text,canonicalAlias:"text",kind:m.PartialMatch,property:"functionalText",hasMarkup:!0,isString:!0,partialMatch:!0},Xt={category:l.Trait,canonicalAlias:"trait",kind:m.PartialMatch,vocabulary:Object.values(h.Trait),property:"traits",isArray:!0,partialMatch:!0},yt={category:l.TypeText,canonicalAlias:"x",kind:m.PartialMatch,property:"typeText",isString:!0,partialMatch:!0},ge={category:l.Treatment,canonicalAlias:"treatment",kind:m.ExactMatch,vocabulary:Object.values(h.Treatment),nestedProperty:"treatments",property:"printings",isArray:!0,isNestedPropertyArray:!0},Zt={category:l.Year,canonicalAlias:"year",kind:m.PartialMatch,property:"firstReleaseDate",isString:!0,partialMatch:!0},ee={arcane:zt,a:Ae,artist:Ae,art:Ae,attack:ce,b:re,block:re,banned:qe,bond:Xe,bonds:Xe,c:Ze,class:Ze,co:Je,cost:Je,createdby:et,creates:tt,color:Pe,d:re,def:re,defense:re,flow:rt,flows:rt,f:st,fusion:st,foil:at,foiling:at,i:it,intellect:it,is:lt,k:nt,keyword:nt,l:be,legal:be,hero:be,li:ot,life:ot,madeby:et,makes:tt,meta:lt,n:dt,name:dt,p:Pe,pitch:Pe,pwr:ce,pow:ce,power:ce,print:pe,printing:pe,printings:pe,prints:pe,r:ct,rarity:ct,referencedby:Wt,references:Yt,rf:qe,s:pt,set:pt,short:ve,shorthand:ve,shorthands:ve,sp:ue,spec:ue,specialization:ue,specializations:ue,st:ut,subtype:ut,t:gt,type:gt,tal:Re,talent:Re,talents:Re,text:qt,trait:Xt,treat:ge,treatment:ge,var:ge,variation:ge,x:yt,typetext:yt,year:Zt},Jt=new Map(Object.entries(ee)),ye=e=>Jt.get(e.toLowerCase()),ae=e=>ye(e)?.category,er=()=>{let e=Object.create(null);for(let[t,{category:r}]of Object.entries(ee)){let a=e[r];a?a.push(t):e[r]=[t]}return e},te=er(),tr=()=>{let e=new Map,t=new Set,r=Object.values(ee);for(let a of r){let{vocabulary:s}=a;if(s&&!t.has(a)){t.add(a);for(let i of s){let n=w(i),o=e.get(n);o?o.push(a):e.set(n,[a])}}}return e},mt=tr(),Se=(e,t)=>!!mt.get(w(t))?.some(r=>r.category===e),rr=(e,t)=>{let r=[],a=!0;for(let s of t){let i=(mt.get(w(s))||[]).filter(n=>n.category!==e);r=a?i:r.filter(n=>i.includes(n)),a=!1}return r},Ve=(e,t)=>{let r=rr(e,t),[a]=r;return r.length===1?a.canonicalAlias:void 0};var ie=require("@flesh-and-blood/types");var d=require("@flesh-and-blood/types");var N=require("@flesh-and-blood/types");var q={BannedFormats:"bannedFormats",LegalFormats:"legalFormats",LegalHeroes:"legalHeroes"},fe=Array.from(Array(50).keys()).map(e=>`${e}`),ar=[{format:N.Format.ClassicConstructed,nicknames:["cc","classic"]},{format:N.Format.LivingLegend,nicknames:["cc ll","classic constructed ll","ll cc","ll","living legend"]},{format:N.Format.SilverAge,nicknames:["sage"]},{format:N.Format.GoldenAge,nicknames:["gage"]},{format:N.Format.UltimatePitFight,nicknames:["upf"]}],sr=Object.values(N.Format).map(e=>{let t=ar.find(({format:a})=>a===e),r=e.toLowerCase().replaceAll(S,"");return t?{...t,format:r}:{format:r}}),ir=Object.values(N.Hero).map(O),Ct=e=>e.replaceAll(" ",""),nr=(e,t)=>{let r=Ct(e),a,s=[];for(let n of t){let o=Ct(n);o===r?a=n:o.startsWith(r)&&s.push(n)}let i=s.length===1;return a??(i?s[0]:void 0)},ht=["common","rare","super rare","majestic","legendary","fabled"],or=({modifier:e,value:t})=>{let r=[],a=e==="<"||e==="<=",s=e===">="||e==="<=",i=a?[...ht].reverse():ht,n=!1;for(let o of i)n?r.push(o):o===t&&(n=!0,s&&r.push(o));return r},lr=(e,t)=>{let r=[];for(let a of e)a.modifier?r.push(...or(a)):r.push(a.value);return{filterToPropertyMapping:{nestedProperty:"rarity",property:"printings",isArray:!0},isExcluded:t,isOr:!0,values:r}},Ft=(e,t,r,a)=>{let s=new Set([...ir,...r.map(O)]),i=[],n=[],o=[],p=[];for(let{value:f}of e){let u=sr.find(({format:y,nicknames:F})=>y===f||!!F&&F.includes(f));if(u)n.push(u.format);else{let y=nr(f,s);y?o.push(y):p.push(f)}}return n.length>0&&i.push({filterToPropertyMapping:{property:a,isArray:!0},values:n,isOr:!0,isExcluded:t}),o.length>0&&i.push({filterToPropertyMapping:{property:q.LegalHeroes,isArray:!0},values:o,isOr:!0,isExcluded:t}),{appliedFilters:i,unresolvedValues:p}},se=(e,t,{additionalHeroes:r=[],isExcluded:a=!1}={})=>{let s=ae(e),i={appliedFilters:[],unresolvedValues:[]};return s===l.Legal?i=Ft(t,a,r,q.LegalFormats):s===l.Banned?i=Ft(t,a,r,q.BannedFormats):s===l.Rarity&&(i={appliedFilters:[lr(t,a)],unresolvedValues:[]}),i},dr=(e,t,r,a,s,i)=>se(r,a.map(n=>({modifier:s,value:n})),{additionalHeroes:i,isExcluded:e}).appliedFilters,cr=[{filterToPropertyMapping:{property:"cost",isNumber:!0},isExcluded:!0,values:fe},{filterToPropertyMapping:{property:"specialCost",isString:!0,partialMatch:!0},isExcluded:!0,values:["*","x"]},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["equipment","hero","placeholder","token","weapon"]}],pr=[{filterToPropertyMapping:{property:"defense",isNumber:!0},isExcluded:!0,values:fe},{filterToPropertyMapping:{property:"specialDefense",isString:!0,partialMatch:!0},isExcluded:!0,values:["*","x"]},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["hero","placeholder","token","weapon"]}],ur=[{filterToPropertyMapping:{property:"pitch",isNumber:!0},isExcluded:!0,values:fe},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["equipment","hero","placeholder","token","weapon"]},{filterToPropertyMapping:{property:"isCardBack",isBoolean:!0},isExcluded:!0,values:["true"]}],gr=[{filterToPropertyMapping:{property:"power",isNumber:!0},isExcluded:!0,values:fe},{filterToPropertyMapping:{property:"specialPower",isString:!0,partialMatch:!0},isExcluded:!0,values:["*","x"]},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["equipment","hero","placeholder","token"]}],yr=[{filterToPropertyMapping:{property:"talents",isArray:!0},isExcluded:!0,values:Object.values(N.Talent).map(e=>e.toLowerCase())}],fr=[{filterToPropertyMapping:{property:"classes",isArray:!0},isExcluded:!0,values:Object.values(N.Class).map(e=>e.toLowerCase())}],mr=[{category:l.Class,filters:fr},{category:l.Cost,filters:cr},{category:l.Defense,filters:pr},{category:l.Pitch,filters:ur},{category:l.Power,filters:gr},{category:l.Talent,filters:yr}],Cr=()=>{let e=new Map;for(let{category:t,filters:r}of mr)for(let a of te[t])for(let s of z)e.set(`${s}${a}`,r);return e},hr=Cr(),we=e=>{let t=[],r=hr.get(e);return r&&t.push(...r),t};var Fr=e=>{let[t]=e,r=t?.modifier;return e.every(({modifier:s})=>s===r)?r:void 0},Ee=({filterValues:e,isAnd:t,isExcluded:r,mapping:a})=>{let s=[];for(let{value:i}of e)s.push(a.hasMarkup?Z(i):i);return{filterToPropertyMapping:a,filterValues:e,isAnd:t,isExcluded:r,isOr:!t&&s.length>1,modifier:Fr(e),values:s}},At=({isAnd:e,isExcluded:t,mapping:r},a)=>({filterToPropertyMapping:r,isAnd:e,isExcluded:t,isOr:!e&&a.length>1,values:a}),Tr=({category:e,filterValues:t,mapping:r})=>{let a=[];if(r.kind===m.ExactMatch&&!!r.vocabulary)for(let{value:i}of t)Se(e,i)||a.push(i);return a},xr=e=>({appliedFilters:[Ee(e)],unresolvedValues:Tr(e)}),Ne=({isExcluded:e},t,r)=>e?void 0:{[t]:r},bt=(e,t)=>({appliedFilters:[Ee(e)],attributes:Ne(e,t,e.filterValues.map(({value:r})=>r)),unresolvedValues:[]}),Mr=e=>bt(e,"artists"),Ar=e=>bt(e,"prints"),Be=(e,t,r)=>{let a=[],s=[],i=[];for(let{value:n}of e.filterValues){let o=r(n);if(o.length>0)for(let p of o)a.push(p),s.push(w(p));else i.push(n)}return{appliedFilters:[At(e,s)],attributes:Ne(e,t,a),canonicalValues:s,unresolvedValues:i}},br=new Map(Object.entries({purple:4,blue:3,yellow:2,red:1,white:0})),Pr=e=>{let t=[],r=[];for(let{modifier:a,value:s}of e.filterValues){let i=br.get(s),n=i===void 0?s:`${i}`;t.push({modifier:a,value:n}),r.push(n)}return{appliedFilters:[Ee({...e,filterValues:t})],canonicalValues:r,unresolvedValues:[]}},Ie=new Map;for(let e of Object.values(d.Release)){let t=w(e),r=Ie.get(t);if(r===void 0)Ie.set(t,e);else throw new Error(`${r} and ${e} are one name as a filter reads it, so a set filter naming it could reach either`)}var Tt=(e,t)=>{let r=e.get(t);return r?[r]:[]},vr=(e,t)=>{let r=[()=>Tt(Ie,e),()=>Tt(d.setIdentifierToSetMappings,e),()=>Object.values(d.Release).filter(s=>s.toLowerCase().includes(e)),()=>{let s=t.find(i=>w(i)===e);return s?[s]:[]}],a=[];for(let s of r)a.length===0&&a.push(...s());return a},Rr=(e,{additionalSets:t})=>Be(e,"releases",r=>vr(r,t)),kr=new Map(Object.entries({r:d.Foiling.Rainbow,rf:d.Foiling.Rainbow,rainbow:d.Foiling.Rainbow,c:d.Foiling.Cold,cf:d.Foiling.Cold,cold:d.Foiling.Cold,g:d.Foiling.Gold,gf:d.Foiling.Gold,gold:d.Foiling.Gold})),Sr=e=>{let t=kr.get(e);return t?[t]:[]},Vr=e=>Be(e,"foilings",Sr),Pt=new Map(Object.entries({aa:d.Treatment.AA,alt:d.Treatment.AA,"alt art":d.Treatment.AA,ab:d.Treatment.AB,"alt border":d.Treatment.AB,at:d.Treatment.AT,"alt text":d.Treatment.AT,ea:d.Treatment.EA,extended:d.Treatment.EA,"extended art":d.Treatment.EA,fa:d.Treatment.FA,full:d.Treatment.FA,"full art":d.Treatment.FA}));for(let e of Object.values(d.Treatment))Pt.set(e.toLowerCase(),e);var wr=new Map(Object.entries(d.Treatment)),Ir=e=>{let t=Pt.get(e)||wr.get(e.toUpperCase());return t?[t]:[]},Er=e=>Be(e,"treatments",Ir),Oe=new Map(Object.entries({b:d.Rarity.Basic,c:d.Rarity.Common,f:d.Rarity.Fabled,l:d.Rarity.Legendary,m:d.Rarity.Majestic,p:d.Rarity.Promo,r:d.Rarity.Rare,s:d.Rarity.SuperRare,t:d.Rarity.Token,v:d.Rarity.Marvel})),Nr=e=>Oe.get(e)||Object.values(d.Rarity).find(t=>t.toLowerCase()===e),Br=(e,{additionalHeroes:t})=>{let r=[],a=[],s=[],i=[];for(let{modifier:o,value:p}of e.filterValues){let f=Nr(p);f?(r.push(f),a.push(f.toLowerCase()),s.push({modifier:o,value:f.toLowerCase()})):(i.push(p),s.push({modifier:o,value:p}))}let{appliedFilters:n}=se(e.key,s,{additionalHeroes:t,isExcluded:e.isExcluded});return{appliedFilters:n,attributes:Ne(e,"rarities",r),canonicalValues:a,unresolvedValues:i}},xt=({filterValues:e,isExcluded:t,key:r},{additionalHeroes:a})=>{let{appliedFilters:s,unresolvedValues:i}=se(r,e,{additionalHeroes:a,isExcluded:t}),n=[];for(let{values:o}of s)n.push(...o);return{appliedFilters:s,canonicalValues:n,unresolvedValues:i}},Or=["unique"],Lr=["preview","spoiler","unreleased"],Dr=["released"],Mt={property:"firstReleaseDate",isDate:!0},Qr=new Map(Object.entries({dual:d.Meta.DualClass,exp:d.Meta.Expansion,expansion:d.Meta.Expansion,rainbow:d.Meta.Rainbow,reprint:d.Meta.Reprint,reprints:d.Meta.Reprint})),Hr=e=>{let t=[],r=[];for(let s of e){let i=Qr.get(s);i?t.push(i):r.push(s)}let a=[];if(t.length===0){let s=new Set;for(let i of Object.values(d.Meta)){let n=!1;for(let o of r)i.toLowerCase().includes(o)&&(n=!0,s.add(o));n&&t.push(i)}for(let i of r)s.has(i)||a.push(i)}else a.push(...r);return{unresolvedValues:a,values:t}},jr=(e,{today:t})=>{let{filterValues:r,isAnd:a,isExcluded:s}=e,i=[],n=[],o=[],p=[],f=[];for(let{value:b}of r)Or.includes(b)?n.push(b):Lr.includes(b)?o.push(b):Dr.includes(b)?p.push(b):f.push(b);let u=!a&&r.length>1;n.length>0&&i.push({filterToPropertyMapping:ee.is,values:[w(d.Meta.Reprint)],isAnd:a,isOr:u,isExcluded:!s}),o.length>0&&i.push({filterToPropertyMapping:Mt,values:[t],isAnd:a,isOr:u,isExcluded:s}),p.length>0&&i.push({filterToPropertyMapping:Mt,values:[t],isAnd:a,isOr:u,isExcluded:!s});let{unresolvedValues:y,values:F}=Hr(f),x=[...n,...o,...p,...F.map(w)];(f.length>0||i.length===0)&&i.push(At(e,F.map(w)));let I=F.includes(d.Meta.Expansion)&&!s;return{appliedFilters:i,attributes:I?{isExpansionSlot:I}:void 0,canonicalValues:x,unresolvedValues:y}},Ur={property:"cardIdentifier",isString:!0,isNormalized:!0},Kr=(e,t)=>{let r=e.getCardsByExactName(t);return r.length===0&&(r=e.getCardsByGroup(t)),r.length===0&&(r=e.getCardsByName(t)),r},_r=(e,t,r)=>{let a=new Set;for(let s of Kr(e,t))for(let i of r(e,s.cardIdentifier))if(!a.has(i.cardIdentifier))for(let o of e.getPitchCycle(i.cardIdentifier))a.add(o.cardIdentifier);return a},Gr=(e,t)=>{let r=new Set,[a=new Set,...s]=e;if(t)for(let i of a)s.every(o=>o.has(i))&&r.add(i);else for(let i of e)for(let n of i)r.add(n);return r},$r=(e,t)=>({filterToPropertyMapping:Ur,values:[...e],valuesSet:e,isExcluded:t,isOr:!0}),me=e=>({filterValues:t,isAnd:r,isExcluded:a},{index:s})=>{let i=[],n=[];for(let{value:o}of t){let p=_r(s,o,e);i.push(p),p.size===0&&n.push(o)}return{appliedFilters:[$r(Gr(i,r),a)],unresolvedValues:n}},zr=new Map([[l.Artist,Mr],[l.Banned,xt],[l.CreatedBy,me((e,t)=>e.getCreates(t))],[l.Creates,me((e,t)=>e.getCreatedBy(t))],[l.Foiling,Vr],[l.Is,jr],[l.Legal,xt],[l.Pitch,Pr],[l.Print,Ar],[l.Rarity,Br],[l.ReferencedBy,me((e,t)=>e.getReferences(t))],[l.References,me((e,t)=>e.getReferencedBy(t))],[l.Set,Rr],[l.Treatment,Er]]),vt=(e,t)=>(zr.get(e.category)||xr)(e,t);var kt=z.map(J).join(""),Wr=/(?:[^\s"]+|"[^"]*(?:"|$))+/g,Yr=new RegExp(`^([${kt}])?([A-Za-z]+):(.+)$`),qr=new RegExp(`^([${kt}])?([A-Za-z]+):$`),Xr=",",Rt="+",Zr='"',St=e=>{let t=[],r=!1,a="",s=!1;for(let i of e)i===Zr?(s=!s,a+=i):!s&&(i===Xr||i===Rt)?(r=r||i===Rt,a&&t.push(a),a=""):a+=i;return a&&t.push(a),{isAndList:r,parts:t}},Ce=e=>{let t=[];for(let r of e.matchAll(Wr))t.push({end:r.index+r[0].length,start:r.index,token:r[0]});return t},Jr=e=>z.some(t=>e.startsWith(t)),he=e=>{let t=e.match(Yr),r;if(t){let[,a,s,i]=t;r={isAndList:St(i).isAndList,isExcluded:!!a,key:s,valueText:i}}return r},De=e=>{let t=e.match(qr),r;return t&&(r={isAndList:!1,isExcluded:!!t[1],key:t[2],valueText:""}),r},Qe=e=>{let t=e.trim(),r=ke.find(a=>t.startsWith(a));return{modifier:r,value:r?t.slice(r.length).trim():t}},Le=e=>ae(e)??e.toLowerCase(),ea=(e,t)=>{let r=Le(t),a=[];for(let{end:s,start:i,token:n}of Ce(e)){let o=he(n);o&&Le(o.key)===r&&a.push({...o,end:s,start:i,token:n})}return a},Vt=e=>St(e).parts,Fe=e=>e.replace(/^"|"$/g,""),He=e=>{let t=[];for(let r of Vt(e)){let a=Fe(r);a&&t.push(a)}return t},ta=/[\s,:+"]/,ra=e=>{let t=e.replaceAll('"',"");return ta.test(e)?`"${t}"`:t};var D=require("@flesh-and-blood/types"),je=[{description:"Attack actions",expanded:["st:attack"],filters:{subtypes:[D.Subtype.Attack]},isCardProperty:!1,shorthands:["AA"]},{description:"Arcane barrier",expanded:['k:"arcane barrier"'],filters:{keywords:[D.Keyword.ArcaneBarrier]},isCardProperty:!1,shorthands:["AB"]},{description:"Attack reactions",expanded:['t:"attack reaction"'],filters:{types:[D.Type.AttackReaction]},isCardProperty:!1,shorthands:["AR"]},{description:"Defense reactions",expanded:['t:"defense reaction"'],filters:{types:[D.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:[D.Keyword.GoAgain]},isCardProperty:!1,shorthands:["GA"]},{description:"Non-attack actions",expanded:["t:action","st:non-attack"],filters:{subtypes:[D.Subtype.NonAttack],types:[D.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:[D.Keyword.Spellvoid]},isCardProperty:!1,shorthands:["SV"]}],Ue=je.filter(({shorthands:e})=>e.some(t=>t.includes(" "))).map(e=>({...e,shorthands:e.shorthands.filter(t=>t.includes(" ")).map(t=>t.toLowerCase()).sort((t,r)=>r.length-t.length)})),Ke=je.filter(({shorthands:e})=>e.some(t=>!t.includes(" "))).map(e=>({...e,shorthands:e.shorthands.filter(t=>!t.includes(" ")).map(t=>t.toLowerCase()).sort((t,r)=>r.length-t.length)}));var aa=["\u201C","\u201D"],sa=[{text:ie.Release.ClassicBattlesRhinarDorinthea.toLowerCase(),override:ie.Release.ClassicBattlesRhinarDorinthea.toLowerCase().replaceAll(S,"")}],_e=new Map([...ie.setToSetIdentifierMappings].map(([e,t])=>[e.toLowerCase(),t])),ia=[...te[l.Set],...te[l.Print]],na=z.map(J).join(""),oa=[..._e.keys()].sort((e,t)=>t.length-e.length).map(J).join("|"),la=new RegExp(`(?<=^|\\s)([${na}]?(?:${ia.join("|")}):(?:[^\\s]*[,+])?"?)(${oa})(?="?(?:[,+]|\\s|$))`,"g"),da=(e,t)=>{let r=e.trim().toLowerCase();for(let i of aa)r=r.replaceAll(i,'"');for(let{expanded:i,shorthands:n}of Ue)for(let o of n)if(r.includes(o)){r=r.replace(o,i.join(" "));break}r=r.replace(la,(i,n,o)=>{let p=_e.get(o);return p?`${n}${p[0]}`:i});let a=_e.get(r),s=t.getCardsByExactName(r).length>0;a&&!s&&(r=`set:${a[0]}`);for(let{override:i,text:n}of sa)r.includes(n)&&(r=r.replace(n,i));return r},ca=e=>{let t=Ke.find(({shorthands:a})=>a.includes(e)),r=!!t&&!t.isCardProperty;return{isExpanded:r,tokens:r?t.expanded:[e]}},pa=e=>{let t=[];for(let{end:r,start:a,token:s}of Ce(e)){let{isExpanded:i,tokens:n}=ca(s);for(let o of n)t.push({end:r,isExpanded:i,start:a,token:o})}return t},ua=e=>{let t=[];for(let r of e){let{modifier:a,value:s}=Qe(r),i=w(s);i&&t.push({modifier:a,value:i})}return t},ga=(e,t,r)=>{let a={key:e,reason:"value",values:r},s=Ve(t,r);return s&&(a.suggestedKey=s),a},ya=()=>{let e=new Date,t=`${e.getMonth()+1}`.padStart(2,"0"),r=`${e.getDate()}`.padStart(2,"0");return`${e.getFullYear()}-${t}-${r}`},ne=(e,t,{additionalHeroes:r=[],additionalSets:a=[],today:s=ya()}={})=>{let i=da(e,t),n={additionalHeroes:r,additionalSets:a,index:t,today:s},o=[],p={artists:[],foilings:[],isExpansionSlot:!1,prints:[],rarities:[],releases:[],treatments:[]},f=[],u=[],y=[];for(let F of pa(i)){let x=he(F.token)||De(F.token);if(x){let{isAndList:H,isExcluded:I,key:b,valueText:L}=x,B=ye(b),j=B?.category,_=He(L),W=ua(_),G={...F,canonicalValues:W.map(({value:T})=>T),category:j,filterValues:W,isAnd:H,isExcluded:I,isFilter:!0,isResolved:!0,key:b};if(_.length>0)if(B&&j){let T=_;if(W.length>0){let v=vt({category:j,filterValues:W,isAnd:G.isAnd,isExcluded:I,key:b,mapping:B},n);o.push(...v.appliedFilters),v.canonicalValues&&(G.canonicalValues=v.canonicalValues),v.attributes&&Object.assign(p,v.attributes),T=v.unresolvedValues}T.length>0&&(G.isResolved=!1,y.push(ga(b,j,T)))}else G.isResolved=!1,y.push({key:b,reason:"key",values:[]});u.push(G)}else{let{end:H,start:I,token:b}=F;u.push({end:H,isFilter:!1,start:I,token:b});let L=Fe(F.token),B=we(L);B.length>0?o.push(...B):L&&f.push(L.replace(S,""))}}return{appliedFilters:o,attributes:p,keywords:f,nodes:u,text:i,unresolvedFilters:y}};var A=require("@flesh-and-blood/types"),wt={artists:["Hoodwill"],cardIdentifier:"fangs-a-lot-blue",classes:[A.Class.Generic],defaultImage:"FNG000",firstReleaseDate:"2022-06-02",functionalText:"If Fangs A Lot is put into your banished zone from your graveyard, instead put it into your hand.",legalFormats:[],legalHeroes:[A.Hero.Kayo,A.Hero.Levia,A.Hero.Rhinar],printings:[{artists:["Hoodwill"],identifier:"FNG000",image:"FNG000",print:"FNG000",rarity:A.Rarity.Rare,set:A.Release.Promos},{artists:["Hoodwill"],identifier:"FNG000",image:"FNG000_Marvel",print:`FNG000-${A.Treatment.FA}`,rarity:A.Rarity.Marvel,set:A.Release.Promos,treatments:[A.Treatment.FA]}],name:"Fangs A Lot",rarities:[A.Rarity.Rare,A.Rarity.Marvel],rarity:A.Rarity.Rare,sets:[A.Release.Promos],setIdentifiers:["FNG000"],specialImage:"FNG000_Marvel",subtypes:[A.Subtype.Attack],types:[A.Type.Action],typeText:"Generic Action - Attack"},It=[{keyword:wt.name.toLowerCase(),card:wt}];var X=require("@flesh-and-blood/types");var fa=3,ma=e=>{let t=Y(e.toLowerCase()).replace(/[^a-z\s-]/g,""),r=new Set;for(let a of[/[\s-]+/,/\s+/]){let s="";for(let i of t.split(a)){let n=i.replaceAll("-","");n&&(s+=n[0])}s.length>=fa&&r.add(s)}return[...r]},Te=e=>O(e).replaceAll("-",""),Ge=(e,t,r)=>{let a=e.get(t);a?a.push(r):e.set(t,[r])},Et=new WeakMap,Q=Object.freeze([]),Ca=Number.MAX_SAFE_INTEGER,Nt=(e,t)=>{let r=new Map;for(let a of e)for(let s of t(a)||[]){let i=r.get(s);i?i.push(a):r.set(s,[a])}return r},ha=e=>{let t=new Map;for(let r of e){let a=r.types.includes(X.Type.Hero)&&!r.isCardBack,s=a?X.CardRole.Hero:(0,X.getCardRole)(r);if(a||s!==X.CardRole.Hero){let n=t.get(s);n?n.push(r):t.set(s,[r])}}return t},Fa=e=>{let t,r,a,s,i,n,o,p,f=()=>{if(!t){let g=new Map,c=new Map,C=[],M=new Map,P=0;for(let E of e){g.set(E.cardIdentifier,E),c.set(E.cardIdentifier,P),P++;let V=O(E.name),U=M.get(V);U?U.push(E):(M.set(V,[E]),C.push(V))}t={cardByCardIdentifier:g,corpusPositionByCardIdentifier:c,cleanedNames:C,pitchCycleByCleanedName:M}}return t},u=g=>{let{corpusPositionByCardIdentifier:c}=f(),C=({cardIdentifier:M})=>c.get(M)??Ca;return[...g].sort((M,P)=>C(M)-C(P))},y=g=>f().cardByCardIdentifier.get(g),F=g=>{let{cardByCardIdentifier:c}=f(),C=[];for(let M of g||[]){let P=c.get(M);P&&C.push(P)}return u(C)},x=g=>{let c=new Map;return C=>{let M=c.get(C);if(!M){let P=y(C),E=F(P&&g(P)),V=E.length>0;M=V?E:Q,V&&c.set(C,M)}return M}},H=g=>{let{pitchCycleByCleanedName:c}=f(),C=y(g);return C?c.get(O(C.name))??Q:Q},I=g=>{let{cleanedNames:c,pitchCycleByCleanedName:C}=f(),M=O(g),P=C.get(M);if(!P&&M.length>0){let V=c.find(U=>U.includes(M));V&&(P=C.get(V))}return P??Q},b=g=>{let{pitchCycleByCleanedName:c}=f();return c.get(O(g))??Q},L=g=>{if(!n){n=new Map;for(let c of e)for(let C of c.nicknames??[])Ge(n,Te(C),c)}return n.get(Te(g))??Q},B=g=>{if(!o){o=new Map;for(let c of e)for(let C of[...c.types,...c.subtypes,...c.traits??[]])Ge(o,Te(C),c)}return o.get(Te(g))??Q},j=g=>{if(!p){p=new Map;for(let c of e)for(let C of ma(c.name))Ge(p,C,c)}return p.get(g)??Q},_=()=>{if(!i){let g=new Set;for(let c of e)for(let C of c.artists)g.add(C);i=[...g].sort((c,C)=>c.localeCompare(C,"en",{sensitivity:"base"}))}return i},W=x(({oppositeSideCardIdentifiers:g})=>g),G=x(({referencedCards:g})=>g),T=g=>(r||(r=Nt(e,({referencedCards:c})=>c)),r.get(g)??Q),v=x(({createdExtras:g})=>g);return{cards:e,getCard:y,getPitchCycle:H,getCardsByName:I,getCardsByExactName:b,getCardsByNickname:L,getCardsByGroup:B,getCardsByInitials:j,getArtists:_,getOppositeSide:W,getReferences:G,getReferencedBy:T,getCreates:v,getCreatedBy:g=>(a||(a=Nt(e,({createdExtras:c})=>c)),a.get(g)??Q),getCreatedClosure:g=>{let c=new Map,C=new Set,M=[...g];for(let P of M)if(!C.has(P)){C.add(P);for(let V of v(P))c.set(V.cardIdentifier,V),M.push(V.cardIdentifier)}return u([...c.values()])},getByRole:g=>(s||(s=ha(e)),s.get(g)??Q),getCardsInCorpusOrder:u}},$e=e=>{let t=Et.get(e);return t||(t=Fa(e),Et.set(e,t)),t},Ta=(e,t)=>e.getCardsByName(t);var xa={getFn:(e,t)=>{let r=We.default.config.getFn(e,t),a=r;if(Array.isArray(r))a=r.map(s=>{let i=typeof s=="string"?s:s.v;return Y(i.replace(S,""))});else if(r){let s=Y(r).replace(S,"");a=t.includes("functionalText")?Z(s):s}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},ze=class{constructor(t,r=[],a=[]){this.getFuse=()=>(this.fuse||(this.fuse=new We.default(this.cards,xa)),this.fuse);this.getPoolCards=t=>{this.poolCardByCardIdentifier||(this.poolCardByCardIdentifier=new Map(this.cards.map(a=>[a.cardIdentifier,a])));let r=[];for(let{cardIdentifier:a}of t){let s=this.poolCardByCardIdentifier.get(a);s&&r.push(s)}return r};this.search=(t,r)=>{let a,s,{appliedFilters:i,attributes:n,keywords:o,unresolvedFilters:p}=ne(t,this.index,{additionalHeroes:this.additionalHeroes,additionalSets:this.additionalSets}),f=o.join(" "),u=r?It.filter(T=>T.keyword===f):[],y=T=>i.length>0?T.filter(v=>v&&Lt(v,i)):T;if(u.length>0)a=y(u.map(({card:T})=>T));else if(o.length){let T=O(f),v=this.getPoolCards(this.index.getCardsByNickname(T)),k=new Map;for(let c of[...this.getPoolCards(this.index.getCardsByExactName(T)),...v])k.set(c.cardIdentifier,c);let R=this.getFuse().search(f).map(c=>c.item).filter(({cardIdentifier:c})=>!k.has(c));a=y([...k.values(),...R]),a.some(c=>v.includes(c))&&(s={kind:"nickname",text:T}),a.length===0&&o.length===1&&(a=y(this.getPoolCards(this.index.getCardsByInitials(T))),a.length>0&&(s={kind:"initials",text:T}))}else a=y([...this.cards]);if(!(o.length>0&&s?.kind!=="initials")){let T="";if(n.releases.length===1){let R=xe.setToSetIdentifierMappings.get(n.releases[0]);R?.length&&(T=R[0].toUpperCase())}if(!T&&n.prints.length===1){let R=n.prints[0];xe.setIdentifierToSetMappings.has(R)&&(T=R.toUpperCase())}T?a.sort((R,$)=>{let g=R.setIdentifiers.find(C=>C.includes(T))?.replace(T,""),c=$.setIdentifiers.find(C=>C.includes(T))?.replace(T,"");return g&&c?g.localeCompare(c):-1}):a.sort((R,$)=>R.name===$.name?`${R.pitch}`.localeCompare(`${$.pitch}`):R.name.localeCompare($.name))}let x=[],{artists:H,isExpansionSlot:I,foilings:b,prints:L,rarities:B,releases:j,treatments:_}=n;(H.length>0||I||b.length>0||L.length>0||B.length>0||j.length>0||_.length>0)&&(x=a.map(T=>{let v=T.printings.filter(k=>{let R=!!k.image,$=H.length===0||H.some(U=>k.artists.find(Dt=>Dt.replace(S,"").toLowerCase().includes(U))),g=!I||I===k.isExpansionSlot,c=b.length===0||!!k.foiling&&b.includes(k.foiling),C=L.length===0||L.some(U=>k.identifier.includes(U.toUpperCase())),M=B.length===0||B.includes(k.rarity),P=j.length===0||j.includes(k.set),E=_.length===0||k.treatments?.some(U=>_.includes(U));return R&&$&&g&&c&&C&&M&&P&&E});return{...T,matchingPrintings:v}}));let G=x.length>0?x:a;return{alias:s,appliedFilters:i,attributes:n,keywords:o,searchResults:G,unresolvedFilters:p}};let s=Array.isArray(r)?{additionalHeroes:r,additionalSets:a}:r;this.additionalHeroes=s.additionalHeroes||[],this.additionalSets=s.additionalSets||[],this.cards=[...t],this.index=s.index||$e(t)}},Ot=ze,Lt=(e,t)=>{let r=!0;for(let a of t){let{isNumber:s,isString:i,isArray:n,isBoolean:o,isDate:p}=a.filterToPropertyMapping;a.isOptional||(s?r=r&&Ma(e,a):i?r=r&&Aa(e,a):n?r=r&&ba(e,a,t):o?r=r&&Pa(e,a):p&&(r=r&&va(e,a)))}return r},Bt=(e,t,r)=>{let a=parseInt(t),s;switch(r){case">=":s=e>=a;break;case">":s=e>a;break;case"<=":s=e<=a;break;case"<":s=e<a;break;default:s=e===a}return s},Ma=(e,t)=>{let{filterValues:r,values:a,modifier:s,isExcluded:i,filterToPropertyMapping:{partialMatch:n}}=t,o=!0;if(le(t,e)){let p=oe(e,t),f;if(p!=null&&!isNaN(p)){let u=parseInt(p);f=r?r.some(({modifier:y,value:F})=>Bt(u,F,y)):a.some(y=>Bt(u,y,s))}else{let u=ka(e,t)?.toLowerCase();f=n?a.some(y=>!!u?.includes(y)):a.some(y=>u===y)}o=i?!f:f}return o},Aa=(e,t)=>{if(le(t,e)){let{values:r,valuesSet:a,isAnd:s,isExcluded:i,filterToPropertyMapping:{hasMarkup:n,isNormalized:o,partialMatch:p}}=t,f=oe(e,t),u=o?f:f?.replaceAll(S,"").toLowerCase(),y=n&&u?Z(u):u;if(p){let F=s?r?.every(x=>y?.includes(x)):r?.some(x=>y?.includes(x));return i?!F:F}else{let F;return s?F=r?.every(x=>y===x):a?F=a.has(y):F=r?.some(x=>y===x),i?!F:F}}else return!0},ba=(e,t,r)=>{if(le(t,e)){let{values:a,isAnd:s,isExcluded:i,filterToPropertyMapping:{partialMatch:n}}=t,o=Ra(e,t,r).map(p=>p?.replaceAll(S,""));if(n){let p=s?a.every(u=>o?.some(y=>y?.toLowerCase().includes(u))):a.some(u=>o?.some(y=>y?.toLowerCase().includes(u))),f=o.length===0;return i?!p||f:p}else{let p=s?a.every(f=>o?.some(u=>u?.toLowerCase()===f)):a.some(f=>o?.some(u=>u?.toLowerCase()===f));return i?!p:p}}else return!0},Pa=(e,t)=>{if(le(t,e)){let{isExcluded:r}=t,a=oe(e,t);return r?!a:a}else return!0},va=(e,t)=>{if(le(t,e)){let{values:r,isExcluded:a}=t,s=oe(e,t),i=r?.some(n=>s>n);return a?!i:i}else return!0},oe=(e,t)=>{let{filterToPropertyMapping:{property:r}}=t,a;return r!==K&&(a=e[r]),a},Ra=(e,t,r)=>{let{filterToPropertyMapping:{isNestedPropertyArray:a,nestedProperty:s}}=t,i=[],n=Object.keys(e.legalOverrides||{}).length>0,o=t.filterToPropertyMapping.property===q.LegalHeroes,p=r.find(({filterToPropertyMapping:u})=>u.property===q.LegalFormats);if(n&&o&&!!p){let u=new Set;for(let{format:y,heroes:F}of e.legalOverrides||[])if(p.values.includes(y.toLowerCase()))for(let x of F)u.add(x);i=Array.from(u)}if(i.length===0)if(s){let u=new Set;for(let y of e.printings){let F=y[s];if(a){if(Array.isArray(F))for(let x of F)u.add(x)}else F&&typeof F=="string"&&u.add(F)}i=Array.from(u)}else{let u=oe(e,t);if(Array.isArray(u))for(let y of u)typeof y=="string"&&i.push(y)}return i},ka=(e,t)=>{let{filterToPropertyMapping:{specialProperty:r}}=t,a;return r&&(a=e[r]),a},le=({cardTypes:e},{types:t,subtypes:r})=>!e||e?.some(a=>t.map(s=>s.toLowerCase()).includes(a.toLowerCase())||r.map(s=>s.toLowerCase()).includes(a.toLowerCase()));var Sa=(e,t,r=[],a=[],s)=>{let{appliedFilters:i,attributes:n,keywords:o}=ne(e,t,{additionalHeroes:r,additionalSets:a,today:s});return{appliedFilters:i,attributes:n,keywords:o}};var Va=(e,t)=>{let r=new Set;for(let s of e)for(let i of s.createdExtras||[])r.add(i);let a=[];for(let s of t)r.has(s.cardIdentifier)&&a.push(s);return a};0&&(module.exports={FilterCategory,FilterKind,FilterProperty,MARKUP,NO_CARD_PROPERTY,PUNCTUATION,RARITY_VALUES_MAPPING,aliasesByFilterCategory,availableExclusions,availableModifiers,filterCard,filtersToCardPropertyMappings,getCardsByName,getCatalogueIndex,getCleanText,getEscapedForRegExp,getExcludedMetaFilters,getFilterCategory,getFilterMapping,getFilterTokenSpansForKey,getFilterValue,getIncompleteFilterToken,getIsExcludedToken,getIsValueInFilterVocabulary,getKeywordsAndAppliedFiltersFromText,getMetaFilterResolution,getMetaFilters,getNormalizedFilterValue,getNormalizedText,getParsedQuery,getQueryFilterToken,getQueryTokenSpans,getQuotedValue,getResolvedFilterKey,getSuggestedFilterKey,getTextWithoutMarkup,getTokensReferencedByCards,getUnquotedValue,getValuePartsFromFilterValue,getValuesFromFilterValue,multiWordShorthands,shorthands,singleWordShorthands});
1
+ "use strict";var _t=Object.create;var ge=Object.defineProperty;var Gt=Object.getOwnPropertyDescriptor;var zt=Object.getOwnPropertyNames;var $t=Object.getPrototypeOf,Wt=Object.prototype.hasOwnProperty;var Yt=(e,t)=>{for(var r in t)ge(e,r,{get:t[r],enumerable:!0})},Je=(e,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of zt(t))!Wt.call(e,a)&&a!==r&&ge(e,a,{get:()=>t[a],enumerable:!(s=Gt(t,a))||s.enumerable});return e};var qt=(e,t,r)=>(r=e!=null?_t($t(e)):{},Je(t||!e||!e.__esModule?ge(r,"default",{value:e,enumerable:!0}):r,e)),Xt=e=>Je(ge({},"__esModule",{value:!0}),e);var Os={};Yt(Os,{FilterCategory:()=>l,FilterKind:()=>m,FilterProperty:()=>J,MARKUP:()=>Re,NO_CARD_PROPERTY:()=>_,PUNCTUATION:()=>V.PUNCTUATION,RARITY_VALUES_MAPPING:()=>De,aliasesByFilterCategory:()=>ae,availableExclusions:()=>q,availableModifiers:()=>we,default:()=>jt,filterCard:()=>Ut,filtersToCardPropertyMappings:()=>se,getCardsByName:()=>Rs,getCatalogueIndex:()=>We,getCleanText:()=>O,getEscapedForRegExp:()=>re,getExcludedMetaFilters:()=>Ee,getFilterCategory:()=>ne,getFilterMapping:()=>he,getFilterTokenSpansForKey:()=>is,getFilterValue:()=>je,getIncompleteFilterToken:()=>He,getIsExcludedToken:()=>as,getIsValueInFilterVocabulary:()=>Ve,getKeywordsAndAppliedFiltersFromText:()=>Es,getMetaFilterResolution:()=>oe,getMetaFilters:()=>fr,getNormalizedFilterValue:()=>N.getNormalizedFilterValue,getNormalizedText:()=>Z,getParsedQuery:()=>le,getQueryFilterToken:()=>Me,getQueryTokenSpans:()=>xe,getQuotedValue:()=>os,getResolvedFilterKey:()=>Qe,getSuggestedFilterKey:()=>Ne,getTextWithoutMarkup:()=>te,getTokensReferencedByCards:()=>Bs,getUnquotedValue:()=>Ae,getValuePartsFromFilterValue:()=>Et,getValuesFromFilterValue:()=>Ue,multiWordShorthands:()=>_e,shorthands:()=>Ke,singleWordShorthands:()=>Ge});module.exports=Xt(Os);var qe=qt(require("fuse.js"),1);var V=require("@flesh-and-blood/types"),Re=/\*/g;var T=require("@flesh-and-blood/types");var et=require("@flesh-and-blood/types");var N=require("@flesh-and-blood/types"),O=e=>Z(e.toLowerCase().trim().replace(et.PUNCTUATION,"")),Z=e=>e.normalize("NFD").replace(/\p{Diacritic}/gu,""),te=e=>e.replace(Re,""),re=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");var l={Arcane:"arcane",Artist:"artist",Banned:"banned",Bond:"bond",Class:"class",Cost:"cost",CreatedBy:"createdby",Creates:"creates",Defense:"defense",Flow:"flow",Foiling:"foiling",Fusion:"fusion",Intellect:"intellect",Is:"is",Keyword:"keyword",Legal:"legal",Life:"life",Name:"name",Pitch:"pitch",Power:"power",Print:"print",Rarity:"rarity",ReferencedBy:"referencedby",References:"references",Set:"set",Shorthand:"shorthand",Specialization:"specialization",Subtype:"subtype",Talent:"talent",Text:"text",Trait:"trait",Treatment:"treatment",Type:"type",TypeText:"typetext",Year:"year"},m={Comparator:"comparator",ExactMatch:"exactMatch",PartialMatch:"partialMatch"},we=[">=",">","<=","<"],q=["!","-"],_="n/a",Tt=[...Object.values(T.Format),...Object.values(T.Hero)],Zt={category:l.Arcane,canonicalAlias:"arcane",kind:m.Comparator,property:"arcane",specialProperty:"specialArcane",isNumber:!0,partialMatch:!0},Pe={category:l.Artist,canonicalAlias:"art",kind:m.PartialMatch,property:"artists",isArray:!0,partialMatch:!0},tt={category:l.Banned,canonicalAlias:"banned",kind:m.ExactMatch,vocabulary:Tt,property:_,isMeta:!0},rt={category:l.Bond,canonicalAlias:"bond",kind:m.ExactMatch,vocabulary:Object.values(T.Bond),property:"bonds",isArray:!0},st={category:l.Class,canonicalAlias:"c",kind:m.PartialMatch,vocabulary:Object.values(T.Class),property:"classes",isArray:!0,partialMatch:!0},at={category:l.Cost,canonicalAlias:"co",kind:m.Comparator,property:"cost",specialProperty:"specialCost",isNumber:!0,partialMatch:!0},it={category:l.CreatedBy,canonicalAlias:"createdby",kind:m.PartialMatch,property:_},nt={category:l.Creates,canonicalAlias:"creates",kind:m.PartialMatch,property:_},ie={category:l.Defense,canonicalAlias:"d",kind:m.Comparator,property:"defense",specialProperty:"specialDefense",isNumber:!0},ot={category:l.Flow,canonicalAlias:"flow",kind:m.ExactMatch,vocabulary:Object.values(T.Flow),property:"flows",isArray:!0},lt={category:l.Foiling,canonicalAlias:"foil",kind:m.ExactMatch,vocabulary:Object.values(T.Foiling),nestedProperty:"foiling",property:"printings",isArray:!0},dt={category:l.Fusion,canonicalAlias:"f",kind:m.ExactMatch,vocabulary:Object.values(T.Fusion),property:"fusions",isArray:!0},ct={category:l.Intellect,canonicalAlias:"i",kind:m.Comparator,property:"intellect",isNumber:!0},pt={category:l.Keyword,canonicalAlias:"k",kind:m.ExactMatch,vocabulary:Object.values(T.Keyword),property:"keywords",isArray:!0},ve={category:l.Legal,canonicalAlias:"l",kind:m.ExactMatch,vocabulary:Tt,property:_,isMeta:!0},ut={category:l.Life,canonicalAlias:"li",kind:m.Comparator,property:"life",specialProperty:"specialLife",isNumber:!0},gt={category:l.Is,canonicalAlias:"is",kind:m.ExactMatch,vocabulary:Object.values(T.Meta),property:"meta",isArray:!0},ft={category:l.Name,canonicalAlias:"name",kind:m.PartialMatch,property:"name",isString:!0,partialMatch:!0},ke={category:l.Pitch,canonicalAlias:"p",kind:m.Comparator,property:"pitch",isNumber:!0},fe={category:l.Power,canonicalAlias:"pwr",kind:m.Comparator,property:"power",specialProperty:"specialPower",isNumber:!0},ye={category:l.Print,canonicalAlias:"print",kind:m.PartialMatch,property:"setIdentifiers",isArray:!0,partialMatch:!0},yt={category:l.Rarity,canonicalAlias:"r",kind:m.ExactMatch,vocabulary:Object.values(T.Rarity),property:_,isMeta:!0},Jt={category:l.ReferencedBy,canonicalAlias:"referencedby",kind:m.PartialMatch,property:_},er={category:l.References,canonicalAlias:"references",kind:m.PartialMatch,property:_},mt={category:l.Set,canonicalAlias:"s",kind:m.PartialMatch,property:"sets",isArray:!0,partialMatch:!0},Ie={category:l.Shorthand,canonicalAlias:"short",kind:m.PartialMatch,vocabulary:Object.values(T.Shorthand),property:"shorthands",isArray:!0,partialMatch:!0},me={category:l.Specialization,canonicalAlias:"sp",kind:m.PartialMatch,vocabulary:Object.values(T.Hero),property:"specializations",isArray:!0,partialMatch:!0},Ct={category:l.Subtype,canonicalAlias:"st",kind:m.ExactMatch,vocabulary:Object.values(T.Subtype),property:"subtypes",isArray:!0},ht={category:l.Type,canonicalAlias:"t",kind:m.ExactMatch,vocabulary:Object.values(T.Type),property:"types",isArray:!0},Se={category:l.Talent,canonicalAlias:"tal",kind:m.ExactMatch,vocabulary:Object.values(T.Talent),property:"talents",isArray:!0},tr={category:l.Text,canonicalAlias:"text",kind:m.PartialMatch,property:"functionalText",hasMarkup:!0,isString:!0,partialMatch:!0},rr={category:l.Trait,canonicalAlias:"trait",kind:m.PartialMatch,vocabulary:Object.values(T.Trait),property:"traits",isArray:!0,partialMatch:!0},Ft={category:l.TypeText,canonicalAlias:"x",kind:m.PartialMatch,property:"typeText",isString:!0,partialMatch:!0},Ce={category:l.Treatment,canonicalAlias:"treatment",kind:m.ExactMatch,vocabulary:Object.values(T.Treatment),nestedProperty:"treatments",property:"printings",isArray:!0,isNestedPropertyArray:!0},sr={category:l.Year,canonicalAlias:"year",kind:m.PartialMatch,property:"firstReleaseDate",isString:!0,partialMatch:!0},se={arcane:Zt,a:Pe,artist:Pe,art:Pe,attack:fe,b:ie,block:ie,banned:tt,bond:rt,bonds:rt,c:st,class:st,co:at,cost:at,createdby:it,creates:nt,color:ke,d:ie,def:ie,defense:ie,flow:ot,flows:ot,f:dt,fusion:dt,foil:lt,foiling:lt,i:ct,intellect:ct,is:gt,k:pt,keyword:pt,l:ve,legal:ve,hero:ve,li:ut,life:ut,madeby:it,makes:nt,meta:gt,n:ft,name:ft,p:ke,pitch:ke,pwr:fe,pow:fe,power:fe,print:ye,printing:ye,printings:ye,prints:ye,r:yt,rarity:yt,referencedby:Jt,references:er,rf:tt,s:mt,set:mt,short:Ie,shorthand:Ie,shorthands:Ie,sp:me,spec:me,specialization:me,specializations:me,st:Ct,subtype:Ct,t:ht,type:ht,tal:Se,talent:Se,talents:Se,text:tr,trait:rr,treat:Ce,treatment:Ce,var:Ce,variation:Ce,x:Ft,typetext:Ft,year:sr},ar=new Map(Object.entries(se)),he=e=>ar.get(e.toLowerCase()),ne=e=>he(e)?.category,ir=()=>{let e=Object.create(null);for(let[t,{category:r}]of Object.entries(se)){let s=e[r];s?s.push(t):e[r]=[t]}return e},ae=ir(),nr=()=>{let e=new Map,t=new Set,r=Object.values(se);for(let s of r){let{vocabulary:a}=s;if(a&&!t.has(s)){t.add(s);for(let i of a){let n=(0,N.getNormalizedFilterValue)(i),o=e.get(n);o?o.push(s):e.set(n,[s])}}}return e},xt=nr(),Ve=(e,t)=>!!xt.get((0,N.getNormalizedFilterValue)(t))?.some(r=>r.category===e),or=(e,t)=>{let r=[],s=!0;for(let a of t){let i=(xt.get((0,N.getNormalizedFilterValue)(a))||[]).filter(n=>n.category!==e);r=s?i:r.filter(n=>i.includes(n)),s=!1}return r},Ne=(e,t)=>{let r=or(e,t),[s]=r;return r.length===1?s.canonicalAlias:void 0};var ze=require("@flesh-and-blood/types");var u=require("@flesh-and-blood/types");var E=require("@flesh-and-blood/types");var J={BannedFormats:"bannedFormats",LegalFormats:"legalFormats",LegalHeroes:"legalHeroes"},Fe=Array.from(Array(50).keys()).map(e=>`${e}`),lr=[{format:E.Format.ClassicConstructed,nicknames:["cc","classic"]},{format:E.Format.LivingLegend,nicknames:["cc ll","classic constructed ll","ll cc","ll","living legend"]},{format:E.Format.SilverAge,nicknames:["sage"]},{format:E.Format.GoldenAge,nicknames:["gage"]},{format:E.Format.UltimatePitFight,nicknames:["upf"]}],dr=Object.values(E.Format).map(e=>{let t=lr.find(({format:s})=>s===e),r=e.toLowerCase().replaceAll(V.PUNCTUATION,"");return t?{...t,format:r}:{format:r}}),cr=Object.values(E.Hero).map(O),Mt=e=>e.replaceAll(" ",""),pr=(e,t)=>{let r=Mt(e),s,a=[];for(let n of t){let o=Mt(n);o===r?s=n:o.startsWith(r)&&a.push(n)}let i=a.length===1;return s??(i?a[0]:void 0)},At=["common","rare","super rare","majestic","legendary","fabled"],ur=({modifier:e,value:t})=>{let r=[],s=e==="<"||e==="<=",a=e===">="||e==="<=",i=s?[...At].reverse():At,n=!1;for(let o of i)n?r.push(o):o===t&&(n=!0,a&&r.push(o));return r},gr=(e,t)=>{let r=[];for(let s of e)s.modifier?r.push(...ur(s)):r.push(s.value);return{filterToPropertyMapping:{nestedProperty:"rarity",property:"printings",isArray:!0},isExcluded:t,isOr:!0,values:r}},bt=(e,t,r,s)=>{let a=new Set([...cr,...r.map(O)]),i=[],n=[],o=[],d=[];for(let{value:f}of e){let c=dr.find(({format:g,nicknames:C})=>g===f||!!C&&C.includes(f));if(c)n.push(c.format);else{let g=pr(f,a);g?o.push(g):d.push(f)}}return n.length>0&&i.push({filterToPropertyMapping:{property:s,isArray:!0},values:n,isOr:!0,isExcluded:t}),o.length>0&&i.push({filterToPropertyMapping:{property:J.LegalHeroes,isArray:!0},values:o,isOr:!0,isExcluded:t}),{appliedFilters:i,unresolvedValues:d}},oe=(e,t,{additionalHeroes:r=[],isExcluded:s=!1}={})=>{let a=ne(e),i={appliedFilters:[],unresolvedValues:[]};return a===l.Legal?i=bt(t,s,r,J.LegalFormats):a===l.Banned?i=bt(t,s,r,J.BannedFormats):a===l.Rarity&&(i={appliedFilters:[gr(t,s)],unresolvedValues:[]}),i},fr=(e,t,r,s,a,i)=>oe(r,s.map(n=>({modifier:a,value:n})),{additionalHeroes:i,isExcluded:e}).appliedFilters,yr=[{filterToPropertyMapping:{property:"cost",isNumber:!0},isExcluded:!0,values:Fe},{filterToPropertyMapping:{property:"specialCost",isString:!0,partialMatch:!0},isExcluded:!0,values:["*","x"]},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["equipment","hero","placeholder","token","weapon"]}],mr=[{filterToPropertyMapping:{property:"defense",isNumber:!0},isExcluded:!0,values:Fe},{filterToPropertyMapping:{property:"specialDefense",isString:!0,partialMatch:!0},isExcluded:!0,values:["*","x"]},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["hero","placeholder","token","weapon"]}],Cr=[{filterToPropertyMapping:{property:"pitch",isNumber:!0},isExcluded:!0,values:Fe},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["equipment","hero","placeholder","token","weapon"]},{filterToPropertyMapping:{property:"isCardBack",isBoolean:!0},isExcluded:!0,values:["true"]}],hr=[{filterToPropertyMapping:{property:"power",isNumber:!0},isExcluded:!0,values:Fe},{filterToPropertyMapping:{property:"specialPower",isString:!0,partialMatch:!0},isExcluded:!0,values:["*","x"]},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["equipment","hero","placeholder","token"]}],Fr=[{filterToPropertyMapping:{property:"talents",isArray:!0},isExcluded:!0,values:Object.values(E.Talent).map(e=>e.toLowerCase())}],Tr=[{filterToPropertyMapping:{property:"classes",isArray:!0},isExcluded:!0,values:Object.values(E.Class).map(e=>e.toLowerCase())}],xr=[{category:l.Class,filters:Tr},{category:l.Cost,filters:yr},{category:l.Defense,filters:mr},{category:l.Pitch,filters:Cr},{category:l.Power,filters:hr},{category:l.Talent,filters:Fr}],Mr=()=>{let e=new Map;for(let{category:t,filters:r}of xr)for(let s of ae[t])for(let a of q)e.set(`${a}${s}`,r);return e},Ar=Mr(),Ee=e=>{let t=[],r=Ar.get(e);return r&&t.push(...r),t};var br=e=>{let[t]=e,r=t?.modifier;return e.every(({modifier:a})=>a===r)?r:void 0},Be=({filterValues:e,isAnd:t,isExcluded:r,mapping:s})=>{let a=[];for(let{value:i}of e)a.push(s.hasMarkup?te(i):i);return{filterToPropertyMapping:s,filterValues:e,isAnd:t,isExcluded:r,isOr:!t&&a.length>1,modifier:br(e),values:a}},vt=({isAnd:e,isExcluded:t,mapping:r},s)=>({filterToPropertyMapping:r,isAnd:e,isExcluded:t,isOr:!e&&s.length>1,values:s}),Rr=({category:e,filterValues:t,mapping:r})=>{let s=[];if(r.kind===m.ExactMatch&&!!r.vocabulary)for(let{value:i}of t)Ve(e,i)||s.push(i);return s},Pr=e=>({appliedFilters:[Be(e)],unresolvedValues:Rr(e)}),Oe=({isExcluded:e},t,r)=>e?void 0:{[t]:r},kt=(e,t)=>({appliedFilters:[Be(e)],attributes:Oe(e,t,e.filterValues.map(({value:r})=>r)),unresolvedValues:[]}),vr=e=>kt(e,"artists"),kr=e=>kt(e,"prints"),Le=(e,t,r)=>{let s=[],a=[],i=[];for(let{value:n}of e.filterValues){let o=r(n);if(o.length>0)for(let d of o)s.push(d),a.push((0,N.getNormalizedFilterValue)(d));else i.push(n)}return{appliedFilters:[vt(e,a)],attributes:Oe(e,t,s),canonicalValues:a,unresolvedValues:i}},Ir=new Map(Object.entries({purple:4,blue:3,yellow:2,red:1,white:0})),Sr=e=>{let t=[],r=[];for(let{modifier:s,value:a}of e.filterValues){let i=Ir.get(a),n=i===void 0?a:`${i}`;t.push({modifier:s,value:n}),r.push(n)}return{appliedFilters:[Be({...e,filterValues:t})],canonicalValues:r,unresolvedValues:[]}},wr=(e,t)=>{let r=[()=>{let a=t.getReleaseByName(e);return a?[a.release]:[]},()=>{let a=t.getReleaseBySetIdentifier(e);return a?[a.release]:[]},()=>{let a=[];for(let{release:i}of t.releases)i.toLowerCase().includes(e)&&a.push(i);return a}],s=[];for(let a of r)s.length===0&&s.push(...a());return s},Vr=(e,{index:t})=>Le(e,"releases",r=>wr(r,t)),Nr=new Map(Object.entries({r:u.Foiling.Rainbow,rf:u.Foiling.Rainbow,rainbow:u.Foiling.Rainbow,c:u.Foiling.Cold,cf:u.Foiling.Cold,cold:u.Foiling.Cold,g:u.Foiling.Gold,gf:u.Foiling.Gold,gold:u.Foiling.Gold})),Er=e=>{let t=Nr.get(e);return t?[t]:[]},Br=e=>Le(e,"foilings",Er),It=new Map(Object.entries({aa:u.Treatment.AA,alt:u.Treatment.AA,"alt art":u.Treatment.AA,ab:u.Treatment.AB,"alt border":u.Treatment.AB,at:u.Treatment.AT,"alt text":u.Treatment.AT,ea:u.Treatment.EA,extended:u.Treatment.EA,"extended art":u.Treatment.EA,fa:u.Treatment.FA,full:u.Treatment.FA,"full art":u.Treatment.FA}));for(let e of Object.values(u.Treatment))It.set(e.toLowerCase(),e);var Or=new Map(Object.entries(u.Treatment)),Lr=e=>{let t=It.get(e)||Or.get(e.toUpperCase());return t?[t]:[]},Dr=e=>Le(e,"treatments",Lr),De=new Map(Object.entries({b:u.Rarity.Basic,c:u.Rarity.Common,f:u.Rarity.Fabled,l:u.Rarity.Legendary,m:u.Rarity.Majestic,p:u.Rarity.Promo,r:u.Rarity.Rare,s:u.Rarity.SuperRare,t:u.Rarity.Token,v:u.Rarity.Marvel})),Qr=e=>De.get(e)||Object.values(u.Rarity).find(t=>t.toLowerCase()===e),Hr=(e,{additionalHeroes:t})=>{let r=[],s=[],a=[],i=[];for(let{modifier:o,value:d}of e.filterValues){let f=Qr(d);f?(r.push(f),s.push(f.toLowerCase()),a.push({modifier:o,value:f.toLowerCase()})):(i.push(d),a.push({modifier:o,value:d}))}let{appliedFilters:n}=oe(e.key,a,{additionalHeroes:t,isExcluded:e.isExcluded});return{appliedFilters:n,attributes:Oe(e,"rarities",r),canonicalValues:s,unresolvedValues:i}},Rt=({filterValues:e,isExcluded:t,key:r},{additionalHeroes:s})=>{let{appliedFilters:a,unresolvedValues:i}=oe(r,e,{additionalHeroes:s,isExcluded:t}),n=[];for(let{values:o}of a)n.push(...o);return{appliedFilters:a,canonicalValues:n,unresolvedValues:i}},jr=["unique"],Ur=["preview","spoiler","unreleased"],Kr=["released"],Pt={property:"firstReleaseDate",isDate:!0},_r=new Map(Object.entries({dual:u.Meta.DualClass,exp:u.Meta.Expansion,expansion:u.Meta.Expansion,rainbow:u.Meta.Rainbow,reprint:u.Meta.Reprint,reprints:u.Meta.Reprint})),Gr=e=>{let t=[],r=[];for(let a of e){let i=_r.get(a);i?t.push(i):r.push(a)}let s=[];if(t.length===0){let a=new Set;for(let i of Object.values(u.Meta)){let n=!1;for(let o of r)i.toLowerCase().includes(o)&&(n=!0,a.add(o));n&&t.push(i)}for(let i of r)a.has(i)||s.push(i)}else s.push(...r);return{unresolvedValues:s,values:t}},zr=(e,{today:t})=>{let{filterValues:r,isAnd:s,isExcluded:a}=e,i=[],n=[],o=[],d=[],f=[];for(let{value:b}of r)jr.includes(b)?n.push(b):Ur.includes(b)?o.push(b):Kr.includes(b)?d.push(b):f.push(b);let c=!s&&r.length>1;n.length>0&&i.push({filterToPropertyMapping:se.is,values:[(0,N.getNormalizedFilterValue)(u.Meta.Reprint)],isAnd:s,isOr:c,isExcluded:!a}),o.length>0&&i.push({filterToPropertyMapping:Pt,values:[t],isAnd:s,isOr:c,isExcluded:a}),d.length>0&&i.push({filterToPropertyMapping:Pt,values:[t],isAnd:s,isOr:c,isExcluded:!a});let{unresolvedValues:g,values:C}=Gr(f),x=[...n,...o,...d,...C.map(N.getNormalizedFilterValue)];(f.length>0||i.length===0)&&i.push(vt(e,C.map(N.getNormalizedFilterValue)));let P=C.includes(u.Meta.Expansion)&&!a;return{appliedFilters:i,attributes:P?{isExpansionSlot:P}:void 0,canonicalValues:x,unresolvedValues:g}},$r={property:"cardIdentifier",isString:!0,isNormalized:!0},Wr=(e,t)=>{let r=e.getCardsByExactName(t);return r.length===0&&(r=e.getCardsByGroup(t)),r.length===0&&(r=e.getCardsByName(t)),r},Yr=(e,t,r)=>{let s=new Set;for(let a of Wr(e,t))for(let i of r(e,a.cardIdentifier))if(!s.has(i.cardIdentifier))for(let o of e.getPitchCycle(i.cardIdentifier))s.add(o.cardIdentifier);return s},qr=(e,t)=>{let r=new Set,[s=new Set,...a]=e;if(t)for(let i of s)a.every(o=>o.has(i))&&r.add(i);else for(let i of e)for(let n of i)r.add(n);return r},Xr=(e,t)=>({filterToPropertyMapping:$r,values:[...e],valuesSet:e,isExcluded:t,isOr:!0}),Te=e=>({filterValues:t,isAnd:r,isExcluded:s},{index:a})=>{let i=[],n=[];for(let{value:o}of t){let d=Yr(a,o,e);i.push(d),d.size===0&&n.push(o)}return{appliedFilters:[Xr(qr(i,r),s)],unresolvedValues:n}},Zr=new Map([[l.Artist,vr],[l.Banned,Rt],[l.CreatedBy,Te((e,t)=>e.getCreates(t))],[l.Creates,Te((e,t)=>e.getCreatedBy(t))],[l.Foiling,Br],[l.Is,zr],[l.Legal,Rt],[l.Pitch,Sr],[l.Print,kr],[l.Rarity,Hr],[l.ReferencedBy,Te((e,t)=>e.getReferences(t))],[l.References,Te((e,t)=>e.getReferencedBy(t))],[l.Set,Vr],[l.Treatment,Dr]]),St=(e,t)=>(Zr.get(e.category)||Pr)(e,t);var Vt=q.map(re).join(""),Jr=/(?:[^\s"]+|"[^"]*(?:"|$))+/g,es=new RegExp(`^([${Vt}])?([A-Za-z]+):(.+)$`),ts=new RegExp(`^([${Vt}])?([A-Za-z]+):$`),rs=",",wt="+",ss='"',Nt=e=>{let t=[],r=!1,s="",a=!1;for(let i of e)i===ss?(a=!a,s+=i):!a&&(i===rs||i===wt)?(r=r||i===wt,s&&t.push(s),s=""):s+=i;return s&&t.push(s),{isAndList:r,parts:t}},xe=e=>{let t=[];for(let r of e.matchAll(Jr))t.push({end:r.index+r[0].length,start:r.index,token:r[0]});return t},as=e=>q.some(t=>e.startsWith(t)),Me=e=>{let t=e.match(es),r;if(t){let[,s,a,i]=t;r={isAndList:Nt(i).isAndList,isExcluded:!!s,key:a,valueText:i}}return r},He=e=>{let t=e.match(ts),r;return t&&(r={isAndList:!1,isExcluded:!!t[1],key:t[2],valueText:""}),r},je=e=>{let t=e.trim(),r=we.find(s=>t.startsWith(s));return{modifier:r,value:r?t.slice(r.length).trim():t}},Qe=e=>ne(e)??e.toLowerCase(),is=(e,t)=>{let r=Qe(t),s=[];for(let{end:a,start:i,token:n}of xe(e)){let o=Me(n);o&&Qe(o.key)===r&&s.push({...o,end:a,start:i,token:n})}return s},Et=e=>Nt(e).parts,Ae=e=>e.replace(/^"|"$/g,""),Ue=e=>{let t=[];for(let r of Et(e)){let s=Ae(r);s&&t.push(s)}return t},ns=/[\s,:+"]/,os=e=>{let t=e.replaceAll('"',"");return ns.test(e)?`"${t}"`:t};var H=require("@flesh-and-blood/types"),Ke=[{description:"Attack actions",expanded:["st:attack"],filters:{subtypes:[H.Subtype.Attack]},isCardProperty:!1,shorthands:["AA"]},{description:"Arcane barrier",expanded:['k:"arcane barrier"'],filters:{keywords:[H.Keyword.ArcaneBarrier]},isCardProperty:!1,shorthands:["AB"]},{description:"Attack reactions",expanded:['t:"attack reaction"'],filters:{types:[H.Type.AttackReaction]},isCardProperty:!1,shorthands:["AR"]},{description:"Defense reactions",expanded:['t:"defense reaction"'],filters:{types:[H.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:[H.Keyword.GoAgain]},isCardProperty:!1,shorthands:["GA"]},{description:"Non-attack actions",expanded:["t:action","st:non-attack"],filters:{subtypes:[H.Subtype.NonAttack],types:[H.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:[H.Keyword.Spellvoid]},isCardProperty:!1,shorthands:["SV"]}],_e=Ke.filter(({shorthands:e})=>e.some(t=>t.includes(" "))).map(e=>({...e,shorthands:e.shorthands.filter(t=>t.includes(" ")).map(t=>t.toLowerCase()).sort((t,r)=>r.length-t.length)})),Ge=Ke.filter(({shorthands:e})=>e.some(t=>!t.includes(" "))).map(e=>({...e,shorthands:e.shorthands.filter(t=>!t.includes(" ")).map(t=>t.toLowerCase()).sort((t,r)=>r.length-t.length)}));var ls=["\u201C","\u201D"],ds=[{text:ze.Release.ClassicBattlesRhinarDorinthea.toLowerCase(),override:ze.Release.ClassicBattlesRhinarDorinthea.toLowerCase().replaceAll(V.PUNCTUATION,"")}],cs=[...ae[l.Set],...ae[l.Print]],ps=q.map(re).join(""),Bt=new WeakMap,us=e=>{let t=Bt.get(e);if(!t){let r=new Map;for(let{release:a,setIdentifiers:i}of e)r.set(a.toLowerCase(),i);let s=[...r.keys()].sort((a,i)=>i.length-a.length).map(re).join("|");t={setNameInSetFilterPattern:new RegExp(`(?<=^|\\s)([${ps}]?(?:${cs.join("|")}):(?:[^\\s]*[,+])?"?)(${s})(?="?(?:[,+]|\\s|$))`,"g"),setIdentifiersBySetName:r},Bt.set(e,t)}return t},gs=(e,t)=>{let r=e.trim().toLowerCase();for(let o of ls)r=r.replaceAll(o,'"');for(let{expanded:o,shorthands:d}of _e)for(let f of d)if(r.includes(f)){r=r.replace(f,o.join(" "));break}let{setIdentifiersBySetName:s,setNameInSetFilterPattern:a}=us(t.releases);r=r.replace(a,(o,d,f)=>{let c=s.get(f);return c?`${d}${c[0]}`:o});let i=s.get(r),n=t.getCardsByExactName(r).length>0;i&&!n&&(r=`set:${i[0]}`);for(let{override:o,text:d}of ds)r.includes(d)&&(r=r.replace(d,o));return r},fs=e=>{let t=Ge.find(({shorthands:s})=>s.includes(e)),r=!!t&&!t.isCardProperty;return{isExpanded:r,tokens:r?t.expanded:[e]}},ys=e=>{let t=[];for(let{end:r,start:s,token:a}of xe(e)){let{isExpanded:i,tokens:n}=fs(a);for(let o of n)t.push({end:r,isExpanded:i,start:s,token:o})}return t},ms=e=>{let t=[];for(let r of e){let{modifier:s,value:a}=je(r),i=(0,N.getNormalizedFilterValue)(a);i&&t.push({modifier:s,value:i})}return t},Cs=(e,t,r)=>{let s={key:e,reason:"value",values:r},a=Ne(t,r);return a&&(s.suggestedKey=a),s},hs=()=>{let e=new Date,t=`${e.getMonth()+1}`.padStart(2,"0"),r=`${e.getDate()}`.padStart(2,"0");return`${e.getFullYear()}-${t}-${r}`},le=(e,t,{additionalHeroes:r=[],today:s=hs()}={})=>{let a=gs(e,t),i={additionalHeroes:r,index:t,today:s},n=[],o={artists:[],foilings:[],isExpansionSlot:!1,prints:[],rarities:[],releases:[],treatments:[]},d=[],f=[],c=[];for(let g of ys(a)){let C=Me(g.token)||He(g.token);if(C){let{isAndList:x,isExcluded:S,key:P,valueText:b}=C,B=he(P),j=B?.category,z=Ue(b),U=ms(z),Y={...g,canonicalValues:U.map(({value:$})=>$),category:j,filterValues:U,isAnd:x,isExcluded:S,isFilter:!0,isResolved:!0,key:P};if(z.length>0)if(B&&j){let $=z;if(U.length>0){let h=St({category:j,filterValues:U,isAnd:Y.isAnd,isExcluded:S,key:P,mapping:B},i);n.push(...h.appliedFilters),h.canonicalValues&&(Y.canonicalValues=h.canonicalValues),h.attributes&&Object.assign(o,h.attributes),$=h.unresolvedValues}$.length>0&&(Y.isResolved=!1,c.push(Cs(P,j,$)))}else Y.isResolved=!1,c.push({key:P,reason:"key",values:[]});f.push(Y)}else{let{end:x,start:S,token:P}=g;f.push({end:x,isFilter:!1,start:S,token:P});let b=Ae(g.token),B=Ee(b);B.length>0?n.push(...B):b&&d.push(b.replace(V.PUNCTUATION,""))}}return{appliedFilters:n,attributes:o,keywords:d,nodes:f,text:a,unresolvedFilters:c}};var A=require("@flesh-and-blood/types"),Ot={artists:["Hoodwill"],cardIdentifier:"fangs-a-lot-blue",classes:[A.Class.Generic],defaultImage:"FNG000",firstReleaseDate:"2022-06-02",functionalText:"If Fangs A Lot is put into your banished zone from your graveyard, instead put it into your hand.",legalFormats:[],legalHeroes:[A.Hero.Kayo,A.Hero.Levia,A.Hero.Rhinar],printings:[{artists:["Hoodwill"],identifier:"FNG000",image:"FNG000",print:"FNG000",rarity:A.Rarity.Rare,set:A.Release.Promos},{artists:["Hoodwill"],identifier:"FNG000",image:"FNG000_Marvel",print:`FNG000-${A.Treatment.FA}`,rarity:A.Rarity.Marvel,set:A.Release.Promos,treatments:[A.Treatment.FA]}],name:"Fangs A Lot",rarities:[A.Rarity.Rare,A.Rarity.Marvel],rarity:A.Rarity.Rare,sets:[A.Release.Promos],setIdentifiers:["FNG000"],specialImage:"FNG000_Marvel",subtypes:[A.Subtype.Attack],types:[A.Type.Action],typeText:"Generic Action - Attack"},Lt=[{keyword:Ot.name.toLowerCase(),card:Ot}];var G=require("@flesh-and-blood/types");var Fs=3,Ts=e=>{let t=Z(e.toLowerCase()).replace(/[^a-z\s-]/g,""),r=new Set;for(let s of[/[\s-]+/,/\s+/]){let a="";for(let i of t.split(s)){let n=i.replaceAll("-","");n&&(a+=n[0])}a.length>=Fs&&r.add(a)}return[...r]},be=e=>O(e).replaceAll("-",""),$e=(e,t,r)=>{let s=e.get(t);s?s.push(r):e.set(t,[r])},Dt=new WeakMap,L=Object.freeze([]),xs=Number.MAX_SAFE_INTEGER,Qt=(e,t)=>{let r=new Map;for(let s of e)for(let a of t(s)||[]){let i=r.get(a);i?i.push(s):r.set(a,[s])}return r},Ms=e=>{let t=new Map;for(let r of e){let s=r.types.includes(G.Type.Hero)&&!r.isCardBack,a=s?G.CardRole.Hero:(0,G.getCardRole)(r);if(s||a!==G.CardRole.Hero){let n=t.get(a);n?n.push(r):t.set(a,[r])}}return t},As=e=>{let t=new Map,r=new Map,s=new Map;for(let a of e){t.set((0,G.getNormalizedFilterValue)(a.release),a),r.set(a.release,a);for(let i of a.setIdentifiers)s.set(i.toLowerCase(),a)}return{releaseByFilterName:t,releaseByRelease:r,releaseBySetIdentifier:s}},bs=(e,t)=>{let r,s=new Map,a,i,n,o,d,f,c,g,C=()=>{if(!a){let p=new Map,y=new Map,F=[],M=new Map,R=0;for(let Q of e){p.set(Q.cardIdentifier,Q),y.set(Q.cardIdentifier,R),R++;let w=O(Q.name),ue=M.get(w);ue?ue.push(Q):(M.set(w,[Q]),F.push(w))}a={cardByCardIdentifier:p,corpusPositionByCardIdentifier:y,cleanedNames:F,pitchCycleByCleanedName:M}}return a},x=p=>{let{corpusPositionByCardIdentifier:y}=C(),F=({cardIdentifier:M})=>y.get(M)??xs;return[...p].sort((M,R)=>F(M)-F(R))},S=p=>C().cardByCardIdentifier.get(p),P=p=>{let{cardByCardIdentifier:y}=C(),F=[];for(let M of p||[]){let R=y.get(M);R&&F.push(R)}return x(F)},b=p=>{let y=new Map;return F=>{let M=y.get(F);if(!M){let R=S(F),Q=P(R&&p(R)),w=Q.length>0;M=w?Q:L,w&&y.set(F,M)}return M}},B=p=>{let{pitchCycleByCleanedName:y}=C(),F=S(p);return F?y.get(O(F.name))??L:L},j=p=>{let{cleanedNames:y,pitchCycleByCleanedName:F}=C(),M=O(p),R=F.get(M);if(!R&&M.length>0){let w=y.find(ue=>ue.includes(M));w&&(R=F.get(w))}return R??L},z=p=>{let{pitchCycleByCleanedName:y}=C();return y.get(O(p))??L},U=p=>{if(!f){f=new Map;for(let y of e)for(let F of y.nicknames??[])$e(f,be(F),y)}return f.get(be(p))??L},Y=p=>{if(!c){c=new Map;for(let y of e)for(let F of[...y.types,...y.subtypes,...y.traits??[]])$e(c,be(F),y)}return c.get(be(p))??L},$=p=>{if(!g){g=new Map;for(let y of e)for(let F of Ts(y.name))$e(g,F,y)}return g.get(p)??L},h=()=>{if(!d){let p=new Set;for(let y of e)for(let F of y.artists)p.add(F);d=[...p].sort((y,F)=>y.localeCompare(F,"en",{sensitivity:"base"}))}return d},K=b(({oppositeSideCardIdentifiers:p})=>p),k=b(({referencedCards:p})=>p),v=p=>(i||(i=Qt(e,({referencedCards:y})=>y)),i.get(p)??L),D=b(({createdExtras:p})=>p),X=p=>(n||(n=Qt(e,({createdExtras:y})=>y)),n.get(p)??L),I=p=>{let y=new Map,F=new Set,M=[...p];for(let R of M)if(!F.has(R)){F.add(R);for(let w of D(R))y.set(w.cardIdentifier,w),M.push(w.cardIdentifier)}return x([...y.values()])},W=()=>(r||(r=As(t)),r),pe=p=>W().releaseByRelease.get(p);return{cards:e,releases:t,getCard:S,getRelease:pe,getReleaseByName:p=>W().releaseByFilterName.get((0,G.getNormalizedFilterValue)(p)),getReleaseBySetIdentifier:p=>W().releaseBySetIdentifier.get(p.toLowerCase()),getReleaseHeroCards:p=>{let y=s.get(p);if(!y){let F=pe(p),M=P(F?.heroIdentifiers),R=M.length>0;y=R?M:L,R&&s.set(p,y)}return y},getPitchCycle:B,getCardsByName:j,getCardsByExactName:z,getCardsByNickname:U,getCardsByGroup:Y,getCardsByInitials:$,getArtists:h,getOppositeSide:K,getReferences:k,getReferencedBy:v,getCreates:D,getCreatedBy:X,getCreatedClosure:I,getByRole:p=>(o||(o=Ms(e)),o.get(p)??L),getCardsInCorpusOrder:x}},We=(e,t)=>{let r=Dt.get(e);r||(r=new WeakMap,Dt.set(e,r));let s=r.get(t);return s||(s=bs(e,t),r.set(t,s)),s},Rs=(e,t)=>e.getCardsByName(t);var Ps={getFn:(e,t)=>{let r=qe.default.config.getFn(e,t),s=r;if(Array.isArray(r))s=r.map(a=>{let i=typeof a=="string"?a:a.v;return Z(i.replace(V.PUNCTUATION,""))});else if(r){let a=Z(r).replace(V.PUNCTUATION,"");s=t.includes("functionalText")?te(a):a}return s},ignoreLocation:!0,includeScore:!0,keys:[{name:"name",weight:10},{name:"functionalText",weight:6},{name:"shorthands",weight:4},{name:"setIdentifiers",weight:2},{name:"traits",weight:4},{name:"typeText",weight:6}],threshold:.15,useExtendedSearch:!0},Ye=class{constructor(t,r){this.getFuse=()=>(this.fuse||(this.fuse=new qe.default(this.cards,Ps)),this.fuse);this.getPoolCards=t=>{this.poolCardByCardIdentifier||(this.poolCardByCardIdentifier=new Map(this.cards.map(s=>[s.cardIdentifier,s])));let r=[];for(let{cardIdentifier:s}of t){let a=this.poolCardByCardIdentifier.get(s);a&&r.push(a)}return r};this.search=(t,r)=>{let s,a,{appliedFilters:i,attributes:n,keywords:o,unresolvedFilters:d}=le(t,this.index,{additionalHeroes:this.additionalHeroes}),f=o.join(" "),c=r?Lt.filter(h=>h.keyword===f):[],g=h=>i.length>0?h.filter(K=>K&&Ut(K,i)):h;if(c.length>0)s=g(c.map(({card:h})=>h));else if(o.length){let h=O(f),K=this.getPoolCards(this.index.getCardsByNickname(h)),k=new Map;for(let I of[...this.getPoolCards(this.index.getCardsByExactName(h)),...K])k.set(I.cardIdentifier,I);let v=this.getFuse().search(f).map(I=>I.item).filter(({cardIdentifier:I})=>!k.has(I));s=g([...k.values(),...v]),s.some(I=>K.includes(I))&&(a={kind:"nickname",text:h}),s.length===0&&o.length===1&&(s=g(this.getPoolCards(this.index.getCardsByInitials(h))),s.length>0&&(a={kind:"initials",text:h}))}else s=g([...this.cards]);if(!(o.length>0&&a?.kind!=="initials")){let h="";if(n.releases.length===1){let v=this.index.getRelease(n.releases[0])?.setIdentifiers;v?.length&&(h=v[0].toUpperCase())}if(!h&&n.prints.length===1){let v=n.prints[0];this.index.getReleaseBySetIdentifier(v)&&(h=v.toUpperCase())}h?s.sort((v,D)=>{let X=v.setIdentifiers.find(W=>W.includes(h))?.replace(h,""),I=D.setIdentifiers.find(W=>W.includes(h))?.replace(h,"");return X&&I?X.localeCompare(I):-1}):s.sort((v,D)=>v.name===D.name?`${v.pitch}`.localeCompare(`${D.pitch}`):v.name.localeCompare(D.name))}let x=[],{artists:S,isExpansionSlot:P,foilings:b,prints:B,rarities:j,releases:z,treatments:U}=n;(S.length>0||P||b.length>0||B.length>0||j.length>0||z.length>0||U.length>0)&&(x=s.map(h=>{let K=h.printings.filter(k=>{let v=!!k.image,D=S.length===0||S.some(ee=>k.artists.find(p=>p.replace(V.PUNCTUATION,"").toLowerCase().includes(ee))),X=!P||P===k.isExpansionSlot,I=b.length===0||!!k.foiling&&b.includes(k.foiling),W=B.length===0||B.some(ee=>k.identifier.includes(ee.toUpperCase())),pe=j.length===0||j.includes(k.rarity),Xe=z.length===0||z.includes(k.set),Ze=U.length===0||k.treatments?.some(ee=>U.includes(ee));return v&&D&&X&&I&&W&&pe&&Xe&&Ze});return{...h,matchingPrintings:K}}));let $=x.length>0?x:s;return{alias:a,appliedFilters:i,attributes:n,keywords:o,searchResults:$,unresolvedFilters:d}};this.additionalHeroes=r.additionalHeroes||[],this.cards=[...t],this.index=r.index||We(t,r.releases)}},jt=Ye,Ut=(e,t)=>{let r=!0;for(let s of t){let{isNumber:a,isString:i,isArray:n,isBoolean:o,isDate:d}=s.filterToPropertyMapping;s.isOptional||(a?r=r&&vs(e,s):i?r=r&&ks(e,s):n?r=r&&Is(e,s,t):o?r=r&&Ss(e,s):d&&(r=r&&ws(e,s)))}return r},Ht=(e,t,r)=>{let s=parseInt(t),a;switch(r){case">=":a=e>=s;break;case">":a=e>s;break;case"<=":a=e<=s;break;case"<":a=e<s;break;default:a=e===s}return a},vs=(e,t)=>{let{filterValues:r,values:s,modifier:a,isExcluded:i,filterToPropertyMapping:{partialMatch:n}}=t,o=!0;if(ce(t,e)){let d=de(e,t),f;if(d!=null&&!isNaN(d)){let c=parseInt(d);f=r?r.some(({modifier:g,value:C})=>Ht(c,C,g)):s.some(g=>Ht(c,g,a))}else{let c=Ns(e,t)?.toLowerCase();f=n?s.some(g=>!!c?.includes(g)):s.some(g=>c===g)}o=i?!f:f}return o},ks=(e,t)=>{if(ce(t,e)){let{values:r,valuesSet:s,isAnd:a,isExcluded:i,filterToPropertyMapping:{hasMarkup:n,isNormalized:o,partialMatch:d}}=t,f=de(e,t),c=o?f:f?.replaceAll(V.PUNCTUATION,"").toLowerCase(),g=n&&c?te(c):c;if(d){let C=a?r?.every(x=>g?.includes(x)):r?.some(x=>g?.includes(x));return i?!C:C}else{let C;return a?C=r?.every(x=>g===x):s?C=s.has(g):C=r?.some(x=>g===x),i?!C:C}}else return!0},Is=(e,t,r)=>{if(ce(t,e)){let{values:s,isAnd:a,isExcluded:i,filterToPropertyMapping:{partialMatch:n}}=t,o=Vs(e,t,r).map(d=>d?.replaceAll(V.PUNCTUATION,""));if(n){let d=a?s.every(c=>o?.some(g=>g?.toLowerCase().includes(c))):s.some(c=>o?.some(g=>g?.toLowerCase().includes(c))),f=o.length===0;return i?!d||f:d}else{let d=a?s.every(f=>o?.some(c=>c?.toLowerCase()===f)):s.some(f=>o?.some(c=>c?.toLowerCase()===f));return i?!d:d}}else return!0},Ss=(e,t)=>{if(ce(t,e)){let{isExcluded:r}=t,s=de(e,t);return r?!s:s}else return!0},ws=(e,t)=>{if(ce(t,e)){let{values:r,isExcluded:s}=t,a=de(e,t),i=r?.some(n=>a>n);return s?!i:i}else return!0},de=(e,t)=>{let{filterToPropertyMapping:{property:r}}=t,s;return r!==_&&(s=e[r]),s},Vs=(e,t,r)=>{let{filterToPropertyMapping:{isNestedPropertyArray:s,nestedProperty:a}}=t,i=[],n=Object.keys(e.legalOverrides||{}).length>0,o=t.filterToPropertyMapping.property===J.LegalHeroes,d=r.find(({filterToPropertyMapping:c})=>c.property===J.LegalFormats);if(n&&o&&!!d){let c=new Set;for(let{format:g,heroes:C}of e.legalOverrides||[])if(d.values.includes(g.toLowerCase()))for(let x of C)c.add(x);i=Array.from(c)}if(i.length===0)if(a){let c=new Set;for(let g of e.printings){let C=g[a];if(s){if(Array.isArray(C))for(let x of C)c.add(x)}else C&&typeof C=="string"&&c.add(C)}i=Array.from(c)}else{let c=de(e,t);if(Array.isArray(c))for(let g of c)typeof g=="string"&&i.push(g)}return i},Ns=(e,t)=>{let{filterToPropertyMapping:{specialProperty:r}}=t,s;return r&&(s=e[r]),s},ce=({cardTypes:e},{types:t,subtypes:r})=>!e||e?.some(s=>t.map(a=>a.toLowerCase()).includes(s.toLowerCase())||r.map(a=>a.toLowerCase()).includes(s.toLowerCase()));var Es=(e,t,r=[],s)=>{let{appliedFilters:a,attributes:i,keywords:n}=le(e,t,{additionalHeroes:r,today:s});return{appliedFilters:a,attributes:i,keywords:n}};var Bs=(e,t)=>{let r=new Set;for(let a of e)for(let i of a.createdExtras||[])r.add(i);let s=[];for(let a of t)r.has(a.cardIdentifier)&&s.push(a);return s};0&&(module.exports={FilterCategory,FilterKind,FilterProperty,MARKUP,NO_CARD_PROPERTY,PUNCTUATION,RARITY_VALUES_MAPPING,aliasesByFilterCategory,availableExclusions,availableModifiers,filterCard,filtersToCardPropertyMappings,getCardsByName,getCatalogueIndex,getCleanText,getEscapedForRegExp,getExcludedMetaFilters,getFilterCategory,getFilterMapping,getFilterTokenSpansForKey,getFilterValue,getIncompleteFilterToken,getIsExcludedToken,getIsValueInFilterVocabulary,getKeywordsAndAppliedFiltersFromText,getMetaFilterResolution,getMetaFilters,getNormalizedFilterValue,getNormalizedText,getParsedQuery,getQueryFilterToken,getQueryTokenSpans,getQuotedValue,getResolvedFilterKey,getSuggestedFilterKey,getTextWithoutMarkup,getTokensReferencedByCards,getUnquotedValue,getValuePartsFromFilterValue,getValuesFromFilterValue,multiWordShorthands,shorthands,singleWordShorthands});
@@ -1,4 +1,4 @@
1
- import { Hero, Release } from "@flesh-and-blood/types";
1
+ import { Hero } from "@flesh-and-blood/types";
2
2
  import { FilterCategory, type AppliedFilter, type FilterValue } from "./filterMappings.js";
3
3
  import { type QueryAttributes } from "./filterResolvers.js";
4
4
  import { type QueryTokenSpan } from "./queryTokens.js";
@@ -64,8 +64,7 @@ export interface ParsedQuery {
64
64
  }
65
65
  export interface ParseOptions {
66
66
  additionalHeroes?: Hero[];
67
- additionalSets?: Release[];
68
67
  /** Today, for the filters that compare a release date against it. */
69
68
  today?: string;
70
69
  }
71
- export declare const getParsedQuery: (text: string, index: CatalogueIndex, { additionalHeroes, additionalSets, today, }?: ParseOptions) => ParsedQuery;
70
+ export declare const getParsedQuery: (text: string, index: CatalogueIndex, { additionalHeroes, today }?: ParseOptions) => ParsedQuery;
@@ -1,7 +1,4 @@
1
- import {
2
- Release,
3
- setToSetIdentifierMappings
4
- } from "@flesh-and-blood/types";
1
+ import { Release } from "@flesh-and-blood/types";
5
2
  import { PUNCTUATION } from "./constants.js";
6
3
  import {
7
4
  aliasesByFilterCategory,
@@ -34,26 +31,33 @@ const punctuationOverrides = [
34
31
  )
35
32
  }
36
33
  ];
37
- const setIdentifiersBySetName = new Map(
38
- [...setToSetIdentifierMappings].map(
39
- ([release, setIdentifiers]) => [
40
- release.toLowerCase(),
41
- setIdentifiers
42
- ]
43
- )
44
- );
45
34
  const SET_FILTER_KEYS = [
46
35
  ...aliasesByFilterCategory[FilterCategory.Set],
47
36
  ...aliasesByFilterCategory[FilterCategory.Print]
48
37
  ];
49
38
  const EXCLUSION_CHARACTERS = availableExclusions.map(getEscapedForRegExp).join("");
50
- const setNamesLongestFirst = [...setIdentifiersBySetName.keys()].sort((first, second) => second.length - first.length).map(getEscapedForRegExp).join("|");
51
- const setNameInSetFilterPattern = new RegExp(
52
- `(?<=^|\\s)([${EXCLUSION_CHARACTERS}]?(?:${SET_FILTER_KEYS.join(
53
- "|"
54
- )}):(?:[^\\s]*[,+])?"?)(${setNamesLongestFirst})(?="?(?:[,+]|\\s|$))`,
55
- "g"
56
- );
39
+ const setNameRewriteByReleases = /* @__PURE__ */ new WeakMap();
40
+ const getSetNameRewrite = (releases) => {
41
+ let setNameRewrite = setNameRewriteByReleases.get(releases);
42
+ if (!setNameRewrite) {
43
+ const setIdentifiersBySetName = /* @__PURE__ */ new Map();
44
+ for (const { release, setIdentifiers } of releases) {
45
+ setIdentifiersBySetName.set(release.toLowerCase(), setIdentifiers);
46
+ }
47
+ const setNamesLongestFirst = [...setIdentifiersBySetName.keys()].sort((first, second) => second.length - first.length).map(getEscapedForRegExp).join("|");
48
+ setNameRewrite = {
49
+ setNameInSetFilterPattern: new RegExp(
50
+ `(?<=^|\\s)([${EXCLUSION_CHARACTERS}]?(?:${SET_FILTER_KEYS.join(
51
+ "|"
52
+ )}):(?:[^\\s]*[,+])?"?)(${setNamesLongestFirst})(?="?(?:[,+]|\\s|$))`,
53
+ "g"
54
+ ),
55
+ setIdentifiersBySetName
56
+ };
57
+ setNameRewriteByReleases.set(releases, setNameRewrite);
58
+ }
59
+ return setNameRewrite;
60
+ };
57
61
  const getPreparedText = (text, index) => {
58
62
  let preparedText = text.trim().toLowerCase();
59
63
  for (const smartQuote of SMART_DOUBLE_QUOTES) {
@@ -67,6 +71,7 @@ const getPreparedText = (text, index) => {
67
71
  }
68
72
  }
69
73
  }
74
+ const { setIdentifiersBySetName, setNameInSetFilterPattern } = getSetNameRewrite(index.releases);
70
75
  preparedText = preparedText.replace(
71
76
  setNameInSetFilterPattern,
72
77
  (setNameInSetFilter, filterPrefix, setName) => {
@@ -131,15 +136,10 @@ const getTodayAsReleaseDate = () => {
131
136
  const dayOfMonth = `${now.getDate()}`.padStart(2, "0");
132
137
  return `${now.getFullYear()}-${month}-${dayOfMonth}`;
133
138
  };
134
- const getParsedQuery = (text, index, {
135
- additionalHeroes = [],
136
- additionalSets = [],
137
- today = getTodayAsReleaseDate()
138
- } = {}) => {
139
+ const getParsedQuery = (text, index, { additionalHeroes = [], today = getTodayAsReleaseDate() } = {}) => {
139
140
  const preparedText = getPreparedText(text, index);
140
141
  const context = {
141
142
  additionalHeroes,
142
- additionalSets,
143
143
  index,
144
144
  today
145
145
  };
package/dist/search.d.ts CHANGED
@@ -1,23 +1,29 @@
1
- import { Card, DoubleSidedCard, Hero, Printing, Release } from "@flesh-and-blood/types";
1
+ import { Card, DoubleSidedCard, Hero, Printing, ReleaseInfo } from "@flesh-and-blood/types";
2
2
  import { AppliedFilter } from "./filterMappings.js";
3
3
  import { QueryAttributes, UnresolvedFilter } from "./queryParse.js";
4
4
  import { CatalogueIndex } from "./searchIndex.js";
5
5
  export interface SearchCard extends DoubleSidedCard {
6
6
  matchingPrintings?: Printing[];
7
7
  }
8
- export interface SearchOptions {
8
+ /**
9
+ * The catalogue the parser resolves names, sets and relations against: an index
10
+ * built elsewhere, or the releases the corpus ships with, making the corpus its
11
+ * own catalogue. A pool searched out of a larger catalogue shares the
12
+ * catalogue's index, so a relation is answered from every card that carries it
13
+ * while the search still answers with the pool alone. The pool must be a subset
14
+ * of the catalogue the index was built over: a pool card the catalogue does not
15
+ * hold resolves to nothing, with no error.
16
+ */
17
+ type SearchCatalogue = {
18
+ index: CatalogueIndex;
19
+ releases?: never;
20
+ } | {
21
+ index?: never;
22
+ releases: readonly ReleaseInfo[];
23
+ };
24
+ export type SearchOptions = SearchCatalogue & {
9
25
  additionalHeroes?: Hero[];
10
- additionalSets?: Release[];
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
- }
26
+ };
21
27
  /** How the free text named cards other than by their names. */
22
28
  export interface SearchAlias {
23
29
  kind: "nickname" | "initials";
@@ -38,13 +44,11 @@ export interface SearchResults {
38
44
  }
39
45
  declare class Search {
40
46
  private additionalHeroes;
41
- private additionalSets;
42
47
  private cards;
43
48
  private fuse;
44
49
  private index;
45
50
  private poolCardByCardIdentifier;
46
- constructor(cards: DoubleSidedCard[], options?: SearchOptions);
47
- constructor(cards: DoubleSidedCard[], additionalHeroes?: Hero[], additionalSets?: Release[]);
51
+ constructor(cards: DoubleSidedCard[], options: SearchOptions);
48
52
  private getFuse;
49
53
  /**
50
54
  * The pool's own copies of index cards, dropping any the pool lacks, so a pool
package/dist/search.js CHANGED
@@ -1,7 +1,3 @@
1
- import {
2
- setIdentifierToSetMappings,
3
- setToSetIdentifierMappings
4
- } from "@flesh-and-blood/types";
5
1
  import Fuse from "fuse.js";
6
2
  import { PUNCTUATION } from "./constants.js";
7
3
  import {
@@ -47,7 +43,7 @@ const searchOptions = {
47
43
  useExtendedSearch: true
48
44
  };
49
45
  class Search {
50
- constructor(cards, additionalHeroesOrOptions = [], additionalSets = []) {
46
+ constructor(cards, options) {
51
47
  // Scoring the corpus is the costly half of a search, so a catalogue that is
52
48
  // only ever filtered never pays to index it.
53
49
  this.getFuse = () => {
@@ -79,8 +75,7 @@ class Search {
79
75
  let results;
80
76
  let alias;
81
77
  const { appliedFilters, attributes, keywords, unresolvedFilters } = getParsedQuery(text, this.index, {
82
- additionalHeroes: this.additionalHeroes,
83
- additionalSets: this.additionalSets
78
+ additionalHeroes: this.additionalHeroes
84
79
  });
85
80
  const keyword = keywords.join(" ");
86
81
  const matchingMemes = includeMemes ? memes.filter((meme) => meme.keyword === keyword) : [];
@@ -131,9 +126,9 @@ class Search {
131
126
  let setIdentifierToSortBy = "";
132
127
  const shouldSortByRelease = attributes.releases.length === 1;
133
128
  if (shouldSortByRelease) {
134
- const matchingSetIdentifiers = setToSetIdentifierMappings.get(
129
+ const matchingSetIdentifiers = this.index.getRelease(
135
130
  attributes.releases[0]
136
- );
131
+ )?.setIdentifiers;
137
132
  if (matchingSetIdentifiers?.length) {
138
133
  setIdentifierToSortBy = matchingSetIdentifiers[0].toUpperCase();
139
134
  }
@@ -141,7 +136,7 @@ class Search {
141
136
  const shouldSortByPrint = !setIdentifierToSortBy && attributes.prints.length === 1;
142
137
  if (shouldSortByPrint) {
143
138
  const setToSort = attributes.prints[0];
144
- if (setIdentifierToSetMappings.has(setToSort)) {
139
+ if (this.index.getReleaseBySetIdentifier(setToSort)) {
145
140
  setIdentifierToSortBy = setToSort.toUpperCase();
146
141
  }
147
142
  }
@@ -206,11 +201,9 @@ class Search {
206
201
  unresolvedFilters
207
202
  };
208
203
  };
209
- const options = Array.isArray(additionalHeroesOrOptions) ? { additionalHeroes: additionalHeroesOrOptions, additionalSets } : additionalHeroesOrOptions;
210
204
  this.additionalHeroes = options.additionalHeroes || [];
211
- this.additionalSets = options.additionalSets || [];
212
205
  this.cards = [...cards];
213
- this.index = options.index || getCatalogueIndex(cards);
206
+ this.index = options.index || getCatalogueIndex(cards, options.releases);
214
207
  }
215
208
  }
216
209
  var search_default = Search;
@@ -1,7 +1,7 @@
1
- import { CardRole, DoubleSidedCard } from "@flesh-and-blood/types";
1
+ import { CardRole, DoubleSidedCard, ReleaseInfo } from "@flesh-and-blood/types";
2
2
  /**
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,
3
+ * Everything a corpus can be asked about its cards and releases: lookups, the
4
+ * relations the cards carry, and what each card is for. Every relation is identifier-level,
5
5
  * so a card named at one pitch answers for that pitch alone; widening a
6
6
  * relation to the whole name is the reader's rule rather than the corpus's.
7
7
  * Every list-returning read but `getCreatedClosure` and `getCardsInCorpusOrder`
@@ -11,7 +11,17 @@ import { CardRole, DoubleSidedCard } from "@flesh-and-blood/types";
11
11
  */
12
12
  export interface CatalogueIndex<CardType extends DoubleSidedCard = DoubleSidedCard> {
13
13
  cards: readonly CardType[];
14
+ /** Every release the corpus ships with, in release order. */
15
+ releases: readonly ReleaseInfo[];
14
16
  getCard: (cardIdentifier: string) => CardType | undefined;
17
+ /** The release a card's sets name, matched exactly. */
18
+ getRelease: (release: string) => ReleaseInfo | undefined;
19
+ /** The release with the name, read as a filter reads it. */
20
+ getReleaseByName: (name: string) => ReleaseInfo | undefined;
21
+ /** The release carrying the set identifier, in any case. */
22
+ getReleaseBySetIdentifier: (setIdentifier: string) => ReleaseInfo | undefined;
23
+ /** The hero cards the release is for. */
24
+ getReleaseHeroCards: (release: string) => readonly CardType[];
15
25
  /** Every pitch of the card's name, the card itself among them. */
16
26
  getPitchCycle: (cardIdentifier: string) => readonly CardType[];
17
27
  /**
@@ -69,11 +79,12 @@ export interface CatalogueIndex<CardType extends DoubleSidedCard = DoubleSidedCa
69
79
  getCardsInCorpusOrder: <OrderedCard extends DoubleSidedCard>(cardsToOrder: readonly OrderedCard[]) => OrderedCard[];
70
80
  }
71
81
  /**
72
- * The index for a corpus, one per array, so everything reading the same cards
73
- * shares its maps. Each map is built the first time a read asks for it. The
74
- * array is treated as immutable from that first read on: a caller that changes
75
- * which cards the catalogue holds builds a new array.
82
+ * The index for a corpus, one per pair of cards and releases arrays, so
83
+ * everything reading the same catalogue shares its maps. Each map is built the
84
+ * first time a read asks for it. Both arrays are treated as immutable from that
85
+ * first read on: a caller that changes what the catalogue holds builds a new
86
+ * array.
76
87
  */
77
- export declare const getCatalogueIndex: <CardType extends DoubleSidedCard = DoubleSidedCard>(cards: readonly CardType[]) => CatalogueIndex<CardType>;
88
+ export declare const getCatalogueIndex: <CardType extends DoubleSidedCard = DoubleSidedCard>(cards: readonly CardType[], releases: readonly ReleaseInfo[]) => CatalogueIndex<CardType>;
78
89
  /** {@link CatalogueIndex.getCardsByName}, as a free function over an index. */
79
90
  export declare const getCardsByName: (index: CatalogueIndex, name: string) => readonly DoubleSidedCard[];
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  CardRole,
3
3
  getCardRole,
4
+ getNormalizedFilterValue,
4
5
  Type
5
6
  } from "@flesh-and-blood/types";
6
7
  import { getCleanText, getNormalizedText } from "./helpers.js";
@@ -34,7 +35,7 @@ const addToCardList = (cardsByKey, key, card) => {
34
35
  cardsByKey.set(key, [card]);
35
36
  }
36
37
  };
37
- const catalogueIndexByCards = /* @__PURE__ */ new WeakMap();
38
+ const catalogueIndexByReleasesByCards = /* @__PURE__ */ new WeakMap();
38
39
  const noCards = Object.freeze([]);
39
40
  const strayCorpusPosition = Number.MAX_SAFE_INTEGER;
40
41
  const getNamingCardsByNamedCardIdentifier = (cards, getNamedCardIdentifiers) => {
@@ -68,7 +69,25 @@ const getCardsByRole = (cards) => {
68
69
  }
69
70
  return cardsByRole;
70
71
  };
71
- const getNewCatalogueIndex = (cards) => {
72
+ const getNewReleaseLookups = (releases) => {
73
+ const releaseByFilterName = /* @__PURE__ */ new Map();
74
+ const releaseByRelease = /* @__PURE__ */ new Map();
75
+ const releaseBySetIdentifier = /* @__PURE__ */ new Map();
76
+ for (const releaseInfo of releases) {
77
+ releaseByFilterName.set(
78
+ getNormalizedFilterValue(releaseInfo.release),
79
+ releaseInfo
80
+ );
81
+ releaseByRelease.set(releaseInfo.release, releaseInfo);
82
+ for (const setIdentifier of releaseInfo.setIdentifiers) {
83
+ releaseBySetIdentifier.set(setIdentifier.toLowerCase(), releaseInfo);
84
+ }
85
+ }
86
+ return { releaseByFilterName, releaseByRelease, releaseBySetIdentifier };
87
+ };
88
+ const getNewCatalogueIndex = (cards, releases) => {
89
+ let releaseLookups;
90
+ const releaseHeroCardsByRelease = /* @__PURE__ */ new Map();
72
91
  let cardLookups;
73
92
  let referencingCardsByCardIdentifier;
74
93
  let creatingCardsByCardIdentifier;
@@ -264,6 +283,28 @@ const getNewCatalogueIndex = (cards) => {
264
283
  }
265
284
  return getCardsInCorpusOrder([...createdCardByCardIdentifier.values()]);
266
285
  };
286
+ const getReleaseLookups = () => {
287
+ if (!releaseLookups) {
288
+ releaseLookups = getNewReleaseLookups(releases);
289
+ }
290
+ return releaseLookups;
291
+ };
292
+ const getRelease = (release) => getReleaseLookups().releaseByRelease.get(release);
293
+ const getReleaseByName = (name) => getReleaseLookups().releaseByFilterName.get(getNormalizedFilterValue(name));
294
+ const getReleaseBySetIdentifier = (setIdentifier) => getReleaseLookups().releaseBySetIdentifier.get(setIdentifier.toLowerCase());
295
+ const getReleaseHeroCards = (release) => {
296
+ let releaseHeroCards = releaseHeroCardsByRelease.get(release);
297
+ if (!releaseHeroCards) {
298
+ const releaseInfo = getRelease(release);
299
+ const heroCards = getNamedCards(releaseInfo?.heroIdentifiers);
300
+ const namesHeroCards = heroCards.length > 0;
301
+ releaseHeroCards = namesHeroCards ? heroCards : noCards;
302
+ if (namesHeroCards) {
303
+ releaseHeroCardsByRelease.set(release, releaseHeroCards);
304
+ }
305
+ }
306
+ return releaseHeroCards;
307
+ };
267
308
  const getByRole = (role) => {
268
309
  if (!cardsByRole) {
269
310
  cardsByRole = getCardsByRole(cards);
@@ -272,7 +313,12 @@ const getNewCatalogueIndex = (cards) => {
272
313
  };
273
314
  return {
274
315
  cards,
316
+ releases,
275
317
  getCard,
318
+ getRelease,
319
+ getReleaseByName,
320
+ getReleaseBySetIdentifier,
321
+ getReleaseHeroCards,
276
322
  getPitchCycle,
277
323
  getCardsByName: getCardsByName2,
278
324
  getCardsByExactName,
@@ -290,11 +336,16 @@ const getNewCatalogueIndex = (cards) => {
290
336
  getCardsInCorpusOrder
291
337
  };
292
338
  };
293
- const getCatalogueIndex = (cards) => {
294
- let catalogueIndex = catalogueIndexByCards.get(cards);
339
+ const getCatalogueIndex = (cards, releases) => {
340
+ let catalogueIndexByReleases = catalogueIndexByReleasesByCards.get(cards);
341
+ if (!catalogueIndexByReleases) {
342
+ catalogueIndexByReleases = /* @__PURE__ */ new WeakMap();
343
+ catalogueIndexByReleasesByCards.set(cards, catalogueIndexByReleases);
344
+ }
345
+ let catalogueIndex = catalogueIndexByReleases.get(releases);
295
346
  if (!catalogueIndex) {
296
- catalogueIndex = getNewCatalogueIndex(cards);
297
- catalogueIndexByCards.set(cards, catalogueIndex);
347
+ catalogueIndex = getNewCatalogueIndex(cards, releases);
348
+ catalogueIndexByReleases.set(releases, catalogueIndex);
298
349
  }
299
350
  return catalogueIndex;
300
351
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@flesh-and-blood/search",
3
3
  "description": "TypeScript search engine for Flesh and Blood cards",
4
- "version": "5.4.0",
4
+ "version": "6.0.1",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "main": "dist/index.cjs",
@@ -13,10 +13,6 @@
13
13
  "import": "./dist/index.js",
14
14
  "require": "./dist/index.cjs"
15
15
  },
16
- "./abbreviations": {
17
- "types": "./dist/abbreviations.d.ts",
18
- "import": "./dist/abbreviations.js"
19
- },
20
16
  "./shorthands": {
21
17
  "types": "./dist/shorthands.d.ts",
22
18
  "import": "./dist/shorthands.js"
@@ -44,11 +40,11 @@
44
40
  "fuse.js": "^7.5.0"
45
41
  },
46
42
  "peerDependencies": {
47
- "@flesh-and-blood/types": "^5.0.0"
43
+ "@flesh-and-blood/types": "^6.0.0"
48
44
  },
49
45
  "devDependencies": {
50
- "@flesh-and-blood/cards": "^5.4.0",
51
- "@flesh-and-blood/types": "^5.3.0",
46
+ "@flesh-and-blood/cards": "^6.0.0",
47
+ "@flesh-and-blood/types": "^6.0.0",
52
48
  "@types/node": "^26.6.3",
53
49
  "esbuild": "^0.28.2",
54
50
  "typescript": "^7.0.2",
@@ -75,5 +71,5 @@
75
71
  "FAB",
76
72
  "FABTCG"
77
73
  ],
78
- "gitHead": "b9859b97493dfa6b6d0990be6b19341ec54a315e"
74
+ "gitHead": "623a6b7c352392a511cc113ae7de3535a8399764"
79
75
  }