tsondb 0.5.1 → 0.5.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/lib/node/Schema.js +7 -4
- package/lib/node/index.js +3 -1
- package/lib/node/schema/declarations/Declaration.d.ts +2 -1
- package/lib/node/schema/declarations/Declaration.js +22 -0
- package/lib/node/schema/types/Type.js +29 -27
- package/lib/node/schema/types/references/IncludeIdentifierType.js +2 -2
- package/lib/shared/utils/markdown.d.ts +10 -0
- package/lib/shared/utils/markdown.js +52 -8
- package/lib/web/components/typeInputs/ObjectTypeInput.js +2 -1
- package/lib/web/components/typeInputs/StringTypeInput.js +1 -1
- package/lib/web/routes/Entity.js +2 -1
- package/lib/web/routes/Home.js +2 -1
- package/lib/web/{components/typeInputs/utils → utils}/Markdown.d.ts +1 -0
- package/lib/web/utils/Markdown.js +39 -0
- package/package.json +4 -4
- package/public/css/styles.css +21 -9
- package/lib/web/components/typeInputs/utils/Markdown.js +0 -26
package/lib/node/Schema.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { getNestedDeclarations, getParameterNames } from "./schema/declarations/Declaration.js";
|
|
1
|
+
import { getNestedDeclarations, getParameterNames, walkNodeTree, } from "./schema/declarations/Declaration.js";
|
|
2
2
|
import { isEntityDecl } from "./schema/declarations/EntityDecl.js";
|
|
3
3
|
import { isStringType } from "./schema/types/primitives/StringType.js";
|
|
4
|
+
import { isIncludeIdentifierType } from "./schema/types/references/IncludeIdentifierType.js";
|
|
4
5
|
import { isNestedEntityMapType } from "./schema/types/references/NestedEntityMapType.js";
|
|
5
6
|
import { findTypeAtPath } from "./schema/types/Type.js";
|
|
6
7
|
const checkDuplicateIdentifier = (existingDecls, decl) => {
|
|
@@ -14,9 +15,11 @@ const checkDuplicateIdentifier = (existingDecls, decl) => {
|
|
|
14
15
|
const checkParameterNamesShadowing = (decls) => {
|
|
15
16
|
for (const decl of decls) {
|
|
16
17
|
for (const param of getParameterNames(decl)) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
walkNodeTree(node => {
|
|
19
|
+
if (isIncludeIdentifierType(node) && node.reference.name === param) {
|
|
20
|
+
throw new Error(`Parameter name "${param}" shadows declaration name in declaration "${decl.name}".`);
|
|
21
|
+
}
|
|
22
|
+
}, decl);
|
|
20
23
|
}
|
|
21
24
|
}
|
|
22
25
|
};
|
package/lib/node/index.js
CHANGED
|
@@ -21,7 +21,9 @@ export const generateOutputs = async (schema, outputs) => {
|
|
|
21
21
|
}
|
|
22
22
|
};
|
|
23
23
|
const _validate = (dataRootPath, entities, instancesByEntityName) => {
|
|
24
|
-
const errors = entities
|
|
24
|
+
const errors = entities
|
|
25
|
+
.flatMap(entity => parallelizeErrors(instancesByEntityName[entity.name]?.map(instance => wrapErrorsIfAny(`in file "${join(dataRootPath, entity.name, instance.fileName)}"`, validateEntityDecl(createValidators(instancesByEntityName), entity, instance.content))) ?? []))
|
|
26
|
+
.toSorted((a, b) => a.message.localeCompare(b.message));
|
|
25
27
|
if (errors.length === 0) {
|
|
26
28
|
debug("All entities are valid");
|
|
27
29
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { BaseNode, GetReferences, Node, Serializer } from "../Node.js";
|
|
2
2
|
import type { SerializedTypeParameter, TypeParameter } from "../TypeParameter.js";
|
|
3
3
|
import type { EnumCaseDecl, SerializedEnumCaseDecl } from "../types/generic/EnumType.js";
|
|
4
|
-
import type
|
|
4
|
+
import { type SerializedType, type Type } from "../types/Type.js";
|
|
5
5
|
import type { ValidatorHelpers } from "../validation/type.js";
|
|
6
6
|
import type { EntityDecl, SerializedEntityDecl } from "./EntityDecl.js";
|
|
7
7
|
import type { EnumDecl, SerializedEnumDecl } from "./EnumDecl.js";
|
|
@@ -40,6 +40,7 @@ export declare const validateDeclName: (name: string) => void;
|
|
|
40
40
|
export declare const resolveTypeArgumentsInDecl: <Params extends TypeParameter[]>(decl: DeclP<Params>, args: TypeArguments<Params>) => DeclP<[]>;
|
|
41
41
|
export declare const isDeclWithoutTypeParameters: (decl: Decl) => decl is DeclP<[]>;
|
|
42
42
|
export declare const resolveTypeArgumentsInDecls: (decls: readonly Decl[]) => DeclP<[]>[];
|
|
43
|
+
export declare function walkNodeTree(callbackFn: (node: Node) => void, decl: Decl): void;
|
|
43
44
|
export declare const serializeDecl: Serializer<Decl, SerializedDecl>;
|
|
44
45
|
export declare const getReferencesForDecl: GetReferences<Decl>;
|
|
45
46
|
export declare const groupDeclarationsBySourceUrl: (decls: readonly Decl[]) => Partial<Record<string, Decl[]>>;
|
|
@@ -6,6 +6,7 @@ import { getNestedDeclarationsInObjectType } from "../types/generic/ObjectType.j
|
|
|
6
6
|
import { getNestedDeclarationsInIncludeIdentifierType } from "../types/references/IncludeIdentifierType.js";
|
|
7
7
|
import { getNestedDeclarationsInNestedEntityMapType } from "../types/references/NestedEntityMapType.js";
|
|
8
8
|
import { getNestedDeclarationsInReferenceIdentifierType } from "../types/references/ReferenceIdentifierType.js";
|
|
9
|
+
import { walkTypeNodeTree } from "../types/Type.js";
|
|
9
10
|
import { getNestedDeclarationsInEntityDecl, getReferencesForEntityDecl, isEntityDecl, resolveTypeArgumentsInEntityDecl, serializeEntityDecl, validateEntityDecl, } from "./EntityDecl.js";
|
|
10
11
|
import { getNestedDeclarationsInEnumDecl, getReferencesForEnumDecl, isEnumDecl, resolveTypeArgumentsInEnumDecl, serializeEnumDecl, validateEnumDecl, } from "./EnumDecl.js";
|
|
11
12
|
import { getNestedDeclarationsInTypeAliasDecl, getReferencesForTypeAliasDecl, isTypeAliasDecl, resolveTypeArgumentsInTypeAliasDecl, serializeTypeAliasDecl, validateTypeAliasDecl, } from "./TypeAliasDecl.js";
|
|
@@ -77,6 +78,27 @@ export const resolveTypeArgumentsInDecl = (decl, args) => {
|
|
|
77
78
|
};
|
|
78
79
|
export const isDeclWithoutTypeParameters = (decl) => decl.parameters.length === 0;
|
|
79
80
|
export const resolveTypeArgumentsInDecls = (decls) => decls.filter(isDeclWithoutTypeParameters).map(decl => resolveTypeArgumentsInDecl(decl, []));
|
|
81
|
+
export function walkNodeTree(callbackFn, decl) {
|
|
82
|
+
switch (decl.kind) {
|
|
83
|
+
case NodeKind.EntityDecl: {
|
|
84
|
+
callbackFn(decl);
|
|
85
|
+
walkTypeNodeTree(callbackFn, decl.type.value);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
case NodeKind.EnumDecl: {
|
|
89
|
+
callbackFn(decl);
|
|
90
|
+
walkTypeNodeTree(callbackFn, decl.type.value);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
case NodeKind.TypeAliasDecl: {
|
|
94
|
+
callbackFn(decl);
|
|
95
|
+
walkTypeNodeTree(callbackFn, decl.type.value);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
default:
|
|
99
|
+
return assertExhaustive(decl);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
80
102
|
export const serializeDecl = decl => {
|
|
81
103
|
switch (decl.kind) {
|
|
82
104
|
case NodeKind.EntityDecl:
|
|
@@ -71,47 +71,49 @@ export const resolveTypeArgumentsInType = (args, type) => {
|
|
|
71
71
|
};
|
|
72
72
|
export function walkTypeNodeTree(callbackFn, type) {
|
|
73
73
|
switch (type.kind) {
|
|
74
|
-
case NodeKind.ArrayType:
|
|
74
|
+
case NodeKind.ArrayType: {
|
|
75
75
|
callbackFn(type);
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
case NodeKind.ObjectType:
|
|
76
|
+
walkTypeNodeTree(callbackFn, type.items);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
case NodeKind.ObjectType: {
|
|
81
80
|
callbackFn(type);
|
|
82
|
-
{
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
case NodeKind.NestedEntityMapType:
|
|
81
|
+
Object.values(type.properties).forEach(prop => {
|
|
82
|
+
walkTypeNodeTree(callbackFn, prop.type);
|
|
83
|
+
});
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
case NodeKind.NestedEntityMapType: {
|
|
89
87
|
callbackFn(type);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
88
|
+
walkTypeNodeTree(callbackFn, type.type.value);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
94
91
|
case NodeKind.BooleanType:
|
|
95
92
|
case NodeKind.DateType:
|
|
96
93
|
case NodeKind.FloatType:
|
|
97
94
|
case NodeKind.IntegerType:
|
|
98
95
|
case NodeKind.StringType:
|
|
99
96
|
case NodeKind.TypeArgumentType:
|
|
100
|
-
case NodeKind.ReferenceIdentifierType:
|
|
97
|
+
case NodeKind.ReferenceIdentifierType: {
|
|
98
|
+
callbackFn(type);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
101
|
case NodeKind.IncludeIdentifierType: {
|
|
102
102
|
callbackFn(type);
|
|
103
|
+
type.args.forEach(arg => {
|
|
104
|
+
walkTypeNodeTree(callbackFn, arg);
|
|
105
|
+
});
|
|
103
106
|
return;
|
|
104
107
|
}
|
|
105
|
-
case NodeKind.EnumType:
|
|
108
|
+
case NodeKind.EnumType: {
|
|
106
109
|
callbackFn(type);
|
|
107
|
-
{
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
110
|
+
Object.values(type.values).forEach(value => {
|
|
111
|
+
if (value.type) {
|
|
112
|
+
walkTypeNodeTree(callbackFn, value.type);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
115
117
|
default:
|
|
116
118
|
return assertExhaustive(type);
|
|
117
119
|
}
|
|
@@ -15,9 +15,9 @@ export const IncludeIdentifierType = (reference) => ({
|
|
|
15
15
|
});
|
|
16
16
|
export { IncludeIdentifierType as IncludeIdentifier };
|
|
17
17
|
export const isIncludeIdentifierType = (node) => node.kind === NodeKind.IncludeIdentifierType;
|
|
18
|
-
export const getNestedDeclarationsInIncludeIdentifierType = (addedDecls, type) => addedDecls.includes(type.reference)
|
|
18
|
+
export const getNestedDeclarationsInIncludeIdentifierType = (addedDecls, type) => type.args.reduce((accAddedDecls, arg) => getNestedDeclarations(accAddedDecls, arg), addedDecls.includes(type.reference)
|
|
19
19
|
? addedDecls
|
|
20
|
-
: getNestedDeclarations([type.reference, ...addedDecls], type.reference);
|
|
20
|
+
: getNestedDeclarations([type.reference, ...addedDecls], type.reference));
|
|
21
21
|
export const validateIncludeIdentifierType = (helpers, type, value) => validateDecl(helpers, type.reference, type.args, value);
|
|
22
22
|
export const resolveTypeArgumentsInIncludeIdentifierType = (args, type) => type.args.length === 0
|
|
23
23
|
? type
|
|
@@ -5,10 +5,20 @@ type TextNode = {
|
|
|
5
5
|
export type InlineMarkdownNode = {
|
|
6
6
|
kind: "bold" | "italic";
|
|
7
7
|
content: InlineMarkdownNode[];
|
|
8
|
+
} | {
|
|
9
|
+
kind: "code";
|
|
10
|
+
content: string;
|
|
8
11
|
} | TextNode;
|
|
9
12
|
export type BlockMarkdownNode = {
|
|
10
13
|
kind: "paragraph";
|
|
11
14
|
content: InlineMarkdownNode[];
|
|
15
|
+
} | {
|
|
16
|
+
kind: "list";
|
|
17
|
+
ordered: boolean;
|
|
18
|
+
content: {
|
|
19
|
+
kind: "listitem";
|
|
20
|
+
content: InlineMarkdownNode[];
|
|
21
|
+
}[];
|
|
12
22
|
} | TextNode;
|
|
13
23
|
export declare const parseBlockMarkdown: (text: string) => BlockMarkdownNode[];
|
|
14
24
|
export {};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
const codeRule = {
|
|
2
|
+
pattern: /`(.*?)`/,
|
|
3
|
+
map: result => ({ kind: "code", content: result[1] ?? "" }),
|
|
4
|
+
};
|
|
1
5
|
const boldWithItalicRule = {
|
|
2
6
|
pattern: /\*\*(.*?\*.+?\*.*?)\*\*/,
|
|
3
7
|
map: (result, parseInside) => ({ kind: "bold", content: parseInside(result[1] ?? "") }),
|
|
@@ -14,9 +18,14 @@ const italicRule = {
|
|
|
14
18
|
pattern: /\*(.+?)\*/,
|
|
15
19
|
map: (result, parseInside) => ({ kind: "italic", content: parseInside(result[1] ?? "") }),
|
|
16
20
|
};
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
const inlineRules = [
|
|
22
|
+
codeRule,
|
|
23
|
+
boldWithItalicRule,
|
|
24
|
+
italicWithBoldRule,
|
|
25
|
+
boldRule,
|
|
26
|
+
italicRule,
|
|
27
|
+
];
|
|
28
|
+
const parseForInlineRules = (rules, text) => {
|
|
20
29
|
if (text.length === 0) {
|
|
21
30
|
return [];
|
|
22
31
|
}
|
|
@@ -30,13 +39,48 @@ const parseForRules = (rules, text) => {
|
|
|
30
39
|
const before = text.slice(0, index);
|
|
31
40
|
const after = text.slice(index + res[0].length);
|
|
32
41
|
return [
|
|
33
|
-
...(before.length > 0 ?
|
|
34
|
-
activeRule.map(res, text =>
|
|
35
|
-
...(after.length > 0 ?
|
|
42
|
+
...(before.length > 0 ? parseForInlineRules(rules.slice(1), before) : []),
|
|
43
|
+
activeRule.map(res, text => parseForInlineRules(rules.slice(1), text)),
|
|
44
|
+
...(after.length > 0 ? parseForInlineRules(rules, after) : []),
|
|
36
45
|
];
|
|
37
46
|
}
|
|
38
47
|
else {
|
|
39
|
-
return
|
|
48
|
+
return parseForInlineRules(rules.slice(1), text);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const parseInlineMarkdown = (text) => parseForInlineRules(inlineRules, text);
|
|
52
|
+
const listRule = {
|
|
53
|
+
pattern: /^((?:(?:\d+\.|[-*]) [^\n]+?)(?:\n(?:\d+\.|[-*]) [^\n]+?)*)(?:\n{2,}|$)/,
|
|
54
|
+
map: result => ({
|
|
55
|
+
kind: "list",
|
|
56
|
+
ordered: /^\d+\. /.test(result[0]),
|
|
57
|
+
content: (result[1] ?? "").split("\n").map(item => ({
|
|
58
|
+
kind: "listitem",
|
|
59
|
+
content: parseInlineMarkdown(item.replace(/^\d+\. |[-*] /, "")),
|
|
60
|
+
})),
|
|
61
|
+
}),
|
|
62
|
+
};
|
|
63
|
+
const paragraphRule = {
|
|
64
|
+
pattern: /^((?:[^\n]+?)(?:\n[^\n]+?)*)(?:\n{2,}|$)/,
|
|
65
|
+
map: result => ({ kind: "paragraph", content: parseInlineMarkdown(result[1] ?? "") }),
|
|
66
|
+
};
|
|
67
|
+
const blockRules = [listRule, paragraphRule];
|
|
68
|
+
const parseForBlockRules = (rules, text, remainingRules = rules) => {
|
|
69
|
+
if (text.length === 0) {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
const activeRule = remainingRules[0];
|
|
73
|
+
if (activeRule === undefined) {
|
|
74
|
+
return [{ kind: "paragraph", content: [{ kind: "text", content: text }] }];
|
|
75
|
+
}
|
|
76
|
+
const res = activeRule.pattern.exec(text);
|
|
77
|
+
if (res && (activeRule.predicate?.(res) ?? true)) {
|
|
78
|
+
const { index } = res;
|
|
79
|
+
const after = text.slice(index + res[0].length);
|
|
80
|
+
return [activeRule.map(res), ...(after.length > 0 ? parseForBlockRules(rules, after) : [])];
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
return parseForBlockRules(rules, text, remainingRules.slice(1));
|
|
40
84
|
}
|
|
41
85
|
};
|
|
42
|
-
const
|
|
86
|
+
export const parseBlockMarkdown = (text) => parseForBlockRules(blockRules, text);
|
|
@@ -2,12 +2,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
|
2
2
|
import { sortObjectKeys } from "../../../shared/utils/object.js";
|
|
3
3
|
import { toTitleCase } from "../../../shared/utils/string.js";
|
|
4
4
|
import { validateObjectConstraints } from "../../../shared/validation/object.js";
|
|
5
|
+
import { Markdown } from "../../utils/Markdown.js";
|
|
5
6
|
import { createTypeSkeleton } from "../../utils/typeSkeleton.js";
|
|
6
7
|
import { TypeInput } from "./TypeInput.js";
|
|
7
8
|
import { ValidationErrors } from "./utils/ValidationErrors.js";
|
|
8
9
|
export const ObjectTypeInput = ({ type, value, instanceNamesByEntity, getDeclFromDeclName, onChange, }) => {
|
|
9
10
|
const errors = validateObjectConstraints(type, Object.keys(type.properties), value);
|
|
10
|
-
return (_jsxs("div", { class: "field field--container field--object", children: [_jsx("ul", { children: Object.entries(type.properties).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(
|
|
11
|
+
return (_jsxs("div", { class: "field field--container field--object", children: [_jsx("ul", { children: Object.entries(type.properties).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] === undefined ? (_jsx("button", { onClick: () => {
|
|
11
12
|
onChange(sortObjectKeys({
|
|
12
13
|
...value,
|
|
13
14
|
[key]: createTypeSkeleton(getDeclFromDeclName, memberDecl.type),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime";
|
|
2
2
|
import { validateStringConstraints } from "../../../shared/validation/string.js";
|
|
3
|
-
import { Markdown } from "
|
|
3
|
+
import { Markdown } from "../../utils/Markdown.js";
|
|
4
4
|
import { ValidationErrors } from "./utils/ValidationErrors.js";
|
|
5
5
|
export const StringTypeInput = ({ type, value, onChange }) => {
|
|
6
6
|
const { minLength, maxLength, pattern, isMarkdown } = type;
|
package/lib/web/routes/Entity.js
CHANGED
|
@@ -6,6 +6,7 @@ import { deleteInstanceByEntityNameAndId, getEntityByName, getInstancesByEntityN
|
|
|
6
6
|
import { Layout } from "../components/Layout.js";
|
|
7
7
|
import { useAPIResource } from "../hooks/useAPIResource.js";
|
|
8
8
|
import { useMappedAPIResource } from "../hooks/useMappedAPIResource.js";
|
|
9
|
+
import { Markdown } from "../utils/Markdown.js";
|
|
9
10
|
import { NotFound } from "./NotFound.js";
|
|
10
11
|
const mapInstances = (data) => data.instances;
|
|
11
12
|
export const Entity = () => {
|
|
@@ -26,7 +27,7 @@ export const Entity = () => {
|
|
|
26
27
|
if (!entity || !instances) {
|
|
27
28
|
return (_jsxs("div", { children: [_jsx("h1", { children: name }), _jsx("p", { className: "loading", children: "Loading \u2026" })] }));
|
|
28
29
|
}
|
|
29
|
-
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(
|
|
30
|
+
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(Markdown, { class: "description", string: entity.declaration.comment })), _jsxs("p", { children: [instances.length, " instance", instances.length === 1 ? "" : "s"] }), _jsx("ul", { class: "instances", children: instances.map(instance => {
|
|
30
31
|
const gitStatusForDisplay = getGitStatusForDisplay(instance.gitStatus);
|
|
31
32
|
return (_jsxs("li", { id: `instance-${instance.id}`, class: `instance-item ${created === instance.id ? "instance-item--created" : ""} ${gitStatusForDisplay === undefined ? "" : `git-status--${gitStatusForDisplay}`}`, children: [_jsx("h2", { children: instance.displayName }), _jsx("p", { "aria-hidden": true, class: "id", children: instance.id }), gitStatusForDisplay !== undefined && (_jsx("p", { class: `git-status git-status--${gitStatusForDisplay}`, title: getLabelForGitStatus(gitStatusForDisplay), children: gitStatusForDisplay })), _jsxs("div", { className: "btns", children: [_jsx("a", { href: `/entities/${entity.declaration.name}/instances/${instance.id}`, class: "btn", children: "Edit" }), _jsx("button", { class: "destructive", onClick: () => {
|
|
32
33
|
if (confirm("Are you sure you want to delete this instance?")) {
|
package/lib/web/routes/Home.js
CHANGED
|
@@ -3,8 +3,9 @@ import { toTitleCase } from "../../shared/utils/string.js";
|
|
|
3
3
|
import { getAllEntities } from "../api.js";
|
|
4
4
|
import { Layout } from "../components/Layout.js";
|
|
5
5
|
import { useMappedAPIResource } from "../hooks/useMappedAPIResource.js";
|
|
6
|
+
import { Markdown } from "../utils/Markdown.js";
|
|
6
7
|
const mapEntities = (data) => data.declarations.sort((a, b) => a.declaration.name.localeCompare(b.declaration.name));
|
|
7
8
|
export const Home = () => {
|
|
8
9
|
const [entities] = useMappedAPIResource(getAllEntities, mapEntities);
|
|
9
|
-
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(
|
|
10
|
+
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(Markdown, { class: "description", string: 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))) })] }));
|
|
10
11
|
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "preact/jsx-runtime";
|
|
2
|
+
import { parseBlockMarkdown } from "../../shared/utils/markdown.js";
|
|
3
|
+
export const Markdown = ({ class: className, string }) => {
|
|
4
|
+
const blocks = parseBlockMarkdown(string);
|
|
5
|
+
const blockElements = blocks.map((block, i) => (_jsx(BlockMarkdown, { node: block }, `md-block-${i.toString()}`)));
|
|
6
|
+
if (className) {
|
|
7
|
+
return _jsx("div", { class: className, children: blockElements });
|
|
8
|
+
}
|
|
9
|
+
return _jsx(_Fragment, { children: blockElements });
|
|
10
|
+
};
|
|
11
|
+
const BlockMarkdown = ({ node }) => {
|
|
12
|
+
switch (node.kind) {
|
|
13
|
+
case "paragraph":
|
|
14
|
+
return (_jsx("p", { children: node.content.map((inline, ii) => (_jsx(InlineMarkdown, { node: inline }, ii))) }));
|
|
15
|
+
case "list":
|
|
16
|
+
if (node.ordered) {
|
|
17
|
+
return (_jsx("ol", { children: node.content.map((item, ii) => (_jsx("li", { children: item.content.map((inline, iii) => (_jsx(InlineMarkdown, { node: inline }, iii))) }, ii))) }));
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
return (_jsx("ul", { children: node.content.map((item, ii) => (_jsx("li", { children: item.content.map((inline, iii) => (_jsx(InlineMarkdown, { node: inline }, iii))) }, ii))) }));
|
|
21
|
+
}
|
|
22
|
+
case "text":
|
|
23
|
+
return node.content;
|
|
24
|
+
default:
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const InlineMarkdown = ({ node }) => {
|
|
29
|
+
switch (node.kind) {
|
|
30
|
+
case "code":
|
|
31
|
+
return _jsx("code", { children: node.content });
|
|
32
|
+
case "bold":
|
|
33
|
+
return (_jsx("strong", { children: node.content.map((inline, i) => (_jsx(InlineMarkdown, { node: inline }, i))) }));
|
|
34
|
+
case "italic":
|
|
35
|
+
return (_jsx("em", { children: node.content.map((inline, i) => (_jsx(InlineMarkdown, { node: inline }, i))) }));
|
|
36
|
+
case "text":
|
|
37
|
+
return node.content;
|
|
38
|
+
}
|
|
39
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tsondb",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"author": "Lukas Obermann",
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
"release:sign": "commit-and-tag-version --sign --signoff"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@eslint/js": "^9.
|
|
35
|
+
"@eslint/js": "^9.31.0",
|
|
36
36
|
"@types/debug": "^4.1.12",
|
|
37
37
|
"@types/express": "^5.0.3",
|
|
38
|
-
"@types/node": "^24.0.
|
|
38
|
+
"@types/node": "^24.0.13",
|
|
39
39
|
"commit-and-tag-version": "^12.5.1",
|
|
40
|
-
"eslint": "^9.
|
|
40
|
+
"eslint": "^9.31.0",
|
|
41
41
|
"eslint-plugin-react": "^7.37.5",
|
|
42
42
|
"eslint-plugin-react-hooks": "^5.2.0",
|
|
43
43
|
"globals": "^16.3.0",
|
package/public/css/styles.css
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
--separator-color: #e9e5eb;
|
|
16
16
|
--secondary-color: #7e7f87;
|
|
17
17
|
--tertiary-color: #bcbdc2;
|
|
18
|
-
--input-border-color:
|
|
18
|
+
--input-border-color: black;
|
|
19
19
|
--button-background: #c7cad0;
|
|
20
20
|
--button-background-hover: #dedfe4;
|
|
21
21
|
--button-background-primary: black;
|
|
@@ -436,29 +436,29 @@ form > .field--container {
|
|
|
436
436
|
border: none;
|
|
437
437
|
}
|
|
438
438
|
|
|
439
|
-
.field--container ul,
|
|
440
|
-
.field--container ol {
|
|
439
|
+
.field--container > ul,
|
|
440
|
+
.field--container > ol {
|
|
441
441
|
margin: 0;
|
|
442
442
|
padding: 0;
|
|
443
443
|
list-style-type: " ";
|
|
444
444
|
}
|
|
445
445
|
|
|
446
|
-
.field--container ul li,
|
|
447
|
-
.field--container ol li {
|
|
446
|
+
.field--container > ul > li,
|
|
447
|
+
.field--container > ol > li {
|
|
448
448
|
padding-top: 0.5rem;
|
|
449
449
|
padding-bottom: 0.75rem;
|
|
450
450
|
border-top: 1px solid var(--separator-color);
|
|
451
451
|
display: block;
|
|
452
452
|
}
|
|
453
453
|
|
|
454
|
-
.field--container ul li:first-child,
|
|
455
|
-
.field--container ol li:first-child {
|
|
454
|
+
.field--container > ul > li:first-child,
|
|
455
|
+
.field--container > ol > li:first-child {
|
|
456
456
|
padding-top: 0;
|
|
457
457
|
border-top: none;
|
|
458
458
|
}
|
|
459
459
|
|
|
460
|
-
.field--container ul li:last-child,
|
|
461
|
-
.field--container ol li:last-child {
|
|
460
|
+
.field--container > ul > li:last-child,
|
|
461
|
+
.field--container > ol > li:last-child {
|
|
462
462
|
padding-bottom: 0;
|
|
463
463
|
}
|
|
464
464
|
|
|
@@ -539,8 +539,20 @@ button[type="submit"] {
|
|
|
539
539
|
|
|
540
540
|
.comment {
|
|
541
541
|
font-size: 0.8rem;
|
|
542
|
+
line-height: 1.4;
|
|
542
543
|
color: var(--secondary-color);
|
|
543
544
|
margin: 0.5rem 0 0;
|
|
545
|
+
max-width: 55em;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
.comment p {
|
|
549
|
+
margin: 0.35rem 0 0;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
.comment ul {
|
|
553
|
+
list-style-type: disc;
|
|
554
|
+
padding-left: 1.5rem;
|
|
555
|
+
margin: 0.35rem 0 0;
|
|
544
556
|
}
|
|
545
557
|
|
|
546
558
|
.git-status {
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
|
-
import { parseBlockMarkdown } from "../../../../shared/utils/markdown.js";
|
|
3
|
-
export const Markdown = ({ string }) => {
|
|
4
|
-
const blocks = parseBlockMarkdown(string);
|
|
5
|
-
return blocks.map((block, i) => _jsx(BlockMarkdown, { node: block }, `md-block-${i.toString()}`));
|
|
6
|
-
};
|
|
7
|
-
const BlockMarkdown = ({ node }) => {
|
|
8
|
-
switch (node.kind) {
|
|
9
|
-
case "paragraph":
|
|
10
|
-
return (_jsx("p", { children: node.content.map((inline, ii) => (_jsx(InlineMarkdown, { node: inline }, ii))) }));
|
|
11
|
-
case "text":
|
|
12
|
-
return node.content;
|
|
13
|
-
default:
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
const InlineMarkdown = ({ node }) => {
|
|
18
|
-
switch (node.kind) {
|
|
19
|
-
case "bold":
|
|
20
|
-
return (_jsx("strong", { children: node.content.map((inline, i) => (_jsx(InlineMarkdown, { node: inline }, i))) }));
|
|
21
|
-
case "italic":
|
|
22
|
-
return (_jsx("em", { children: node.content.map((inline, i) => (_jsx(InlineMarkdown, { node: inline }, i))) }));
|
|
23
|
-
case "text":
|
|
24
|
-
return node.content;
|
|
25
|
-
}
|
|
26
|
-
};
|