tsondb 0.5.0 → 0.5.2

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.
@@ -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
- if (decls.values().some(decl => decl.name === param)) {
18
- throw new Error(`Parameter name "${param}" shadows declaration name.`);
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
  };
@@ -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 { SerializedType, Type } from "../types/Type.js";
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
- walkTypeNodeTree(callbackFn, type.items);
78
- return;
79
- }
80
- case NodeKind.ObjectType:
76
+ walkTypeNodeTree(callbackFn, type.items);
77
+ return;
78
+ }
79
+ case NodeKind.ObjectType: {
81
80
  callbackFn(type);
82
- {
83
- Object.values(type.properties).forEach(prop => {
84
- walkTypeNodeTree(callbackFn, prop.type);
85
- });
86
- return;
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
- walkTypeNodeTree(callbackFn, type.type.value);
92
- return;
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
- Object.values(type.values).forEach(value => {
109
- if (value.type) {
110
- walkTypeNodeTree(callbackFn, value.type);
111
- }
112
- });
113
- return;
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
@@ -1,17 +1,26 @@
1
1
  import Debug from "debug";
2
2
  import express from "express";
3
- import { join } from "node:path";
3
+ import { findPackageJSON } from "node:module";
4
+ import { dirname, join } from "node:path";
4
5
  import { api } from "./api/index.js";
5
6
  import { init } from "./init.js";
6
7
  const debug = Debug("tsondb:server");
7
8
  const defaultOptions = {
8
9
  port: 3000,
9
10
  };
11
+ const staticNodeModule = (moduleName) => {
12
+ const pathToPackageJson = findPackageJSON(moduleName, import.meta.url);
13
+ if (!pathToPackageJson) {
14
+ throw new Error(`Could not find module "${moduleName}"`);
15
+ }
16
+ return express.static(dirname(pathToPackageJson));
17
+ };
10
18
  export const createServer = async (schema, dataRootPath, instancesByEntityName, options) => {
11
19
  const { port } = { ...defaultOptions, ...options };
12
20
  const app = express();
13
21
  app.use(express.static(join(import.meta.dirname, "../../../public")));
14
- app.use("/js/node_modules", express.static(join(import.meta.dirname, "../../../node_modules")));
22
+ app.use("/js/node_modules/preact", staticNodeModule("preact"));
23
+ app.use("/js/node_modules/preact-iso", staticNodeModule("preact-iso"));
15
24
  app.use("/js/client", express.static(join(import.meta.dirname, "../../../lib/web")));
16
25
  app.use("/js/shared", express.static(join(import.meta.dirname, "../../../lib/shared")));
17
26
  app.use(express.json());
@@ -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 rules = [boldWithItalicRule, italicWithBoldRule, boldRule, italicRule];
18
- export const parseBlockMarkdown = (text) => text.split(/\n{2,}/).map(par => ({ kind: "paragraph", content: parseInlineMarkdown(par) }));
19
- const parseForRules = (rules, text) => {
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 ? parseForRules(rules.slice(1), before) : []),
34
- activeRule.map(res, text => parseForRules(rules.slice(1), text)),
35
- ...(after.length > 0 ? parseForRules(rules, after) : []),
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 parseForRules(rules.slice(1), text);
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 parseInlineMarkdown = (text) => parseForRules(rules, text);
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("p", { class: "comment", children: memberDecl.comment }))] }), memberDecl.isRequired ? null : value[key] === undefined ? (_jsx("button", { onClick: () => {
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 "./utils/Markdown.js";
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;
@@ -12,6 +12,7 @@ export const useInstanceNamesByEntity = (locales = []) => {
12
12
  console.error("Error fetching data:", error.toString());
13
13
  }
14
14
  });
15
+ // eslint-disable-next-line react-hooks/exhaustive-deps
15
16
  }, [locales.toString()]);
