tsondb 0.21.4 → 0.21.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/dist/src/node/bin/tsondb.js +10 -4
  2. package/dist/src/node/index.d.ts +12 -3
  3. package/dist/src/node/index.js +29 -14
  4. package/dist/src/node/renderers/jsonschema/index.d.ts +1 -1
  5. package/dist/src/node/renderers/jsonschema/index.js +2 -2
  6. package/dist/src/node/renderers/jsonschema/render.js +4 -6
  7. package/dist/src/node/renderers/ts/index.d.ts +1 -1
  8. package/dist/src/node/renderers/ts/index.js +2 -2
  9. package/dist/src/node/renderers/ts/render.js +11 -21
  10. package/dist/src/node/schema/detached.d.ts +1 -1
  11. package/dist/src/node/schema/detached.js +0 -1
  12. package/dist/src/node/schema/dsl/declarations/Decl.d.ts +3 -3
  13. package/dist/src/node/schema/dsl/declarations/Decl.js +1 -1
  14. package/dist/src/node/schema/dsl/declarations/EntityDecl.d.ts +2 -2
  15. package/dist/src/node/schema/dsl/declarations/EntityDecl.js +1 -1
  16. package/dist/src/node/schema/dsl/declarations/EnumDecl.d.ts +2 -3
  17. package/dist/src/node/schema/dsl/declarations/SingletonEntityDecl.d.ts +1 -1
  18. package/dist/src/node/schema/dsl/declarations/TypeAliasDecl.d.ts +1 -1
  19. package/dist/src/node/schema/dsl/index.d.ts +1 -1
  20. package/dist/src/node/schema/dsl/types/ChildEntitiesType.d.ts +1 -1
  21. package/dist/src/node/schema/dsl/types/ChildEntitiesType.js +0 -1
  22. package/dist/src/node/schema/dsl/types/IncludeIdentifierType.d.ts +1 -1
  23. package/dist/src/node/schema/dsl/types/IncludeIdentifierType.js +0 -1
  24. package/dist/src/node/schema/dsl/types/NestedEntityMapType.d.ts +1 -1
  25. package/dist/src/node/schema/dsl/types/NestedEntityMapType.js +0 -1
  26. package/dist/src/node/schema/dsl/types/ObjectType.js +1 -1
  27. package/dist/src/node/schema/helpers.d.ts +4 -4
  28. package/dist/src/node/schema/helpers.js +8 -11
  29. package/dist/src/node/schema/index.d.ts +2 -2
  30. package/dist/src/node/schema/index.js +4 -3
  31. package/dist/src/node/schema/treeOperations/format.js +2 -1
  32. package/dist/src/node/schema/treeOperations/serialization.d.ts +19 -19
  33. package/dist/src/node/schema/treeOperations/serialization.js +0 -18
  34. package/dist/src/node/schema/treeOperations/typeResolution.d.ts +9 -11
  35. package/dist/src/node/schema/treeOperations/typeResolution.js +0 -7
  36. package/dist/src/node/schema/treeOperations/validation.d.ts +1 -1
  37. package/dist/src/node/schema/treeOperations/validation.js +5 -6
  38. package/dist/src/node/schema/validation/options.js +2 -1
  39. package/dist/src/node/server/api/declarations.js +2 -2
  40. package/dist/src/node/server/api/git.js +2 -2
  41. package/dist/src/node/server/index.d.ts +2 -2
  42. package/dist/src/node/server/index.js +2 -2
  43. package/dist/src/node/server/utils/query.js +1 -1
  44. package/dist/src/node/transaction.d.ts +2 -2
  45. package/dist/src/node/transaction.js +0 -2
  46. package/dist/src/node/utils/childInstances.d.ts +1 -1
  47. package/dist/src/node/utils/childInstances.js +3 -2
  48. package/dist/src/node/utils/customConstraints.d.ts +1 -1
  49. package/dist/src/node/utils/customConstraints.js +0 -1
  50. package/dist/src/node/utils/databaseInMemory.js +16 -18
  51. package/dist/src/node/utils/databaseOnDisk.js +8 -0
  52. package/dist/src/node/utils/displayName.d.ts +1 -1
  53. package/dist/src/node/utils/displayName.js +24 -29
  54. package/dist/src/node/utils/files.d.ts +1 -1
  55. package/dist/src/node/utils/files.js +1 -2
  56. package/dist/src/node/utils/path.js +2 -1
  57. package/dist/src/node/utils/references.d.ts +1 -1
  58. package/dist/src/node/utils/references.js +6 -5
  59. package/dist/src/node/utils/unique.d.ts +1 -1
  60. package/dist/src/node/utils/unique.js +8 -17
  61. package/dist/src/shared/schema/declarations/Declaration.d.ts +1 -1
  62. package/dist/src/shared/schema/declarations/Declaration.js +0 -1
  63. package/dist/src/shared/schema/declarations/EnumDecl.js +5 -7
  64. package/dist/src/shared/schema/types/EnumType.js +2 -2
  65. package/dist/src/shared/schema/types/NestedEntityMapType.d.ts +1 -2
  66. package/dist/src/shared/schema/utils/keyPath.js +14 -14
  67. package/dist/src/shared/schema/utils/sortOrder.js +1 -1
  68. package/dist/src/shared/utils/git.js +6 -1
  69. package/dist/src/shared/utils/render.js +3 -3
  70. package/dist/src/shared/utils/translation.js +15 -16
  71. package/dist/src/shared/utils/validation.js +4 -4
  72. package/dist/src/shared/validation/date.js +2 -2
  73. package/dist/src/shared/validation/identifier.js +1 -1
  74. package/dist/src/shared/validation/number.js +3 -3
  75. package/dist/src/shared/validation/object.js +1 -1
  76. package/dist/src/shared/validation/string.js +1 -1
  77. package/dist/src/web/web.js +1140 -1212
  78. package/package.json +19 -18
@@ -8,6 +8,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
8
8
  return path;
9
9
  };
