tsondb 0.7.6 → 0.7.7

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 (30) hide show
  1. package/dist/src/node/schema/Node.d.ts +8 -1
  2. package/dist/src/node/schema/Node.js +34 -18
  3. package/dist/src/node/schema/Schema.js +14 -10
  4. package/dist/src/node/schema/TypeParameter.js +1 -1
  5. package/dist/src/node/schema/declarations/EntityDecl.js +1 -1
  6. package/dist/src/node/schema/declarations/EnumDecl.js +1 -1
  7. package/dist/src/node/schema/declarations/TypeAliasDecl.js +1 -1
  8. package/dist/src/node/schema/types/generic/ArrayType.js +1 -1
  9. package/dist/src/node/schema/types/generic/EnumType.js +1 -1
  10. package/dist/src/node/schema/types/generic/ObjectType.js +1 -1
  11. package/dist/src/node/schema/types/references/ChildEntitiesType.js +1 -1
  12. package/dist/src/node/schema/types/references/IncludeIdentifierType.js +2 -2
  13. package/dist/src/node/schema/types/references/NestedEntityMapType.d.ts +12 -2
  14. package/dist/src/node/schema/types/references/NestedEntityMapType.js +2 -2
  15. package/dist/src/node/schema/types/references/ReferenceIdentifierType.js +2 -2
  16. package/dist/src/shared/schema/declarations/EntityDecl.d.ts +2 -0
  17. package/dist/src/shared/schema/declarations/EntityDecl.js +2 -0
  18. package/dist/src/shared/schema/declarations/EnumDecl.d.ts +2 -1
  19. package/dist/src/shared/schema/declarations/EnumDecl.js +2 -0
  20. package/dist/src/shared/schema/declarations/TypeAliasDecl.d.ts +2 -1
  21. package/dist/src/shared/schema/declarations/TypeAliasDecl.js +2 -1
  22. package/dist/src/web/components/InstanceRouteSkeleton.d.ts +5 -0
  23. package/dist/src/web/components/InstanceRouteSkeleton.js +4 -4
  24. package/dist/src/web/components/typeInputs/utils/MismatchingTypeError.js +2 -2
  25. package/dist/src/web/hooks/useSecondaryDeclarations.js +6 -3
  26. package/dist/src/web/hooks/useSettings.js +0 -1
  27. package/dist/src/web/routes/CreateInstance.js +27 -22
  28. package/dist/src/web/routes/Instance.js +20 -8
  29. package/dist/src/web/utils/typeSkeleton.js +1 -1
  30. package/package.json +1 -1
@@ -39,6 +39,13 @@ import type { Type } from "./types/Type.ts";
39
39
  export type { BaseNode } from "../../shared/schema/Node.ts";
40
40
  export { NodeKind };
41
41
  export type Node = Decl | Type | TypeParameter;
42
+ export type NestedDecl = Decl | NestedEntity;
43
+ export type NestedEntity = {
44
+ kind: "NestedEntity";
45
+ sourceUrl: string;
46
+ name: string;
47
+ type: NestedEntityMapType;
48
+ };
42
49
  export declare const reduceNodes: <R>(reducer: (parentNodes: Node[], node: Node, collectedResults: R[]) => R[], nodes: readonly Node[], options?: {
43
50
  initialResults?: R[];
44
51
  followIncludes?: boolean;
@@ -55,7 +62,7 @@ export interface Validators {
55
62
  }
56
63
  export declare const createValidators: (instancesByEntityName: InstancesByEntityName, useStyling: boolean, checkReferentialIntegrity?: boolean) => Validators;
57
64
  export type Predicate<T extends Node> = (node: Node) => node is T;
58
- export type GetNestedDeclarations<T extends Node = Node> = (addedDecls: Decl[], node: T) => Decl[];
65
+ export type GetNestedDeclarations<T extends Node = Node> = (addedDecls: NestedDecl[], node: T, parentDecl: Decl | undefined) => NestedDecl[];
59
66
  export declare const getNestedDeclarations: GetNestedDeclarations;
60
67
  export type Validator<T extends Node = Node> = (helpers: Validators, node: T, value: unknown) => Error[];
61
68
  export type ValidatorOfParamDecl<T extends Node = Node> = (helpers: Validators, node: T, typeArgs: Type[], value: unknown) => Error[];
@@ -91,42 +91,58 @@ export const createValidators = (instancesByEntityName, useStyling, checkReferen
91
91
  ]
92
92
  : () => [],
93
93
  });