16
17
  useEffect(() => {
17
18
  updateInstanceNamesByEntity();
@@ -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("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 => {
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?")) {
@@ -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("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))) })] }));
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
  };
@@ -1,5 +1,6 @@
1
1
  import type { FunctionalComponent } from "preact";
2
2
  type Props = {
3
+ class?: string;
3
4
  string: string;
4
5
  };
5
6
  export declare const Markdown: FunctionalComponent<Props>;
@@ -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.0",
3
+ "version": "0.5.2",
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.30.1",
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.12",
38
+ "@types/node": "^24.0.13",
39
39
  "commit-and-tag-version": "^12.5.1",
40
- "eslint": "^9.30.1",
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",
@@ -15,6 +15,7 @@
15
15
  --separator-color: #e9e5eb;
16
16
  --secondary-color: #7e7f87;
17
17
  --tertiary-color: #bcbdc2;
18
+ --input-border-color: black;
18
19
  --button-background: #c7cad0;
19
20
  --button-background-hover: #dedfe4;
20
21
  --button-background-primary: black;
@@ -32,10 +33,51 @@
32
33
  --highlight-color: #a08500;
33
34
  --highlight-background: #fdfab9;
34
35
  --disabled-color: #cdced2;
36
+ --git-status-untracked-color: rgb(13, 149, 101);
37
+ --git-status-untracked-background: rgba(13, 149, 101, 0.15);
38
+ --git-status-added-color: rgb(20, 148, 29);
39
+ --git-status-added-background: rgba(20, 148, 29, 0.15);
40
+ --git-status-modified-color: rgb(196, 155, 18);
41
+ --git-status-modified-background: rgba(196, 155, 18, 0.15);
42
+ --git-status-deleted-color: rgb(135, 22, 11);
43
+ --git-status-deleted-background: rgba(135, 22, 11, 0.15);
44
+ --git-status-renamed-color: rgb(20, 97, 148);
45
+ --git-status-renamed-background: rgba(20, 97, 148, 0.15);
46
+ --shadow-color: rgba(160, 163, 165, 0.5);
47
+ }
48
+
49
+ @media (prefers-color-scheme: dark) {
50
+ :root {
51
+ --background: hsl(260, 6%, 10%);
52
+ --markdown-background: hsl(260, 6%, 17%);
53
+ --color: hsl(260, 6%, 88%);
54
+ --error-color: #ff6b6b;
55
+ --separator-color: hsl(260, 6%, 24%);
56
+ --secondary-color: hsl(260, 6%, 69%);
57
+ --tertiary-color: hsl(260, 6%, 49%);
58
+ --input-border-color: hsl(260, 6%, 40%);
59
+ --button-background: hsl(260, 6%, 24%);
60
+ --button-background-hover: hsl(260, 6%, 30%);
61
+ --button-background-primary: hsl(260, 6%, 80%);
62
+ --button-background-primary-hover: hsl(260, 6%, 60%);
63
+ --button-background-destructive: #922727;
64
+ --button-background-destructive-hover: #ff8080;
65
+ --button-background-disabled: hsl(260, 6%, 35%);
66
+ --button-color: #fff;
67
+ --button-color-hover: #fff;
68
+ --button-color-primary: #000;
69
+ --button-color-primary-hover: #000;
70
+ --button-color-destructive: #fff;
71
+ --button-color-destructive-hover: #fff;
72
+ --button-color-disabled: hsl(260, 6%, 54%);
73
+ --highlight-color: #f2d600;
74
+ --highlight-background: #333300;
75
+ }
35
76
  }
36
77
 
37
78
  body {
38
79
  font-family: var(--font-sans);
80
+ color: var(--color);
39
81
  margin: 0;
40
82
  padding: 1.5rem;
41
83
  line-height: 1.4;
@@ -143,6 +185,13 @@ button.primary {
143
185
  border: none;
144
186
  }
145
187
 
188
+ @media (prefers-color-scheme: dark) {
189
+ a.btn--primary,
190
+ button.primary {
191
+ font-weight: 700;
192
+ }
193
+ }
194
+
146
195
  a.btn--primary:hover,
147
196
  button.primary:hover {
148
197
  background: var(--button-background-primary-hover);
@@ -179,8 +228,10 @@ button.destructive:disabled {
179
228
  input,
180
229
  textarea,
181
230
  select {
231
+ background: var(--background);
232
+ color: var(--color);
182
233
  font-family: var(--font-sans);
183
- border: 1px solid var(--color);
234
+ border: 1px solid var(--input-border-color);
184
235
  padding: 0.5rem;
185
236
  display: block;
186
237
  width: 100%;
@@ -301,7 +352,7 @@ select {
301
352
  font-size: 1rem;
302
353
  margin: 0;
303
354
  flex: 1 1 auto;
304
- padding: 0.5rem 0;
355
+ padding: 0.65rem 0;
305
356
  }
306
357
 
307
358
  .entity-item .title {
@@ -385,29 +436,29 @@ form > .field--container {
385
436
  border: none;
386
437
  }
387
438
 
388
- .field--container ul,
389
- .field--container ol {
439
+ .field--container > ul,
440
+ .field--container > ol {
390
441
  margin: 0;
391
442
  padding: 0;
392
443
  list-style-type: " ";
393
444
  }
394
445
 
395
- .field--container ul li,
396
- .field--container ol li {
446
+ .field--container > ul > li,
447
+ .field--container > ol > li {
397
448
  padding-top: 0.5rem;
398
449
  padding-bottom: 0.75rem;
399
450
  border-top: 1px solid var(--separator-color);
400
451
  display: block;
401
452
  }
402
453
 
403
- .field--container ul li:first-child,
404
- .field--container ol li:first-child {
454
+ .field--container > ul > li:first-child,
455
+ .field--container > ol > li:first-child {
405
456
  padding-top: 0;
406
457
  border-top: none;
407
458
  }
408
459
 
409
- .field--container ul li:last-child,
410
- .field--container ol li:last-child {
460
+ .field--container > ul > li:last-child,
461
+ .field--container > ol > li:last-child {
411
462
  padding-bottom: 0;
412
463
  }
413
464
 
@@ -488,8 +539,20 @@ button[type="submit"] {
488
539
 
489
540
  .comment {
490
541
  font-size: 0.8rem;
542
+ line-height: 1.4;
491
543
  color: var(--secondary-color);
492
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;
493
556
  }
494
557
 
495
558
  .git-status {
@@ -507,28 +570,28 @@ button[type="submit"] {
507
570
  }
508
571
 
509
572
  .git-status.git-status--U {
510
- color: rgb(13, 149, 101);
511
- background: rgba(13, 149, 101, 0.15);
573
+ color: var(--git-status-untracked-color);
574
+ background: var(--git-status-untracked-background);
512
575
  }
513
576
 
514
577
  .git-status.git-status--A {
515
- color: rgb(20, 148, 29);
516
- background: rgba(20, 148, 29, 0.15);
578
+ color: var(--git-status-added-color);
579
+ background: var(--git-status-added-background);
517
580
  }
518
581
 
519
582
  .git-status.git-status--M {
520
- color: rgb(196, 155, 18);
521
- background: rgba(196, 155, 18, 0.15);
583
+ color: var(--git-status-modified-color);
584
+ background: var(--git-status-modified-background);
522
585
  }
523
586
 
524
587
  .git-status.git-status--D {
525
- color: rgb(135, 22, 11);
526
- background: rgba(135, 22, 11, 0.15);
588
+ color: var(--git-status-deleted-color);
589
+ background: var(--git-status-deleted-background);
527
590
  }
528
591
 
529
592
  .git-status.git-status--R {
530
- color: rgb(20, 97, 148);
531
- background: rgba(20, 97, 148, 0.15);
593
+ color: var(--git-status-renamed-color);
594
+ background: var(--git-status-renamed-background);
532
595
  }
533
596
 
534
597
  aside.git {
@@ -632,7 +695,7 @@ aside.git .branch .select-wrapper {
632
695
  display: none;
633
696
  position: absolute;
634
697
  right: 1.5rem;
635
- box-shadow: 0 0.5rem 2rem rgba(160, 163, 165, 0.5);
698
+ box-shadow: 0 0.5rem 2rem var(--shadow-color);
636
699
  z-index: 1000;
637
700
  padding: 1rem;
638
701
  background: var(--background);
@@ -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
- };