tsondb 0.15.0 → 0.17.0
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 +3 -3
- package/dist/src/node/renderers/ts/render.js +2 -2
- package/dist/src/node/schema/Schema.js +2 -2
- package/dist/src/node/schema/declarations/EntityDecl.d.ts +29 -9
- package/dist/src/node/schema/declarations/EntityDecl.js +5 -6
- package/dist/src/node/schema/helpers.d.ts +38 -1
- package/dist/src/node/schema/helpers.js +20 -1
- package/dist/src/node/schema/types/generic/EnumType.d.ts +8 -0
- package/dist/src/node/schema/types/generic/EnumType.js +11 -11
- package/dist/src/node/schema/types/generic/ObjectType.d.ts +12 -0
- package/dist/src/node/schema/types/generic/ObjectType.js +4 -6
- package/dist/src/node/schema/types/references/NestedEntityMapType.d.ts +0 -7
- package/dist/src/node/schema/types/references/NestedEntityMapType.js +0 -1
- package/dist/src/node/utils/childInstances.js +3 -3
- package/dist/src/node/utils/customConstraints.d.ts +7 -3
- package/dist/src/node/utils/customConstraints.js +30 -13
- package/dist/src/node/utils/displayName.js +2 -2
- package/dist/src/shared/schema/declarations/EntityDecl.d.ts +11 -2
- package/dist/src/shared/schema/types/EnumType.d.ts +4 -0
- package/dist/src/shared/schema/types/EnumType.js +3 -3
- package/dist/src/shared/schema/types/ObjectType.d.ts +4 -0
- package/dist/src/shared/utils/displayName.js +1 -4
- package/dist/src/web/components/typeInputs/ChildEntitiesTypeInput.js +22 -3
- package/dist/src/web/components/typeInputs/EnumTypeInput.js +12 -12
- package/dist/src/web/components/typeInputs/ObjectTypeInput.js +3 -3
- package/dist/src/web/routes/Entity.js +3 -2
- package/dist/src/web/routes/Home.js +1 -1
- package/package.json +1 -1
- package/public/css/styles.css +7 -0
- package/dist/src/shared/enum.d.ts +0 -1
- package/dist/src/shared/enum.js +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { dirname, relative } from "node:path";
|
|
2
|
-
import {
|
|
2
|
+
import { ENUM_DISCRIMINATOR_KEY } from "../../../shared/schema/declarations/EnumDecl.js";
|
|
3
3
|
import { assertExhaustive } from "../../../shared/utils/typeSafety.js";
|
|
4
4
|
import { asDecl } from "../../schema/declarations/Declaration.js";
|
|
5
5
|
import { addEphemeralUUIDToType, createEntityIdentifierTypeAsDecl, isEntityDecl, } from "../../schema/declarations/EntityDecl.js";
|
|
@@ -96,12 +96,12 @@ const renderEnumType = (options, type) => ({
|
|
|
96
96
|
type: "object",
|
|
97
97
|
deprecated: caseDef.isDeprecated,
|
|
98
98
|
properties: {
|
|
99
|
-
[
|
|
99
|
+
[ENUM_DISCRIMINATOR_KEY]: {
|
|
100
100
|
const: caseName,
|
|
101
101
|
},
|
|
102
102
|
...(caseDef.type === null ? {} : { [caseName]: renderType(options, caseDef.type) }),
|
|
103
103
|
},
|
|
104
|
-
required: [
|
|
104
|
+
required: [ENUM_DISCRIMINATOR_KEY, ...(caseDef.type === null ? [] : [caseName])],
|
|
105
105
|
})),
|
|
106
106
|
});
|
|
107
107
|
const renderChildEntitiesType = (options, type) => renderType(options, ArrayType(ReferenceIdentifierType(type.entity), { uniqueItems: true }));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EOL } from "node:os";
|
|
2
2
|
import { dirname, relative } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { ENUM_DISCRIMINATOR_KEY } from "../../../shared/schema/declarations/EnumDecl.js";
|
|
4
4
|
import { unique } from "../../../shared/utils/array.js";
|
|
5
5
|
import { toCamelCase } from "../../../shared/utils/string.js";
|
|
6
6
|
import { extractParameterTypeNamesFromMessage, mapParameterTypeNames, } from "../../../shared/utils/translation.js";
|
|
@@ -59,7 +59,7 @@ const renderIncludeIdentifierType = (options, type) => combineSyntaxes([
|
|
|
59
59
|
: syntax `<${combineSyntaxes(type.args.map(arg => renderType(options, arg)), ", ")}>`,
|
|
60
60
|
]);
|
|
61
61
|
const renderNestedEntityMapType = (options, type) => wrapAsObject(options, syntax `[${toCamelCase(type.secondaryEntity.name)}Id: string]: ${type.name}`);
|
|
62
|
-
const renderEnumType = (options, type) => combineSyntaxes(Object.entries(type.values).map(([caseName, caseDef]) => indent(options.indentation, 1, syntax `${EOL}| {${EOL}${indent(options.indentation, 1, syntax `${
|
|
62
|
+
const renderEnumType = (options, type) => combineSyntaxes(Object.entries(type.values).map(([caseName, caseDef]) => indent(options.indentation, 1, syntax `${EOL}| {${EOL}${indent(options.indentation, 1, syntax `${ENUM_DISCRIMINATOR_KEY}: "${caseName}"${caseDef.type === null
|
|
63
63
|
? ""
|
|
64
64
|
: syntax `${EOL}${caseName}: ${renderType(options, caseDef.type)}`}`)}${EOL}}`)));
|
|
65
65
|
const renderChildEntitiesType = (options, type) => renderType(options, ArrayType(ReferenceIdentifierType(type.entity), { uniqueItems: true }));
|
|
@@ -43,8 +43,8 @@ const checkParameterNamesShadowing = (decls) => {
|
|
|
43
43
|
};
|
|
44
44
|
const checkEntityDisplayNamePaths = (decls, localeEntity) => {
|
|
45
45
|
for (const decl of decls) {
|
|
46
|
-
if (isEntityDecl(decl) && decl.
|
|
47
|
-
const displayName = decl.
|
|
46
|
+
if (isEntityDecl(decl) && decl.instanceDisplayName !== null) {
|
|
47
|
+
const displayName = decl.instanceDisplayName ?? "name";
|
|
48
48
|
if (typeof displayName === "function") {
|
|
49
49
|
continue;
|
|
50
50
|
}
|
|
@@ -30,16 +30,28 @@ type PathTo<T extends TConstraint, R> = {
|
|
|
30
30
|
export interface EntityDecl<Name extends string = string, T extends TConstraint = TConstraint, FK extends Extract<keyof T, string> | undefined = Extract<keyof T, string> | undefined> extends BaseDecl<Name, []> {
|
|
31
31
|
kind: NodeKind["EntityDecl"];
|
|
32
32
|
namePlural: string;
|
|
33
|
+
/**
|
|
34
|
+
* Changes the appearance of the entity’s name in singular form.
|
|
35
|
+
*/
|
|
36
|
+
displayName?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Changes the appearance of the entity’s name in plural form.
|
|
39
|
+
*/
|
|
40
|
+
displayNamePlural?: string;
|
|
33
41
|
type: Lazy<ObjectType<T>>;
|
|
34
42
|
parentReferenceKey: FK;
|
|
35
43
|
/**
|
|
44
|
+
* Sets the property used to retrieve the display name of an instance in editor forms (such as when selecting a reference) and error messages.
|
|
36
45
|
* @default "name"
|
|
37
46
|
*/
|
|
38
|
-
|
|
39
|
-
|
|
47
|
+
instanceDisplayName?: GenericEntityDisplayName;
|
|
48
|
+
/**
|
|
49
|
+
* A function that is used to further customize the display name of an instance.
|
|
50
|
+
*/
|
|
51
|
+
instanceDisplayNameCustomizer?: DisplayNameCustomizer;
|
|
40
52
|
isDeprecated?: boolean;
|
|
41
53
|
uniqueConstraints?: UniqueConstraints;
|
|
42
|
-
|
|
54
|
+
customConstraints?: CustomConstraint;
|
|
43
55
|
}
|
|
44
56
|
export interface EntityDeclWithParentReference<Name extends string = string, T extends TConstraint = TConstraint, FK extends Extract<keyof T, string> = Extract<keyof T, string>> extends EntityDecl<Name, T, FK> {
|
|
45
57
|
}
|
|
@@ -50,13 +62,17 @@ export declare const EntityDecl: {
|
|
|
50
62
|
comment?: string;
|
|
51
63
|
type: () => ObjectType<T>;
|
|
52
64
|
/**
|
|
65
|
+
* Sets the property used to retrieve the display name of an instance in editor forms (such as when selecting a reference) and error messages.
|
|
53
66
|
* @default "name"
|
|
54
67
|
*/
|
|
55
|
-
|
|
56
|
-
|
|
68
|
+
instanceDisplayName?: EntityDisplayName<T>;
|
|
69
|
+
/**
|
|
70
|
+
* A function that is used to further customize the display name of an instance.
|
|
71
|
+
*/
|
|
72
|
+
instanceDisplayNameCustomizer?: TypedDisplayNameCustomizer<Name>;
|
|
57
73
|
isDeprecated?: boolean;
|
|
58
74
|
uniqueConstraints?: UniqueConstraints;
|
|
59
|
-
|
|
75
|
+
customConstraints?: TypedCustomConstraint<Name>;
|
|
60
76
|
}): EntityDecl<Name, T, undefined>;
|
|
61
77
|
<Name extends string, T extends TConstraint, FK extends Extract<keyof T, string>>(sourceUrl: string, options: {
|
|
62
78
|
name: Name;
|
|
@@ -65,13 +81,17 @@ export declare const EntityDecl: {
|
|
|
65
81
|
type: () => ObjectType<T>;
|
|
66
82
|
parentReferenceKey: FK;
|
|
67
83
|
/**
|
|
84
|
+
* Sets the property used to retrieve the display name of an instance in editor forms (such as when selecting a reference) and error messages.
|
|
68
85
|
* @default "name"
|
|
69
86
|
*/
|
|
70
|
-
|
|
71
|
-
|
|
87
|
+
instanceDisplayName?: EntityDisplayName<T>;
|
|
88
|
+
/**
|
|
89
|
+
* A function that is used to further customize the display name of an instance.
|
|
90
|
+
*/
|
|
91
|
+
instanceDisplayNameCustomizer?: TypedDisplayNameCustomizer<Name>;
|
|
72
92
|
isDeprecated?: boolean;
|
|
73
93
|
uniqueConstraints?: UniqueConstraints;
|
|
74
|
-
|
|
94
|
+
customConstraints?: TypedCustomConstraint<Name>;
|
|
75
95
|
}): EntityDecl<Name, T, FK>;
|
|
76
96
|
};
|
|
77
97
|
export { EntityDecl as Entity };
|
|
@@ -8,8 +8,8 @@ export const EntityDecl = (sourceUrl, options) => {
|
|
|
8
8
|
validateDeclName(options.name);
|
|
9
9
|
return {
|
|
10
10
|
...options,
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
instanceDisplayNameCustomizer: options.instanceDisplayNameCustomizer, // ignore contravariance of registered entity type
|
|
12
|
+
customConstraints: options.customConstraints, // ignore contravariance of registered entity type
|
|
13
13
|
kind: NodeKind.EntityDecl,
|
|
14
14
|
sourceUrl,
|
|
15
15
|
parameters: [],
|
|
@@ -54,9 +54,8 @@ export const createEntityIdentifierTypeAsDecl = (decl) => TypeAliasDecl(decl.sou
|
|
|
54
54
|
export const serializeEntityDecl = ((type) => ({
|
|
55
55
|
...type,
|
|
56
56
|
type: serializeObjectType(type.type.value),
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
displayNameCustomizer: type.displayNameCustomizer !== undefined,
|
|
57
|
+
instanceDisplayName: type.instanceDisplayName,
|
|
58
|
+
instanceDisplayNameCustomizer: type.instanceDisplayNameCustomizer !== undefined,
|
|
59
|
+
customConstraints: type.customConstraints !== undefined,
|
|
61
60
|
}));
|
|
62
61
|
export const getReferencesForEntityDecl = (decl, value, inDecl) => getReferencesForObjectType(decl.type.value, value, [...inDecl, decl]);
|
|
@@ -1,4 +1,41 @@
|
|
|
1
|
+
import { ENUM_DISCRIMINATOR_KEY } from "../../shared/schema/declarations/EnumDecl.ts";
|
|
1
2
|
import type { RegisteredChildEntityMap, RegisteredEntityMap } from "./externalTypes.ts";
|
|
2
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Creates an enum case object.
|
|
5
|
+
*/
|
|
6
|
+
export declare const Case: {
|
|
7
|
+
<T extends string>(type: T): Case<T>;
|
|
8
|
+
<T extends string, V extends NonNullable<unknown> | null>(type: T, value: V): Case<T, V>;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Type representing an enum case object.
|
|
12
|
+
*/
|
|
13
|
+
export type Case<K extends string, T = undefined> = {
|
|
14
|
+
[P in K]: T extends NonNullable<unknown> | null ? {
|
|
15
|
+
[Key in ENUM_DISCRIMINATOR_KEY]: P;
|
|
16
|
+
} & {
|
|
17
|
+
[Key in P]: Extract<T, NonNullable<unknown> | null>;
|
|
18
|
+
} : {
|
|
19
|
+
[Key in ENUM_DISCRIMINATOR_KEY]: P;
|
|
20
|
+
};
|
|
21
|
+
}[K];
|
|
22
|
+
/**
|
|
23
|
+
* A single instance might be defined by entity and identifier separately or by
|
|
24
|
+
* them being wrapped in an enum case.
|
|
25
|
+
*/
|
|
26
|
+
export type IdArgsVariant<U extends keyof RegisteredEntityMap = keyof RegisteredEntityMap> = [entity: U, id: string] | [enumCase: Case<U, string>];
|
|
27
|
+
export declare const normalizedIdArgs: <U extends keyof RegisteredEntityMap>(args: IdArgsVariant<U>) => {
|
|
28
|
+
entityName: U;
|
|
29
|
+
id: string;
|
|
30
|
+
};
|
|
31
|
+
export type GetInstanceById = <U extends keyof RegisteredEntityMap>(...args: IdArgsVariant<U>) => RegisteredEntityMap[U] | undefined;
|
|
3
32
|
export type GetAllInstances = <U extends keyof RegisteredEntityMap>(entity: U) => RegisteredEntityMap[U][];
|
|
4
33
|
export type GetAllChildInstancesForParent = <U extends keyof RegisteredChildEntityMap>(entity: U, parentId: RegisteredChildEntityMap[U][2]) => RegisteredChildEntityMap[U][0][];
|
|
34
|
+
/**
|
|
35
|
+
* Displays the name of an entity instance including its ID. If no display name is found, `undefined` is returned.
|
|
36
|
+
*/
|
|
37
|
+
export type GetDisplayName = (...args: IdArgsVariant) => string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Displays the name of an entity instance including its ID. If no display name is found, only the ID is returned.
|
|
40
|
+
*/
|
|
41
|
+
export type GetDisplayNameWithId = (...args: IdArgsVariant) => string;
|
|
@@ -1 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
import { ENUM_DISCRIMINATOR_KEY } from "../../shared/schema/declarations/EnumDecl.js";
|
|
2
|
+
/**
|
|
3
|
+
* Creates an enum case object.
|
|
4
|
+
*/
|
|
5
|
+
export const Case = ((type, value) => (value === undefined
|
|
6
|
+
? { [ENUM_DISCRIMINATOR_KEY]: type }
|
|
7
|
+
: { [ENUM_DISCRIMINATOR_KEY]: type, [type]: value }));
|
|
8
|
+
export const normalizedIdArgs = (args) => {
|
|
9
|
+
if (typeof args[0] === "object") {
|
|
10
|
+
const [enumCase] = args;
|
|
11
|
+
return {
|
|
12
|
+
entityName: enumCase[ENUM_DISCRIMINATOR_KEY],
|
|
13
|
+
id: enumCase[enumCase[ENUM_DISCRIMINATOR_KEY]],
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
const [entityName, id] = args;
|
|
18
|
+
return { entityName, id };
|
|
19
|
+
}
|
|
20
|
+
};
|
|
@@ -13,11 +13,19 @@ export declare const resolveTypeArgumentsInEnumType: TypeArgumentsResolver<EnumT
|
|
|
13
13
|
export interface EnumCaseDecl<T extends Type | null = Type | null> {
|
|
14
14
|
kind: NodeKind["EnumCaseDecl"];
|
|
15
15
|
type: T;
|
|
16
|
+
/**
|
|
17
|
+
* Changes the appearance of the enum case’s name in editor forms.
|
|
18
|
+
*/
|
|
19
|
+
displayName?: string;
|
|
16
20
|
comment?: string;
|
|
17
21
|
isDeprecated?: boolean;
|
|
18
22
|
}
|
|
19
23
|
export declare const EnumCaseDecl: <T extends Type | null>(options: {
|
|
20
24
|
type: T;
|
|
25
|
+
/**
|
|
26
|
+
* Changes the appearance of the enum case’s name in editor forms.
|
|
27
|
+
*/
|
|
28
|
+
displayName?: string;
|
|
21
29
|
comment?: string;
|
|
22
30
|
isDeprecated?: boolean;
|
|
23
31
|
}) => EnumCaseDecl<T>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ENUM_DISCRIMINATOR_KEY } from "../../../../shared/schema/declarations/EnumDecl.js";
|
|
2
2
|
import { parallelizeErrors } from "../../../../shared/utils/validation.js";
|
|
3
3
|
import { wrapErrorsIfAny } from "../../../utils/error.js";
|
|
4
4
|
import { json, key } from "../../../utils/errorFormatting.js";
|
|
@@ -15,18 +15,18 @@ export const validateEnumType = (helpers, inDecls, type, value) => {
|
|
|
15
15
|
return [TypeError(`expected an object, but got ${json(value, helpers.useStyling)}`)];
|
|
16
16
|
}
|
|
17
17
|
const actualKeys = Object.keys(value);
|
|
18
|
-
if (!(
|
|
18
|
+
if (!(ENUM_DISCRIMINATOR_KEY in value) || typeof value[ENUM_DISCRIMINATOR_KEY] !== "string") {
|
|
19
19
|
return [
|
|
20
|
-
TypeError(`missing required discriminator value at key ${key(`"${
|
|
20
|
+
TypeError(`missing required discriminator value at key ${key(`"${ENUM_DISCRIMINATOR_KEY}"`, helpers.useStyling)} of type string`),
|
|
21
21
|
];
|
|
22
22
|
}
|
|
23
|
-
const caseName = value[
|
|
23
|
+
const caseName = value[ENUM_DISCRIMINATOR_KEY];
|
|
24
24
|
if (!(caseName in type.values)) {
|
|
25
25
|
return [
|
|
26
26
|
TypeError(`discriminator ${key(`"${caseName}"`, helpers.useStyling)} is not a valid enum case, possible cases are: ${Object.keys(type.values).join(", ")}`),
|
|
27
27
|
];
|
|
28
28
|
}
|
|
29
|
-
const unknownKeyErrors = actualKeys.flatMap(actualKey => actualKey ===
|
|
29
|
+
const unknownKeyErrors = actualKeys.flatMap(actualKey => actualKey === ENUM_DISCRIMINATOR_KEY || actualKey in type.values
|
|
30
30
|
? []
|
|
31
31
|
: [
|
|
32
32
|
TypeError(`key ${key(`"${actualKey}"`, helpers.useStyling)} is not the discriminator key ${key(`"${caseName}"`, helpers.useStyling)} or a valid enum case, possible cases are: ${Object.keys(type.values).join(", ")}`),
|
|
@@ -73,10 +73,10 @@ export const getReferencesForEnumType = (type, value, inDecl) => {
|
|
|
73
73
|
if (typeof value !== "object" ||
|
|
74
74
|
value === null ||
|
|
75
75
|
Array.isArray(value) ||
|
|
76
|
-
!(
|
|
76
|
+
!(ENUM_DISCRIMINATOR_KEY in value)) {
|
|
77
77
|
return [];
|
|
78
78
|
}
|
|
79
|
-
const enumCase = value[
|
|
79
|
+
const enumCase = value[ENUM_DISCRIMINATOR_KEY];
|
|
80
80
|
return typeof enumCase === "string" &&
|
|
81
81
|
enumCase in type.values &&
|
|
82
82
|
type.values[enumCase] !== undefined &&
|
|
@@ -89,13 +89,13 @@ export const formatEnumType = (type, value) => {
|
|
|
89
89
|
if (typeof value === "object" &&
|
|
90
90
|
value !== null &&
|
|
91
91
|
!Array.isArray(value) &&
|
|
92
|
-
|
|
93
|
-
typeof value[
|
|
94
|
-
const caseName = value[
|
|
92
|
+
ENUM_DISCRIMINATOR_KEY in value &&
|
|
93
|
+
typeof value[ENUM_DISCRIMINATOR_KEY] === "string") {
|
|
94
|
+
const caseName = value[ENUM_DISCRIMINATOR_KEY];
|
|
95
95
|
const caseValue = value[caseName];
|
|
96
96
|
const caseType = type.values[caseName]?.type;
|
|
97
97
|
return {
|
|
98
|
-
[
|
|
98
|
+
[ENUM_DISCRIMINATOR_KEY]: caseName,
|
|
99
99
|
...(caseValue == null || caseType == null
|
|
100
100
|
? {}
|
|
101
101
|
: { [caseName]: formatValue(caseType, caseValue) }),
|
|
@@ -21,15 +21,27 @@ export interface MemberDecl<T extends Type = Type, R extends boolean = boolean>
|
|
|
21
21
|
kind: NodeKind["MemberDecl"];
|
|
22
22
|
isRequired: R;
|
|
23
23
|
type: T;
|
|
24
|
+
/**
|
|
25
|
+
* Changes the appearance of the member’s name in editor forms.
|
|
26
|
+
*/
|
|
27
|
+
displayName?: string;
|
|
24
28
|
comment?: string;
|
|
25
29
|
isDeprecated?: boolean;
|
|
26
30
|
}
|
|
27
31
|
export declare const Required: <T extends Type>(options: {
|
|
32
|
+
/**
|
|
33
|
+
* Changes the appearance of the member’s name in editor forms.
|
|
34
|
+
*/
|
|
35
|
+
displayName?: string;
|
|
28
36
|
comment?: string;
|
|
29
37
|
isDeprecated?: boolean;
|
|
30
38
|
type: T;
|
|
31
39
|
}) => MemberDecl<T, true>;
|
|
32
40
|
export declare const Optional: <T extends Type>(options: {
|
|
41
|
+
/**
|
|
42
|
+
* Changes the appearance of the member’s name in editor forms.
|
|
43
|
+
*/
|
|
44
|
+
displayName?: string;
|
|
33
45
|
comment?: string;
|
|
34
46
|
isDeprecated?: boolean;
|
|
35
47
|
type: T;
|
|
@@ -49,15 +49,13 @@ export const validateObjectType = (helpers, inDecls, type, value) => {
|
|
|
49
49
|
export const resolveTypeArgumentsInObjectType = (args, type, inDecl) => ObjectType(Object.fromEntries(Object.entries(type.properties).map(([key, config]) => [key, { ...config, type: resolveTypeArguments(args, config.type, inDecl) }])), {
|
|
50
50
|
...type,
|
|
51
51
|
});
|
|
52
|
-
const MemberDecl = (isRequired,
|
|
52
|
+
const MemberDecl = (isRequired, options) => ({
|
|
53
|
+
...options,
|
|
53
54
|
kind: NodeKind.MemberDecl,
|
|
54
55
|
isRequired,
|
|
55
|
-
type,
|
|
56
|
-
comment,
|
|
57
|
-
isDeprecated,
|
|
58
56
|
});
|
|
59
|
-
export const Required = (options) => MemberDecl(true, options
|
|
60
|
-
export const Optional = (options) => MemberDecl(false, options
|
|
57
|
+
export const Required = (options) => MemberDecl(true, options);
|
|
58
|
+
export const Optional = (options) => MemberDecl(false, options);
|
|
61
59
|
export const serializeObjectType = (type) => ({
|
|
62
60
|
...type,
|
|
63
61
|
properties: Object.fromEntries(Object.entries(type.properties).map(([key, prop]) => [
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { Lazy } from "../../../../shared/utils/lazy.ts";
|
|
2
|
-
import type { DisplayNameCustomizer } from "../../../utils/displayName.ts";
|
|
3
2
|
import type { EntityDecl } from "../../declarations/EntityDecl.js";
|
|
4
|
-
import { type EntityDisplayName } from "../../declarations/EntityDecl.js";
|
|
5
3
|
import type { TypeAliasDecl } from "../../declarations/TypeAliasDecl.js";
|
|
6
4
|
import type { GetNestedDeclarations, GetReferences, Predicate, Serializer, TypeArgumentsResolver, Validator } from "../../Node.ts";
|
|
7
5
|
import { NodeKind } from "../../Node.ts";
|
|
@@ -24,11 +22,6 @@ export declare const NestedEntityMapType: <Name extends string, T extends TConst
|
|
|
24
22
|
comment?: string;
|
|
25
23
|
secondaryEntity: EntityDecl;
|
|
26
24
|
type: PossibleType<T>;
|
|
27
|
-
/**
|
|
28
|
-
* @default "name"
|
|
29
|
-
*/
|
|
30
|
-
displayName?: EntityDisplayName<T>;
|
|
31
|
-
displayNameCustomizer?: DisplayNameCustomizer;
|
|
32
25
|
isDeprecated?: boolean;
|
|
33
26
|
}) => NestedEntityMapType<Name, T>;
|
|
34
27
|
export { NestedEntityMapType as NestedEntityMap };
|
|
@@ -3,7 +3,6 @@ import { sortObjectKeysAlphabetically } from "../../../../shared/utils/object.js
|
|
|
3
3
|
import { parallelizeErrors } from "../../../../shared/utils/validation.js";
|
|
4
4
|
import { wrapErrorsIfAny } from "../../../utils/error.js";
|
|
5
5
|
import { entity, json, key as keyColor } from "../../../utils/errorFormatting.js";
|
|
6
|
-
import {} from "../../declarations/EntityDecl.js";
|
|
7
6
|
import { getNestedDeclarations, NodeKind, resolveTypeArguments, validateType } from "../../Node.js";
|
|
8
7
|
import { getReferencesForObjectType, isObjectType, serializeObjectType, } from "../generic/ObjectType.js";
|
|
9
8
|
import { formatValue } from "../Type.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createEnumCaseValue } from "../../shared/schema/declarations/EnumDecl.js";
|
|
1
|
+
import { createEnumCaseValue, ENUM_DISCRIMINATOR_KEY, } from "../../shared/schema/declarations/EnumDecl.js";
|
|
2
2
|
import { hasKey } from "../../shared/utils/object.js";
|
|
3
3
|
import { error, isError, map, ok } from "../../shared/utils/result.js";
|
|
4
4
|
import { isEntityDeclWithParentReference, isEnumDecl, isIncludeIdentifierType, reduceNodes, } from "../schema/index.js";
|
|
@@ -7,8 +7,8 @@ import { getInstancesOfEntityFromDatabaseInMemory, } from "./databaseInMemory.js
|
|
|
7
7
|
import { HTTPError } from "./error.js";
|
|
8
8
|
import { createInstance, deleteInstance, updateInstance } from "./instanceTransactionSteps.js";
|
|
9
9
|
const isParentReferenceReferencingParent = (value, parentEntityName, parentId) => {
|
|
10
|
-
if (typeof value === "object" && value !== null && hasKey(value,
|
|
11
|
-
return (value
|
|
10
|
+
if (typeof value === "object" && value !== null && hasKey(value, ENUM_DISCRIMINATOR_KEY)) {
|
|
11
|
+
return (value[ENUM_DISCRIMINATOR_KEY] === parentEntityName &&
|
|
12
12
|
hasKey(value, parentEntityName) &&
|
|
13
13
|
value[parentEntityName] === parentId);
|
|
14
14
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { InstanceContainerOverview, InstanceContent } from "../../shared/utils/instances.ts";
|
|
2
2
|
import { type Result } from "../../shared/utils/result.ts";
|
|
3
3
|
import type { RegisteredEntity } from "../schema/externalTypes.ts";
|
|
4
|
-
import type
|
|
4
|
+
import { type GetAllChildInstancesForParent, type GetAllInstances, type GetDisplayName, type GetDisplayNameWithId, type GetInstanceById } from "../schema/helpers.ts";
|
|
5
5
|
import type { EntityDecl } from "../schema/index.ts";
|
|
6
6
|
import { type DatabaseInMemory } from "./databaseInMemory.ts";
|
|
7
7
|
/**
|
|
@@ -17,8 +17,10 @@ export type CustomConstraint = (params: {
|
|
|
17
17
|
instanceId: string;
|
|
18
18
|
instanceContent: InstanceContent;
|
|
19
19
|
getInstanceById: GetInstanceById;
|
|
20
|
-
|
|
20
|
+
getAllInstances: GetAllInstances;
|
|
21
21
|
getAllChildInstancesForParent: GetAllChildInstancesForParent;
|
|
22
|
+
getDisplayName: GetDisplayName;
|
|
23
|
+
getDisplayNameWithId: GetDisplayNameWithId;
|
|
22
24
|
}) => string[];
|
|
23
25
|
/**
|
|
24
26
|
* A constraint that can be defined on an entity to enforce custom validation logic.
|
|
@@ -33,8 +35,10 @@ export type TypedCustomConstraint<Name extends string> = (params: {
|
|
|
33
35
|
instanceId: string;
|
|
34
36
|
instanceContent: RegisteredEntity<Name>;
|
|
35
37
|
getInstanceById: GetInstanceById;
|
|
36
|
-
|
|
38
|
+
getAllInstances: GetAllInstances;
|
|
37
39
|
getAllChildInstancesForParent: GetAllChildInstancesForParent;
|
|
40
|
+
getDisplayName: GetDisplayName;
|
|
41
|
+
getDisplayNameWithId: GetDisplayNameWithId;
|
|
38
42
|
}) => string[];
|
|
39
43
|
/**
|
|
40
44
|
* Checks all custom constraints for all provided entities and their instances.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { deepEqual } from "../../shared/utils/compare.js";
|
|
2
2
|
import { error, isError, mapError, ok } from "../../shared/utils/result.js";
|
|
3
|
+
import { normalizedIdArgs, } from "../schema/helpers.js";
|
|
3
4
|
import { getInstanceOfEntityFromDatabaseInMemory, getInstancesOfEntityFromDatabaseInMemory, } from "./databaseInMemory.js";
|
|
4
5
|
/**
|
|
5
6
|
* Checks all custom constraints for all provided entities and their instances.
|
|
@@ -9,20 +10,32 @@ import { getInstanceOfEntityFromDatabaseInMemory, getInstancesOfEntityFromDataba
|
|
|
9
10
|
* constraint.
|
|
10
11
|
*/
|
|
11
12
|
export const checkCustomConstraintsForAllEntities = (db, entitiesByName, instanceOverviewsByEntityName) => {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
const getInstanceById = (...args) => {
|
|
14
|
+
const { entityName, id } = normalizedIdArgs(args);
|
|
15
|
+
return getInstanceOfEntityFromDatabaseInMemory(db, entityName, id)?.content;
|
|
16
|
+
};
|
|
17
|
+
const getAllInstances = entityName => getInstancesOfEntityFromDatabaseInMemory(db, entityName).map(i => i.content);
|
|
18
|
+
const getAllChildInstancesForParent = (entityName, parentId) => {
|
|
19
|
+
const entity = entitiesByName[entityName];
|
|
20
|
+
if (!entity || !entity.parentReferenceKey) {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
const parentKey = entity.parentReferenceKey;
|
|
24
|
+
return getInstancesOfEntityFromDatabaseInMemory(db, entityName)
|
|
25
|
+
.filter(instance => deepEqual(instance.content[parentKey], parentId))
|
|
26
|
+
.map(i => i.content);
|
|
27
|
+
};
|
|
28
|
+
const getDisplayName = (...args) => {
|
|
29
|
+
const { entityName, id } = normalizedIdArgs(args);
|
|
30
|
+
return instanceOverviewsByEntityName[entityName]?.find(o => o.id === id)?.displayName;
|
|
31
|
+
};
|
|
32
|
+
const getDisplayNameWithId = (...args) => {
|
|
33
|
+
const { id } = normalizedIdArgs(args);
|
|
34
|
+
const displayName = getDisplayName(...args);
|
|
35
|
+
return displayName ? `"${displayName}" (${id})` : id;
|
|
23
36
|
};
|
|
24
37
|
return mapError(Object.values(entitiesByName).reduce((acc, entity) => {
|
|
25
|
-
const constraintFn = entity.
|
|
38
|
+
const constraintFn = entity.customConstraints;
|
|
26
39
|
if (!constraintFn) {
|
|
27
40
|
return acc;
|
|
28
41
|
}
|
|
@@ -30,7 +43,11 @@ export const checkCustomConstraintsForAllEntities = (db, entitiesByName, instanc
|
|
|
30
43
|
.map((instance) => [
|
|
31
44
|
instance,
|
|
32
45
|
constraintFn({
|
|
33
|
-
|
|
46
|
+
getInstanceById,
|
|
47
|
+
getAllInstances,
|
|
48
|
+
getAllChildInstancesForParent,
|
|
49
|
+
getDisplayName,
|
|
50
|
+
getDisplayNameWithId,
|
|
34
51
|
instanceId: instance.id,
|
|
35
52
|
instanceContent: instance.content,
|
|
36
53
|
}),
|
|
@@ -3,9 +3,9 @@ import { serializeEntityDecl } from "../schema/declarations/EntityDecl.js";
|
|
|
3
3
|
import { createChildInstancesForInstanceIdGetter } from "../server/utils/childInstances.js";
|
|
4
4
|
import { createInstanceFromDatabaseInMemoryGetter, getGroupedInstancesFromDatabaseInMemory, } from "./databaseInMemory.js";
|
|
5
5
|
export const getDisplayNameFromEntityInstance = (entity, instanceContainer, getInstanceById, getChildInstancesForInstanceId, locales, defaultName = "", useCustomizer = true) => {
|
|
6
|
-
if (useCustomizer && entity.
|
|
6
|
+
if (useCustomizer && entity.instanceDisplayNameCustomizer) {
|
|
7
7
|
const calculatedName = getDisplayNameFromEntityInstance(entity, instanceContainer, getInstanceById, getChildInstancesForInstanceId, locales, defaultName, false);
|
|
8
|
-
return entity.
|
|
8
|
+
return entity.instanceDisplayNameCustomizer({
|
|
9
9
|
instance: instanceContainer.content,
|
|
10
10
|
instanceId: instanceContainer.id,
|
|
11
11
|
instanceDisplayName: calculatedName.name,
|
|
@@ -48,15 +48,24 @@ export type UniqueConstraints = UniqueConstraint[];
|
|
|
48
48
|
export interface SerializedEntityDecl<Name extends string = string, T extends TSerializedConstraint = TSerializedConstraint, FK extends Extract<keyof T, string> | undefined = Extract<keyof T, string> | undefined> extends SerializedBaseDecl<Name, []> {
|
|
49
49
|
kind: NodeKind["EntityDecl"];
|
|
50
50
|
namePlural: string;
|
|
51
|
+
/**
|
|
52
|
+
* Changes the appearance of the entity’s name in singular form.
|
|
53
|
+
*/
|
|
54
|
+
displayName?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Changes the appearance of the entity’s name in plural form.
|
|
57
|
+
*/
|
|
58
|
+
displayNamePlural?: string;
|
|
51
59
|
type: SerializedObjectType<T>;
|
|
52
60
|
parentReferenceKey: FK;
|
|
53
61
|
/**
|
|
54
62
|
* @default "name"
|
|
55
63
|
*/
|
|
56
|
-
|
|
57
|
-
|
|
64
|
+
instanceDisplayName?: GenericEntityDisplayName;
|
|
65
|
+
instanceDisplayNameCustomizer: boolean;
|
|
58
66
|
isDeprecated?: boolean;
|
|
59
67
|
uniqueConstraints?: UniqueConstraints;
|
|
68
|
+
customConstraints: boolean;
|
|
60
69
|
}
|
|
61
70
|
export declare const isSerializedEntityDecl: (node: SerializedNode) => node is SerializedEntityDecl;
|
|
62
71
|
export declare const isSerializedEntityDeclWithParentReference: <Name extends string, T extends TSerializedConstraint, FK extends Extract<keyof T, string> | undefined>(decl: SerializedEntityDecl<Name, T, FK>) => decl is SerializedEntityDecl<Name, T, NonNullable<FK>>;
|
|
@@ -7,6 +7,10 @@ export interface SerializedEnumType<T extends Record<string, SerializedEnumCaseD
|
|
|
7
7
|
export interface SerializedEnumCaseDecl<T extends SerializedType | null = SerializedType | null> {
|
|
8
8
|
kind: NodeKind["EnumCaseDecl"];
|
|
9
9
|
type: T;
|
|
10
|
+
/**
|
|
11
|
+
* Changes the appearance of the enum case’s name in editor forms.
|
|
12
|
+
*/
|
|
13
|
+
displayName?: string;
|
|
10
14
|
comment?: string;
|
|
11
15
|
isDeprecated?: boolean;
|
|
12
16
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ENUM_DISCRIMINATOR_KEY } from "../declarations/EnumDecl.js";
|
|
2
2
|
import { getReferencesSerialized, resolveSerializedTypeArguments, } from "../Node.js";
|
|
3
3
|
export const resolveTypeArgumentsInSerializedEnumType = (decls, args, type) => ({
|
|
4
4
|
...type,
|
|
@@ -14,10 +14,10 @@ export const getReferencesForSerializedEnumType = (decls, type, value) => {
|
|
|
14
14
|
if (typeof value !== "object" ||
|
|
15
15
|
value === null ||
|
|
16
16
|
Array.isArray(value) ||
|
|
17
|
-
!(
|
|
17
|
+
!(ENUM_DISCRIMINATOR_KEY in value)) {
|
|
18
18
|
return [];
|
|
19
19
|
}
|
|
20
|
-
const enumCase = value[
|
|
20
|
+
const enumCase = value[ENUM_DISCRIMINATOR_KEY];
|
|
21
21
|
return typeof enumCase === "string" &&
|
|
22
22
|
enumCase in type.values &&
|
|
23
23
|
type.values[enumCase] !== undefined &&
|
|
@@ -10,6 +10,10 @@ export interface SerializedMemberDecl<T extends SerializedType = SerializedType,
|
|
|
10
10
|
kind: NodeKind["MemberDecl"];
|
|
11
11
|
isRequired: R;
|
|
12
12
|
type: T;
|
|
13
|
+
/**
|
|
14
|
+
* Changes the appearance of the member’s name in editor forms.
|
|
15
|
+
*/
|
|
16
|
+
displayName?: string;
|
|
13
17
|
comment?: string;
|
|
14
18
|
isDeprecated?: boolean;
|
|
15
19
|
}
|
|
@@ -12,10 +12,7 @@ const getValueAtPath = (value, path) => {
|
|
|
12
12
|
return current;
|
|
13
13
|
};
|
|
14
14
|
export const getSerializedDisplayNameFromEntityInstance = (entity, instance, defaultName, locales) => {
|
|
15
|
-
|
|
16
|
-
return { name: defaultName, localeId: locales[0] };
|
|
17
|
-
}
|
|
18
|
-
const displayNamePath = entity.displayName ?? "name";
|
|
15
|
+
const displayNamePath = entity.instanceDisplayName ?? "name";
|
|
19
16
|
if (typeof displayNamePath === "string") {
|
|
20
17
|
return {
|
|
21
18
|
name: getValueAtPath(instance, displayNamePath) ?? defaultName,
|
|
@@ -30,6 +30,23 @@ export const ChildEntitiesTypeInput = props => {
|
|
|
30
30
|
{ entityName, childInstances: [], id: undefined, content: value },
|
|
31
31
|
]);
|
|
32
32
|
}, [setChildInstances]);
|
|
33
|
+
const onChildDuplicate = useCallback((index) => {
|
|
34
|
+
const setChildInstancesAsNew = (childInstances) => childInstances.map(ci => ({
|
|
35
|
+
...ci,
|
|
36
|
+
childInstances: setChildInstancesAsNew(ci.childInstances),
|
|
37
|
+
id: undefined,
|
|
38
|
+
}));
|
|
39
|
+
setChildInstances(old => old[index]
|
|
40
|
+
? [
|
|
41
|
+
...old,
|
|
42
|
+
{
|
|
43
|
+
...old[index],
|
|
44
|
+
childInstances: setChildInstancesAsNew(old[index].childInstances),
|
|
45
|
+
id: undefined,
|
|
46
|
+
},
|
|
47
|
+
]
|
|
48
|
+
: old);
|
|
49
|
+
}, [setChildInstances]);
|
|
33
50
|
const onChildRemove = useCallback((index) => {
|
|
34
51
|
setChildInstances(old => removeAt(old, index));
|
|
35
52
|
}, [setChildInstances]);
|
|
@@ -39,9 +56,11 @@ export const ChildEntitiesTypeInput = props => {
|
|
|
39
56
|
if (path === undefined) {
|
|
40
57
|
return _jsx("div", { role: "alert", children: "A child entities type cannot be the root type of a document." });
|
|
41
58
|
}
|
|
42
|
-
return (_jsxs("div", { class: "field field--container field--array", children: [childInstancesForEntity.length > 0 ? (_jsx("ol", { children: childInstancesForEntity.map(([item, originalIndex], i) => (_jsxs("li", { class: "container-item array-item", children: [_jsxs("div", { className: "container-item-header", children: [_jsxs("div", { className: "container-item-title", children: [i + 1, "."] }),
|
|
43
|
-
|
|
44
|
-
|
|
59
|
+
return (_jsxs("div", { class: "field field--container field--array", children: [childInstancesForEntity.length > 0 ? (_jsx("ol", { children: childInstancesForEntity.map(([item, originalIndex], i) => (_jsxs("li", { class: "container-item array-item", children: [_jsxs("div", { className: "container-item-header", children: [_jsxs("div", { className: "container-item-title", children: [i + 1, "."] }), _jsxs("div", { class: "container-item-actions", children: [_jsxs("button", { onClick: () => {
|
|
60
|
+
onChildDuplicate(i);
|
|
61
|
+
}, disabled: disabled, children: ["Duplicate Item #", i + 1] }), _jsxs("button", { class: "destructive", onClick: () => {
|
|
62
|
+
onChildRemove(i);
|
|
63
|
+
}, disabled: disabled, children: ["Delete Item #", i + 1] })] })] }), _jsx(TypeInput, { ...props, type: childEntity.type, value: item.content, parentKey: childEntity.parentReferenceKey, onChange: newItem => {
|
|
45
64
|
onChildChange(originalIndex, newItem); // guaranteed to be an object because of the ObjectType in the child entity
|
|
46
65
|
}, childInstances: item.childInstances, setChildInstances: newChildInstances => {
|
|
47
66
|
onGrandChildrenChange(originalIndex, newChildInstances);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { ENUM_DISCRIMINATOR_KEY } from "../../../shared/schema/declarations/EnumDecl.js";
|
|
3
3
|
import { toTitleCase } from "../../../shared/utils/string.js";
|
|
4
4
|
import { assertExhaustive } from "../../../shared/utils/typeSafety.js";
|
|
5
5
|
import { useSetting } from "../../hooks/useSettings.js";
|
|
@@ -14,12 +14,12 @@ export const EnumTypeInput = props => {
|
|
|
14
14
|
if (typeof value !== "object" ||
|
|
15
15
|
value === null ||
|
|
16
16
|
Array.isArray(value) ||
|
|
17
|
-
!(
|
|
18
|
-
typeof value[
|
|
17
|
+
!(ENUM_DISCRIMINATOR_KEY in value) ||
|
|
18
|
+
typeof value[ENUM_DISCRIMINATOR_KEY] !== "string") {
|
|
19
19
|
return _jsx(MismatchingTypeError, { expected: "enumeration value", actual: value });
|
|
20
20
|
}
|
|
21
21
|
const enumValues = Object.entries(type.values);
|
|
22
|
-
const activeEnumCase = value[
|
|
22
|
+
const activeEnumCase = value[ENUM_DISCRIMINATOR_KEY];
|
|
23
23
|
const activeCaseMember = type.values[activeEnumCase];
|
|
24
24
|
switch (enumDisplay) {
|
|
25
25
|
case "select":
|
|
@@ -27,18 +27,18 @@ export const EnumTypeInput = props => {
|
|
|
27
27
|
const caseMember = type.values[event.currentTarget.value];
|
|
28
28
|
if (caseMember?.type == null) {
|
|
29
29
|
onChange({
|
|
30
|
-
[
|
|
30
|
+
[ENUM_DISCRIMINATOR_KEY]: event.currentTarget.value,
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
33
|
else {
|
|
34
34
|
onChange({
|
|
35
|
-
[
|
|
35
|
+
[ENUM_DISCRIMINATOR_KEY]: event.currentTarget.value,
|
|
36
36
|
[event.currentTarget.value]: createTypeSkeleton(getDeclFromDeclName, caseMember.type),
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
|
-
}, disabled: disabled, children: enumValues.map(([enumValue]) => (_jsx("option", { value: enumValue, selected: enumValue === activeEnumCase, children: toTitleCase(enumValue) }, enumValue))) }), activeCaseMember?.comment === undefined ? null : (_jsx(Markdown, { class: "comment", string: activeCaseMember.comment })), activeCaseMember?.type == null ? null : (_jsx("div", { className: "associated-type", children: _jsx(TypeInput, { ...props, parentKey: undefined, type: activeCaseMember.type, path: path === undefined ? `{${activeEnumCase}}` : `${path}.{${activeEnumCase}}`, value: value[activeEnumCase], onChange: newValue => {
|
|
39
|
+
}, disabled: disabled, children: enumValues.map(([enumValue, caseMember]) => (_jsx("option", { value: enumValue, selected: enumValue === activeEnumCase, children: caseMember.displayName ?? toTitleCase(enumValue) }, enumValue))) }), activeCaseMember?.comment === undefined ? null : (_jsx(Markdown, { class: "comment", string: activeCaseMember.comment })), activeCaseMember?.type == null ? null : (_jsx("div", { className: "associated-type", children: _jsx(TypeInput, { ...props, parentKey: undefined, type: activeCaseMember.type, path: path === undefined ? `{${activeEnumCase}}` : `${path}.{${activeEnumCase}}`, value: value[activeEnumCase], onChange: newValue => {
|
|
40
40
|
onChange({
|
|
41
|
-
[
|
|
41
|
+
[ENUM_DISCRIMINATOR_KEY]: activeEnumCase,
|
|
42
42
|
[activeEnumCase]: newValue,
|
|
43
43
|
});
|
|
44
44
|
} }) }))] }));
|
|
@@ -46,22 +46,22 @@ export const EnumTypeInput = props => {
|
|
|
46
46
|
return (_jsx("div", { class: "field field--enum", children: enumValues.map(([enumValue, caseMember]) => (_jsxs("div", { class: "field--option", children: [_jsx("input", { type: "radio", name: path, value: enumValue, id: path === undefined ? enumValue : `${path}-${enumValue}`, checked: enumValue === activeEnumCase, onInput: () => {
|
|
47
47
|
if (caseMember.type == null) {
|
|
48
48
|
onChange({
|
|
49
|
-
[
|
|
49
|
+
[ENUM_DISCRIMINATOR_KEY]: enumValue,
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
52
|
else {
|
|
53
53
|
onChange({
|
|
54
|
-
[
|
|
54
|
+
[ENUM_DISCRIMINATOR_KEY]: enumValue,
|
|
55
55
|
[enumValue]: createTypeSkeleton(getDeclFromDeclName, caseMember.type),
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
|
-
}, disabled: disabled }), _jsxs("div", { children: [_jsx("label", { htmlFor: path === undefined ? enumValue : `${path}-${enumValue}`, children: toTitleCase(enumValue) }), caseMember.comment === undefined ? null : (_jsx(Markdown, { class: "comment", string: caseMember.comment })), caseMember.type == null ? null : (_jsx("div", { className: "associated-type", children: _jsx(TypeInput, { ...props, parentKey: undefined, type: caseMember.type, path: path === undefined ? `{${activeEnumCase}}` : `${path}.{${activeEnumCase}}`, value: enumValue === activeEnumCase
|
|
58
|
+
}, disabled: disabled }), _jsxs("div", { children: [_jsx("label", { htmlFor: path === undefined ? enumValue : `${path}-${enumValue}`, children: caseMember.displayName ?? toTitleCase(enumValue) }), caseMember.comment === undefined ? null : (_jsx(Markdown, { class: "comment", string: caseMember.comment })), caseMember.type == null ? null : (_jsx("div", { className: "associated-type", children: _jsx(TypeInput, { ...props, parentKey: undefined, type: caseMember.type, path: path === undefined ? `{${activeEnumCase}}` : `${path}.{${activeEnumCase}}`, value: enumValue === activeEnumCase
|
|
59
59
|
? value[activeEnumCase]
|
|
60
60
|
: createTypeSkeleton(getDeclFromDeclName, caseMember.type), disabled: disabled || enumValue !== activeEnumCase, onChange: disabled
|
|
61
61
|
? () => { }
|
|
62
62
|
: newValue => {
|
|
63
63
|
onChange({
|
|
64
|
-
[
|
|
64
|
+
[ENUM_DISCRIMINATOR_KEY]: activeEnumCase,
|
|
65
65
|
[activeEnumCase]: newValue,
|
|
66
66
|
});
|
|
67
67
|
} }) }))] })] }, enumValue))) }));
|
|
@@ -15,18 +15,18 @@ export const ObjectTypeInput = props => {
|
|
|
15
15
|
const errors = validateObjectConstraints(type, Object.keys(type.properties), value);
|
|
16
16
|
return (_jsxs("div", { class: "field field--container field--object" + (disabled ? " field--disabled" : ""), children: [_jsx("ul", { children: Object.entries(type.properties)
|
|
17
17
|
.filter(([key]) => key !== parentKey)
|
|
18
|
-
.map(([key, memberDecl]) => (_jsxs("li", { class: "container-item object-item", children: [_jsxs("div", { className: "container-item-header", children: [_jsxs("div", { className: "container-item-title", children: [_jsx("strong", { children: toTitleCase(key) }), memberDecl.comment === undefined ? null : (_jsx(Markdown, { class: "comment", string: memberDecl.comment }))] }), memberDecl.isRequired ? null : value[key] ===
|
|
18
|
+
.map(([key, memberDecl]) => (_jsxs("li", { class: "container-item object-item", children: [_jsxs("div", { className: "container-item-header", children: [_jsxs("div", { className: "container-item-title", children: [_jsx("strong", { children: memberDecl.displayName ?? toTitleCase(key) }), memberDecl.comment === undefined ? null : (_jsx(Markdown, { class: "comment", string: memberDecl.comment }))] }), memberDecl.isRequired ? null : value[key] ===
|
|
19
19
|
undefined ? (_jsxs("button", { onClick: () => {
|
|
20
20
|
onChange(sortObjectKeys({
|
|
21
21
|
...value,
|
|
22
22
|
[key]: createTypeSkeleton(getDeclFromDeclName, memberDecl.type),
|
|
23
23
|
}, Object.keys(type.properties)));
|
|
24
|
-
}, disabled: disabled, children: ["Add ", toTitleCase(key)] })) : (_jsxs("button", { class: "destructive", onClick: () => {
|
|
24
|
+
}, disabled: disabled, children: ["Add ", memberDecl.displayName ?? toTitleCase(key)] })) : (_jsxs("button", { class: "destructive", onClick: () => {
|
|
25
25
|
const newObj = { ...value };
|
|
26
26
|
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
27
27
|
delete newObj[key];
|
|
28
28
|
onChange(newObj);
|
|
29
|
-
}, disabled: disabled, children: ["Remove ", toTitleCase(key)] }))] }), memberDecl.isRequired || value[key] !== undefined ? (_jsx(TypeInput, { ...props, parentKey: undefined, type: memberDecl.type, path: path === undefined ? key : `${path}.${key}`, value: value[key], onChange: newItem => {
|
|
29
|
+
}, disabled: disabled, children: ["Remove ", memberDecl.displayName ?? toTitleCase(key)] }))] }), memberDecl.isRequired || value[key] !== undefined ? (_jsx(TypeInput, { ...props, parentKey: undefined, type: memberDecl.type, path: path === undefined ? key : `${path}.${key}`, value: value[key], onChange: newItem => {
|
|
30
30
|
onChange(sortObjectKeys({ ...value, [key]: newItem }, Object.keys(type.properties)));
|
|
31
31
|
} })) : null] }, key))) }), _jsx(ValidationErrors, { disabled: disabled, errors: errors })] }));
|
|
32
32
|
};
|
|
@@ -36,8 +36,9 @@ export const Entity = () => {
|
|
|
36
36
|
.catch(logAndAlertError);
|
|
37
37
|
}, [latestCommit, reloadInstances, reloadLocaleInstances]);
|
|
38
38
|
useEffect(() => {
|
|
39
|
-
document.title =
|
|
40
|
-
|
|
39
|
+
document.title =
|
|
40
|
+
(entity?.displayNamePlural ?? toTitleCase(entity?.namePlural ?? name ?? "")) + " — TSONDB";
|
|
41
|
+
}, [entity?.displayNamePlural, entity?.namePlural, name]);
|
|
41
42
|
useEffect(() => {
|
|
42
43
|
if (created) {
|
|
43
44
|
const instanceElement = document.getElementById(`instance-${created}`);
|
|
@@ -34,7 +34,7 @@ export const Home = () => {
|
|
|
34
34
|
},
|
|
35
35
|
].filter(section => section.entities.length > 0)
|
|
36
36
|
: undefined;
|
|
37
|
-
const mapEntity = (entity) => (_jsxs("li", { class: "entries-item", children: [_jsxs("div", { class: "entries-item__title", children: [_jsx("h2", { children: toTitleCase(entity.declaration.namePlural) }), entity.declaration.comment && (_jsx(Markdown, { class: "description", string: entity.declaration.comment }))] }), _jsxs("p", { class: "entries-item__subtitle", children: [entity.instanceCount, " instance", entity.instanceCount === 1 ? "" : "s"] }), _jsx("div", { class: "entries-item__side", children: _jsx("div", { class: "btns", children: _jsx("a", { href: `/entities/${entity.declaration.name}`, class: "btn", children: "View" }) }) })] }, entity.declaration.name));
|
|
37
|
+
const mapEntity = (entity) => (_jsxs("li", { class: "entries-item", children: [_jsxs("div", { class: "entries-item__title", children: [_jsx("h2", { children: entity.declaration.displayNamePlural ?? toTitleCase(entity.declaration.namePlural) }), entity.declaration.comment && (_jsx(Markdown, { class: "description", string: entity.declaration.comment }))] }), _jsxs("p", { class: "entries-item__subtitle", children: [entity.instanceCount, " instance", entity.instanceCount === 1 ? "" : "s"] }), _jsx("div", { class: "entries-item__side", children: _jsx("div", { class: "btns", children: _jsx("a", { href: `/entities/${entity.declaration.name}`, class: "btn", children: "View" }) }) })] }, entity.declaration.name));
|
|
38
38
|
return (_jsxs(Layout, { breadcrumbs: [], children: [_jsx("h1", { children: homeTitle }), _jsxs("div", { className: "list-header", children: [_jsxs("p", { class: "instance-count", children: [searchText === "" ? "" : `${filteredEntities.length.toString()} of `, entities.length, " entit", entities.length === 1 ? "y" : "ies"] }), _jsxs("form", { action: "", rel: "search", onSubmit: e => {
|
|
39
39
|
e.preventDefault();
|
|
40
40
|
}, children: [_jsx("label", { htmlFor: "entity-search", class: "visually-hidden", children: "Search" }), _jsx("input", { type: "text", id: "entity-search", value: searchText, onInput: event => {
|
package/package.json
CHANGED
package/public/css/styles.css
CHANGED
|
@@ -856,6 +856,13 @@ form > .field--container {
|
|
|
856
856
|
margin: 0.125rem 0 0;
|
|
857
857
|
}
|
|
858
858
|
|
|
859
|
+
.container-item-actions {
|
|
860
|
+
flex: none;
|
|
861
|
+
display: flex;
|
|
862
|
+
gap: 0.5rem;
|
|
863
|
+
margin-left: 1rem;
|
|
864
|
+
}
|
|
865
|
+
|
|
859
866
|
.add-item-container {
|
|
860
867
|
display: flex;
|
|
861
868
|
margin-top: 1rem;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const discriminatorKey = "kind";
|
package/dist/src/shared/enum.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const discriminatorKey = "kind";
|