10
10
  import { omitUndefinedKeys } from "@elyukai/utils/object";
11
+ import { assertExhaustive } from "@elyukai/utils/typeSafety";
11
12
  import Debug from "debug";
12
13
  import { access, constants } from "node:fs/promises";
13
14
  import { join } from "node:path";
@@ -87,12 +88,14 @@ const config = await (async () => {
87
88
  for (const configName of possibleConfigNames) {
88
89
  const fullPath = join(cwd(), configName);
89
90
  try {
91
+ // oxlint-disable-next-line no-await-in-loop
90
92
  await access(fullPath, constants.R_OK);
91
93
  }
92
94
  catch {
93
95
  debug(`could not use config file ${fullPath}, not found`);
94
96
  continue;
95
97
  }
98
+ // oxlint-disable-next-line no-await-in-loop
96
99
  const foundConfigModule = (await import(__rewriteRelativeImportExtension(pathToFileURL(fullPath).toString())));
97
100
  if ("default" in foundConfigModule) {
98
101
  debug(`config file ${fullPath} found with config`);
@@ -110,18 +113,19 @@ if (config === undefined) {
110
113
  if (passedArguments.command === undefined) {
111
114
  throw new Error("No command has been specified. Possible commands are: generate, serve, validate.");
112
115
  }
113
- const createDB = (config, validationOptions, skipReferenceCache) => TSONDB.create({
114
- ...config,
116
+ const createDB = (dataConfig, validationOptions, skipReferenceCache) => TSONDB.create({
117
+ ...dataConfig,
115
118
  validationOptions,
116
119
  }, skipReferenceCache);
117
- if (passedArguments.command.name === "generate") {
120
+ const commandName = passedArguments.command.name;
121
+ if (commandName === "generate") {
118
122
  debug(`running command: generate`);
119
123
  validateConfigForGeneration(config);
120
124
  await TSONDB.generateOutputs(config);
121
125
  }
122
126
  else {
123
127
  validateConfigForData(config);
124
- switch (passedArguments.command.name) {
128
+ switch (commandName) {
125
129
  case "serve": {
126
130
  debug(`running command: serve`);
127
131
  validateConfigForServer(config);
@@ -200,5 +204,7 @@ else {
200
204
  }
201
205
  break;
202
206
  }
207
+ default:
208
+ assertExhaustive(commandName);
203
209
  }
204
210
  }
@@ -2,9 +2,8 @@ import type { InstanceContainer, InstanceContainerOverview, InstanceContent, Sin
2
2
  import type { FormatterOptions } from "./config.ts";
3
3
  import { Git } from "./git.js";
4
4
  import type { Output } from "./output.ts";
5
- import { type EntityDecl } from "./schema/dsl/index.ts";
6
- import type { AnyChildEntityMap, AnyEntityMap, AnyEnumMap, AnySingletonEntityMap, AnyTypeAliasMap } from "./schema/generatedTypeHelpers.ts";
7
- import { type IdArgsVariant } from "./schema/generatedTypeHelpers.ts";
5
+ import type { EntityDecl } from "./schema/dsl/index.ts";
6
+ import type { AnyChildEntityMap, AnyEntityMap, AnyEnumMap, AnySingletonEntityMap, AnyTypeAliasMap, IdArgsVariant } from "./schema/generatedTypeHelpers.ts";
8
7
  import type { Schema } from "./schema/index.ts";
9
8
  import { Transaction } from "./transaction.ts";
10
9
  export interface DefaultTSONDBTypes {
@@ -104,6 +103,7 @@ export interface TranslationValidationOptions {
104
103
  */
105
104
  matchParametersInKeys?: boolean;
106
105
  }
106
+ export type HookTrigger = "transaction:before" | "transaction:after";
107
107
  /**
108
108
  * The main class for managing a typed JSON database.
109
109
  */
@@ -318,8 +318,17 @@ export declare class TSONDB<T extends DefaultTSONDBTypes = DefaultTSONDBTypes> {
318
318
  * @param path The file path where the compressed database will be saved.
319
319
  */
320
320
  compressToSingleFile(path: string): Promise<void>;
321
+ /**
322
+ * Registers a new hook for the specified trigger. The callback will be invoked whenever the trigger is activated.
323
+ */
324
+ registerHook(trigger: HookTrigger, callback: (db: TSONDB<T>) => void): void;
325
+ /**
326
+ * Unregisters a hook for the specified trigger.
327
+ */
328
+ unregisterHook(trigger: HookTrigger, callback: (db: TSONDB<T>) => void): void;
321
329
  }
322
330
  export type TSONDBWithGit<T extends DefaultTSONDBTypes = DefaultTSONDBTypes> = TSONDB<T> & {
323
331
  git: Git<T>;
324
332
  };
325
333
  export type { Config } from "./config.ts";
334
+ export { createServer } from "./server/index.ts";
@@ -15,8 +15,6 @@ import { countError, countErrors, getErrorMessageForDisplay, HTTPError, wrapErro
15
15
  import { parallelizeErrors } from "../shared/utils/validation.js";
16
16
  import { Git } from "./git.js";
17
17
  import { getDisplayName, getDisplayNameWithId } from "./schema/detached.js";
18
- import {} from "./schema/dsl/index.js";
19
- import {} from "./schema/generatedTypeHelpers.js";
20
18
  import { isEntityDecl, isEntityDeclWithParentReference } from "./schema/guards.js";
21
19
  import { serializeNode } from "./schema/treeOperations/serialization.js";
22
20
  import { createEntityNameValidator, createReferenceValidator, validateDeclReferentialIntegrity, validateDeclStructuralIntegrity, } from "./schema/treeOperations/validation.js";
@@ -32,15 +30,10 @@ import { checkUniqueConstraintsForAllEntities } from "./utils/unique.js";
32
30
  const debug = Debug("tsondb:class");
33
31
  const prepareFolders = async (dataRootPath, entities) => {
34
32
  await mkdir(dataRootPath, { recursive: true });
35
- for (const entity of entities) {
36
- const entityDir = join(dataRootPath, entity.name);
37
- await mkdir(entityDir, { recursive: true });
38
- }
33
+ await Promise.all(entities.map(entity => mkdir(join(dataRootPath, entity.name), { recursive: true })));
39
34
  };
40
35
  const generateOutputs = async (schema, outputs) => {
41
- for (const output of outputs) {
42
- await output.run(schema);
43
- }
36
+ await Promise.all(outputs.map(output => output.run(schema)));
44
37
  };
45
38
  const getGit = async (dataRootPath) => {
46
39
  const git = simpleGit({ baseDir: dataRootPath });
@@ -59,7 +52,7 @@ const getGit = async (dataRootPath) => {
59
52
  }
60
53
  };
61
54
  const checkLocales = (schema, data, locales) => {
62
- const localeEntity = schema.localeEntity;
55
+ const { localeEntity } = schema;
63
56
  if (localeEntity &&
64
57
  !locales.every(locale => data.hasInstanceOfEntityById(localeEntity.name, locale))) {
65
58
  throw new Error("All provided locales must exist in the database.");
@@ -71,7 +64,7 @@ const initData = async (dataRootPath, schema, locales, git, gitStatus, skipRefer
71
64
  debug("done");
72
65
  checkLocales(schema, data, locales);
73
66
  const serializedDeclarationsByName = Object.fromEntries(schema.resolvedDeclarations.map(decl => [decl.name, serializeNode(decl)]));
74
- let referencesToInstances;
67
+ let referencesToInstances = {};
75
68
  if (!skipReferenceCache) {
76
69
  debug("creating references cache ...");
77
70
  referencesToInstances = await getReferencesToInstances(data, serializedDeclarationsByName);
@@ -79,7 +72,6 @@ const initData = async (dataRootPath, schema, locales, git, gitStatus, skipRefer
79
72
  }
80
73
  else {
81
74
  debug("skipping references cache creation");
82
- referencesToInstances = {};
83
75
  }
84
76
  if (git) {
85
77
  const status = gitStatus ?? (await git.client.status());
@@ -102,6 +94,7 @@ export class TSONDB {
102
94
  #formatterOptions;
103
95
  #gitWrapper;
104
96
  #locked = false;
97
+ #hooks = {};
105
98
  constructor(options) {
106
99
  this.#dataRootPath = options.dataRootPath;
107
100
  this.#data = options.data;
@@ -124,7 +117,7 @@ export class TSONDB {
124
117
  * @param skipReferenceCache If set to `true`, the reference cache will not be created during initialization. This can speed up the initialization process, but referential integrity checks will not work correctly until the cache is created. This should only be set to `true` if you plan to call `sync()` immediately after initialization.
125
118
  */
126
119
  static async create(options, skipReferenceCache = false) {
127
- const entities = options.schema.entities;
120
+ const { entities } = options.schema;
128
121
  debug("using data root path: %s", options.dataRootPath);
129
122
  await prepareFolders(options.dataRootPath, entities);
130
123
  debug("prepared folders");
@@ -135,7 +128,7 @@ export class TSONDB {
135
128
  else {
136
129
  debug("no git repository found");
137
130
  }
138
- const localeEntity = options.schema.localeEntity;
131
+ const { localeEntity } = options.schema;
139
132
  if (!localeEntity && options.locales) {
140
133
  throw new Error("Schema does not contain a locale entity, locales cannot be provided.");
141
134
  }
@@ -386,6 +379,7 @@ export class TSONDB {
386
379
  throw new HTTPError(503, "Another transaction is currently running. Transactions cannot be run concurrently.");
387
380
  }
388
381
  debug("Starting transaction, locking database ...");
382
+ this.#hooks["transaction:before"]?.forEach(hook => hook(this));
389
383
  this.#locked = true;
390
384
  try {
391
385
  const getEntity = this.#schema.getEntity.bind(this.#schema);
@@ -434,6 +428,7 @@ export class TSONDB {
434
428
  this.#referencesToInstances = newRefs;
435
429
  this.#locked = false;
436
430
  debug("Transaction successful, released lock");
431
+ this.#hooks["transaction:after"]?.forEach(hook => hook(this));
437
432
  return res;
438
433
  }
439
434
  catch (error) {
@@ -732,4 +727,24 @@ export class TSONDB {
732
727
  async compressToSingleFile(path) {
733
728
  await writeFile(path, JSON.stringify(this.#data), "utf-8");
734
729
  }
730
+ /**
731
+ * Registers a new hook for the specified trigger. The callback will be invoked whenever the trigger is activated.
732
+ */
733
+ registerHook(trigger, callback) {
734
+ ;
735
+ (this.#hooks[trigger] ??= []).push(callback);
736
+ }
737
+ /**
738
+ * Unregisters a hook for the specified trigger.
739
+ */
740
+ unregisterHook(trigger, callback) {
741
+ const callbacks = this.#hooks[trigger];
742
+ if (callbacks) {
743
+ const index = callbacks.indexOf(callback);
744
+ if (index !== -1) {
745
+ callbacks.splice(index, 1);
746
+ }
747
+ }
748
+ }
735
749
  }
750
+ export { createServer } from "./server/index.js";
@@ -1,5 +1,5 @@
1
1
  import type { Output } from "../../output.ts";
2
- import type { JsonSchemaRendererOptions } from "./render.ts";
2
+ import { type JsonSchemaRendererOptions } from "./render.ts";
3
3
  export declare const JsonSchemaOutput: (options: {
4
4
  targetPath: string;
5
5
  rendererOptions?: Partial<JsonSchemaRendererOptions>;
@@ -17,7 +17,7 @@ export const JsonSchemaOutput = (options) => ({
17
17
  const sourceRootPath = fileURLToPath(commonPrefix(...Object.keys(declarationsBySourceUrl)));
18
18
  debug("common source root path: %s", sourceRootPath);
19
19
  if (sourceRootPath) {
20
- for (const [sourceUrl, decls] of Object.entries(declarationsBySourceUrl)) {
20
+ await Promise.all(Object.entries(declarationsBySourceUrl).map(async ([sourceUrl, decls]) => {
21
21
  const sourcePath = fileURLToPath(sourceUrl);
22
22
  const relativePath = dirname(relative(sourceRootPath, sourcePath));
23
23
  const newDir = join(options.targetPath, relativePath);
@@ -26,7 +26,7 @@ export const JsonSchemaOutput = (options) => ({
26
26
  await writeFile(newPath, render(options.rendererOptions, decls ?? []), {
27
27
  encoding: "utf-8",
28
28
  });
29
- }
29
+ }));
30
30
  debug("emitted declaration files to %s", options.targetPath);
31
31
  }
32
32
  }
@@ -5,8 +5,8 @@ import { NodeKind } from "../../../shared/schema/Node.js";
5
5
  import { asDecl } from "../../schema/dsl/declarations/Decl.js";
6
6
  import { addEphemeralUUIDToType, createEntityIdentifierTypeAsDecl, isEntityDecl, } from "../../schema/dsl/declarations/EntityDecl.js";
7
7
  import { TypeAliasDecl } from "../../schema/dsl/declarations/TypeAliasDecl.js";
8
- import { isNestedEntityMapType } from "../../schema/dsl/types/NestedEntityMapType.js";
9
- import { getTypeOfKey } from "../../schema/dsl/types/TranslationObjectType.js";
8
+ import { isNestedEntityMapType, } from "../../schema/dsl/types/NestedEntityMapType.js";
9
+ import { getTypeOfKey, } from "../../schema/dsl/types/TranslationObjectType.js";
10
10
  import { flatMapAuxiliaryDecls, isFinalChildEntitiesType } from "../../schema/helpers.js";
11
11
  import { ensureSpecialDirStart } from "../../utils/path.js";
12
12
  const defaultIndentation = 2;
@@ -24,7 +24,7 @@ const renderArrayType = (options, type) => ({
24
24
  const renderObjectType = (options, type) => ({
25
25
  type: "object",
26
26
  properties: Object.fromEntries(Object.entries(type.properties)
27
- .filter(([_, config]) => !isFinalChildEntitiesType(config.type))
27
+ .filter(([_key, config]) => !isFinalChildEntitiesType(config.type))
28
28
  .map(([name, config]) => [
29
29
  name,
30
30
  {
@@ -192,9 +192,7 @@ export const render = (options = defaultOptions, declarations) => {
192
192
  $defs: renderDeclarations(finalOptions, flatMapAuxiliaryDecls((parentNodes, node, existingDecls) => {
193
193
  if (isNestedEntityMapType(node)) {
194
194
  if (existingDecls.some(decl => decl.name === node.name)) {
195
- // this may happen when a nested entity map is defined in a generic declaration and the generic declaration is used multiple times
196
- // TODO: circumvent by defining the nested entity declaration outside the generic declaration
197
- return undefined;
195
+ throw new Error("A nested entity map type with the same name has already been defined in this schema. Make sure the nested entity map type is defined only once in the schema. If the nested entity map type is defined in a generic declaration, consider defining it outside the generic declaration to avoid this issue.");
198
196
  }
199
197
  return TypeAliasDecl(asDecl(parentNodes[0])?.sourceUrl ?? "", {
200
198
  name: node.name,
@@ -1,5 +1,5 @@
1
1
  import type { Output } from "../../output.ts";
2
- import type { TypeScriptRendererOptions } from "./render.ts";
2
+ import { type TypeScriptRendererOptions } from "./render.ts";
3
3
  export declare const TypeScriptOutput: (options: {
4
4
  targetPath: string;
5
5
  rendererOptions?: Partial<TypeScriptRendererOptions>;
@@ -18,7 +18,7 @@ export const TypeScriptOutput = (options) => ({
18
18
  const sourceRootPath = fileURLToPath(commonPrefix(...Object.keys(declarationsBySourceUrl)));
19
19
  debug("common source root path: %s", sourceRootPath);
20
20
  if (sourceRootPath) {
21
- for (const [sourceUrl, decls] of Object.entries(declarationsBySourceUrl)) {
21
+ await Promise.all(Object.entries(declarationsBySourceUrl).map(async ([sourceUrl, decls]) => {
22
22
  const sourcePath = fileURLToPath(sourceUrl);
23
23
  const relativePath = dirname(relative(sourceRootPath, sourcePath));
24
24
  const newDir = join(options.targetPath, relativePath);
@@ -27,7 +27,7 @@ export const TypeScriptOutput = (options) => ({
27
27
  await writeFile(newPath, pragma + render(options.rendererOptions, decls ?? []), {
28
28
  encoding: "utf-8",
29
29
  });
30
- }
30
+ }));
31
31
  debug("emitted declaration files to %s", options.targetPath);
32
32
  }
33
33
  }
@@ -12,9 +12,9 @@ import { addEphemeralUUIDToType, createEntityIdentifierTypeAsDecl, isEntityDecl,
12
12
  import { isEnumDecl } from "../../schema/dsl/declarations/EnumDecl.js";
13
13
  import { isSingletonEntityDecl, } from "../../schema/dsl/declarations/SingletonEntityDecl.js";
14
14
  import { isTypeAliasDecl, TypeAliasDecl } from "../../schema/dsl/declarations/TypeAliasDecl.js";
15
- import { isNestedEntityMapType } from "../../schema/dsl/types/NestedEntityMapType.js";
16
- import { isObjectType } from "../../schema/dsl/types/ObjectType.js";
17
- import { getTypeOfKey } from "../../schema/dsl/types/TranslationObjectType.js";
15
+ import { isNestedEntityMapType, } from "../../schema/dsl/types/NestedEntityMapType.js";
16
+ import { isObjectType, } from "../../schema/dsl/types/ObjectType.js";
17
+ import { getTypeOfKey, } from "../../schema/dsl/types/TranslationObjectType.js";
18
18
  import { flatMapAuxiliaryDecls, isFinalChildEntitiesType } from "../../schema/helpers.js";
19
19
  import { ensureSpecialDirStart } from "../../utils/path.js";
20
20
  const defaultOptions = {
@@ -52,11 +52,9 @@ const renderArrayType = (options, type) => type.minItems !== undefined && type.m
52
52
  ])
53
53
  : syntax `${renderType(options, type.items)}[]`;
54
54
  const wrapAsObject = (options, str) => syntax `{${EOL}${indent(options.indentation, 1, str)}${EOL}}`;
55
- const renderObjectType = (options, type) => {
56
- return wrapAsObject(options, combineSyntaxes(Object.entries(type.properties)
57
- .filter(([_, config]) => !isFinalChildEntitiesType(config.type))
58
- .map(([name, config]) => syntax `${renderDocumentation(config.comment, config.isDeprecated)}${name}${config.isRequired ? "" : "?"}: ${renderType(options, config.type)}`), Object.values(type.properties).some(prop => prop.comment !== undefined) ? EOL + EOL : EOL));
59
- };
55
+ const renderObjectType = (options, type) => wrapAsObject(options, combineSyntaxes(Object.entries(type.properties)
56
+ .filter(([_key, config]) => !isFinalChildEntitiesType(config.type))
57
+ .map(([name, config]) => syntax `${renderDocumentation(config.comment, config.isDeprecated)}${name}${config.isRequired ? "" : "?"}: ${renderType(options, config.type)}`), Object.values(type.properties).some(prop => prop.comment !== undefined) ? EOL + EOL : EOL));
60
58
  const renderBooleanType = (_options, _type) => syntax `boolean`;
61
59
  const renderDateType = (options, _type) => options.dateType === "Date" ? syntax `Date` : syntax `string`;
62
60
  const renderFloatType = (_options, _type) => syntax `number`;
@@ -64,8 +62,8 @@ const renderIntegerType = (_options, _type) => syntax `number`;
64
62
  const renderStringType = (_options, _type) => syntax `string`;
65
63
  const renderTypeArgumentType = (_options, type) => syntax `${type.argument.name}`;
66
64
  const renderReferenceIdentifierType = (_options, type) => [
67
- { [type.entity.sourceUrl]: [type.entity.name + "_ID"] },
68
- type.entity.name + "_ID",
65
+ { [type.entity.sourceUrl]: [`${type.entity.name}_ID`] },
66
+ `${type.entity.name}_ID`,
69
67
  ];
70
68
  const renderIncludeIdentifierType = (options, type) => combineSyntaxes([
71
69
  [{ [type.reference.sourceUrl]: [type.reference.name] }, type.reference.name],
@@ -111,9 +109,7 @@ const renderTranslationParameterBrand = (options, params) => {
111
109
  }
112
110
  return syntax ` & { __params: { ${entries.map(([name, type]) => `"${name}": ${type}`).join("; ")} } }`;
113
111
  };
114
- const renderTranslationObjectType = (options, type) => {
115
- return wrapAsObject(options, combineSyntaxes(Object.entries(type.properties).map(([name, config]) => syntax `"${name.replace('"', '\\"')}"${type.allKeysAreRequired ? "" : "?"}: ${renderType(options, getTypeOfKey(config, type))}${renderTranslationParameterBrand(options, mapParameterTypeNames(extractParameterTypeNamesFromMessage(name), typeName => mapTypeNameToType(options, typeName)))}`), EOL));
116
- };
112
+ const renderTranslationObjectType = (options, type) => wrapAsObject(options, combineSyntaxes(Object.entries(type.properties).map(([name, config]) => syntax `"${name.replace('"', '\\"')}"${type.allKeysAreRequired ? "" : "?"}: ${renderType(options, getTypeOfKey(config, type))}${renderTranslationParameterBrand(options, mapParameterTypeNames(extractParameterTypeNamesFromMessage(name), typeName => mapTypeNameToType(options, typeName)))}`), EOL));
117
113
  const renderType = (options, type) => {
118
114
  switch (type.kind) {
119
115
  case NodeKind.ArrayType:
@@ -192,7 +188,7 @@ const renderMapHelperType = (options, declarations, key, defaultName, filterFn,
192
188
  .filter(filterFn)
193
189
  .sort((a, b) => a.name.localeCompare(b.name))
194
190
  .map(renderKeyFn ??
195
- (decl => `${decl.name}: ${decl.name}${decl.parameters.length > 0 ? "<" + decl.parameters.map(param => (param.constraint ? renderType(options, param.constraint)[1] : "unknown")).join(", ") + ">" : ""}`))
191
+ (decl => `${decl.name}: ${decl.name}${decl.parameters.length > 0 ? `<${decl.parameters.map(param => (param.constraint ? renderType(options, param.constraint)[1] : "unknown")).join(", ")}>` : ""}`))
196
192
  .join(EOL))}${EOL}}${EOL + EOL}`
197
193
  : "";
198
194
  };
@@ -205,13 +201,7 @@ const renderStringableTranslationParameterType = (options) => options.inferTrans
205
201
  (options.inferTranslationParameters.defaultTranslationParameterType === undefined ||
206
202
  options.inferTranslationParameters.defaultTranslationParameterType ===
207
203
  "StringableTranslationParameter")
208
- ? "export type StringableTranslationParameter = {" +
209
- EOL +
210
- prefixLines(getIndentation(options.indentation, 1), "toString(): string") +
211
- EOL +
212
- "}" +
213
- EOL +
214
- EOL
204
+ ? `export type StringableTranslationParameter = {${EOL}${prefixLines(getIndentation(options.indentation, 1), "toString(): string")}${EOL}}${EOL}${EOL}`
215
205
  : "";
216
206
  // const renderGetterConstruct = (
217
207
  // config: GetterOptions | undefined,
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Standalone functions for database operations without needing a full TSONDB instance.
3
3
  */
4
- import { type DatabaseInMemory } from "../utils/databaseInMemory.ts";
4
+ import type { DatabaseInMemory } from "../utils/databaseInMemory.ts";
5
5
  import { type AnyEntityMap, type GetEntityByName, type IdArgsVariant } from "./generatedTypeHelpers.ts";
6
6
  export declare const getDisplayName: <EM extends AnyEntityMap>(getEntity: GetEntityByName<EM>, locales: string[], data: DatabaseInMemory<EM>, ...args: IdArgsVariant<EM>) => string | undefined;
7
7
  export declare const getDisplayNameWithId: <EM extends AnyEntityMap>(getEntity: GetEntityByName<EM>, locales: string[], data: DatabaseInMemory<EM>, ...args: IdArgsVariant<EM>) => string;
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * Standalone functions for database operations without needing a full TSONDB instance.
3
3
  */
4
- import {} from "../utils/databaseInMemory.js";
5
4
  import { getDisplayNameFromEntityInstance } from "../utils/displayName.js";
6
5
  import { normalizedIdArgs, } from "./generatedTypeHelpers.js";
7
6
  export const getDisplayName = (getEntity, locales, data, ...args) => {
@@ -3,10 +3,10 @@ import type { Node } from "../index.ts";
3
3
  import type { TypeParameter } from "../TypeParameter.ts";
4
4
  import type { EnumCaseDecl } from "../types/EnumType.ts";
5
5
  import type { Type } from "../types/Type.ts";
6
- import type { EntityDecl } from "./EntityDecl.ts";
7
- import type { EnumDecl } from "./EnumDecl.ts";
6
+ import { type EntityDecl } from "./EntityDecl.ts";
7
+ import { type EnumDecl } from "./EnumDecl.ts";
8
8
  import { type SingletonEntityDecl } from "./SingletonEntityDecl.ts";
9
- import type { TypeAliasDecl } from "./TypeAliasDecl.ts";
9
+ import { type TypeAliasDecl } from "./TypeAliasDecl.ts";
10
10
  export type TypeArguments<Params extends TypeParameter[]> = {
11
11
  [K in keyof Params]: Params[K] extends TypeParameter<string, infer T> ? T : Type;
12
12
  };
@@ -10,7 +10,7 @@ export const getTypeArgumentsRecord = (decl, args) => Object.fromEntries(
10
10
  args.slice(0, decl.parameters.length).map((arg, i) => [decl.parameters[i].name, arg]));
11
11
  export const isDecl = (node) => isEntityDecl(node) || isSingletonEntityDecl(node) || isEnumDecl(node) || isTypeAliasDecl(node);
12
12
  export const asDecl = (node) => node && isDecl(node) ? node : undefined;
13
- const declNamePattern = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
13
+ const declNamePattern = /^[a-zA-Z_][a-zA-Z0-9_]*$/u;
14
14
  export const validateDeclName = (name) => {
15
15
  if (!declNamePattern.test(name)) {
16
16
  throw new Error(`Invalid declaration name "${name}". Declaration names must match the pattern ${declNamePattern.toString()}.`);
@@ -7,9 +7,9 @@ import type { CustomConstraint, TypedCustomConstraint } from "../../../utils/cus
7
7
  import type { DisplayNameCustomizer, TypedDisplayNameCustomizer } from "../../../utils/displayName.ts";
8
8
  import type { Node } from "../index.ts";
9
9
  import type { NestedEntityMapType } from "../types/NestedEntityMapType.ts";
10
- import type { MemberDecl, ObjectType } from "../types/ObjectType.ts";
10
+ import { type MemberDecl, type ObjectType } from "../types/ObjectType.ts";
11
11
  import { StringType } from "../types/StringType.ts";
12
- import type { BaseDecl } from "./Decl.ts";
12
+ import { type BaseDecl } from "./Decl.ts";
13
13
  import { TypeAliasDecl } from "./TypeAliasDecl.ts";
14
14
  export type EntityDisplayName<T extends TConstraint> = PathTo<T, StringType> | {
15
15
  /**
@@ -41,6 +41,6 @@ export const addEphemeralUUIDToType = (decl) => ({
41
41
  export const createEntityIdentifierType = () => StringType();
42
42
  export const createEntityIdentifierTypeAsDecl = (decl) => TypeAliasDecl(decl.sourceUrl, {
43
43
  comment: createEntityIdentifierComment(),
44
- name: (decl.name + "_ID"),
44
+ name: `${decl.name}_ID`,
45
45
  type: createEntityIdentifierType,
46
46
  });
@@ -4,9 +4,8 @@ import { NodeKind } from "../../../../shared/schema/Node.ts";
4
4
  import type { NestedCustomConstraint, TypedNestedCustomConstraint } from "../../../utils/customConstraints.ts";
5
5
  import type { Node } from "../index.ts";
6
6
  import type { TypeParameter } from "../TypeParameter.ts";
7
- import type { EnumCaseDecl } from "../types/EnumType.ts";
8
- import { EnumType } from "../types/EnumType.ts";
9
- import type { BaseDecl } from "./Decl.ts";
7
+ import { type EnumCaseDecl, EnumType } from "../types/EnumType.ts";
8
+ import { type BaseDecl } from "./Decl.ts";
10
9
  type TConstraint = Record<string, EnumCaseDecl>;
11
10
  export interface EnumDecl<Name extends string = string, T extends TConstraint = TConstraint, Params extends TypeParameter[] = TypeParameter[]> extends BaseDecl<Name, Params> {
12
11
  kind: NodeKind["EnumDecl"];
@@ -4,7 +4,7 @@ import type { SortOrder } from "../../../../shared/schema/utils/sortOrder.ts";
4
4
  import type { CustomConstraint, TypedCustomConstraint } from "../../../utils/customConstraints.ts";
5
5
  import type { Node } from "../index.ts";
6
6
  import type { MemberDecl, ObjectType } from "../types/ObjectType.ts";
7
- import type { BaseDecl } from "./Decl.ts";
7
+ import { type BaseDecl } from "./Decl.ts";
8
8
  type TConstraint = Record<string, MemberDecl>;
9
9
  export interface SingletonEntityDecl<Name extends string = string, T extends TConstraint = TConstraint> extends BaseDecl<Name, []> {
10
10
  kind: NodeKind["SingletonEntityDecl"];
@@ -4,7 +4,7 @@ import type { NestedCustomConstraint, TypedNestedCustomConstraint } from "../../
4
4
  import type { Node } from "../index.ts";
5
5
  import type { TypeParameter } from "../TypeParameter.ts";
6
6
  import type { Type } from "../types/Type.ts";
7
- import type { BaseDecl } from "./Decl.ts";
7
+ import { type BaseDecl } from "./Decl.ts";
8
8
  export interface TypeAliasDecl<Name extends string = string, T extends Type = Type, Params extends TypeParameter[] = TypeParameter[]> extends BaseDecl<Name, Params> {
9
9
  kind: NodeKind["TypeAliasDecl"];
10
10
  type: Lazy<T>;
@@ -1,5 +1,5 @@
1
- import type { TypeParameter } from "./TypeParameter.ts";
2
1
  import type { Decl } from "./declarations/Decl.ts";
2
+ import type { TypeParameter } from "./TypeParameter.ts";
3
3
  import type { Type } from "./types/Type.ts";
4
4
  export { Param, TypeParameter } from "./TypeParameter.ts";
5
5
  export { type Decl, type DeclP, type IncludableDeclP, type SecondaryDecl, } from "./declarations/Decl.ts";
@@ -1,5 +1,5 @@
1
1
  import { NodeKind } from "../../../../shared/schema/Node.ts";
2
- import { type EntityDecl } from "../declarations/EntityDecl.ts";
2
+ import type { EntityDecl } from "../declarations/EntityDecl.ts";
3
3
  import type { Node } from "../index.ts";
4
4
  import type { MemberDecl } from "./ObjectType.ts";
5
5
  import type { BaseType } from "./Type.ts";
@@ -1,5 +1,4 @@
1
1
  import { NodeKind } from "../../../../shared/schema/Node.js";
2
- import {} from "../declarations/EntityDecl.js";
3
2
  export const ChildEntitiesType = (entity) => ({
4
3
  kind: NodeKind.ChildEntitiesType,
5
4
  entity,
@@ -1,7 +1,7 @@
1
1
  import { NodeKind } from "../../../../shared/schema/Node.ts";
2
2
  import type { IncludableDeclP, TypeArguments } from "../declarations/Decl.ts";
3
3
  import type { EnumDecl } from "../declarations/EnumDecl.ts";
4
- import { type TypeAliasDecl } from "../declarations/TypeAliasDecl.ts";
4
+ import type { TypeAliasDecl } from "../declarations/TypeAliasDecl.ts";
5
5
  import type { Node } from "../index.ts";
6
6
  import type { TypeParameter } from "../TypeParameter.ts";
7
7
  import type { EnumCaseDecl } from "./EnumType.ts";
@@ -1,5 +1,4 @@
1
1
  import { NodeKind } from "../../../../shared/schema/Node.js";
2
- import {} from "../declarations/TypeAliasDecl.js";
3
2
  export const GenIncludeIdentifierType = (reference, args) => ({
4
3
  kind: NodeKind.IncludeIdentifierType,
5
4
  reference,
@@ -4,7 +4,7 @@ import type { EntityDecl } from "../declarations/EntityDecl.ts";
4
4
  import type { TypeAliasDecl } from "../declarations/TypeAliasDecl.ts";
5
5
  import type { Node } from "../index.ts";
6
6
  import type { TypeParameter } from "../TypeParameter.ts";
7
- import { type IncludeIdentifier } from "./IncludeIdentifierType.ts";
7
+ import type { IncludeIdentifier } from "./IncludeIdentifierType.ts";
8
8
  import type { MemberDecl, ObjectType } from "./ObjectType.ts";
9
9
  import type { BaseType } from "./Type.ts";
10
10
  type TConstraint = Record<string, MemberDecl>;
@@ -1,6 +1,5 @@
1
1
  import { Lazy } from "@elyukai/utils/lazy";
2
2
  import { NodeKind } from "../../../../shared/schema/Node.js";
3
- import {} from "./IncludeIdentifierType.js";
4
3
  export const NestedEntityMapType = (options) => {
5
4
  const nestedEntityMapType = {
6
5
  ...options,
@@ -1,6 +1,6 @@
1
1
  import { NodeKind } from "../../../../shared/schema/Node.js";
2
2
  import { validateOption } from "../../validation/options.js";
3
- const keyPattern = /^[a-zA-Z0-9][a-zA-Z0-9_]*$/;
3
+ const keyPattern = /^[a-zA-Z0-9][a-zA-Z0-9_]*$/u;
4
4
  export const ObjectType = (properties, options = {}) => {
5
5
  const type = {
6
6
  ...options,
@@ -1,9 +1,9 @@
1
1
  import { type KeyPath } from "../../shared/schema/utils/keyPath.ts";
2
- import { type Decl, type EntityDecl, type EnumDecl, type Node, type Type, type TypeAliasDecl } from "./dsl/index.ts";
2
+ import type { Decl, EntityDecl, EnumDecl, Node, Type, TypeAliasDecl } from "./dsl/index.ts";
3
3
  import type { TypeParameter } from "./dsl/TypeParameter.ts";
4
4
  import type { ArrayType } from "./dsl/types/ArrayType.ts";
5
5
  import type { BooleanType } from "./dsl/types/BooleanType.ts";
6
- import { type ChildEntitiesType } from "./dsl/types/ChildEntitiesType.ts";
6
+ import type { ChildEntitiesType } from "./dsl/types/ChildEntitiesType.ts";
7
7
  import type { DateType } from "./dsl/types/DateType.ts";
8
8
  import type { EnumCaseDecl, EnumType } from "./dsl/types/EnumType.ts";
9
9
  import type { FloatType } from "./dsl/types/FloatType.ts";
@@ -13,7 +13,7 @@ import type { NestedEntityMapType } from "./dsl/types/NestedEntityMapType.ts";
13
13
  import type { MemberDecl, ObjectType } from "./dsl/types/ObjectType.ts";
14
14
  import type { ReferenceIdentifierType } from "./dsl/types/ReferenceIdentifierType.ts";
15
15
  import type { StringType } from "./dsl/types/StringType.ts";
16
- import { type TranslationObjectType } from "./dsl/types/TranslationObjectType.ts";
16
+ import type { TranslationObjectType } from "./dsl/types/TranslationObjectType.ts";
17
17
  import type { TypeArgumentType } from "./dsl/types/TypeArgumentType.ts";
18
18
  type KindToTypeMap = {
19
19
  ChildEntityDecl: ChildEntitiesType;
@@ -64,7 +64,7 @@ type MemberDeclsAsType<P extends Record<string, MemberDecl>> = {
64
64
  type MemberDeclsAsDeepType<P extends Record<string, MemberDecl>> = {
65
65
  [K in keyof P]: P[K] extends MemberDecl<Type, true> ? AsDeepType<P[K]["type"]> : AsDeepType<P[K]["type"]> | undefined;
66
66
  };
67
- export type AsDeepType<T extends Type> = T extends ArrayType<infer I> ? AsDeepType<I>[] : T extends ObjectType<infer P> ? MemberDeclsAsDeepType<P> : T extends BooleanType ? boolean : T extends DateType ? Date : T extends FloatType ? number : T extends IntegerType ? number : T extends StringType ? string : T extends TypeArgumentType ? unknown : T extends IncludeIdentifierType<TypeParameter[], infer Decl> ? Decl extends TypeAliasDecl<string, infer TA> ? AsDeepType<TA> : Decl extends EnumDecl<string, infer EC> ? AsDeepType<EnumType<EC>> : unknown : T extends NestedEntityMapType<string, infer TC> ? {
67
+ export type AsDeepType<T extends Type> = T extends ArrayType<infer I> ? AsDeepType<I>[] : T extends ObjectType<infer P> ? MemberDeclsAsDeepType<P> : T extends BooleanType ? boolean : T extends DateType ? Date : T extends FloatType ? number : T extends IntegerType ? number : T extends StringType ? string : T extends TypeArgumentType ? unknown : T extends IncludeIdentifierType<TypeParameter[], infer InnerDecl> ? InnerDecl extends TypeAliasDecl<string, infer TA> ? AsDeepType<TA> : InnerDecl extends EnumDecl<string, infer EC> ? AsDeepType<EnumType<EC>> : unknown : T extends NestedEntityMapType<string, infer TC> ? {
68
68
  [id: string]: MemberDeclsAsDeepType<TC>;
69
69
  } : T extends ReferenceIdentifierType ? string : T extends ChildEntitiesType ? never : T extends EnumType<infer EC> ? EC extends Record<string, EnumCaseDecl> ? {
70
70
  [Case in keyof EC]: EnumCaseTypeAsDeepType<Case & string, EC[Case]["type"]>;
@@ -2,9 +2,6 @@ import { error, ok } from "@elyukai/utils/result";
2
2
  import { assertExhaustive } from "@elyukai/utils/typeSafety";
3
3
  import { NodeKind } from "../../shared/schema/Node.js";
4
4
  import { getAtKeyPath, parseKeyPath } from "../../shared/schema/utils/keyPath.js";
5
- import {} from "./dsl/index.js";
6
- import {} from "./dsl/types/ChildEntitiesType.js";
7
- import {} from "./dsl/types/TranslationObjectType.js";
8
5
  import { isArrayType, isDecl, isIncludeIdentifierType, isObjectType, isTypeAliasDecl, } from "./guards.js";
9
6
  export const isOfKind = (node, kind) => node.kind === kind;
10
7
  export const reduceNodes = (reducer, nodes, options = {}) => {
@@ -118,11 +115,11 @@ export function walkTypeNodeTree(callbackFn, type, parentTypes, parentDecl) {
118
115
  return assertExhaustive(type);
119
116
  }
120
117
  }
121
- export const findTypeAtPath = (type, path, options = {}) => getAtKeyPath(type, [], parseKeyPath(path), options.throwOnPathMismatch ?? false, type => isArrayType(type)
122
- ? ok(type.items)
123
- : error(previousPath => `Key path "${previousPath}" does not contain an array type.`), (type, name) => {
124
- if (isObjectType(type)) {
125
- const prop = type.properties[name];
118
+ export const findTypeAtPath = (type, path, options = {}) => getAtKeyPath(type, [], parseKeyPath(path), options.throwOnPathMismatch ?? false, innerType => isArrayType(innerType)
119
+ ? ok(innerType.items)
120
+ : error(previousPath => `Key path "${previousPath}" does not contain an array type.`), (innerType, name) => {
121
+ if (isObjectType(innerType)) {
122
+ const prop = innerType.properties[name];
126
123
  if (prop) {
127
124
  return ok(prop.type);
128
125
  }
@@ -136,10 +133,10 @@ export const findTypeAtPath = (type, path, options = {}) => getAtKeyPath(type, [
136
133
  },
137
134
  // recursively resolves type aliases in includes as this is automatically
138
135
  // called recursively if needed
139
- type => isIncludeIdentifierType(type) &&
136
+ innerType => isIncludeIdentifierType(innerType) &&
140
137
  options.followTypeAliasIncludes &&
141
- isTypeAliasDecl(type.reference)
142
- ? ok([type.reference.type.value, true])
138
+ isTypeAliasDecl(innerType.reference)
139
+ ? ok([innerType.reference.type.value, true])
143
140
  : error());
144
141
  /**
145
142
  * Tests whether a type is a child entity type, either directly or through an include.