@flesh-and-blood/search 5.3.1 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/filterMappings.d.ts +30 -12
- package/dist/filterMappings.js +18 -10
- package/dist/filterResolvers.d.ts +0 -1
- package/dist/filterResolvers.js +67 -107
- 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 +24 -12
- package/dist/searchIndex.js +81 -35
- package/package.json +4 -8
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
|
|
@@ -11,9 +11,10 @@ export declare const FilterCategory: {
|
|
|
11
11
|
readonly Artist: "artist";
|
|
12
12
|
readonly Banned: "banned";
|
|
13
13
|
readonly Bond: "bond";
|
|
14
|
-
readonly Chain: "chain";
|
|
15
14
|
readonly Class: "class";
|
|
16
15
|
readonly Cost: "cost";
|
|
16
|
+
readonly CreatedBy: "createdby";
|
|
17
|
+
readonly Creates: "creates";
|
|
17
18
|
readonly Defense: "defense";
|
|
18
19
|
readonly Flow: "flow";
|
|
19
20
|
readonly Foiling: "foiling";
|
|
@@ -168,8 +169,9 @@ export interface FilterToPropertyMapping extends CardPropertyMapping {
|
|
|
168
169
|
* It is not the set of spellings the parse accepts, which is wider, since
|
|
169
170
|
* the foiling, treatment, rarity, legality and meta resolvers each take
|
|
170
171
|
* abbreviations of their own. A filter reading free text (`artist`, `name`,
|
|
171
|
-
* `text`, `typetext`), a card name (`
|
|
172
|
-
* a set identifier (`print`), a date
|
|
172
|
+
* `text`, `typetext`), a card name or group (`creates`, `createdby`,
|
|
173
|
+
* `references`, `referencedby`), a set identifier (`print`), a date
|
|
174
|
+
* (`year`) or a number carries none.
|
|
173
175
|
*/
|
|
174
176
|
vocabulary?: readonly string[];
|
|
175
177
|
}
|
|
@@ -274,12 +276,6 @@ export declare const filtersToCardPropertyMappings: {
|
|
|
274
276
|
isArray: true;
|
|
275
277
|
partialMatch: true;
|
|
276
278
|
};
|
|
277
|
-
chain: {
|
|
278
|
-
category: "chain";
|
|
279
|
-
canonicalAlias: string;
|
|
280
|
-
kind: "partialMatch";
|
|
281
|
-
property: "n/a";
|
|
282
|
-
};
|
|
283
279
|
co: {
|
|
284
280
|
category: "cost";
|
|
285
281
|
canonicalAlias: string;
|
|
@@ -298,6 +294,18 @@ export declare const filtersToCardPropertyMappings: {
|
|
|
298
294
|
isNumber: true;
|
|
299
295
|
partialMatch: true;
|
|
300
296
|
};
|
|
297
|
+
createdby: {
|
|
298
|
+
category: "createdby";
|
|
299
|
+
canonicalAlias: string;
|
|
300
|
+
kind: "partialMatch";
|
|
301
|
+
property: "n/a";
|
|
302
|
+
};
|
|
303
|
+
creates: {
|
|
304
|
+
category: "creates";
|
|
305
|
+
canonicalAlias: string;
|
|
306
|
+
kind: "partialMatch";
|
|
307
|
+
property: "n/a";
|
|
308
|
+
};
|
|
301
309
|
color: {
|
|
302
310
|
category: "pitch";
|
|
303
311
|
canonicalAlias: string;
|
|
@@ -457,6 +465,18 @@ export declare const filtersToCardPropertyMappings: {
|
|
|
457
465
|
specialProperty: "specialLife";
|
|
458
466
|
isNumber: true;
|
|
459
467
|
};
|
|
468
|
+
madeby: {
|
|
469
|
+
category: "createdby";
|
|
470
|
+
canonicalAlias: string;
|
|
471
|
+
kind: "partialMatch";
|
|
472
|
+
property: "n/a";
|
|
473
|
+
};
|
|
474
|
+
makes: {
|
|
475
|
+
category: "creates";
|
|
476
|
+
canonicalAlias: string;
|
|
477
|
+
kind: "partialMatch";
|
|
478
|
+
property: "n/a";
|
|
479
|
+
};
|
|
460
480
|
meta: {
|
|
461
481
|
category: "is";
|
|
462
482
|
canonicalAlias: string;
|
|
@@ -591,7 +611,6 @@ export declare const filtersToCardPropertyMappings: {
|
|
|
591
611
|
category: "set";
|
|
592
612
|
canonicalAlias: string;
|
|
593
613
|
kind: "partialMatch";
|
|
594
|
-
vocabulary: Release[];
|
|
595
614
|
property: "sets";
|
|
596
615
|
isArray: true;
|
|
597
616
|
partialMatch: true;
|
|
@@ -600,7 +619,6 @@ export declare const filtersToCardPropertyMappings: {
|
|
|
600
619
|
category: "set";
|
|
601
620
|
canonicalAlias: string;
|
|
602
621
|
kind: "partialMatch";
|
|
603
|
-
vocabulary: Release[];
|
|
604
622
|
property: "sets";
|
|
605
623
|
isArray: true;
|
|
606
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,
|
|
@@ -23,9 +22,10 @@ const FilterCategory = {
|
|
|
23
22
|
Artist: "artist",
|
|
24
23
|
Banned: "banned",
|
|
25
24
|
Bond: "bond",
|
|
26
|
-
Chain: "chain",
|
|
27
25
|
Class: "class",
|
|
28
26
|
Cost: "cost",
|
|
27
|
+
CreatedBy: "createdby",
|
|
28
|
+
Creates: "creates",
|
|
29
29
|
Defense: "defense",
|
|
30
30
|
Flow: "flow",
|
|
31
31
|
Foiling: "foiling",
|
|
@@ -102,12 +102,6 @@ const bondFilter = {
|
|
|
102
102
|
property: "bonds",
|
|
103
103
|
isArray: true
|
|
104
104
|
};
|
|
105
|
-
const chainFilter = {
|
|
106
|
-
category: FilterCategory.Chain,
|
|
107
|
-
canonicalAlias: "chain",
|
|
108
|
-
kind: FilterKind.PartialMatch,
|
|
109
|
-
property: NO_CARD_PROPERTY
|
|
110
|
-
};
|
|
111
105
|
const classFilter = {
|
|
112
106
|
category: FilterCategory.Class,
|
|
113
107
|
canonicalAlias: "c",
|
|
@@ -126,6 +120,18 @@ const costFilter = {
|
|
|
126
120
|
isNumber: true,
|
|
127
121
|
partialMatch: true
|
|
128
122
|
};
|
|
123
|
+
const createdByFilter = {
|
|
124
|
+
category: FilterCategory.CreatedBy,
|
|
125
|
+
canonicalAlias: "createdby",
|
|
126
|
+
kind: FilterKind.PartialMatch,
|
|
127
|
+
property: NO_CARD_PROPERTY
|
|
128
|
+
};
|
|
129
|
+
const createsFilter = {
|
|
130
|
+
category: FilterCategory.Creates,
|
|
131
|
+
canonicalAlias: "creates",
|
|
132
|
+
kind: FilterKind.PartialMatch,
|
|
133
|
+
property: NO_CARD_PROPERTY
|
|
134
|
+
};
|
|
129
135
|
const defenseFilter = {
|
|
130
136
|
category: FilterCategory.Defense,
|
|
131
137
|
canonicalAlias: "d",
|
|
@@ -254,7 +260,6 @@ const setFilter = {
|
|
|
254
260
|
category: FilterCategory.Set,
|
|
255
261
|
canonicalAlias: "s",
|
|
256
262
|
kind: FilterKind.PartialMatch,
|
|
257
|
-
vocabulary: Object.values(Release),
|
|
258
263
|
property: "sets",
|
|
259
264
|
isArray: true,
|
|
260
265
|
partialMatch: true
|
|
@@ -358,9 +363,10 @@ const filtersToCardPropertyMappings = {
|
|
|
358
363
|
bonds: bondFilter,
|
|
359
364
|
c: classFilter,
|
|
360
365
|
class: classFilter,
|
|
361
|
-
chain: chainFilter,
|
|
362
366
|
co: costFilter,
|
|
363
367
|
cost: costFilter,
|
|
368
|
+
createdby: createdByFilter,
|
|
369
|
+
creates: createsFilter,
|
|
364
370
|
color: pitchFilter,
|
|
365
371
|
d: defenseFilter,
|
|
366
372
|
def: defenseFilter,
|
|
@@ -381,6 +387,8 @@ const filtersToCardPropertyMappings = {
|
|
|
381
387
|
hero: legalFilter,
|
|
382
388
|
li: lifeFilter,
|
|
383
389
|
life: lifeFilter,
|
|
390
|
+
madeby: createdByFilter,
|
|
391
|
+
makes: createsFilter,
|
|
384
392
|
meta: metaFilter,
|
|
385
393
|
n: nameFilter,
|
|
386
394
|
name: nameFilter,
|
package/dist/filterResolvers.js
CHANGED
|
@@ -2,10 +2,7 @@ import {
|
|
|
2
2
|
Foiling,
|
|
3
3
|
Meta,
|
|
4
4
|
Rarity,
|
|
5
|
-
|
|
6
|
-
setIdentifierToSetMappings,
|
|
7
|
-
Treatment,
|
|
8
|
-
Type
|
|
5
|
+
Treatment
|
|
9
6
|
} from "@flesh-and-blood/types";
|
|
10
7
|
import {
|
|
11
8
|
FilterCategory,
|
|
@@ -15,11 +12,6 @@ import {
|
|
|
15
12
|
} from "./filterMappings.js";
|
|
16
13
|
import { getNormalizedFilterValue, getTextWithoutMarkup } from "./helpers.js";
|
|
17
14
|
import { getMetaFilterResolution } from "./metaFilters.js";
|
|
18
|
-
import {
|
|
19
|
-
getCardsByName,
|
|
20
|
-
getCardsReferencedBy,
|
|
21
|
-
getCardsReferencing
|
|
22
|
-
} from "./searchIndex.js";
|
|
23
15
|
const getSharedModifier = (filterValues) => {
|
|
24
16
|
const [firstValue] = filterValues;
|
|
25
17
|
const firstModifier = firstValue?.modifier;
|
|
@@ -133,34 +125,24 @@ const getPitchResolution = (term) => {
|
|
|
133
125
|
unresolvedValues: []
|
|
134
126
|
};
|
|
135
127
|
};
|
|
136
|
-
const
|
|
137
|
-
for (const release of Object.values(Release)) {
|
|
138
|
-
const name = getNormalizedFilterValue(release);
|
|
139
|
-
const releaseWithSameName = releasesByName.get(name);
|
|
140
|
-
if (releaseWithSameName === void 0) {
|
|
141
|
-
releasesByName.set(name, release);
|
|
142
|
-
} else {
|
|
143
|
-
throw new Error(
|
|
144
|
-
`${releaseWithSameName} and ${release} are one name as a filter reads it, so a set filter naming it could reach either`
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
const getReleasesFromLookup = (lookup, value) => {
|
|
149
|
-
const release = lookup.get(value);
|
|
150
|
-
return release ? [release] : [];
|
|
151
|
-
};
|
|
152
|
-
const getMatchingReleasesFromValue = (value, additionalSets) => {
|
|
128
|
+
const getMatchingReleasesFromValue = (value, index) => {
|
|
153
129
|
const rungs = [
|
|
154
|
-
() => getReleasesFromLookup(releasesByName, value),
|
|
155
|
-
() => getReleasesFromLookup(setIdentifierToSetMappings, value),
|
|
156
|
-
() => Object.values(Release).filter(
|
|
157
|
-
(release) => release.toLowerCase().includes(value)
|
|
158
|
-
),
|
|
159
130
|
() => {
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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;
|
|
164
146
|
}
|
|
165
147
|
];
|
|
166
148
|
const releases = [];
|
|
@@ -171,10 +153,10 @@ const getMatchingReleasesFromValue = (value, additionalSets) => {
|
|
|
171
153
|
}
|
|
172
154
|
return releases;
|
|
173
155
|
};
|
|
174
|
-
const getSetResolution = (term, {
|
|
156
|
+
const getSetResolution = (term, { index }) => getVocabularyResolution(
|
|
175
157
|
term,
|
|
176
158
|
"releases",
|
|
177
|
-
(value) => getMatchingReleasesFromValue(value,
|
|
159
|
+
(value) => getMatchingReleasesFromValue(value, index)
|
|
178
160
|
);
|
|
179
161
|
const foilingValuesMapping = new Map(
|
|
180
162
|
Object.entries({
|
|
@@ -401,55 +383,28 @@ const cardIdentifierFilter = {
|
|
|
401
383
|
isString: true,
|
|
402
384
|
isNormalized: true
|
|
403
385
|
};
|
|
404
|
-
const
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
const namesToExpand = /* @__PURE__ */ new Set();
|
|
409
|
-
const unresolvedValues = [];
|
|
410
|
-
const addToChain = (card) => {
|
|
411
|
-
cardIdentifiers.add(card.cardIdentifier);
|
|
412
|
-
if (!namesToExpand.has(card.name)) {
|
|
413
|
-
namesToExpand.add(card.name);
|
|
414
|
-
cardsToExpand.push(card);
|
|
415
|
-
}
|
|
416
|
-
};
|
|
417
|
-
const addRelatedCardToChain = (card) => {
|
|
418
|
-
if (!card.types.includes(Type.Hero)) {
|
|
419
|
-
addToChain(card);
|
|
420
|
-
}
|
|
421
|
-
};
|
|
422
|
-
for (const name of names) {
|
|
423
|
-
const seedCards = getCardsByName(index, name);
|
|
424
|
-
for (const seedCard of seedCards) {
|
|
425
|
-
addToChain(seedCard);
|
|
426
|
-
}
|
|
427
|
-
if (seedCards.length === 0) {
|
|
428
|
-
unresolvedValues.push(name);
|
|
429
|
-
}
|
|
386
|
+
const getCardsByNameOrGroup = (index, value) => {
|
|
387
|
+
let cards = index.getCardsByExactName(value);
|
|
388
|
+
if (cards.length === 0) {
|
|
389
|
+
cards = index.getCardsByGroup(value);
|
|
430
390
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
const cardToExpand = cardsToExpand[expansions];
|
|
434
|
-
for (const referencedCard of getCardsReferencedBy(index, cardToExpand)) {
|
|
435
|
-
addRelatedCardToChain(referencedCard);
|
|
436
|
-
}
|
|
437
|
-
const isSeed = expansions === 0;
|
|
438
|
-
if (isSeed) {
|
|
439
|
-
for (const referencingCard of getCardsReferencing(index, cardToExpand)) {
|
|
440
|
-
addRelatedCardToChain(referencingCard);
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
expansions++;
|
|
391
|
+
if (cards.length === 0) {
|
|
392
|
+
cards = index.getCardsByName(value);
|
|
444
393
|
}
|
|
445
|
-
return
|
|
394
|
+
return cards;
|
|
446
395
|
};
|
|
447
|
-
const getRelatedCardIdentifiers = (index,
|
|
396
|
+
const getRelatedCardIdentifiers = (index, value, readRelation) => {
|
|
448
397
|
const relatedCardIdentifiers = /* @__PURE__ */ new Set();
|
|
449
|
-
for (const
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
|
|
398
|
+
for (const card of getCardsByNameOrGroup(index, value)) {
|
|
399
|
+
for (const relatedCard of readRelation(index, card.cardIdentifier)) {
|
|
400
|
+
const isCycleAdded = relatedCardIdentifiers.has(
|
|
401
|
+
relatedCard.cardIdentifier
|
|
402
|
+
);
|
|
403
|
+
if (!isCycleAdded) {
|
|
404
|
+
for (const pitch of index.getPitchCycle(relatedCard.cardIdentifier)) {
|
|
405
|
+
relatedCardIdentifiers.add(pitch.cardIdentifier);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
453
408
|
}
|
|
454
409
|
}
|
|
455
410
|
return relatedCardIdentifiers;
|
|
@@ -482,11 +437,15 @@ const getCardIdentifiersFilter = (cardIdentifiers, isExcluded) => ({
|
|
|
482
437
|
isExcluded,
|
|
483
438
|
isOr: true
|
|
484
439
|
});
|
|
485
|
-
const
|
|
440
|
+
const getRelationResolver = (readRelation) => ({ filterValues, isAnd, isExcluded }, { index }) => {
|
|
486
441
|
const cardIdentifiersByValue = [];
|
|
487
442
|
const unresolvedValues = [];
|
|
488
443
|
for (const { value } of filterValues) {
|
|
489
|
-
const cardIdentifiers =
|
|
444
|
+
const cardIdentifiers = getRelatedCardIdentifiers(
|
|
445
|
+
index,
|
|
446
|
+
value,
|
|
447
|
+
readRelation
|
|
448
|
+
);
|
|
490
449
|
cardIdentifiersByValue.push(cardIdentifiers);
|
|
491
450
|
if (cardIdentifiers.size === 0) {
|
|
492
451
|
unresolvedValues.push(value);
|
|
@@ -502,38 +461,39 @@ const getRelationResolution = ({ filterValues, isAnd, isExcluded }, getCardIdent
|
|
|
502
461
|
unresolvedValues
|
|
503
462
|
};
|
|
504
463
|
};
|
|
505
|
-
const getChainResolution = (term, { index }) => {
|
|
506
|
-
const { cardIdentifiers, unresolvedValues } = getChainedCardIdentifiers(
|
|
507
|
-
index,
|
|
508
|
-
term.filterValues.map(({ value }) => value)
|
|
509
|
-
);
|
|
510
|
-
return {
|
|
511
|
-
appliedFilters: [
|
|
512
|
-
getCardIdentifiersFilter(cardIdentifiers, term.isExcluded)
|
|
513
|
-
],
|
|
514
|
-
unresolvedValues
|
|
515
|
-
};
|
|
516
|
-
};
|
|
517
|
-
const getReferencedByResolution = (term, { index }) => getRelationResolution(
|
|
518
|
-
term,
|
|
519
|
-
(value) => getRelatedCardIdentifiers(index, value, true)
|
|
520
|
-
);
|
|
521
|
-
const getReferencesResolution = (term, { index }) => getRelationResolution(
|
|
522
|
-
term,
|
|
523
|
-
(value) => getRelatedCardIdentifiers(index, value, false)
|
|
524
|
-
);
|
|
525
464
|
const resolverByFilterCategory = /* @__PURE__ */ new Map([
|
|
526
465
|
[FilterCategory.Artist, getArtistResolution],
|
|
527
466
|
[FilterCategory.Banned, getLegalityResolution],
|
|
528
|
-
[
|
|
467
|
+
[
|
|
468
|
+
FilterCategory.CreatedBy,
|
|
469
|
+
getRelationResolver(
|
|
470
|
+
(index, cardIdentifier) => index.getCreates(cardIdentifier)
|
|
471
|
+
)
|
|
472
|
+
],
|
|
473
|
+
[
|
|
474
|
+
FilterCategory.Creates,
|
|
475
|
+
getRelationResolver(
|
|
476
|
+
(index, cardIdentifier) => index.getCreatedBy(cardIdentifier)
|
|
477
|
+
)
|
|
478
|
+
],
|
|
529
479
|
[FilterCategory.Foiling, getFoilingResolution],
|
|
530
480
|
[FilterCategory.Is, getMetaResolution],
|
|
531
481
|
[FilterCategory.Legal, getLegalityResolution],
|
|
532
482
|
[FilterCategory.Pitch, getPitchResolution],
|
|
533
483
|
[FilterCategory.Print, getPrintResolution],
|
|
534
484
|
[FilterCategory.Rarity, getRarityResolution],
|
|
535
|
-
[
|
|
536
|
-
|
|
485
|
+
[
|
|
486
|
+
FilterCategory.ReferencedBy,
|
|
487
|
+
getRelationResolver(
|
|
488
|
+
(index, cardIdentifier) => index.getReferences(cardIdentifier)
|
|
489
|
+
)
|
|
490
|
+
],
|
|
491
|
+
[
|
|
492
|
+
FilterCategory.References,
|
|
493
|
+
getRelationResolver(
|
|
494
|
+
(index, cardIdentifier) => index.getReferencedBy(cardIdentifier)
|
|
495
|
+
)
|
|
496
|
+
],
|
|
537
497
|
[FilterCategory.Set, getSetResolution],
|
|
538
498
|
[FilterCategory.Treatment, getTreatmentResolution]
|
|
539
499
|
]);
|
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 Kt=Object.create;var le=Object.defineProperty;var _t=Object.getOwnPropertyDescriptor;var $t=Object.getOwnPropertyNames;var zt=Object.getPrototypeOf,Gt=Object.prototype.hasOwnProperty;var Wt=(e,t)=>{for(var r in t)le(e,r,{get:t[r],enumerable:!0})},Ye=(e,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of $t(t))!Gt.call(e,a)&&a!==r&&le(e,a,{get:()=>t[a],enumerable:!(s=_t(t,a))||s.enumerable});return e};var Yt=(e,t,r)=>(r=e!=null?Kt(zt(e)):{},Ye(t||!e||!e.__esModule?le(r,"default",{value:e,enumerable:!0}):r,e)),qt=e=>Ye(le({},"__esModule",{value:!0}),e);var Ls={};Wt(Ls,{FilterCategory:()=>l,FilterKind:()=>m,FilterProperty:()=>G,MARKUP:()=>Me,NO_CARD_PROPERTY:()=>K,PUNCTUATION:()=>k,RARITY_VALUES_MAPPING:()=>De,aliasesByFilterCategory:()=>J,availableExclusions:()=>_,availableModifiers:()=>Se,default:()=>Ht,filterCard:()=>jt,filtersToCardPropertyMappings:()=>Z,getCardsByName:()=>ye,getCardsReferencedBy:()=>Ce,getCardsReferencing:()=>me,getCatalogueIndex:()=>we,getCleanText:()=>B,getEscapedForRegExp:()=>X,getExcludedMetaFilters:()=>Ie,getFilterCategory:()=>re,getFilterMapping:()=>ge,getFilterTokenSpansForKey:()=>us,getFilterValue:()=>je,getIncompleteFilterToken:()=>He,getIsExcludedToken:()=>ps,getIsValueInFilterVocabulary:()=>ke,getKeywordsAndAppliedFiltersFromText:()=>Bs,getMetaFilterResolution:()=>se,getMetaFilters:()=>fr,getNormalizedFilterValue:()=>V,getNormalizedText:()=>z,getParsedQuery:()=>ie,getQueryFilterToken:()=>Fe,getQueryTokenSpans:()=>he,getQuotedValue:()=>fs,getResolvedFilterKey:()=>Qe,getSuggestedFilterKey:()=>Ve,getTextWithoutMarkup:()=>q,getTokensReferencedByCards:()=>Os,getUnquotedValue:()=>Te,getValuePartsFromFilterValue:()=>Ot,getValuesFromFilterValue:()=>Ue,multiWordShorthands:()=>_e,shorthands:()=>Ke,singleWordShorthands:()=>$e});module.exports=qt(Ls);var xe=require("@flesh-and-blood/types"),We=Yt(require("fuse.js"),1);var k=/[!"#$%&'’(),./:;<=>?@[\]^_`|~]/g,Me=/\*/g;var T=require("@flesh-and-blood/types");var B=e=>z(e.toLowerCase().trim().replace(k,"")),z=e=>e.normalize("NFD").replace(/\p{Diacritic}/gu,""),V=e=>e.toLowerCase().replace(k,""),q=e=>e.replace(Me,""),X=e=>e.replace(/[.*+?^${}()|[\]\\-]/g,"\\$&");var l={Arcane:"arcane",Artist:"artist",Banned:"banned",Bond:"bond",Chain:"chain",Class:"class",Cost:"cost",Defense:"defense",Flow:"flow",Foiling:"foiling",Fusion:"fusion",Intellect:"intellect",Is:"is",Keyword:"keyword",Legal:"legal",Life:"life",Name:"name",Pitch:"pitch",Power:"power",Print:"print",Rarity:"rarity",ReferencedBy:"referencedby",References:"references",Set:"set",Shorthand:"shorthand",Specialization:"specialization",Subtype:"subtype",Talent:"talent",Text:"text",Trait:"trait",Treatment:"treatment",Type:"type",TypeText:"typetext",Year:"year"},m={Comparator:"comparator",ExactMatch:"exactMatch",PartialMatch:"partialMatch"},Se=[">=",">","<=","<"],_=["!","-"],K="n/a",gt=[...Object.values(T.Format),...Object.values(T.Hero)],Xt={category:l.Arcane,canonicalAlias:"arcane",kind:m.Comparator,property:"arcane",specialProperty:"specialArcane",isNumber:!0,partialMatch:!0},be={category:l.Artist,canonicalAlias:"art",kind:m.PartialMatch,property:"artists",isArray:!0,partialMatch:!0},qe={category:l.Banned,canonicalAlias:"banned",kind:m.ExactMatch,vocabulary:gt,property:K,isMeta:!0},Xe={category:l.Bond,canonicalAlias:"bond",kind:m.ExactMatch,vocabulary:Object.values(T.Bond),property:"bonds",isArray:!0},Zt={category:l.Chain,canonicalAlias:"chain",kind:m.PartialMatch,property:K},Ze={category:l.Class,canonicalAlias:"c",kind:m.PartialMatch,vocabulary:Object.values(T.Class),property:"classes",isArray:!0,partialMatch:!0},Je={category:l.Cost,canonicalAlias:"co",kind:m.Comparator,property:"cost",specialProperty:"specialCost",isNumber:!0,partialMatch:!0},te={category:l.Defense,canonicalAlias:"d",kind:m.Comparator,property:"defense",specialProperty:"specialDefense",isNumber:!0},et={category:l.Flow,canonicalAlias:"flow",kind:m.ExactMatch,vocabulary:Object.values(T.Flow),property:"flows",isArray:!0},tt={category:l.Foiling,canonicalAlias:"foil",kind:m.ExactMatch,vocabulary:Object.values(T.Foiling),nestedProperty:"foiling",property:"printings",isArray:!0},rt={category:l.Fusion,canonicalAlias:"f",kind:m.ExactMatch,vocabulary:Object.values(T.Fusion),property:"fusions",isArray:!0},st={category:l.Intellect,canonicalAlias:"i",kind:m.Comparator,property:"intellect",isNumber:!0},at={category:l.Keyword,canonicalAlias:"k",kind:m.ExactMatch,vocabulary:Object.values(T.Keyword),property:"keywords",isArray:!0},Ae={category:l.Legal,canonicalAlias:"l",kind:m.ExactMatch,vocabulary:gt,property:K,isMeta:!0},it={category:l.Life,canonicalAlias:"li",kind:m.Comparator,property:"life",specialProperty:"specialLife",isNumber:!0},nt={category:l.Is,canonicalAlias:"is",kind:m.ExactMatch,vocabulary:Object.values(T.Meta),property:"meta",isArray:!0},ot={category:l.Name,canonicalAlias:"name",kind:m.PartialMatch,property:"name",isString:!0,partialMatch:!0},Pe={category:l.Pitch,canonicalAlias:"p",kind:m.Comparator,property:"pitch",isNumber:!0},de={category:l.Power,canonicalAlias:"pwr",kind:m.Comparator,property:"power",specialProperty:"specialPower",isNumber:!0},ce={category:l.Print,canonicalAlias:"print",kind:m.PartialMatch,property:"setIdentifiers",isArray:!0,partialMatch:!0},lt={category:l.Rarity,canonicalAlias:"r",kind:m.ExactMatch,vocabulary:Object.values(T.Rarity),property:K,isMeta:!0},Jt={category:l.ReferencedBy,canonicalAlias:"referencedby",kind:m.PartialMatch,property:K},er={category:l.References,canonicalAlias:"references",kind:m.PartialMatch,property:K},dt={category:l.Set,canonicalAlias:"s",kind:m.PartialMatch,vocabulary:Object.values(T.Release),property:"sets",isArray:!0,partialMatch:!0},ve={category:l.Shorthand,canonicalAlias:"short",kind:m.PartialMatch,vocabulary:Object.values(T.Shorthand),property:"shorthands",isArray:!0,partialMatch:!0},pe={category:l.Specialization,canonicalAlias:"sp",kind:m.PartialMatch,vocabulary:Object.values(T.Hero),property:"specializations",isArray:!0,partialMatch:!0},ct={category:l.Subtype,canonicalAlias:"st",kind:m.ExactMatch,vocabulary:Object.values(T.Subtype),property:"subtypes",isArray:!0},pt={category:l.Type,canonicalAlias:"t",kind:m.ExactMatch,vocabulary:Object.values(T.Type),property:"types",isArray:!0},Re={category:l.Talent,canonicalAlias:"tal",kind:m.ExactMatch,vocabulary:Object.values(T.Talent),property:"talents",isArray:!0},tr={category:l.Text,canonicalAlias:"text",kind:m.PartialMatch,property:"functionalText",hasMarkup:!0,isString:!0,partialMatch:!0},rr={category:l.Trait,canonicalAlias:"trait",kind:m.PartialMatch,vocabulary:Object.values(T.Trait),property:"traits",isArray:!0,partialMatch:!0},ut={category:l.TypeText,canonicalAlias:"x",kind:m.PartialMatch,property:"typeText",isString:!0,partialMatch:!0},ue={category:l.Treatment,canonicalAlias:"treatment",kind:m.ExactMatch,vocabulary:Object.values(T.Treatment),nestedProperty:"treatments",property:"printings",isArray:!0,isNestedPropertyArray:!0},sr={category:l.Year,canonicalAlias:"year",kind:m.PartialMatch,property:"firstReleaseDate",isString:!0,partialMatch:!0},Z={arcane:Xt,a:be,artist:be,art:be,attack:de,b:te,block:te,banned:qe,bond:Xe,bonds:Xe,c:Ze,class:Ze,chain:Zt,co:Je,cost:Je,color:Pe,d:te,def:te,defense:te,flow:et,flows:et,f:rt,fusion:rt,foil:tt,foiling:tt,i:st,intellect:st,is:nt,k:at,keyword:at,l:Ae,legal:Ae,hero:Ae,li:it,life:it,meta:nt,n:ot,name:ot,p:Pe,pitch:Pe,pwr:de,pow:de,power:de,print:ce,printing:ce,printings:ce,prints:ce,r:lt,rarity:lt,referencedby:Jt,references:er,rf:qe,s:dt,set:dt,short:ve,shorthand:ve,shorthands:ve,sp:pe,spec:pe,specialization:pe,specializations:pe,st:ct,subtype:ct,t:pt,type:pt,tal:Re,talent:Re,talents:Re,text:tr,trait:rr,treat:ue,treatment:ue,var:ue,variation:ue,x:ut,typetext:ut,year:sr},ar=new Map(Object.entries(Z)),ge=e=>ar.get(e.toLowerCase()),re=e=>ge(e)?.category,ir=()=>{let e=Object.create(null);for(let[t,{category:r}]of Object.entries(Z)){let s=e[r];s?s.push(t):e[r]=[t]}return e},J=ir(),nr=()=>{let e=new Map,t=new Set,r=Object.values(Z);for(let s of r){let{vocabulary:a}=s;if(a&&!t.has(s)){t.add(s);for(let i of a){let n=V(i),o=e.get(n);o?o.push(s):e.set(n,[s])}}}return e},ft=nr(),ke=(e,t)=>!!ft.get(V(t))?.some(r=>r.category===e),or=(e,t)=>{let r=[],s=!0;for(let a of t){let i=(ft.get(V(a))||[]).filter(n=>n.category!==e);r=s?i:r.filter(n=>i.includes(n)),s=!1}return r},Ve=(e,t)=>{let r=or(e,t),[s]=r;return r.length===1?s.canonicalAlias:void 0};var ae=require("@flesh-and-blood/types");var d=require("@flesh-and-blood/types");var E=require("@flesh-and-blood/types");var G={BannedFormats:"bannedFormats",LegalFormats:"legalFormats",LegalHeroes:"legalHeroes"},fe=Array.from(Array(50).keys()).map(e=>`${e}`),lr=[{format:E.Format.ClassicConstructed,nicknames:["cc","classic"]},{format:E.Format.LivingLegend,nicknames:["cc ll","classic constructed ll","ll cc","ll","living legend"]},{format:E.Format.SilverAge,nicknames:["sage"]},{format:E.Format.GoldenAge,nicknames:["gage"]},{format:E.Format.UltimatePitFight,nicknames:["upf"]}],dr=Object.values(E.Format).map(e=>{let t=lr.find(({format:s})=>s===e),r=e.toLowerCase().replaceAll(k,"");return t?{...t,format:r}:{format:r}}),cr=Object.values(E.Hero).map(B),yt=e=>e.replaceAll(" ",""),pr=(e,t)=>{let r=yt(e),s,a=[];for(let n of t){let o=yt(n);o===r?s=n:o.startsWith(r)&&a.push(n)}let i=a.length===1;return s??(i?a[0]:void 0)},mt=["common","rare","super rare","majestic","legendary","fabled"],ur=({modifier:e,value:t})=>{let r=[],s=e==="<"||e==="<=",a=e===">="||e==="<=",i=s?[...mt].reverse():mt,n=!1;for(let o of i)n?r.push(o):o===t&&(n=!0,a&&r.push(o));return r},gr=(e,t)=>{let r=[];for(let s of e)s.modifier?r.push(...ur(s)):r.push(s.value);return{filterToPropertyMapping:{nestedProperty:"rarity",property:"printings",isArray:!0},isExcluded:t,isOr:!0,values:r}},Ct=(e,t,r,s)=>{let a=new Set([...cr,...r.map(B)]),i=[],n=[],o=[],c=[];for(let{value:p}of e){let g=dr.find(({format:f,nicknames:C})=>f===p||!!C&&C.includes(p));if(g)n.push(g.format);else{let f=pr(p,a);f?o.push(f):c.push(p)}}return n.length>0&&i.push({filterToPropertyMapping:{property:s,isArray:!0},values:n,isOr:!0,isExcluded:t}),o.length>0&&i.push({filterToPropertyMapping:{property:G.LegalHeroes,isArray:!0},values:o,isOr:!0,isExcluded:t}),{appliedFilters:i,unresolvedValues:c}},se=(e,t,{additionalHeroes:r=[],isExcluded:s=!1}={})=>{let a=re(e),i={appliedFilters:[],unresolvedValues:[]};return a===l.Legal?i=Ct(t,s,r,G.LegalFormats):a===l.Banned?i=Ct(t,s,r,G.BannedFormats):a===l.Rarity&&(i={appliedFilters:[gr(t,s)],unresolvedValues:[]}),i},fr=(e,t,r,s,a,i)=>se(r,s.map(n=>({modifier:a,value:n})),{additionalHeroes:i,isExcluded:e}).appliedFilters,yr=[{filterToPropertyMapping:{property:"cost",isNumber:!0},isExcluded:!0,values:fe},{filterToPropertyMapping:{property:"specialCost",isString:!0,partialMatch:!0},isExcluded:!0,values:["*","x"]},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["equipment","hero","placeholder","token","weapon"]}],mr=[{filterToPropertyMapping:{property:"defense",isNumber:!0},isExcluded:!0,values:fe},{filterToPropertyMapping:{property:"specialDefense",isString:!0,partialMatch:!0},isExcluded:!0,values:["*","x"]},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["hero","placeholder","token","weapon"]}],Cr=[{filterToPropertyMapping:{property:"pitch",isNumber:!0},isExcluded:!0,values:fe},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["equipment","hero","placeholder","token","weapon"]},{filterToPropertyMapping:{property:"isCardBack",isBoolean:!0},isExcluded:!0,values:["true"]}],hr=[{filterToPropertyMapping:{property:"power",isNumber:!0},isExcluded:!0,values:fe},{filterToPropertyMapping:{property:"specialPower",isString:!0,partialMatch:!0},isExcluded:!0,values:["*","x"]},{filterToPropertyMapping:{property:"types",isArray:!0,partialMatch:!0},isExcluded:!0,values:["equipment","hero","placeholder","token"]}],Fr=[{filterToPropertyMapping:{property:"talents",isArray:!0},isExcluded:!0,values:Object.values(E.Talent).map(e=>e.toLowerCase())}],Tr=[{filterToPropertyMapping:{property:"classes",isArray:!0},isExcluded:!0,values:Object.values(E.Class).map(e=>e.toLowerCase())}],xr=[{category:l.Class,filters:Tr},{category:l.Cost,filters:yr},{category:l.Defense,filters:mr},{category:l.Pitch,filters:Cr},{category:l.Power,filters:hr},{category:l.Talent,filters:Fr}],Mr=()=>{let e=new Map;for(let{category:t,filters:r}of xr)for(let s of J[t])for(let a of _)e.set(`${a}${s}`,r);return e},br=Mr(),Ie=e=>{let t=[],r=br.get(e);return r&&t.push(...r),t};var W=require("@flesh-and-blood/types");var Ar=3,Pr=e=>{let t=z(e.toLowerCase()).replace(/[^a-z\s-]/g,""),r=new Set;for(let s of[/[\s-]+/,/\s+/]){let a="";for(let i of t.split(s)){let n=i.replaceAll("-","");n&&(a+=n[0])}a.length>=Ar&&r.add(a)}return[...r]},ht=e=>B(e).replaceAll("-",""),Ft=(e,t,r)=>{let s=e.get(t);s?s.push(r):e.set(t,[r])},Tt=new WeakMap,j=Object.freeze([]),vr=Number.MAX_SAFE_INTEGER,xt=(e,t)=>{let r=new Map;for(let s of e)for(let a of t(s)||[]){let i=r.get(a);i?i.push(s):r.set(a,[s])}return r},Rr=e=>{let t=new Map;for(let r of e){let s=r.types.includes(W.Type.Hero)&&!r.isCardBack,a=s?W.CardRole.Hero:(0,W.getCardRole)(r);if(s||a!==W.CardRole.Hero){let n=t.get(a);n?n.push(r):t.set(a,[r])}}return t},Sr=e=>{let t,r,s,a,i,n,o,c=()=>{if(!t){let u=new Map,y=new Map,h=[],F=new Map,M=0;for(let w of e){u.set(w.cardIdentifier,w),y.set(w.cardIdentifier,M),M++;let S=B(w.name),Y=F.get(S);Y?Y.push(w):(F.set(S,[w]),h.push(S))}t={cardByCardIdentifier:u,corpusPositionByCardIdentifier:y,cleanedNames:h,pitchCycleByCleanedName:F}}return t},p=u=>{let{corpusPositionByCardIdentifier:y}=c(),h=({cardIdentifier:F})=>y.get(F)??vr;return[...u].sort((F,M)=>h(F)-h(M))},g=u=>c().cardByCardIdentifier.get(u),f=u=>{let{cardByCardIdentifier:y}=c(),h=[];for(let F of u||[]){let M=y.get(F);M&&h.push(M)}return p(h)},C=u=>{let y=new Map;return h=>{let F=y.get(h);if(!F){let M=g(h),w=f(M&&u(M)),S=w.length>0;F=S?w:j,S&&y.set(h,F)}return F}},b=u=>{let{pitchCycleByCleanedName:y}=c(),h=g(u);return h?y.get(B(h.name))??j:j},D=u=>{let{cleanedNames:y,pitchCycleByCleanedName:h}=c(),F=B(u),M=h.get(F);if(!M&&F.length>0){let S=y.find(Y=>Y.includes(F));S&&(M=h.get(S))}return M??j},I=u=>{let{pitchCycleByCleanedName:y}=c();return y.get(B(u))??j},P=u=>{if(!n){n=new Map;for(let y of e)for(let h of y.nicknames??[])Ft(n,ht(h),y)}return n.get(ht(u))??j},O=u=>{if(!o){o=new Map;for(let y of e)for(let h of Pr(y.name))Ft(o,h,y)}return o.get(u)??j},N=()=>{if(!i){let u=new Set;for(let y of e)for(let h of y.artists)u.add(h);i=[...u].sort((y,h)=>y.localeCompare(h,"en",{sensitivity:"base"}))}return i},Q=C(({oppositeSideCardIdentifiers:u})=>u),U=C(({referencedCards:u})=>u),$=u=>(r||(r=xt(e,({referencedCards:y})=>y)),r.get(u)??j),H=C(({createdExtras:u})=>u);return{cards:e,getCard:g,getPitchCycle:b,getCardsByName:D,getCardsByExactName:I,getCardsByNickname:P,getCardsByInitials:O,getArtists:N,getOppositeSide:Q,getReferences:U,getReferencedBy:$,getCreates:H,getCreatedBy:u=>(s||(s=xt(e,({createdExtras:y})=>y)),s.get(u)??j),getCreatedClosure:u=>{let y=new Map,h=new Set,F=[...u];for(let M of F)if(!h.has(M)){h.add(M);for(let S of H(M))y.set(S.cardIdentifier,S),F.push(S.cardIdentifier)}return p([...y.values()])},getByRole:u=>(a||(a=Rr(e)),a.get(u)??j),getCardsInCorpusOrder:p}},we=e=>{let t=Tt.get(e);return t||(t=Sr(e),Tt.set(e,t)),t},Ee=(e,t)=>e.getPitchCycle(t.cardIdentifier),ye=(e,t)=>e.getCardsByName(t),Mt=(e,t)=>{let r=new Map;for(let s of t)for(let a of Ee(e,s))r.set(a.cardIdentifier,a);return e.getCardsInCorpusOrder([...r.values()])},me=(e,t)=>{let r=[];for(let s of Ee(e,t))r.push(...e.getReferencedBy(s.cardIdentifier));return Mt(e,r)},Ce=(e,t)=>{let r=[];for(let s of Ee(e,t))r.push(...e.getReferences(s.cardIdentifier));return Mt(e,r)};var kr=e=>{let[t]=e,r=t?.modifier;return e.every(({modifier:a})=>a===r)?r:void 0},Be=({filterValues:e,isAnd:t,isExcluded:r,mapping:s})=>{let a=[];for(let{value:i}of e)a.push(s.hasMarkup?q(i):i);return{filterToPropertyMapping:s,filterValues:e,isAnd:t,isExcluded:r,isOr:!t&&a.length>1,modifier:kr(e),values:a}},vt=({isAnd:e,isExcluded:t,mapping:r},s)=>({filterToPropertyMapping:r,isAnd:e,isExcluded:t,isOr:!e&&s.length>1,values:s}),Vr=({category:e,filterValues:t,mapping:r})=>{let s=[];if(r.kind===m.ExactMatch&&!!r.vocabulary)for(let{value:i}of t)ke(e,i)||s.push(i);return s},Ir=e=>({appliedFilters:[Be(e)],unresolvedValues:Vr(e)}),Oe=({isExcluded:e},t,r)=>e?void 0:{[t]:r},Rt=(e,t)=>({appliedFilters:[Be(e)],attributes:Oe(e,t,e.filterValues.map(({value:r})=>r)),unresolvedValues:[]}),wr=e=>Rt(e,"artists"),Er=e=>Rt(e,"prints"),Le=(e,t,r)=>{let s=[],a=[],i=[];for(let{value:n}of e.filterValues){let o=r(n);if(o.length>0)for(let c of o)s.push(c),a.push(V(c));else i.push(n)}return{appliedFilters:[vt(e,a)],attributes:Oe(e,t,s),canonicalValues:a,unresolvedValues:i}},Nr=new Map(Object.entries({purple:4,blue:3,yellow:2,red:1,white:0})),Br=e=>{let t=[],r=[];for(let{modifier:s,value:a}of e.filterValues){let i=Nr.get(a),n=i===void 0?a:`${i}`;t.push({modifier:s,value:n}),r.push(n)}return{appliedFilters:[Be({...e,filterValues:t})],canonicalValues:r,unresolvedValues:[]}},Ne=new Map;for(let e of Object.values(d.Release)){let t=V(e),r=Ne.get(t);if(r===void 0)Ne.set(t,e);else throw new Error(`${r} and ${e} are one name as a filter reads it, so a set filter naming it could reach either`)}var bt=(e,t)=>{let r=e.get(t);return r?[r]:[]},Or=(e,t)=>{let r=[()=>bt(Ne,e),()=>bt(d.setIdentifierToSetMappings,e),()=>Object.values(d.Release).filter(a=>a.toLowerCase().includes(e)),()=>{let a=t.find(i=>V(i)===e);return a?[a]:[]}],s=[];for(let a of r)s.length===0&&s.push(...a());return s},Lr=(e,{additionalSets:t})=>Le(e,"releases",r=>Or(r,t)),Dr=new Map(Object.entries({r:d.Foiling.Rainbow,rf:d.Foiling.Rainbow,rainbow:d.Foiling.Rainbow,c:d.Foiling.Cold,cf:d.Foiling.Cold,cold:d.Foiling.Cold,g:d.Foiling.Gold,gf:d.Foiling.Gold,gold:d.Foiling.Gold})),Qr=e=>{let t=Dr.get(e);return t?[t]:[]},Hr=e=>Le(e,"foilings",Qr),St=new Map(Object.entries({aa:d.Treatment.AA,alt:d.Treatment.AA,"alt art":d.Treatment.AA,ab:d.Treatment.AB,"alt border":d.Treatment.AB,at:d.Treatment.AT,"alt text":d.Treatment.AT,ea:d.Treatment.EA,extended:d.Treatment.EA,"extended art":d.Treatment.EA,fa:d.Treatment.FA,full:d.Treatment.FA,"full art":d.Treatment.FA}));for(let e of Object.values(d.Treatment))St.set(e.toLowerCase(),e);var jr=new Map(Object.entries(d.Treatment)),Ur=e=>{let t=St.get(e)||jr.get(e.toUpperCase());return t?[t]:[]},Kr=e=>Le(e,"treatments",Ur),De=new Map(Object.entries({b:d.Rarity.Basic,c:d.Rarity.Common,f:d.Rarity.Fabled,l:d.Rarity.Legendary,m:d.Rarity.Majestic,p:d.Rarity.Promo,r:d.Rarity.Rare,s:d.Rarity.SuperRare,t:d.Rarity.Token,v:d.Rarity.Marvel})),_r=e=>De.get(e)||Object.values(d.Rarity).find(t=>t.toLowerCase()===e),$r=(e,{additionalHeroes:t})=>{let r=[],s=[],a=[],i=[];for(let{modifier:o,value:c}of e.filterValues){let p=_r(c);p?(r.push(p),s.push(p.toLowerCase()),a.push({modifier:o,value:p.toLowerCase()})):(i.push(c),a.push({modifier:o,value:c}))}let{appliedFilters:n}=se(e.key,a,{additionalHeroes:t,isExcluded:e.isExcluded});return{appliedFilters:n,attributes:Oe(e,"rarities",r),canonicalValues:s,unresolvedValues:i}},At=({filterValues:e,isExcluded:t,key:r},{additionalHeroes:s})=>{let{appliedFilters:a,unresolvedValues:i}=se(r,e,{additionalHeroes:s,isExcluded:t}),n=[];for(let{values:o}of a)n.push(...o);return{appliedFilters:a,canonicalValues:n,unresolvedValues:i}},zr=["unique"],Gr=["preview","spoiler","unreleased"],Wr=["released"],Pt={property:"firstReleaseDate",isDate:!0},Yr=new Map(Object.entries({dual:d.Meta.DualClass,exp:d.Meta.Expansion,expansion:d.Meta.Expansion,rainbow:d.Meta.Rainbow,reprint:d.Meta.Reprint,reprints:d.Meta.Reprint})),qr=e=>{let t=[],r=[];for(let a of e){let i=Yr.get(a);i?t.push(i):r.push(a)}let s=[];if(t.length===0){let a=new Set;for(let i of Object.values(d.Meta)){let n=!1;for(let o of r)i.toLowerCase().includes(o)&&(n=!0,a.add(o));n&&t.push(i)}for(let i of r)a.has(i)||s.push(i)}else s.push(...r);return{unresolvedValues:s,values:t}},Xr=(e,{today:t})=>{let{filterValues:r,isAnd:s,isExcluded:a}=e,i=[],n=[],o=[],c=[],p=[];for(let{value:P}of r)zr.includes(P)?n.push(P):Gr.includes(P)?o.push(P):Wr.includes(P)?c.push(P):p.push(P);let g=!s&&r.length>1;n.length>0&&i.push({filterToPropertyMapping:Z.is,values:[V(d.Meta.Reprint)],isAnd:s,isOr:g,isExcluded:!a}),o.length>0&&i.push({filterToPropertyMapping:Pt,values:[t],isAnd:s,isOr:g,isExcluded:a}),c.length>0&&i.push({filterToPropertyMapping:Pt,values:[t],isAnd:s,isOr:g,isExcluded:!a});let{unresolvedValues:f,values:C}=qr(p),b=[...n,...o,...c,...C.map(V)];(p.length>0||i.length===0)&&i.push(vt(e,C.map(V)));let I=C.includes(d.Meta.Expansion)&&!a;return{appliedFilters:i,attributes:I?{isExpansionSlot:I}:void 0,canonicalValues:b,unresolvedValues:f}},Zr={property:"cardIdentifier",isString:!0,isNormalized:!0},Jr=20,es=(e,t)=>{let r=new Set,s=[],a=new Set,i=[],n=p=>{r.add(p.cardIdentifier),a.has(p.name)||(a.add(p.name),s.push(p))},o=p=>{p.types.includes(d.Type.Hero)||n(p)};for(let p of t){let g=ye(e,p);for(let f of g)n(f);g.length===0&&i.push(p)}let c=0;for(;c<s.length&&c<=Jr;){let p=s[c];for(let f of Ce(e,p))o(f);if(c===0)for(let f of me(e,p))o(f);c++}return{cardIdentifiers:r,unresolvedValues:i}},kt=(e,t,r)=>{let s=new Set;for(let a of ye(e,t)){let i=r?Ce(e,a):me(e,a);for(let n of i)s.add(n.cardIdentifier)}return s},ts=(e,t)=>{let r=new Set,[s=new Set,...a]=e;if(t)for(let i of s)a.every(o=>o.has(i))&&r.add(i);else for(let i of e)for(let n of i)r.add(n);return r},Vt=(e,t)=>({filterToPropertyMapping:Zr,values:[...e],valuesSet:e,isExcluded:t,isOr:!0}),It=({filterValues:e,isAnd:t,isExcluded:r},s)=>{let a=[],i=[];for(let{value:n}of e){let o=s(n);a.push(o),o.size===0&&i.push(n)}return{appliedFilters:[Vt(ts(a,t),r)],unresolvedValues:i}},rs=(e,{index:t})=>{let{cardIdentifiers:r,unresolvedValues:s}=es(t,e.filterValues.map(({value:a})=>a));return{appliedFilters:[Vt(r,e.isExcluded)],unresolvedValues:s}},ss=(e,{index:t})=>It(e,r=>kt(t,r,!0)),as=(e,{index:t})=>It(e,r=>kt(t,r,!1)),is=new Map([[l.Artist,wr],[l.Banned,At],[l.Chain,rs],[l.Foiling,Hr],[l.Is,Xr],[l.Legal,At],[l.Pitch,Br],[l.Print,Er],[l.Rarity,$r],[l.ReferencedBy,ss],[l.References,as],[l.Set,Lr],[l.Treatment,Kr]]),wt=(e,t)=>(is.get(e.category)||Ir)(e,t);var Nt=_.map(X).join(""),ns=/(?:[^\s"]+|"[^"]*(?:"|$))+/g,os=new RegExp(`^([${Nt}])?([A-Za-z]+):(.+)$`),ls=new RegExp(`^([${Nt}])?([A-Za-z]+):$`),ds=",",Et="+",cs='"',Bt=e=>{let t=[],r=!1,s="",a=!1;for(let i of e)i===cs?(a=!a,s+=i):!a&&(i===ds||i===Et)?(r=r||i===Et,s&&t.push(s),s=""):s+=i;return s&&t.push(s),{isAndList:r,parts:t}},he=e=>{let t=[];for(let r of e.matchAll(ns))t.push({end:r.index+r[0].length,start:r.index,token:r[0]});return t},ps=e=>_.some(t=>e.startsWith(t)),Fe=e=>{let t=e.match(os),r;if(t){let[,s,a,i]=t;r={isAndList:Bt(i).isAndList,isExcluded:!!s,key:a,valueText:i}}return r},He=e=>{let t=e.match(ls),r;return t&&(r={isAndList:!1,isExcluded:!!t[1],key:t[2],valueText:""}),r},je=e=>{let t=e.trim(),r=Se.find(s=>t.startsWith(s));return{modifier:r,value:r?t.slice(r.length).trim():t}},Qe=e=>re(e)??e.toLowerCase(),us=(e,t)=>{let r=Qe(t),s=[];for(let{end:a,start:i,token:n}of he(e)){let o=Fe(n);o&&Qe(o.key)===r&&s.push({...o,end:a,start:i,token:n})}return s},Ot=e=>Bt(e).parts,Te=e=>e.replace(/^"|"$/g,""),Ue=e=>{let t=[];for(let r of Ot(e)){let s=Te(r);s&&t.push(s)}return t},gs=/[\s,:+"]/,fs=e=>{let t=e.replaceAll('"',"");return gs.test(e)?`"${t}"`:t};var L=require("@flesh-and-blood/types"),Ke=[{description:"Attack actions",expanded:["st:attack"],filters:{subtypes:[L.Subtype.Attack]},isCardProperty:!1,shorthands:["AA"]},{description:"Arcane barrier",expanded:['k:"arcane barrier"'],filters:{keywords:[L.Keyword.ArcaneBarrier]},isCardProperty:!1,shorthands:["AB"]},{description:"Attack reactions",expanded:['t:"attack reaction"'],filters:{types:[L.Type.AttackReaction]},isCardProperty:!1,shorthands:["AR"]},{description:"Defense reactions",expanded:['t:"defense reaction"'],filters:{types:[L.Type.DefenseReaction]},isCardProperty:!1,shorthands:["DR"]},{description:"Gain life",expanded:["gain {h}"],filters:{functionalText:"gain {h}"},isCardProperty:!1,shorthands:["Gain life","Gains life"]},{description:"Go again",expanded:['k:"go again"'],filters:{keywords:[L.Keyword.GoAgain]},isCardProperty:!1,shorthands:["GA"]},{description:"Non-attack actions",expanded:["t:action","st:non-attack"],filters:{subtypes:[L.Subtype.NonAttack],types:[L.Type.Action]},isCardProperty:!1,shorthands:["NAA"]},{description:"Plus defense",expanded:["+ {d}"],filters:{functionalText:"+ {d}"},isCardProperty:!1,shorthands:["Pump defense","Pumps defense","Buff defense","Buffs defense"]},{description:"Spellvoid",expanded:['k:"spellvoid"'],filters:{keywords:[L.Keyword.Spellvoid]},isCardProperty:!1,shorthands:["SV"]}],_e=Ke.filter(({shorthands:e})=>e.some(t=>t.includes(" "))).map(e=>({...e,shorthands:e.shorthands.filter(t=>t.includes(" ")).map(t=>t.toLowerCase()).sort((t,r)=>r.length-t.length)})),$e=Ke.filter(({shorthands:e})=>e.some(t=>!t.includes(" "))).map(e=>({...e,shorthands:e.shorthands.filter(t=>!t.includes(" ")).map(t=>t.toLowerCase()).sort((t,r)=>r.length-t.length)}));var ys=["\u201C","\u201D"],ms=[{text:ae.Release.ClassicBattlesRhinarDorinthea.toLowerCase(),override:ae.Release.ClassicBattlesRhinarDorinthea.toLowerCase().replaceAll(k,"")}],ze=new Map([...ae.setToSetIdentifierMappings].map(([e,t])=>[e.toLowerCase(),t])),Cs=[...J[l.Set],...J[l.Print]],hs=_.map(X).join(""),Fs=[...ze.keys()].sort((e,t)=>t.length-e.length).map(X).join("|"),Ts=new RegExp(`(?<=^|\\s)([${hs}]?(?:${Cs.join("|")}):(?:[^\\s]*[,+])?"?)(${Fs})(?="?(?:[,+]|\\s|$))`,"g"),xs=(e,t)=>{let r=e.trim().toLowerCase();for(let i of ys)r=r.replaceAll(i,'"');for(let{expanded:i,shorthands:n}of _e)for(let o of n)if(r.includes(o)){r=r.replace(o,i.join(" "));break}r=r.replace(Ts,(i,n,o)=>{let c=ze.get(o);return c?`${n}${c[0]}`:i});let s=ze.get(r),a=t.getCardsByExactName(r).length>0;s&&!a&&(r=`set:${s[0]}`);for(let{override:i,text:n}of ms)r.includes(n)&&(r=r.replace(n,i));return r},Ms=e=>{let t=$e.find(({shorthands:s})=>s.includes(e)),r=!!t&&!t.isCardProperty;return{isExpanded:r,tokens:r?t.expanded:[e]}},bs=e=>{let t=[];for(let{end:r,start:s,token:a}of he(e)){let{isExpanded:i,tokens:n}=Ms(a);for(let o of n)t.push({end:r,isExpanded:i,start:s,token:o})}return t},As=e=>{let t=[];for(let r of e){let{modifier:s,value:a}=je(r),i=V(a);i&&t.push({modifier:s,value:i})}return t},Ps=(e,t,r)=>{let s={key:e,reason:"value",values:r},a=Ve(t,r);return a&&(s.suggestedKey=a),s},vs=()=>{let e=new Date,t=`${e.getMonth()+1}`.padStart(2,"0"),r=`${e.getDate()}`.padStart(2,"0");return`${e.getFullYear()}-${t}-${r}`},ie=(e,t,{additionalHeroes:r=[],additionalSets:s=[],today:a=vs()}={})=>{let i=xs(e,t),n={additionalHeroes:r,additionalSets:s,index:t,today:a},o=[],c={artists:[],foilings:[],isExpansionSlot:!1,prints:[],rarities:[],releases:[],treatments:[]},p=[],g=[],f=[];for(let C of bs(i)){let b=Fe(C.token)||He(C.token);if(b){let{isAndList:D,isExcluded:I,key:P,valueText:O}=b,N=ge(P),Q=N?.category,U=Ue(O),$=As(U),H={...C,canonicalValues:$.map(({value:x})=>x),category:Q,filterValues:$,isAnd:D,isExcluded:I,isFilter:!0,isResolved:!0,key:P};if(U.length>0)if(N&&Q){let x=U;if($.length>0){let v=wt({category:Q,filterValues:$,isAnd:H.isAnd,isExcluded:I,key:P,mapping:N},n);o.push(...v.appliedFilters),v.canonicalValues&&(H.canonicalValues=v.canonicalValues),v.attributes&&Object.assign(c,v.attributes),x=v.unresolvedValues}x.length>0&&(H.isResolved=!1,f.push(Ps(P,Q,x)))}else H.isResolved=!1,f.push({key:P,reason:"key",values:[]});g.push(H)}else{let{end:D,start:I,token:P}=C;g.push({end:D,isFilter:!1,start:I,token:P});let O=Te(C.token),N=Ie(O);N.length>0?o.push(...N):O&&p.push(O.replace(k,""))}}return{appliedFilters:o,attributes:c,keywords:p,nodes:g,text:i,unresolvedFilters:f}};var A=require("@flesh-and-blood/types"),Lt={artists:["Hoodwill"],cardIdentifier:"fangs-a-lot-blue",classes:[A.Class.Generic],defaultImage:"FNG000",firstReleaseDate:"2022-06-02",functionalText:"If Fangs A Lot is put into your banished zone from your graveyard, instead put it into your hand.",legalFormats:[],legalHeroes:[A.Hero.Kayo,A.Hero.Levia,A.Hero.Rhinar],printings:[{artists:["Hoodwill"],identifier:"FNG000",image:"FNG000",print:"FNG000",rarity:A.Rarity.Rare,set:A.Release.Promos},{artists:["Hoodwill"],identifier:"FNG000",image:"FNG000_Marvel",print:`FNG000-${A.Treatment.FA}`,rarity:A.Rarity.Marvel,set:A.Release.Promos,treatments:[A.Treatment.FA]}],name:"Fangs A Lot",rarities:[A.Rarity.Rare,A.Rarity.Marvel],rarity:A.Rarity.Rare,sets:[A.Release.Promos],setIdentifiers:["FNG000"],specialImage:"FNG000_Marvel",subtypes:[A.Subtype.Attack],types:[A.Type.Action],typeText:"Generic Action - Attack"},Dt=[{keyword:Lt.name.toLowerCase(),card:Lt}];var Rs={getFn:(e,t)=>{let r=We.default.config.getFn(e,t),s=r;if(Array.isArray(r))s=r.map(a=>{let i=typeof a=="string"?a:a.v;return z(i.replace(k,""))});else if(r){let a=z(r).replace(k,"");s=t.includes("functionalText")?q(a):a}return s},ignoreLocation:!0,includeScore:!0,keys:[{name:"name",weight:10},{name:"functionalText",weight:6},{name:"shorthands",weight:4},{name:"setIdentifiers",weight:2},{name:"traits",weight:4},{name:"typeText",weight:6}],threshold:.15,useExtendedSearch:!0},Ge=class{constructor(t,r=[],s=[]){this.getFuse=()=>(this.fuse||(this.fuse=new We.default(this.cards,Rs)),this.fuse);this.getPoolCards=t=>{this.poolCardByCardIdentifier||(this.poolCardByCardIdentifier=new Map(this.cards.map(s=>[s.cardIdentifier,s])));let r=[];for(let{cardIdentifier:s}of t){let a=this.poolCardByCardIdentifier.get(s);a&&r.push(a)}return r};this.search=(t,r)=>{let s,a,{appliedFilters:i,attributes:n,keywords:o,unresolvedFilters:c}=ie(t,this.index,{additionalHeroes:this.additionalHeroes,additionalSets:this.additionalSets}),p=o.join(" "),g=r?Dt.filter(x=>x.keyword===p):[],f=x=>i.length>0?x.filter(v=>v&&jt(v,i)):x;if(g.length>0)s=f(g.map(({card:x})=>x));else if(o.length){let x=B(p),v=this.getPoolCards(this.index.getCardsByNickname(x)),R=new Map;for(let F of[...this.getPoolCards(this.index.getCardsByExactName(x)),...v])R.set(F.cardIdentifier,F);let u=this.getFuse().search(p).map(F=>F.item).filter(({cardIdentifier:F})=>!R.has(F));s=f([...R.values(),...u]),s.some(F=>v.includes(F))&&(a={kind:"nickname",text:x}),s.length===0&&o.length===1&&(s=f(this.getPoolCards(this.index.getCardsByInitials(x))),s.length>0&&(a={kind:"initials",text:x}))}else s=f([...this.cards]);if(!(o.length>0&&a?.kind!=="initials")){let x="";if(n.releases.length===1){let u=xe.setToSetIdentifierMappings.get(n.releases[0]);u?.length&&(x=u[0].toUpperCase())}if(!x&&n.prints.length===1){let u=n.prints[0];xe.setIdentifierToSetMappings.has(u)&&(x=u.toUpperCase())}x?s.sort((u,y)=>{let h=u.setIdentifiers.find(M=>M.includes(x))?.replace(x,""),F=y.setIdentifiers.find(M=>M.includes(x))?.replace(x,"");return h&&F?h.localeCompare(F):-1}):s.sort((u,y)=>u.name===y.name?`${u.pitch}`.localeCompare(`${y.pitch}`):u.name.localeCompare(y.name))}let b=[],{artists:D,isExpansionSlot:I,foilings:P,prints:O,rarities:N,releases:Q,treatments:U}=n;(D.length>0||I||P.length>0||O.length>0||N.length>0||Q.length>0||U.length>0)&&(b=s.map(x=>{let v=x.printings.filter(R=>{let u=!!R.image,y=D.length===0||D.some(ee=>R.artists.find(Ut=>Ut.replace(k,"").toLowerCase().includes(ee))),h=!I||I===R.isExpansionSlot,F=P.length===0||!!R.foiling&&P.includes(R.foiling),M=O.length===0||O.some(ee=>R.identifier.includes(ee.toUpperCase())),w=N.length===0||N.includes(R.rarity),S=Q.length===0||Q.includes(R.set),Y=U.length===0||R.treatments?.some(ee=>U.includes(ee));return u&&y&&h&&F&&M&&w&&S&&Y});return{...x,matchingPrintings:v}}));let H=b.length>0?b:s;return{alias:a,appliedFilters:i,attributes:n,keywords:o,searchResults:H,unresolvedFilters:c}};let a=Array.isArray(r)?{additionalHeroes:r,additionalSets:s}:r;this.additionalHeroes=a.additionalHeroes||[],this.additionalSets=a.additionalSets||[],this.cards=[...t],this.index=a.index||we(t)}},Ht=Ge,jt=(e,t)=>{let r=!0;for(let s of t){let{isNumber:a,isString:i,isArray:n,isBoolean:o,isDate:c}=s.filterToPropertyMapping;s.isOptional||(a?r=r&&Ss(e,s):i?r=r&&ks(e,s):n?r=r&&Vs(e,s,t):o?r=r&&Is(e,s):c&&(r=r&&ws(e,s)))}return r},Qt=(e,t,r)=>{let s=parseInt(t),a;switch(r){case">=":a=e>=s;break;case">":a=e>s;break;case"<=":a=e<=s;break;case"<":a=e<s;break;default:a=e===s}return a},Ss=(e,t)=>{let{filterValues:r,values:s,modifier:a,isExcluded:i,filterToPropertyMapping:{partialMatch:n}}=t,o=!0;if(oe(t,e)){let c=ne(e,t),p;if(c!=null&&!isNaN(c)){let g=parseInt(c);p=r?r.some(({modifier:f,value:C})=>Qt(g,C,f)):s.some(f=>Qt(g,f,a))}else{let g=Ns(e,t)?.toLowerCase();p=n?s.some(f=>!!g?.includes(f)):s.some(f=>g===f)}o=i?!p:p}return o},ks=(e,t)=>{if(oe(t,e)){let{values:r,valuesSet:s,isAnd:a,isExcluded:i,filterToPropertyMapping:{hasMarkup:n,isNormalized:o,partialMatch:c}}=t,p=ne(e,t),g=o?p:p?.replaceAll(k,"").toLowerCase(),f=n&&g?q(g):g;if(c){let C=a?r?.every(b=>f?.includes(b)):r?.some(b=>f?.includes(b));return i?!C:C}else{let C;return a?C=r?.every(b=>f===b):s?C=s.has(f):C=r?.some(b=>f===b),i?!C:C}}else return!0},Vs=(e,t,r)=>{if(oe(t,e)){let{values:s,isAnd:a,isExcluded:i,filterToPropertyMapping:{partialMatch:n}}=t,o=Es(e,t,r).map(c=>c?.replaceAll(k,""));if(n){let c=a?s.every(g=>o?.some(f=>f?.toLowerCase().includes(g))):s.some(g=>o?.some(f=>f?.toLowerCase().includes(g))),p=o.length===0;return i?!c||p:c}else{let c=a?s.every(p=>o?.some(g=>g?.toLowerCase()===p)):s.some(p=>o?.some(g=>g?.toLowerCase()===p));return i?!c:c}}else return!0},Is=(e,t)=>{if(oe(t,e)){let{isExcluded:r}=t,s=ne(e,t);return r?!s:s}else return!0},ws=(e,t)=>{if(oe(t,e)){let{values:r,isExcluded:s}=t,a=ne(e,t),i=r?.some(n=>a>n);return s?!i:i}else return!0},ne=(e,t)=>{let{filterToPropertyMapping:{property:r}}=t,s;return r!==K&&(s=e[r]),s},Es=(e,t,r)=>{let{filterToPropertyMapping:{isNestedPropertyArray:s,nestedProperty:a}}=t,i=[],n=Object.keys(e.legalOverrides||{}).length>0,o=t.filterToPropertyMapping.property===G.LegalHeroes,c=r.find(({filterToPropertyMapping:g})=>g.property===G.LegalFormats);if(n&&o&&!!c){let g=new Set;for(let{format:f,heroes:C}of e.legalOverrides||[])if(c.values.includes(f.toLowerCase()))for(let b of C)g.add(b);i=Array.from(g)}if(i.length===0)if(a){let g=new Set;for(let f of e.printings){let C=f[a];if(s){if(Array.isArray(C))for(let b of C)g.add(b)}else C&&typeof C=="string"&&g.add(C)}i=Array.from(g)}else{let g=ne(e,t);if(Array.isArray(g))for(let f of g)typeof f=="string"&&i.push(f)}return i},Ns=(e,t)=>{let{filterToPropertyMapping:{specialProperty:r}}=t,s;return r&&(s=e[r]),s},oe=({cardTypes:e},{types:t,subtypes:r})=>!e||e?.some(s=>t.map(a=>a.toLowerCase()).includes(s.toLowerCase())||r.map(a=>a.toLowerCase()).includes(s.toLowerCase()));var Bs=(e,t,r=[],s=[],a)=>{let{appliedFilters:i,attributes:n,keywords:o}=ie(e,t,{additionalHeroes:r,additionalSets:s,today:a});return{appliedFilters:i,attributes:n,keywords:o}};var Os=(e,t)=>{let r=new Set;for(let a of e)for(let i of a.createdExtras||[])r.add(i);let s=[];for(let a of t)r.has(a.cardIdentifier)&&s.push(a);return s};0&&(module.exports={FilterCategory,FilterKind,FilterProperty,MARKUP,NO_CARD_PROPERTY,PUNCTUATION,RARITY_VALUES_MAPPING,aliasesByFilterCategory,availableExclusions,availableModifiers,filterCard,filtersToCardPropertyMappings,getCardsByName,getCardsReferencedBy,getCardsReferencing,getCatalogueIndex,getCleanText,getEscapedForRegExp,getExcludedMetaFilters,getFilterCategory,getFilterMapping,getFilterTokenSpansForKey,getFilterValue,getIncompleteFilterToken,getIsExcludedToken,getIsValueInFilterVocabulary,getKeywordsAndAppliedFiltersFromText,getMetaFilterResolution,getMetaFilters,getNormalizedFilterValue,getNormalizedText,getParsedQuery,getQueryFilterToken,getQueryTokenSpans,getQuotedValue,getResolvedFilterKey,getSuggestedFilterKey,getTextWithoutMarkup,getTokensReferencedByCards,getUnquotedValue,getValuePartsFromFilterValue,getValuesFromFilterValue,multiWordShorthands,shorthands,singleWordShorthands});
|
|
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 {
|
|
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 { Card, 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
|
/**
|
|
@@ -28,6 +38,11 @@ export interface CatalogueIndex<CardType extends DoubleSidedCard = DoubleSidedCa
|
|
|
28
38
|
getCardsByExactName: (name: string) => readonly CardType[];
|
|
29
39
|
/** Every card carrying the nickname, matched whole, hyphens ignored. */
|
|
30
40
|
getCardsByNickname: (nickname: string) => readonly CardType[];
|
|
41
|
+
/**
|
|
42
|
+
* Every card carrying the type, subtype or trait, matched whole, hyphens
|
|
43
|
+
* ignored.
|
|
44
|
+
*/
|
|
45
|
+
getCardsByGroup: (group: string) => readonly CardType[];
|
|
31
46
|
/**
|
|
32
47
|
* Every card whose name has the initials, in corpus order, counting a
|
|
33
48
|
* hyphenated word both as one word and as the words the hyphens join.
|
|
@@ -64,15 +79,12 @@ export interface CatalogueIndex<CardType extends DoubleSidedCard = DoubleSidedCa
|
|
|
64
79
|
getCardsInCorpusOrder: <OrderedCard extends DoubleSidedCard>(cardsToOrder: readonly OrderedCard[]) => OrderedCard[];
|
|
65
80
|
}
|
|
66
81
|
/**
|
|
67
|
-
* The index for a corpus, one per
|
|
68
|
-
* shares its maps. Each map is built the
|
|
69
|
-
*
|
|
70
|
-
*
|
|
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.
|
|
71
87
|
*/
|
|
72
|
-
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>;
|
|
73
89
|
/** {@link CatalogueIndex.getCardsByName}, as a free function over an index. */
|
|
74
90
|
export declare const getCardsByName: (index: CatalogueIndex, name: string) => readonly DoubleSidedCard[];
|
|
75
|
-
/** The cards naming the card, at every pitch of both. */
|
|
76
|
-
export declare const getCardsReferencing: (index: CatalogueIndex, card: Card) => DoubleSidedCard[];
|
|
77
|
-
/** The cards the card names, at every pitch of both. */
|
|
78
|
-
export declare const getCardsReferencedBy: (index: CatalogueIndex, card: Card) => 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";
|
|
@@ -25,7 +26,7 @@ const getInitialsOfName = (name) => {
|
|
|
25
26
|
}
|
|
26
27
|
return [...initialsOfName];
|
|
27
28
|
};
|
|
28
|
-
const
|
|
29
|
+
const getHyphenFreeKey = (text) => getCleanText(text).replaceAll("-", "");
|
|
29
30
|
const addToCardList = (cardsByKey, key, card) => {
|
|
30
31
|
const cardsForKey = cardsByKey.get(key);
|
|
31
32
|
if (cardsForKey) {
|
|
@@ -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,13 +69,32 @@ 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;
|
|
75
94
|
let cardsByRole;
|
|
76
95
|
let artists;
|
|
77
96
|
let cardsByNicknameKey;
|
|
97
|
+
let cardsByGroup;
|
|
78
98
|
let cardsByInitials;
|
|
79
99
|
const getCardLookups = () => {
|
|
80
100
|
if (!cardLookups) {
|
|
@@ -169,11 +189,30 @@ const getNewCatalogueIndex = (cards) => {
|
|
|
169
189
|
cardsByNicknameKey = /* @__PURE__ */ new Map();
|
|
170
190
|
for (const card of cards) {
|
|
171
191
|
for (const cardNickname of card.nicknames ?? []) {
|
|
172
|
-
addToCardList(
|
|
192
|
+
addToCardList(
|
|
193
|
+
cardsByNicknameKey,
|
|
194
|
+
getHyphenFreeKey(cardNickname),
|
|
195
|
+
card
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return cardsByNicknameKey.get(getHyphenFreeKey(nickname)) ?? noCards;
|
|
201
|
+
};
|
|
202
|
+
const getCardsByGroup = (group) => {
|
|
203
|
+
if (!cardsByGroup) {
|
|
204
|
+
cardsByGroup = /* @__PURE__ */ new Map();
|
|
205
|
+
for (const card of cards) {
|
|
206
|
+
for (const cardGroup of [
|
|
207
|
+
...card.types,
|
|
208
|
+
...card.subtypes,
|
|
209
|
+
...card.traits ?? []
|
|
210
|
+
]) {
|
|
211
|
+
addToCardList(cardsByGroup, getHyphenFreeKey(cardGroup), card);
|
|
173
212
|
}
|
|
174
213
|
}
|
|
175
214
|
}
|
|
176
|
-
return
|
|
215
|
+
return cardsByGroup.get(getHyphenFreeKey(group)) ?? noCards;
|
|
177
216
|
};
|
|
178
217
|
const getCardsByInitials = (initials) => {
|
|
179
218
|
if (!cardsByInitials) {
|
|
@@ -244,6 +283,28 @@ const getNewCatalogueIndex = (cards) => {
|
|
|
244
283
|
}
|
|
245
284
|
return getCardsInCorpusOrder([...createdCardByCardIdentifier.values()]);
|
|
246
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
|
+
};
|
|
247
308
|
const getByRole = (role) => {
|
|
248
309
|
if (!cardsByRole) {
|
|
249
310
|
cardsByRole = getCardsByRole(cards);
|
|
@@ -252,11 +313,17 @@ const getNewCatalogueIndex = (cards) => {
|
|
|
252
313
|
};
|
|
253
314
|
return {
|
|
254
315
|
cards,
|
|
316
|
+
releases,
|
|
255
317
|
getCard,
|
|
318
|
+
getRelease,
|
|
319
|
+
getReleaseByName,
|
|
320
|
+
getReleaseBySetIdentifier,
|
|
321
|
+
getReleaseHeroCards,
|
|
256
322
|
getPitchCycle,
|
|
257
323
|
getCardsByName: getCardsByName2,
|
|
258
324
|
getCardsByExactName,
|
|
259
325
|
getCardsByNickname,
|
|
326
|
+
getCardsByGroup,
|
|
260
327
|
getCardsByInitials,
|
|
261
328
|
getArtists,
|
|
262
329
|
getOppositeSide,
|
|
@@ -269,42 +336,21 @@ const getNewCatalogueIndex = (cards) => {
|
|
|
269
336
|
getCardsInCorpusOrder
|
|
270
337
|
};
|
|
271
338
|
};
|
|
272
|
-
const getCatalogueIndex = (cards) => {
|
|
273
|
-
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);
|
|
274
346
|
if (!catalogueIndex) {
|
|
275
|
-
catalogueIndex = getNewCatalogueIndex(cards);
|
|
276
|
-
|
|
347
|
+
catalogueIndex = getNewCatalogueIndex(cards, releases);
|
|
348
|
+
catalogueIndexByReleases.set(releases, catalogueIndex);
|
|
277
349
|
}
|
|
278
350
|
return catalogueIndex;
|
|
279
351
|
};
|
|
280
|
-
const getPitchCycleOfCard = (index, card) => index.getPitchCycle(card.cardIdentifier);
|
|
281
352
|
const getCardsByName = (index, name) => index.getCardsByName(name);
|
|
282
|
-
const getCardsWithPitchSiblings = (index, cards) => {
|
|
283
|
-
const cardByCardIdentifier = /* @__PURE__ */ new Map();
|
|
284
|
-
for (const card of cards) {
|
|
285
|
-
for (const pitch of getPitchCycleOfCard(index, card)) {
|
|
286
|
-
cardByCardIdentifier.set(pitch.cardIdentifier, pitch);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
return index.getCardsInCorpusOrder([...cardByCardIdentifier.values()]);
|
|
290
|
-
};
|
|
291
|
-
const getCardsReferencing = (index, card) => {
|
|
292
|
-
const referencingCards = [];
|
|
293
|
-
for (const pitch of getPitchCycleOfCard(index, card)) {
|
|
294
|
-
referencingCards.push(...index.getReferencedBy(pitch.cardIdentifier));
|
|
295
|
-
}
|
|
296
|
-
return getCardsWithPitchSiblings(index, referencingCards);
|
|
297
|
-
};
|
|
298
|
-
const getCardsReferencedBy = (index, card) => {
|
|
299
|
-
const referencedCards = [];
|
|
300
|
-
for (const pitch of getPitchCycleOfCard(index, card)) {
|
|
301
|
-
referencedCards.push(...index.getReferences(pitch.cardIdentifier));
|
|
302
|
-
}
|
|
303
|
-
return getCardsWithPitchSiblings(index, referencedCards);
|
|
304
|
-
};
|
|
305
353
|
export {
|
|
306
354
|
getCardsByName,
|
|
307
|
-
getCardsReferencedBy,
|
|
308
|
-
getCardsReferencing,
|
|
309
355
|
getCatalogueIndex
|
|
310
356
|
};
|
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.0",
|
|
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"
|
|
@@ -47,8 +43,8 @@
|
|
|
47
43
|
"@flesh-and-blood/types": "^5.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": "3d19edf0d4b060755686cb871a9283f8bdfcc438"
|
|
79
75
|
}
|