@datasworn-community/build-tools 0.2.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 (134) hide show
  1. package/README.md +17 -0
  2. package/dist/cli/args.d.ts +3 -0
  3. package/dist/cli/args.d.ts.map +1 -0
  4. package/dist/cli/args.js +10 -0
  5. package/dist/cli/args.js.map +1 -0
  6. package/dist/cli/datasworn-build.d.ts +3 -0
  7. package/dist/cli/datasworn-build.d.ts.map +1 -0
  8. package/dist/cli/datasworn-build.js +33 -0
  9. package/dist/cli/datasworn-build.js.map +1 -0
  10. package/dist/cli/datasworn-migrate.d.ts +3 -0
  11. package/dist/cli/datasworn-migrate.d.ts.map +1 -0
  12. package/dist/cli/datasworn-migrate.js +26 -0
  13. package/dist/cli/datasworn-migrate.js.map +1 -0
  14. package/dist/config.d.ts +3 -0
  15. package/dist/config.d.ts.map +1 -0
  16. package/dist/config.js +10 -0
  17. package/dist/config.js.map +1 -0
  18. package/dist/index.d.ts +4 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +4 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/rules-package-builder.d.ts +22 -0
  23. package/dist/rules-package-builder.d.ts.map +1 -0
  24. package/dist/rules-package-builder.js +84 -0
  25. package/dist/rules-package-builder.js.map +1 -0
  26. package/dist/schema.d.ts +8 -0
  27. package/dist/schema.d.ts.map +1 -0
  28. package/dist/schema.js +18 -0
  29. package/dist/schema.js.map +1 -0
  30. package/dist/validators.d.ts +8 -0
  31. package/dist/validators.d.ts.map +1 -0
  32. package/dist/validators.js +35 -0
  33. package/dist/validators.js.map +1 -0
  34. package/package.json +60 -0
  35. package/schema-source/schema/Assets.ts +66 -0
  36. package/schema-source/schema/Atlas.ts +20 -0
  37. package/schema-source/schema/Defs.ts +126 -0
  38. package/schema-source/schema/DelveSites.ts +3 -0
  39. package/schema-source/schema/Entities.ts +1 -0
  40. package/schema-source/schema/Generic.ts +18 -0
  41. package/schema-source/schema/Moves.ts +1 -0
  42. package/schema-source/schema/Npcs.ts +80 -0
  43. package/schema-source/schema/Oracles.ts +20 -0
  44. package/schema-source/schema/Rarities.ts +36 -0
  45. package/schema-source/schema/Root.ts +94 -0
  46. package/schema-source/schema/Rules.ts +61 -0
  47. package/schema-source/schema/RulesPackages.ts +135 -0
  48. package/schema-source/schema/Symbols.ts +30 -0
  49. package/schema-source/schema/Truths.ts +53 -0
  50. package/schema-source/schema/Utils.ts +21 -0
  51. package/schema-source/schema/assets/Ability.ts +79 -0
  52. package/schema-source/schema/assets/Enhancement.ts +62 -0
  53. package/schema-source/schema/assets/Fields.ts +285 -0
  54. package/schema-source/schema/assets/common.ts +29 -0
  55. package/schema-source/schema/common/Fields.ts +327 -0
  56. package/schema-source/schema/common/Id.ts +64 -0
  57. package/schema-source/schema/common/Inputs.ts +374 -0
  58. package/schema-source/schema/common/Metadata.ts +142 -0
  59. package/schema-source/schema/common/Player.ts +17 -0
  60. package/schema-source/schema/common/Progress.ts +63 -0
  61. package/schema-source/schema/common/Range.ts +53 -0
  62. package/schema-source/schema/common/RollableValues.ts +152 -0
  63. package/schema-source/schema/common/Rolls.ts +108 -0
  64. package/schema-source/schema/common/Text.ts +95 -0
  65. package/schema-source/schema/common/index.ts +16 -0
  66. package/schema-source/schema/delve/DelveSite.ts +121 -0
  67. package/schema-source/schema/delve/DelveSiteDomain.ts +136 -0
  68. package/schema-source/schema/delve/DelveSiteTheme.ts +97 -0
  69. package/schema-source/schema/delve/common.ts +32 -0
  70. package/schema-source/schema/entities/EntityPrompt.ts +13 -0
  71. package/schema-source/schema/entities/index.ts +1 -0
  72. package/schema-source/schema/generic/CollectableNode.ts +75 -0
  73. package/schema-source/schema/generic/CollectionNode.ts +145 -0
  74. package/schema-source/schema/generic/Dictionary.ts +39 -0
  75. package/schema-source/schema/generic/EmbedOnlyNode.ts +19 -0
  76. package/schema-source/schema/generic/Enhance.ts +38 -0
  77. package/schema-source/schema/generic/IdNode.ts +40 -0
  78. package/schema-source/schema/generic/Mixin.ts +11 -0
  79. package/schema-source/schema/generic/NonCollectableNode.ts +38 -0
  80. package/schema-source/schema/generic/PrimaryTypeNode.ts +115 -0
  81. package/schema-source/schema/generic/SourcedNode.ts +51 -0
  82. package/schema-source/schema/index.ts +23 -0
  83. package/schema-source/schema/moves/ActionRoll.ts +152 -0
  84. package/schema-source/schema/moves/EmbeddedMove.ts +24 -0
  85. package/schema-source/schema/moves/Move.ts +26 -0
  86. package/schema-source/schema/moves/MoveCategory.ts +6 -0
  87. package/schema-source/schema/moves/MoveEnhancement.ts +29 -0
  88. package/schema-source/schema/moves/ProgressRoll.ts +184 -0
  89. package/schema-source/schema/moves/Trigger.ts +193 -0
  90. package/schema-source/schema/moves/common.ts +136 -0
  91. package/schema-source/schema/moves/index.ts +13 -0
  92. package/schema-source/schema/moves/utils.ts +132 -0
  93. package/schema-source/schema/object_type/ObjectType.ts +23 -0
  94. package/schema-source/schema/oracles/EmbeddedOracleRollable.ts +28 -0
  95. package/schema-source/schema/oracles/OracleCollection.ts +140 -0
  96. package/schema-source/schema/oracles/OracleRollable.ts +207 -0
  97. package/schema-source/schema/oracles/Table.ts +94 -0
  98. package/schema-source/schema/oracles/TableRow.ts +141 -0
  99. package/schema-source/schema/root/NiceSchema.ts +15 -0
  100. package/schema-source/schema/root/Root.ts +41 -0
  101. package/schema-source/schema/root/SchemaTransform.ts +89 -0
  102. package/schema-source/schema/root/SourceData.ts +151 -0
  103. package/schema-source/schema/rules/ConditionMeterRule.ts +25 -0
  104. package/schema-source/schema/rules/ImpactRule.ts +54 -0
  105. package/schema-source/schema/rules/SpecialTrackRule.ts +29 -0
  106. package/schema-source/schema/rules/StatRule.ts +23 -0
  107. package/schema-source/schema/rules/TagRule.ts +176 -0
  108. package/schema-source/schema/rules/TagSchema.ts +161 -0
  109. package/schema-source/schema/tags/canonicalTags.ts +29 -0
  110. package/schema-source/schema/tools/build/index.ts +48 -0
  111. package/schema-source/schema/tools/i18n/index.ts +9 -0
  112. package/schema-source/schema/utils/Computed.ts +82 -0
  113. package/schema-source/schema/utils/DiscriminatedUnion.ts +255 -0
  114. package/schema-source/schema/utils/EmbeddedNode.ts +172 -0
  115. package/schema-source/schema/utils/ExtractLiteralFromEnum.ts +22 -0
  116. package/schema-source/schema/utils/FlatIntersect.ts +107 -0
  117. package/schema-source/schema/utils/IfThen.ts +50 -0
  118. package/schema-source/schema/utils/MergeEnumSchemas.ts +16 -0
  119. package/schema-source/schema/utils/NonNullable.ts +6 -0
  120. package/schema-source/schema/utils/Nullable.ts +29 -0
  121. package/schema-source/schema/utils/ObjectLiteral.ts +16 -0
  122. package/schema-source/schema/utils/ObjectProperties.ts +4 -0
  123. package/schema-source/schema/utils/OmitMeta.ts +22 -0
  124. package/schema-source/schema/utils/OmitOptional.ts +27 -0
  125. package/schema-source/schema/utils/PartialExcept.ts +26 -0
  126. package/schema-source/schema/utils/SetNullable.ts +44 -0
  127. package/schema-source/schema/utils/SetOptional.ts +48 -0
  128. package/schema-source/schema/utils/UnionEnum.ts +82 -0
  129. package/schema-source/schema/utils/UnionEnumFromRecord.ts +36 -0
  130. package/schema-source/schema/utils/UnionOneOf.ts +80 -0
  131. package/schema-source/schema/utils/generateRulesetSchemas.ts +204 -0
  132. package/schema-source/schema/utils/string.ts +15 -0
  133. package/schema-source/schema/utils/typebox.ts +141 -0
  134. package/schema-source/scripts/const.ts +55 -0