94
- export const getNestedDeclarations = (addedDecls, node) => {
94
+ export const getNestedDeclarations = (addedDecls, node, parentDecl) => {
95
95
  switch (node.kind) {
96
96
  case NodeKind.EntityDecl:
97
- return getNestedDeclarationsInEntityDecl(addedDecls, node);
97
+ return addedDecls.includes(node)
98
+ ? addedDecls
99
+ : getNestedDeclarationsInEntityDecl([...addedDecls, node], node, parentDecl);
98
100
  case NodeKind.EnumDecl:
99
- return getNestedDeclarationsInEnumDecl(addedDecls, node);
101
+ return addedDecls.includes(node)
102
+ ? addedDecls
103
+ : getNestedDeclarationsInEnumDecl([...addedDecls, node], node, parentDecl);
100
104
  case NodeKind.TypeAliasDecl:
101
- return getNestedDeclarationsInTypeAliasDecl(addedDecls, node);
105
+ return addedDecls.includes(node)
106
+ ? addedDecls
107
+ : getNestedDeclarationsInTypeAliasDecl([...addedDecls, node], node, parentDecl);
102
108
  case NodeKind.ArrayType:
103
- return getNestedDeclarationsInArrayType(addedDecls, node);
109
+ return getNestedDeclarationsInArrayType(addedDecls, node, parentDecl);
104
110
  case NodeKind.ObjectType:
105
- return getNestedDeclarationsInObjectType(addedDecls, node);
111
+ return getNestedDeclarationsInObjectType(addedDecls, node, parentDecl);
106
112
  case NodeKind.BooleanType:
107
- return getNestedDeclarationsInBooleanType(addedDecls, node);
113
+ return getNestedDeclarationsInBooleanType(addedDecls, node, parentDecl);
108
114
  case NodeKind.DateType:
109
- return getNestedDeclarationsInDateType(addedDecls, node);
115
+ return getNestedDeclarationsInDateType(addedDecls, node, parentDecl);
110
116
  case NodeKind.FloatType:
111
- return getNestedDeclarationsInFloatType(addedDecls, node);
117
+ return getNestedDeclarationsInFloatType(addedDecls, node, parentDecl);
112
118
  case NodeKind.IntegerType:
113
- return getNestedDeclarationsInIntegerType(addedDecls, node);
119
+ return getNestedDeclarationsInIntegerType(addedDecls, node, parentDecl);
114
120
  case NodeKind.StringType:
115
- return getNestedDeclarationsInStringType(addedDecls, node);
121
+ return getNestedDeclarationsInStringType(addedDecls, node, parentDecl);
116
122
  case NodeKind.TypeArgumentType:
117
- return getNestedDeclarationsInTypeArgumentType(addedDecls, node);
123
+ return getNestedDeclarationsInTypeArgumentType(addedDecls, node, parentDecl);
118
124
  case NodeKind.ReferenceIdentifierType:
119
- return getNestedDeclarationsInReferenceIdentifierType(addedDecls, node);
125
+ return getNestedDeclarationsInReferenceIdentifierType(addedDecls, node, parentDecl);
120
126
  case NodeKind.IncludeIdentifierType:
121
- return getNestedDeclarationsInIncludeIdentifierType(addedDecls, node);
127
+ return getNestedDeclarationsInIncludeIdentifierType(addedDecls, node, parentDecl);
122
128
  case NodeKind.NestedEntityMapType:
123
- return getNestedDeclarationsInNestedEntityMapType(addedDecls, node);
129
+ return addedDecls.some(addedDecl => addedDecl.kind === "NestedEntity" && addedDecl.type === node)
130
+ ? addedDecls
131
+ : getNestedDeclarationsInNestedEntityMapType([
132
+ ...addedDecls,
133
+ {
134
+ kind: "NestedEntity",
135
+ sourceUrl: parentDecl?.sourceUrl ?? "",
136
+ name: node.name,
137
+ type: node,
138
+ },
139
+ ], node, parentDecl);
124
140
  case NodeKind.EnumType:
125
- return getNestedDeclarationsInEnumType(addedDecls, node);
141
+ return getNestedDeclarationsInEnumType(addedDecls, node, parentDecl);
126
142
  case NodeKind.TypeParameter:
127
- return getNestedDeclarationsInTypeParameter(addedDecls, node);
143
+ return getNestedDeclarationsInTypeParameter(addedDecls, node, parentDecl);
128
144
  case NodeKind.ChildEntitiesType:
129
- return getNestedDeclarationsInChildEntitiesType(addedDecls, node);
145
+ return getNestedDeclarationsInChildEntitiesType(addedDecls, node, parentDecl);
130
146
  default:
131
147
  return assertExhaustive(node);
132
148
  }
@@ -152,29 +152,33 @@ const checkChildEntitiesProvideCorrectPathToParentReferenceIdentifierType = (dec
152
152
  }
153
153
  }
154
154
  };
