@optolith/entity-descriptions 0.11.1 → 0.12.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.
Files changed (103) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/lib/entities/activatable.js +11 -5
  3. package/lib/entities/elixir.js +9 -1
  4. package/lib/entities/influence.js +10 -1
  5. package/lib/entities/partial/activatableNameChunks.d.ts +2 -2
  6. package/lib/entities/partial/activatableNameChunks.js +18 -4
  7. package/lib/entities/partial/adventurePointsValue.js +19 -12
  8. package/lib/entities/partial/commonnessRatedAdvantagesAndDisadvantages.d.ts +1 -1
  9. package/lib/entities/partial/commonnessRatedAdvantagesAndDisadvantages.js +4 -4
  10. package/lib/entities/partial/enhancements.d.ts +1 -1
  11. package/lib/entities/partial/enhancements.js +13 -4
  12. package/lib/entities/partial/map.d.ts +1 -1
  13. package/lib/entities/partial/markdown.d.ts +5 -1
  14. package/lib/entities/partial/markdown.js +13 -1
  15. package/lib/entities/partial/prerequisites/displayOption.d.ts +2 -7
  16. package/lib/entities/partial/prerequisites/displayOption.js +1 -18
  17. package/lib/entities/partial/prerequisites/index.d.ts +26 -20
  18. package/lib/entities/partial/prerequisites/index.js +89 -65
  19. package/lib/entities/partial/prerequisites/part.d.ts +4 -4
  20. package/lib/entities/partial/prerequisites/part.js +23 -14
  21. package/lib/entities/partial/prerequisites/prerequisiteGroups.d.ts +16 -18
  22. package/lib/entities/partial/prerequisites/prerequisiteGroups.js +90 -82
  23. package/lib/entities/partial/prerequisites/single/activatable.d.ts +4 -5
  24. package/lib/entities/partial/prerequisites/single/activatable.js +21 -29
  25. package/lib/entities/partial/prerequisites/single/animistPower.d.ts +2 -3
  26. package/lib/entities/partial/prerequisites/single/animistPower.js +6 -9
  27. package/lib/entities/partial/prerequisites/single/anySpecialAbilityOfGroup.d.ts +1 -1
  28. package/lib/entities/partial/prerequisites/single/anySpecialAbilityOfGroup.js +4 -7
  29. package/lib/entities/partial/prerequisites/single/blessedTradition.d.ts +2 -2
  30. package/lib/entities/partial/prerequisites/single/blessedTradition.js +15 -17
  31. package/lib/entities/partial/prerequisites/single/commonSuggestedByRCP.d.ts +2 -2
  32. package/lib/entities/partial/prerequisites/single/commonSuggestedByRCP.js +9 -6
  33. package/lib/entities/partial/prerequisites/single/culture.d.ts +2 -3
  34. package/lib/entities/partial/prerequisites/single/culture.js +8 -15
  35. package/lib/entities/partial/prerequisites/single/enhancement.d.ts +1 -1
  36. package/lib/entities/partial/prerequisites/single/enhancement.js +1 -1
  37. package/lib/entities/partial/prerequisites/single/influence.d.ts +2 -3
  38. package/lib/entities/partial/prerequisites/single/influence.js +7 -10
  39. package/lib/entities/partial/prerequisites/single/magicalTradition.d.ts +2 -2
  40. package/lib/entities/partial/prerequisites/single/magicalTradition.js +10 -12
  41. package/lib/entities/partial/prerequisites/single/noOtherAncestorBloodAdvantage.d.ts +2 -2
  42. package/lib/entities/partial/prerequisites/single/noOtherAncestorBloodAdvantage.js +4 -3
  43. package/lib/entities/partial/prerequisites/single/pact.d.ts +2 -3
  44. package/lib/entities/partial/prerequisites/single/pact.js +17 -18
  45. package/lib/entities/partial/prerequisites/single/personalityTrait.d.ts +2 -3
  46. package/lib/entities/partial/prerequisites/single/personalityTrait.js +21 -22
  47. package/lib/entities/partial/prerequisites/single/primaryAttribute.d.ts +2 -2
  48. package/lib/entities/partial/prerequisites/single/primaryAttribute.js +6 -8
  49. package/lib/entities/partial/prerequisites/single/profession.d.ts +2 -3
  50. package/lib/entities/partial/prerequisites/single/profession.js +11 -14
  51. package/lib/entities/partial/prerequisites/single/publication.d.ts +2 -3
  52. package/lib/entities/partial/prerequisites/single/publication.js +7 -13
  53. package/lib/entities/partial/prerequisites/single/race.d.ts +2 -3
  54. package/lib/entities/partial/prerequisites/single/race.js +8 -15
  55. package/lib/entities/partial/prerequisites/single/rated.d.ts +2 -3
  56. package/lib/entities/partial/prerequisites/single/rated.js +7 -9
  57. package/lib/entities/partial/prerequisites/single/ratedMinimumNumber.d.ts +2 -3
  58. package/lib/entities/partial/prerequisites/single/ratedMinimumNumber.js +52 -53
  59. package/lib/entities/partial/prerequisites/single/ratedSum.d.ts +2 -3
  60. package/lib/entities/partial/prerequisites/single/ratedSum.js +15 -15
  61. package/lib/entities/partial/prerequisites/single/rule.d.ts +2 -2
  62. package/lib/entities/partial/prerequisites/single/rule.js +2 -1
  63. package/lib/entities/partial/prerequisites/single/sex.d.ts +2 -2
  64. package/lib/entities/partial/prerequisites/single/sex.js +7 -6
  65. package/lib/entities/partial/prerequisites/single/sexualCharacteristic.d.ts +2 -2
  66. package/lib/entities/partial/prerequisites/single/sexualCharacteristic.js +11 -8
  67. package/lib/entities/partial/prerequisites/single/socialStatus.d.ts +2 -3
  68. package/lib/entities/partial/prerequisites/single/socialStatus.js +9 -15
  69. package/lib/entities/partial/prerequisites/single/state.d.ts +2 -3
  70. package/lib/entities/partial/prerequisites/single/state.js +8 -15
  71. package/lib/entities/partial/prerequisites/single/text.d.ts +2 -2
  72. package/lib/entities/partial/prerequisites/single/text.js +4 -3
  73. package/lib/entities/partial/prerequisites/single/tinyActivatable.d.ts +1 -1
  74. package/lib/entities/partial/prerequisites/single/tinyActivatable.js +5 -8
  75. package/lib/entities/partial/rated/activatable/castingTime.d.ts +1 -1
  76. package/lib/entities/partial/rated/activatable/checkResultBased.d.ts +1 -1
  77. package/lib/entities/partial/rated/activatable/cost.d.ts +3 -3
  78. package/lib/entities/partial/rated/activatable/duration.d.ts +1 -1
  79. package/lib/entities/partial/rated/activatable/duration.js +1 -1
  80. package/lib/entities/partial/rated/activatable/effect.d.ts +1 -1
  81. package/lib/entities/partial/rated/activatable/index.d.ts +1 -1
  82. package/lib/entities/partial/rated/activatable/isMinimumMaximum.d.ts +1 -1
  83. package/lib/entities/partial/rated/activatable/nonModifiableSuffix.d.ts +1 -1
  84. package/lib/entities/partial/rated/activatable/nonModifiableSuffix.js +1 -1
  85. package/lib/entities/partial/rated/activatable/range.d.ts +1 -1
  86. package/lib/entities/partial/rated/activatable/targetCategory.d.ts +1 -1
  87. package/lib/entities/partial/rated/improvementCost.d.ts +1 -1
  88. package/lib/entities/partial/rated/skillCheck.d.ts +1 -1
  89. package/lib/entities/partial/reader.d.ts +2 -57
  90. package/lib/entities/partial/responsiveText.d.ts +1 -1
  91. package/lib/entities/partial/units/length.d.ts +1 -1
  92. package/lib/entities/partial/units/timeSpan.d.ts +3 -4
  93. package/lib/entities/personalityTrait.js +8 -1
  94. package/lib/entities/poison.js +5 -1
  95. package/lib/entities/profession.js +23 -18
  96. package/lib/entities/race.d.ts +1 -1
  97. package/lib/entities/race.js +16 -12
  98. package/lib/entities/spell.js +5 -2
  99. package/lib/env.d.ts +66 -0
  100. package/lib/env.js +1 -0
  101. package/lib/references/publicationOptions.d.ts +1 -1
  102. package/lib/tsconfig.tsbuildinfo +1 -1
  103. package/package.json +2 -2
