Skip to content

Queries

Queries express boolean conditions over tag containers — "any of these, all of those, none of these" — and nest arbitrarily, matching Unreal's FGameplayTagQuery.

From filters

The filter form covers most application search state:

ts
import { makeGameplayTagQueryFromFilters } from "gameplay-tags";

const query = makeGameplayTagQueryFromFilters({
  anyTags: ["Ability.Element"],          // hierarchical
  noTags: ["Character.State"],
  exactAnyTags: ["Character.Class.Mage"],
  description: "usable elemental loadout"
});

query.matches(makeGameplayTagContainer([
  "Ability.Element.Fire",
  "Character.Class.Mage"
])); // true

From expression trees

For full control, compose expressions the way Unreal builds them:

ts
import { GameplayTagQuery, GameplayTagQueryExpression } from "gameplay-tags";

const query = GameplayTagQuery.buildQuery(
  new GameplayTagQueryExpression()
    .allExprMatch()
    .addExpr(new GameplayTagQueryExpression().anyTagsMatch().addTag("Ability.Element"))
    .addExpr(new GameplayTagQueryExpression().noTagsMatch().addTag("Character.State.Stunned")),
  "elemental and not stunned"
);

Expression types: anyTagsMatch, allTagsMatch, noTagsMatch, anyTagsExactMatch, allTagsExactMatch for tag sets, and anyExprMatch, allExprMatch, noExprMatch for nesting.

Persistence

Queries round-trip through JSON:

ts
const saved = stringifyGameplayTagQuery(query);
const loaded = parseGameplayTagQuery(saved);

loaded.equals(query); // true — order-insensitive structural comparison

makeGameplayTagQuery accepts an existing query, an expression, a parsed JSON shape, or a filter object, so persistence code can stay format-agnostic.

Filtering records

ts
import { doesGameplayTagContainerMatchQuery, filterGameplayTagQueryMatches } from "gameplay-tags";

const encounters = [
  { title: "Ashfall pyromancer", tags: ["Character.Class.Mage", "Ability.Element.Fire"] },
  { title: "Stunned champion", tags: ["Character.State.Stunned"] }
];

filterGameplayTagQueryMatches(encounters, query, (encounter) => encounter.tags);
// [{ title: "Ashfall pyromancer", ... }]

doesGameplayTagContainerMatchQuery(["Ability.Element.Fire"], query);

Both helpers accept an emptyQueryMatches option to choose whether an empty query matches everything or nothing (default: nothing).