155
- const addDeclarations = (existingDecls, declsToAdd, nested) => declsToAdd.reduce((accDecls, decl) => {
155
+ const addDeclarations = (existingDecls, declsToAdd) => declsToAdd.reduce((accDecls, decl) => {
156
156
  if (!accDecls.includes(decl)) {
157
- checkDuplicateIdentifier(accDecls, decl);
158
- const nestedDecls = nested ? getNestedDeclarations(accDecls, decl) : [];
159
- return addDeclarations([...accDecls, decl], nestedDecls, false);
157
+ return getNestedDeclarations(accDecls, decl.kind === "NestedEntity" ? decl.type : decl, undefined);
160
158
  }
161
159
  return accDecls;
162
160
  }, existingDecls);
163
161
  export const Schema = (declarations, localeEntity) => {
164
162
  debug("creating schema from %d declarations", declarations.length);
165
163
  debug("collecting nested declarations ...");
166
- const allDecls = addDeclarations([], localeEntity ? declarations.concat(localeEntity) : declarations, true);
164
+ const allDecls = addDeclarations([], localeEntity ? declarations.concat(localeEntity) : declarations);
165
+ debug("found %d nested declarations", allDecls.length);
166
+ debug("checking for duplicate identifiers ...");
167
+ allDecls.forEach((decl, declIndex) => {
168
+ checkDuplicateIdentifier(allDecls.slice(0, declIndex), decl);
169
+ });
170
+ const allDeclsWithoutNestedEntities = allDecls.filter(decl => decl.kind !== "NestedEntity");
167
171
  debug("checking name shadowing ...");
168
- checkParameterNamesShadowing(allDecls);
172
+ checkParameterNamesShadowing(allDeclsWithoutNestedEntities);
169
173
  debug("checking entity display name paths ...");
170
- checkEntityDisplayNamePaths(allDecls, localeEntity);
174
+ checkEntityDisplayNamePaths(allDeclsWithoutNestedEntities, localeEntity);
171
175
  debug("checking child entities ...");
172
- checkChildEntitiesProvideCorrectPathToParentReferenceIdentifierType(allDecls);
176
+ checkChildEntitiesProvideCorrectPathToParentReferenceIdentifierType(allDeclsWithoutNestedEntities);
173
177
  debug("checking child entity types ...");
174
- checkChildEntityTypes(localeEntity, allDecls);
178
+ checkChildEntityTypes(localeEntity, allDeclsWithoutNestedEntities);
175
179
  debug("created schema, no integrity violations found");
176
180
  return {
177
- declarations: allDecls,
181
+ declarations: allDeclsWithoutNestedEntities,
178
182
  localeEntity,
179
183
  };
180
184
  };
@@ -4,7 +4,7 @@ export const Param = (name, constraint) => ({
4
4
  name,
5
5
  constraint,
6
6
  });
7
- export const getNestedDeclarationsInTypeParameter = (addedDecls, param) => (param.constraint ? getNestedDeclarations(addedDecls, param.constraint) : addedDecls);
7
+ export const getNestedDeclarationsInTypeParameter = (addedDecls, param, parentDecl) => param.constraint ? getNestedDeclarations(addedDecls, param.constraint, parentDecl) : addedDecls;
8
8
  export const resolveTypeArgumentsInTypeParameter = (_args, param) => param;
9
9
  export const serializeTypeParameter = type => ({
10
10
  ...type,
@@ -26,7 +26,7 @@ export const EntityDecl = (sourceUrl, options) => {
26
26
  export { EntityDecl as Entity };
27
27
  export const isEntityDecl = node => node.kind === NodeKind.EntityDecl;
28
28
  export const isEntityDeclWithParentReference = (decl) => decl.parentReferenceKey !== undefined;
29
- export const getNestedDeclarationsInEntityDecl = (isDeclAdded, decl) => getNestedDeclarationsInObjectType(isDeclAdded, decl.type.value);
29
+ export const getNestedDeclarationsInEntityDecl = (isDeclAdded, decl) => getNestedDeclarationsInObjectType(isDeclAdded, decl.type.value, decl);
30
30
  export const validateEntityDecl = (helpers, decl, value) => validateType(helpers, decl.type.value, value);
31
31
  export const resolveTypeArgumentsInEntityDecl = (_args, decl) => EntityDecl(decl.sourceUrl, {
32
32
  ...decl,
@@ -28,7 +28,7 @@ export const EnumDecl = (sourceUrl, options) => {
28
28
  };
29
29
  export { EnumDecl as Enum };
30
30
  export const isEnumDecl = node => node.kind === NodeKind.EnumDecl;
31
- export const getNestedDeclarationsInEnumDecl = (addedDecls, decl) => getNestedDeclarationsInEnumType(addedDecls, decl.type.value);
31
+ export const getNestedDeclarationsInEnumDecl = (addedDecls, decl) => getNestedDeclarationsInEnumType(addedDecls, decl.type.value, decl);
32
32
  export const validateEnumDecl = (helpers, decl, args, value) => validateEnumType(helpers, resolveTypeArgumentsInEnumType(getTypeArgumentsRecord(decl, args), decl.type.value), value);
33
33
  export const resolveTypeArgumentsInEnumDecl = (args, decl) => EnumDecl(decl.sourceUrl, {
34
34
  name: decl.name,
@@ -26,7 +26,7 @@ export const TypeAliasDecl = (sourceUrl, options) => {
26
26
  };
27
27
  export { TypeAliasDecl as TypeAlias };
28
28
  export const isTypeAliasDecl = node => node.kind === NodeKind.TypeAliasDecl;
29
- export const getNestedDeclarationsInTypeAliasDecl = (addedDecls, decl) => getNestedDeclarations(addedDecls, decl.type.value);
29
+ export const getNestedDeclarationsInTypeAliasDecl = (addedDecls, decl) => getNestedDeclarations(addedDecls, decl.type.value, decl);
30
30
  export const validateTypeAliasDecl = ((helpers, decl, args, value) => validateType(helpers, resolveTypeArguments(getTypeArgumentsRecord(decl, args), decl.type.value), value));
31
31
  export const resolveTypeArgumentsInTypeAliasDecl = (args, decl) => TypeAliasDecl(decl.sourceUrl, {
32
32
  ...decl,
@@ -14,7 +14,7 @@ export const ArrayType = (items, options = {}) => ({
14
14
  });
15
15
  export { ArrayType as Array };
16
16
  export const isArrayType = node => node.kind === NodeKind.ArrayType;
17
- export const getNestedDeclarationsInArrayType = (addedDecls, type) => getNestedDeclarations(addedDecls, type.items);
17
+ export const getNestedDeclarationsInArrayType = (addedDecls, type, parentDecl) => getNestedDeclarations(addedDecls, type.items, parentDecl);
18
18
  export const validateArrayType = (helpers, type, value) => {
19
19
  if (!Array.isArray(value)) {
20
20
  return [TypeError(`expected an array, but got ${json(value, helpers.useStyling)}`)];
@@ -9,7 +9,7 @@ export const EnumType = (values) => ({
9
9
  values,
10
10
  });
11
11
  export const isEnumType = node => node.kind === NodeKind.EnumType;
12
- export const getNestedDeclarationsInEnumType = (addedDecls, type) => Object.values(type.values).reduce((acc, caseMember) => caseMember.type === null ? acc : getNestedDeclarations(acc, caseMember.type), addedDecls);
12
+ export const getNestedDeclarationsInEnumType = (addedDecls, type, parentDecl) => Object.values(type.values).reduce((acc, caseMember) => caseMember.type === null ? acc : getNestedDeclarations(acc, caseMember.type, parentDecl), addedDecls);
13
13
  export const validateEnumType = (helpers, type, value) => {
14
14
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
15
15
  return [TypeError(`expected an object, but got ${json(value, helpers.useStyling)}`)];
@@ -25,7 +25,7 @@ export const ObjectType = (properties, options = {}) => {
25
25
  };
26
26
  export { ObjectType as Object };
27
27
  export const isObjectType = node => node.kind === NodeKind.ObjectType;
28
- export const getNestedDeclarationsInObjectType = (addedDecls, type) => Object.values(type.properties).reduce((acc, prop) => getNestedDeclarations(acc, prop.type), addedDecls);
28
+ export const getNestedDeclarationsInObjectType = (addedDecls, type, parentDecl) => Object.values(type.properties).reduce((acc, prop) => getNestedDeclarations(acc, prop.type, parentDecl), addedDecls);
29
29
  export const validateObjectType = (helpers, type, value) => {
30
30
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
31
31
  return [TypeError(`expected an object, but got ${json(value, helpers.useStyling)}`)];
@@ -7,7 +7,7 @@ export const ChildEntitiesType = (entity) => ({
7
7
  });
8
8
  export { ChildEntitiesType as ChildEntities };
9
9
  export const isChildEntitiesType = node => node.kind === NodeKind.ChildEntitiesType;
10
- export const getNestedDeclarationsInChildEntitiesType = (addedDecls, type) => getNestedDeclarations([type.entity, ...addedDecls], type.entity);
10
+ export const getNestedDeclarationsInChildEntitiesType = (addedDecls, type, parentDecl) => getNestedDeclarations(addedDecls, type.entity, parentDecl);
11
11
  export const validateChildEntitiesType = () => [];
12
12
  export const resolveTypeArgumentsInChildEntitiesType = (_args, type) => type;
13
13
  export const serializeChildEntitiesType = type => ({
@@ -16,9 +16,9 @@ export const IncludeIdentifierType = (reference) => ({
16
16
  export { IncludeIdentifierType as IncludeIdentifier };
17
17
  export const isIncludeIdentifierType = node => node.kind === NodeKind.IncludeIdentifierType;
18
18
  const isNoGenericIncludeIdentifierType = (node) => node.args.length === 0 && node.reference.parameters.length === 0;
19
- export const getNestedDeclarationsInIncludeIdentifierType = (addedDecls, type) => type.args.reduce((accAddedDecls, arg) => getNestedDeclarations(accAddedDecls, arg), addedDecls.includes(type.reference)
19
+ export const getNestedDeclarationsInIncludeIdentifierType = (addedDecls, type, parentDecl) => type.args.reduce((accAddedDecls, arg) => getNestedDeclarations(accAddedDecls, arg, parentDecl), addedDecls.includes(type.reference)
20
20
  ? addedDecls
21
- : getNestedDeclarations([type.reference, ...addedDecls], type.reference));
21
+ : getNestedDeclarations(addedDecls, type.reference, parentDecl));
22
22
  export const validateIncludeIdentifierType = (helpers, type, value) => validateDecl(helpers, type.reference, type.args, value);
23
23
  export const resolveTypeArgumentsInIncludeIdentifierType = ((args, type) => (isNoGenericIncludeIdentifierType(type)
24
24
  ? type
@@ -1,6 +1,8 @@
1
1
  import { Lazy } from "../../../../shared/utils/lazy.ts";
2
- import type { EntityDecl } from "../../declarations/EntityDecl.ts";
3
- import type { TypeAliasDecl } from "../../declarations/TypeAliasDecl.ts";
2
+ import type { DisplayNameCustomizer } from "../../../utils/displayName.ts";
3
+ import type { EntityDecl } from "../../declarations/EntityDecl.js";
4
+ import { type EntityDisplayName } from "../../declarations/EntityDecl.js";
5
+ import type { TypeAliasDecl } from "../../declarations/TypeAliasDecl.js";
4
6
  import type { GetNestedDeclarations, GetReferences, Predicate, Serializer, TypeArgumentsResolver, Validator } from "../../Node.ts";
5
7
  import { NodeKind } from "../../Node.ts";
6
8
  import type { MemberDecl, ObjectType } from "../generic/ObjectType.ts";
@@ -11,15 +13,23 @@ type PossibleType<T extends TConstraint> = ObjectType<T> | IncludeIdentifier<[],
11
13
  export interface NestedEntityMapType<Name extends string = string, T extends TConstraint = TConstraint> extends BaseType {
12
14
  kind: NodeKind["NestedEntityMapType"];
13
15
  name: Name;
16
+ namePlural: string;
14
17
  comment?: string;
15
18
  secondaryEntity: EntityDecl;
16
19
  type: Lazy<PossibleType<T>>;
17
20
  }
18
21
  export declare const NestedEntityMapType: <Name extends string, T extends TConstraint>(options: {
19
22
  name: Name;
23
+ namePlural: string;
20
24
  comment?: string;
21
25
  secondaryEntity: EntityDecl;
22
26
  type: PossibleType<T>;
27
+ /**
28
+ * @default "name"
29
+ */
30
+ displayName?: EntityDisplayName<T>;
31
+ displayNameCustomizer?: DisplayNameCustomizer<ObjectType<T>>;
32
+ isDeprecated?: boolean;
23
33
  }) => NestedEntityMapType<Name, T>;
24
34
  export { NestedEntityMapType as NestedEntityMap };
25
35
  export declare const isNestedEntityMapType: Predicate<NestedEntityMapType>;
@@ -3,7 +3,7 @@ import { sortObjectKeysAlphabetically } from "../../../../shared/utils/object.js
3
3
  import { parallelizeErrors } from "../../../../shared/utils/validation.js";
4
4
  import { wrapErrorsIfAny } from "../../../utils/error.js";
5
5
  import { entity, json, key as keyColor } from "../../../utils/errorFormatting.js";
6
- import {} from "../../declarations/Declaration.js";
6
+ import {} from "../../declarations/EntityDecl.js";
7
7
  import { getNestedDeclarations, NodeKind, resolveTypeArguments, validateType } from "../../Node.js";
8
8
  import { getReferencesForObjectType, isObjectType, serializeObjectType, } from "../generic/ObjectType.js";
9
9
  import { formatValue } from "../Type.js";
@@ -26,7 +26,7 @@ const _NestedEntityMapType = (options) => {
26
26
  return nestedEntityMapType;
27
27
  };
28
28
  export const isNestedEntityMapType = node => node.kind === NodeKind.NestedEntityMapType;
29
- export const getNestedDeclarationsInNestedEntityMapType = (addedDecls, type) => getNestedDeclarations(addedDecls.includes(type.secondaryEntity) ? addedDecls : [type.secondaryEntity, ...addedDecls], type.type.value);
29
+ export const getNestedDeclarationsInNestedEntityMapType = (addedDecls, type, parentDecl) => getNestedDeclarations(getNestedDeclarations(addedDecls, type.secondaryEntity, parentDecl), type.type.value, parentDecl);
30
30
  export const validateNestedEntityMapType = (helpers, type, value) => {
31
31
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
32
32
  return [TypeError(`expected an object, but got ${json(value, helpers.useStyling)}`)];
@@ -6,9 +6,9 @@ export const ReferenceIdentifierType = (entity) => ({
6
6
  });
7
7
  export { ReferenceIdentifierType as ReferenceIdentifier };
8
8
  export const isReferenceIdentifierType = (node) => node.kind === NodeKind.ReferenceIdentifierType;
9
- export const getNestedDeclarationsInReferenceIdentifierType = (addedDecls, type) => addedDecls.includes(type.entity)
9
+ export const getNestedDeclarationsInReferenceIdentifierType = (addedDecls, type, parentDecl) => addedDecls.includes(type.entity)
10
10
  ? addedDecls
11
- : getNestedDeclarations([...addedDecls, type.entity], type.entity);
11
+ : getNestedDeclarations(addedDecls, type.entity, parentDecl);
12
12
  export const validateReferenceIdentifierType = (helpers, type, value) => validateType(helpers, createEntityIdentifierType(), value).concat(helpers.checkReferentialIntegrity({
13
13
  name: type.entity.name,
14
14
  value: value,
@@ -27,6 +27,8 @@ export interface SerializedEntityDecl<Name extends string = string, T extends TC
27
27
  isDeprecated?: boolean;
28
28
  }
29
29
  export declare const isSerializedEntityDecl: (node: SerializedNode) => node is SerializedEntityDecl;
30
+ export declare const isSerializedEntityDeclWithParentReference: <Name extends string, T extends TConstraint, FK extends (keyof T & string) | undefined>(decl: SerializedEntityDecl<Name, T, FK>) => decl is SerializedEntityDecl<Name, T, NonNullable<FK>>;
31
+ export declare const isSerializedEntityDeclWithoutParentReference: <Name extends string, T extends TConstraint>(decl: SerializedEntityDecl<Name, T>) => decl is SerializedEntityDecl<Name, T, undefined>;
30
32
  export declare const resolveTypeArgumentsInSerializedEntityDecl: SerializedTypeArgumentsResolver<SerializedEntityDecl>;
31
33
  export declare const getReferencesForSerializedEntityDecl: GetReferencesSerialized<SerializedEntityDecl>;
32
34
  export {};
@@ -1,6 +1,8 @@
1
1
  import { NodeKind, resolveSerializedTypeArguments, } from "../Node.js";
2
2
  import { getReferencesForSerializedObjectType, } from "../types/ObjectType.js";
3
3
  export const isSerializedEntityDecl = (node) => node.kind === NodeKind.EntityDecl;
4
+ export const isSerializedEntityDeclWithParentReference = (decl) => decl.parentReferenceKey !== undefined;
5
+ export const isSerializedEntityDeclWithoutParentReference = (decl) => decl.parentReferenceKey === undefined;
4
6
  export const resolveTypeArgumentsInSerializedEntityDecl = (decls, _args, decl) => ({
5
7
  ...decl,
6
8
  type: resolveSerializedTypeArguments(decls, {}, decl.type),
@@ -1,4 +1,4 @@
1
- import type { GetReferencesSerialized, NodeKind, SerializedTypeArgumentsResolver } from "../Node.ts";
1
+ import { NodeKind, type GetReferencesSerialized, type SerializedNode, type SerializedTypeArgumentsResolver } from "../Node.js";
2
2
  import type { SerializedTypeParameter } from "../TypeParameter.ts";
3
3
  import { type SerializedEnumCaseDecl, type SerializedEnumType } from "../types/EnumType.ts";
4
4
  import type { SerializedBaseDecl } from "./Declaration.ts";
@@ -7,5 +7,6 @@ export interface SerializedEnumDecl<Name extends string = string, T extends Reco
7
7
  type: SerializedEnumType<T>;
8
8
  isDeprecated?: boolean;
9
9
  }
10
+ export declare const isSerializedEnumDecl: (node: SerializedNode) => node is SerializedEnumDecl;
10
11
  export declare const resolveTypeArgumentsInSerializedEnumDecl: SerializedTypeArgumentsResolver<SerializedEnumDecl>;
11
12
  export declare const getReferencesForSerializedEnumDecl: GetReferencesSerialized<SerializedEnumDecl>;
@@ -1,4 +1,6 @@
1
+ import { NodeKind, } from "../Node.js";
1
2
  import { getReferencesForSerializedEnumType, resolveTypeArgumentsInSerializedEnumType, } from "../types/EnumType.js";
3
+ export const isSerializedEnumDecl = (node) => node.kind === NodeKind.EnumDecl;
2
4
  export const resolveTypeArgumentsInSerializedEnumDecl = (decls, args, decl) => {
3
5
  return {
4
6
  ...decl,
@@ -1,4 +1,4 @@
1
- import { type GetReferencesSerialized, type NodeKind, type SerializedTypeArgumentsResolver } from "../Node.ts";
1
+ import { NodeKind, type GetReferencesSerialized, type SerializedNode, type SerializedTypeArgumentsResolver } from "../Node.ts";
2
2
  import type { SerializedTypeParameter } from "../TypeParameter.ts";
3
3
  import type { SerializedType } from "../types/Type.ts";
4
4
  import type { SerializedBaseDecl } from "./Declaration.ts";
@@ -7,5 +7,6 @@ export interface SerializedTypeAliasDecl<Name extends string = string, T extends
7
7
  type: T;
8
8
  isDeprecated?: boolean;
9
9
  }
10
+ export declare const isSerializedTypeAliasDecl: (node: SerializedNode) => node is SerializedTypeAliasDecl;
10
11
  export declare const resolveTypeArgumentsInSerializedTypeAliasDecl: SerializedTypeArgumentsResolver<SerializedTypeAliasDecl>;
11
12
  export declare const getReferencesForSerializedTypeAliasDecl: GetReferencesSerialized<SerializedTypeAliasDecl>;
@@ -1,4 +1,5 @@
1
- import { getReferencesSerialized, resolveSerializedTypeArguments, } from "../Node.js";
1
+ import { getReferencesSerialized, NodeKind, resolveSerializedTypeArguments, } from "../Node.js";
2
+ export const isSerializedTypeAliasDecl = (node) => node.kind === NodeKind.TypeAliasDecl;
2
3
  export const resolveTypeArgumentsInSerializedTypeAliasDecl = (decls, args, decl) => ({
3
4
  ...decl,
4
5
  parameters: [],
@@ -34,6 +34,11 @@ export type InstanceRouteSkeletonTitleBuilder = (values: {
34
34
  }) => string | undefined;
35
35
  type Props = {
36
36
  mode: "create" | "edit";
37
+ buttons: {
38
+ label: string;
39
+ name: string;
40
+ primary?: boolean;
41
+ }[];
37
42
  init: InstanceRouteSkeletonInitializer;
38
43
  titleBuilder: InstanceRouteSkeletonTitleBuilder;
39
44
  onSubmit: InstanceRouteSkeletonOnSubmitHandler;
@@ -15,7 +15,7 @@ import { NotFound } from "../routes/NotFound.js";
15
15
  import { Layout } from "./Layout.js";
16
16
  import { TypeInput } from "./typeInputs/TypeInput.js";
17
17
  import { ValidationErrors } from "./typeInputs/utils/ValidationErrors.js";
18
- export const InstanceRouteSkeleton = ({ mode, init, titleBuilder, onSubmit, }) => {
18
+ export const InstanceRouteSkeleton = ({ mode, buttons, init, titleBuilder, onSubmit, }) => {
19
19
  const { params: { name, id }, } = useRoute();
20
20
  const [locales] = useSetting("displayedLocales");
21
21
  const [getDeclFromDeclName, declsLoaded] = useGetDeclFromDeclName();
@@ -31,7 +31,7 @@ export const InstanceRouteSkeleton = ({ mode, init, titleBuilder, onSubmit, }) =
31
31
  "Not found — TSONDB";
32
32
  }, [entity, id, instanceContent, locales, titleBuilder]);
33
33
  useEffect(() => {
34
- if (entity && instanceContent === undefined) {
34
+ if (entity && instanceContent === undefined && declsLoaded) {
35
35
  init({ locales, entity, instanceId: id, setInstanceContent, getDeclFromDeclName })
36
36
  .then(() => id
37
37
  ? getChildInstancesForInstanceByEntityName(locales, entity.name, id).then(result => {
@@ -42,7 +42,7 @@ export const InstanceRouteSkeleton = ({ mode, init, titleBuilder, onSubmit, }) =
42
42
  console.error("Error initializing instance route skeleton:", error);
43
43
  });
44
44
  }
45
- }, [entity, getDeclFromDeclName, id, init, instanceContent, locales, name]);
45
+ }, [entity, declsLoaded, getDeclFromDeclName, id, init, instanceContent, locales, name]);
46
46
  const handleSubmit = (event) => {
47
47
  event.preventDefault();
48
48
  if (entity && instanceContent !== undefined) {
@@ -110,5 +110,5 @@ export const InstanceRouteSkeleton = ({ mode, init, titleBuilder, onSubmit, }) =
110
110
  }
111
111
  }, children: "Delete" }))] }), !id && isLocaleEntity && (_jsxs("div", { class: "field field--id", children: [_jsx("label", { htmlFor: "id", children: "ID" }), _jsx("p", { className: "comment", children: "The instance\u2019s identifier. An IETF language tag (BCP47)." }), _jsx("input", { type: "text", id: "id", value: customId, required: true, pattern: "[a-z]{2,3}(-[A-Z]{2,3})?", placeholder: "en-US, de-DE, \u2026", onInput: event => {
112
112
  setCustomId(event.currentTarget.value);
113
- }, "aria-invalid": idErrors.length > 0 }), _jsx(ValidationErrors, { errors: idErrors })] })), _jsxs("form", { onSubmit: handleSubmit, children: [_jsx(TypeInput, { type: entity.type, value: instanceContent, path: undefined, instanceNamesByEntity: instanceNamesByEntity, childInstances: childInstances, getDeclFromDeclName: getDeclFromDeclName, onChange: setInstanceContent, onChildChange: handleOnChildChange, onChildAdd: handleOnChildAdd, onChildRemove: handleOnChildRemove }), _jsx("div", { class: "form-footer btns", children: _jsx("button", { type: "submit", name: "save", class: "primary", children: "Save" }) })] })] }));
113
+ }, "aria-invalid": idErrors.length > 0 }), _jsx(ValidationErrors, { errors: idErrors })] })), _jsxs("form", { onSubmit: handleSubmit, children: [_jsx(TypeInput, { type: entity.type, value: instanceContent, path: undefined, instanceNamesByEntity: instanceNamesByEntity, childInstances: childInstances, getDeclFromDeclName: getDeclFromDeclName, onChange: setInstanceContent, onChildChange: handleOnChildChange, onChildAdd: handleOnChildAdd, onChildRemove: handleOnChildRemove }), _jsx("div", { class: "form-footer btns", children: buttons.map(button => (_jsx("button", { type: "submit", name: button.name, class: button.primary ? "primary" : undefined, children: button.label }, button.name))) })] })] }));
114
114
  };
@@ -1,4 +1,4 @@
1
- import { jsxs as _jsxs } from "preact/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
2
  export const MismatchingTypeError = ({ expected, actual }) => {
3
- return (_jsxs("div", { role: "alert", children: ["Expected value of type ", expected, ", but got ", JSON.stringify(actual)] }));
3
+ return (_jsxs("div", { role: "alert", children: ["Expected value of type ", expected, ", but got", " ", _jsx("code", { children: actual === undefined ? "undefined" : JSON.stringify(actual) })] }));
4
4
  };
@@ -1,4 +1,7 @@
1
1
  import { useCallback, useEffect, useState } from "preact/hooks";
2
+ import { isSerializedEntityDeclWithParentReference } from "../../shared/schema/declarations/EntityDecl.js";
3
+ import { isSerializedEnumDecl } from "../../shared/schema/declarations/EnumDecl.js";
4
+ import { isSerializedTypeAliasDecl } from "../../shared/schema/declarations/TypeAliasDecl.js";
2
5
  import { getAllDeclarations } from "../api/declarations.js";
3
6
  import { useSetting } from "./useSettings.js";
4
7
  export const useGetDeclFromDeclName = () => {
@@ -9,9 +12,9 @@ export const useGetDeclFromDeclName = () => {
9
12
  .then(data => {
10
13
  setSecondaryDeclarations(data.declarations
11
14
  .map(decl => decl.declaration)
12
- .filter((decl) => decl.kind === "EnumDecl" ||
13
- decl.kind === "TypeAliasDecl" ||
14
- decl.parentReferenceKey !== undefined));
15
+ .filter(decl => isSerializedEnumDecl(decl) ||
16
+ isSerializedTypeAliasDecl(decl) ||
17
+ isSerializedEntityDeclWithParentReference(decl)));
15
18
  })
16
19
  .catch((error) => {
17
20
  if (error instanceof Error) {
@@ -9,7 +9,6 @@ const defaultSettingsFromConfig = (config) => ({
9
9
  displayedLocales: config.defaultLocales.length > 0 ? config.defaultLocales : defaultSettings.displayedLocales,
10
10
  });
11
11
  export const useSettings = (config) => {
12
- console.log("useSettings");
13
12
  const [settings, setSettings] = useState(() => Object.fromEntries(Object.entries(defaultSettingsFromConfig(config)).map(([key, initialValue]) => {
14
13
  const item = localStorage.getItem(key);
15
14
  if (item) {
@@ -13,27 +13,28 @@ const titleBuilder = ({ entity }) => {
13
13
  };
14
14
  const onSubmit = async ({ locales, entity, buttonName, instanceContent, isLocaleEntity, customId, childInstances, setInstanceContent, setCustomId, route, getDeclFromDeclName, }) => {
15
15
  try {
16
- const createdInstance = await createInstanceByEntityNameAndId(locales, entity.name, {
17
- childInstances,
18
- entityName: entity.name,
19
- content: instanceContent,
20
- id: undefined,
21
- }, isLocaleEntity ? customId : undefined);
22
- switch (buttonName) {
23
- case "saveandcontinue": {
24
- route(`/entities/${entity.name}/instances/${createdInstance.instance.id}`);
25
- break;
26
- }
27
- case "saveandaddanother": {
28
- setInstanceContent(createTypeSkeleton(getDeclFromDeclName, entity.type));
29
- setCustomId("");
30
- alert(`Instance of entity ${entity.name} created successfully with identifier ${createdInstance.instance.id}. You can add another instance now.`);
31
- break;
32
- }
33
- case "save":
34
- default: {
35
- route(`/entities/${entity.name}?created=${encodeURIComponent(createdInstance.instance.id)}`);
36
- break;
16
+ if (buttonName) {
17
+ const createdInstance = await createInstanceByEntityNameAndId(locales, entity.name, {
18
+ childInstances,
19
+ entityName: entity.name,
20
+ content: instanceContent,
21
+ id: undefined,
22
+ }, isLocaleEntity ? customId : undefined);
23
+ switch (buttonName) {
24
+ case "saveandcontinue": {
25
+ route(`/entities/${entity.name}/instances/${createdInstance.instance.id}`);
26
+ break;
27
+ }
28
+ case "saveandaddanother": {
29
+ setInstanceContent(createTypeSkeleton(getDeclFromDeclName, entity.type));
30
+ setCustomId("");
31
+ alert(`Instance of entity ${entity.name} created successfully with identifier ${createdInstance.instance.id}. You can add another instance now.`);
32
+ break;
33
+ }
34
+ case "save": {
35
+ route(`/entities/${entity.name}?created=${encodeURIComponent(createdInstance.instance.id)}`);
36
+ break;
37
+ }
37
38
  }
38
39
  }
39
40
  }
@@ -43,4 +44,8 @@ const onSubmit = async ({ locales, entity, buttonName, instanceContent, isLocale
43
44
  }
44
45
  }
45
46
  };
46
- export const CreateInstance = () => (_jsx(InstanceRouteSkeleton, { mode: "create", init: init, titleBuilder: titleBuilder, onSubmit: onSubmit }));
47
+ export const CreateInstance = () => (_jsx(InstanceRouteSkeleton, { mode: "create", buttons: [
48
+ { label: "Save", name: "save", primary: true },
49
+ { label: "Save and continue", name: "saveandcontinue" },
50
+ { label: "Save and add another", name: "saveandaddanother" },
51
+ ], init: init, titleBuilder: titleBuilder, onSubmit: onSubmit }));
@@ -21,23 +21,35 @@ const titleBuilder = ({ locales, entity, instanceId, instanceContent, }) => {
21
21
  }
22
22
  return undefined;
23
23
  };
24
- const onSubmit = async ({ locales, entity, instanceId, instanceContent, buttonName, childInstances, }) => {
25
- if (instanceId && buttonName === "save") {
26
- try {
24
+ const onSubmit = async ({ locales, entity, instanceId, instanceContent, buttonName, childInstances, route, }) => {
25
+ try {
26
+ if (instanceId && buttonName) {
27
27
  await updateInstanceByEntityNameAndId(locales, entity.name, instanceId, {
28
28
  childInstances,
29
29
  entityName: entity.name,
30
30
  content: instanceContent,
31
31
  id: instanceId,
32
32
  });
33
- }
34
- catch (error) {
35
- if (error instanceof Error) {
36
- alert(`Error updating instance:\n\n${error}`);
33
+ switch (buttonName) {
34
+ case "saveandcontinue": {
35
+ break;
36
+ }
37
+ case "save": {
38
+ route(`/entities/${entity.name}`);
39
+ break;
40
+ }
37
41
  }
38
42
  }
39
43
  }
44
+ catch (error) {
45
+ if (error instanceof Error) {
46
+ alert(`Error updating instance:\n\n${error}`);
47
+ }
48
+ }
40
49
  };
41
50
  export const Instance = () => {
42
- return (_jsx(InstanceRouteSkeleton, { mode: "edit", init: init, titleBuilder: titleBuilder, onSubmit: onSubmit }));
51
+ return (_jsx(InstanceRouteSkeleton, { mode: "edit", buttons: [
52
+ { label: "Save", name: "save", primary: true },
53
+ { label: "Save and continue", name: "saveandcontinue" },
54
+ ], init: init, titleBuilder: titleBuilder, onSubmit: onSubmit }));
43
55
  };
@@ -43,7 +43,7 @@ export const createTypeSkeleton = (getDeclFromDeclName, type) => {
43
43
  };
44
44
  }
45
45
  case "ChildEntitiesType":
46
- return [];
46
+ return undefined;
47
47
  default:
48
48
  return assertExhaustive(type);
49
49
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsondb",
3
- "version": "0.7.6",
3
+ "version": "0.7.7",
4
4
  "description": "",
5
5
  "license": "ISC",
6
6
  "author": "Lukas Obermann",