tsondb 0.12.0 → 0.12.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.
Files changed (27) hide show
  1. package/dist/src/node/renderers/jsonschema/render.js +14 -0
  2. package/dist/src/node/renderers/ts/render.js +6 -0
  3. package/dist/src/node/schema/Node.d.ts +6 -3
  4. package/dist/src/node/schema/Node.js +12 -0
  5. package/dist/src/node/schema/Schema.js +1 -0
  6. package/dist/src/node/schema/index.d.ts +1 -0
  7. package/dist/src/node/schema/index.js +1 -0
  8. package/dist/src/node/schema/types/Type.d.ts +2 -1
  9. package/dist/src/node/schema/types/Type.js +5 -1
  10. package/dist/src/node/schema/types/generic/TranslationObjectType.d.ts +25 -0
  11. package/dist/src/node/schema/types/generic/TranslationObjectType.js +66 -0
  12. package/dist/src/node/utils/errorFormatting.js +1 -1
  13. package/dist/src/shared/schema/Node.d.ts +4 -2
  14. package/dist/src/shared/schema/Node.js +6 -0
  15. package/dist/src/shared/schema/types/TranslationObjectType.d.ts +16 -0
  16. package/dist/src/shared/schema/types/TranslationObjectType.js +12 -0
  17. package/dist/src/shared/schema/types/Type.d.ts +3 -2
  18. package/dist/src/shared/validation/object.d.ts +1 -0
  19. package/dist/src/shared/validation/object.js +4 -3
  20. package/dist/src/web/components/typeInputs/StringTypeInput.js +4 -2
  21. package/dist/src/web/components/typeInputs/TranslationObjectTypeInput.d.ts +6 -0
  22. package/dist/src/web/components/typeInputs/TranslationObjectTypeInput.js +39 -0
  23. package/dist/src/web/components/typeInputs/TypeInput.d.ts +1 -0
  24. package/dist/src/web/components/typeInputs/TypeInput.js +3 -0
  25. package/dist/src/web/utils/typeSkeleton.js +7 -0
  26. package/package.json +10 -10
  27. package/public/css/styles.css +28 -3
@@ -6,6 +6,7 @@ import { addEphemeralUUIDToType, createEntityIdentifierTypeAsDecl, isEntityDecl,
6
6
  import { TypeAliasDecl } from "../../schema/declarations/TypeAliasDecl.js";
7
7
  import { flatMapAuxiliaryDecls, NodeKind } from "../../schema/Node.js";
8
8
  import { ArrayType } from "../../schema/types/generic/ArrayType.js";
9
+ import { getTypeOfKey } from "../../schema/types/generic/TranslationObjectType.js";
9
10
  import { isNestedEntityMapType } from "../../schema/types/references/NestedEntityMapType.js";
10
11
  import { ReferenceIdentifierType } from "../../schema/types/references/ReferenceIdentifierType.js";
11
12
  import { ensureSpecialDirStart } from "../../utils/path.js";
@@ -104,6 +105,17 @@ const renderEnumType = (options, type) => ({
104
105
  })),
105
106
  });
106
107
  const renderChildEntitiesType = (options, type) => renderType(options, ArrayType(ReferenceIdentifierType(type.entity), { uniqueItems: true }));
108
+ const renderTranslationObjectType = (options, type) => ({
109
+ type: "object",
110
+ properties: Object.fromEntries(Object.entries(type.properties).map(([name, config]) => [
111
+ name,
112
+ {
113
+ ...renderType(options, getTypeOfKey(config, type)),
114
+ },
115
+ ])),
116
+ required: type.allKeysAreRequired ? Object.keys(type.properties) : undefined,
117
+ additionalProperties: false,
118
+ });
107
119
  const renderType = (options, type) => {
108
120
  switch (type.kind) {
109
121
  case NodeKind.ArrayType:
@@ -132,6 +144,8 @@ const renderType = (options, type) => {
132
144
  return renderEnumType(options, type);
133
145
  case NodeKind.ChildEntitiesType:
134
146
  return renderChildEntitiesType(options, type);
147
+ case NodeKind.TranslationObjectType:
148
+ return renderTranslationObjectType(options, type);
135
149
  default:
136
150
  return assertExhaustive(type, "Unknown type");
137
151
  }
@@ -10,6 +10,7 @@ import { TypeAliasDecl } from "../../schema/declarations/TypeAliasDecl.js";
10
10
  import { flatMapAuxiliaryDecls, NodeKind } from "../../schema/Node.js";
11
11
  import { ArrayType } from "../../schema/types/generic/ArrayType.js";
12
12
  import { isObjectType } from "../../schema/types/generic/ObjectType.js";
13
+ import { getTypeOfKey } from "../../schema/types/generic/TranslationObjectType.js";
13
14
  import { isNestedEntityMapType } from "../../schema/types/references/NestedEntityMapType.js";
14
15
  import { ReferenceIdentifierType } from "../../schema/types/references/ReferenceIdentifierType.js";
15
16
  import { ensureSpecialDirStart } from "../../utils/path.js";
@@ -61,6 +62,9 @@ const renderEnumType = (options, type) => combineSyntaxes(Object.entries(type.va
61
62
  ? ""
62
63
  : syntax `${EOL}${caseName}: ${renderType(options, caseDef.type)}`}`)}${EOL}}`)));
63
64
  const renderChildEntitiesType = (options, type) => renderType(options, ArrayType(ReferenceIdentifierType(type.entity), { uniqueItems: true }));
