@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,176 @@
1
+ import { type Static, Type } from '@sinclair/typebox'
2
+ import TypeId from '../../pkg-core/IdElements/TypeId.js'
3
+ import JtdType from '../../scripts/json-typedef/typedef.js'
4
+ import Id, { RulesetId } from '../common/Id.js'
5
+ import { DiceExpression } from '../common/Rolls.js'
6
+ import { Dictionary } from '../generic/Dictionary.js'
7
+ import { JsonTypeDef } from '../Symbols.js'
8
+ import { Nullable, UnionEnum } from '../Utils.js'
9
+ import { type PascalCase, pascalCase } from '../utils/string.js'
10
+ import { TagSchema } from './TagSchema.js'
11
+
12
+ type _NodeSchemaName<T extends string> = PascalCase<T>
13
+ type EmbeddedNodeSchemaName<T extends string> = `Embedded${PascalCase<T>}`
14
+ type IdSchemaName<T extends string> = `${PascalCase<T>}Id`
15
+ type WildcardIdSchemaName<T extends string> = `${PascalCase<T>}IdWildcard`
16
+
17
+ function getNodeSchemaName<T extends string>(typeId: T) {
18
+ return pascalCase(typeId)
19
+ }
20
+
21
+ function getEmbeddedNodeSchemaName<T extends string>(typeId: T) {
22
+ return `Embedded${pascalCase(typeId)}` as EmbeddedNodeSchemaName<T>
23
+ }
24
+
25
+ function getIdSchemaName<T extends string>(typeId: T) {
26
+ return `${pascalCase(typeId)}Id` as IdSchemaName<T>
27
+ }
28
+ function getWildcardIdSchemaName<T extends string>(typeId: T) {
29
+ return `${pascalCase(typeId)}IdWildcard` as WildcardIdSchemaName<T>
30
+ }
31
+
32
+ const AnyPrimary = TypeId.Primary.map(getNodeSchemaName)
33
+
34
+ const _EmbedOnly = TypeId.EmbedOnly.map(getNodeSchemaName)
35
+ const _EmbeddedPrimary = TypeId.EmbeddablePrimary.map(getEmbeddedNodeSchemaName)
36
+
37
+ // TODO: could this be generated by iterating over objects and picking the ones with `tags` properties?
38
+ const AnyPrimaryId = AnyPrimary.map(getIdSchemaName)
39
+ const AnyPrimaryIdWildcard = AnyPrimary.map(getWildcardIdSchemaName)
40
+
41
+ export const CollectionType = UnionEnum<typeof TypeId.Collection>(
42
+ TypeId.Collection,
43
+ {
44
+ $id: 'CollectionType'
45
+ }
46
+ )
47
+ export type CollectionType = Static<typeof CollectionType>
48
+
49
+ export const CollectableType = UnionEnum(TypeId.Collectable, {
50
+ $id: 'CollectableType'
51
+ })
52
+ export type CollectableType = Static<typeof CollectableType>
53
+
54
+ export const NonCollectableType = UnionEnum(TypeId.NonCollectable, {
55
+ $id: 'NonCollectableType'
56
+ })
57
+ export type NonCollectableType = Static<typeof NonCollectableType>
58
+
59
+ export const EmbedOnlyType = UnionEnum(TypeId.EmbedOnly, {
60
+ $id: 'EmbedOnlyType'
61
+ })
62
+ export type EmbedOnlyType = Static<typeof EmbedOnlyType>
63
+
64
+ export const RuleType = UnionEnum(
65
+ ['impact', 'condition_meter', 'special_track', 'stat'],
66
+ { $id: 'RuleType' }
67
+ )
68
+ export type RuleType = Static<typeof RuleType>
69
+
70
+ export const TaggableNodeType = Type.Union(
71
+ [
72
+ Type.Ref(CollectableType),
73
+ Type.Ref(NonCollectableType),
74
+ Type.Ref(CollectionType),
75
+ Type.Ref(EmbedOnlyType),
76
+ Type.Ref(RuleType)
77
+ ],
78
+ {
79
+ [JsonTypeDef]: {
80
+ schema: JtdType.Enum([
81
+ ...TypeId.Primary,
82
+ ...TypeId.EmbedOnly,
83
+ 'impact',
84
+ 'condition_meter',
85
+ 'special_track',
86
+ 'stat'
87
+ ])
88
+ },
89
+ $id: 'TaggableNodeType'
90
+ }
91
+ )
92
+ export type TaggableNodeType = Static<typeof TaggableNodeType>
93
+
94
+ export { TagSchema }
95
+
96
+ export const TagRule = Type.Object(
97
+ {
98
+ node_types: Nullable(Type.Array(Type.Ref(TaggableNodeType)), {
99
+ description:
100
+ 'Types of object that can receive this tag, or `null` if any type of object accepts it.',
101
+ default: null
102
+ }),
103
+ $schema: Type.Ref(TagSchema, {
104
+ description: 'The JSON schema for this tag value.'
105
+ })
106
+ },
107
+ { $id: 'TagRule' }
108
+ )
109
+
110
+ // export const TagRule = DiscriminatedUnion(typedTags, 'value_type', {
111
+ // $id: 'TagRule'
112
+ // })
113
+ export type TagRule = Static<typeof TagRule>
114
+
115
+ const TagValueNonId = [
116
+ Type.Boolean(),
117
+ Type.Integer(),
118
+ Type.Ref(Id.DictKey), // from enums
119
+ Type.Ref(DiceExpression)
120
+ ]
121
+
122
+ export const Tag = Type.Union(
123
+ [
124
+ ...TagValueNonId,
125
+ ...AnyPrimaryId.map((type) => Type.Ref(type)),
126
+ Type.Array(
127
+ Type.Union([
128
+ // Type.Ref(Id.DictKey), // from enums
129
+ // Type.Ref(Rolls.DiceExpression),
130
+ ...AnyPrimaryIdWildcard.map((type) => Type.Ref(type))
131
+ ])
132
+ )
133
+ ],
134
+ { $id: 'Tag', [JsonTypeDef]: { schema: JtdType.Any() as any } }
135
+ )
136
+
137
+ export const Tags = Type.Record(
138
+ RulesetId,
139
+ Dictionary(Type.Ref('Tag'), { title: 'RulesPackageTags' }),
140
+ {
141
+ releaseStage: 'experimental',
142
+ $id: 'Tags',
143
+ key: Id.RulesetId.pattern,
144
+ description:
145
+ 'A dictionary of tags, keyed by the RulesPackageId that the tags are from.'
146
+ }
147
+ )
148
+
149
+ export const CoreTags = Type.Object(
150
+ {
151
+ supernatural: Type.Optional(
152
+ Type.Boolean({
153
+ description:
154
+ 'This object is supernatural in nature, and is ideal for settings that feature supernatural or mythic powers.'
155
+ })
156
+ ),
157
+ technological: Type.Optional(
158
+ Type.Boolean({
159
+ description:
160
+ 'This object is technological in nature, and is ideal for settings that feature remarkable technologies.'
161
+ })
162
+ ),
163
+ requires_allies: Type.Optional(
164
+ Type.Boolean({
165
+ description:
166
+ 'This object requires allies to function, and is intended for co-op play, or guided play with allies. It is not appropriate for solo play.'
167
+ })
168
+ )
169
+ },
170
+ { $id: 'CoreTags' }
171
+ )
172
+ const coreNamespaceId = '_core' as const
173
+
174
+ Tags.properties = {
175
+ [coreNamespaceId]: Type.Optional(Type.Ref(CoreTags))
176
+ }
@@ -0,0 +1,161 @@
1
+ import { type TSchema, Type } from '@sinclair/typebox'
2
+ import type { JSONSchema7 } from 'json-schema'
3
+ import { $schema } from '../../scripts/const.js'
4
+ import JtdType from '../../scripts/json-typedef/typedef.js'
5
+ import { DictKey } from '../common/Id.js'
6
+ import { JsonTypeDef, Typescript } from '../Symbols.js'
7
+
8
+ const validSchemaTypes = [
9
+ 'boolean',
10
+ 'integer',
11
+ 'number',
12
+ 'string',
13
+ 'null'
14
+ ] satisfies JSONSchema7['type']
15
+
16
+ export function isValidTagSchema(schema: TSchema) {
17
+ if (validSchemaTypes.includes(schema?.type)) return true
18
+ // some IDs are union schemas, these are fine
19
+ if (schema.$id?.endsWith('Id') || schema.$id?.endsWith('IdWildcard'))
20
+ return true
21
+ if ('enum' in schema) return true
22
+ if ('const' in schema) return true
23
+ if ('anyOf' in schema)
24
+ return (schema.anyOf as TSchema[]).every(isValidTagSchema)
25
+
26
+ return false
27
+ }
28
+
29
+ const TagSchemaInteger = Type.Object(
30
+ { type: Type.Const('integer') },
31
+ { title: 'TagSchemaInteger', additionalProperties: true }
32
+ )
33
+
34
+ const TagSchemaFloat = Type.Object(
35
+ {
36
+ type: Type.Const('number')
37
+ },
38
+ { title: 'TagSchemaFloat', additionalProperties: true }
39
+ )
40
+
41
+ const TagSchemaStringEnum = Type.Object(
42
+ {
43
+ enum: Type.Array(Type.Ref(DictKey))
44
+ },
45
+ { title: 'TagSchemaStringEnum', additionalProperties: true }
46
+ )
47
+
48
+ const TagSchemaIntegerEnum = Type.Object(
49
+ {
50
+ enum: Type.Array(Type.Integer())
51
+ },
52
+ {
53
+ title: 'TagSchemaIntegerEnum',
54
+ additionalProperties: true
55
+ }
56
+ )
57
+
58
+ const TagSchemaBoolean = Type.Object(
59
+ {
60
+ type: Type.Const('boolean')
61
+ },
62
+ {
63
+ description: 'Schema for a true or false value.',
64
+ title: 'TagSchemaBoolean',
65
+ additionalProperties: true
66
+ }
67
+ )
68
+
69
+ const TagSchemaDataswornRef = Type.Object(
70
+ {
71
+ $ref: Type.Any()
72
+ // this a placeholder value.
73
+ // an enum is computed from all datasworn schemata at build time.
74
+ },
75
+ { title: 'TagSchemaDataswornRef', additionalProperties: true }
76
+ )
77
+
78
+ // future additions - nested objects?
79
+
80
+ const _schemaKeyBlacklist = [
81
+ '$id',
82
+ '$defs',
83
+ '$schema',
84
+ 'definitions',
85
+ 'dependencies',
86
+ 'if',
87
+ 'then',
88
+ 'else',
89
+ 'allOf',
90
+ 'anyOf',
91
+ 'oneOf',
92
+ 'not',
93
+ 'additionalItems',
94
+ 'additionalProperties'
95
+ ] as const satisfies (keyof JSONSchema7)[]
96
+
97
+ // set here to use as a forward reference
98
+ const TagSchemaId = 'TagSchema' as const
99
+
100
+ const TagSchemaObject = Type.Object(
101
+ {
102
+ type: Type.Const('object'),
103
+ properties: Type.Record(DictKey, Type.Ref(TagSchemaId))
104
+ //
105
+ },
106
+ { title: 'TagSchemaObject', additionalProperties: true }
107
+ )
108
+
109
+ const TagSchemaArray = Type.Object(
110
+ {
111
+ type: Type.Const('array'),
112
+ items: Type.Ref(TagSchemaId)
113
+ //
114
+ },
115
+ { title: 'TagSchemaArray', additionalProperties: true }
116
+ )
117
+
118
+ export const TagSchema = Type.Intersect(
119
+ [
120
+ Type.Union([
121
+ TagSchemaDataswornRef as TSchema,
122
+ // enumerations
123
+ TagSchemaStringEnum,
124
+ TagSchemaIntegerEnum,
125
+ // primitives
126
+ TagSchemaBoolean,
127
+ TagSchemaInteger,
128
+ TagSchemaFloat,
129
+ // basic string schema intentionally omitted -- strings must be one of datasworn's subtypes or an enum.
130
+ TagSchemaObject,
131
+ TagSchemaArray
132
+ ]),
133
+ Type.Ref($schema)
134
+ // Type.Not(
135
+ // Type.Record(
136
+ // Type.Enum(Object.fromEntries(schemaKeyBlacklist.map((v) => [v, v]))),
137
+ // Type.Any()
138
+ // )
139
+ // )
140
+ ],
141
+ {
142
+ $id: TagSchemaId,
143
+ // TODO: JTD schema for JSON schema of JSON schema? :sob:
144
+ [JsonTypeDef]: { schema: JtdType.Any() as any },
145
+ // TODO: add json schema type stub lib as dependency; point at this type
146
+ [Typescript]: (identifier: string, _schema: TSchema) =>
147
+ `export type ${identifier} = Record<string, unknown>`,
148
+ description:
149
+ 'JSON schema used to validate the tag data, with a mandatory description. Only a subset of all possible JSON schema are allowed, including references to some Datasworn types.',
150
+ releaseStage: 'experimental',
151
+ examples: [
152
+ Type.Boolean({
153
+ description: 'An example tag with a simple true/false value.'
154
+ }),
155
+ Type.Array(Type.Ref('OracleRollableIdWildcard'), {
156
+ description:
157
+ 'An example tag with an array of oracle rollable ID wildcards.'
158
+ })
159
+ ]
160
+ }
161
+ )
@@ -0,0 +1,29 @@
1
+ import { type TSchema, Type } from '@sinclair/typebox'
2
+ import { UnionEnum } from '../Utils.js'
3
+
4
+ const _TagsClassic = {}
5
+ const _TagsStarforged = {
6
+ recommended: Type.Boolean({
7
+ description: 'This object is ideal for use in Starforged.'
8
+ })
9
+ } satisfies Record<string, TSchema>
10
+ const _TagsDelve = {} satisfies Record<string, TSchema>
11
+ type _TagParams = {
12
+ schema: TSchema
13
+ node_types: []
14
+ }
15
+ const _TagsSunderedIsles = {
16
+ recommended: Type.Boolean({
17
+ description: 'This object is ideal for use in Sundered Isles.'
18
+ }),
19
+ cursed_version_of: Type.Array(Type.Ref('OracleRollableIdWildcard')),
20
+ // wrap these into their own objects: "cursed" and "curses"?
21
+ curse_behavior: Type.Array(UnionEnum(['replace_result', 'add_result'])),
22
+ cursed_by: Type.Array(Type.String()),
23
+ region: UnionEnum(['myriads', 'margins', 'reaches'])
24
+ // overland_region
25
+ // location
26
+ // faction_type
27
+ // ship_size
28
+ // treasure_size
29
+ } satisfies Record<string, TSchema>
@@ -0,0 +1,48 @@
1
+ import { type Static, Type } from '@sinclair/typebox'
2
+ import {
3
+ PKG_SCOPE_COMMUNITY,
4
+ PKG_SCOPE_OFFICIAL
5
+ } from '../../../scripts/const.js'
6
+ import { UnionEnumFromRecord } from '../../utils/UnionEnumFromRecord.js'
7
+
8
+ export const RulesPackageConfig = Type.Object({
9
+ id: Type.String({
10
+ description:
11
+ 'The namespace ID for this data set. This is the first path element of all its object IDs.'
12
+ }),
13
+ description: Type.Optional(Type.String()),
14
+ type: Type.Union([Type.Literal('ruleset'), Type.Literal('expansion')]),
15
+ pkg: Type.Object({
16
+ name: Type.String({
17
+ description: 'The package ID, not including its scope (see `scope`).'
18
+ }),
19
+ private: Type.Boolean({ default: false }),
20
+ description: Type.String(),
21
+ keywords: Type.Array(Type.String()),
22
+ authors: Type.Array(
23
+ Type.Object({
24
+ name: Type.String(),
25
+ email: Type.String({ format: 'email' }),
26
+ url: Type.String({ format: 'uri' })
27
+ })
28
+ ),
29
+ scope: UnionEnumFromRecord(
30
+ {
31
+ [PKG_SCOPE_OFFICIAL]: 'Official Ironsworn content.',
32
+ [PKG_SCOPE_COMMUNITY]:
33
+ 'Ironsworn-compatible content from third parties.'
34
+ },
35
+ {
36
+ description: 'The namespace or scope used by the package.',
37
+ default: PKG_SCOPE_COMMUNITY
38
+ }
39
+ )
40
+ }),
41
+ paths: Type.Object({
42
+ source: Type.String(),
43
+ assets: Type.Optional(Type.Array(Type.String()))
44
+ })
45
+
46
+ // TODO: configure more of package construction from here, e.g. content of package.json
47
+ })
48
+ export type RulesPackageConfig = Static<typeof RulesPackageConfig>
@@ -0,0 +1,9 @@
1
+ import { type Static, Type } from '@sinclair/typebox'
2
+
3
+ export const Term = Type.Object({
4
+ context: Type.String(),
5
+ value: Type.Union([Type.String(), Type.Null()]),
6
+ source: Type.Array(Type.String()),
7
+ markdown: Type.Boolean(),
8
+ })
9
+ export type Term = Static<typeof Term>
@@ -0,0 +1,82 @@
1
+ import {
2
+ CloneType,
3
+ type SchemaOptions,
4
+ type Static,
5
+ type TObject,
6
+ type TSchema
7
+ } from '@sinclair/typebox'
8
+
9
+ /** Symbol indicating that this property is computed at build time, and is therefore optional in DataswornSource */
10
+ export const ComputedPropertyBrand = Symbol('ComputedProperty')
11
+
12
+ type ComputedOptions<
13
+ T extends TSchema,
14
+ ParentObject extends TObject
15
+ > = SchemaOptions & {
16
+ [ComputedPropertyBrand]:
17
+ | 'ComputedProperty'
18
+ | ComputedPropertyFn<T, ParentObject>
19
+ }
20
+
21
+ /** Create a schema that is computed at build time, and is therefore optional in DataswornSource */
22
+ // TODO: make it possible for this to supply a function that computes the property!
23
+ export function Computed<
24
+ T extends TSchema,
25
+ ParentObject extends TObject = TObject
26
+ >(
27
+ schema: T,
28
+ options: ComputedOptions<T, ParentObject> = {
29
+ [ComputedPropertyBrand]: 'ComputedProperty'
30
+ }
31
+ ) {
32
+ return CloneType(schema, {
33
+ ...options
34
+ }) as TComputed<T, ParentObject>
35
+ }
36
+ export type TComputed<
37
+ T extends TSchema,
38
+ ParentObject extends TObject = TObject
39
+ > = T & {
40
+ [ComputedPropertyBrand]:
41
+ | 'ComputedProperty'
42
+ | ComputedPropertyFn<T, ParentObject>
43
+ }
44
+
45
+ type ComputedPropertyFn<T extends TSchema, ParentObject extends TObject> = (
46
+ object: Static<ParentObject>,
47
+ property: string,
48
+ pointer: string
49
+ ) => Static<T>
50
+
51
+ /** Symbol indicating that this property is optional in DataswornSource */
52
+ export const SourceOptionalBrand = Symbol('SourceOptional')
53
+
54
+ /** Flags a schema as being optional in DataswornSource. Mutates the original schema.
55
+ * @remarks Functionally similar to {@link Computed}, but with different semantics.
56
+ */
57
+ export function setSourceOptional<T extends TSchema>(schema: T) {
58
+ if (schema == null) return schema
59
+ ;(schema as TSourceOptional<T>)[SourceOptionalBrand] = 'SourceOptional'
60
+ return schema as TSourceOptional<T>
61
+ }
62
+ export type TSourceOptional<T extends TSchema> = T & {
63
+ [SourceOptionalBrand]: 'SourceOptional'
64
+ }
65
+
66
+ export const GetSourceDataSchema = Symbol('GetSourceDataSchema')
67
+
68
+ /** Provide an override value */
69
+ export function setSourceDataSchema<
70
+ T extends TSchema,
71
+ SourceSchema extends TSchema
72
+ >(schema: T, sourceSchema: SourceSchema | ((schema: T) => SourceSchema)): T {
73
+ // @ts-expect-error
74
+ schema[GetSourceDataSchema] =
75
+ typeof sourceSchema === 'function' ? sourceSchema : () => sourceSchema
76
+
77
+ return schema as THasSourceSchema<T, SourceSchema>
78
+ }
79
+ export type THasSourceSchema<
80
+ T extends TSchema = TSchema,
81
+ SourceSchema extends TSchema = TSchema
82
+ > = T & { [GetSourceDataSchema]: (schema: T) => SourceSchema }