@@ -2,66 +2,11 @@ import { Reader } from "@elyukai/utils/reader";
2
2
  import type { ChildEntityMap, EntityMap, FastSkillModificationLevelConfig, ResponsiveText, ResponsiveTextOptional, SkillModificationLevel, SlowSkillModificationLevelConfig } from "@optolith/database-schema/gen";
3
3
  import type { IdArgsVariant } from "tsondb/schema/gen";
4
4
  import type { GetAllChildInstancesForParent, GetAllInstances, GetInstanceById } from "../../helpers/getTypes.js";
5
- import type { FormatNumber, LocaleCompare, LocaleJoin, LocaleJoinType } from "../../helpers/locale.js";
6
- import type { Format, LocaleMap, Translate, TranslateMap, TranslationKeyMatchingParamsOfKey, TranslationKeysWithoutParams, TranslationParamsInArray, Translations } from "../../helpers/translate.js";
7
- import type { PublicationOptions } from "../../references/publicationOptions.js";
8
- import type { GetResolvedSelectOptionById } from "./prerequisites/single/activatable.js";
9
- import type { ModifiableParameter } from "./rated/activatable/nonModifiableSuffix.js";
5
+ import type { LocaleCompare, LocaleJoin, LocaleJoinType } from "../../helpers/locale.js";
6
+ import type { Format, LocaleMap, Translate, TranslateMap, TranslationKeyMatchingParamsOfKey, TranslationParamsInArray, Translations } from "../../helpers/translate.js";
10
7
  import { Speed } from "./rated/activatable/speed.js";
