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.
Files changed (170) hide show
  1. package/README.md +3 -0
  2. package/lib/ModelContainer.d.ts +17 -0
  3. package/lib/ModelContainer.js +63 -0
  4. package/lib/Schema.d.ts +8 -0
  5. package/lib/Schema.js +72 -0
  6. package/lib/client/api.d.ts +11 -0
  7. package/lib/client/api.js +83 -0
  8. package/lib/client/components/Layout.d.ts +10 -0
  9. package/lib/client/components/Layout.js +4 -0
  10. package/lib/client/components/Select.d.ts +3 -0
  11. package/lib/client/components/Select.js +2 -0
  12. package/lib/client/components/typeInputs/ArrayTypeInput.d.ts +13 -0
  13. package/lib/client/components/typeInputs/ArrayTypeInput.js +10 -0
  14. package/lib/client/components/typeInputs/BooleanTypeInput.d.ts +9 -0
  15. package/lib/client/components/typeInputs/BooleanTypeInput.js +6 -0
  16. package/lib/client/components/typeInputs/DateTypeInput.d.ts +9 -0
  17. package/lib/client/components/typeInputs/DateTypeInput.js +9 -0
  18. package/lib/client/components/typeInputs/FloatTypeInput.d.ts +9 -0
  19. package/lib/client/components/typeInputs/FloatTypeInput.js +15 -0
  20. package/lib/client/components/typeInputs/GenericTypeArgumentIdentifierTypeInput.d.ts +7 -0
  21. package/lib/client/components/typeInputs/GenericTypeArgumentIdentifierTypeInput.js +4 -0
  22. package/lib/client/components/typeInputs/IncludeIdentifierTypeInput.d.ts +13 -0
  23. package/lib/client/components/typeInputs/IncludeIdentifierTypeInput.js +18 -0
  24. package/lib/client/components/typeInputs/IntegerTypeInput.d.ts +9 -0
  25. package/lib/client/components/typeInputs/IntegerTypeInput.js +15 -0
  26. package/lib/client/components/typeInputs/NestedEntityMapTypeInput.d.ts +13 -0
  27. package/lib/client/components/typeInputs/NestedEntityMapTypeInput.js +25 -0
  28. package/lib/client/components/typeInputs/ObjectTypeInput.d.ts +13 -0
  29. package/lib/client/components/typeInputs/ObjectTypeInput.js +20 -0
  30. package/lib/client/components/typeInputs/ReferenceIdentifierTypeInput.d.ts +11 -0
  31. package/lib/client/components/typeInputs/ReferenceIdentifierTypeInput.js +9 -0
  32. package/lib/client/components/typeInputs/StringTypeInput.d.ts +9 -0
  33. package/lib/client/components/typeInputs/StringTypeInput.js +10 -0
  34. package/lib/client/components/typeInputs/TypeInput.d.ts +13 -0
  35. package/lib/client/components/typeInputs/TypeInput.js +87 -0
  36. package/lib/client/components/typeInputs/utils/EnumDeclField.d.ts +13 -0
  37. package/lib/client/components/typeInputs/utils/EnumDeclField.js +38 -0
  38. package/lib/client/components/typeInputs/utils/MismatchingTypeError.d.ts +7 -0
  39. package/lib/client/components/typeInputs/utils/MismatchingTypeError.js +4 -0
  40. package/lib/client/components/typeInputs/utils/ValidationErrors.d.ts +6 -0
  41. package/lib/client/components/typeInputs/utils/ValidationErrors.js +4 -0
  42. package/lib/client/hooks/useEntityFromRoute.d.ts +5 -0
  43. package/lib/client/hooks/useEntityFromRoute.js +20 -0
  44. package/lib/client/hooks/useInstanceNamesByEntity.d.ts +3 -0
  45. package/lib/client/hooks/useInstanceNamesByEntity.js +18 -0
  46. package/lib/client/hooks/useSecondaryDeclarations.d.ts +3 -0
  47. package/lib/client/hooks/useSecondaryDeclarations.js +18 -0
  48. package/lib/client/index.d.ts +1 -0
  49. package/lib/client/index.js +11 -0
  50. package/lib/client/routes/CreateInstance.d.ts +2 -0
  51. package/lib/client/routes/CreateInstance.js +68 -0
  52. package/lib/client/routes/Entity.d.ts +2 -0
  53. package/lib/client/routes/Entity.js +47 -0
  54. package/lib/client/routes/Home.d.ts +2 -0
  55. package/lib/client/routes/Home.js +18 -0
  56. package/lib/client/routes/Instance.d.ts +2 -0
  57. package/lib/client/routes/Instance.js +73 -0
  58. package/lib/client/routes/NotFound.d.ts +2 -0
  59. package/lib/client/routes/NotFound.js +5 -0
  60. package/lib/client/utils/typeSkeleton.d.ts +3 -0
  61. package/lib/client/utils/typeSkeleton.js +51 -0
  62. package/lib/index.d.ts +1 -0
  63. package/lib/index.js +1 -0
  64. package/lib/renderers/Output.d.ts +4 -0
  65. package/lib/renderers/Output.js +1 -0
  66. package/lib/renderers/jsonschema/index.d.ts +6 -0
  67. package/lib/renderers/jsonschema/index.js +12 -0
  68. package/lib/renderers/jsonschema/render.d.ts +5 -0
  69. package/lib/renderers/jsonschema/render.js +156 -0
  70. package/lib/renderers/ts/index.d.ts +6 -0
  71. package/lib/renderers/ts/index.js +11 -0
  72. package/lib/renderers/ts/render.d.ts +5 -0
  73. package/lib/renderers/ts/render.js +109 -0
  74. package/lib/schema/Node.d.ts +37 -0
  75. package/lib/schema/Node.js +79 -0
  76. package/lib/schema/declarations/Declaration.d.ts +44 -0
  77. package/lib/schema/declarations/Declaration.js +98 -0
  78. package/lib/schema/declarations/EntityDecl.d.ts +73 -0
  79. package/lib/schema/declarations/EntityDecl.js +57 -0
  80. package/lib/schema/declarations/EnumDecl.d.ts +33 -0
  81. package/lib/schema/declarations/EnumDecl.js +104 -0
  82. package/lib/schema/declarations/TypeAliasDecl.d.ts +33 -0
  83. package/lib/schema/declarations/TypeAliasDecl.js +49 -0
  84. package/lib/schema/index.d.ts +20 -0
  85. package/lib/schema/index.js +20 -0
  86. package/lib/schema/parameters/TypeParameter.d.ts +14 -0
  87. package/lib/schema/parameters/TypeParameter.js +11 -0
  88. package/lib/schema/types/Type.d.ts +42 -0
  89. package/lib/schema/types/Type.js +177 -0
  90. package/lib/schema/types/generic/ArrayType.d.ts +30 -0
  91. package/lib/schema/types/generic/ArrayType.js +38 -0
  92. package/lib/schema/types/generic/ObjectType.d.ts +47 -0
  93. package/lib/schema/types/generic/ObjectType.js +70 -0
  94. package/lib/schema/types/primitives/BooleanType.d.ts +15 -0
  95. package/lib/schema/types/primitives/BooleanType.js +15 -0
  96. package/lib/schema/types/primitives/DateType.d.ts +16 -0
  97. package/lib/schema/types/primitives/DateType.js +17 -0
  98. package/lib/schema/types/primitives/FloatType.d.ts +26 -0
  99. package/lib/schema/types/primitives/FloatType.js +17 -0
  100. package/lib/schema/types/primitives/IntegerType.d.ts +26 -0
  101. package/lib/schema/types/primitives/IntegerType.js +21 -0
  102. package/lib/schema/types/primitives/NumericType.d.ts +6 -0
  103. package/lib/schema/types/primitives/NumericType.js +2 -0
  104. package/lib/schema/types/primitives/PrimitiveType.d.ts +6 -0
  105. package/lib/schema/types/primitives/PrimitiveType.js +1 -0
  106. package/lib/schema/types/primitives/StringType.d.ts +25 -0
  107. package/lib/schema/types/primitives/StringType.js +20 -0
  108. package/lib/schema/types/references/GenericArgumentIdentifierType.d.ts +21 -0
  109. package/lib/schema/types/references/GenericArgumentIdentifierType.js +18 -0
  110. package/lib/schema/types/references/IncludeIdentifierType.d.ts +28 -0
  111. package/lib/schema/types/references/IncludeIdentifierType.js +25 -0
  112. package/lib/schema/types/references/NestedEntityMapType.d.ts +36 -0
  113. package/lib/schema/types/references/NestedEntityMapType.js +67 -0
  114. package/lib/schema/types/references/ReferenceIdentifierType.d.ts +23 -0
  115. package/lib/schema/types/references/ReferenceIdentifierType.js +21 -0
  116. package/lib/schema/validation/options.d.ts +4 -0
  117. package/lib/schema/validation/options.js +12 -0
  118. package/lib/schema/validation/type.d.ts +4 -0
  119. package/lib/schema/validation/type.js +1 -0
  120. package/lib/server/index.d.ts +8 -0
  121. package/lib/server/index.js +207 -0
  122. package/lib/server/instanceOperations.d.ts +7 -0
  123. package/lib/server/instanceOperations.js +67 -0
  124. package/lib/shared/api.d.ts +42 -0
  125. package/lib/shared/api.js +1 -0
  126. package/lib/shared/enum.d.ts +1 -0
  127. package/lib/shared/enum.js +1 -0
  128. package/lib/shared/utils/compare.d.ts +13 -0
  129. package/lib/shared/utils/compare.js +24 -0
  130. package/lib/shared/utils/displayName.d.ts +2 -0
  131. package/lib/shared/utils/displayName.js +31 -0
  132. package/lib/shared/utils/instances.d.ts +6 -0
  133. package/lib/shared/utils/instances.js +1 -0
  134. package/lib/shared/utils/object.d.ts +2 -0
  135. package/lib/shared/utils/object.js +2 -0
  136. package/lib/shared/utils/string.d.ts +6 -0
  137. package/lib/shared/utils/string.js +52 -0
  138. package/lib/shared/utils/typeSafety.d.ts +1 -0
  139. package/lib/shared/utils/typeSafety.js +3 -0
  140. package/lib/shared/utils/validation.d.ts +3 -0
  141. package/lib/shared/utils/validation.js +14 -0
  142. package/lib/shared/validation/array.d.ts +6 -0
  143. package/lib/shared/validation/array.js +29 -0
  144. package/lib/shared/validation/date.d.ts +4 -0
  145. package/lib/shared/validation/date.js +13 -0
  146. package/lib/shared/validation/identifier.d.ts +1 -0
  147. package/lib/shared/validation/identifier.js +7 -0
  148. package/lib/shared/validation/number.d.ts +12 -0
  149. package/lib/shared/validation/number.js +34 -0
  150. package/lib/shared/validation/object.d.ts +6 -0
  151. package/lib/shared/validation/object.js +13 -0
  152. package/lib/shared/validation/string.d.ts +6 -0
  153. package/lib/shared/validation/string.js +15 -0
  154. package/lib/tsconfig.tsbuildinfo +1 -0
  155. package/lib/utils/enum.d.ts +6 -0
  156. package/lib/utils/enum.js +1 -0
  157. package/lib/utils/error.d.ts +2 -0
  158. package/lib/utils/error.js +18 -0
  159. package/lib/utils/instances.d.ts +4 -0
  160. package/lib/utils/instances.js +12 -0
  161. package/lib/utils/lazy.d.ts +16 -0
  162. package/lib/utils/lazy.js +32 -0
  163. package/lib/utils/object.d.ts +3 -0
  164. package/lib/utils/object.js +1 -0
  165. package/lib/utils/render.d.ts +4 -0
  166. package/lib/utils/render.js +8 -0
  167. package/lib/utils/result.d.ts +57 -0
  168. package/lib/utils/result.js +48 -0
  169. package/package.json +46 -0
  170. 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,7 @@
