tsondb 0.12.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/node/renderers/jsonschema/render.js +14 -0
- package/dist/src/node/renderers/ts/render.js +6 -0
- package/dist/src/node/schema/Node.d.ts +6 -3
- package/dist/src/node/schema/Node.js +12 -0
- package/dist/src/node/schema/Schema.js +1 -0
- package/dist/src/node/schema/types/Type.d.ts +2 -1
- package/dist/src/node/schema/types/Type.js +5 -1
- package/dist/src/node/schema/types/generic/TranslationObjectType.d.ts +25 -0
- package/dist/src/node/schema/types/generic/TranslationObjectType.js +66 -0
- package/dist/src/node/utils/errorFormatting.js +1 -1
- package/dist/src/shared/schema/Node.d.ts +4 -2
- package/dist/src/shared/schema/Node.js +6 -0
- package/dist/src/shared/schema/types/TranslationObjectType.d.ts +16 -0
- package/dist/src/shared/schema/types/TranslationObjectType.js +12 -0
- package/dist/src/shared/schema/types/Type.d.ts +3 -2
- package/dist/src/shared/validation/object.d.ts +1 -0
- package/dist/src/shared/validation/object.js +4 -3
- package/dist/src/web/components/typeInputs/StringTypeInput.js +4 -2
- package/dist/src/web/components/typeInputs/TranslationObjectTypeInput.d.ts +6 -0
- package/dist/src/web/components/typeInputs/TranslationObjectTypeInput.js +39 -0
- package/dist/src/web/components/typeInputs/TypeInput.d.ts +1 -0
- package/dist/src/web/components/typeInputs/TypeInput.js +3 -0
- package/dist/src/web/utils/typeSkeleton.js +7 -0
- package/package.json +10 -10
- 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
|
|
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);
|
|
@@ -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
|
|
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
|
-
?
|
|
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:
|
|
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.
|
|
3
|
+
"version": "0.12.1",
|
|
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.
|
|
35
|
+
"@eslint/js": "^9.39.1",
|
|
36
36
|
"@types/debug": "^4.1.12",
|
|
37
|
-
"@types/express": "^5.0.
|
|
38
|
-
"@types/node": "^24.
|
|
37
|
+
"@types/express": "^5.0.5",
|
|
38
|
+
"@types/node": "^24.10.1",
|
|
39
39
|
"commit-and-tag-version": "^12.6.0",
|
|
40
|
-
"eslint": "^9.
|
|
40
|
+
"eslint": "^9.39.1",
|
|
41
41
|
"eslint-plugin-react": "^7.37.5",
|
|
42
|
-
"eslint-plugin-react-hooks": "^7.0.
|
|
43
|
-
"globals": "^16.
|
|
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.
|
|
47
|
+
"typescript-eslint": "^8.46.4"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@preact/signals": "^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.
|
|
56
|
+
"simple-git": "^3.30.0"
|
|
57
57
|
},
|
|
58
58
|
"repository": "github:elyukai/tsondb",
|
|
59
59
|
"bugs": {
|
package/public/css/styles.css
CHANGED
|
@@ -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
|
+
}
|