11
8
  import { ResponsiveTextSize } from "./responsiveText.js";
12
9
  import { type EnergyUnit } from "./units/energy.js";
13
- /**
14
- * The standard set of environment properties for readers in this project.
15
- */
16
- export type EnvMap<E extends keyof EntityMap = never, AE extends keyof EntityMap = never, CE extends keyof ChildEntityMap = never> = {
17
- format: Format;
18
- formatNumber: FormatNumber;
19
- translate: Translate;
20
- translateMap: TranslateMap;
21
- localeJoin: LocaleJoin;
22
- localeCompare: LocaleCompare;
23
- responsiveTextSize: ResponsiveTextSize;
24
- speed: Speed;
25
- energyUnit: EnergyUnit;
26
- nonModifiableSuffix?: (param: ModifiableParameter) => TranslationKeysWithoutParams;
27
- getInstanceById: GetInstanceById<E>;
28
- getAllInstances: GetAllInstances<AE>;
29
- getChildInstancesForInstanceId: GetAllChildInstancesForParent<CE>;
30
- getResolvedSelectOptionById: GetResolvedSelectOptionById;
31
- publicationOptions: PublicationOptions;
32
- };
33
- /**
34
- * Shortcuts for selecting keys of the shared environment map type.
35
- */
36
- export type EnvMapAbbr = {
37
- f: "format";
38
- fn: "formatNumber";
39
- t: "translate";
40
- tm: "translateMap";
41
- lj: "localeJoin";
42
- lc: "localeCompare";
43
- rts: "responsiveTextSize";
44
- s: "speed";
45
- eu: "energyUnit";
46
- nms: "nonModifiableSuffix";
47
- ibi: "getInstanceById";
48
- ai: "getAllInstances";
49
- acibp: "getChildInstancesForInstanceId";
50
- rso: "getResolvedSelectOptionById";
51
- po: "publicationOptions";
52
- };
53
- /**
54
- * The standard set of environment properties for readers in this project.
55
- *
56
- * The keys are abbreviated to keep type annotations short.
57
- */
58
- export type StdEnv<K extends keyof EnvMapAbbr = keyof EnvMapAbbr, E extends keyof EntityMap = never, AE extends keyof EntityMap = never, CE extends keyof ChildEntityMap = never> = Pick<EnvMap<E, AE, CE>, EnvMapAbbr[K]>;
59
- /**
60
- * Shortcut for a reader with common environment properties.
61
- *
62
- * The keys are abbreviated to keep return type annotations short.
63
- */
64
- export type StdReader<T, K extends keyof EnvMapAbbr, E extends keyof EntityMap = never, AE extends keyof EntityMap = never, CE extends keyof ChildEntityMap = never> = Reader<StdEnv<K, E, AE, CE>, T>;
65
10
  /**
66
11
  * Treats the text as a translation string and applies supplied arguments.
67
12
  */
@@ -1,7 +1,7 @@
1
1
  import { Reader } from "@elyukai/utils/reader";
2
2
  import type { ResponsiveText, ResponsiveTextOptional, ResponsiveTextReplace } from "@optolith/database-schema/gen";
3
+ import type { StdEnv } from "../../env.js";
3
4
  import { type LocaleMap } from "../../helpers/translate.js";
