@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.
- package/README.md +17 -0
- package/dist/cli/args.d.ts +3 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +10 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/datasworn-build.d.ts +3 -0
- package/dist/cli/datasworn-build.d.ts.map +1 -0
- package/dist/cli/datasworn-build.js +33 -0
- package/dist/cli/datasworn-build.js.map +1 -0
- package/dist/cli/datasworn-migrate.d.ts +3 -0
- package/dist/cli/datasworn-migrate.d.ts.map +1 -0
- package/dist/cli/datasworn-migrate.js +26 -0
- package/dist/cli/datasworn-migrate.js.map +1 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +10 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/rules-package-builder.d.ts +22 -0
- package/dist/rules-package-builder.d.ts.map +1 -0
- package/dist/rules-package-builder.js +84 -0
- package/dist/rules-package-builder.js.map +1 -0
- package/dist/schema.d.ts +8 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +18 -0
- package/dist/schema.js.map +1 -0
- package/dist/validators.d.ts +8 -0
- package/dist/validators.d.ts.map +1 -0
- package/dist/validators.js +35 -0
- package/dist/validators.js.map +1 -0
- package/package.json +60 -0
- package/schema-source/schema/Assets.ts +66 -0
- package/schema-source/schema/Atlas.ts +20 -0
- package/schema-source/schema/Defs.ts +126 -0
- package/schema-source/schema/DelveSites.ts +3 -0
- package/schema-source/schema/Entities.ts +1 -0
- package/schema-source/schema/Generic.ts +18 -0
- package/schema-source/schema/Moves.ts +1 -0
- package/schema-source/schema/Npcs.ts +80 -0
- package/schema-source/schema/Oracles.ts +20 -0
- package/schema-source/schema/Rarities.ts +36 -0
- package/schema-source/schema/Root.ts +94 -0
- package/schema-source/schema/Rules.ts +61 -0
- package/schema-source/schema/RulesPackages.ts +135 -0
- package/schema-source/schema/Symbols.ts +30 -0
- package/schema-source/schema/Truths.ts +53 -0
- package/schema-source/schema/Utils.ts +21 -0
- package/schema-source/schema/assets/Ability.ts +79 -0
- package/schema-source/schema/assets/Enhancement.ts +62 -0
- package/schema-source/schema/assets/Fields.ts +285 -0
- package/schema-source/schema/assets/common.ts +29 -0
- package/schema-source/schema/common/Fields.ts +327 -0
- package/schema-source/schema/common/Id.ts +64 -0
- package/schema-source/schema/common/Inputs.ts +374 -0
- package/schema-source/schema/common/Metadata.ts +142 -0
- package/schema-source/schema/common/Player.ts +17 -0
- package/schema-source/schema/common/Progress.ts +63 -0
- package/schema-source/schema/common/Range.ts +53 -0
- package/schema-source/schema/common/RollableValues.ts +152 -0
- package/schema-source/schema/common/Rolls.ts +108 -0
- package/schema-source/schema/common/Text.ts +95 -0
- package/schema-source/schema/common/index.ts +16 -0
- package/schema-source/schema/delve/DelveSite.ts +121 -0
- package/schema-source/schema/delve/DelveSiteDomain.ts +136 -0
- package/schema-source/schema/delve/DelveSiteTheme.ts +97 -0
- package/schema-source/schema/delve/common.ts +32 -0
- package/schema-source/schema/entities/EntityPrompt.ts +13 -0
- package/schema-source/schema/entities/index.ts +1 -0
- package/schema-source/schema/generic/CollectableNode.ts +75 -0
- package/schema-source/schema/generic/CollectionNode.ts +145 -0
- package/schema-source/schema/generic/Dictionary.ts +39 -0
- package/schema-source/schema/generic/EmbedOnlyNode.ts +19 -0
- package/schema-source/schema/generic/Enhance.ts +38 -0
- package/schema-source/schema/generic/IdNode.ts +40 -0
- package/schema-source/schema/generic/Mixin.ts +11 -0
- package/schema-source/schema/generic/NonCollectableNode.ts +38 -0
- package/schema-source/schema/generic/PrimaryTypeNode.ts +115 -0
- package/schema-source/schema/generic/SourcedNode.ts +51 -0
- package/schema-source/schema/index.ts +23 -0
- package/schema-source/schema/moves/ActionRoll.ts +152 -0
- package/schema-source/schema/moves/EmbeddedMove.ts +24 -0
- package/schema-source/schema/moves/Move.ts +26 -0
- package/schema-source/schema/moves/MoveCategory.ts +6 -0
- package/schema-source/schema/moves/MoveEnhancement.ts +29 -0
- package/schema-source/schema/moves/ProgressRoll.ts +184 -0
- package/schema-source/schema/moves/Trigger.ts +193 -0
- package/schema-source/schema/moves/common.ts +136 -0
- package/schema-source/schema/moves/index.ts +13 -0
- package/schema-source/schema/moves/utils.ts +132 -0
- package/schema-source/schema/object_type/ObjectType.ts +23 -0
- package/schema-source/schema/oracles/EmbeddedOracleRollable.ts +28 -0
- package/schema-source/schema/oracles/OracleCollection.ts +140 -0
- package/schema-source/schema/oracles/OracleRollable.ts +207 -0
- package/schema-source/schema/oracles/Table.ts +94 -0
- package/schema-source/schema/oracles/TableRow.ts +141 -0
- package/schema-source/schema/root/NiceSchema.ts +15 -0
- package/schema-source/schema/root/Root.ts +41 -0
- package/schema-source/schema/root/SchemaTransform.ts +89 -0
- package/schema-source/schema/root/SourceData.ts +151 -0
- package/schema-source/schema/rules/ConditionMeterRule.ts +25 -0
- package/schema-source/schema/rules/ImpactRule.ts +54 -0
- package/schema-source/schema/rules/SpecialTrackRule.ts +29 -0
- package/schema-source/schema/rules/StatRule.ts +23 -0
- package/schema-source/schema/rules/TagRule.ts +176 -0
- package/schema-source/schema/rules/TagSchema.ts +161 -0
- package/schema-source/schema/tags/canonicalTags.ts +29 -0
- package/schema-source/schema/tools/build/index.ts +48 -0
- package/schema-source/schema/tools/i18n/index.ts +9 -0
- package/schema-source/schema/utils/Computed.ts +82 -0
- package/schema-source/schema/utils/DiscriminatedUnion.ts +255 -0
- package/schema-source/schema/utils/EmbeddedNode.ts +172 -0
- package/schema-source/schema/utils/ExtractLiteralFromEnum.ts +22 -0
- package/schema-source/schema/utils/FlatIntersect.ts +107 -0
- package/schema-source/schema/utils/IfThen.ts +50 -0
- package/schema-source/schema/utils/MergeEnumSchemas.ts +16 -0
- package/schema-source/schema/utils/NonNullable.ts +6 -0
- package/schema-source/schema/utils/Nullable.ts +29 -0
- package/schema-source/schema/utils/ObjectLiteral.ts +16 -0
- package/schema-source/schema/utils/ObjectProperties.ts +4 -0
- package/schema-source/schema/utils/OmitMeta.ts +22 -0
- package/schema-source/schema/utils/OmitOptional.ts +27 -0
- package/schema-source/schema/utils/PartialExcept.ts +26 -0
- package/schema-source/schema/utils/SetNullable.ts +44 -0
- package/schema-source/schema/utils/SetOptional.ts +48 -0
- package/schema-source/schema/utils/UnionEnum.ts +82 -0
- package/schema-source/schema/utils/UnionEnumFromRecord.ts +36 -0
- package/schema-source/schema/utils/UnionOneOf.ts +80 -0
- package/schema-source/schema/utils/generateRulesetSchemas.ts +204 -0
- package/schema-source/schema/utils/string.ts +15 -0
- package/schema-source/schema/utils/typebox.ts +141 -0
- 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
|
+
}
|