tsondb 0.21.1 → 0.21.2
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/dist/src/node/config.d.ts +2 -2
- package/dist/src/node/git.d.ts +4 -4
- package/dist/src/node/index.d.ts +39 -4
- package/dist/src/node/index.js +112 -11
- package/dist/src/node/renderers/jsonschema/render.js +7 -0
- package/dist/src/node/renderers/ts/render.d.ts +4 -0
- package/dist/src/node/renderers/ts/render.js +6 -0
- package/dist/src/node/schema/dsl/declarations/Decl.d.ts +3 -2
- package/dist/src/node/schema/dsl/declarations/Decl.js +2 -1
- package/dist/src/node/schema/dsl/declarations/SingletonEntityDecl.d.ts +35 -0
- package/dist/src/node/schema/dsl/declarations/SingletonEntityDecl.js +23 -0
- package/dist/src/node/schema/dsl/index.d.ts +1 -0
- package/dist/src/node/schema/dsl/index.js +1 -0
- package/dist/src/node/schema/generatedTypeHelpers.d.ts +18 -0
- package/dist/src/node/schema/guards.d.ts +1 -0
- package/dist/src/node/schema/guards.js +1 -0
- package/dist/src/node/schema/helpers.js +1 -0
- package/dist/src/node/schema/index.d.ts +12 -1
- package/dist/src/node/schema/index.js +44 -0
- package/dist/src/node/schema/treeOperations/customConstraints.d.ts +2 -1
- package/dist/src/node/schema/treeOperations/customConstraints.js +10 -10
- package/dist/src/node/schema/treeOperations/implicitSchema.js +1 -0
- package/dist/src/node/schema/treeOperations/references.js +1 -0
- package/dist/src/node/schema/treeOperations/serialization.d.ts +4 -1
- package/dist/src/node/schema/treeOperations/serialization.js +8 -0
- package/dist/src/node/schema/treeOperations/typeResolution.d.ts +4 -1
- package/dist/src/node/schema/treeOperations/typeResolution.js +6 -0
- package/dist/src/node/schema/treeOperations/validation.js +2 -0
- package/dist/src/node/server/api/declarations.js +165 -23
- package/dist/src/node/transaction.d.ts +28 -11
- package/dist/src/node/transaction.js +93 -0
- package/dist/src/node/utils/customConstraints.d.ts +6 -5
- package/dist/src/node/utils/customConstraints.js +34 -15
- package/dist/src/node/utils/databaseInMemory.d.ts +20 -8
- package/dist/src/node/utils/databaseInMemory.js +67 -9
- package/dist/src/node/utils/databaseOnDisk.js +27 -30
- package/dist/src/node/utils/files.d.ts +7 -2
- package/dist/src/node/utils/files.js +9 -0
- package/dist/src/node/utils/references.d.ts +2 -0
- package/dist/src/node/utils/references.js +6 -1
- package/dist/src/shared/api.d.ts +41 -2
- package/dist/src/shared/schema/Node.d.ts +5 -1
- package/dist/src/shared/schema/Node.js +6 -0
- package/dist/src/shared/schema/declarations/Declaration.d.ts +3 -2
- package/dist/src/shared/schema/declarations/SingletonEntityDecl.d.ts +18 -0
- package/dist/src/shared/schema/declarations/SingletonEntityDecl.js +8 -0
- package/dist/src/shared/utils/childInstances.d.ts +4 -0
- package/dist/src/shared/utils/instances.d.ts +4 -0
- package/dist/src/web/web.js +573 -130
- package/package.json +1 -1
- package/public/css/styles.css +1 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { FormatterOptions as MarkdownFormatterOptions } from "@elyukai/markdown/format";
|
|
2
2
|
import type { DefaultTSONDBTypes, ValidationOptions } from "./index.ts";
|
|
3
3
|
import type { Output } from "./output.ts";
|
|
4
|
-
import type { EntityDecl } from "./schema/dsl/index.ts";
|
|
4
|
+
import type { EntityDecl, SingletonEntityDecl } from "./schema/dsl/index.ts";
|
|
5
5
|
import type { Schema } from "./schema/index.ts";
|
|
6
6
|
/**
|
|
7
7
|
* The main configuration type for TSONDB.
|
|
@@ -33,7 +33,7 @@ export type ServerOptions = {
|
|
|
33
33
|
export type HomeLayoutSection = {
|
|
34
34
|
title: string;
|
|
35
35
|
comment?: string;
|
|
36
|
-
entities: EntityDecl[];
|
|
36
|
+
entities: (EntityDecl | SingletonEntityDecl)[];
|
|
37
37
|
};
|
|
38
38
|
/**
|
|
39
39
|
* The configuration type required for generation commands.
|
package/dist/src/node/git.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { SimpleGit } from "simple-git";
|
|
2
2
|
import type { InstanceContainerOverview } from "../shared/utils/instances.ts";
|
|
3
|
-
import type { DefaultTSONDBTypes,
|
|
3
|
+
import type { DefaultTSONDBTypes, StoringEntityName, TSONDB } from "./index.ts";
|
|
4
4
|
import type { DatabaseInMemory } from "./utils/databaseInMemory.ts";
|
|
5
5
|
export declare class Git<T extends DefaultTSONDBTypes = DefaultTSONDBTypes> {
|
|
6
6
|
#private;
|
|
@@ -36,7 +36,7 @@ export declare class Git<T extends DefaultTSONDBTypes = DefaultTSONDBTypes> {
|
|
|
36
36
|
*
|
|
37
37
|
* @throws {HTTPError} when no git repository is found
|
|
38
38
|
*/
|
|
39
|
-
stage(entity?:
|
|
39
|
+
stage(entity?: StoringEntityName<T>, id?: string): Promise<void>;
|
|
40
40
|
/**
|
|
41
41
|
* Removes files from the git staging area.
|
|
42
42
|
*
|
|
@@ -46,7 +46,7 @@ export declare class Git<T extends DefaultTSONDBTypes = DefaultTSONDBTypes> {
|
|
|
46
46
|
*
|
|
47
47
|
* @throws {HTTPError} when no git repository is found
|
|
48
48
|
*/
|
|
49
|
-
unstage(entity?:
|
|
49
|
+
unstage(entity?: StoringEntityName<T>, id?: string): Promise<void>;
|
|
50
50
|
/**
|
|
51
51
|
* Restores files in the git repository to their last committed state.
|
|
52
52
|
*
|
|
@@ -56,7 +56,7 @@ export declare class Git<T extends DefaultTSONDBTypes = DefaultTSONDBTypes> {
|
|
|
56
56
|
*
|
|
57
57
|
* @throws {HTTPError} when no git repository is found
|
|
58
58
|
*/
|
|
59
|
-
restore(entity?:
|
|
59
|
+
restore(entity?: StoringEntityName<T>, id?: string): Promise<void>;
|
|
60
60
|
/**
|
|
61
61
|
* Commits staged changes to the git repository with the provided commit message.
|
|
62
62
|
*
|
package/dist/src/node/index.d.ts
CHANGED
|
@@ -1,23 +1,27 @@
|
|
|
1
|
-
import type { InstanceContainer, InstanceContainerOverview } from "../shared/utils/instances.ts";
|
|
1
|
+
import type { InstanceContainer, InstanceContainerOverview, SingletonInstanceContainer } from "../shared/utils/instances.ts";
|
|
2
2
|
import type { FormatterOptions } from "./config.ts";
|
|
3
3
|
import { Git } from "./git.js";
|
|
4
4
|
import type { Output } from "./output.ts";
|
|
5
5
|
import { type EntityDecl } from "./schema/dsl/index.ts";
|
|
6
|
-
import type { AnyChildEntityMap, AnyEntityMap, AnyEnumMap, AnyTypeAliasMap } from "./schema/generatedTypeHelpers.ts";
|
|
6
|
+
import type { AnyChildEntityMap, AnyEntityMap, AnyEnumMap, AnySingletonEntityMap, AnyTypeAliasMap } from "./schema/generatedTypeHelpers.ts";
|
|
7
7
|
import { type IdArgsVariant } from "./schema/generatedTypeHelpers.ts";
|
|
8
8
|
import type { Schema } from "./schema/index.ts";
|
|
9
9
|
import { Transaction } from "./transaction.ts";
|
|
10
10
|
export interface DefaultTSONDBTypes {
|
|
11
11
|
entityMap: AnyEntityMap;
|
|
12
|
+
singletonEntityMap: AnySingletonEntityMap;
|
|
12
13
|
childEntityMap: AnyChildEntityMap;
|
|
13
14
|
enumMap: AnyEnumMap;
|
|
14
15
|
typeAliasMap: AnyTypeAliasMap;
|
|
15
16
|
}
|
|
16
17
|
export type Entity<T extends DefaultTSONDBTypes, E extends EntityName<T>> = T["entityMap"][E];
|
|
17
18
|
export type EntityName<T extends DefaultTSONDBTypes> = Extract<keyof T["entityMap"], string>;
|
|
19
|
+
export type SingletonEntity<T extends DefaultTSONDBTypes, E extends SingletonEntityName<T>> = T["singletonEntityMap"][E];
|
|
20
|
+
export type SingletonEntityName<T extends DefaultTSONDBTypes> = Extract<keyof T["singletonEntityMap"], string>;
|
|
18
21
|
export type EnumName<T extends DefaultTSONDBTypes> = Extract<keyof T["enumMap"], string>;
|
|
19
22
|
export type TypeAliasName<T extends DefaultTSONDBTypes> = Extract<keyof T["typeAliasMap"], string>;
|
|
20
|
-
export type
|
|
23
|
+
export type StoringEntityName<T extends DefaultTSONDBTypes> = EntityName<T> | SingletonEntityName<T>;
|
|
24
|
+
export type DeclarationName<T extends DefaultTSONDBTypes> = EntityName<T> | SingletonEntityName<T> | EnumName<T> | TypeAliasName<T>;
|
|
21
25
|
export type ChildEntity<T extends DefaultTSONDBTypes, E extends ChildEntityName<T>> = T["childEntityMap"][E][0];
|
|
22
26
|
export type ChildEntityConfig<T extends DefaultTSONDBTypes, E extends ChildEntityName<T>> = T["childEntityMap"][E];
|
|
23
27
|
export type ChildEntityName<T extends DefaultTSONDBTypes> = Extract<keyof T["childEntityMap"], string>;
|
|
@@ -148,7 +152,7 @@ export declare class TSONDB<T extends DefaultTSONDBTypes = DefaultTSONDBTypes> {
|
|
|
148
152
|
* The provided function is called with a `Transaction` object, which can be used to create, update, or delete instances. If an error is thrown during the execution of the function, the transaction is rolled back and no changes are made to the database.
|
|
149
153
|
* @throws {Error} when the transaction could not be completed
|
|
150
154
|
*/
|
|
151
|
-
runTransaction<R>(fn: (transaction: Transaction<T["entityMap"]>) => [Transaction<T["entityMap"]>, R]): Promise<R>;
|
|
155
|
+
runTransaction<R>(fn: (transaction: Transaction<T["entityMap"], T["singletonEntityMap"]>) => [Transaction<T["entityMap"], T["singletonEntityMap"]>, R]): Promise<R>;
|
|
152
156
|
/**
|
|
153
157
|
* Creates a new instance in the database.
|
|
154
158
|
*
|
|
@@ -168,6 +172,25 @@ export declare class TSONDB<T extends DefaultTSONDBTypes = DefaultTSONDBTypes> {
|
|
|
168
172
|
* @throws {Error} when the instance could not be deleted
|
|
169
173
|
*/
|
|
170
174
|
deleteInstance<E extends EntityName<T>>(entityName: E, id: string): Promise<Entity<T, E>>;
|
|
175
|
+
/**
|
|
176
|
+
* Creates a new singleton instance in the database.
|
|
177
|
+
*
|
|
178
|
+
* If the instance is of the locale entity, a locale identifier must be provided as `id`.
|
|
179
|
+
* @throws {Error} when the instance could not be created
|
|
180
|
+
*/
|
|
181
|
+
createSingletonInstance<E extends SingletonEntityName<T>>(entityName: E, content: SingletonEntity<T, E>): Promise<SingletonInstanceContainer<SingletonEntity<T, E>>>;
|
|
182
|
+
/**
|
|
183
|
+
* Updates a singleton instance in the database.
|
|
184
|
+
*
|
|
185
|
+
* @throws {Error} when the instance could not be updated
|
|
186
|
+
*/
|
|
187
|
+
updateSingletonInstance<E extends SingletonEntityName<T>>(entityName: E, content: SingletonEntity<T, E>): Promise<SingletonInstanceContainer<SingletonEntity<T, E>>>;
|
|
188
|
+
/**
|
|
189
|
+
* Deletes a singleton instance in the database.
|
|
190
|
+
*
|
|
191
|
+
* @throws {Error} when the instance could not be deleted
|
|
192
|
+
*/
|
|
193
|
+
deleteSingletonInstance<E extends SingletonEntityName<T>>(entityName: E): Promise<SingletonEntity<T, E>>;
|
|
171
194
|
/**
|
|
172
195
|
* Retrieves an instance of the specified entity by its identifier.
|
|
173
196
|
*/
|
|
@@ -192,10 +215,22 @@ export declare class TSONDB<T extends DefaultTSONDBTypes = DefaultTSONDBTypes> {
|
|
|
192
215
|
* Retrieves all instance overviews of the specified entity.
|
|
193
216
|
*/
|
|
194
217
|
getAllInstanceOverviewsOfEntity(entity: EntityDecl<EntityName<T>> | EntityName<T>): InstanceContainerOverview[];
|
|
218
|
+
/**
|
|
219
|
+
* Retrieves an instance of the specified entity by its identifier.
|
|
220
|
+
*/
|
|
221
|
+
getSingletonInstanceOfEntity<E extends SingletonEntityName<T>>(entityName: E): T["singletonEntityMap"][E] | undefined;
|
|
222
|
+
/**
|
|
223
|
+
* Retrieves the instance container of the specified entity by its identifier.
|
|
224
|
+
*/
|
|
225
|
+
getSingletonInstanceContainerOfEntity<E extends SingletonEntityName<T>>(entityName: E): SingletonInstanceContainer<T["singletonEntityMap"][E]> | undefined;
|
|
195
226
|
/**
|
|
196
227
|
* Counts the number of instances registered for the specified entity.
|
|
197
228
|
*/
|
|
198
229
|
countInstancesOfEntity(entityName: EntityName<T>): number;
|
|
230
|
+
/**
|
|
231
|
+
* Returns whether the singleton entity has an instance.
|
|
232
|
+
*/
|
|
233
|
+
hasInstanceOfSingletonEntity(entityName: SingletonEntityName<T>): boolean;
|
|
199
234
|
/**
|
|
200
235
|
* Retrieves overviews for all instances in the database, grouped by entity name.
|
|
201
236
|
*/
|
package/dist/src/node/index.js
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import { on } from "@elyukai/utils/function";
|
|
2
2
|
import { Lazy } from "@elyukai/utils/lazy";
|
|
3
|
+
import { nullableToArray } from "@elyukai/utils/nullable";
|
|
3
4
|
import { compareNumber, reduceCompare } from "@elyukai/utils/ordering";
|
|
4
5
|
import { isError } from "@elyukai/utils/result";
|
|
6
|
+
import { assertExhaustive } from "@elyukai/utils/typeSafety";
|
|
5
7
|
import Debug from "debug";
|
|
6
8
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
7
9
|
import { join, sep } from "node:path";
|
|
8
10
|
import { stderr } from "node:process";
|
|
9
11
|
import { styleText } from "node:util";
|
|
10
12
|
import { simpleGit } from "simple-git";
|
|
13
|
+
import { NodeKind } from "../shared/schema/Node.js";
|
|
11
14
|
import { parallelizeErrors } from "../shared/utils/validation.js";
|
|
12
15
|
import { Git } from "./git.js";
|
|
13
16
|
import { getDisplayName, getDisplayNameWithId } from "./schema/detached.js";
|
|
14
17
|
import {} from "./schema/dsl/index.js";
|
|
15
18
|
import {} from "./schema/generatedTypeHelpers.js";
|
|
16
|
-
import { isEntityDeclWithParentReference } from "./schema/guards.js";
|
|
19
|
+
import { isEntityDecl, isEntityDeclWithParentReference } from "./schema/guards.js";
|
|
17
20
|
import { serializeNode } from "./schema/treeOperations/serialization.js";
|
|
18
21
|
import { createEntityNameValidator, createReferenceValidator, validateDeclReferentialIntegrity, validateDeclStructuralIntegrity, } from "./schema/treeOperations/validation.js";
|
|
19
22
|
import { Transaction } from "./transaction.js";
|
|
@@ -22,7 +25,7 @@ import { DatabaseInMemory } from "./utils/databaseInMemory.js";
|
|
|
22
25
|
import { applyStepsToDisk } from "./utils/databaseOnDisk.js";
|
|
23
26
|
import { getAllInstanceOverviewsByEntityName, getDisplayNameFromEntityInstance, getInstanceOverview, getInstanceOverviewsByEntityName, } from "./utils/displayName.js";
|
|
24
27
|
import { countError, countErrors, getErrorMessageForDisplay, HTTPError, wrapErrorsIfAny, } from "./utils/error.js";
|
|
25
|
-
import { formatInstance, getFileNameForId, readInstance, writeInstance } from "./utils/files.js";
|
|
28
|
+
import { formatInstance, getFileNameForId, getSingletonFileName, readInstance, readSingletonInstance, writeInstance, writeSingletonInstance, } from "./utils/files.js";
|
|
26
29
|
import { attachGitStatusToDatabaseInMemory } from "./utils/git.js";
|
|
27
30
|
import { getReferencesToInstances, isReferencedByOtherInstances, } from "./utils/references.js";
|
|
28
31
|
import { checkUniqueConstraintsForAllEntities } from "./utils/unique.js";
|
|
@@ -64,7 +67,7 @@ const checkLocales = (schema, data, locales) => {
|
|
|
64
67
|
};
|
|
65
68
|
const initData = async (dataRootPath, schema, locales, git, gitStatus, skipReferenceCache) => {
|
|
66
69
|
debug("loading database into memory ...");
|
|
67
|
-
let data = await DatabaseInMemory.load(dataRootPath, schema.entities);
|
|
70
|
+
let data = await DatabaseInMemory.load(dataRootPath, schema.entities, schema.singletonEntities);
|
|
68
71
|
debug("done");
|
|
69
72
|
checkLocales(schema, data, locales);
|
|
70
73
|
const serializedDeclarationsByName = Object.fromEntries(schema.resolvedDeclarations.map(decl => [decl.name, serializeNode(decl)]));
|
|
@@ -172,7 +175,7 @@ export class TSONDB {
|
|
|
172
175
|
#validate(data, options = {}) {
|
|
173
176
|
const { checkReferentialIntegrity, checkOnlyEntities } = this.#validationOptions;
|
|
174
177
|
const { skipStructuralValidation = false, logToConsole = true, changedEntities: changedEntityNames, } = options;
|
|
175
|
-
const entities = this.#schema.entities;
|
|
178
|
+
const entities = [...this.#schema.entities, ...this.#schema.singletonEntities];
|
|
176
179
|
const getEntity = this.#schema.getEntity.bind(this.#schema);
|
|
177
180
|
for (const onlyEntity of checkOnlyEntities) {
|
|
178
181
|
if (!entities.find(entity => entity.name === onlyEntity)) {
|
|
@@ -193,9 +196,23 @@ export class TSONDB {
|
|
|
193
196
|
if (!skipStructuralValidation) {
|
|
194
197
|
debug("Checking structural integrity ...");
|
|
195
198
|
const structureErrors = onlyEntities
|
|
196
|
-
.flatMap(entity =>
|
|
197
|
-
|
|
198
|
-
|
|
199
|
+
.flatMap(entity => {
|
|
200
|
+
switch (entity.kind) {
|
|
201
|
+
case NodeKind.EntityDecl:
|
|
202
|
+
return parallelizeErrors(data
|
|
203
|
+
.getAllInstanceContainersOfEntity(entity.name)
|
|
204
|
+
.map(instance => wrapErrorsIfAny(`in file ${styleText("white", `"${this.#dataRootPath}${sep}${styleText("bold", join(entity.name, getFileNameForId(instance.id)))}"`)}`, validateDeclStructuralIntegrity(validationContext, [], entity, [], instance.content))));
|
|
205
|
+
case NodeKind.SingletonEntityDecl: {
|
|
206
|
+
const instance = data.getSingletonInstanceContainerOfEntity(entity.name);
|
|
207
|
+
if (instance) {
|
|
208
|
+
return nullableToArray(wrapErrorsIfAny(`in file ${styleText("white", `"${this.#dataRootPath}${sep}${styleText("bold", getSingletonFileName(entity.name))}"`)}`, validateDeclStructuralIntegrity(validationContext, [], entity, [], instance.content)));
|
|
209
|
+
}
|
|
210
|
+
return [];
|
|
211
|
+
}
|
|
212
|
+
default:
|
|
213
|
+
return assertExhaustive(entity);
|
|
214
|
+
}
|
|
215
|
+
})
|
|
199
216
|
.toSorted((a, b) => a.message.localeCompare(b.message));
|
|
200
217
|
if (structureErrors.length > 0) {
|
|
201
218
|
const errorCount = countErrors(structureErrors);
|
|
@@ -213,9 +230,23 @@ export class TSONDB {
|
|
|
213
230
|
const entityNameValidator = createEntityNameValidator(this.#schema.isEntityName.bind(this.#schema), true);
|
|
214
231
|
const referenceValidator = createReferenceValidator(this.#schema.isEntityName.bind(this.#schema), data, true);
|
|
215
232
|
const referenceErrors = onlyEntities
|
|
216
|
-
.flatMap(entity =>
|
|
217
|
-
|
|
218
|
-
|
|
233
|
+
.flatMap(entity => {
|
|
234
|
+
switch (entity.kind) {
|
|
235
|
+
case NodeKind.EntityDecl:
|
|
236
|
+
return parallelizeErrors(data
|
|
237
|
+
.getAllInstanceContainersOfEntity(entity.name)
|
|
238
|
+
.map(instance => wrapErrorsIfAny(`in file ${styleText("white", `"${this.#dataRootPath}${sep}${styleText("bold", join(entity.name, getFileNameForId(instance.id)))}"`)}`, validateDeclReferentialIntegrity(validationContext, entityNameValidator, referenceValidator, [], entity, [], instance.content))));
|
|
239
|
+
case NodeKind.SingletonEntityDecl: {
|
|
240
|
+
const instance = data.getSingletonInstanceContainerOfEntity(entity.name);
|
|
241
|
+
if (instance) {
|
|
242
|
+
return nullableToArray(wrapErrorsIfAny(`in file ${styleText("white", `"${this.#dataRootPath}${sep}${styleText("bold", getSingletonFileName(entity.name))}"`)}`, validateDeclReferentialIntegrity(validationContext, entityNameValidator, referenceValidator, [], entity, [], instance.content)));
|
|
243
|
+
}
|
|
244
|
+
return [];
|
|
245
|
+
}
|
|
246
|
+
default:
|
|
247
|
+
return assertExhaustive(entity);
|
|
248
|
+
}
|
|
249
|
+
})
|
|
219
250
|
.toSorted((a, b) => a.message.localeCompare(b.message));
|
|
220
251
|
if (referenceErrors.length > 0) {
|
|
221
252
|
const errorCount = countErrors(referenceErrors);
|
|
@@ -232,7 +263,7 @@ export class TSONDB {
|
|
|
232
263
|
}
|
|
233
264
|
debug("Checking unique constraints ...");
|
|
234
265
|
const instanceOverviewsByEntityName = getAllInstanceOverviewsByEntityName(getEntity, data, this.#locales);
|
|
235
|
-
const uniqueConstraintResult = checkUniqueConstraintsForAllEntities(data, changedEntities ?? onlyEntities, instanceOverviewsByEntityName);
|
|
266
|
+
const uniqueConstraintResult = checkUniqueConstraintsForAllEntities(data, (changedEntities ?? onlyEntities).filter(e => isEntityDecl(e)), instanceOverviewsByEntityName);
|
|
236
267
|
if (isError(uniqueConstraintResult)) {
|
|
237
268
|
const errorCount = countError(uniqueConstraintResult.error);
|
|
238
269
|
debug(`${errorCount.toString()} unique constraint violation${errorCount === 1 ? "" : "s"} found`);
|
|
@@ -286,6 +317,11 @@ export class TSONDB {
|
|
|
286
317
|
const entity = this.#schema.getEntity(entityName);
|
|
287
318
|
await writeInstance(this.#dataRootPath, entity, instance.id, instance.content, this.#formatterOptions);
|
|
288
319
|
}, true);
|
|
320
|
+
await this.#data.forEachSingletonInstance(async (entityName, instance) => {
|
|
321
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
322
|
+
const entity = this.#schema.getSingletonEntity(entityName);
|
|
323
|
+
await writeSingletonInstance(this.#dataRootPath, entity, instance.content, this.#formatterOptions);
|
|
324
|
+
}, true);
|
|
289
325
|
debug("All data is formatted");
|
|
290
326
|
}
|
|
291
327
|
/**
|
|
@@ -306,6 +342,17 @@ export class TSONDB {
|
|
|
306
342
|
}
|
|
307
343
|
total++;
|
|
308
344
|
}, true);
|
|
345
|
+
await this.#data.forEachSingletonInstance(async (entityName, instance) => {
|
|
346
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
347
|
+
const entity = this.#schema.getSingletonEntity(entityName);
|
|
348
|
+
const instanceOnDisk = await readSingletonInstance(this.#dataRootPath, entity);
|
|
349
|
+
const currentFormatted = formatInstance(entity, instance.content, this.#formatterOptions);
|
|
350
|
+
if (instanceOnDisk !== currentFormatted) {
|
|
351
|
+
console.log(`Singleton instance of entity ${styleText("cyan", entityName)} is not formatted correctly.`);
|
|
352
|
+
counter++;
|
|
353
|
+
}
|
|
354
|
+
total++;
|
|
355
|
+
}, true);
|
|
309
356
|
if (counter === 0) {
|
|
310
357
|
console.log(styleText("green", `All ${total.toFixed()} instance${total === 1 ? "" : "s"} are formatted correctly`));
|
|
311
358
|
return true;
|
|
@@ -342,9 +389,11 @@ export class TSONDB {
|
|
|
342
389
|
this.#locked = true;
|
|
343
390
|
try {
|
|
344
391
|
const getEntity = this.#schema.getEntity.bind(this.#schema);
|
|
392
|
+
const getSingletonEntity = this.#schema.getSingletonEntity.bind(this.#schema);
|
|
345
393
|
const [txn, res] = fn(new Transaction({
|
|
346
394
|
data: this.#data,
|
|
347
395
|
getEntity,
|
|
396
|
+
getSingletonEntity,
|
|
348
397
|
referencesToInstances: this.#referencesToInstances,
|
|
349
398
|
validate: this.#strucurallyValidateInstance.bind(this),
|
|
350
399
|
localeEntity: this.#schema.localeEntity,
|
|
@@ -426,6 +475,40 @@ export class TSONDB {
|
|
|
426
475
|
txn.deleteInstance(this.#schema.getEntity(entityName), id));
|
|
427
476
|
return res.content;
|
|
428
477
|
}
|
|
478
|
+
/**
|
|
479
|
+
* Creates a new singleton instance in the database.
|
|
480
|
+
*
|
|
481
|
+
* If the instance is of the locale entity, a locale identifier must be provided as `id`.
|
|
482
|
+
* @throws {Error} when the instance could not be created
|
|
483
|
+
*/
|
|
484
|
+
async createSingletonInstance(entityName, content) {
|
|
485
|
+
const res = await this.runTransaction(txn =>
|
|
486
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
487
|
+
txn.createSingletonInstance(this.#schema.getSingletonEntity(entityName), content));
|
|
488
|
+
return res;
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Updates a singleton instance in the database.
|
|
492
|
+
*
|
|
493
|
+
* @throws {Error} when the instance could not be updated
|
|
494
|
+
*/
|
|
495
|
+
async updateSingletonInstance(entityName, content) {
|
|
496
|
+
const res = await this.runTransaction(txn =>
|
|
497
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
498
|
+
txn.updateSingletonInstance(this.#schema.getSingletonEntity(entityName), content));
|
|
499
|
+
return res;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Deletes a singleton instance in the database.
|
|
503
|
+
*
|
|
504
|
+
* @throws {Error} when the instance could not be deleted
|
|
505
|
+
*/
|
|
506
|
+
async deleteSingletonInstance(entityName) {
|
|
507
|
+
const res = await this.runTransaction(txn =>
|
|
508
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
509
|
+
txn.deleteSingletonInstance(this.#schema.getSingletonEntity(entityName)));
|
|
510
|
+
return res.content;
|
|
511
|
+
}
|
|
429
512
|
/**
|
|
430
513
|
* Retrieves an instance of the specified entity by its identifier.
|
|
431
514
|
*/
|
|
@@ -466,12 +549,30 @@ export class TSONDB {
|
|
|
466
549
|
}
|
|
467
550
|
return getInstanceOverviewsByEntityName(this.getInstanceContainerOfEntityById.bind(this), this.getAllChildInstanceContainersForParent.bind(this), this.#schema.getEntity.bind(this.#schema), normEntity, this.getAllInstanceContainersOfEntity(normEntity.name), this.#locales);
|
|
468
551
|
}
|
|
552
|
+
/**
|
|
553
|
+
* Retrieves an instance of the specified entity by its identifier.
|
|
554
|
+
*/
|
|
555
|
+
getSingletonInstanceOfEntity(entityName) {
|
|
556
|
+
return this.#data.getSingletonInstanceOfEntity(entityName);
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Retrieves the instance container of the specified entity by its identifier.
|
|
560
|
+
*/
|
|
561
|
+
getSingletonInstanceContainerOfEntity(entityName) {
|
|
562
|
+
return this.#data.getSingletonInstanceContainerOfEntity(entityName);
|
|
563
|
+
}
|
|
469
564
|
/**
|
|
470
565
|
* Counts the number of instances registered for the specified entity.
|
|
471
566
|
*/
|
|
472
567
|
countInstancesOfEntity(entityName) {
|
|
473
568
|
return this.#data.countInstancesOfEntity(entityName);
|
|
474
569
|
}
|
|
570
|
+
/**
|
|
571
|
+
* Returns whether the singleton entity has an instance.
|
|
572
|
+
*/
|
|
573
|
+
hasInstanceOfSingletonEntity(entityName) {
|
|
574
|
+
return this.#data.hasInstanceOfSingletonEntity(entityName);
|
|
575
|
+
}
|
|
475
576
|
/**
|
|
476
577
|
* Retrieves overviews for all instances in the database, grouped by entity name.
|
|
477
578
|
*/
|
|
@@ -156,6 +156,11 @@ const renderEntityDecl = (options, decl) => ({
|
|
|
156
156
|
deprecated: decl.isDeprecated,
|
|
157
157
|
...renderType(options, addEphemeralUUIDToType(decl)),
|
|
158
158
|
});
|
|
159
|
+
const renderSingletonEntityDecl = (options, decl) => ({
|
|
160
|
+
description: decl.comment,
|
|
161
|
+
deprecated: decl.isDeprecated,
|
|
162
|
+
...renderType(options, decl.type.value),
|
|
163
|
+
});
|
|
159
164
|
const renderEnumDecl = (options, decl) => ({
|
|
160
165
|
description: decl.comment,
|
|
161
166
|
deprecated: decl.isDeprecated,
|
|
@@ -170,6 +175,8 @@ const renderDecl = (options, decl) => {
|
|
|
170
175
|
switch (decl.kind) {
|
|
171
176
|
case NodeKind.EntityDecl:
|
|
172
177
|
return renderEntityDecl({ ...options, parentDecl: decl }, decl);
|
|
178
|
+
case NodeKind.SingletonEntityDecl:
|
|
179
|
+
return renderSingletonEntityDecl({ ...options, parentDecl: decl }, decl);
|
|
173
180
|
case NodeKind.EnumDecl:
|
|
174
181
|
return renderEnumDecl({ ...options, parentDecl: decl }, decl);
|
|
175
182
|
case NodeKind.TypeAliasDecl:
|
|
@@ -8,6 +8,10 @@ export type TypeScriptRendererOptions = {
|
|
|
8
8
|
* If `true` or a string, generates an object type with all names of the entities as the key and their corresponding generated type as their respective value. Uses `EntityMap` as a default name when using `true` or the string if set to a string.
|
|
9
9
|
*/
|
|
10
10
|
entityMap: boolean | string;
|
|
11
|
+
/**
|
|
12
|
+
* If `true` or a string, generates an object type with all names of the singleton entities as the key and their corresponding generated type as their respective value. Uses `SingletonEntityMap` as a default name when using `true` or the string if set to a string.
|
|
13
|
+
*/
|
|
14
|
+
singletonEntityMap: boolean | string;
|
|
11
15
|
/**
|
|
12
16
|
* If `true` or a string, generates an object type with all names of entities with parent references as the key and their corresponding generated type as well as their parent reference key as their respective value. Uses `ChildEntityMap` as a default name when using `true` or the string if set to a string.
|
|
13
17
|
*/
|
|
@@ -9,6 +9,7 @@ import { extractParameterTypeNamesFromMessage, mapParameterTypeNames, } from "..
|
|
|
9
9
|
import { asDecl } from "../../schema/dsl/declarations/Decl.js";
|
|
10
10
|
import { addEphemeralUUIDToType, createEntityIdentifierTypeAsDecl, isEntityDecl, isEntityDeclWithParentReference, } from "../../schema/dsl/declarations/EntityDecl.js";
|
|
11
11
|
import { isEnumDecl } from "../../schema/dsl/declarations/EnumDecl.js";
|
|
12
|
+
import { isSingletonEntityDecl, } from "../../schema/dsl/declarations/SingletonEntityDecl.js";
|
|
12
13
|
import { isTypeAliasDecl, TypeAliasDecl } from "../../schema/dsl/declarations/TypeAliasDecl.js";
|
|
13
14
|
import { isNestedEntityMapType } from "../../schema/dsl/types/NestedEntityMapType.js";
|
|
14
15
|
import { isObjectType } from "../../schema/dsl/types/ObjectType.js";
|
|
@@ -148,6 +149,7 @@ const renderType = (options, type) => {
|
|
|
148
149
|
}
|
|
149
150
|
};
|
|
150
151
|
const renderEntityDecl = (options, decl) => syntax `${renderDocumentation(decl.comment, decl.isDeprecated)}export ${options.objectTypeKeyword} ${decl.name} ${options.objectTypeKeyword === "type" ? "= " : ""}${renderType(options, options.addIdentifierToEntities ? addEphemeralUUIDToType(decl) : decl.type.value)}`;
|
|
152
|
+
const renderSingletonEntityDecl = (options, decl) => syntax `${renderDocumentation(decl.comment, decl.isDeprecated)}export ${options.objectTypeKeyword} ${decl.name} ${options.objectTypeKeyword === "type" ? "= " : ""}${renderType(options, decl.type.value)}`;
|
|
151
153
|
const renderEnumDecl = (options, decl) => syntax `${renderDocumentation(decl.comment, decl.isDeprecated)}export type ${decl.name}${renderTypeParameters(options, decl.parameters)} =${renderEnumType(options, decl.type.value)}`;
|
|
152
154
|
const renderTypeAliasDecl = (options, decl) => isObjectType(decl.type.value)
|
|
153
155
|
? syntax `${renderDocumentation(decl.comment, decl.isDeprecated)}export ${options.objectTypeKeyword} ${decl.name}${renderTypeParameters(options, decl.parameters)} ${options.objectTypeKeyword === "type" ? "= " : ""}${renderType(options, decl.type.value)}`
|
|
@@ -156,6 +158,8 @@ const renderDecl = (options, decl) => {
|
|
|
156
158
|
switch (decl.kind) {
|
|
157
159
|
case NodeKind.EntityDecl:
|
|
158
160
|
return renderEntityDecl(options, decl);
|
|
161
|
+
case NodeKind.SingletonEntityDecl:
|
|
162
|
+
return renderSingletonEntityDecl(options, decl);
|
|
159
163
|
case NodeKind.EnumDecl:
|
|
160
164
|
return renderEnumDecl(options, decl);
|
|
161
165
|
case NodeKind.TypeAliasDecl:
|
|
@@ -193,6 +197,7 @@ const renderMapHelperType = (options, declarations, key, defaultName, filterFn,
|
|
|
193
197
|
: "";
|
|
194
198
|
};
|
|
195
199
|
const renderEntityMapType = (options, declarations) => renderMapHelperType(options, declarations, "entityMap", "EntityMap", isEntityDecl);
|
|
200
|
+
const renderSingletonEntityMapType = (options, declarations) => renderMapHelperType(options, declarations, "singletonEntityMap", "SingletonEntityMap", isSingletonEntityDecl);
|
|
196
201
|
const renderChildEntityMapType = (options, declarations) => renderMapHelperType(options, declarations, "childEntityMap", "ChildEntityMap", decl => isEntityDecl(decl) && isEntityDeclWithParentReference(decl), decl => `${decl.name}: [${decl.name}, "${decl.parentReferenceKey}", ${decl.name}["${decl.parentReferenceKey}"]]`);
|
|
197
202
|
const renderEnumMapType = (options, declarations) => renderMapHelperType(options, declarations, "enumMap", "EnumMap", isEnumDecl);
|
|
198
203
|
const renderTypeAliasMapType = (options, declarations) => renderMapHelperType(options, declarations, "typeAliasMap", "TypeAliasMap", isTypeAliasDecl);
|
|
@@ -255,6 +260,7 @@ export const render = (options = defaultOptions, declarations) => {
|
|
|
255
260
|
return undefined;
|
|
256
261
|
}, declarations));
|
|
257
262
|
return (renderEntityMapType(finalOptions, declarations) +
|
|
263
|
+
renderSingletonEntityMapType(finalOptions, declarations) +
|
|
258
264
|
renderChildEntityMapType(finalOptions, declarations) +
|
|
259
265
|
renderEnumMapType(finalOptions, declarations) +
|
|
260
266
|
renderTypeAliasMapType(finalOptions, declarations) +
|
|
@@ -5,14 +5,15 @@ import type { EnumCaseDecl } from "../types/EnumType.ts";
|
|
|
5
5
|
import type { Type } from "../types/Type.ts";
|
|
6
6
|
import type { EntityDecl } from "./EntityDecl.ts";
|
|
7
7
|
import type { EnumDecl } from "./EnumDecl.ts";
|
|
8
|
+
import { type SingletonEntityDecl } from "./SingletonEntityDecl.ts";
|
|
8
9
|
import type { TypeAliasDecl } from "./TypeAliasDecl.ts";
|
|
9
10
|
export type TypeArguments<Params extends TypeParameter[]> = {
|
|
10
11
|
[K in keyof Params]: Params[K] extends TypeParameter<string, infer T> ? T : Type;
|
|
11
12
|
};
|
|
12
13
|
export declare const getParameterNames: (decl: Decl) => string[];
|
|
13
14
|
export declare const getTypeArgumentsRecord: <Params extends TypeParameter[]>(decl: DeclP<Params>, args: TypeArguments<Params>) => Record<string, Type>;
|
|
14
|
-
export type Decl<Name extends string = string> = EntityDecl<Name> | EnumDecl<Name> | TypeAliasDecl<Name>;
|
|
15
|
-
export type DeclP<Params extends TypeParameter[] = TypeParameter[]> = EntityDecl | EnumDecl<string, Record<string, EnumCaseDecl>, Params> | TypeAliasDecl<string, Type, Params>;
|
|
15
|
+
export type Decl<Name extends string = string> = EntityDecl<Name> | SingletonEntityDecl<Name> | EnumDecl<Name> | TypeAliasDecl<Name>;
|
|
16
|
+
export type DeclP<Params extends TypeParameter[] = TypeParameter[]> = EntityDecl | SingletonEntityDecl | EnumDecl<string, Record<string, EnumCaseDecl>, Params> | TypeAliasDecl<string, Type, Params>;
|
|
16
17
|
export type IncludableDeclP<Params extends TypeParameter[] = TypeParameter[]> = EnumDecl<string, Record<string, EnumCaseDecl>, Params> | TypeAliasDecl<string, Type, Params>;
|
|
17
18
|
export type SecondaryDecl = EnumDecl | TypeAliasDecl;
|
|
18
19
|
export declare const isDecl: (node: Node) => node is Decl;
|
|
@@ -2,12 +2,13 @@ import { walkTypeNodeTree } from "../../helpers.js";
|
|
|
2
2
|
import { resolveTypeArguments } from "../../treeOperations/typeResolution.js";
|
|
3
3
|
import { isEntityDecl } from "./EntityDecl.js";
|
|
4
4
|
import { isEnumDecl } from "./EnumDecl.js";
|
|
5
|
+
import { isSingletonEntityDecl } from "./SingletonEntityDecl.js";
|
|
5
6
|
import { isTypeAliasDecl } from "./TypeAliasDecl.js";
|
|
6
7
|
export const getParameterNames = (decl) => decl.parameters.map(param => param.name);
|
|
7
8
|
export const getTypeArgumentsRecord = (decl, args) => Object.fromEntries(
|
|
8
9
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
9
10
|
args.slice(0, decl.parameters.length).map((arg, i) => [decl.parameters[i].name, arg]));
|
|
10
|
-
export const isDecl = (node) => isEntityDecl(node) || isEnumDecl(node) || isTypeAliasDecl(node);
|
|
11
|
+
export const isDecl = (node) => isEntityDecl(node) || isSingletonEntityDecl(node) || isEnumDecl(node) || isTypeAliasDecl(node);
|
|
11
12
|
export const asDecl = (node) => node && isDecl(node) ? node : undefined;
|
|
12
13
|
const declNamePattern = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
13
14
|
export const validateDeclName = (name) => {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Lazy } from "@elyukai/utils/lazy";
|
|
2
|
+
import { NodeKind } from "../../../../shared/schema/Node.ts";
|
|
3
|
+
import type { SortOrder } from "../../../../shared/schema/utils/sortOrder.ts";
|
|
4
|
+
import type { CustomConstraint, TypedCustomConstraint } from "../../../utils/customConstraints.ts";
|
|
5
|
+
import type { Node } from "../index.ts";
|
|
6
|
+
import type { MemberDecl, ObjectType } from "../types/ObjectType.ts";
|
|
7
|
+
import type { BaseDecl } from "./Decl.ts";
|
|
8
|
+
type TConstraint = Record<string, MemberDecl>;
|
|
9
|
+
export interface SingletonEntityDecl<Name extends string = string, T extends TConstraint = TConstraint> extends BaseDecl<Name, []> {
|
|
10
|
+
kind: NodeKind["SingletonEntityDecl"];
|
|
11
|
+
/**
|
|
12
|
+
* Changes the appearance of the entity’s name in singular form.
|
|
13
|
+
*/
|
|
14
|
+
displayName?: string;
|
|
15
|
+
type: Lazy<ObjectType<T>>;
|
|
16
|
+
isDeprecated?: boolean;
|
|
17
|
+
customConstraints?: CustomConstraint;
|
|
18
|
+
/**
|
|
19
|
+
* The order in which instances of an entity are sorted in the editor. This affects entity details pages and reference options.
|
|
20
|
+
*/
|
|
21
|
+
sortOrder?: SortOrder;
|
|
22
|
+
}
|
|
23
|
+
export declare const SingletonEntityDecl: <Name extends string, T extends TConstraint>(sourceUrl: string, options: {
|
|
24
|
+
name: Name;
|
|
25
|
+
/**
|
|
26
|
+
* Changes the appearance of the entity’s name in singular form.
|
|
27
|
+
*/
|
|
28
|
+
displayName?: string;
|
|
29
|
+
comment?: string;
|
|
30
|
+
type: () => ObjectType<T>;
|
|
31
|
+
isDeprecated?: boolean;
|
|
32
|
+
customConstraints?: TypedCustomConstraint<Name>;
|
|
33
|
+
}) => SingletonEntityDecl<Name, T>;
|
|
34
|
+
export { SingletonEntityDecl as SingletonEntity };
|
|
35
|
+
export declare const isSingletonEntityDecl: (node: Node) => node is SingletonEntityDecl;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Lazy } from "@elyukai/utils/lazy";
|
|
2
|
+
import { NodeKind } from "../../../../shared/schema/Node.js";
|
|
3
|
+
import { validateDeclName } from "./Decl.js";
|
|
4
|
+
export const SingletonEntityDecl = (sourceUrl, options) => {
|
|
5
|
+
validateDeclName(options.name);
|
|
6
|
+
return {
|
|
7
|
+
...options,
|
|
8
|
+
kind: NodeKind.SingletonEntityDecl,
|
|
9
|
+
sourceUrl,
|
|
10
|
+
parameters: [],
|
|
11
|
+
type: Lazy.of(() => {
|
|
12
|
+
const type = options.type();
|
|
13
|
+
Object.keys(type.properties).forEach(key => {
|
|
14
|
+
if (key === "id") {
|
|
15
|
+
throw new TypeError(`Invalid object key "${key}" for entity "${options.name}". The key "id" is reserved for the entity identifier.`);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
return type;
|
|
19
|
+
}),
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export { SingletonEntityDecl as SingletonEntity };
|
|
23
|
+
export const isSingletonEntityDecl = (node) => node.kind === NodeKind.SingletonEntityDecl;
|
|
@@ -5,6 +5,7 @@ export { Param, TypeParameter } from "./TypeParameter.ts";
|
|
|
5
5
|
export { type Decl, type DeclP, type IncludableDeclP, type SecondaryDecl, } from "./declarations/Decl.ts";
|
|
6
6
|
export { Entity, EntityDecl, type EntityDeclWithParentReference, type EntityDisplayName, } from "./declarations/EntityDecl.ts";
|
|
7
7
|
export { Enum, EnumDecl, GenEnum, GenEnumDecl } from "./declarations/EnumDecl.ts";
|
|
8
|
+
export { SingletonEntity, SingletonEntityDecl } from "./declarations/SingletonEntityDecl.ts";
|
|
8
9
|
export { GenTypeAlias, GenTypeAliasDecl, TypeAlias, TypeAliasDecl, } from "./declarations/TypeAliasDecl.ts";
|
|
9
10
|
export { Array, ArrayType } from "./types/ArrayType.ts";
|
|
10
11
|
export { Boolean, BooleanType } from "./types/BooleanType.ts";
|
|
@@ -2,6 +2,7 @@ export { Param, TypeParameter } from "./TypeParameter.js";
|
|
|
2
2
|
export {} from "./declarations/Decl.js";
|
|
3
3
|
export { Entity, EntityDecl, } from "./declarations/EntityDecl.js";
|
|
4
4
|
export { Enum, EnumDecl, GenEnum, GenEnumDecl } from "./declarations/EnumDecl.js";
|
|
5
|
+
export { SingletonEntity, SingletonEntityDecl } from "./declarations/SingletonEntityDecl.js";
|
|
5
6
|
export { GenTypeAlias, GenTypeAliasDecl, TypeAlias, TypeAliasDecl, } from "./declarations/TypeAliasDecl.js";
|
|
6
7
|
export { Array, ArrayType } from "./types/ArrayType.js";
|
|
7
8
|
export { Boolean, BooleanType } from "./types/BooleanType.js";
|
|
@@ -8,6 +8,7 @@ import type { DisplayNameResult } from "../../shared/utils/displayName.ts";
|
|
|
8
8
|
import type { InstanceContainer, InstanceContainerOverview, InstanceContent } from "../../shared/utils/instances.ts";
|
|
9
9
|
import type { DeclarationName, DefaultTSONDBTypes } from "../index.ts";
|
|
10
10
|
import type { EntityDecl } from "./dsl/declarations/EntityDecl.ts";
|
|
11
|
+
import type { SingletonEntityDecl } from "./dsl/declarations/SingletonEntityDecl.ts";
|
|
11
12
|
export interface Register {
|
|
12
13
|
}
|
|
13
14
|
export type AnyEntityMap = Record<string, InstanceContent>;
|
|
@@ -19,6 +20,15 @@ export type RegisteredEntity<Name extends string, T = Register> = T extends {
|
|
|
19
20
|
[K in Name]: InstanceContent;
|
|
20
21
|
};
|
|
21
22
|
} ? T["entityMap"][Name] : InstanceContent;
|
|
23
|
+
export type AnySingletonEntityMap = Record<string, InstanceContent>;
|
|
24
|
+
export type RegisteredSingletonEntityMap<T = Register> = T extends {
|
|
25
|
+
singletonEntityMap: AnySingletonEntityMap;
|
|
26
|
+
} ? T["singletonEntityMap"] : AnySingletonEntityMap;
|
|
27
|
+
export type RegisteredSingletonEntity<Name extends string, T = Register> = T extends {
|
|
28
|
+
singletonEntityMap: {
|
|
29
|
+
[K in Name]: InstanceContent;
|
|
30
|
+
};
|
|
31
|
+
} ? T["singletonEntityMap"][Name] : InstanceContent;
|
|
22
32
|
export type AnyChildEntityMap = Record<string, [
|
|
23
33
|
content: InstanceContent,
|
|
24
34
|
parentKey: string,
|
|
@@ -133,6 +143,14 @@ export type GetDisplayNameAndId<T extends AnyEntityMap = RegisteredEntityMap> =
|
|
|
133
143
|
* A function that retrieves an entity declaration by its name.
|
|
134
144
|
*/
|
|
135
145
|
export type GetEntityByName<T extends AnyEntityMap = RegisteredEntityMap> = <E extends Extract<keyof T, string> = Extract<keyof T, string>>(name: E) => EntityDecl<E> | undefined;
|
|
146
|
+
/**
|
|
147
|
+
* A function that retrieves an entity declaration by its name.
|
|
148
|
+
*/
|
|
149
|
+
export type GetSingletonEntityByName<T extends AnySingletonEntityMap = RegisteredSingletonEntityMap> = <E extends Extract<keyof T, string> = Extract<keyof T, string>>(name: E) => SingletonEntityDecl<E> | undefined;
|
|
150
|
+
/**
|
|
151
|
+
* A function that retrieves the singleton instance by its entity if available.
|
|
152
|
+
*/
|
|
153
|
+
export type GetSingletonInstance<T extends AnySingletonEntityMap = RegisteredSingletonEntityMap> = <E extends Extract<keyof T, string> = Extract<keyof T, string>>(entity: E) => T[E] | undefined;
|
|
136
154
|
/**
|
|
137
155
|
* A type guard function that checks if a given string is a valid declaration name.
|
|
138
156
|
*/
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { isDecl, isDeclWithoutTypeParameters } from "./dsl/declarations/Decl.ts";
|
|
2
2
|
export { isEntityDecl, isEntityDeclWithParentReference } from "./dsl/declarations/EntityDecl.ts";
|
|
3
3
|
export { isEnumDecl } from "./dsl/declarations/EnumDecl.ts";
|
|
4
|
+
export { isSingletonEntityDecl } from "./dsl/declarations/SingletonEntityDecl.ts";
|
|
4
5
|
export { isTypeAliasDecl } from "./dsl/declarations/TypeAliasDecl.ts";
|
|
5
6
|
export { isArrayType } from "./dsl/types/ArrayType.ts";
|
|
6
7
|
export { isBooleanType } from "./dsl/types/BooleanType.ts";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { isDecl, isDeclWithoutTypeParameters } from "./dsl/declarations/Decl.js";
|
|
2
2
|
export { isEntityDecl, isEntityDeclWithParentReference } from "./dsl/declarations/EntityDecl.js";
|
|
3
3
|
export { isEnumDecl } from "./dsl/declarations/EnumDecl.js";
|
|
4
|
+
export { isSingletonEntityDecl } from "./dsl/declarations/SingletonEntityDecl.js";
|
|
4
5
|
export { isTypeAliasDecl } from "./dsl/declarations/TypeAliasDecl.js";
|
|
5
6
|
export { isArrayType } from "./dsl/types/ArrayType.js";
|
|
6
7
|
export { isBooleanType } from "./dsl/types/BooleanType.js";
|
|
@@ -12,6 +12,7 @@ export const reduceNodes = (reducer, nodes, options = {}) => {
|
|
|
12
12
|
const reduceNodeTree = (parentNodes, node, collectedResults, reducedDecls) => {
|
|
13
13
|
switch (node.kind) {
|
|
14
14
|
case NodeKind.EntityDecl:
|
|
15
|
+
case NodeKind.SingletonEntityDecl:
|
|
15
16
|
case NodeKind.EnumDecl:
|
|
16
17
|
case NodeKind.TypeAliasDecl:
|
|
17
18
|
return reduceNodeTree([node], node.type.value, reducer(parentNodes, node, collectedResults), [...reducedDecls, node]);
|