tsondb 0.1.3
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/README.md +3 -0
- package/lib/ModelContainer.d.ts +17 -0
- package/lib/ModelContainer.js +63 -0
- package/lib/Schema.d.ts +8 -0
- package/lib/Schema.js +72 -0
- package/lib/client/api.d.ts +11 -0
- package/lib/client/api.js +83 -0
- package/lib/client/components/Layout.d.ts +10 -0
- package/lib/client/components/Layout.js +4 -0
- package/lib/client/components/Select.d.ts +3 -0
- package/lib/client/components/Select.js +2 -0
- package/lib/client/components/typeInputs/ArrayTypeInput.d.ts +13 -0
- package/lib/client/components/typeInputs/ArrayTypeInput.js +10 -0
- package/lib/client/components/typeInputs/BooleanTypeInput.d.ts +9 -0
- package/lib/client/components/typeInputs/BooleanTypeInput.js +6 -0
- package/lib/client/components/typeInputs/DateTypeInput.d.ts +9 -0
- package/lib/client/components/typeInputs/DateTypeInput.js +9 -0
- package/lib/client/components/typeInputs/FloatTypeInput.d.ts +9 -0
- package/lib/client/components/typeInputs/FloatTypeInput.js +15 -0
- package/lib/client/components/typeInputs/GenericTypeArgumentIdentifierTypeInput.d.ts +7 -0
- package/lib/client/components/typeInputs/GenericTypeArgumentIdentifierTypeInput.js +4 -0
- package/lib/client/components/typeInputs/IncludeIdentifierTypeInput.d.ts +13 -0
- package/lib/client/components/typeInputs/IncludeIdentifierTypeInput.js +18 -0
- package/lib/client/components/typeInputs/IntegerTypeInput.d.ts +9 -0
- package/lib/client/components/typeInputs/IntegerTypeInput.js +15 -0
- package/lib/client/components/typeInputs/NestedEntityMapTypeInput.d.ts +13 -0
- package/lib/client/components/typeInputs/NestedEntityMapTypeInput.js +25 -0
- package/lib/client/components/typeInputs/ObjectTypeInput.d.ts +13 -0
- package/lib/client/components/typeInputs/ObjectTypeInput.js +20 -0
- package/lib/client/components/typeInputs/ReferenceIdentifierTypeInput.d.ts +11 -0
- package/lib/client/components/typeInputs/ReferenceIdentifierTypeInput.js +9 -0
- package/lib/client/components/typeInputs/StringTypeInput.d.ts +9 -0
- package/lib/client/components/typeInputs/StringTypeInput.js +10 -0
- package/lib/client/components/typeInputs/TypeInput.d.ts +13 -0
- package/lib/client/components/typeInputs/TypeInput.js +87 -0
- package/lib/client/components/typeInputs/utils/EnumDeclField.d.ts +13 -0
- package/lib/client/components/typeInputs/utils/EnumDeclField.js +38 -0
- package/lib/client/components/typeInputs/utils/MismatchingTypeError.d.ts +7 -0
- package/lib/client/components/typeInputs/utils/MismatchingTypeError.js +4 -0
- package/lib/client/components/typeInputs/utils/ValidationErrors.d.ts +6 -0
- package/lib/client/components/typeInputs/utils/ValidationErrors.js +4 -0
- package/lib/client/hooks/useEntityFromRoute.d.ts +5 -0
- package/lib/client/hooks/useEntityFromRoute.js +20 -0
- package/lib/client/hooks/useInstanceNamesByEntity.d.ts +3 -0
- package/lib/client/hooks/useInstanceNamesByEntity.js +18 -0
- package/lib/client/hooks/useSecondaryDeclarations.d.ts +3 -0
- package/lib/client/hooks/useSecondaryDeclarations.js +18 -0
- package/lib/client/index.d.ts +1 -0
- package/lib/client/index.js +11 -0
- package/lib/client/routes/CreateInstance.d.ts +2 -0
- package/lib/client/routes/CreateInstance.js +68 -0
- package/lib/client/routes/Entity.d.ts +2 -0
- package/lib/client/routes/Entity.js +47 -0
- package/lib/client/routes/Home.d.ts +2 -0
- package/lib/client/routes/Home.js +18 -0
- package/lib/client/routes/Instance.d.ts +2 -0
- package/lib/client/routes/Instance.js +73 -0
- package/lib/client/routes/NotFound.d.ts +2 -0
- package/lib/client/routes/NotFound.js +5 -0
- package/lib/client/utils/typeSkeleton.d.ts +3 -0
- package/lib/client/utils/typeSkeleton.js +51 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/renderers/Output.d.ts +4 -0
- package/lib/renderers/Output.js +1 -0
- package/lib/renderers/jsonschema/index.d.ts +6 -0
- package/lib/renderers/jsonschema/index.js +12 -0
- package/lib/renderers/jsonschema/render.d.ts +5 -0
- package/lib/renderers/jsonschema/render.js +156 -0
- package/lib/renderers/ts/index.d.ts +6 -0
- package/lib/renderers/ts/index.js +11 -0
- package/lib/renderers/ts/render.d.ts +5 -0
- package/lib/renderers/ts/render.js +109 -0
- package/lib/schema/Node.d.ts +37 -0
- package/lib/schema/Node.js +79 -0
- package/lib/schema/declarations/Declaration.d.ts +44 -0
- package/lib/schema/declarations/Declaration.js +98 -0
- package/lib/schema/declarations/EntityDecl.d.ts +73 -0
- package/lib/schema/declarations/EntityDecl.js +57 -0
- package/lib/schema/declarations/EnumDecl.d.ts +33 -0
- package/lib/schema/declarations/EnumDecl.js +104 -0
- package/lib/schema/declarations/TypeAliasDecl.d.ts +33 -0
- package/lib/schema/declarations/TypeAliasDecl.js +49 -0
- package/lib/schema/index.d.ts +20 -0
- package/lib/schema/index.js +20 -0
- package/lib/schema/parameters/TypeParameter.d.ts +14 -0
- package/lib/schema/parameters/TypeParameter.js +11 -0
- package/lib/schema/types/Type.d.ts +42 -0
- package/lib/schema/types/Type.js +177 -0
- package/lib/schema/types/generic/ArrayType.d.ts +30 -0
- package/lib/schema/types/generic/ArrayType.js +38 -0
- package/lib/schema/types/generic/ObjectType.d.ts +47 -0
- package/lib/schema/types/generic/ObjectType.js +70 -0
- package/lib/schema/types/primitives/BooleanType.d.ts +15 -0
- package/lib/schema/types/primitives/BooleanType.js +15 -0
- package/lib/schema/types/primitives/DateType.d.ts +16 -0
- package/lib/schema/types/primitives/DateType.js +17 -0
- package/lib/schema/types/primitives/FloatType.d.ts +26 -0
- package/lib/schema/types/primitives/FloatType.js +17 -0
- package/lib/schema/types/primitives/IntegerType.d.ts +26 -0
- package/lib/schema/types/primitives/IntegerType.js +21 -0
- package/lib/schema/types/primitives/NumericType.d.ts +6 -0
- package/lib/schema/types/primitives/NumericType.js +2 -0
- package/lib/schema/types/primitives/PrimitiveType.d.ts +6 -0
- package/lib/schema/types/primitives/PrimitiveType.js +1 -0
- package/lib/schema/types/primitives/StringType.d.ts +25 -0
- package/lib/schema/types/primitives/StringType.js +20 -0
- package/lib/schema/types/references/GenericArgumentIdentifierType.d.ts +21 -0
- package/lib/schema/types/references/GenericArgumentIdentifierType.js +18 -0
- package/lib/schema/types/references/IncludeIdentifierType.d.ts +28 -0
- package/lib/schema/types/references/IncludeIdentifierType.js +25 -0
- package/lib/schema/types/references/NestedEntityMapType.d.ts +36 -0
- package/lib/schema/types/references/NestedEntityMapType.js +67 -0
- package/lib/schema/types/references/ReferenceIdentifierType.d.ts +23 -0
- package/lib/schema/types/references/ReferenceIdentifierType.js +21 -0
- package/lib/schema/validation/options.d.ts +4 -0
- package/lib/schema/validation/options.js +12 -0
- package/lib/schema/validation/type.d.ts +4 -0
- package/lib/schema/validation/type.js +1 -0
- package/lib/server/index.d.ts +8 -0
- package/lib/server/index.js +207 -0
- package/lib/server/instanceOperations.d.ts +7 -0
- package/lib/server/instanceOperations.js +67 -0
- package/lib/shared/api.d.ts +42 -0
- package/lib/shared/api.js +1 -0
- package/lib/shared/enum.d.ts +1 -0
- package/lib/shared/enum.js +1 -0
- package/lib/shared/utils/compare.d.ts +13 -0
- package/lib/shared/utils/compare.js +24 -0
- package/lib/shared/utils/displayName.d.ts +2 -0
- package/lib/shared/utils/displayName.js +31 -0
- package/lib/shared/utils/instances.d.ts +6 -0
- package/lib/shared/utils/instances.js +1 -0
- package/lib/shared/utils/object.d.ts +2 -0
- package/lib/shared/utils/object.js +2 -0
- package/lib/shared/utils/string.d.ts +6 -0
- package/lib/shared/utils/string.js +52 -0
- package/lib/shared/utils/typeSafety.d.ts +1 -0
- package/lib/shared/utils/typeSafety.js +3 -0
- package/lib/shared/utils/validation.d.ts +3 -0
- package/lib/shared/utils/validation.js +14 -0
- package/lib/shared/validation/array.d.ts +6 -0
- package/lib/shared/validation/array.js +29 -0
- package/lib/shared/validation/date.d.ts +4 -0
- package/lib/shared/validation/date.js +13 -0
- package/lib/shared/validation/identifier.d.ts +1 -0
- package/lib/shared/validation/identifier.js +7 -0
- package/lib/shared/validation/number.d.ts +12 -0
- package/lib/shared/validation/number.js +34 -0
- package/lib/shared/validation/object.d.ts +6 -0
- package/lib/shared/validation/object.js +13 -0
- package/lib/shared/validation/string.d.ts +6 -0
- package/lib/shared/validation/string.js +15 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/lib/utils/enum.d.ts +6 -0
- package/lib/utils/enum.js +1 -0
- package/lib/utils/error.d.ts +2 -0
- package/lib/utils/error.js +18 -0
- package/lib/utils/instances.d.ts +4 -0
- package/lib/utils/instances.js +12 -0
- package/lib/utils/lazy.d.ts +16 -0
- package/lib/utils/lazy.js +32 -0
- package/lib/utils/object.d.ts +3 -0
- package/lib/utils/object.js +1 -0
- package/lib/utils/render.d.ts +4 -0
- package/lib/utils/render.js +8 -0
- package/lib/utils/result.d.ts +57 -0
- package/lib/utils/result.js +48 -0
- package/package.json +46 -0
- package/public/css/styles.css +418 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
|
+
import { assertExhaustive } from "../../../shared/utils/typeSafety.js";
|
|
3
|
+
import { ArrayTypeInput } from "./ArrayTypeInput.js";
|
|
4
|
+
import { BooleanTypeInput } from "./BooleanTypeInput.js";
|
|
5
|
+
import { DateTypeInput } from "./DateTypeInput.js";
|
|
6
|
+
import { FloatTypeInput } from "./FloatTypeInput.js";
|
|
7
|
+
import { GenericArgumentIdentifierTypeInput } from "./GenericTypeArgumentIdentifierTypeInput.js";
|
|
8
|
+
import { IncludeIdentifierTypeInput } from "./IncludeIdentifierTypeInput.js";
|
|
9
|
+
import { IntegerTypeInput } from "./IntegerTypeInput.js";
|
|
10
|
+
import { NestedEntityMapTypeInput } from "./NestedEntityMapTypeInput.js";
|
|
11
|
+
import { ObjectTypeInput } from "./ObjectTypeInput.js";
|
|
12
|
+
import { ReferenceIdentifierTypeInput } from "./ReferenceIdentifierTypeInput.js";
|
|
13
|
+
import { StringTypeInput } from "./StringTypeInput.js";
|
|
14
|
+
import { MismatchingTypeError } from "./utils/MismatchingTypeError.js";
|
|
15
|
+
export const TypeInput = ({ type, value, instanceNamesByEntity, getDeclFromDeclName, onChange, }) => {
|
|
16
|
+
switch (type.kind) {
|
|
17
|
+
case "BooleanType":
|
|
18
|
+
if (typeof value === "boolean") {
|
|
19
|
+
return _jsx(BooleanTypeInput, { type: type, value: value, onChange: onChange });
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
return _jsx(MismatchingTypeError, { expected: "boolean", actual: value });
|
|
23
|
+
}
|
|
24
|
+
case "DateType":
|
|
25
|
+
if (typeof value === "string") {
|
|
26
|
+
return _jsx(DateTypeInput, { type: type, value: value, onChange: onChange });
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
return _jsx(MismatchingTypeError, { expected: "date string", actual: value });
|
|
30
|
+
}
|
|
31
|
+
case "FloatType":
|
|
32
|
+
if (typeof value === "number") {
|
|
33
|
+
return _jsx(FloatTypeInput, { type: type, value: value, onChange: onChange });
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
return _jsx(MismatchingTypeError, { expected: "float", actual: value });
|
|
37
|
+
}
|
|
38
|
+
case "IntegerType":
|
|
39
|
+
if (typeof value === "number" && Number.isInteger(value)) {
|
|
40
|
+
return _jsx(IntegerTypeInput, { type: type, value: value, onChange: onChange });
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
return _jsx(MismatchingTypeError, { expected: "integer", actual: value });
|
|
44
|
+
}
|
|
45
|
+
case "StringType":
|
|
46
|
+
if (typeof value === "string") {
|
|
47
|
+
return _jsx(StringTypeInput, { type: type, value: value, onChange: onChange });
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
return _jsx(MismatchingTypeError, { expected: "string", actual: value });
|
|
51
|
+
}
|
|
52
|
+
case "ArrayType":
|
|
53
|
+
if (Array.isArray(value)) {
|
|
54
|
+
return (_jsx(ArrayTypeInput, { type: type, value: value, instanceNamesByEntity: instanceNamesByEntity, getDeclFromDeclName: getDeclFromDeclName, onChange: onChange }));
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
return _jsx(MismatchingTypeError, { expected: "array", actual: value });
|
|
58
|
+
}
|
|
59
|
+
case "ObjectType":
|
|
60
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
61
|
+
return (_jsx(ObjectTypeInput, { type: type, value: value, instanceNamesByEntity: instanceNamesByEntity, getDeclFromDeclName: getDeclFromDeclName, onChange: onChange }));
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
return _jsx(MismatchingTypeError, { expected: "object", actual: value });
|
|
65
|
+
}
|
|
66
|
+
case "GenericArgumentIdentifierType":
|
|
67
|
+
return _jsx(GenericArgumentIdentifierTypeInput, { type: type });
|
|
68
|
+
case "ReferenceIdentifierType":
|
|
69
|
+
if (typeof value === "string") {
|
|
70
|
+
return (_jsx(ReferenceIdentifierTypeInput, { type: type, value: value, instanceNamesByEntity: instanceNamesByEntity, onChange: onChange }));
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
return _jsx(MismatchingTypeError, { expected: "string identifier", actual: value });
|
|
74
|
+
}
|
|
75
|
+
case "IncludeIdentifierType":
|
|
76
|
+
return (_jsx(IncludeIdentifierTypeInput, { type: type, value: value, instanceNamesByEntity: instanceNamesByEntity, getDeclFromDeclName: getDeclFromDeclName, onChange: onChange }));
|
|
77
|
+
case "NestedEntityMapType":
|
|
78
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
79
|
+
return (_jsx(NestedEntityMapTypeInput, { type: type, value: value, instanceNamesByEntity: instanceNamesByEntity, getDeclFromDeclName: getDeclFromDeclName, onChange: onChange }));
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
return _jsx(MismatchingTypeError, { expected: "entity map", actual: value });
|
|
83
|
+
}
|
|
84
|
+
default:
|
|
85
|
+
return assertExhaustive(type);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { FunctionComponent } from "preact";
|
|
2
|
+
import { SerializedEnumDecl } from "../../../../schema/declarations/EnumDecl.js";
|
|
3
|
+
import { InstanceNamesByEntity } from "../../../hooks/useInstanceNamesByEntity.js";
|
|
4
|
+
import { GetDeclFromDeclName } from "../../../hooks/useSecondaryDeclarations.js";
|
|
5
|
+
type Props = {
|
|
6
|
+
decl: SerializedEnumDecl;
|
|
7
|
+
value: unknown;
|
|
8
|
+
instanceNamesByEntity: InstanceNamesByEntity;
|
|
9
|
+
getDeclFromDeclName: GetDeclFromDeclName;
|
|
10
|
+
onChange: (value: unknown) => void;
|
|
11
|
+
};
|
|
12
|
+
export declare const EnumDeclField: FunctionComponent<Props>;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { discriminatorKey } from "../../../../shared/enum.js";
|
|
3
|
+
import { toTitleCase } from "../../../../shared/utils/string.js";
|
|
4
|
+
import { createTypeSkeleton } from "../../../utils/typeSkeleton.js";
|
|
5
|
+
import { Select } from "../../Select.js";
|
|
6
|
+
import { TypeInput } from "../TypeInput.js";
|
|
7
|
+
import { MismatchingTypeError } from "./MismatchingTypeError.js";
|
|
8
|
+
export const EnumDeclField = ({ decl, value, instanceNamesByEntity, getDeclFromDeclName, onChange, }) => {
|
|
9
|
+
if (typeof value !== "object" ||
|
|
10
|
+
value === null ||
|
|
11
|
+
Array.isArray(value) ||
|
|
12
|
+
!(discriminatorKey in value) ||
|
|
13
|
+
typeof value[discriminatorKey] !== "string") {
|
|
14
|
+
return _jsx(MismatchingTypeError, { expected: "enumeration value", actual: value });
|
|
15
|
+
}
|
|
16
|
+
const enumValues = Object.keys(decl.values);
|
|
17
|
+
const activeEnumCase = value[discriminatorKey];
|
|
18
|
+
const associatedType = decl.values[activeEnumCase];
|
|
19
|
+
return (_jsxs("div", { class: "field field--enum", children: [_jsx(Select, { value: activeEnumCase, onInput: event => {
|
|
20
|
+
const associatedType = decl.values[event.currentTarget.value];
|
|
21
|
+
if (associatedType == null) {
|
|
22
|
+
onChange({
|
|
23
|
+
[discriminatorKey]: event.currentTarget.value,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
onChange({
|
|
28
|
+
[discriminatorKey]: event.currentTarget.value,
|
|
29
|
+
[event.currentTarget.value]: createTypeSkeleton(getDeclFromDeclName, associatedType),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}, children: enumValues.map(enumValue => (_jsx("option", { value: enumValue, selected: enumValue === activeEnumCase, children: toTitleCase(enumValue) }))) }), associatedType == null ? null : (_jsx("div", { className: "associated-type", children: _jsx(TypeInput, { type: associatedType, value: value[activeEnumCase], instanceNamesByEntity: instanceNamesByEntity, getDeclFromDeclName: getDeclFromDeclName, onChange: newValue => {
|
|
33
|
+
onChange({
|
|
34
|
+
[discriminatorKey]: activeEnumCase,
|
|
35
|
+
[activeEnumCase]: newValue,
|
|
36
|
+
});
|
|
37
|
+
} }) }))] }));
|
|
38
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
|
+
export const ValidationErrors = ({ errors }) => {
|
|
3
|
+
return errors.length === 0 ? null : (_jsx("div", { role: "alert", class: "validation-errors", children: _jsx("ul", { children: errors.map((error, i) => (_jsx("li", { children: error.message }, i))) }) }));
|
|
4
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useRoute } from "preact-iso";
|
|
2
|
+
import { useEffect, useMemo, useState } from "preact/hooks";
|
|
3
|
+
import { getEntityByName } from "../api.js";
|
|
4
|
+
export const useEntityFromRoute = () => {
|
|
5
|
+
const { params: { name }, } = useRoute();
|
|
6
|
+
const [entityData, setEntityData] = useState();
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (name) {
|
|
9
|
+
getEntityByName(name)
|
|
10
|
+
.then(data => {
|
|
11
|
+
setEntityData(data);
|
|
12
|
+
})
|
|
13
|
+
.catch(error => {
|
|
14
|
+
console.error("Error fetching data:", error);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}, [name]);
|
|
18
|
+
const entityObj = useMemo(() => entityData && { entity: entityData.declaration, isLocaleEntity: entityData.isLocaleEntity }, [entityData]);
|
|
19
|
+
return entityObj;
|
|
20
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useEffect, useState } from "preact/hooks";
|
|
2
|
+
import { getAllInstances } from "../api.js";
|
|
3
|
+
export const useInstanceNamesByEntity = (locales = []) => {
|
|
4
|
+
const [instanceNamesByEntity, setInstanceNamesByEntity] = useState({});
|
|
5
|
+
const updateInstanceNamesByEntity = () => {
|
|
6
|
+
getAllInstances(locales)
|
|
7
|
+
.then(data => {
|
|
8
|
+
setInstanceNamesByEntity(data.instances);
|
|
9
|
+
})
|
|
10
|
+
.catch(error => {
|
|
11
|
+
console.error("Error fetching data:", error);
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
updateInstanceNamesByEntity();
|
|
16
|
+
}, []);
|
|
17
|
+
return [instanceNamesByEntity, updateInstanceNamesByEntity];
|
|
18
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from "preact/hooks";
|
|
2
|
+
import { getAllDeclarations } from "../api.js";
|
|
3
|
+
export const useGetDeclFromDeclName = () => {
|
|
4
|
+
const [secondaryDeclarations, setSecondaryDeclarations] = useState([]);
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
getAllDeclarations()
|
|
7
|
+
.then(data => {
|
|
8
|
+
setSecondaryDeclarations(data.declarations
|
|
9
|
+
.map(decl => decl.declaration)
|
|
10
|
+
.filter((decl) => decl.kind === "EnumDecl" || decl.kind === "TypeAliasDecl"));
|
|
11
|
+
})
|
|
12
|
+
.catch(error => {
|
|
13
|
+
console.error("Error fetching data:", error);
|
|
14
|
+
});
|
|
15
|
+
}, []);
|
|
16
|
+
const getDeclFromDeclName = useCallback((name) => secondaryDeclarations.find(decl => decl.name === name), [secondaryDeclarations]);
|
|
17
|
+
return getDeclFromDeclName;
|
|
18
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { render } from "preact";
|
|
3
|
+
import { LocationProvider, Route, Router } from "preact-iso";
|
|
4
|
+
import { CreateInstance } from "./routes/CreateInstance.js";
|
|
5
|
+
import { Entity } from "./routes/Entity.js";
|
|
6
|
+
import { Home } from "./routes/Home.js";
|
|
7
|
+
import { Instance } from "./routes/Instance.js";
|
|
8
|
+
import { NotFound } from "./routes/NotFound.js";
|
|
9
|
+
const App = () => (_jsx(LocationProvider, { children: _jsxs(Router, { children: [_jsx(Route, { path: "/", component: Home }), _jsx(Route, { path: "/entities/:name", component: Entity }), _jsx(Route, { path: "/entities/:name/instances/create", component: CreateInstance }), _jsx(Route, { path: "/entities/:name/instances/:id", component: Instance }), _jsx(Route, { default: true, component: NotFound })] }) }));
|
|
10
|
+
const root = document.getElementById("app");
|
|
11
|
+
render(_jsx(App, {}), root);
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { useLocation, useRoute } from "preact-iso";
|
|
3
|
+
import { useEffect, useState } from "preact/hooks";
|
|
4
|
+
import { getDisplayNameFromEntityInstance } from "../../shared/utils/displayName.js";
|
|
5
|
+
import { toTitleCase } from "../../shared/utils/string.js";
|
|
6
|
+
import { validateLocaleIdentifier } from "../../shared/validation/identifier.js";
|
|
7
|
+
import { createInstanceByEntityNameAndId } from "../api.js";
|
|
8
|
+
import { Layout } from "../components/Layout.js";
|
|
9
|
+
import { TypeInput } from "../components/typeInputs/TypeInput.js";
|
|
10
|
+
import { ValidationErrors } from "../components/typeInputs/utils/ValidationErrors.js";
|
|
11
|
+
import { useEntityFromRoute } from "../hooks/useEntityFromRoute.js";
|
|
12
|
+
import { useInstanceNamesByEntity } from "../hooks/useInstanceNamesByEntity.js";
|
|
13
|
+
import { useGetDeclFromDeclName } from "../hooks/useSecondaryDeclarations.js";
|
|
14
|
+
import { createTypeSkeleton } from "../utils/typeSkeleton.js";
|
|
15
|
+
import { NotFound } from "./NotFound.js";
|
|
16
|
+
export const CreateInstance = () => {
|
|
17
|
+
const { params: { name }, } = useRoute();
|
|
18
|
+
const getDeclFromDeclName = useGetDeclFromDeclName();
|
|
19
|
+
const entityFromRoute = useEntityFromRoute();
|
|
20
|
+
const [instanceNamesByEntity] = useInstanceNamesByEntity();
|
|
21
|
+
const [instance, setInstance] = useState();
|
|
22
|
+
const [customId, setCustomId] = useState("");
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (entityFromRoute) {
|
|
25
|
+
setInstance(createTypeSkeleton(getDeclFromDeclName, entityFromRoute.entity.type));
|
|
26
|
+
}
|
|
27
|
+
}, [getDeclFromDeclName, entityFromRoute]);
|
|
28
|
+
const { route } = useLocation();
|
|
29
|
+
if (!name) {
|
|
30
|
+
return _jsx(NotFound, {});
|
|
31
|
+
}
|
|
32
|
+
if (!entityFromRoute) {
|
|
33
|
+
return (_jsxs("div", { children: [_jsx("h1", { children: name }), _jsx("p", { className: "loading", children: "Loading \u2026" })] }));
|
|
34
|
+
}
|
|
35
|
+
const { entity, isLocaleEntity } = entityFromRoute;
|
|
36
|
+
const handleSubmit = (event) => {
|
|
37
|
+
event.preventDefault();
|
|
38
|
+
const name = event.submitter?.getAttribute("name");
|
|
39
|
+
if (name) {
|
|
40
|
+
createInstanceByEntityNameAndId(entity.name, instance, isLocaleEntity ? customId : undefined)
|
|
41
|
+
.then(createdInstance => {
|
|
42
|
+
if (name === "saveandaddanother") {
|
|
43
|
+
setInstance(createTypeSkeleton(getDeclFromDeclName, entity.type));
|
|
44
|
+
setCustomId("");
|
|
45
|
+
alert(`Instance of entity ${entity.name} created successfully with identifier ${createdInstance.instance.id}. You can add another instance now.`);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
route(`/entities/${entity.name}?created=${encodeURIComponent(createdInstance.instance.id)}`);
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
.catch(error => {
|
|
52
|
+
alert(`Error updating instance:\n\n${error}`);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const defaultName = customId || `New ${toTitleCase(entity.name)}`;
|
|
57
|
+
const instanceName = getDisplayNameFromEntityInstance(entity, instance, defaultName);
|
|
58
|
+
const idErrors = isLocaleEntity ? validateLocaleIdentifier(customId) : [];
|
|
59
|
+
return (_jsxs(Layout, { breadcrumbs: [
|
|
60
|
+
{ url: "/", label: "Home" },
|
|
61
|
+
{ url: `/entities/${entity.name}`, label: entity.name },
|
|
62
|
+
], children: [_jsx("div", { class: "header-with-btns", children: _jsx("h1", { class: instanceName.length === 0 ? "empty-name" : undefined, children: instanceName || defaultName }) }), isLocaleEntity && (_jsxs("div", { class: "field field--id", children: [_jsx("label", { htmlFor: "id", children: "ID" }), _jsx("p", { className: "comment", children: "The instance\u2019s identifier. An IETF language tag (BCP47)." }), _jsx("input", { type: "text", id: "id", value: customId, required: true, pattern: "[a-z]{2,3}(-[A-Z]{2,3})?", placeholder: "en-US, de-DE, \u2026", onInput: event => {
|
|
63
|
+
setCustomId(event.currentTarget.value);
|
|
64
|
+
}, "aria-invalid": idErrors.length > 0 }), _jsx(ValidationErrors, { errors: idErrors })] })), _jsxs("form", { onSubmit: handleSubmit, children: [_jsx(TypeInput, { type: entity.type, value: instance, instanceNamesByEntity: instanceNamesByEntity, getDeclFromDeclName: getDeclFromDeclName, onChange: value => {
|
|
65
|
+
console.log("onChange", value);
|
|
66
|
+
setInstance(value);
|
|
67
|
+
} }), _jsxs("div", { className: "btns", children: [_jsx("button", { type: "submit", class: "primary", name: "save", children: "Save" }), _jsx("button", { type: "submit", class: "primary", name: "saveandaddanother", children: "Save and Add Another" })] })] })] }));
|
|
68
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { useRoute } from "preact-iso";
|
|
3
|
+
import { useEffect, useState } from "preact/hooks";
|
|
4
|
+
import { getDisplayNameFromEntityInstance } from "../../shared/utils/displayName.js";
|
|
5
|
+
import { deleteInstanceByEntityNameAndId, getEntityByName, getInstancesByEntityName, } from "../api.js";
|
|
6
|
+
import { Layout } from "../components/Layout.js";
|
|
7
|
+
import { NotFound } from "./NotFound.js";
|
|
8
|
+
export const Entity = () => {
|
|
9
|
+
const { params: { name }, query: { created }, } = useRoute();
|
|
10
|
+
const [entity, setEntity] = useState();
|
|
11
|
+
const [instances, setInstances] = useState();
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (name) {
|
|
14
|
+
Promise.all([getEntityByName(name), getInstancesByEntityName(name)])
|
|
15
|
+
.then(([entityData, instancesData]) => {
|
|
16
|
+
setEntity(entityData);
|
|
17
|
+
setInstances(instancesData.instances);
|
|
18
|
+
})
|
|
19
|
+
.catch(error => {
|
|
20
|
+
console.error("Error fetching entities:", error);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
if (created) {
|
|
24
|
+
const instanceElement = document.getElementById(`instance-${created}`);
|
|
25
|
+
if (instanceElement) {
|
|
26
|
+
instanceElement.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}, []);
|
|
30
|
+
if (!name) {
|
|
31
|
+
return _jsx(NotFound, {});
|
|
32
|
+
}
|
|
33
|
+
if (!entity || !instances) {
|
|
34
|
+
return (_jsxs("div", { children: [_jsx("h1", { children: name }), _jsx("p", { className: "loading", children: "Loading \u2026" })] }));
|
|
35
|
+
}
|
|
36
|
+
return (_jsxs(Layout, { breadcrumbs: [{ url: "/", label: "Home" }], children: [_jsxs("div", { class: "header-with-btns", children: [_jsx("h1", { children: name }), _jsx("a", { class: "btn btn--primary", href: `/entities/${entity.declaration.name}/instances/create`, children: "Add" })] }), entity.declaration.comment && _jsx("p", { className: "description", children: entity.declaration.comment }), _jsxs("p", { children: [instances.length, " instance", instances.length === 1 ? "" : "s"] }), _jsx("ul", { class: "instances", children: instances.map(instance => (_jsxs("li", { id: `instance-${instance.id}`, class: `instance-item ${created === instance.id ? "instance-item--created" : ""}`, children: [_jsx("h2", { children: getDisplayNameFromEntityInstance(entity.declaration, instance.content, instance.id) }), _jsx("p", { "aria-hidden": true, class: "id", children: instance.id }), _jsxs("div", { className: "btns", children: [_jsx("a", { href: `/entities/${entity.declaration.name}/instances/${instance.id}`, class: "btn", children: "Edit" }), _jsx("button", { class: "destructive", onClick: () => {
|
|
37
|
+
if (confirm("Are you sure you want to delete this instance?")) {
|
|
38
|
+
deleteInstanceByEntityNameAndId(entity.declaration.name, instance.id)
|
|
39
|
+
.then(() => {
|
|
40
|
+
setInstances(instances.filter(i => i.id !== instance.id));
|
|
41
|
+
})
|
|
42
|
+
.catch(error => {
|
|
43
|
+
alert("Error deleting instance:\n\n" + error);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}, children: "Delete" })] })] }, instance.id))) })] }));
|
|
47
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "preact/hooks";
|
|
3
|
+
import { toTitleCase } from "../../shared/utils/string.js";
|
|
4
|
+
import { getAllEntities } from "../api.js";
|
|
5
|
+
import { Layout } from "../components/Layout.js";
|
|
6
|
+
export const Home = () => {
|
|
7
|
+
const [entities, setEntities] = useState([]);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
getAllEntities()
|
|
10
|
+
.then(data => {
|
|
11
|
+
setEntities(data.declarations.sort((a, b) => a.declaration.name.localeCompare(b.declaration.name)));
|
|
12
|
+
})
|
|
13
|
+
.catch(error => {
|
|
14
|
+
console.error("Error fetching entities:", error);
|
|
15
|
+
});
|
|
16
|
+
}, []);
|
|
17
|
+
return (_jsxs(Layout, { breadcrumbs: [{ url: "/", label: "Home" }], children: [_jsx("h1", { children: "Entities" }), _jsx("ul", { class: "entities", children: entities.map(entity => (_jsxs("li", { class: "entity-item", children: [_jsxs("div", { className: "title", children: [_jsx("h2", { children: toTitleCase(entity.declaration.name) }), entity.declaration.comment && _jsx("p", { children: entity.declaration.comment })] }), _jsxs("p", { class: "meta", children: [entity.instanceCount, " instance", entity.instanceCount === 1 ? "" : "s"] }), _jsx("div", { className: "btns", children: _jsx("a", { href: `/entities/${entity.declaration.name}`, class: "btn", children: "View" }) })] }, entity.declaration.name))) })] }));
|
|
18
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { useLocation, useRoute } from "preact-iso";
|
|
3
|
+
import { useEffect, useMemo, useState } from "preact/hooks";
|
|
4
|
+
import { deepEqual } from "../../shared/utils/compare.js";
|
|
5
|
+
import { getDisplayNameFromEntityInstance } from "../../shared/utils/displayName.js";
|
|
6
|
+
import { deleteInstanceByEntityNameAndId, getInstanceByEntityNameAndId, updateInstanceByEntityNameAndId, } from "../api.js";
|
|
7
|
+
import { Layout } from "../components/Layout.js";
|
|
8
|
+
import { TypeInput } from "../components/typeInputs/TypeInput.js";
|
|
9
|
+
import { useEntityFromRoute } from "../hooks/useEntityFromRoute.js";
|
|
10
|
+
import { useInstanceNamesByEntity } from "../hooks/useInstanceNamesByEntity.js";
|
|
11
|
+
import { useGetDeclFromDeclName } from "../hooks/useSecondaryDeclarations.js";
|
|
12
|
+
import { NotFound } from "./NotFound.js";
|
|
13
|
+
export const Instance = () => {
|
|
14
|
+
const { params: { name, id }, } = useRoute();
|
|
15
|
+
const getDeclFromDeclName = useGetDeclFromDeclName();
|
|
16
|
+
const entityFromRoute = useEntityFromRoute();
|
|
17
|
+
const [instanceNamesByEntity] = useInstanceNamesByEntity();
|
|
18
|
+
const [instance, setInstance] = useState();
|
|
19
|
+
const [originalInstance, setOriginalInstance] = useState();
|
|
20
|
+
const { route } = useLocation();
|
|
21
|
+
const hasChanges = useMemo(() => !deepEqual(instance?.content, originalInstance?.content), [instance?.content, originalInstance?.content]);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (name && id) {
|
|
24
|
+
getInstanceByEntityNameAndId(name, id)
|
|
25
|
+
.then(instanceData => {
|
|
26
|
+
setInstance(instanceData.instance);
|
|
27
|
+
setOriginalInstance(instanceData.instance);
|
|
28
|
+
})
|
|
29
|
+
.catch(error => {
|
|
30
|
+
console.error("Error fetching entities:", error);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}, []);
|
|
34
|
+
const handleSubmit = (event) => {
|
|
35
|
+
event.preventDefault();
|
|
36
|
+
if (name && id && instance) {
|
|
37
|
+
updateInstanceByEntityNameAndId(name, id, instance.content)
|
|
38
|
+
.then(updatedInstance => {
|
|
39
|
+
0;
|
|
40
|
+
setInstance(updatedInstance.instance);
|
|
41
|
+
setOriginalInstance(updatedInstance.instance);
|
|
42
|
+
})
|
|
43
|
+
.catch(error => {
|
|
44
|
+
alert(`Error updating instance:\n\n${error}`);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
if (!name || !id) {
|
|
49
|
+
return _jsx(NotFound, {});
|
|
50
|
+
}
|
|
51
|
+
if (!entityFromRoute || !instance || !originalInstance) {
|
|
52
|
+
return (_jsxs(Layout, { breadcrumbs: [
|
|
53
|
+
{ url: "/", label: "Home" },
|
|
54
|
+
{ url: `/entities/${name}`, label: name },
|
|
55
|
+
], children: [_jsx("h1", { children: id }), _jsx("p", { className: "loading", children: "Loading \u2026" })] }));
|
|
56
|
+
}
|
|
57
|
+
const defaultName = id;
|
|
58
|
+
const instanceName = getDisplayNameFromEntityInstance(entityFromRoute.entity, instance.content, defaultName);
|
|
59
|
+
return (_jsxs(Layout, { breadcrumbs: [
|
|
60
|
+
{ url: "/", label: "Home" },
|
|
61
|
+
{ url: `/entities/${name}`, label: entityFromRoute.entity.name },
|
|
62
|
+
], children: [_jsxs("div", { class: "header-with-btns", children: [_jsxs("h1", { class: instanceName.length === 0 ? "empty-name" : undefined, children: [_jsx("span", { children: instanceName || defaultName }), " ", _jsx("span", { className: "id", "aria-hidden": true, children: instance.id })] }), _jsx("button", { class: "destructive", onClick: () => {
|
|
63
|
+
if (confirm("Are you sure you want to delete this instance?")) {
|
|
64
|
+
deleteInstanceByEntityNameAndId(entityFromRoute.entity.name, instance.id)
|
|
65
|
+
.then(() => {
|
|
66
|
+
route(`/entities/${name}`);
|
|
67
|
+
})
|
|
68
|
+
.catch(error => {
|
|
69
|
+
alert("Error deleting instance:\n\n" + error);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}, children: "Delete" })] }), _jsxs("form", { onSubmit: handleSubmit, children: [_jsx(TypeInput, { type: entityFromRoute.entity.type, value: instance.content, instanceNamesByEntity: instanceNamesByEntity, getDeclFromDeclName: getDeclFromDeclName, onChange: value => setInstance(container => ({ ...container, content: value })) }), _jsx("button", { type: "submit", disabled: !hasChanges, class: "primary", children: "Save" })] })] }));
|
|
73
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { Layout } from "../components/Layout.js";
|
|
3
|
+
export const NotFound = () => {
|
|
4
|
+
return (_jsxs(Layout, { breadcrumbs: [{ url: "/", label: "Home" }], children: [_jsx("h1", { children: "404 Not Found" }), _jsx("p", { children: "The page you are looking for does not exist." })] }));
|
|
5
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { assertExhaustive } from "../../shared/utils/typeSafety.js";
|
|
2
|
+
export const createTypeSkeleton = (getDeclFromDeclName, type) => {
|
|
3
|
+
switch (type.kind) {
|
|
4
|
+
case "BooleanType":
|
|
5
|
+
return false;
|
|
6
|
+
case "DateType":
|
|
7
|
+
return type.time === true ? new Date().toISOString() : new Date().toDateString();
|
|
8
|
+
case "FloatType":
|
|
9
|
+
return 0.0;
|
|
10
|
+
case "IntegerType":
|
|
11
|
+
return 0;
|
|
12
|
+
case "StringType":
|
|
13
|
+
return "";
|
|
14
|
+
case "ArrayType":
|
|
15
|
+
return Array.from({ length: type.minItems ?? 0 }, () => createTypeSkeleton(getDeclFromDeclName, type.items));
|
|
16
|
+
case "ObjectType":
|
|
17
|
+
return Object.fromEntries(Object.entries(type.properties).flatMap(([key, memberDecl]) => memberDecl.isRequired
|
|
18
|
+
? [[key, createTypeSkeleton(getDeclFromDeclName, memberDecl.type)]]
|
|
19
|
+
: []));
|
|
20
|
+
case "GenericArgumentIdentifierType":
|
|
21
|
+
return undefined;
|
|
22
|
+
case "ReferenceIdentifierType":
|
|
23
|
+
return "";
|
|
24
|
+
case "IncludeIdentifierType": {
|
|
25
|
+
const referencedDecl = getDeclFromDeclName(type.reference);
|
|
26
|
+
if (referencedDecl === undefined) {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
switch (referencedDecl.kind) {
|
|
30
|
+
case "TypeAliasDecl":
|
|
31
|
+
return createTypeSkeleton(getDeclFromDeclName, referencedDecl.type);
|
|
32
|
+
case "EnumDecl": {
|
|
33
|
+
const firstCase = Object.entries(referencedDecl.values)[0];
|
|
34
|
+
if (firstCase[1] === null) {
|
|
35
|
+
return { kind: firstCase[0] };
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
kind: firstCase[0],
|
|
39
|
+
[firstCase[0]]: createTypeSkeleton(getDeclFromDeclName, firstCase[1]),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
default:
|
|
43
|
+
return assertExhaustive(referencedDecl);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
case "NestedEntityMapType":
|
|
47
|
+
return {};
|
|
48
|
+
default:
|
|
49
|
+
return assertExhaustive(type);
|
|
50
|
+
}
|
|
51
|
+
};
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/lib/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
2
|
+
import { dirname } from "path";
|
|
3
|
+
import { resolveTypeArgumentsInDecls } from "../../schema/index.js";
|
|
4
|
+
import { render } from "./render.js";
|
|
5
|
+
export const JsonSchemaOutput = (options) => ({
|
|
6
|
+
run: async (schema) => {
|
|
7
|
+
await mkdir(dirname(options.targetPath), { recursive: true });
|
|
8
|
+
await writeFile(options.targetPath, render(options.rendererOptions, resolveTypeArgumentsInDecls(schema.declarations)), {
|
|
9
|
+
encoding: "utf-8",
|
|
10
|
+
});
|
|
11
|
+
},
|
|
12
|
+
});
|