65
+ const renderTranslationObjectType = (options, type) => {
66
+ return wrapAsObject(options, combineSyntaxes(Object.entries(type.properties).map(([name, config]) => syntax `"${name.replace('"', '\\"')}"${type.allKeysAreRequired ? "" : "?"}: ${renderType(options, getTypeOfKey(config, type))}`), EOL));
67
+ };
64
68
  const renderType = (options, type) => {
65
69
  switch (type.kind) {
66
70
  case NodeKind.ArrayType:
@@ -89,6 +93,8 @@ const renderType = (options, type) => {
89
93
  return renderEnumType(options, type);
90
94
  case NodeKind.ChildEntitiesType:
91
95
  return renderChildEntitiesType(options, type);
96
+ case NodeKind.TranslationObjectType:
97
+ return renderTranslationObjectType(options, type);
92
98
  default:
93
99
  return assertExhaustive(type, "Unknown type");
94
100
  }
@@ -15,6 +15,7 @@ import type { SerializedNestedEntityMapType } from "../../shared/schema/types/Ne
15
15
  import type { SerializedMemberDecl, SerializedObjectType } from "../../shared/schema/types/ObjectType.ts";
16
16
  import type { SerializedReferenceIdentifierType } from "../../shared/schema/types/ReferenceIdentifierType.ts";
17
17
  import type { SerializedStringType } from "../../shared/schema/types/StringType.ts";
18
+ import type { SerializedTranslationObjectType } from "../../shared/schema/types/TranslationObjectType.ts";
18
19
  import type { SerializedTypeArgumentType } from "../../shared/schema/types/TypeArgumentType.ts";
19
20
  import type { InstancesByEntityName } from "../../shared/utils/instances.ts";
20
21
  import { type Decl, type IncludableDeclP } from "./declarations/Declaration.ts";
@@ -25,6 +26,7 @@ import { type TypeParameter } from "./TypeParameter.ts";
25
26
  import { type ArrayType } from "./types/generic/ArrayType.ts";
26
27
  import { type EnumCaseDecl, type EnumType } from "./types/generic/EnumType.ts";
27
28
  import { type MemberDecl, type ObjectType } from "./types/generic/ObjectType.ts";
29
+ import { type TranslationObjectType } from "./types/generic/TranslationObjectType.ts";
28
30
  import { type BooleanType } from "./types/primitives/BooleanType.ts";
29
31
  import { type DateType } from "./types/primitives/DateType.ts";
30
32
  import { type FloatType } from "./types/primitives/FloatType.ts";
@@ -68,7 +70,7 @@ export type Validator<T extends Node = Node> = (helpers: Validators, inDecls: De
68
70
  export type ValidatorOfParamDecl<T extends Node = Node> = (helpers: Validators, inDecls: Decl[], node: T, typeArgs: Type[], value: unknown) => Error[];
69
71
  export declare const validateDecl: ValidatorOfParamDecl<Decl>;
70
72
  export declare const validateType: Validator<Type>;
71
- export type NodeWithResolvedTypeArguments<T extends Node | null> = T extends BooleanType | DateType | FloatType | IntegerType | StringType | ReferenceIdentifierType ? T : T extends EntityDecl<infer N, infer P, infer FK> ? EntityDecl<N, {
73
+ export type NodeWithResolvedTypeArguments<T extends Node | null> = T extends BooleanType | DateType | FloatType | IntegerType | StringType | ReferenceIdentifierType | ChildEntitiesType | TranslationObjectType ? T : T extends EntityDecl<infer N, infer P, infer FK> ? EntityDecl<N, {
72
74
  [K in keyof P]: P[K] extends MemberDecl<infer PT, infer R> ? MemberDecl<NodeWithResolvedTypeArguments<PT>, R> : never;
73
75
  }, FK> : T extends EnumDecl<infer N, infer V, TypeParameter[]> ? EnumDecl<N, {
74
76
  [K in keyof V]: V[K] extends EnumCaseDecl<infer CT> ? EnumCaseDecl<NodeWithResolvedTypeArguments<CT>> : never;
@@ -79,7 +81,7 @@ export type NodeWithResolvedTypeArguments<T extends Node | null> = T extends Boo
79
81
  [K in keyof P]: P[K] extends MemberDecl<infer PT, infer R> ? MemberDecl<NodeWithResolvedTypeArguments<PT>, R> : never;
80
82
  }> : T extends TypeArgumentType ? Type : T extends IncludeIdentifierType<[], IncludableDeclP<[]>> ? T : T extends IncludeIdentifierType ? Type : T extends NestedEntityMapType<infer N, infer P> ? NestedEntityMapType<N, {
81
83
  [K in keyof P]: P[K] extends MemberDecl<infer PT, infer R> ? MemberDecl<NodeWithResolvedTypeArguments<PT>, R> : never;
82
- }> : T extends TypeParameter<infer N, infer C> ? TypeParameter<N, NodeWithResolvedTypeArguments<C>> : T extends ChildEntitiesType<infer E> ? ChildEntitiesType<E> : T extends null ? null : never;
84
+ }> : T extends TypeParameter<infer N, infer C> ? TypeParameter<N, NodeWithResolvedTypeArguments<C>> : T extends null ? null : never;
83
85
  export type TypeArgumentsResolver<T extends Node = Node> = (args: Record<string, Type>, node: T, inDecl: Decl[]) => NodeWithResolvedTypeArguments<T>;
84
86
  export declare const resolveTypeArguments: <T extends Node = Node>(args: Record<string, Type>, node: T, inDecl: Decl[]) => NodeWithResolvedTypeArguments<T>;
85
87
  export type SerializedNodeMap = {
@@ -100,6 +102,7 @@ export type SerializedNodeMap = {
100
102
  [NodeKind.EnumType]: [EnumType, SerializedEnumType];
101
103
  [NodeKind.TypeParameter]: [TypeParameter, SerializedTypeParameter];
102
104
  [NodeKind.ChildEntitiesType]: [ChildEntitiesType, SerializedChildEntitiesType];
105
+ [NodeKind.TranslationObjectType]: [TranslationObjectType, SerializedTranslationObjectType];
103
106
  };
104
107
  export type SerializedTypeParameters<T extends TypeParameter[]> = {
105
108
  [K in keyof T]: T[K] extends TypeParameter<infer N, infer C> ? SerializedTypeParameter<N, C extends Type ? Serialized<C> : undefined> : never;
@@ -110,7 +113,7 @@ export type SerializedMemberDeclObject<T extends Record<string, MemberDecl>> = {
110
113
  export type SerializedEnumCaseDeclObject<T extends Record<string, EnumCaseDecl>> = {
111
114
  [K in keyof T]: T[K] extends EnumCaseDecl<infer CT> ? SerializedEnumCaseDecl<CT extends Type ? Serialized<CT> : null> : never;
112
115
  };
113
- export type Serialized<T extends Node> = T extends EntityDecl<infer Name, infer T, infer FK> ? SerializedEntityDecl<Name, SerializedMemberDeclObject<T>, FK> : T extends EnumDecl<infer Name, infer T, infer Params> ? SerializedEnumDecl<Name, SerializedEnumCaseDeclObject<T>, SerializedTypeParameters<Params>> : T extends TypeAliasDecl<infer Name, infer T, infer Params> ? SerializedTypeAliasDecl<Name, Serialized<T>, SerializedTypeParameters<Params>> : T extends ArrayType<infer T> ? SerializedArrayType<Serialized<T>> : T extends ObjectType<infer T> ? SerializedObjectType<SerializedMemberDeclObject<T>> : T extends BooleanType ? SerializedBooleanType : T extends DateType ? SerializedDateType : T extends FloatType ? SerializedFloatType : T extends IntegerType ? SerializedIntegerType : T extends StringType ? SerializedStringType : T extends TypeArgumentType<infer T> ? SerializedTypeArgumentType<Serialized<T>> : T extends ReferenceIdentifierType ? SerializedReferenceIdentifierType : T extends IncludeIdentifierType<infer Params> ? SerializedIncludeIdentifierType<SerializedTypeParameters<Params>> : T extends NestedEntityMapType<infer Name, infer T> ? SerializedNestedEntityMapType<Name, SerializedMemberDeclObject<T>> : T extends EnumType<infer T> ? SerializedEnumType<SerializedEnumCaseDeclObject<T>> : T extends TypeParameter<infer N, infer C> ? SerializedTypeParameter<N, C extends Type ? Serialized<C> : undefined> : T extends ChildEntitiesType ? SerializedChildEntitiesType : never;
116
+ export type Serialized<T extends Node> = T extends EntityDecl<infer Name, infer T, infer FK> ? SerializedEntityDecl<Name, SerializedMemberDeclObject<T>, FK> : T extends EnumDecl<infer Name, infer T, infer Params> ? SerializedEnumDecl<Name, SerializedEnumCaseDeclObject<T>, SerializedTypeParameters<Params>> : T extends TypeAliasDecl<infer Name, infer T, infer Params> ? SerializedTypeAliasDecl<Name, Serialized<T>, SerializedTypeParameters<Params>> : T extends ArrayType<infer T> ? SerializedArrayType<Serialized<T>> : T extends ObjectType<infer T> ? SerializedObjectType<SerializedMemberDeclObject<T>> : T extends BooleanType ? SerializedBooleanType : T extends DateType ? SerializedDateType : T extends FloatType ? SerializedFloatType : T extends IntegerType ? SerializedIntegerType : T extends StringType ? SerializedStringType : T extends TypeArgumentType<infer T> ? SerializedTypeArgumentType<Serialized<T>> : T extends ReferenceIdentifierType ? SerializedReferenceIdentifierType : T extends IncludeIdentifierType<infer Params> ? SerializedIncludeIdentifierType<SerializedTypeParameters<Params>> : T extends NestedEntityMapType<infer Name, infer T> ? SerializedNestedEntityMapType<Name, SerializedMemberDeclObject<T>> : T extends EnumType<infer T> ? SerializedEnumType<SerializedEnumCaseDeclObject<T>> : T extends TypeParameter<infer N, infer C> ? SerializedTypeParameter<N, C extends Type ? Serialized<C> : undefined> : T extends ChildEntitiesType ? SerializedChildEntitiesType : T extends TranslationObjectType<infer E> ? SerializedTranslationObjectType<E> : never;
114
117
  export type SerializedOf<T extends Node> = SerializedNodeMap[T["kind"]][1];
115
118
  export type Serializer<T extends Node = Node> = (node: T) => Serialized<T>;
116
119
  export declare const serializeNode: <T extends Node>(node: T) => Serialized<T>;
@@ -9,6 +9,7 @@ import { getNestedDeclarationsInTypeParameter, getReferencesForTypeParameter, re
9
9
  import { getNestedDeclarationsInArrayType, getReferencesForArrayType, resolveTypeArgumentsInArrayType, serializeArrayType, validateArrayType, } from "./types/generic/ArrayType.js";
10
10
  import { getNestedDeclarationsInEnumType, getReferencesForEnumType, resolveTypeArgumentsInEnumType, serializeEnumType, validateEnumType, } from "./types/generic/EnumType.js";
11
11
  import { getNestedDeclarationsInObjectType, getReferencesForObjectType, resolveTypeArgumentsInObjectType, serializeObjectType, validateObjectType, } from "./types/generic/ObjectType.js";
12
+ import { getNestedDeclarationsInTranslationObjectType, getReferencesForTranslationObjectType, resolveTypeArgumentsInTranslationObjectType, serializeTranslationObjectType, validateTranslationObjectType, } from "./types/generic/TranslationObjectType.js";
12
13
  import { getNestedDeclarationsInBooleanType, getReferencesForBooleanType, resolveTypeArgumentsInBooleanType, serializeBooleanType, validateBooleanType, } from "./types/primitives/BooleanType.js";
13
14
  import { getNestedDeclarationsInDateType, getReferencesForDateType, resolveTypeArgumentsInDateType, serializeDateType, validateDateType, } from "./types/primitives/DateType.js";
14
15
  import { getNestedDeclarationsInFloatType, getReferencesForFloatType, resolveTypeArgumentsInFloatType, serializeFloatType, validateFloatType, } from "./types/primitives/FloatType.js";
@@ -59,6 +60,7 @@ export const reduceNodes = (reducer, nodes, options = {}) => {
59
60
  case NodeKind.ReferenceIdentifierType:
60
61
  case NodeKind.NestedEntityMapType:
61
62
  case NodeKind.TypeParameter:
63
+ case NodeKind.TranslationObjectType:
62
64
  return { results: reducer(parentNodes, node, collectedResults), reducedDecls };
63
65
  default:
64
66
  return assertExhaustive(node);
@@ -143,6 +145,8 @@ export const getNestedDeclarations = (addedDecls, node, parentDecl) => {
143
145
  return getNestedDeclarationsInTypeParameter(addedDecls, node, parentDecl);
144
146
  case NodeKind.ChildEntitiesType:
145
147
  return getNestedDeclarationsInChildEntitiesType(addedDecls, node, parentDecl);
148
+ case NodeKind.TranslationObjectType:
149
+ return getNestedDeclarationsInTranslationObjectType(addedDecls, node, parentDecl);
146
150
  default:
147
151
  return assertExhaustive(node);
148
152
  }
@@ -187,6 +191,8 @@ export const validateType = (helpers, inDecls, type, value) => {
187
191
  return validateEnumType(helpers, inDecls, type, value);
188
192
  case NodeKind.ChildEntitiesType:
189
193
  return validateChildEntitiesType(helpers, inDecls, type, value);
194
+ case NodeKind.TranslationObjectType:
195
+ return validateTranslationObjectType(helpers, inDecls, type, value);
190
196
  default:
191
197
  return assertExhaustive(type);
192
198
  }
@@ -227,6 +233,8 @@ export const resolveTypeArguments = (args, node, inDecl) => {
227
233
  return resolveTypeArgumentsInTypeParameter(args, node, inDecl);
228
234
  case NodeKind.ChildEntitiesType:
229
235
  return resolveTypeArgumentsInChildEntitiesType(args, node, inDecl);
236
+ case NodeKind.TranslationObjectType:
237
+ return resolveTypeArgumentsInTranslationObjectType(args, node, inDecl);
230
238
  default:
231
239
  return assertExhaustive(node);
232
240
  }
@@ -267,6 +275,8 @@ export const serializeNode = (node) => {
267
275
  return serializeTypeParameter(node);
268
276
  case NodeKind.ChildEntitiesType:
269
277
  return serializeChildEntitiesType(node);
278
+ case NodeKind.TranslationObjectType:
279
+ return serializeTranslationObjectType(node);
270
280
  default:
271
281
  return assertExhaustive(node);
272
282
  }
@@ -307,6 +317,8 @@ export const getReferences = (node, value, inDecl) => {
307
317
  return getReferencesForTypeParameter(node, value, inDecl);
308
318
  case NodeKind.ChildEntitiesType:
309
319
  return getReferencesForChildEntitiesType(node, value, inDecl);
320
+ case NodeKind.TranslationObjectType:
321
+ return getReferencesForTranslationObjectType(node, value, inDecl);
310
322
  default:
311
323
  return assertExhaustive(node);
312
324
  }
@@ -172,6 +172,7 @@ const isDeclarationRecursive = (declToCheck) => {
172
172
  case NodeKind.ReferenceIdentifierType:
173
173
  case NodeKind.TypeParameter:
174
174
  case NodeKind.ChildEntitiesType:
175
+ case NodeKind.TranslationObjectType:
175
176
  return false;
176
177
  case NodeKind.ArrayType:
177
178
  return isDeclarationIncludedInNode(visitedDecls, node.items);
@@ -7,6 +7,7 @@ export * from "./TypeParameter.ts";
7
7
  export * from "./types/generic/ArrayType.ts";
8
8
  export * from "./types/generic/EnumType.ts";
9
9
  export * from "./types/generic/ObjectType.ts";
10
+ export * from "./types/generic/TranslationObjectType.ts";
10
11
  export * from "./types/primitives/BooleanType.ts";
11
12
  export * from "./types/primitives/DateType.ts";
12
13
  export * from "./types/primitives/FloatType.ts";
@@ -7,6 +7,7 @@ export * from "./TypeParameter.js";
7
7
  export * from "./types/generic/ArrayType.js";
8
8
  export * from "./types/generic/EnumType.js";
9
9
  export * from "./types/generic/ObjectType.js";
10
+ export * from "./types/generic/TranslationObjectType.js";
10
11
  export * from "./types/primitives/BooleanType.js";
11
12
  export * from "./types/primitives/DateType.js";
12
13
  export * from "./types/primitives/FloatType.js";
@@ -3,6 +3,7 @@ import type { BaseNode } from "../Node.ts";
3
3
  import type { ArrayType } from "./generic/ArrayType.ts";
4
4
  import type { EnumCaseDecl, EnumType } from "./generic/EnumType.ts";
5
5
  import type { MemberDecl, ObjectType } from "./generic/ObjectType.ts";
6
+ import { type TranslationObjectType } from "./generic/TranslationObjectType.ts";
6
7
  import type { BooleanType } from "./primitives/BooleanType.ts";
7
8
  import type { DateType } from "./primitives/DateType.ts";
8
9
  import type { FloatType } from "./primitives/FloatType.ts";
@@ -15,7 +16,7 @@ import type { ReferenceIdentifierType } from "./references/ReferenceIdentifierTy
15
16
  import type { TypeArgumentType } from "./references/TypeArgumentType.ts";
16
17
  export interface BaseType extends BaseNode {
17
18
  }
18
- export type Type = BooleanType | DateType | FloatType | IntegerType | StringType | ArrayType | ObjectType | TypeArgumentType | ReferenceIdentifierType | IncludeIdentifierType | NestedEntityMapType | EnumType | ChildEntitiesType;
19
+ export type Type = BooleanType | DateType | FloatType | IntegerType | StringType | ArrayType | ObjectType | TypeArgumentType | ReferenceIdentifierType | IncludeIdentifierType | NestedEntityMapType | EnumType | ChildEntitiesType | TranslationObjectType;
19
20
  export declare function walkTypeNodeTree(callbackFn: (type: Type, parentTypes: Type[], parentDecl: Decl) => void, type: Type, parentTypes: Type[], parentDecl: Decl): void;
20
21
  type EnumCaseTypeAsType<Case extends string, T extends Type | null> = T extends object ? {
21
22
  kind: Case;
@@ -4,6 +4,7 @@ import { NodeKind } from "../Node.js";
4
4
  import { formatArrayValue, isArrayType } from "./generic/ArrayType.js";
5
5
  import { formatEnumType } from "./generic/EnumType.js";
6
6
  import { formatObjectValue, isObjectType } from "./generic/ObjectType.js";
7
+ import { formatTranslationObjectValue, } from "./generic/TranslationObjectType.js";
7
8
  import { formatBooleanValue } from "./primitives/BooleanType.js";
8
9
  import { formatDateValue } from "./primitives/DateType.js";
9
10
  import { formatFloatValue } from "./primitives/FloatType.js";
@@ -40,7 +41,8 @@ export function walkTypeNodeTree(callbackFn, type, parentTypes, parentDecl) {
40
41
  case NodeKind.StringType:
41
42
  case NodeKind.TypeArgumentType:
42
43
  case NodeKind.ReferenceIdentifierType:
43
- case NodeKind.ChildEntitiesType: {
44
+ case NodeKind.ChildEntitiesType:
45
+ case NodeKind.TranslationObjectType: {
44
46
  callbackFn(type, parentTypes, parentDecl);
45
47
  return;
46
48
  }
@@ -113,6 +115,8 @@ export const formatValue = (type, value) => {
113
115
  return formatEnumType(type, value);
114
116
  case NodeKind.ChildEntitiesType:
115
117
  return formatChildEntitiesValue(type, value);
118
+ case NodeKind.TranslationObjectType:
119
+ return formatTranslationObjectValue(type, value);
116
120
  default:
117
121
  return assertExhaustive(type);
118
122
  }
@@ -0,0 +1,25 @@
1
+ import type { GetNestedDeclarations, GetReferences, Predicate, Serialized, TypeArgumentsResolver, Validator } from "../../Node.ts";
2
+ import { NodeKind } from "../../Node.ts";
3
+ import type { StringType } from "../primitives/StringType.ts";
4
+ import type { BaseType, StructureFormatter } from "../Type.ts";
5
+ type TConstraint = {
6
+ [key: string]: null | TConstraint;
7
+ };
8
+ export type { TConstraint as TranslationObjectTypeConstraint };
9
+ export interface TranslationObjectType<T extends TConstraint = TConstraint> extends BaseType {
10
+ kind: NodeKind["TranslationObjectType"];
11
+ properties: T;
12
+ allKeysAreRequired: boolean;
13
+ }
14
+ export declare const TranslationObjectType: <T extends TConstraint>(properties: T, options?: {
15
+ allKeysAreRequired?: boolean;
16
+ }) => TranslationObjectType<T>;
17
+ export { TranslationObjectType as TranslationObject };
18
+ export declare const isTranslationObjectType: Predicate<TranslationObjectType>;
19
+ export declare const getNestedDeclarationsInTranslationObjectType: GetNestedDeclarations<TranslationObjectType>;
20
+ export declare const validateTranslationObjectType: Validator<TranslationObjectType>;
21
+ export declare const resolveTypeArgumentsInTranslationObjectType: TypeArgumentsResolver<TranslationObjectType>;
22
+ export declare const serializeTranslationObjectType: <P extends TConstraint>(type: TranslationObjectType<P>) => Serialized<TranslationObjectType<P>>;
23
+ export declare const getReferencesForTranslationObjectType: GetReferences<TranslationObjectType>;
24
+ export declare const formatTranslationObjectValue: StructureFormatter<TranslationObjectType>;
25
+ export declare const getTypeOfKey: <T extends TConstraint>(keyValue: null | T, parentType?: TranslationObjectType) => StringType | TranslationObjectType<T>;
@@ -0,0 +1,66 @@
1
+ import { sortObjectKeys } from "../../../../shared/utils/object.js";
2
+ import { parallelizeErrors } from "../../../../shared/utils/validation.js";
3
+ import { validateUnknownKeys } from "../../../../shared/validation/object.js";
4
+ import { wrapErrorsIfAny } from "../../../utils/error.js";
5
+ import { json, key as keyColor } from "../../../utils/errorFormatting.js";
6
+ import { NodeKind } from "../../Node.js";
7
+ export const TranslationObjectType = (properties, options = {}) => {
8
+ const type = {
9
+ allKeysAreRequired: false,
10
+ ...options,
11
+ kind: NodeKind.TranslationObjectType,
12
+ properties,
13
+ };
14
+ return type;
15
+ };
16
+ export { TranslationObjectType as TranslationObject };
17
+ export const isTranslationObjectType = node => node.kind === NodeKind.TranslationObjectType;
18
+ export const getNestedDeclarationsInTranslationObjectType = addedDecls => addedDecls;
19
+ const validateRecursively = (helpers, allKeysAreRequired, type, value) => {
20
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
21
+ return [TypeError(`expected an object, but got ${json(value, helpers.useStyling)}`)];
22
+ }
23
+ const expectedKeys = Object.keys(type).filter(key => type[key] !== undefined);
24
+ return parallelizeErrors([
25
+ ...validateUnknownKeys(expectedKeys, Object.keys(value)),
26
+ ...expectedKeys.map(key => {
27
+ const propType = type[key];
28
+ const propValue = value[key];
29
+ if (allKeysAreRequired && propValue === undefined) {
30
+ return TypeError(`missing required translation ${keyColor(`"${key}"`, helpers.useStyling)}`);
31
+ }
32
+ if (propType === null && propValue !== undefined && typeof propValue !== "string") {
33
+ return TypeError(`expected a string at translation key ${keyColor(`"${key}"`, helpers.useStyling)}, but got ${json(propValue, helpers.useStyling)}`);
34
+ }
35
+ if (propType === null &&
36
+ typeof propValue === "string" &&
37
+ allKeysAreRequired &&
38
+ propValue.length === 0) {
39
+ return TypeError(`expected a non-empty string at translation key ${keyColor(`"${key}"`, helpers.useStyling)}`);
40
+ }
41
+ if (propType !== null && propValue !== undefined) {
42
+ return wrapErrorsIfAny(`at translation object key ${keyColor(`"${key}"`, helpers.useStyling)}`, validateRecursively(helpers, allKeysAreRequired, propType, propValue));
43
+ }
44
+ return undefined;
45
+ }),
46
+ ]);
47
+ };
48
+ export const validateTranslationObjectType = (helpers, _inDecls, type, value) => validateRecursively(helpers, type.allKeysAreRequired, type.properties, value);
49
+ export const resolveTypeArgumentsInTranslationObjectType = (_args, type, _inDecl) => type;
50
+ export const serializeTranslationObjectType = (type) => type;
51
+ export const getReferencesForTranslationObjectType = () => [];
52
+ const formatRecursively = (type, value) => typeof value === "object" && value !== null && !Array.isArray(value)
53
+ ? sortObjectKeys(Object.fromEntries(Object.entries(value).map(([key, item]) => [
54
+ key,
55
+ type[key] ? formatRecursively(type[key], item) : item,
56
+ ])), Object.keys(type))
57
+ : value;
58
+ export const formatTranslationObjectValue = (type, value) => formatRecursively(type.properties, value);
59
+ export const getTypeOfKey = (keyValue, parentType) => keyValue === null
60
+ ? { kind: "StringType" }
61
+ : {
62
+ kind: "TranslationObjectType",
63
+ allKeysAreRequired: false,
64
+ ...parentType,
65
+ properties: keyValue,
66
+ };
@@ -1,6 +1,6 @@
1
1
  import { styleText } from "node:util";
2
2
  export const json = (value, useStyling) => useStyling
3
- ? styleText("blue", JSON.stringify(value, undefined, 2))
3
+ ? styleText("blue", value === undefined ? "undefined" : JSON.stringify(value, undefined, 2))
4
4
  : JSON.stringify(value, undefined, 2);
5
5
  export const key = (str, useStyling) => useStyling ? styleText(["yellow", "bold"], str) : str;
6
6
  export const entity = (str, useStyling) => useStyling ? styleText("green", str) : str;
@@ -15,6 +15,7 @@ import { type SerializedNestedEntityMapType } from "./types/NestedEntityMapType.
15
15
  import { type SerializedMemberDecl, type SerializedObjectType } from "./types/ObjectType.ts";
16
16
  import { type SerializedReferenceIdentifierType } from "./types/ReferenceIdentifierType.ts";
17
17
  import { type SerializedStringType } from "./types/StringType.ts";
18
+ import { type SerializedTranslationObjectType } from "./types/TranslationObjectType.ts";
18
19
  import type { SerializedType } from "./types/Type.ts";
19
20
  import { type SerializedTypeArgumentType } from "./types/TypeArgumentType.ts";
20
21
  export interface NodeKind {
@@ -38,13 +39,14 @@ export interface NodeKind {
38
39
  NestedEntityMapType: "NestedEntityMapType";
39
40
  EnumType: "EnumType";
40
41
  ChildEntitiesType: "ChildEntitiesType";
42
+ TranslationObjectType: "TranslationObjectType";
41
43
  }
42
44
  export declare const NodeKind: NodeKind;
43
45
  export interface BaseNode {
44
46
  kind: (typeof NodeKind)[keyof typeof NodeKind];
45
47
  }
46
48
  export type SerializedNode = SerializedDecl | SerializedType | SerializedTypeParameter;
47
- export type SerializedNodeWithResolvedTypeArguments<T extends SerializedNode | null> = T extends SerializedBooleanType | SerializedDateType | SerializedFloatType | SerializedIntegerType | SerializedStringType | SerializedReferenceIdentifierType ? T : T extends SerializedEntityDecl<infer N, infer P, infer FK> ? SerializedEntityDecl<N, {
49
+ export type SerializedNodeWithResolvedTypeArguments<T extends SerializedNode | null> = T extends SerializedBooleanType | SerializedDateType | SerializedFloatType | SerializedIntegerType | SerializedStringType | SerializedReferenceIdentifierType | SerializedChildEntitiesType | SerializedTranslationObjectType ? T : T extends SerializedEntityDecl<infer N, infer P, infer FK> ? SerializedEntityDecl<N, {
48
50
  [K in keyof P]: P[K] extends SerializedMemberDecl<infer PT, infer R> ? SerializedMemberDecl<SerializedNodeWithResolvedTypeArguments<PT>, R> : never;
49
51
  }, FK> : T extends SerializedEnumDecl<infer N, infer V, SerializedTypeParameter[]> ? SerializedEnumDecl<N, {
50
52
  [K in keyof V]: V[K] extends SerializedEnumCaseDecl<infer CT> ? SerializedEnumCaseDecl<SerializedNodeWithResolvedTypeArguments<CT>> : never;
@@ -55,7 +57,7 @@ export type SerializedNodeWithResolvedTypeArguments<T extends SerializedNode | n
55
57
  [K in keyof P]: P[K] extends SerializedMemberDecl<infer PT, infer R> ? SerializedMemberDecl<SerializedNodeWithResolvedTypeArguments<PT>, R> : never;
56
58
  }> : T extends SerializedTypeArgumentType ? SerializedType : T extends SerializedIncludeIdentifierType<[]> ? T : T extends SerializedIncludeIdentifierType ? SerializedType : T extends SerializedNestedEntityMapType<infer N, infer P> ? SerializedNestedEntityMapType<N, {
57
59
  [K in keyof P]: P[K] extends SerializedMemberDecl<infer PT, infer R> ? SerializedMemberDecl<SerializedNodeWithResolvedTypeArguments<PT>, R> : never;
58
- }> : T extends SerializedTypeParameter<infer N, infer C> ? SerializedTypeParameter<N, SerializedNodeWithResolvedTypeArguments<C>> : T extends SerializedChildEntitiesType ? SerializedChildEntitiesType : T extends null ? null : never;
60
+ }> : T extends SerializedTypeParameter<infer N, infer C> ? SerializedTypeParameter<N, SerializedNodeWithResolvedTypeArguments<C>> : T extends null ? null : never;
59
61
  export type SerializedTypeArgumentsResolver<T extends SerializedNode = SerializedNode> = (decls: Record<string, SerializedDecl>, args: Record<string, SerializedType>, node: T) => SerializedNodeWithResolvedTypeArguments<T>;
60
62
  export declare const resolveSerializedTypeArguments: <T extends SerializedNode = SerializedNode>(decls: Record<string, SerializedDecl>, args: Record<string, SerializedType>, node: T) => SerializedNodeWithResolvedTypeArguments<T>;
61
63
  export type GetReferencesSerialized<T extends SerializedNode = SerializedNode> = (decls: Record<string, SerializedDecl>, node: T, value: unknown) => string[];
@@ -16,6 +16,7 @@ import { getReferencesForSerializedNestedEntityMapType, resolveTypeArgumentsInSe
16
16
  import { getReferencesForSerializedObjectType, resolveTypeArgumentsInSerializedObjectType, } from "./types/ObjectType.js";
17
17
  import { getReferencesForSerializedReferenceIdentifierType, resolveTypeArgumentsInSerializedReferenceIdentifierType, } from "./types/ReferenceIdentifierType.js";
18
18
  import { getReferencesForSerializedStringType, resolveTypeArgumentsInSerializedStringType, } from "./types/StringType.js";
19
+ import { getReferencesForSerializedTranslationObjectType, resolveTypeArgumentsInSerializedTranslationObjectType, } from "./types/TranslationObjectType.js";
19
20
  import { getReferencesForSerializedTypeArgumentType, resolveTypeArgumentsInSerializedTypeArgumentType, } from "./types/TypeArgumentType.js";
20
21
  export const NodeKind = enumOfObject({
21
22
  ChildEntityDecl: null,
@@ -38,6 +39,7 @@ export const NodeKind = enumOfObject({
38
39
  NestedEntityMapType: null,
39
40
  EnumType: null,
40
41
  ChildEntitiesType: null,
42
+ TranslationObjectType: null,
41
43
  });
42
44
  export const resolveSerializedTypeArguments = (decls, args, node) => {
43
45
  switch (node.kind) {
@@ -75,6 +77,8 @@ export const resolveSerializedTypeArguments = (decls, args, node) => {
75
77
  return resolveTypeArgumentsInSerializedTypeParameter(decls, args, node);
76
78
  case NodeKind.ChildEntitiesType:
77
79
  return resolveTypeArgumentsInSerializedChildEntitiesType(decls, args, node);
80
+ case NodeKind.TranslationObjectType:
81
+ return resolveTypeArgumentsInSerializedTranslationObjectType(decls, args, node);
78
82
  default:
79
83
  return assertExhaustive(node);
80
84
  }
@@ -115,6 +119,8 @@ export const getReferencesSerialized = (decls, node, value) => {
115
119
  return getReferencesForSerializedTypeParameter(decls, node, value);
116
120
  case NodeKind.ChildEntitiesType:
117
121
  return getReferencesForSerializedChildEntitiesType(decls, node, value);
122
+ case NodeKind.TranslationObjectType:
123
+ return getReferencesForSerializedTranslationObjectType(decls, node, value);
118
124
  default:
119
125
  return assertExhaustive(node);
120
126
  }
@@ -0,0 +1,16 @@
1
+ import { NodeKind, type GetReferencesSerialized, type SerializedNode, type SerializedTypeArgumentsResolver } from "../Node.js";
2
+ import type { SerializedStringType } from "./StringType.ts";
3
+ import type { SerializedBaseType } from "./Type.ts";
4
+ type TSerializedConstraint = {
5
+ [key: string]: null | TSerializedConstraint;
6
+ };
7
+ export interface SerializedTranslationObjectType<T extends TSerializedConstraint = TSerializedConstraint> extends SerializedBaseType {
8
+ kind: NodeKind["TranslationObjectType"];
9
+ properties: T;
10
+ allKeysAreRequired: boolean;
11
+ }
12
+ export declare const isSerializedTranslationObjectType: (node: SerializedNode) => node is SerializedTranslationObjectType;
13
+ export declare const resolveTypeArgumentsInSerializedTranslationObjectType: SerializedTypeArgumentsResolver<SerializedTranslationObjectType>;
14
+ export declare const getReferencesForSerializedTranslationObjectType: GetReferencesSerialized<SerializedTranslationObjectType>;
15
+ export declare const getSerializedTypeOfKey: <T extends TSerializedConstraint>(keyValue: null | T, parentType?: SerializedTranslationObjectType) => SerializedStringType | SerializedTranslationObjectType<T>;
16
+ export {};
@@ -0,0 +1,12 @@
1
+ import { NodeKind, } from "../Node.js";
2
+ export const isSerializedTranslationObjectType = (node) => node.kind === NodeKind.TranslationObjectType;
3
+ export const resolveTypeArgumentsInSerializedTranslationObjectType = (_decls, _args, type) => type;
4
+ export const getReferencesForSerializedTranslationObjectType = () => [];
5
+ export const getSerializedTypeOfKey = (keyValue, parentType) => keyValue === null
6
+ ? { kind: "StringType" }
7
+ : {
8
+ kind: "TranslationObjectType",
9
+ allKeysAreRequired: false,
10
+ ...parentType,
11
+ properties: keyValue,
12
+ };
@@ -11,10 +11,11 @@ import type { SerializedNestedEntityMapType } from "./NestedEntityMapType.ts";
11
11
  import type { SerializedMemberDecl, SerializedObjectType } from "./ObjectType.ts";
12
12
  import type { SerializedReferenceIdentifierType } from "./ReferenceIdentifierType.ts";
13
13
  import type { SerializedStringType } from "./StringType.ts";
14
+ import type { SerializedTranslationObjectType } from "./TranslationObjectType.ts";
14
15
  import type { SerializedTypeArgumentType } from "./TypeArgumentType.ts";
15
16
  export interface SerializedBaseType extends BaseNode {
16
17
  }
17
- export type SerializedType = SerializedBooleanType | SerializedDateType | SerializedFloatType | SerializedIntegerType | SerializedStringType | SerializedArrayType | SerializedObjectType | SerializedTypeArgumentType | SerializedReferenceIdentifierType | SerializedIncludeIdentifierType | SerializedNestedEntityMapType | SerializedEnumType | SerializedChildEntitiesType;
18
+ export type SerializedType = SerializedBooleanType | SerializedDateType | SerializedFloatType | SerializedIntegerType | SerializedStringType | SerializedArrayType | SerializedObjectType | SerializedTypeArgumentType | SerializedReferenceIdentifierType | SerializedIncludeIdentifierType | SerializedNestedEntityMapType | SerializedEnumType | SerializedChildEntitiesType | SerializedTranslationObjectType;
18
19
  export type SerializedAsType<T extends SerializedType> = T extends SerializedArrayType<infer I> ? SerializedAsType<I>[] : T extends SerializedObjectType<infer P> ? {
19
20
  [K in keyof P]: P[K] extends SerializedMemberDecl<SerializedType, true> ? SerializedAsType<P[K]["type"]> : SerializedAsType<P[K]["type"]> | undefined;
20
- } : T extends SerializedBooleanType ? boolean : T extends SerializedDateType ? Date : T extends SerializedFloatType ? number : T extends SerializedIntegerType ? number : T extends SerializedStringType ? string : T extends SerializedTypeArgumentType ? unknown : T extends SerializedIncludeIdentifierType ? unknown : T extends SerializedNestedEntityMapType ? unknown : T extends SerializedReferenceIdentifierType ? unknown : T extends SerializedChildEntitiesType ? unknown : never;
21
+ } : T extends SerializedBooleanType ? boolean : T extends SerializedDateType ? Date : T extends SerializedFloatType ? number : T extends SerializedIntegerType ? number : T extends SerializedStringType ? string : T extends SerializedTypeArgumentType ? unknown : T extends SerializedIncludeIdentifierType ? unknown : T extends SerializedNestedEntityMapType ? unknown : T extends SerializedReferenceIdentifierType ? unknown : T extends SerializedChildEntitiesType ? unknown : T extends SerializedTranslationObjectType ? unknown : never;
@@ -4,3 +4,4 @@ export interface ObjectConstraints {
4
4
  maxProperties?: number;
5
5
  }
6
6
  export declare const validateObjectConstraints: (constraints: ObjectConstraints, expectedKeys: string[], value: object) => Error[];
7
+ export declare const validateUnknownKeys: (expectedKeys: string[], actualKeys: string[]) => TypeError[];
@@ -6,9 +6,10 @@ export const validateObjectConstraints = (constraints, expectedKeys, value) => {
6
6
  validateLengthRangeBound("lower", label, constraints.minProperties, actualKeys),
7
7
  validateLengthRangeBound("upper", label, constraints.maxProperties, actualKeys),
8
8
  ...(constraints.additionalProperties !== true
9
- ? actualKeys.flatMap(valueKey => expectedKeys.includes(valueKey)
10
- ? []
11
- : [TypeError(`object does not allow unknown keys and key "${valueKey}" is not known`)])
9
+ ? validateUnknownKeys(expectedKeys, actualKeys)
12
10
  : []),
13
11
  ]);
14
12
  };
13
+ export const validateUnknownKeys = (expectedKeys, actualKeys) => actualKeys.flatMap(valueKey => expectedKeys.includes(valueKey)
14
+ ? []
15
+ : [TypeError(`object does not allow unknown keys and key "${valueKey}" is not known`)]);
@@ -4,13 +4,15 @@ import { Markdown } from "../../utils/Markdown.js";
4
4
  import { MarkdownHighlighting } from "../../utils/MarkdownHighlighting.js";
5
5
  import { MismatchingTypeError } from "./utils/MismatchingTypeError.js";
6
6
  import { ValidationErrors } from "./utils/ValidationErrors.js";
7
- export const StringTypeInput = ({ type, value, disabled, onChange }) => {
7
+ export const StringTypeInput = ({ type, value, disabled, onChange, inTranslationObject, }) => {
8
8
  if (typeof value !== "string") {
9
9
  return _jsx(MismatchingTypeError, { expected: "string", actual: value });
10
10
  }
11
11
  const { minLength, maxLength, pattern, isMarkdown } = type;
12
12
  const errors = validateStringConstraints(type, value);
13
- return (_jsx("div", { class: "field field--string", children: isMarkdown ? (_jsxs(_Fragment, { children: [_jsxs("div", { class: "editor editor--markdown", children: [_jsxs("div", { class: "textarea-grow-wrap", children: [_jsx("textarea", { value: value, minLength: minLength, maxLength: maxLength, onInput: event => {
13
+ return (_jsx("div", { class: "field field--string", children: inTranslationObject ? (_jsx(_Fragment, { children: _jsxs("div", { class: "editor editor--translation", children: [_jsxs("div", { class: "textarea-grow-wrap", children: [_jsx("textarea", { rows: 1, value: value, minLength: minLength, maxLength: maxLength, onInput: event => {
14
+ onChange(event.currentTarget.value);
15
+ }, "aria-invalid": errors.length > 0, disabled: disabled }), _jsx("div", { class: "textarea-grow-wrap__mirror", children: value + " " })] }), _jsx(ValidationErrors, { disabled: disabled, errors: errors })] }) })) : isMarkdown ? (_jsxs(_Fragment, { children: [_jsxs("div", { class: "editor editor--markdown", children: [_jsxs("div", { class: "textarea-grow-wrap", children: [_jsx("textarea", { rows: 1, value: value, minLength: minLength, maxLength: maxLength, onInput: event => {
14
16
  onChange(event.currentTarget.value);
15
17
  }, "aria-invalid": errors.length > 0, disabled: disabled }), _jsxs("p", { class: "help", children: ["This textarea supports", " ", _jsx("a", { href: "https://www.markdownguide.org/getting-started/", target: "_blank", rel: "noreferrer", children: "Markdown" }), "."] }), _jsx(MarkdownHighlighting, { class: "textarea-grow-wrap__mirror editor-highlighting", string: value + " " })] }), _jsx(ValidationErrors, { disabled: disabled, errors: errors })] }), _jsx("div", { class: "preview", children: _jsx(Markdown, { string: value, outerHeadingLevel: 2 }) })] })) : (_jsxs("div", { class: "editor", children: [_jsx("input", { type: "text", value: value, minLength: minLength, maxLength: maxLength, pattern: pattern === undefined
16
18
  ? undefined
@@ -0,0 +1,6 @@
1
+ import type { FunctionComponent } from "preact";
2
+ import { type SerializedTranslationObjectType } from "../../../shared/schema/types/TranslationObjectType.ts";
3
+ import { type TypeInputProps } from "./TypeInput.tsx";
4
+ type Props = TypeInputProps<SerializedTranslationObjectType, Record<string, unknown>>;
5
+ export declare const TranslationObjectTypeInput: FunctionComponent<Props>;
6
+ export {};
@@ -0,0 +1,39 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
+ import { getSerializedTypeOfKey, } from "../../../shared/schema/types/TranslationObjectType.js";
3
+ import { sortObjectKeys } from "../../../shared/utils/object.js";
4
+ import { validateUnknownKeys } from "../../../shared/validation/object.js";
5
+ import { createTypeSkeleton } from "../../utils/typeSkeleton.js";
6
+ import { TypeInput } from "./TypeInput.js";
7
+ import { MismatchingTypeError } from "./utils/MismatchingTypeError.js";
8
+ import { ValidationErrors } from "./utils/ValidationErrors.js";
9
+ export const TranslationObjectTypeInput = props => {
10
+ const { type, path, value, parentKey, disabled, getDeclFromDeclName, onChange } = props;
11
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
12
+ return _jsx(MismatchingTypeError, { expected: "object", actual: value });
13
+ }
14
+ const errors = validateUnknownKeys(Object.keys(type.properties), Object.keys(value));
15
+ return (_jsxs("div", { class: "field field--container field--object" + (disabled ? " field--disabled" : ""), children: [_jsx("ul", { children: Object.entries(type.properties)
16
+ .filter(([key]) => key !== parentKey)
17
+ .map(([key, memberDecl]) => {
18
+ const keyType = getSerializedTypeOfKey(memberDecl, type);
19
+ return (_jsxs("li", { class: "container-item object-item object-item--translation" +
20
+ (memberDecl === null ? "" : "object-item--translation-object"), children: [_jsx("div", { className: "container-item-title", children: key }), type.allKeysAreRequired ||
21
+ value[key] !== undefined ? (_jsx(TypeInput, { ...props, inTranslationObject: true, parentKey: undefined, type: keyType, path: path === undefined ? key : `${path}.${key}`, value: value[key] ??
22
+ (type.allKeysAreRequired
23
+ ? createTypeSkeleton(getDeclFromDeclName, keyType)
24
+ : undefined), onChange: newItem => {
25
+ onChange(sortObjectKeys({ ...value, [key]: newItem }, Object.keys(type.properties)));
26
+ } })) : null, type.allKeysAreRequired ? null : value[key] ===
27
+ undefined ? (_jsx("button", { onClick: () => {
28
+ onChange(sortObjectKeys({
29
+ ...value,
30
+ [key]: createTypeSkeleton(getDeclFromDeclName, keyType),
31
+ }, Object.keys(type.properties)));
32
+ }, disabled: disabled, children: "Add" })) : (_jsx("button", { class: "destructive", onClick: () => {
33
+ const newObj = { ...value };
34
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
35
+ delete newObj[key];
36
+ onChange(newObj);
37
+ }, disabled: disabled, children: "Remove" }))] }, key));
38
+ }) }), _jsx(ValidationErrors, { disabled: disabled, errors: errors })] }));
39
+ };
@@ -11,6 +11,7 @@ export type TypeInputProps<T, V = unknown> = {
11
11
  parentKey?: string;
12
12
  childInstances: UnsafeEntityTaggedInstanceContainerWithChildInstances[];
13
13
  disabled?: boolean;
14
+ inTranslationObject?: boolean;
14
15
  getDeclFromDeclName: GetDeclFromDeclName;
15
16
  onChange: (value: V) => void;
16
17
  setChildInstances: (newInstances: (oldInstances: UnsafeEntityTaggedInstanceContainerWithChildInstances[]) => UnsafeEntityTaggedInstanceContainerWithChildInstances[]) => void;
@@ -14,6 +14,7 @@ import { NestedEntityMapTypeInput } from "./NestedEntityMapTypeInput.js";
14
14
  import { ObjectTypeInput } from "./ObjectTypeInput.js";
15
15
  import { ReferenceIdentifierTypeInput } from "./ReferenceIdentifierTypeInput.js";
16
16
  import { StringTypeInput } from "./StringTypeInput.js";
17
+ import { TranslationObjectTypeInput } from "./TranslationObjectTypeInput.js";
17
18
  const TypeInput = props => {
18
19
  // console.log("rendering node at path ", props.path ?? "<root>")
19
20
  switch (props.type.kind) {
@@ -43,6 +44,8 @@ const TypeInput = props => {
43
44
  return _jsx(EnumTypeInput, { ...props, type: props.type });
44
45
  case "ChildEntitiesType":
45
46
  return _jsx(ChildEntitiesTypeInput, { ...props, type: props.type });
47
+ case "TranslationObjectType":
48
+ return _jsx(TranslationObjectTypeInput, { ...props, type: props.type });
46
49
  default:
47
50
  return assertExhaustive(props.type);
48
51
  }
@@ -44,6 +44,13 @@ export const createTypeSkeleton = (getDeclFromDeclName, type) => {
44
44
  }
45
45
  case "ChildEntitiesType":
46
46
  return undefined;
47
+ case "TranslationObjectType": {
48
+ const createObject = (type) => Object.fromEntries(Object.entries(type).map(([key, propType]) => [
49
+ key,
50
+ propType === null ? "" : createObject(propType),
51
+ ]));
52
+ return createObject(type.properties);
53
+ }
47
54
  default:
48
55
  return assertExhaustive(type);
49
56
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsondb",
3
- "version": "0.12.0",
3
+ "version": "0.12.2",
4
4
  "description": "",
5
5
  "license": "ISC",
6
6
  "author": "Lukas Obermann",
@@ -32,28 +32,28 @@
32
32
  "release:sign": "commit-and-tag-version --sign --signoff"
33
33
  },
34
34
  "devDependencies": {
35
- "@eslint/js": "^9.37.0",
35
+ "@eslint/js": "^9.39.1",
36
36
  "@types/debug": "^4.1.12",
37
- "@types/express": "^5.0.3",
38
- "@types/node": "^24.8.1",
37
+ "@types/express": "^5.0.5",
38
+ "@types/node": "^24.10.1",
39
39
  "commit-and-tag-version": "^12.6.0",
40
- "eslint": "^9.37.0",
40
+ "eslint": "^9.39.1",
41
41
  "eslint-plugin-react": "^7.37.5",
42
- "eslint-plugin-react-hooks": "^7.0.0",
43
- "globals": "^16.4.0",
42
+ "eslint-plugin-react-hooks": "^7.0.1",
43
+ "globals": "^16.5.0",
44
44
  "prettier": "^3.6.2",
45
45
  "tsx": "^4.20.6",
46
46
  "typescript": "^5.9.3",
47
- "typescript-eslint": "^8.46.1"
47
+ "typescript-eslint": "^8.46.4"
48
48
  },
49
49
  "dependencies": {
50
- "@preact/signals": "^2.3.2",
50
+ "@preact/signals": "^2.5.0",
51
51
  "debug": "^4.4.3",
52
52
  "express": "^5.1.0",
53
53
  "preact": "^10.27.2",
54
54
  "preact-iso": "^2.11.0",
55
55
  "simple-cli-args": "^0.1.3",
56
- "simple-git": "^3.28.0"
56
+ "simple-git": "^3.30.0"
57
57
  },
58
58
  "repository": "github:elyukai/tsondb",
59
59
  "bugs": {
@@ -704,9 +704,9 @@ form > .field--container {
704
704
  flex: 1 1 0;
705
705
  }
706
706
 
707
- .editor--markdown textarea,
708
- .editor--markdown input,
709
- .editor--markdown .textarea-grow-wrap__mirror {
707
+ :is(.editor--markdown, .editor--translation) textarea,
708
+ :is(.editor--markdown, .editor--translation) input,
709
+ :is(.editor--markdown, .editor--translation) .textarea-grow-wrap__mirror {
710
710
  font-family: var(--font-mono);
711
711
  line-height: 1.5;
712
712
  }
@@ -1180,3 +1180,28 @@ dialog[open] > .loading-overlay--open {
1180
1180
  dialog[open]:has(> .loading-overlay--open)::backdrop {
1181
1181
  background: rgba(0, 0, 0, 0.75);
1182
1182
  }
1183
+
1184
+ .field--container > ul > .object-item--translation {
1185
+ display: flex;
1186
+ gap: 1rem;
1187
+ align-items: start;
1188
+ justify-content: space-between;
1189
+ }
1190
+
1191
+ .object-item--translation .container-item-title {
1192
+ flex: none;
1193
+ font-family: var(--font-mono);
1194
+ line-height: 1.5;
1195
+ max-width: 40%;
1196
+ padding: calc(0.5rem + 1px) 0;
1197
+ display: block;
1198
+ }
1199
+
1200
+ .object-item--translation > .field {
1201
+ margin-top: 0;
1202
+ flex: 1 1 0;
1203
+ }
1204
+
1205
+ .object-item--translation button {
1206
+ align-self: center;
1207
+ }