1
+ import { FunctionComponent } from "preact";
2
+ type Props = {
3
+ expected: string;
4
+ actual: unknown;
5
+ };
6
+ export declare const MismatchingTypeError: FunctionComponent<Props>;
7
+ export {};
@@ -0,0 +1,4 @@
1
+ import { jsxs as _jsxs } from "preact/jsx-runtime";
2
+ export const MismatchingTypeError = ({ expected, actual }) => {
3
+ return (_jsxs("div", { role: "alert", children: ["Expected value of type ", expected, ", but got ", JSON.stringify(actual)] }));
4
+ };
@@ -0,0 +1,6 @@
1
+ import { FunctionComponent } from "preact";
2
+ type Props = {
3
+ errors: Error[];
4
+ };
5
+ export declare const ValidationErrors: FunctionComponent<Props>;
6
+ export {};
@@ -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,5 @@
1
+ import { SerializedEntityDecl } from "../../schema/declarations/EntityDecl.js";
2
+ export declare const useEntityFromRoute: () => {
3
+ entity: SerializedEntityDecl;
4
+ isLocaleEntity: boolean;
5
+ } | undefined;
@@ -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,3 @@
1
+ import { GetAllInstancesResponseBody } from "../../shared/api.js";
2
+ export type InstanceNamesByEntity = GetAllInstancesResponseBody["instances"];
3
+ export declare const useInstanceNamesByEntity: (locales?: string[]) => [InstanceNamesByEntity, () => void];
@@ -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,3 @@
1
+ import { SerializedSecondaryDecl } from "../../schema/declarations/Declaration.js";
2
+ export type GetDeclFromDeclName = (name: string) => SerializedSecondaryDecl | undefined;
3
+ export declare const useGetDeclFromDeclName: () => GetDeclFromDeclName;
@@ -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,2 @@
1
+ import { FunctionalComponent } from "preact";
2
+ export declare const CreateInstance: FunctionalComponent;
@@ -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,2 @@
1
+ import { FunctionalComponent } from "preact";
2
+ export declare const Entity: FunctionalComponent;
@@ -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,2 @@
1
+ import { FunctionalComponent } from "preact";
2
+ export declare const Home: FunctionalComponent;
@@ -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,2 @@
1
+ import { FunctionalComponent } from "preact";
2
+ export declare const Instance: FunctionalComponent;
@@ -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,2 @@
1
+ import { FunctionalComponent } from "preact";
2
+ export declare const NotFound: FunctionalComponent;
@@ -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,3 @@
1
+ import { SerializedType } from "../../schema/types/Type.js";
2
+ import { GetDeclFromDeclName } from "../hooks/useSecondaryDeclarations.js";
3
+ export declare const createTypeSkeleton: (getDeclFromDeclName: GetDeclFromDeclName, type: SerializedType) => unknown;
@@ -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,4 @@
1
+ import { Schema } from "../Schema.js";
2
+ export interface Output {
3
+ run: (schema: Schema) => Promise<void>;
4
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ import { Output } from "../Output.js";
2
+ import { JsonSchemaRendererOptions } from "./render.js";
3
+ export declare const JsonSchemaOutput: (options: {
4
+ targetPath: string;
5
+ rendererOptions?: JsonSchemaRendererOptions;
6
+ }) => Output;
@@ -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
+ });
@@ -0,0 +1,5 @@
1
+ import { Decl } from "../../schema/declarations/Declaration.js";
2
+ export type JsonSchemaRendererOptions = {
3
+ indentation: number;
4
+ };
5
+ export declare const render: (options: Partial<JsonSchemaRendererOptions> | undefined, declarations: readonly Decl[]) => string;