@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 +5 -5
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/filterMappings.d.ts +1 -3
- package/dist/filterMappings.js +0 -2
- package/dist/filterResolvers.d.ts +0 -1
- package/dist/filterResolvers.js +18 -30
- package/dist/filters.d.ts +2 -2
- package/dist/filters.js +1 -2
- package/dist/helpers.d.ts +1 -6
- package/dist/helpers.js +3 -2
- package/dist/index.cjs +1 -1
- package/dist/queryParse.d.ts +2 -3
- package/dist/queryParse.js +25 -25
- package/dist/search.d.ts +20 -16
- package/dist/search.js +6 -13
- package/dist/searchIndex.d.ts +19 -8
- package/dist/searchIndex.js +57 -6
- package/package.json +5 -9
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
|
|
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): `
|
|
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
|
package/dist/constants.d.ts
CHANGED
package/dist/constants.js
CHANGED
package/dist/filterMappings.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Bond, Card, Class, Flow, Foiling, Fusion, Hero, Keyword, Meta, Printing, Rarity,
|
|
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;
|
package/dist/filterMappings.js
CHANGED
|
@@ -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
|
package/dist/filterResolvers.js
CHANGED
|
@@ -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
|
|
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
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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, {
|
|
156
|
+
const getSetResolution = (term, { index }) => getVocabularyResolution(
|
|
169
157
|
term,
|
|
170
158
|
"releases",
|
|
171
|
-
(value) => getMatchingReleasesFromValue(value,
|
|
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
|
|
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[],
|
|
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 = [],
|
|
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 {
|
|
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});
|
package/dist/queryParse.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Hero
|
|
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,
|
|
70
|
+
export declare const getParsedQuery: (text: string, index: CatalogueIndex, { additionalHeroes, today }?: ParseOptions) => ParsedQuery;
|
package/dist/queryParse.js
CHANGED
|
@@ -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
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
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 =
|
|
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 (
|
|
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;
|
package/dist/searchIndex.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
73
|
-
* shares its maps. Each map is built the
|
|
74
|
-
*
|
|
75
|
-
*
|
|
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[];
|
package/dist/searchIndex.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
-
|
|
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": "
|
|
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": "^
|
|
43
|
+
"@flesh-and-blood/types": "^6.0.0"
|
|
48
44
|
},
|
|
49
45
|
"devDependencies": {
|
|
50
|
-
"@flesh-and-blood/cards": "^
|
|
51
|
-
"@flesh-and-blood/types": "^
|
|
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": "
|
|
74
|
+
"gitHead": "623a6b7c352392a511cc113ae7de3535a8399764"
|
|
79
75
|
}
|