4
- import { type StdEnv } from "./reader.js";
5
5
  /**
6
6
  * Whether the entry is displayed in a normal or compressed setting. Normal/full
7
7
  * usually means a full library entry display, whether compressed usually means
@@ -1,5 +1,5 @@
1
+ import type { StdReader } from "../../../env.js";
1
2
  import type { Translate } from "../../../helpers/translate.js";
2
- import type { StdReader } from "../reader.js";
3
3
  import { type ResponsiveTextSize } from "../responsiveText.js";
4
4
  type LengthUnit = "Steps" | "Miles";
5
5
  /**
@@ -1,7 +1,6 @@
1
- import { Reader } from "@elyukai/utils/reader";
2
1
  import type { Case } from "tsondb/schema/gen";
2
+ import type { StdReader } from "../../../env.js";
3
3
  import type { Format, LocaleMap, Translate, TranslateMap } from "../../../helpers/translate.js";
4
- import type { StdEnv } from "../reader.js";
5
4
  import { type ResponsiveTextSize } from "../responsiveText.js";
6
5
  /**
7
6
  * Possible units to use for time spans.
@@ -36,11 +35,11 @@ export declare const formatCombinedTimeSpan: (translate: Translate, translateMap
36
35
  /**
37
36
  * Returns the text for a time span unit.
38
37
  */
39
- export declare const formatTimeSpanR: (unit: TimeSpanUnitObject | TimeSpanUnit, value: number | string, interval?: boolean) => Reader<StdEnv<"t" | "tm" | "f" | "rts">, string>;
38
+ export declare const formatTimeSpanR: (unit: TimeSpanUnitObject | TimeSpanUnit, value: number | string, interval?: boolean) => StdReader<string, "t" | "tm" | "f" | "rts">;
40
39
  /**
41
40
  * Returns the text for a time span unit.
42
41
  */
43
42
  export declare const formatCombinedTimeSpanR: (object: {
44
43
  unit: TimeSpanUnitObject;
45
44
  value: number | string;
46
- }, interval?: boolean) => Reader<StdEnv<"t" | "tm" | "f" | "rts">, string>;
45
+ }, interval?: boolean) => StdReader<string, "t" | "tm" | "f" | "rts">;
@@ -16,6 +16,13 @@ export const getPersonalityTraitEntityDescription = createEntityDescriptionCreat
16
16
  if (translation === undefined) {
17
17
  return undefined;
18
18
  }
