@optolith/database-schema 0.112.0 → 0.113.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/gen/types.d.ts +21 -0
- package/lib/cache/activatableSelectOptions.js +16 -16
- package/lib/cache/newApplicationsAndUses.d.ts +3 -1
- package/lib/cache/newApplicationsAndUses.js +15 -7
- package/lib/types/Settings.d.ts +4 -0
- package/lib/types/Settings.js +18 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [0.113.1](https://github.com/Optolith/database-schema/compare/v0.113.0...v0.113.1) (2026-10-26)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
* **cache:** missing sources for derived select options ([68347f2](https://github.com/Optolith/database-schema/commit/68347f21f6adfc62b4c755b4bc1ad5b8db0a543e))
|
|
10
|
+
|
|
11
|
+
## [0.113.0](https://github.com/Optolith/database-schema/compare/v0.112.0...v0.113.0) (2026-10-26)
|
|
12
|
+
|
|
13
|
+
### ⚠ BREAKING CHANGES
|
|
14
|
+
|
|
15
|
+
* pin enhancement focus rules in settings
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* **cache:** include parent source refs in new applications and uses ([26a0c1a](https://github.com/Optolith/database-schema/commit/26a0c1a959dd7c5ced909cee03a13be67174cc5b))
|
|
20
|
+
* pin enhancement focus rules in settings ([711a7d5](https://github.com/Optolith/database-schema/commit/711a7d5ac1f008e0d684cb4a8e94c7c9209eae8a))
|
|
21
|
+
|
|
5
22
|
## [0.112.0](https://github.com/Optolith/database-schema/compare/v0.111.1...v0.112.0) (2026-10-24)
|
|
6
23
|
|
|
7
24
|
### ⚠ BREAKING CHANGES
|
package/gen/types.d.ts
CHANGED
|
@@ -686,6 +686,7 @@ export type TypeAliasMap = {
|
|
|
686
686
|
EnergyType: EnergyType
|
|
687
687
|
EnhancementPrerequisite: EnhancementPrerequisite
|
|
688
688
|
EnhancementPrerequisites: EnhancementPrerequisites
|
|
689
|
+
EnhancementsSettings: EnhancementsSettings
|
|
689
690
|
EquipmentPackageItem: EquipmentPackageItem
|
|
690
691
|
EquipmentPrerequisites: EquipmentPrerequisites
|
|
691
692
|
Errata: Errata
|
|
@@ -29260,6 +29261,11 @@ export interface Settings {
|
|
|
29260
29261
|
*/
|
|
29261
29262
|
styles: StyleSpecialAbilitySettings
|
|
29262
29263
|
|
|
29264
|
+
/**
|
|
29265
|
+
* Spell and Liturgical Chant Enhancements are part of focus rules. This type defines which focus rule must be enabled in order to use an enhancement. Essentially, this is a default prerequisite they must meet, but manually inserting them with every enhancement is a lot of work and error-prone. Therefore, in order to use an enhancement, prerequisites for the respective focus rule must be generated for every entry.
|
|
29266
|
+
*/
|
|
29267
|
+
enhancements: EnhancementsSettings
|
|
29268
|
+
|
|
29263
29269
|
/**
|
|
29264
29270
|
* The publication that extends the description of books with additional information.
|
|
29265
29271
|
*/
|
|
@@ -29341,6 +29347,21 @@ export interface StyleSpecialAbilitySettings {
|
|
|
29341
29347
|
liturgical: FocusRule_ID
|
|
29342
29348
|
}
|
|
29343
29349
|
|
|
29350
|
+
/**
|
|
29351
|
+
* Spell and Liturgical Chant Enhancements are part of focus rules. This type defines which focus rule must be enabled in order to use an enhancement. Essentially, this is a default prerequisite they must meet, but manually inserting them with every enhancement is a lot of work and error-prone. Therefore, in order to use an enhancement, prerequisites for the respective focus rule must be generated for every entry.
|
|
29352
|
+
*/
|
|
29353
|
+
export interface EnhancementsSettings {
|
|
29354
|
+
/**
|
|
29355
|
+
* The focus rule for spell enhancements.
|
|
29356
|
+
*/
|
|
29357
|
+
spell: FocusRule_ID
|
|
29358
|
+
|
|
29359
|
+
/**
|
|
29360
|
+
* The focus rule for liturgical chant enhancements.
|
|
29361
|
+
*/
|
|
29362
|
+
liturgicalChant: FocusRule_ID
|
|
29363
|
+
}
|
|
29364
|
+
|
|
29344
29365
|
export interface SexPractice {
|
|
29345
29366
|
/**
|
|
29346
29367
|
* References to where in which publications this entry has been defined. Entries may also be added or removed in later printings.
|
|
@@ -102,11 +102,12 @@ const getApValueForSkillish = (config, id, ic) => {
|
|
|
102
102
|
return assertExhaustive(config);
|
|
103
103
|
}
|
|
104
104
|
};
|
|
105
|
-
const convertSkillApplicationOrUse = (entryId, id, applicationOrUse) => ({
|
|
105
|
+
const convertSkillApplicationOrUse = (entryId, id, applicationOrUse, src) => ({
|
|
106
106
|
id: `${fromUniformCase(entryId)}+${applicationOrUse.id.toFixed()}`,
|
|
107
107
|
content: {
|
|
108
108
|
parent: entryId,
|
|
109
109
|
skills: [id],
|
|
110
|
+
src,
|
|
110
111
|
translations: applicationOrUse.translations,
|
|
111
112
|
},
|
|
112
113
|
});
|
|
@@ -131,7 +132,7 @@ const getSpellworkFilter = (category) => {
|
|
|
131
132
|
}
|
|
132
133
|
});
|
|
133
134
|
};
|
|
134
|
-
const getDerivedSkillishSelectOptions = (database, entryId, entity, category, options, filter) => {
|
|
135
|
+
const getDerivedSkillishSelectOptions = (database, entryId, entity, category, options, filter, parentSrc) => {
|
|
135
136
|
const { prerequisites } = category;
|
|
136
137
|
const { bindingCost, ap_value } = options;
|
|
137
138
|
const instances = database.getAllInstanceContainersOfEntity(entity);
|
|
@@ -150,13 +151,12 @@ const getDerivedSkillishSelectOptions = (database, entryId, entity, category, op
|
|
|
150
151
|
name: t10n.name,
|
|
151
152
|
})),
|
|
152
153
|
},
|
|
153
|
-
newApplications: category.skill_applications?.map(app => convertSkillApplicationOrUse(entryId, id, app)) ??
|
|
154
|
-
|
|
155
|
-
uses: category.skill_uses?.map(use => convertSkillApplicationOrUse(entryId, id, use)) ?? [],
|
|
154
|
+
newApplications: category.skill_applications?.map(app => convertSkillApplicationOrUse(entryId, id, app, parentSrc)) ?? [],
|
|
155
|
+
uses: category.skill_uses?.map(use => convertSkillApplicationOrUse(entryId, id, use, parentSrc)) ?? [],
|
|
156
156
|
};
|
|
157
157
|
});
|
|
158
158
|
};
|
|
159
|
-
const getDerivedSelectOptions = (selectOptionCategory, entryId, database) => {
|
|
159
|
+
const getDerivedSelectOptions = (selectOptionCategory, entryId, database, parentSrc) => {
|
|
160
160
|
switch (selectOptionCategory.kind) {
|
|
161
161
|
case "Blessings":
|
|
162
162
|
return database
|
|
@@ -685,15 +685,15 @@ const getDerivedSelectOptions = (selectOptionCategory, entryId, database) => {
|
|
|
685
685
|
const matchesIdRequirement = category.Skills.specific === undefined ||
|
|
686
686
|
matchesSpecificSkillishIdList(category.Skills.specific, required => required === id);
|
|
687
687
|
return matchesGroupRequirement && matchesIdRequirement;
|
|
688
|
-
});
|
|
688
|
+
}, parentSrc);
|
|
689
689
|
case "Spells":
|
|
690
|
-
return getDerivedSkillishSelectOptions(database, entryId, "Spell", category.Spells, selectOptionCategory.Skills, getSpellworkFilter(category.Spells));
|
|
690
|
+
return getDerivedSkillishSelectOptions(database, entryId, "Spell", category.Spells, selectOptionCategory.Skills, getSpellworkFilter(category.Spells), parentSrc);
|
|
691
691
|
case "Rituals":
|
|
692
|
-
return getDerivedSkillishSelectOptions(database, entryId, "Ritual", category.Rituals, selectOptionCategory.Skills, getSpellworkFilter(category.Rituals));
|
|
692
|
+
return getDerivedSkillishSelectOptions(database, entryId, "Ritual", category.Rituals, selectOptionCategory.Skills, getSpellworkFilter(category.Rituals), parentSrc);
|
|
693
693
|
case "LiturgicalChants":
|
|
694
|
-
return getDerivedSkillishSelectOptions(database, entryId, "LiturgicalChant", category.LiturgicalChants, selectOptionCategory.Skills, getDefaultSkillishFilter(category.LiturgicalChants));
|
|
694
|
+
return getDerivedSkillishSelectOptions(database, entryId, "LiturgicalChant", category.LiturgicalChants, selectOptionCategory.Skills, getDefaultSkillishFilter(category.LiturgicalChants), parentSrc);
|
|
695
695
|
case "Ceremonies":
|
|
696
|
-
return getDerivedSkillishSelectOptions(database, entryId, "Ceremony", category.Ceremonies, selectOptionCategory.Skills, getDefaultSkillishFilter(category.Ceremonies));
|
|
696
|
+
return getDerivedSkillishSelectOptions(database, entryId, "Ceremony", category.Ceremonies, selectOptionCategory.Skills, getDefaultSkillishFilter(category.Ceremonies), parentSrc);
|
|
697
697
|
default:
|
|
698
698
|
return assertExhaustive(category);
|
|
699
699
|
}
|
|
@@ -702,9 +702,9 @@ const getDerivedSelectOptions = (selectOptionCategory, entryId, database) => {
|
|
|
702
702
|
return selectOptionCategory.CombatTechniques.categories.flatMap(category => {
|
|
703
703
|
switch (category.kind) {
|
|
704
704
|
case "CloseCombatTechniques":
|
|
705
|
-
return getDerivedSkillishSelectOptions(database, entryId, "CloseCombatTechnique", category.CloseCombatTechniques, selectOptionCategory.CombatTechniques, getDefaultSkillishFilter(category.CloseCombatTechniques));
|
|
705
|
+
return getDerivedSkillishSelectOptions(database, entryId, "CloseCombatTechnique", category.CloseCombatTechniques, selectOptionCategory.CombatTechniques, getDefaultSkillishFilter(category.CloseCombatTechniques), parentSrc);
|
|
706
706
|
case "RangedCombatTechniques":
|
|
707
|
-
return getDerivedSkillishSelectOptions(database, entryId, "RangedCombatTechnique", category.RangedCombatTechniques, selectOptionCategory.CombatTechniques, getDefaultSkillishFilter(category.RangedCombatTechniques));
|
|
707
|
+
return getDerivedSkillishSelectOptions(database, entryId, "RangedCombatTechnique", category.RangedCombatTechniques, selectOptionCategory.CombatTechniques, getDefaultSkillishFilter(category.RangedCombatTechniques), parentSrc);
|
|
708
708
|
default:
|
|
709
709
|
return assertExhaustive(category);
|
|
710
710
|
}
|
|
@@ -787,14 +787,14 @@ const getExplicitSelectOptions = (id, database) => database
|
|
|
787
787
|
newApplications: [], // database.getAllChildInstanceContainersForParent("NewSkillApplication", Case("GeneralSelectOption", id)), // prevent duplicates as these can already be queried from the database
|
|
788
788
|
uses: [], // database.getAllChildInstanceContainersForParent("SkillUse", Case("GeneralSelectOption", id)), // prevent duplicates as these can already be queried from the database
|
|
789
789
|
}));
|
|
790
|
-
const getSelectOptions = (selectOptions, id, database) => [
|
|
790
|
+
const getSelectOptions = (selectOptions, id, database, parentSrc) => [
|
|
791
791
|
...(selectOptions.derived === undefined
|
|
792
792
|
? []
|
|
793
|
-
: getDerivedSelectOptions(selectOptions.derived, id, database)),
|
|
793
|
+
: getDerivedSelectOptions(selectOptions.derived, id, database, parentSrc)),
|
|
794
794
|
...getExplicitSelectOptions(id, database),
|
|
795
795
|
];
|
|
796
796
|
const getSelectOptionsForResults = (database, entity, results) => results.reduce((acc, { id, content }) => {
|
|
797
|
-
const options = getSelectOptions(content.select_options ?? {}, Case(entity, id), database);
|
|
797
|
+
const options = getSelectOptions(content.select_options ?? {}, Case(entity, id), database, content.src);
|
|
798
798
|
if (options.length > 0) {
|
|
799
799
|
acc[id] = options;
|
|
800
800
|
}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import type { ActivatableIdentifier, NewSkillApplication, NewSkillApplicationOrUseParentIdentifier, Skill_ID, SkillUse } from "../../gen/types.js";
|
|
1
|
+
import type { ActivatableIdentifier, NewSkillApplication, NewSkillApplicationOrUseParentIdentifier, PublicationRefs, Skill_ID, SkillUse } from "../../gen/types.js";
|
|
2
2
|
import type { ActivatableSelectOptionsCache } from "./activatableSelectOptions.ts";
|
|
3
3
|
import type { CacheBuilder } from "./internal.ts";
|
|
4
4
|
export type ResolvedNewSkillApplication = {
|
|
5
5
|
id: string;
|
|
6
6
|
content: Omit<NewSkillApplication, "parent"> & {
|
|
7
7
|
parent: NewSkillApplicationOrUseParentIdentifier | ActivatableIdentifier;
|
|
8
|
+
src: PublicationRefs | undefined;
|
|
8
9
|
};
|
|
9
10
|
};
|
|
10
11
|
export type ResolvedSkillUse = {
|
|
11
12
|
id: string;
|
|
12
13
|
content: Omit<SkillUse, "parent"> & {
|
|
13
14
|
parent: NewSkillApplicationOrUseParentIdentifier | ActivatableIdentifier;
|
|
15
|
+
src: PublicationRefs | undefined;
|
|
14
16
|
};
|
|
15
17
|
};
|
|
16
18
|
export type NewApplicationsAndUsesCache = {
|
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
const groupByAffectedSkill = (entries, prev = {}) => entries
|
|
1
|
+
const groupByAffectedSkill = (database, entries, prev = {}) => entries
|
|
2
|
+
.map(entry => ({
|
|
3
|
+
...entry,
|
|
4
|
+
content: {
|
|
5
|
+
...entry.content,
|
|
6
|
+
src: database.getInstanceOfEntityById(entry.content.parent)?.src,
|
|
7
|
+
},
|
|
8
|
+
}))
|
|
9
|
+
.reduce((acc, entry) => entry.content.skills.reduce((acc1, skillId) => {
|
|
2
10
|
acc1[skillId] = [...(acc1[skillId] ?? []), entry];
|
|
3
11
|
return acc1;
|
|
4
12
|
}, acc), prev);
|
|
5
|
-
const addGeneratedEntries = (generatedSelectOptions, prev) => Object.values(generatedSelectOptions).reduce((acc, byInstance) => Object.values(byInstance).reduce((acc1, resolvedSelectOptions) => resolvedSelectOptions.reduce((acc2, selectOption) => ({
|
|
6
|
-
newApplications: groupByAffectedSkill(selectOption.newApplications, acc2.newApplications),
|
|
7
|
-
uses: groupByAffectedSkill(selectOption.uses, acc2.uses),
|
|
13
|
+
const addGeneratedEntries = (database, generatedSelectOptions, prev) => Object.values(generatedSelectOptions).reduce((acc, byInstance) => Object.values(byInstance).reduce((acc1, resolvedSelectOptions) => resolvedSelectOptions.reduce((acc2, selectOption) => ({
|
|
14
|
+
newApplications: groupByAffectedSkill(database, selectOption.newApplications, acc2.newApplications),
|
|
15
|
+
uses: groupByAffectedSkill(database, selectOption.uses, acc2.uses),
|
|
8
16
|
}), acc1), acc), prev);
|
|
9
17
|
export const buildNewApplicationsAndUsesCache = (database, _idMap, generatedSelectOptions) => {
|
|
10
18
|
const cache = {
|
|
11
|
-
newApplications: groupByAffectedSkill(database.getAllInstanceContainersOfEntity("NewSkillApplication")),
|
|
12
|
-
uses: groupByAffectedSkill(database.getAllInstanceContainersOfEntity("SkillUse")),
|
|
19
|
+
newApplications: groupByAffectedSkill(database, database.getAllInstanceContainersOfEntity("NewSkillApplication")),
|
|
20
|
+
uses: groupByAffectedSkill(database, database.getAllInstanceContainersOfEntity("SkillUse")),
|
|
13
21
|
};
|
|
14
|
-
return addGeneratedEntries(generatedSelectOptions, cache);
|
|
22
|
+
return addGeneratedEntries(database, generatedSelectOptions, cache);
|
|
15
23
|
};
|
package/lib/types/Settings.d.ts
CHANGED
|
@@ -186,6 +186,10 @@ export declare const Settings: DB.SingletonEntity<"Settings", {
|
|
|
186
186
|
magic: DB.MemberDecl<DB.ReferenceIdentifier, true>;
|
|
187
187
|
liturgical: DB.MemberDecl<DB.ReferenceIdentifier, true>;
|
|
188
188
|
}>, []>>, true>;
|
|
189
|
+
enhancements: DB.MemberDecl<DB.IncludeIdentifier<[], DB.TypeAlias<"EnhancementsSettings", DB.Object<{
|
|
190
|
+
spell: DB.MemberDecl<DB.ReferenceIdentifier, true>;
|
|
191
|
+
liturgicalChant: DB.MemberDecl<DB.ReferenceIdentifier, true>;
|
|
192
|
+
}>, []>>, true>;
|
|
189
193
|
extendedBookDescriptionPublication: DB.MemberDecl<DB.ReferenceIdentifier, true>;
|
|
190
194
|
maximumSkillRatingBonusEntry: DB.MemberDecl<DB.IncludeIdentifier<[], DB.Enum<"ActivatableIdentifier", {
|
|
191
195
|
Adoruzepterzauber: DB.EnumCase<DB.ReferenceIdentifier>;
|
package/lib/types/Settings.js
CHANGED
|
@@ -27,6 +27,10 @@ export const Settings = DB.SingletonEntity(import.meta.url, {
|
|
|
27
27
|
comment: StyleSpecialAbilitySettings.comment,
|
|
28
28
|
type: DB.IncludeIdentifier(StyleSpecialAbilitySettings),
|
|
29
29
|
}),
|
|
30
|
+
enhancements: DB.Required({
|
|
31
|
+
comment: EnhancementsSettings.comment,
|
|
32
|
+
type: DB.IncludeIdentifier(EnhancementsSettings),
|
|
33
|
+
}),
|
|
30
34
|
extendedBookDescriptionPublication: DB.Required({
|
|
31
35
|
comment: "The publication that extends the description of books with additional information.",
|
|
32
36
|
type: PublicationIdentifier(),
|
|
@@ -103,3 +107,17 @@ const StyleSpecialAbilitySettings = DB.TypeAlias(import.meta.url, {
|
|
|
103
107
|
}),
|
|
104
108
|
}),
|
|
105
109
|
});
|
|
110
|
+
const EnhancementsSettings = DB.TypeAlias(import.meta.url, {
|
|
111
|
+
name: "EnhancementsSettings",
|
|
112
|
+
comment: "Spell and Liturgical Chant Enhancements are part of focus rules. This type defines which focus rule must be enabled in order to use an enhancement. Essentially, this is a default prerequisite they must meet, but manually inserting them with every enhancement is a lot of work and error-prone. Therefore, in order to use an enhancement, prerequisites for the respective focus rule must be generated for every entry.",
|
|
113
|
+
type: () => DB.Object({
|
|
114
|
+
spell: DB.Required({
|
|
115
|
+
comment: "The focus rule for spell enhancements.",
|
|
116
|
+
type: FocusRuleIdentifier(),
|
|
117
|
+
}),
|
|
118
|
+
liturgicalChant: DB.Required({
|
|
119
|
+
comment: "The focus rule for liturgical chant enhancements.",
|
|
120
|
+
type: FocusRuleIdentifier(),
|
|
121
|
+
}),
|
|
122
|
+
}),
|
|
123
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optolith/database-schema",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.113.1",
|
|
4
4
|
"description": "Definitions and utilities for the flat-file database of Optolith, a character creation tool for the Pen and Paper RPG “The Dark Eye 5”, and its external integrations into other software.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tde",
|