@datasworn-community/build-tools 0.2.2 → 0.2.3

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.
@@ -7,11 +7,13 @@ import {
7
7
  Type
8
8
  } from '@sinclair/typebox'
9
9
 
10
+ import { IdElements } from '@datasworn-community/core'
10
11
  import ids from '../../builders/IdBuilder.js'
11
- import Pattern from '../../pkg-core/IdElements/Pattern.js'
12
12
  import JtdType from '../../scripts/json-typedef/typedef.js'
13
13
  import { JsonTypeDef } from '../Symbols.js'
14
14
 
15
+ import Pattern = IdElements.Pattern
16
+
15
17
  export const RulesetId = Type.String({
16
18
  $id: 'RulesetId',
17
19
  examples: ['classic', 'starforged'],
@@ -5,7 +5,9 @@ import {
5
5
  type TString,
6
6
  Type
7
7
  } from '@sinclair/typebox'
8
- import type TypeId from '../../pkg-core/IdElements/TypeId.js'
8
+ import { IdElements } from '@datasworn-community/core'
9
+
10
+ import type TypeId = IdElements.TypeId
9
11
  import { Computed } from '../Utils.js'
10
12
  import { pascalCase } from '../utils/string.js'
11
13
 
@@ -1,6 +1,8 @@
1
1
  import { CloneType, type ObjectOptions, type TObject } from '@sinclair/typebox'
2
2
  import type { SetRequired } from 'type-fest'
3
- import type TypeId from '../../pkg-core/IdElements/TypeId.js'
3
+ import { IdElements } from '@datasworn-community/core'
4
+
5
+ import type TypeId = IdElements.TypeId
4
6
  import { setSourceDataSchema } from '../Utils.js'
5
7
  import { pascalCase } from '../utils/string.js'
6
8
  import { PrimarySubtypeNode, PrimaryTypeNode } from './PrimaryTypeNode.js'
@@ -9,7 +9,7 @@ import {
9
9
  Type
10
10
  } from '@sinclair/typebox'
11
11
  import type { SetRequired } from 'type-fest'
12
- import TypeId from '../../pkg-core/IdElements/TypeId.js'
12
+ import { IdElements } from '@datasworn-community/core'
13
13
  import {
14
14
  CollectionsKey,
15
15
  ContentsKey,
@@ -19,6 +19,8 @@ import * as Text from '../common/Text.js'
19
19
  import { setSourceOptional } from '../Utils.js'
20
20
  import { Assign } from '../utils/FlatIntersect.js'
21
21
  import { pascalCase } from '../utils/string.js'
22
+
23
+ import TypeId = IdElements.TypeId
22
24
  import { Dictionary, type TDictionary } from './Dictionary.js'
23
25
  import { PrimarySubtypeNode, PrimaryTypeNode } from './PrimaryTypeNode.js'
24
26
 
@@ -1,5 +1,7 @@
1
1
  import { type ObjectOptions, type TObject, Type } from '@sinclair/typebox'
2
- import type TypeId from '../../pkg-core/IdElements/TypeId.js'
2
+ import { IdElements } from '@datasworn-community/core'
3
+
4
+ import type TypeId = IdElements.TypeId
3
5
  import { pascalCase } from '../utils/string.js'
4
6
  import { IdNode } from './IdNode.js'
5
7
 
@@ -1,5 +1,7 @@
1
1
  import type { ObjectOptions, TObject } from '@sinclair/typebox'
2
- import type TypeId from '../../pkg-core/IdElements/TypeId.js'
2
+ import { IdElements } from '@datasworn-community/core'
3
+
4
+ import type TypeId = IdElements.TypeId
3
5
  import { setSourceDataSchema } from '../Utils.js'
4
6
  import { pascalCase } from '../utils/string.js'
5
7
  import { PrimaryTypeNode } from './PrimaryTypeNode.js'
@@ -6,7 +6,9 @@ import {
6
6
  Type
7
7
  } from '@sinclair/typebox'
8
8
  import type { SetRequired } from 'type-fest'
9
- import type TypeId from '../../pkg-core/IdElements/TypeId.js'
9
+ import { IdElements } from '@datasworn-community/core'
10
+
11
+ import type TypeId = IdElements.TypeId
10
12
  import { CssColor, SvgImageUrl, WebpImageUrl } from '../common/Metadata.js'
11
13
  import { SourcedNode } from '../generic/SourcedNode.js'
12
14
  import { Discriminable } from '../Utils.js'
@@ -1,5 +1,5 @@
1
1
  import { type Static, Type } from '@sinclair/typebox'
2
- import TypeId from '../../pkg-core/IdElements/TypeId.js'
2
+ import { IdElements } from '@datasworn-community/core'
3
3
  import JtdType from '../../scripts/json-typedef/typedef.js'
4
4
  import Id, { RulesetId } from '../common/Id.js'
5
5
  import { DiceExpression } from '../common/Rolls.js'
@@ -9,6 +9,8 @@ import { Nullable, UnionEnum } from '../Utils.js'
9
9
  import { type PascalCase, pascalCase } from '../utils/string.js'
10
10
  import { TagSchema } from './TagSchema.js'
11
11
 
12
+ import TypeId = IdElements.TypeId
13
+
12
14
  type _NodeSchemaName<T extends string> = PascalCase<T>
13
15
  type EmbeddedNodeSchemaName<T extends string> = `Embedded${PascalCase<T>}`
14
16
  type IdSchemaName<T extends string> = `${PascalCase<T>}Id`
@@ -10,7 +10,7 @@ import {
10
10
  Type
11
11
  } from '@sinclair/typebox'
12
12
  import type { Writable } from 'type-fest'
13
- import TypeId from '../../pkg-core/IdElements/TypeId.js'
13
+ import { IdElements } from '@datasworn-community/core'
14
14
  import {
15
15
  EnhancesKey,
16
16
  IdKey,
@@ -19,6 +19,8 @@ import {
19
19
  type TypeSep
20
20
  } from '../../scripts/const.js'
21
21
  import { Computed } from './Computed.js'
22
+
23
+ import TypeId = IdElements.TypeId
22
24
  import { pascalCase } from './string.js'
23
25
 
24
26
  const EmbeddedDictionaryKeys = Object.values(TypeId.BranchKey)
@@ -1,13 +1,13 @@
1
1
  import { camelCase } from 'lodash-es'
2
2
  import type { PascalCase as PascalCaseNoDot } from 'type-fest'
3
- import type { Join, Split } from '../../pkg-core/Utils/String.js'
3
+ import type { Utils } from '@datasworn-community/core'
4
4
 
5
5
  export function capitalize<Str extends string = string>(str: Str) {
6
6
  return (str[0].toLocaleUpperCase('en-US') + str.slice(1)) as Capitalize<Str>
7
7
  }
8
8
 
9
9
  export type PascalCase<T extends string> = PascalCaseNoDot<
10
- Join<Split<T, '.'>, '_'>
10
+ Utils.Join<Utils.Split<T, '.'>, '_'>
11
11
  >
12
12
 
13
13
  export function pascalCase<Str extends string = string>(str: Str) {
@@ -0,0 +1,70 @@
1
+ import { type Kind, type Static, type TSchema, Type } from '@sinclair/typebox'
2
+ import { DiceExpression } from '../schema/common/Rolls.js'
3
+ import type {
4
+ Inherits,
5
+ JsonTypeDef,
6
+ Namespace,
7
+ Simplify,
8
+ Typescript
9
+ } from '../schema/Symbols.js'
10
+ import { UnionEnum } from '../schema/Utils.js'
11
+ import type { Metadata } from './json-typedef/typedef.js'
12
+
13
+ export const Keywords = {
14
+ releaseStage: UnionEnum(['experimental', 'release'], {
15
+ default: 'release'
16
+ }),
17
+ i18n: Type.Boolean({ default: false }),
18
+ deprecated: Type.Boolean({ default: false }),
19
+ remarks: Type.String(),
20
+ rollable: Type.Union([Type.Boolean(), DiceExpression], {
21
+ description:
22
+ 'This array represents rows in a rollable table. If `true`, use the `dice` property of the parent object to roll. Alternatively, provide a dice expression to use.',
23
+ default: false
24
+ })
25
+ } as const
26
+
27
+ type TypeParamCodeGenData = {
28
+ /** Default value for the type parameter. */
29
+ default?: string
30
+ parameters?: Record<string, TypeParamCodeGenData>
31
+ constraint?: string
32
+ }
33
+
34
+ type TypeCodeGenData = {
35
+ id: string
36
+ /**
37
+ * Key is the type generic parameter ID (e.g. `TType`).
38
+ */
39
+ parameters?: Record<string, TypeParamCodeGenData>
40
+ }
41
+
42
+ declare module '@sinclair/typebox' {
43
+ interface SchemaOptions {
44
+ rollable?: Static<typeof Keywords.rollable>
45
+ remarks?: Static<typeof Keywords.remarks>
46
+ releaseStage?: Static<typeof Keywords.releaseStage>
47
+ deprecated?: Static<typeof Keywords.deprecated>
48
+ [Namespace]?: string
49
+ [Inherits]?: TypeCodeGenData[]
50
+ /** A less complex alternate version of the schema for use with code generation tools. */
51
+ [Simplify]?: TSchema
52
+ [Typescript]?: (identifier: string, schema: TSchema) => string
53
+ [JsonTypeDef]?: {
54
+ /** JTD schema to override the automatic conversion. Schema metadata will automatically be inherited from the JSON schema. */
55
+ schema?: TSchema & { [Kind]: `TypeDef:${string}` }
56
+ /** If true, this schema will be ignored when generating JTD schema. */
57
+ skip?: boolean
58
+ metadata?: Metadata
59
+ }
60
+ }
61
+ interface StringOptions extends SchemaOptions {
62
+ i18n?: Static<typeof Keywords.i18n>
63
+ }
64
+ }
65
+
66
+ declare global {
67
+ interface ObjectConstructor {
68
+ keys<T extends object>(object: T): (keyof T)[]
69
+ }
70
+ }
@@ -0,0 +1,290 @@
1
+ import {
2
+ Kind,
3
+ type TArray,
4
+ type TObject,
5
+ type TSchema,
6
+ type TTuple,
7
+ TypeGuard
8
+ } from '@sinclair/typebox'
9
+ import {
10
+ isEqual,
11
+ isNull,
12
+ isUndefined,
13
+ map,
14
+ mapValues,
15
+ pick,
16
+ repeat,
17
+ uniq
18
+ } from 'lodash-es'
19
+ import { Typescript } from '../../schema/Symbols.js'
20
+ import {
21
+ TDiscriminatedUnion,
22
+ TNullable,
23
+ TUnionEnum
24
+ } from '../../schema/Utils.js'
25
+ import { $schema } from '../const.js'
26
+ import Log from '../utils/Log.js'
27
+
28
+ export function extractDefs(defs: Record<string, TSchema>) {
29
+ return mapValues(defs, (v, k) => renderDefinition(k, v))
30
+ }
31
+
32
+ // keywords where they can be included close to as-is. boolean keywords generally have their value omitted, leaving just the tag: "@i18n" rather than "@i18n true"
33
+ const extractableKeywords: string[] = [
34
+ 'minimum',
35
+ 'maximum',
36
+ 'i18n',
37
+ 'deprecated'
38
+ ]
39
+
40
+ // keywords where a string value is expected, and the string value is the keyword
41
+ const extractableKeywordValues: string[] = ['releaseStage']
42
+
43
+ function extractKeywords(schema: TSchema) {
44
+ const jsDoc: string[] = []
45
+
46
+ if (schema.description) jsDoc.push(schema.description)
47
+ if (schema.remarks) jsDoc.push(tag('remarks', schema.remarks))
48
+ if (schema.pattern)
49
+ jsDoc.push(tag('pattern', wrapCodeBlock(`/${schema.pattern}/`)))
50
+ if (schema.examples)
51
+ jsDoc.push(
52
+ ...schema.examples
53
+ .filter(
54
+ (example: unknown) =>
55
+ typeof example !== 'string' || !example.includes('*')
56
+ )
57
+ .map((example: unknown) => {
58
+ let tagContent = renderJsValue(example)
59
+ if (tagContent.includes('\n'))
60
+ tagContent = formatSourceCode(tagContent)
61
+
62
+ return tag('example', tagContent)
63
+ })
64
+ )
65
+ if (!isUndefined(schema.default)) {
66
+ if (!isEqual(schema.default, schema.const)) {
67
+ let tagContent = renderJsValue(schema.default)
68
+ if (tagContent.includes('\n'))
69
+ tagContent = `\n${formatSourceCode(tagContent)}`
70
+ jsDoc.push(tag('default', tagContent))
71
+ }
72
+ }
73
+
74
+ jsDoc.push(
75
+ ...toTags(
76
+ mapValues(pick(schema, ...extractableKeywords), (v, _k) =>
77
+ v === true ? undefined : v
78
+ )
79
+ )
80
+ )
81
+
82
+ jsDoc.push(
83
+ ...Object.values(pick(schema, ...extractableKeywordValues)).map((k) =>
84
+ tag(k as string)
85
+ )
86
+ )
87
+
88
+ return jsDoc
89
+ }
90
+
91
+ function renderJsDoc(lines: string[]) {
92
+ return [
93
+ '/**',
94
+ ...lines
95
+ .join('\n')
96
+ .split('\n')
97
+ .map((line) => ` * ${line}`),
98
+ ' */'
99
+ ].join('\n')
100
+ }
101
+
102
+ function extractType(schema: TSchema): string {
103
+ switch (true) {
104
+ case TypeGuard.IsIntersect(schema):
105
+ return uniq(schema.allOf.map(extractType))
106
+ .map((type) => (type.includes('|') ? `(${type})` : type))
107
+ .join(' & ')
108
+
109
+ case TypeGuard.IsThis(schema):
110
+ case TypeGuard.IsRef(schema):
111
+ // special case: embedded schema
112
+ return schema.$ref === $schema ? 'unknown' : schema.$ref
113
+ case TypeGuard.IsLiteral(schema):
114
+ return JSON.stringify(schema.const)
115
+ case TypeGuard.IsInteger(schema):
116
+ return 'number'
117
+ case TypeGuard.IsString(schema):
118
+ case TypeGuard.IsBoolean(schema):
119
+ case TypeGuard.IsNull(schema):
120
+ case TypeGuard.IsNumber(schema):
121
+ return schema.type
122
+ case TypeGuard.IsTuple(schema):
123
+ return extractTupleType(schema)
124
+ case TypeGuard.IsArray(schema):
125
+ return extractArrayType(schema)
126
+ case schema[Kind] === 'Object':
127
+ case TypeGuard.IsObject(schema):
128
+ return extractObjectLiteralType(schema as any)
129
+ case TypeGuard.IsUnion(schema):
130
+ case schema[Kind] === 'Union':
131
+ case TNullable(schema):
132
+ return uniq(schema.anyOf.map(extractType)).join(' | ')
133
+ case TypeGuard.IsRecord(schema): {
134
+ const keyType = 'DictKey'
135
+ const valueType = extractType(Object.values(schema.patternProperties)[0])
136
+ return `Record<${keyType}, ${valueType}>`
137
+ }
138
+ case TDiscriminatedUnion(schema):
139
+ return uniq(schema.allOf.map((item) => extractType(item.then))).join(
140
+ ' | '
141
+ )
142
+ case TUnionEnum(schema):
143
+ return uniq(schema.enum.map((v) => JSON.stringify(v))).join(' | ')
144
+
145
+ default: {
146
+ Log.info(JSON.stringify(schema))
147
+ throw new Error(
148
+ `missing transform for kind of ${JSON.stringify(schema?.$id)}: ${JSON.stringify(schema[Kind])}`
149
+ )
150
+ }
151
+ }
152
+ }
153
+
154
+ function extractArrayType(schema: TArray<TSchema>): string {
155
+ const innerType = extractType(schema.items)
156
+ const isComplexType = innerType.match(/[^A-z]/)
157
+ return isComplexType ? `Array<${innerType}>` : `${innerType}[]`
158
+ }
159
+
160
+ type ParsedType = { type: string; jsDoc: string[] }
161
+
162
+ function parseType(schema: TSchema): ParsedType {
163
+ return {
164
+ type: extractType(schema),
165
+ jsDoc: extractKeywords(schema)
166
+ }
167
+ }
168
+
169
+ function indent(text: string, levels = 1) {
170
+ const indentString = repeat('\t', levels)
171
+ return text
172
+ .replaceAll(/\n/g, `\n${indentString}`)
173
+ .replaceAll(/^/g, indentString)
174
+ }
175
+
176
+ function renderProperty(key: string, schema: TSchema) {
177
+ let head = key
178
+ if (TypeGuard.IsOptional(schema)) head += '?'
179
+ const { type, jsDoc } = parseType(schema)
180
+
181
+ const lines = []
182
+
183
+ if (jsDoc.length > 0) lines.push(renderJsDoc(jsDoc))
184
+
185
+ lines.push(`${head}: ${type};`)
186
+
187
+ return lines.join('\n')
188
+ }
189
+
190
+ function renderTypeAlias(identifier: string, schema: TSchema) {
191
+ const data = parseType(schema)
192
+ const lines = []
193
+
194
+ if (data.jsDoc.length > 0) lines.push(renderJsDoc(data.jsDoc))
195
+
196
+ lines.push(`export type ${identifier} = ${data.type}`)
197
+
198
+ return lines.join('\n')
199
+ }
200
+
201
+ function renderInterface(identifier: string, schema: TObject) {
202
+ const data = parseType(schema)
203
+
204
+ const lines = []
205
+
206
+ if (data.jsDoc.length > 0) lines.push(renderJsDoc(data.jsDoc))
207
+
208
+ lines.push(`export interface ${identifier} ${data.type}`)
209
+
210
+ return lines.join('\n')
211
+ }
212
+
213
+ function extractObjectLiteralType(schema: TObject): string {
214
+ const properties = Object.entries(schema.properties).map((entry) =>
215
+ renderProperty(...entry)
216
+ )
217
+ const typeLines = [`{`, indent(properties.join('\n')), `}`]
218
+
219
+ return typeLines.join('\n')
220
+ }
221
+
222
+ function extractTupleType(schema: TTuple): string {
223
+ const items = (schema.items as TSchema[]).map(extractType)
224
+ return [`[`, indent(items.join(',\n')), `]`].join('\n')
225
+ }
226
+
227
+ function tag(tag: string, text?: string) {
228
+ if (text) return `@${tag} ${text}`
229
+ return `@${tag}`
230
+ }
231
+
232
+ function toTags(tags: Record<string, string | undefined>) {
233
+ return Object.entries(tags).map((strings) => tag(...strings))
234
+ }
235
+
236
+ function renderDefinition(identifier: string, schema: TSchema) {
237
+ switch (true) {
238
+ case Typescript in schema:
239
+ return schema[Typescript]?.(identifier, schema)
240
+ case TypeGuard.IsObject(schema):
241
+ return renderInterface(identifier, schema)
242
+ default:
243
+ return renderTypeAlias(identifier, schema)
244
+ }
245
+ }
246
+
247
+ function renderJsValue(value: unknown): string {
248
+ let result: string
249
+ switch (true) {
250
+ case Array.isArray(value):
251
+ result =
252
+ value.length === 0 ? '[]' : `[ ${value.map(renderJsValue).join(', ')} ]`
253
+ break
254
+ case isUndefined(value):
255
+ result = 'undefined'
256
+ break
257
+ case isNull(value):
258
+ result = 'null'
259
+ break
260
+
261
+ case typeof value === 'object':
262
+ result =
263
+ Object.keys(value as any).length === 0
264
+ ? '{}'
265
+ : `{\n${indent(
266
+ map(value as any, (v, k) => `${k}: ${renderJsValue(v)}`).join(
267
+ ',\n'
268
+ )
269
+ )}\n}`
270
+ break
271
+ case typeof value === 'string':
272
+ case typeof value === 'number':
273
+ case typeof value === 'boolean':
274
+ result = JSON.stringify(value)
275
+ break
276
+ default:
277
+ throw new Error()
278
+ }
279
+ return result
280
+ }
281
+
282
+ function wrapCodeBlock(code: string) {
283
+ return `\`\`\`javascript\n${code}\n\`\`\``
284
+ }
285
+
286
+ function formatSourceCode(code: string) {
287
+ if (code.includes('\n')) code = wrapCodeBlock(indent(code))
288
+
289
+ return code
290
+ }
@@ -0,0 +1,75 @@
1
+ // @alpha
2
+ // @beta
3
+ // @category
4
+ // @defaultValue
5
+ // @deprecated
6
+ // @enum
7
+ // @event
8
+ // @eventProperty
9
+ // @example
10
+ // @experimental
11
+ // @group
12
+ // @hidden
13
+ // @ignore
14
+ // {@inheritDoc}
15
+ // @interface
16
+ // @internal
17
+ // {@label}
18
+ // {@link}
19
+ // @module
20
+ // @namespace
21
+ // @overload
22
+ // @override
23
+ // @packageDocumentation
24
+ // @param
25
+ // @private
26
+ // @privateRemarks
27
+ // @property
28
+ // @protected
29
+ // @public
30
+ // @readonly
31
+ // @remarks
32
+ // @returns
33
+ // @satisfies
34
+ // @sealed
35
+ // @see
36
+ // @template
37
+ // @throws
38
+ // @typeParam
39
+
40
+ import { Type } from '@sinclair/typebox'
41
+ import type { KeywordDefinition } from 'ajv'
42
+
43
+ // @virtual
44
+ const _tags: Record<string, Omit<KeywordDefinition, 'keyword'>> = {
45
+ alpha: { metaSchema: Type.Boolean() },
46
+ beta: { metaSchema: Type.Boolean() },
47
+ category: { metaSchema: Type.String() },
48
+ deprecated: { metaSchema: Type.Boolean() },
49
+ event: { metaSchema: Type.Boolean() },
50
+ eventProperty: { metaSchema: Type.Boolean() },
51
+ example: { metaSchema: Type.Boolean() },
52
+ experimental: { metaSchema: Type.Boolean() },
53
+ group: { metaSchema: Type.Array(Type.String()) },
54
+ hidden: { metaSchema: Type.Boolean() },
55
+ ignore: { metaSchema: Type.Boolean() },
56
+ interface: { metaSchema: Type.Boolean() },
57
+ internal: { metaSchema: Type.Boolean() },
58
+ namespace: { metaSchema: Type.Array(Type.String()) },
59
+ overload: { metaSchema: Type.Boolean() },
60
+ override: { metaSchema: Type.Boolean() },
61
+ packageDocumentation: { metaSchema: Type.Boolean() },
62
+ param: { metaSchema: Type.Boolean() },
63
+ private: { metaSchema: Type.Boolean() },
64
+ privateRemarks: { metaSchema: Type.String() },
65
+ property: { metaSchema: Type.Boolean() },
66
+ remarks: { metaSchema: Type.String() },
67
+ returns: { metaSchema: Type.Boolean() },
68
+ satisfies: { metaSchema: Type.Boolean() },
69
+ sealed: { metaSchema: Type.Boolean() },
70
+ see: { metaSchema: Type.Array(Type.String()) },
71
+ template: { metaSchema: Type.Boolean() },
72
+ throws: { metaSchema: Type.Boolean() },
73
+ typeParam: { metaSchema: Type.Boolean() },
74
+ virtual: { metaSchema: Type.Boolean() }
75
+ }
@@ -0,0 +1,35 @@
1
+ import path from 'node:path'
2
+ import { DataswornSchema, DataswornSourceSchema } from '../../schema/Root.js'
3
+ import {
4
+ CORE_COMMON,
5
+ DefsKey,
6
+ DIR_HISTORY_CURRENT,
7
+ ROOT_TYPES_OUT
8
+ } from '../const.js'
9
+ import { emptyDir, writeCode } from '../utils/readWrite.js'
10
+ import { extractDefs } from './schemaToTsDeclaration.js'
11
+
12
+ const rootSchemas = {
13
+ Datasworn: DataswornSchema,
14
+ DataswornSource: DataswornSourceSchema
15
+ } satisfies Record<string, unknown>
16
+
17
+ await emptyDir(ROOT_TYPES_OUT)
18
+
19
+ const writeJobs: Promise<void>[] = []
20
+
21
+ for (const identifier in rootSchemas) {
22
+ const value = rootSchemas[identifier as keyof typeof rootSchemas]
23
+
24
+ const paths = [
25
+ path.join(ROOT_TYPES_OUT, `${identifier}.d.ts`),
26
+ path.join(CORE_COMMON, `${identifier}.ts`),
27
+ path.join(DIR_HISTORY_CURRENT, `${identifier}.d.ts`)
28
+ ]
29
+
30
+ const fileContents = Object.values(extractDefs(value[DefsKey])).join('\n\n')
31
+
32
+ for (const path of paths) writeJobs.push(writeCode(path, fileContents))
33
+ }
34
+
35
+ await Promise.all(writeJobs)
@@ -1,5 +1,5 @@
1
1
  import path from 'node:path'
2
- import { DATASWORN_SCHEMA_VERSION } from '@datasworn-community/core'
2
+ import { DATASWORN_SCHEMA_VERSION, IdElements } from '@datasworn-community/core'
3
3
 
4
4
  const root = process.cwd()
5
5
 
@@ -16,7 +16,12 @@ export const ROOT_OUTPUT = path.join(root, 'datasworn')
16
16
  export const ROOT_SOURCE_DATA = path.join(root, 'source_data')
17
17
  export const ROOT_HISTORY = path.join(root, 'packages/core/migration')
18
18
  export const DIR_HISTORY_CURRENT = path.join(ROOT_HISTORY, VERSION)
19
- export const ROOT_TYPES_OUT = path.join(root, 'packages/core/src')
19
+ // Disposable scratch copy of generated types, emptied and rewritten on every
20
+ // `generate` run. Must stay distinct from CORE_COMMON: writeTypescriptTypes
21
+ // empties this directory before writing, and CORE_COMMON holds core's
22
+ // hand-written runtime source alongside the generated Datasworn.ts/
23
+ // DataswornSource.ts files.
24
+ export const ROOT_TYPES_OUT = path.join(root, '.generated/types')
20
25
  export const CORE_COMMON = path.join(root, 'packages/core/src')
21
26
 
22
27
  export const SCHEMA_PATH = path.join(
@@ -53,3 +58,36 @@ export const DefsKey = 'definitions' as const
53
58
 
54
59
  /** Identifier for the type at the root of a Datasworn JSON file. */
55
60
  export const rootSchemaName = 'RulesPackage'
61
+
62
+ // Re-exported from core's IdElements/CONST.js. Upstream colocates these
63
+ // scripts with pkg-core under one `src/`, so its const.ts can `export *`
64
+ // straight from the relative path; here build-tools and core are separate
65
+ // workspace packages, so the keys are re-exported through core's public API.
66
+ export const COLLECTION_DEPTH_MAX = IdElements.CONST.COLLECTION_DEPTH_MAX
67
+ export type COLLECTION_DEPTH_MAX = typeof COLLECTION_DEPTH_MAX
68
+ export const COLLECTION_DEPTH_MIN = IdElements.CONST.COLLECTION_DEPTH_MIN
69
+ export type COLLECTION_DEPTH_MIN = typeof COLLECTION_DEPTH_MIN
70
+ export const MdLinkPrefix = IdElements.CONST.MdLinkPrefix
71
+ export type MdLinkPrefix = typeof MdLinkPrefix
72
+ export const PathKeySep = IdElements.CONST.PathKeySep
73
+ export type PathKeySep = typeof PathKeySep
74
+ export const TypeSep = IdElements.CONST.TypeSep
75
+ export type TypeSep = typeof TypeSep
76
+ export const PrefixSep = IdElements.CONST.PrefixSep
77
+ export type PrefixSep = typeof PrefixSep
78
+ export const WildcardString = IdElements.CONST.WildcardString
79
+ export type WildcardString = typeof WildcardString
80
+ export const GlobstarString = IdElements.CONST.GlobstarString
81
+ export type GlobstarString = typeof GlobstarString
82
+ export const CollectionsKey = IdElements.CONST.CollectionsKey
83
+ export type CollectionsKey = typeof CollectionsKey
84
+ export const ContentsKey = IdElements.CONST.ContentsKey
85
+ export type ContentsKey = typeof ContentsKey
86
+ export const EnhancesKey = IdElements.CONST.EnhancesKey
87
+ export type EnhancesKey = typeof EnhancesKey
88
+ export const ReplacesKey = IdElements.CONST.ReplacesKey
89
+ export type ReplacesKey = typeof ReplacesKey
90
+ export const IdKey = IdElements.CONST.IdKey
91
+ export type IdKey = typeof IdKey
92
+ export const SourceInfoKey = IdElements.CONST.SourceInfoKey
93
+ export type SourceInfoKey = typeof SourceInfoKey