19
+ const env = {
20
+ translate,
21
+ translateMap,
22
+ getInstanceById,
23
+ localeCompare: locale.compare,
24
+ localeJoin: locale.join,
25
+ };
19
26
  return {
20
27
  title: `${translation.name} (${translate("Level {$level}", {
21
28
  level: romanize(entry.level),
@@ -51,7 +58,7 @@ export const getPersonalityTraitEntityDescription = createEntityDescriptionCreat
51
58
  ? undefined
52
59
  : {
53
60
  label: translate("Prerequisites"),
54
- value: printPersonalityTraitPrerequisites(getInstanceById, locale, entry.prerequisites),
61
+ value: printPersonalityTraitPrerequisites(entry.prerequisites).run(env),
55
62
  },
56
63
  ],
57
64
  },
@@ -262,6 +262,10 @@ export const getPoisonEntityDescription = createEntityDescriptionCreator(({ getI
262
262
  translate,
263
263
  translateMap,
264
264
  format,
265
+ localeJoin,
266
+ localeCompare,
267
+ getInstanceById,
268
+ getResolvedSelectOptionById,
265
269
  responsiveTextSize: ResponsiveTextSize.Full,
266
270
  };
267
271
  const applicationType = renderApplicationType(translate, localeJoin, localeCompare, entry.application_type);
@@ -376,7 +380,7 @@ export const getPoisonEntityDescription = createEntityDescriptionCreator(({ getI
376
380
  : {
377
381
  label: `${translate("AP Value")} (${translate("Trade Secret")})`,
378
382
  value: translate("{$value} AP", { value: tradeSecret.apValue }) +
379
- parensIf(mapNullable(tradeSecret.prerequisites, prerequisites => `${translate("Prerequisites")}: ${printPlainGeneralPrerequisites(getInstanceById, getResolvedSelectOptionById, locale, prerequisites)}`)),
383
+ parensIf(mapNullable(tradeSecret.prerequisites, prerequisites => `${translate("Prerequisites")}: ${printPlainGeneralPrerequisites(prerequisites).run(env)}`)),
380
384
  },
381
385
  entry.source_type.kind === "AlchemicalPoison" ||
382
386
  entry.source_type.kind === "AlchemicalPactGiftPoison"
@@ -12,7 +12,7 @@ import { createEntityDescriptionCreator } from "../creator.js";
12
12
  import { combineNameComponents, getNameComponents, renderActivatableNameComponents, renderCombinedActivatableNameComponents, } from "./partial/activatableNameChunks.js";
13
13
  import { renderCommonnessRatedAdvantagesOrDisadvantages, renderValueWithPossibleTranslation, } from "./partial/commonnessRatedAdvantagesAndDisadvantages.js";
14
14
  import { attributedCustomName, attributedInstance, attributedName, attributedNameFromInstance, } from "./partial/markdown.js";
15
- import { printProfessionPrerequisites } from "./partial/prerequisites/index.js";
15
+ import { printProfessionPrerequisites, printProfessionVariantPrerequisites, } from "./partial/prerequisites/index.js";
16
16
  import { parensIf } from "./partial/rated/activatable/parensIf.js";
17
17
  import { attributedCustomNameR, attributedNameR, customNameR, formatR, getChildInstancesForInstanceIdFnR, getChildInstancesForInstanceIdR, getInstanceByIdR, localeCompareR, localeJoinR, localeSortR, strictNameR, translateMapFnR, translateR, translationR, } from "./partial/reader.js";
18
18
  import { MISSING_VALUE, UNHANDLED_VALUE } from "./partial/unknown.js";
@@ -385,7 +385,7 @@ const renderSpecialAbilityName = (specialAbility) => Reader.asks(({ translate, t
385
385
  else {
386
386
  return isCombinedEnhancementNameComponents(possiblyCombined)
387
387
  ? renderCombinedEnhancementNameComponents(possiblyCombined)
388
- : wrapActivatableInAttributedString(renderCombinedActivatableNameComponents(translateMap, possiblyCombined, false, list => localeJoin(list, "disjunction")), possiblyCombined.id);
388
+ : renderCombinedActivatableNameComponents(translateMap, possiblyCombined, false, list => localeJoin(list, "disjunction"), "profession");
389
389
  }
390
390
  }
391
391
  default:
@@ -448,7 +448,7 @@ const renderSpellworks = (professionPackages) => Reader.sequence([
448
448
  const retrieveBlessedTraditionIdentifierFromPrerequisiteGroup = (prerequisite) => prerequisite.kind === "Activatable" && prerequisite.Activatable.id.kind === "BlessedTradition"
449
449
  ? [prerequisite.Activatable.id.BlessedTradition]
450
450
  : [];
451
- const retrieveBlessedTraditionIdentifierFromPrerequisites = (prerequisites) => prerequisites?.flatMap(part => {
451
+ const retrieveBlessedTraditionIdentifierFromPrerequisite = (part) => {
452
452
  switch (part.kind) {
453
453
  case "Single":
454
454
  return retrieveBlessedTraditionIdentifierFromPrerequisiteGroup(part.Single);
@@ -459,6 +459,17 @@ const retrieveBlessedTraditionIdentifierFromPrerequisites = (prerequisites) => p
459
459
  default:
460
460
  return assertExhaustive(part);
461
461
  }
462
+ };
463
+ const retrieveBlessedTraditionIdentifierFromPrerequisites = (prerequisites) => prerequisites?.flatMap(retrieveBlessedTraditionIdentifierFromPrerequisite) ?? [];
464
+ const retrieveBlessedTraditionIdentifierFromVariantPrerequisites = (prerequisites) => prerequisites?.flatMap(part => {
465
+ switch (part.kind) {
466
+ case "Add":
467
+ return retrieveBlessedTraditionIdentifierFromPrerequisite(part.Add);
468
+ case "Remove":
469
+ return [];
470
+ default:
471
+ return assertExhaustive(part);
472
+ }
462
473
  }) ?? [];
463
474
  const renderBlessingList = (blessings) => Reader.traverse(blessings, id => attributedNameR("profession", "Blessing", id).map(name => name ?? MISSING_VALUE)).thenW(localeSortR);
464
475
  const renderRestrictedBlessings = (restrictedBlessings) => {
@@ -508,7 +519,7 @@ const renderBlessings = (traditions) => {
508
519
  };
509
520
  const renderBlessingsForPackages = (professionPackages) => renderBlessings(professionPackages.map(pkg => retrieveBlessedTraditionIdentifierFromPrerequisites(pkg.content.prerequisites)));
510
521
  const renderBlessingsForVariant = (professionVariant) => renderBlessings([
511
- retrieveBlessedTraditionIdentifierFromPrerequisites(professionVariant.prerequisites),
522
+ retrieveBlessedTraditionIdentifierFromVariantPrerequisites(professionVariant.prerequisites),
512
523
  ]).map(blessingsText => (blessingsText !== undefined ? [blessingsText] : []));
513
524
  const renderLiturgicalChantName = (liturgyIds) => Reader.traverse(liturgyIds, id => attributedNameR("profession", id).map(name => name ?? MISSING_VALUE)).thenW(list => localeJoinR(list, "disjunction"));
514
525
  const renderLiturgicalChants = (professionPackages) => Reader.sequence([
@@ -538,15 +549,11 @@ const renderProfessionVariantLabel = (base, variant, translations) => translateR
538
549
  const renderProfessionVariantText = (base, variant, translation) => translation.full_text !== undefined
539
550
  ? Reader.of(translation.full_text)
540
551
  : Reader.sequence([
541
- Reader.asks(env => variant.prerequisites === undefined
542
- ? []
543
- : [
544
- `${env.translate("Additional Prerequisites")}: ${printProfessionPrerequisites(env.getInstanceById, env.getResolvedSelectOptionById, {
545
- ...env,
546
- join: env.localeJoin,
547
- compare: env.localeCompare,
548
- }, variant.prerequisites)}`,
549
- ]),
552
+ variant.prerequisites === undefined
553
+ ? Reader.of([])
554
+ : printProfessionVariantPrerequisites(variant.prerequisites).thenW(prerequisitesText => translateR("Additional Prerequisites").map(label => [
555
+ `${label}: ${prerequisitesText}`,
556
+ ])),
550
557
  renderVariantOption(base, variant, "skill_specialization", renderVariantSkillSpecializationOption),
551
558
  renderVariantOption(base, variant, "languages_scripts", renderVariantLanguagesScriptsOption),
552
559
  renderVariantOption(base, variant, "combat_techniques", renderVariantCombatTechniquesOption),
@@ -672,11 +679,9 @@ export const getProfessionVersionEntityDescription = createEntityDescriptionCrea
672
679
  },
673
680
  {
674
681
  label: translate("Prerequisites"),
675
- value: renderSinglePackageValue(professionPackages, pkg => Reader.of(pkg.content.prerequisites), deepEqual, prerequisitesLists => Reader.of(prerequisitesLists
676
- .map(prerequisites => prerequisites === undefined
677
- ? translate("none")
678
- : printProfessionPrerequisites(getInstanceById, getResolvedSelectOptionById, locale, prerequisites))
679
- .join(" / "))).run(env),
682
+ value: renderSinglePackageValue(professionPackages, pkg => Reader.of(pkg.content.prerequisites), deepEqual, prerequisitesLists => Reader.traverse(prerequisitesLists, prerequisites => prerequisites === undefined
683
+ ? translateR("none")
684
+ : printProfessionPrerequisites(prerequisites)).map(list => list.join(" / "))).run(env),
680
685
  },
681
686
  {
682
687
  label: translate("Special Abilities"),
@@ -1,7 +1,7 @@
1
1
  import type { ActivatableIdentifier, AutomaticAdvantageDisadvantage } from "@optolith/database-schema/gen";
2
+ import type { StdReader } from "../env.js";
2
3
  import type { CountInstances, GetAllChildInstancesForParent, GetInstanceById } from "../helpers/getTypes.js";
3
4
  import { type GetResolvedSelectOptionById } from "./partial/prerequisites/single/activatable.js";
4
- import { type StdReader } from "./partial/reader.js";
5
5
  /**
6
6
  * Render the names of commonness-rated advantages and disadvantages together.
7
7
  */
@@ -12,7 +12,7 @@ import { renderCommonnessRatedAdvantagesOrDisadvantages } from "./partial/common
12
12
  import { attributedCustomName, attributedName, attributedNameFromTranslation, } from "./partial/markdown.js";
13
13
  import { joinPrerequisiteParts } from "./partial/prerequisites/part.js";
14
14
  import { printActivatableName, } from "./partial/prerequisites/single/activatable.js";
15
- import { getInstanceByIdR, translateMapR, } from "./partial/reader.js";
15
+ import { getInstanceByIdR, translateMapR } from "./partial/reader.js";
16
16
  import { MISSING_VALUE } from "./partial/unknown.js";
17
17
  const renderBaseValues = (values) => Reader.traverse(Object.entries(values), ([id, { value }]) => getInstanceByIdR("DerivedCharacteristic", id).thenW(derivedCharacteristic => translateMapR(derivedCharacteristic?.translations).thenW(translation => Reader.asks(({ translate }) => [
18
18
  derivedCharacteristic?.position ?? 0,
@@ -90,24 +90,28 @@ const renderVariantValues = (label, variants, selector, renderValue, translation
90
90
  return undefined;
91
91
  }
92
92
  });
93
- const renderAutomaticAdvantagesOrDisadvantages = (entity, items, emptyString) => Reader.asks(({ translate, translateMap, getInstanceById, getResolvedSelectOptionById, localeCompare }) => items === undefined || !isNotEmpty(items)
94
- ? emptyString
95
- : joinPrerequisiteParts(translate, translateMap, localeCompare, items
96
- .map(item => printActivatableName(getInstanceById, translate, Case(entity, item.id), item.options, item.level, getResolvedSelectOptionById, true))
97
- .filter(isNotNullish)
98
- .map(nameComponents => ({
93
+ const renderAutomaticAdvantagesOrDisadvantages = (entity, items, emptyString) => items === undefined || !isNotEmpty(items)
94
+ ? Reader.of(emptyString)
95
+ : Reader.traverse(items, (item) => printActivatableName(Case(entity, item.id), item.options, item.level).with(env => ({
96
+ ...env,
97
+ displayedInProfession: true,
98
+ })))
99
+ .map(renderedItems => renderedItems.filter(isNotNullish).map(nameComponents => ({
99
100
  type: "activatable",
100
101
  part: { value: nameComponents, sentenceType: undefined, isMeta: false },
101
- }))));
102
+ })))
103
+ .thenW(joinPrerequisiteParts);
102
104
  /**
103
105
  * Render the names of commonness-rated advantages and disadvantages together.
104
106
  */
105
- export const renderAutomaticAdvantagesAndDisadvantages = (advantages, disadvantages, emptyString) => Reader.asks(({ translate, translateMap, getInstanceById, getResolvedSelectOptionById, localeCompare }) => mapNullable(ensureNonEmpty([["Advantage", advantages], ["Disadvantage", disadvantages]].flatMap(([entity, items]) => items
106
- ?.map(item => printActivatableName(getInstanceById, translate, Case(entity, item.id), item.options, item.level, getResolvedSelectOptionById, true))
107
- .filter(isNotNullish) ?? [])), renderedItems => joinPrerequisiteParts(translate, translateMap, localeCompare, renderedItems.map(nameComponents => ({
107
+ export const renderAutomaticAdvantagesAndDisadvantages = (advantages, disadvantages, emptyString) => Reader.traverse([["Advantage", advantages], ["Disadvantage", disadvantages]], ([entity, items]) => Reader.traverse(items ?? [], (item) => printActivatableName(Case(entity, item.id), item.options, item.level).with(env => ({
108
+ ...env,
109
+ displayedInProfession: true,
110
+ })))
111
+ .map(renderedItems => renderedItems.filter(isNotNullish))).thenW((items) => mapNullable(ensureNonEmpty(items.flat()), safeItems => joinPrerequisiteParts(safeItems.map(nameComponents => ({
108
112
  type: "activatable",
109
113
  part: { value: nameComponents, sentenceType: undefined, isMeta: false },
110
- })))) ?? emptyString);
114
+ })))) ?? Reader.of(emptyString));
111
115
  const renderCommonCultures = (items) => Reader.asks(({ translate, translateMap, getInstanceById, localeCompare }) => items === undefined || !isNotEmpty(items)
112
116
  ? translate("none")
113
117
  : items
@@ -604,6 +604,7 @@ export const getAnimistPowerEntityDescription = createEntityDescriptionCreator((
604
604
  format,
605
605
  getInstanceById,
606
606
  localeJoin: locale.join,
607
+ localeCompare: locale.compare,
607
608
  energyUnit: "ArcaneEnergy",
608
609
  responsiveTextSize: ResponsiveTextSize.Full,
609
610
  };
@@ -611,7 +612,7 @@ export const getAnimistPowerEntityDescription = createEntityDescriptionCreator((
611
612
  const levels = entry.levels?.length ?? 1;
612
613
  const prerequisites = entry.prerequisites === undefined
613
614
  ? undefined
614
- : printAnimistPowerPrerequisites(getInstanceById, locale, entry.prerequisites);
615
+ : printAnimistPowerPrerequisites(entry.prerequisites).run(env);
615
616
  const additionalEffectsFromLevels = entry.levels
616
617
  ?.map(level => translateMap(level.translations)?.effect)
617
618
  .filter(isNotNullish)
@@ -690,7 +691,9 @@ export const getGeodeRitualEntityDescription = createEntityDescriptionCreator(({
690
691
  translateMap,
691
692
  format,
692
693
  getInstanceById,
694
+ getResolvedSelectOptionById,
693
695
  localeJoin: locale.join,
696
+ localeCompare: locale.compare,
694
697
  energyUnit: "ArcaneEnergy",
695
698
  responsiveTextSize: ResponsiveTextSize.Full,
696
699
  };
@@ -721,7 +724,7 @@ export const getGeodeRitualEntityDescription = createEntityDescriptionCreator(({
721
724
  ? undefined
722
725
  : {
723
726
  label: translate("Prerequisites"),
724
- value: printGeodeRitualPrerequisites(getInstanceById, getResolvedSelectOptionById, locale, entry.prerequisites),
727
+ value: printGeodeRitualPrerequisites(entry.prerequisites).run(env),
725
728
  },
726
729
  renderProperty(entry.property).run(env),
727
730
  {
package/lib/env.d.ts ADDED
@@ -0,0 +1,66 @@
1
+ import type { AnyNonNullish } from "@elyukai/utils/nullable";
2
+ import type { Reader } from "@elyukai/utils/reader";
3
+ import type { ChildEntityMap, EntityMap } from "@optolith/database-schema/gen";
4
+ import type { GetResolvedSelectOptionById } from "./entities/partial/prerequisites/single/activatable.js";
5
+ import type { ModifiableParameter } from "./entities/partial/rated/activatable/nonModifiableSuffix.js";
6
+ import type { Speed } from "./entities/partial/rated/activatable/speed.js";
7
+ import type { ResponsiveTextSize } from "./entities/partial/responsiveText.js";
8
+ import { type EnergyUnit } from "./entities/partial/units/energy.js";
9
+ import type { GetAllChildInstancesForParent, GetAllInstances, GetInstanceById } from "./helpers/getTypes.js";
10
+ import type { FormatNumber, LocaleCompare, LocaleJoin } from "./helpers/locale.js";
11
+ import type { Format, Translate, TranslateMap, TranslationKeysWithoutParams } from "./helpers/translate.js";
12
+ import type { PublicationOptions } from "./references/publicationOptions.js";
13
+ /**
14
+ * The standard set of environment properties for readers in this project.
15
+ */
16
+ export type EnvMap<E extends keyof EntityMap = never, AE extends keyof EntityMap = never, CE extends keyof ChildEntityMap = never> = {
17
+ format: Format;
18
+ formatNumber: FormatNumber;
19
+ translate: Translate;
20
+ translateMap: TranslateMap;
21
+ localeJoin: LocaleJoin;
22
+ localeCompare: LocaleCompare;
23
+ responsiveTextSize: ResponsiveTextSize;
24
+ speed: Speed;
25
+ energyUnit: EnergyUnit;
26
+ nonModifiableSuffix?: (param: ModifiableParameter) => TranslationKeysWithoutParams;
27
+ getInstanceById: GetInstanceById<E>;
28
+ getAllInstances: GetAllInstances<AE>;
29
+ getChildInstancesForInstanceId: GetAllChildInstancesForParent<CE>;
30
+ getResolvedSelectOptionById: GetResolvedSelectOptionById;
31
+ publicationOptions: PublicationOptions;
32
+ displayedInProfession: boolean;
33
+ };
34
+ /**
35
+ * Shortcuts for selecting keys of the shared environment map type.
36
+ */
37
+ export type EnvMapAbbr = {
38
+ f: "format";
39
+ fn: "formatNumber";
40
+ t: "translate";
41
+ tm: "translateMap";
42
+ lj: "localeJoin";
43
+ lc: "localeCompare";
44
+ rts: "responsiveTextSize";
45
+ s: "speed";
46
+ eu: "energyUnit";
47
+ nms: "nonModifiableSuffix";
48
+ ibi: "getInstanceById";
49
+ ai: "getAllInstances";
50
+ acibp: "getChildInstancesForInstanceId";
51
+ rso: "getResolvedSelectOptionById";
52
+ po: "publicationOptions";
53
+ dip: "displayedInProfession";
54
+ };
55
+ /**
56
+ * The standard set of environment properties for readers in this project.
57
+ *
58
+ * The keys are abbreviated to keep type annotations short.
59
+ */
60
+ export type StdEnv<K extends keyof EnvMapAbbr = keyof EnvMapAbbr, E extends keyof EntityMap = never, AE extends keyof EntityMap = never, CE extends keyof ChildEntityMap = never> = Pick<EnvMap<E, AE, CE>, EnvMapAbbr[K]>;
61
+ /**
62
+ * Shortcut for a reader with common environment properties.
63
+ *
64
+ * The keys are abbreviated to keep return type annotations short.
65
+ */
66
+ export type StdReader<T, K extends keyof EnvMapAbbr, E extends keyof EntityMap = never, AE extends keyof EntityMap = never, CE extends keyof ChildEntityMap = never, EX = AnyNonNullish> = Reader<StdEnv<K, E, AE, CE> & EX, T>;
package/lib/env.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -1,5 +1,5 @@
1
1
  import type { Publication, Publication_ID, PublicationRefs } from "@optolith/database-schema/gen";
2
- import type { StdReader } from "../entities/partial/reader.js";
2
+ import type { StdReader } from "../env.js";
3
3
  import type { GetInstanceById } from "../helpers/getTypes.js";
4
4
  import type { TranslateMap } from "../helpers/translate.js";
5
5
  /**