@@ -0,0 +1,97 @@
1
+ import { type Static, Type } from '@sinclair/typebox'
2
+ import { toJtdElements } from '../../scripts/json-typedef/utils.js'
3
+ import { MarkdownString } from '../common/Text.js'
4
+ import { NonCollectableNode } from '../generic/NonCollectableNode.js'
5
+ import { OracleRollableRowText, StaticRowPartial } from '../oracles/TableRow.js'
6
+ import { JsonTypeDef } from '../Symbols.js'
7
+ import { setSourceDataSchema } from '../Utils.js'
8
+ import { EmbeddedType } from './common.js'
9
+
10
+ export const DelveSiteThemeFeature = EmbeddedType(
11
+ OracleRollableRowText,
12
+ 'delve_site_theme',
13
+ 'feature',
14
+
15
+ {
16
+ description:
17
+ 'Represents a single Feature entry from a delve site Theme card.'
18
+ }
19
+ )
20
+
21
+ export const DelveSiteThemeDanger = EmbeddedType(
22
+ OracleRollableRowText,
23
+ 'delve_site_theme',
24
+ 'danger',
25
+
26
+ {
27
+ description:
28
+ 'Represents a single Danger entry from a delve site Theme card.'
29
+ }
30
+ )
31
+
32
+ const DelveSiteThemeFeatures = Type.Array(Type.Ref(DelveSiteThemeFeature))
33
+ const DelveSiteThemeDangers = Type.Array(Type.Ref(DelveSiteThemeDanger))
34
+
35
+ export const DelveSiteTheme = setSourceDataSchema(
36
+ NonCollectableNode(
37
+ Type.Object({
38
+ summary: Type.Ref(MarkdownString, {
39
+ description: 'The text that appears below the title on the card.'
40
+ }),
41
+ descriptipn: Type.Optional(
42
+ Type.Ref(MarkdownString, {
43
+ description: 'Optional extended description text.'
44
+ })
45
+ ),
46
+ features: Type.Intersect(
47
+ [
48
+ DelveSiteThemeFeatures,
49
+ Type.Tuple([
50
+ StaticRowPartial(1, 4),
51
+ StaticRowPartial(5, 8),
52
+ StaticRowPartial(9, 12),
53
+ StaticRowPartial(13, 16),
54
+ StaticRowPartial(17, 20)
55
+ ])
56
+ ],
57
+ {
58
+ [JsonTypeDef]: {
59
+ schema: toJtdElements(DelveSiteThemeFeatures)
60
+ }
61
+ }
62
+ ),
63
+ dangers: Type.Intersect(
64
+ [
65
+ DelveSiteThemeDangers,
66
+ Type.Tuple([
67
+ StaticRowPartial(1, 5),
68
+ StaticRowPartial(6, 10),
69
+ StaticRowPartial(11, 12),
70
+ StaticRowPartial(13, 14),
71
+ StaticRowPartial(15, 16),
72
+ StaticRowPartial(17, 18),
73
+ StaticRowPartial(19, 20),
74
+ StaticRowPartial(21, 22),
75
+ StaticRowPartial(23, 24),
76
+ StaticRowPartial(25, 26),
77
+ StaticRowPartial(27, 28),
78
+ StaticRowPartial(29, 30)
79
+ ])
80
+ ],
81
+ {
82
+ [JsonTypeDef]: {
83
+ schema: toJtdElements(DelveSiteThemeDangers)
84
+ }
85
+ }
86
+ )
87
+ }),
88
+ 'delve_site_theme',
89
+ {
90
+ description: 'A delve site theme card.',
91
+ $id: 'DelveSiteTheme'
92
+ }
93
+ ),
94
+ (schema) => ({ ...schema, additionalProperties: false })
95
+ )
96
+ export type DelveSiteTheme = Static<typeof DelveSiteTheme>
97
+ export type TDelveSiteTheme = typeof DelveSiteTheme
@@ -0,0 +1,32 @@
1
+ import {
2
+ CloneType,
3
+ type ObjectOptions,
4
+ type TObject,
5
+ type TString,
6
+ Type
7
+ } from '@sinclair/typebox'
8
+ import type TypeId from '../../pkg-core/IdElements/TypeId.js'
9
+ import { Computed } from '../Utils.js'
10
+ import { pascalCase } from '../utils/string.js'
11
+
12
+ export function EmbeddedType<
13
+ TBase extends TObject,
14
+ T extends TypeId.Embedding,
15
+ T2 extends TypeId.EmbeddableIn<T>
16
+ >(
17
+ base: TBase,
18
+ parentTypeId: T,
19
+ embeddedTypeId: T2,
20
+ options: ObjectOptions = {}
21
+ ) {
22
+ const schemaName = pascalCase(parentTypeId) + pascalCase(embeddedTypeId)
23
+ const idSchemaName = `${schemaName}Id`
24
+
25
+ const schema = CloneType(base, options)
26
+
27
+ schema.$id = schemaName
28
+ schema.properties._id = Computed(Type.Ref(idSchemaName))
29
+
30
+ // @ts-expect-error
31
+ return schema as TObject<TBase['properties'] & { _id: TString }>
32
+ }
@@ -0,0 +1,13 @@
1
+ import { type Static, Type } from '@sinclair/typebox'
2
+ import * as Text from '../common/Text.js'
3
+
4
+ export const EntityPrompt = Type.Object(
5
+ { text: Type.Ref(Text.MarkdownString) },
6
+ {
7
+ $id: 'EntityPrompt',
8
+ description:
9
+ 'This type is a placeholder and may see signficant changes in v0.2.0.',
10
+ releaseStage: 'experimental'
11
+ }
12
+ )
13
+ export type EntityPrompt = Static<typeof EntityPrompt>
@@ -0,0 +1 @@
1
+ export * from './EntityPrompt.js'
@@ -0,0 +1,75 @@
1
+ import { CloneType, type ObjectOptions, type TObject } from '@sinclair/typebox'
2
+ import type { SetRequired } from 'type-fest'
3
+ import type TypeId from '../../pkg-core/IdElements/TypeId.js'
4
+ import { setSourceDataSchema } from '../Utils.js'
5
+ import { pascalCase } from '../utils/string.js'
6
+ import { PrimarySubtypeNode, PrimaryTypeNode } from './PrimaryTypeNode.js'
7
+
8
+ export const CollectableBrand = Symbol('Collectable')
9
+
10
+ type TCollectableBranded<TBase extends TObject> = TBase & {
11
+ [CollectableBrand]: 'Collectable'
12
+ }
13
+
14
+ export function CollectableNode<
15
+ TBase extends TObject,
16
+ TType extends TypeId.Collectable
17
+ >(base: TBase, type: TType, options: ObjectOptions = {}) {
18
+ const $id = pascalCase(type)
19
+
20
+ const enhancedBase = PrimaryTypeNode(base, type, {
21
+ $id,
22
+ ...options,
23
+ [CollectableBrand]: 'Collectable'
24
+ })
25
+
26
+ return setSourceDataSchema(enhancedBase, (schema: TObject) => ({
27
+ ...CloneType(schema),
28
+ additionalProperties: true
29
+ })) as unknown as TCollectableNode<TBase, TType>
30
+ }
31
+
32
+ /** Simplified type to avoid deep instantiation - uses TObject as base */
33
+ export type TCollectableNode<
34
+ TBase extends TObject = TObject,
35
+ TType extends TypeId.Collectable = TypeId.Collectable
36
+ > = TObject & TCollectableBranded<TObject> & { _type: TType; _base: TBase }
37
+
38
+ export type CollectableNode<
39
+ TBase extends object,
40
+ TType extends TypeId.Collectable
41
+ > = PrimaryTypeNode<TBase, TType>
42
+
43
+ /** Simplified type to avoid deep instantiation */
44
+ export type TCollectableSubtypeNode<
45
+ TBase extends TObject = TObject,
46
+ TType extends TypeId.Collectable = TypeId.Collectable,
47
+ TSubtypeKey extends string = string,
48
+ TSubtype extends string = string
49
+ > = TCollectableNode<TBase, TType> & {
50
+ _subtypeKey: TSubtypeKey
51
+ _subtype: TSubtype
52
+ }
53
+
54
+ export function CollectableSubtypeNode<
55
+ TBase extends TObject,
56
+ TType extends TypeId.Collectable,
57
+ TSubtypeKey extends string,
58
+ TSubtype extends string
59
+ >(
60
+ base: TBase,
61
+ type: TType,
62
+ subtypeKey: TSubtypeKey,
63
+ subtype: TSubtype,
64
+ options: SetRequired<ObjectOptions, '$id'>
65
+ ) {
66
+ const enhancedBase = PrimarySubtypeNode(base, type, subtypeKey, subtype, {
67
+ ...options,
68
+ [CollectableBrand]: 'Collectable'
69
+ })
70
+
71
+ return setSourceDataSchema(enhancedBase, (schema: TObject) => ({
72
+ ...CloneType(schema),
73
+ additionalProperties: true
74
+ })) as unknown as TCollectableSubtypeNode<TBase, TType, TSubtypeKey, TSubtype>
75
+ }
@@ -0,0 +1,145 @@
1
+ import {
2
+ type ObjectOptions,
3
+ type Static,
4
+ type TObject,
5
+ type TRef,
6
+ type TRefUnsafe,
7
+ type TSchema,
8
+ type TUnion,
9
+ Type
10
+ } from '@sinclair/typebox'
11
+ import type { SetRequired } from 'type-fest'
12
+ import TypeId from '../../pkg-core/IdElements/TypeId.js'
13
+ import {
14
+ CollectionsKey,
15
+ ContentsKey,
16
+ EnhancesKey
17
+ } from '../../scripts/const.js'
18
+ import * as Text from '../common/Text.js'
19
+ import { setSourceOptional } from '../Utils.js'
20
+ import { Assign } from '../utils/FlatIntersect.js'
21
+ import { pascalCase } from '../utils/string.js'
22
+ import { Dictionary, type TDictionary } from './Dictionary.js'
23
+ import { PrimarySubtypeNode, PrimaryTypeNode } from './PrimaryTypeNode.js'
24
+
25
+ export const CollectionBrand = Symbol('Collection')
26
+
27
+ type TCollectionDictionary =
28
+ | TDictionary<TRef | TRefUnsafe<TSchema> | TUnion<TRef[]>>
29
+ | TUnion<TDictionary<TRef | TRefUnsafe<TSchema> | TUnion<TRef[]>>[]>
30
+
31
+ export function getCollectionNodeMetadata(
32
+ enhances: TRef<string>,
33
+ contentChild?: TCollectionDictionary,
34
+ collectionChild?: TCollectionDictionary
35
+ ) {
36
+ const props: Record<string, TSchema> = {
37
+ [EnhancesKey]: Type.Optional(
38
+ Type.Array(enhances, {
39
+ description:
40
+ "This node's content enhances all nodes that match these wildcards, rather than being a standalone item of its own."
41
+ })
42
+ ),
43
+ summary: Type.Optional(
44
+ Type.Ref(Text.MarkdownString, {
45
+ description:
46
+ 'A brief summary of this collection, no more than a few sentences in length. This is intended for use in application tooltips and similar sorts of hints. Longer text should use the "description" key instead.'
47
+ })
48
+ ),
49
+ description: Type.Optional(
50
+ Type.Ref(Text.MarkdownString, {
51
+ description:
52
+ "A longer description of this collection, which might include multiple paragraphs. If it's only a couple sentences, use the `summary` key instead."
53
+ })
54
+ )
55
+ }
56
+
57
+ if (contentChild != null) props[ContentsKey] = contentChild
58
+
59
+ if (collectionChild != null) props[CollectionsKey] = collectionChild
60
+
61
+ return Type.Object(props)
62
+ }
63
+
64
+ export function CollectionNode<
65
+ TBase extends TObject,
66
+ TType extends TypeId.Collection
67
+ >(base: TBase, type: TType, options: ObjectOptions = {}) {
68
+ const collectableTypeId = TypeId.getCollectableOf(type)
69
+ const collectableSchemaRef = Type.Ref(pascalCase(collectableTypeId))
70
+ const thisSchemaId = pascalCase(type)
71
+ const thisIdSchemaId = `${thisSchemaId}Id`
72
+
73
+ const thisWildcardIdRef = Type.Ref(`${thisIdSchemaId}Wildcard`)
74
+ const _thisIdRef = Type.Ref(thisIdSchemaId)
75
+ const thisSchemaRef = Type.Ref(thisSchemaId)
76
+
77
+ // Use explicit TObject casts to avoid deep type instantiation
78
+ const metadata = getCollectionNodeMetadata(
79
+ thisWildcardIdRef,
80
+ setSourceOptional(Dictionary(collectableSchemaRef)),
81
+ setSourceOptional(Dictionary(thisSchemaRef))
82
+ )
83
+ const enhancedBase: TObject = Assign(
84
+ metadata as TObject,
85
+ base as TObject
86
+ ) as TObject
87
+
88
+ return PrimaryTypeNode(enhancedBase, type, {
89
+ ...options,
90
+ $id: thisSchemaId,
91
+ [CollectionBrand]: 'Collection'
92
+ }) as unknown as TCollectionNode<TBase, TType>
93
+ }
94
+
95
+ type TCollectionMeta = ReturnType<typeof getCollectionNodeMetadata>
96
+ type CollectionMeta = Static<TCollectionMeta>
97
+
98
+ export type CollectionNode<
99
+ TBase extends object,
100
+ TType extends TypeId.Collection
101
+ > = PrimaryTypeNode<TBase & CollectionMeta, TType>
102
+
103
+ /** Simplified type to avoid deep instantiation */
104
+ export type TCollectionNode<
105
+ TBase extends TObject = TObject,
106
+ TType extends TypeId.Collection = TypeId.Collection
107
+ > = TObject & {
108
+ $id: string
109
+ [CollectionBrand]: 'Collection'
110
+ _collectionType: TType
111
+ _collectionBase: TBase
112
+ }
113
+
114
+ export function CollectionSubtypeNode<
115
+ TBase extends TObject,
116
+ TType extends TypeId.Collection,
117
+ TSubtypeKey extends string,
118
+ TSubtype extends string
119
+ >(
120
+ base: TBase,
121
+ type: TType,
122
+ subtypeKey: TSubtypeKey,
123
+ subtype: TSubtype,
124
+ contents: TCollectionDictionary | undefined,
125
+ collections: TCollectionDictionary | undefined,
126
+ options: SetRequired<ObjectOptions, '$id'>
127
+ ) {
128
+ const baseSchemaName = pascalCase(type)
129
+ const _thisSchemaName = baseSchemaName + pascalCase(subtype)
130
+
131
+ const thisIdWildcardRef = Type.Ref(`${baseSchemaName}IdWildcard`)
132
+
133
+ // Use explicit TObject casts to avoid deep type instantiation
134
+ const metadata = getCollectionNodeMetadata(
135
+ thisIdWildcardRef,
136
+ contents,
137
+ collections
138
+ )
139
+ const enhancedBase: TObject = Assign(
140
+ metadata as TObject,
141
+ base as TObject
142
+ ) as TObject
143
+
144
+ return PrimarySubtypeNode(enhancedBase, type, subtypeKey, subtype, options)
145
+ }
@@ -0,0 +1,39 @@
1
+ import {
2
+ type ObjectOptions,
3
+ type TRecord,
4
+ type TSchema,
5
+ type TString,
6
+ Type
7
+ } from '@sinclair/typebox'
8
+ import Id from '../common/Id.js'
9
+
10
+ export const DictionaryBrand = Symbol('Dictionary')
11
+
12
+ /**
13
+ *
14
+ * @param schema The schema to use as the dictionary value.
15
+ * @param key The schema to use as the dictionary key (default: Id.DictKey)
16
+ * @param options Any object options to apply to this schema.
17
+ */
18
+ export function Dictionary<T extends TSchema>(
19
+ schema: T,
20
+ { key, ...options }: { key?: TString } & ObjectOptions = { key: Id.DictKey }
21
+ ) {
22
+ const dict =
23
+ // Type.Transform(
24
+ Type.Record(key ?? Id.DictKey, schema, {
25
+ default: {},
26
+ remarks: 'Deserialize as a dictionary object.',
27
+ [DictionaryBrand]: 'Dictionary',
28
+ ...options
29
+ }) as TDictionary<T>
30
+ // )
31
+ // .Decode((value) => new Map<string, Static<T>>(Object.entries(value)))
32
+ // .Encode((value) => Object.fromEntries(Array.from(value.entries())))
33
+
34
+ return dict
35
+ }
36
+ export type TDictionary<T extends TSchema = TSchema> = TRecord<TString, T> & {
37
+ [DictionaryBrand]: 'Dictionary'
38
+ }
39
+ export type Dictionary<T> = Record<string, T>
@@ -0,0 +1,19 @@
1
+ import { type ObjectOptions, type TObject, Type } from '@sinclair/typebox'
2
+ import type TypeId from '../../pkg-core/IdElements/TypeId.js'
3
+ import { pascalCase } from '../utils/string.js'
4
+ import { IdNode } from './IdNode.js'
5
+
6
+ export function EmbedOnlyNode<
7
+ TBase extends TObject,
8
+ TType extends TypeId.EmbedOnly,
9
+ TParentType extends TypeId.CanEmbedType<TType>
10
+ >(
11
+ base: TBase,
12
+ typeId: TType,
13
+ parentType: TParentType,
14
+ options: ObjectOptions = {}
15
+ ) {
16
+ const $id = pascalCase(parentType) + pascalCase(typeId)
17
+ const idSchemaName = `${$id}Id`
18
+ return IdNode(base, Type.Ref(idSchemaName), { $id, ...options })
19
+ }
@@ -0,0 +1,38 @@
1
+ import {
2
+ type ObjectOptions,
3
+ type TObject,
4
+ type TSchema,
5
+ type TString,
6
+ Type
7
+ } from '@sinclair/typebox'
8
+ import { EnhancesKey } from '../../scripts/const.js'
9
+ import * as Utils from '../Utils.js'
10
+ import { Assign } from '../utils/FlatIntersect.js'
11
+
12
+ /**
13
+ * Enhances multiple rules elements
14
+ */
15
+
16
+ export function EnhanceMany<T extends TObject, ID extends TSchema = TString>(
17
+ schema: T,
18
+ wildcardID: ID,
19
+ options: ObjectOptions = {}
20
+ ) {
21
+ const base = Utils.OmitMeta(schema) as TObject
22
+ const mixin = Type.Object({
23
+ [EnhancesKey]: Utils.Nullable(Type.Array(wildcardID), {
24
+ description:
25
+ 'An array of wildcard IDs. An item must match one of the wildcard IDs to receive this enhancement. If this is `null`, any ID is valid.',
26
+ default: null
27
+ })
28
+ })
29
+ return Assign(mixin, base, options)
30
+ }
31
+ export type TEnhanceMany<
32
+ T extends TObject,
33
+ ID extends TSchema = TString
34
+ > = ReturnType<typeof EnhanceMany<T, ID>>
35
+
36
+ export type EnhanceMany<T, WildcardID = string> = Utils.OmitMeta<T> & {
37
+ [EnhancesKey]?: WildcardID[]
38
+ }
@@ -0,0 +1,40 @@
1
+ import {
2
+ Kind,
3
+ type ObjectOptions,
4
+ type Static,
5
+ type TObject,
6
+ Type
7
+ } from '@sinclair/typebox'
8
+ import type { TAnyId } from '../common/Id.js'
9
+ import { Documentation } from '../common/Text.js'
10
+ import { Computed } from '../Utils.js'
11
+ import { FlatIntersect } from '../utils/FlatIntersect.js'
12
+ import { setDescriptions } from '../utils/typebox.js'
13
+
14
+ const IdNodeBase = Type.Object({
15
+ _id: Computed(Type.String()),
16
+ _comment: Type.Optional(Type.Ref(Documentation))
17
+ })
18
+
19
+ export function IdNode<TBase extends TObject>(
20
+ base: TBase,
21
+ _id: TAnyId,
22
+ options: ObjectOptions = {}
23
+ ) {
24
+ const enhancedBase = FlatIntersect(
25
+ [IdNodeBase, Type.Object({ _id: Computed(_id) }), base],
26
+ {
27
+ [Kind]: 'Object',
28
+ ...options
29
+ }
30
+ )
31
+
32
+ return setDescriptions(enhancedBase, {
33
+ _id: 'The unique Datasworn ID for this node.'
34
+ })
35
+ }
36
+ export type TIdNode<TBase extends TObject> = ReturnType<
37
+ typeof IdNode<TBase>
38
+ > & { static: IdNode<Static<TBase>> }
39
+
40
+ export type IdNode<TBase extends object> = TBase & Static<typeof IdNodeBase>
@@ -0,0 +1,11 @@
1
+ import { Type } from '@sinclair/typebox'
2
+ import * as Text from '../common/Text.js'
3
+
4
+ export const Cyclopedia = Type.Object({
5
+ name: Type.Ref(Text.Label),
6
+ features: Type.Array(Type.Ref(Text.MarkdownString)),
7
+ summary: Type.Optional(Type.Ref(Text.MarkdownString)),
8
+ description: Type.Ref(Text.MarkdownString),
9
+ quest_starter: Type.Optional(Type.Ref(Text.MarkdownString)),
10
+ your_truth: Type.Optional(Type.Ref(Text.MarkdownString))
11
+ })
@@ -0,0 +1,38 @@
1
+ import type { ObjectOptions, TObject } from '@sinclair/typebox'
2
+ import type TypeId from '../../pkg-core/IdElements/TypeId.js'
3
+ import { setSourceDataSchema } from '../Utils.js'
4
+ import { pascalCase } from '../utils/string.js'
5
+ import { PrimaryTypeNode } from './PrimaryTypeNode.js'
6
+
7
+ export const NonCollectableBrand = Symbol('NonCollectable')
8
+
9
+ export function NonCollectableNode<
10
+ TBase extends TObject,
11
+ TType extends TypeId.NonCollectable
12
+ >(base: TBase, type: TType, options: ObjectOptions = {}) {
13
+ const $id = pascalCase(type)
14
+ const enhancedBase = PrimaryTypeNode(base, type, {
15
+ $id,
16
+ [NonCollectableBrand]: 'NonCollectable',
17
+ ...options
18
+ })
19
+ return setSourceDataSchema(enhancedBase, (schema) => ({
20
+ ...schema,
21
+ additionalProperties: true
22
+ })) as unknown as TNonCollectableNode<TBase, TType>
23
+ }
24
+
25
+ /** Simplified type to avoid deep instantiation */
26
+ export type TNonCollectableNode<
27
+ TBase extends TObject = TObject,
28
+ TType extends TypeId.NonCollectable = TypeId.NonCollectable
29
+ > = TObject & {
30
+ [NonCollectableBrand]: 'NonCollectable'
31
+ _type: TType
32
+ _base: TBase
33
+ }
34
+
35
+ export type NonCollectableNode<
36
+ TBase extends object,
37
+ TType extends TypeId.NonCollectable
38
+ > = PrimaryTypeNode<TBase, TType>
@@ -0,0 +1,115 @@
1
+ import {
2
+ type ObjectOptions,
3
+ type TObject,
4
+ type TRef,
5
+ type TString,
6
+ Type
7
+ } from '@sinclair/typebox'
8
+ import type { SetRequired } from 'type-fest'
9
+ import type TypeId from '../../pkg-core/IdElements/TypeId.js'
10
+ import { CssColor, SvgImageUrl, WebpImageUrl } from '../common/Metadata.js'
11
+ import { SourcedNode } from '../generic/SourcedNode.js'
12
+ import { Discriminable } from '../Utils.js'
13
+ import { Assign } from '../utils/FlatIntersect.js'
14
+ import { pascalCase } from '../utils/string.js'
15
+
16
+ const replacesDescription =
17
+ 'This node replaces all nodes that match these wildcards. References to the replaced nodes can be considered equivalent to this node.'
18
+ const PrimaryNodeBase = Type.Object({
19
+ replaces: Type.Optional(
20
+ Type.Array(Type.String() as TString | TRef<string>, {
21
+ description: replacesDescription
22
+ })
23
+ ),
24
+ color: Type.Optional(
25
+ Type.Ref(CssColor, {
26
+ description:
27
+ 'An optional thematic color associated with this node. For an example, see "Basic Creature Form" (Starforged p. 337).'
28
+ })
29
+ ),
30
+ images: Type.Optional(
31
+ Type.Array(
32
+ Type.Ref(WebpImageUrl, {
33
+ description: 'Extra images associated with this node.'
34
+ })
35
+ )
36
+ ),
37
+ icon: Type.Optional(
38
+ Type.Ref(SvgImageUrl, {
39
+ description: 'An SVG icon associated with this collection.'
40
+ })
41
+ )
42
+ })
43
+
44
+ export function PrimaryTypeNode<
45
+ TBase extends TObject,
46
+ TType extends TypeId.Primary
47
+ >(base: TBase, type: TType, options: ObjectOptions = {}) {
48
+ const _id = Type.Ref(`${pascalCase(type)}Id`)
49
+
50
+ const replaces = Type.Ref(`${pascalCase(type)}IdWildcard`)
51
+
52
+ // Explicit TObject type to avoid deep type chain
53
+ const replacesObj = Type.Object({
54
+ replaces: Type.Optional(
55
+ Type.Array(replaces, { description: replacesDescription })
56
+ )
57
+ })
58
+ const mixin: TObject = Assign(
59
+ PrimaryNodeBase as TObject,
60
+ replacesObj as TObject
61
+ ) as TObject
62
+
63
+ // Use explicit TObject casts to break deep type chain
64
+ const merged: TObject = Assign(mixin, base as TObject) as TObject
65
+ const enhancedBase: TObject = Discriminable(merged, 'type', type) as TObject
66
+
67
+ return SourcedNode(enhancedBase, _id, options) as unknown as TPrimaryTypeNode<
68
+ TBase,
69
+ TType
70
+ >
71
+ }
72
+
73
+ /** Simplified type to avoid deep instantiation */
74
+ export type TPrimaryTypeNode<
75
+ TBase extends TObject = TObject,
76
+ TType extends TypeId.Primary = TypeId.Primary
77
+ > = TObject & { _primaryType: TType; _primaryBase: TBase }
78
+
79
+ export type PrimaryTypeNode<
80
+ TBase extends object,
81
+ TType extends TypeId.Primary
82
+ > = SourcedNode<Discriminable<'type', TType, TBase>>
83
+
84
+ export function PrimarySubtypeNode<
85
+ TBase extends TObject,
86
+ TType extends TypeId.Primary,
87
+ TSubtypeKey extends string,
88
+ TSubtype extends string
89
+ >(
90
+ base: TBase,
91
+ type: TType,
92
+ subtypeKey: TSubtypeKey,
93
+ subtype: TSubtype,
94
+ options: SetRequired<ObjectOptions, '$id'>
95
+ ) {
96
+ const superType = PrimaryTypeNode(base, type)
97
+
98
+ return Discriminable(
99
+ superType,
100
+ subtypeKey,
101
+ subtype,
102
+ options
103
+ ) as unknown as TPrimarySubtypeNode<TBase, TType, TSubtypeKey, TSubtype>
104
+ }
105
+
106
+ /** Simplified type to avoid deep instantiation */
107
+ export type TPrimarySubtypeNode<
108
+ TBase extends TObject = TObject,
109
+ TType extends TypeId.Primary = TypeId.Primary,
110
+ TSubtypeKey extends string = string,
111
+ TSubtype extends string = string
112
+ > = TPrimaryTypeNode<TBase, TType> & {
113
+ _subtypeKey: TSubtypeKey
114
+ _subtype: TSubtype
115
+ }