tsondb 0.21.1 → 0.21.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.
Files changed (51) hide show
  1. package/dist/src/node/config.d.ts +2 -2
  2. package/dist/src/node/git.d.ts +4 -4
  3. package/dist/src/node/index.d.ts +39 -4
  4. package/dist/src/node/index.js +112 -11
  5. package/dist/src/node/renderers/jsonschema/render.js +7 -0
  6. package/dist/src/node/renderers/ts/render.d.ts +4 -0
  7. package/dist/src/node/renderers/ts/render.js +6 -0
  8. package/dist/src/node/schema/dsl/declarations/Decl.d.ts +3 -2
  9. package/dist/src/node/schema/dsl/declarations/Decl.js +2 -1
  10. package/dist/src/node/schema/dsl/declarations/SingletonEntityDecl.d.ts +35 -0
  11. package/dist/src/node/schema/dsl/declarations/SingletonEntityDecl.js +23 -0
  12. package/dist/src/node/schema/dsl/index.d.ts +1 -0
  13. package/dist/src/node/schema/dsl/index.js +1 -0
  14. package/dist/src/node/schema/generatedTypeHelpers.d.ts +18 -0
  15. package/dist/src/node/schema/guards.d.ts +1 -0
  16. package/dist/src/node/schema/guards.js +1 -0
  17. package/dist/src/node/schema/helpers.js +1 -0
  18. package/dist/src/node/schema/index.d.ts +12 -1
  19. package/dist/src/node/schema/index.js +44 -0
  20. package/dist/src/node/schema/treeOperations/customConstraints.d.ts +2 -1
  21. package/dist/src/node/schema/treeOperations/customConstraints.js +10 -10
  22. package/dist/src/node/schema/treeOperations/implicitSchema.js +1 -0
  23. package/dist/src/node/schema/treeOperations/references.js +1 -0
  24. package/dist/src/node/schema/treeOperations/serialization.d.ts +4 -1
  25. package/dist/src/node/schema/treeOperations/serialization.js +8 -0
  26. package/dist/src/node/schema/treeOperations/typeResolution.d.ts +4 -1
  27. package/dist/src/node/schema/treeOperations/typeResolution.js +6 -0
  28. package/dist/src/node/schema/treeOperations/validation.js +2 -0
  29. package/dist/src/node/server/api/declarations.js +165 -23
  30. package/dist/src/node/transaction.d.ts +28 -11
  31. package/dist/src/node/transaction.js +93 -0
  32. package/dist/src/node/utils/customConstraints.d.ts +6 -5
  33. package/dist/src/node/utils/customConstraints.js +34 -15
  34. package/dist/src/node/utils/databaseInMemory.d.ts +20 -8
  35. package/dist/src/node/utils/databaseInMemory.js +67 -9
  36. package/dist/src/node/utils/databaseOnDisk.js +27 -30
  37. package/dist/src/node/utils/files.d.ts +7 -2
  38. package/dist/src/node/utils/files.js +9 -0
  39. package/dist/src/node/utils/references.d.ts +2 -0
  40. package/dist/src/node/utils/references.js +6 -1
  41. package/dist/src/shared/api.d.ts +41 -2
  42. package/dist/src/shared/schema/Node.d.ts +5 -1
  43. package/dist/src/shared/schema/Node.js +6 -0
  44. package/dist/src/shared/schema/declarations/Declaration.d.ts +3 -2
  45. package/dist/src/shared/schema/declarations/SingletonEntityDecl.d.ts +18 -0
  46. package/dist/src/shared/schema/declarations/SingletonEntityDecl.js +8 -0
  47. package/dist/src/shared/utils/childInstances.d.ts +4 -0
  48. package/dist/src/shared/utils/instances.d.ts +4 -0
  49. package/dist/src/web/web.js +573 -130
  50. package/package.json +1 -1
  51. package/public/css/styles.css +1 -0
@@ -668,6 +668,47 @@ const RouteContext = X({});
668
668
  const Route = (props)=>preact_module_k(props.component, props);
669
669
  const useLocation = ()=>hooks_module_x(LocationProvider.ctx);
670
670
  const useRoute = ()=>hooks_module_x(RouteContext);
671
+ const enumOfObject = (obj)=>Object.fromEntries(Object.keys(obj).map((key)=>[
672
+ key,
673
+ key
674
+ ]));
675
+ const isSerializedEntityDecl = (node)=>node.kind === Node_NodeKind.EntityDecl;
676
+ const isSerializedEntityDeclWithParentReference = (decl)=>void 0 !== decl.parentReferenceKey;
677
+ const isSerializedEnumDecl = (node)=>node.kind === Node_NodeKind.EnumDecl;
678
+ const isSerializedSingletonEntityDecl = (node)=>node.kind === Node_NodeKind.SingletonEntityDecl;
679
+ const isSerializedTypeAliasDecl = (node)=>node.kind === Node_NodeKind.TypeAliasDecl;
680
+ const getSerializedTypeOfKey = (keyValue, parentType)=>null === keyValue ? {
681
+ kind: "StringType"
682
+ } : {
683
+ kind: "TranslationObjectType",
684
+ allKeysAreRequired: false,
685
+ ...parentType,
686
+ properties: keyValue
687
+ };
688
+ const Node_NodeKind = enumOfObject({
689
+ ChildEntityDecl: null,
690
+ EntityDecl: null,
691
+ SingletonEntityDecl: null,
692
+ EnumDecl: null,
693
+ EnumCaseDecl: null,
694
+ TypeAliasDecl: null,
695
+ MemberDecl: null,
696
+ ArrayType: null,
697
+ ObjectType: null,
698
+ BooleanType: null,
699
+ FloatType: null,
700
+ IntegerType: null,
701
+ StringType: null,
702
+ DateType: null,
703
+ TypeArgumentType: null,
704
+ TypeParameter: null,
705
+ ReferenceIdentifierType: null,
706
+ IncludeIdentifierType: null,
707
+ NestedEntityMapType: null,
708
+ EnumType: null,
709
+ ChildEntitiesType: null,
710
+ TranslationObjectType: null
711
+ });
671
712
  const request = async (method, url, options)=>{
672
713
  const resolvedUrl = new URL(url, window.location.origin);
673
714
  for (const locale of options.locales)resolvedUrl.searchParams.append("locales", locale);
@@ -696,6 +737,7 @@ const getAllDeclarations = async (locales, kind)=>api_getResource("/api/declarat
696
737
  }
697
738
  });
698
739
  const getAllEntities = (locales)=>getAllDeclarations(locales, "Entity");
740
+ const getAllSingletonEntities = (locales)=>getAllDeclarations(locales, "SingletonEntity");
699
741
  const getInstancesByEntityName = async (locales, name)=>api_getResource(`/api/declarations/${name}/instances`, {
700
742
  locales
701
743
  });
@@ -733,6 +775,30 @@ const deleteInstanceByEntityNameAndId = async (locales, name, id)=>deleteResourc
733
775
  const getChildInstancesForInstanceByEntityName = async (locales, name, parentId)=>api_getResource(`/api/declarations/${name}/instances/${parentId}/children`, {
734
776
  locales
735
777
  });
778
+ const getSingletonInstanceByEntityName = async (locales, name)=>api_getResource(`/api/declarations/${name}/instance`, {
779
+ locales
780
+ });
781
+ const createSingletonInstanceByEntityName = async (locales, name, content)=>{
782
+ const body = {
783
+ instance: content
784
+ };
785
+ return postResource(`/api/declarations/${name}/instance`, {
786
+ locales,
787
+ body
788
+ });
789
+ };
790
+ const updateSingletonInstanceByEntityName = async (locales, name, content)=>{
791
+ const body = {
792
+ instance: content
793
+ };
794
+ return putResource(`/api/declarations/${name}/instance`, {
795
+ locales,
796
+ body
797
+ });
798
+ };
799
+ const deleteSingletonInstanceByEntityName = async (locales, name)=>deleteResource(`/api/declarations/${name}/instance`, {
800
+ locales
801
+ });
736
802
  const getWebConfig = ()=>api_getResource("/api/config", {
737
803
  locales: []
738
804
  });
@@ -1960,45 +2026,10 @@ const EntitiesContext = X({
1960
2026
  entities: [],
1961
2027
  reloadEntities: async ()=>{}
1962
2028
  });
1963
- const enumOfObject = (obj)=>Object.fromEntries(Object.keys(obj).map((key)=>[
1964
- key,
1965
- key
1966
- ]));
1967
- const isSerializedEnumDecl = (node)=>node.kind === Node_NodeKind.EnumDecl;
1968
- const isSerializedTypeAliasDecl = (node)=>node.kind === Node_NodeKind.TypeAliasDecl;
1969
- const getSerializedTypeOfKey = (keyValue, parentType)=>null === keyValue ? {
1970
- kind: "StringType"
1971
- } : {
1972
- kind: "TranslationObjectType",
1973
- allKeysAreRequired: false,
1974
- ...parentType,
1975
- properties: keyValue
1976
- };
1977
- const Node_NodeKind = enumOfObject({
1978
- ChildEntityDecl: null,
1979
- EntityDecl: null,
1980
- EnumDecl: null,
1981
- EnumCaseDecl: null,
1982
- TypeAliasDecl: null,
1983
- MemberDecl: null,
1984
- ArrayType: null,
1985
- ObjectType: null,
1986
- BooleanType: null,
1987
- FloatType: null,
1988
- IntegerType: null,
1989
- StringType: null,
1990
- DateType: null,
1991
- TypeArgumentType: null,
1992
- TypeParameter: null,
1993
- ReferenceIdentifierType: null,
1994
- IncludeIdentifierType: null,
1995
- NestedEntityMapType: null,
1996
- EnumType: null,
1997
- ChildEntitiesType: null,
1998
- TranslationObjectType: null
2029
+ const SingletonEntitiesContext = X({
2030
+ singletonEntities: [],
2031
+ reloadSingletonEntities: async ()=>{}
1999
2032
  });
2000
- const isSerializedEntityDecl = (node)=>node.kind === Node_NodeKind.EntityDecl;
2001
- const isSerializedEntityDeclWithParentReference = (decl)=>void 0 !== decl.parentReferenceKey;
2002
2033
  const git_isRepo = async (locales)=>api_getResource("/api/git", {
2003
2034
  locales
2004
2035
  });
@@ -2488,6 +2519,15 @@ const useEntityFromRoute = ()=>{
2488
2519
  ]);
2489
2520
  return entityObj;
2490
2521
  };
2522
+ const useSingletonEntityFromRoute = ()=>{
2523
+ const { params: { name } } = useRoute();
2524
+ const { singletonEntities } = hooks_module_x(SingletonEntitiesContext);
2525
+ const entityObj = hooks_module_T(()=>singletonEntities.find((e)=>e.declaration.name === name), [
2526
+ singletonEntities,
2527
+ name
2528
+ ]);
2529
+ return entityObj;
2530
+ };
2491
2531
  const getAllInstances = async (locales)=>api_getResource("/api/instances", {
2492
2532
  locales
2493
2533
  });
@@ -2518,7 +2558,7 @@ const useGetDeclFromDeclName = ()=>{
2518
2558
  const [secondaryDeclarations, setSecondaryDeclarations] = hooks_module_d();
2519
2559
  hooks_module_h(()=>{
2520
2560
  getAllDeclarations(locales).then((data)=>{
2521
- setSecondaryDeclarations(data.declarations.map((decl)=>decl.declaration).filter((decl)=>isSerializedEnumDecl(decl) || isSerializedTypeAliasDecl(decl) || isSerializedEntityDeclWithParentReference(decl)));
2561
+ setSecondaryDeclarations(data.declarations.map((decl)=>decl.declaration).filter((decl)=>isSerializedEnumDecl(decl) || isSerializedTypeAliasDecl(decl) || !isSerializedSingletonEntityDecl(decl) && isSerializedEntityDeclWithParentReference(decl)));
2522
2562
  }).catch((error)=>{
2523
2563
  if (error instanceof Error) console.error("Error fetching data:", error.toString());
2524
2564
  });
@@ -2533,6 +2573,18 @@ const useGetDeclFromDeclName = ()=>{
2533
2573
  void 0 !== secondaryDeclarations
2534
2574
  ];
2535
2575
  };
2576
+ const isNullish = (value)=>null == value;
2577
+ const isNotNullish = (value)=>!isNullish(value);
2578
+ function typeSafety_assertExhaustive(_x, msg = "The switch is not exhaustive.") {
2579
+ throw new Error(msg);
2580
+ }
2581
+ const trySafe = (f, defaultValue)=>{
2582
+ try {
2583
+ return f();
2584
+ } catch {
2585
+ return defaultValue;
2586
+ }
2587
+ };
2536
2588
  const reorder = (arr, sourceIndex, targetIndex)=>{
2537
2589
  if (sourceIndex < 0 || sourceIndex >= arr.length) throw new RangeError(`source index ${sourceIndex.toString()} is out of bounds for array of length ${arr.length.toString()}`);
2538
2590
  if (targetIndex < 0 || targetIndex >= arr.length) throw new RangeError(`target index ${targetIndex.toString()} is out of bounds for array of length ${arr.length.toString()}`);
@@ -3129,16 +3181,6 @@ class StateTParser {
3129
3181
  }
3130
3182
  const naturalNumberPattern = /^(?:0|[1-9][0-9]*)$/u;
3131
3183
  const isNaturalNumber = (test)=>naturalNumberPattern.test(test);
3132
- function typeSafety_assertExhaustive(_x, msg = "The switch is not exhaustive.") {
3133
- throw new Error(msg);
3134
- }
3135
- const trySafe = (f, defaultValue)=>{
3136
- try {
3137
- return f();
3138
- } catch {
3139
- return defaultValue;
3140
- }
3141
- };
3142
3184
  const reduceSyntaxNodes = (nodes)=>nodes.reduce((reducedNodes, node, index)=>{
3143
3185
  const lastNode = index > 0 ? reducedNodes[reducedNodes.length - 1] : void 0;
3144
3186
  const newLastNode = lastNode ? mergeSyntaxNodes(lastNode, node) : null;
@@ -3417,8 +3459,6 @@ const inline_parseInlineMarkdown = (syntax, keepSyntax = false, preserveEscapes
3417
3459
  };
3418
3460
  const parseInlineMarkdown = (syntax)=>inline_parseInlineMarkdown(syntax, false);
3419
3461
  const parseInlineMarkdownForSyntaxHighlighting = (syntax)=>inline_parseInlineMarkdown(syntax, true);
3420
- const isNullish = (value)=>null == value;
3421
- const isNotNullish = (value)=>!isNullish(value);
3422
3462
  const sortObjectKeysByIndex = (obj, keys)=>Object.fromEntries([
3423
3463
  ...keys.flatMap((key)=>void 0 === obj[key] ? [] : [
3424
3464
  [
@@ -4161,61 +4201,109 @@ const Markdown = ({ class: className, string, outerHeadingLevel, footnoteLabelSu
4161
4201
  };
4162
4202
  const homeTitle = "Entities";
4163
4203
  const isEntityInAnyHomeLayoutSection = (entityName, homeLayoutSections)=>homeLayoutSections.some((section)=>section.entities.includes(entityName));
4204
+ const renderDisplayEntityTitle = (entity)=>{
4205
+ switch(entity.type){
4206
+ case Node_NodeKind.EntityDecl:
4207
+ return entity.declaration.displayNamePlural ?? toTitleCase(entity.declaration.namePlural);
4208
+ case Node_NodeKind.SingletonEntityDecl:
4209
+ return entity.declaration.displayName ?? toTitleCase(entity.declaration.name);
4210
+ default:
4211
+ return typeSafety_assertExhaustive(entity);
4212
+ }
4213
+ };
4214
+ const renderDisplayEntitySubtitle = (entity)=>{
4215
+ switch(entity.type){
4216
+ case Node_NodeKind.EntityDecl:
4217
+ return `${entity.instanceCount.toFixed()} instance${1 === entity.instanceCount ? "" : "s"}`;
4218
+ case Node_NodeKind.SingletonEntityDecl:
4219
+ return entity.hasInstance ? "has instance" : "no instance";
4220
+ default:
4221
+ return typeSafety_assertExhaustive(entity);
4222
+ }
4223
+ };
4224
+ const EntityRow = ({ entity })=>{
4225
+ const { reloadSingletonEntities } = hooks_module_x(SingletonEntitiesContext);
4226
+ const [locales] = useSetting("displayedLocales");
4227
+ return /*#__PURE__*/ jsxRuntime_module_u("li", {
4228
+ class: "entries-item",
4229
+ children: [
4230
+ /*#__PURE__*/ jsxRuntime_module_u("div", {
4231
+ class: "entries-item__title",
4232
+ children: [
4233
+ /*#__PURE__*/ jsxRuntime_module_u("h2", {
4234
+ children: renderDisplayEntityTitle(entity)
4235
+ }),
4236
+ entity.declaration.comment && /*#__PURE__*/ jsxRuntime_module_u(Markdown, {
4237
+ class: "description",
4238
+ string: entity.declaration.comment
4239
+ })
4240
+ ]
4241
+ }),
4242
+ /*#__PURE__*/ jsxRuntime_module_u("p", {
4243
+ class: "entries-item__subtitle",
4244
+ children: renderDisplayEntitySubtitle(entity)
4245
+ }),
4246
+ /*#__PURE__*/ jsxRuntime_module_u("div", {
4247
+ class: "entries-item__side",
4248
+ children: /*#__PURE__*/ jsxRuntime_module_u("div", {
4249
+ class: "btns",
4250
+ children: entity.type === Node_NodeKind.EntityDecl ? /*#__PURE__*/ jsxRuntime_module_u("a", {
4251
+ href: `/entities/${entity.declaration.name}`,
4252
+ class: "btn",
4253
+ children: "View"
4254
+ }) : entity.hasInstance ? /*#__PURE__*/ jsxRuntime_module_u(preact_module_S, {
4255
+ children: [
4256
+ /*#__PURE__*/ jsxRuntime_module_u("a", {
4257
+ href: `/entities/${entity.declaration.name}/instance`,
4258
+ class: "btn",
4259
+ children: "Edit"
4260
+ }),
4261
+ /*#__PURE__*/ jsxRuntime_module_u("button", {
4262
+ class: "destructive",
4263
+ onClick: ()=>{
4264
+ if (confirm("Are you sure you want to delete this instance?")) deleteSingletonInstanceByEntityName(locales, entity.declaration.name).then(()=>reloadSingletonEntities()).catch((error)=>{
4265
+ if (error instanceof Error) alert("Error deleting instance:\n\n" + error.toString());
4266
+ });
4267
+ },
4268
+ children: "Delete"
4269
+ })
4270
+ ]
4271
+ }) : /*#__PURE__*/ jsxRuntime_module_u("a", {
4272
+ class: "btn btn--primary",
4273
+ href: `/entities/${entity.declaration.name}/instance/create`,
4274
+ children: "Add"
4275
+ })
4276
+ })
4277
+ })
4278
+ ]
4279
+ }, entity.declaration.name);
4280
+ };
4164
4281
  const Home = ()=>{
4165
4282
  const { homeLayoutSections } = hooks_module_x(ConfigContext);
4166
4283
  const { entities } = hooks_module_x(EntitiesContext);
4284
+ const { singletonEntities } = hooks_module_x(SingletonEntitiesContext);
4167
4285
  hooks_module_h(()=>{
4168
4286
  document.title = homeTitle + " — TSONDB";
4169
4287
  }, []);
4170
4288
  const [searchText, setSearchText] = hooks_module_d("");
4171
4289
  const lowerSearchText = searchText.toLowerCase().replaceAll(" ", "");
4172
- const filteredEntities = 0 === searchText.length ? entities.filter((entity)=>void 0 === entity.declaration.parentReferenceKey) : entities.filter((entity)=>void 0 === entity.declaration.parentReferenceKey && (entity.declaration.name.toLowerCase().includes(lowerSearchText) || entity.declaration.namePlural.toLowerCase().includes(lowerSearchText)));
4290
+ const filteredEntities = 0 === searchText.length ? [
4291
+ ...entities.filter((entity)=>void 0 === entity.declaration.parentReferenceKey),
4292
+ ...singletonEntities
4293
+ ] : [
4294
+ ...entities.filter((entity)=>void 0 === entity.declaration.parentReferenceKey && (entity.declaration.name.toLowerCase().includes(lowerSearchText) || entity.declaration.namePlural.toLowerCase().includes(lowerSearchText))),
4295
+ ...singletonEntities.filter((entity)=>entity.declaration.name.toLowerCase().includes(lowerSearchText))
4296
+ ];
4173
4297
  const filteredEntitiesBySection = homeLayoutSections ? [
4174
4298
  ...homeLayoutSections.map((section)=>({
4175
4299
  ...section,
4176
- entities: section.entities.map((entityName)=>filteredEntities.find((entity)=>entity.declaration.name === entityName)).filter((entity)=>void 0 !== entity)
4300
+ entities: section.entities.map((entityName)=>filteredEntities.find((entity)=>entity.declaration.name === entityName)).filter(isNotNullish)
4177
4301
  })),
4178
4302
  {
4179
4303
  title: "Other",
4180
- entities: filteredEntities.filter((entity)=>!isEntityInAnyHomeLayoutSection(entity.declaration.name, homeLayoutSections))
4304
+ entities: filteredEntities.filter((entity)=>!isEntityInAnyHomeLayoutSection(entity.declaration.name, homeLayoutSections)).toSorted((a, b)=>a.declaration.name.localeCompare(b.declaration.name))
4181
4305
  }
4182
4306
  ].filter((section)=>section.entities.length > 0) : void 0;
4183
- const mapEntity = (entity)=>/*#__PURE__*/ jsxRuntime_module_u("li", {
4184
- class: "entries-item",
4185
- children: [
4186
- /*#__PURE__*/ jsxRuntime_module_u("div", {
4187
- class: "entries-item__title",
4188
- children: [
4189
- /*#__PURE__*/ jsxRuntime_module_u("h2", {
4190
- children: entity.declaration.displayNamePlural ?? toTitleCase(entity.declaration.namePlural)
4191
- }),
4192
- entity.declaration.comment && /*#__PURE__*/ jsxRuntime_module_u(Markdown, {
4193
- class: "description",
4194
- string: entity.declaration.comment
4195
- })
4196
- ]
4197
- }),
4198
- /*#__PURE__*/ jsxRuntime_module_u("p", {
4199
- class: "entries-item__subtitle",
4200
- children: [
4201
- entity.instanceCount,
4202
- " instance",
4203
- 1 === entity.instanceCount ? "" : "s"
4204
- ]
4205
- }),
4206
- /*#__PURE__*/ jsxRuntime_module_u("div", {
4207
- class: "entries-item__side",
4208
- children: /*#__PURE__*/ jsxRuntime_module_u("div", {
4209
- class: "btns",
4210
- children: /*#__PURE__*/ jsxRuntime_module_u("a", {
4211
- href: `/entities/${entity.declaration.name}`,
4212
- class: "btn",
4213
- children: "View"
4214
- })
4215
- })
4216
- })
4217
- ]
4218
- }, entity.declaration.name);
4219
4307
  return /*#__PURE__*/ jsxRuntime_module_u(Layout, {
4220
4308
  breadcrumbs: [],
4221
4309
  children: [
@@ -4273,13 +4361,17 @@ const Home = ()=>{
4273
4361
  }),
4274
4362
  /*#__PURE__*/ jsxRuntime_module_u("ul", {
4275
4363
  class: "entries entries--entities",
4276
- children: section.entities.map(mapEntity)
4364
+ children: section.entities.map((entity)=>/*#__PURE__*/ jsxRuntime_module_u(EntityRow, {
4365
+ entity: entity
4366
+ }, entity.declaration.name))
4277
4367
  })
4278
4368
  ]
4279
4369
  }, si))
4280
4370
  }) : /*#__PURE__*/ jsxRuntime_module_u("ul", {
4281
4371
  class: "entries entries--entities",
4282
- children: filteredEntities.map(mapEntity)
4372
+ children: filteredEntities.map((entity)=>/*#__PURE__*/ jsxRuntime_module_u(EntityRow, {
4373
+ entity: entity
4374
+ }, entity.declaration.name))
4283
4375
  })
4284
4376
  ]
4285
4377
  });
@@ -6065,7 +6157,7 @@ const InstanceRouteSkeleton = ({ mode, buttons, init, titleBuilder, onSubmit, on
6065
6157
  },
6066
6158
  {
6067
6159
  url: `/entities/${name}`,
6068
- label: entity ? toTitleCase(entity.namePlural) : name
6160
+ label: entity ? entity.displayNamePlural ?? toTitleCase(entity.namePlural) : name
6069
6161
  }
6070
6162
  ],
6071
6163
  children: [
@@ -6110,7 +6202,7 @@ const InstanceRouteSkeleton = ({ mode, buttons, init, titleBuilder, onSubmit, on
6110
6202
  },
6111
6203
  {
6112
6204
  url: `/entities/${name}`,
6113
- label: toTitleCase(entity.namePlural)
6205
+ label: entity.displayNamePlural ?? toTitleCase(entity.namePlural)
6114
6206
  }
6115
6207
  ],
6116
6208
  children: [
@@ -6268,6 +6360,279 @@ const CreateInstance = ()=>/*#__PURE__*/ jsxRuntime_module_u(InstanceRouteSkelet
6268
6360
  onSubmit: CreateInstance_onSubmit,
6269
6361
  onSave: CreateInstance_onSave
6270
6362
  });
6363
+ const constant = (value)=>()=>value;
6364
+ const SingletonInstanceRouteSkeleton_onBeforeUnload = (event)=>{
6365
+ event.preventDefault();
6366
+ event.returnValue = "unsaved changes";
6367
+ };
6368
+ const SingletonInstanceRouteSkeleton_applePlatformPattern = /(Mac|iPhone|iPod|iPad)/i;
6369
+ const SingletonInstanceRouteSkeleton_isApplePlatform = ()=>SingletonInstanceRouteSkeleton_applePlatformPattern.test(window.navigator.platform);
6370
+ const SingletonInstanceRouteSkeleton_checkCmdOrCtrl = (event)=>SingletonInstanceRouteSkeleton_isApplePlatform() ? event.metaKey : event.ctrlKey;
6371
+ const SingletonInstanceRouteSkeleton = ({ mode, buttons, init, titleBuilder, onSubmit, onSave })=>{
6372
+ const { params: { name } } = useRoute();
6373
+ const [locales] = useSetting("displayedLocales");
6374
+ const [getDeclFromDeclName, declsLoaded] = useGetDeclFromDeclName();
6375
+ const { declaration: entity } = useSingletonEntityFromRoute() ?? {};
6376
+ const [instanceNamesByEntity] = useInstanceNamesByEntity();
6377
+ const [instanceContent, setInstanceContent] = hooks_module_d();
6378
+ const [savedInstanceContent, setSavedInstanceContent] = hooks_module_d();
6379
+ const client = hooks_module_x(GitClientContext);
6380
+ const { reloadSingletonEntities } = hooks_module_x(SingletonEntitiesContext);
6381
+ const { route } = useLocation();
6382
+ const hasUnsavedChanges = hooks_module_T(()=>!deepEqual(instanceContent, savedInstanceContent), [
6383
+ instanceContent,
6384
+ savedInstanceContent
6385
+ ]);
6386
+ const saveHandler = hooks_module_q((event)=>{
6387
+ if (SingletonInstanceRouteSkeleton_checkCmdOrCtrl(event) && "s" === event.key && entity && void 0 !== instanceContent) {
6388
+ event.preventDefault();
6389
+ runWithLoading(()=>onSave({
6390
+ locales,
6391
+ entity,
6392
+ instanceContent,
6393
+ route,
6394
+ getDeclFromDeclName,
6395
+ setInstanceContent: (value)=>{
6396
+ setInstanceContent(value);
6397
+ setSavedInstanceContent(value);
6398
+ },
6399
+ updateLocalGitState: client?.updateLocalState,
6400
+ reloadSingletonEntities
6401
+ })).catch((error)=>{
6402
+ console.error("Error submitting instance data:", error);
6403
+ });
6404
+ }
6405
+ }, [
6406
+ client?.updateLocalState,
6407
+ entity,
6408
+ getDeclFromDeclName,
6409
+ instanceContent,
6410
+ locales,
6411
+ onSave,
6412
+ route,
6413
+ reloadSingletonEntities
6414
+ ]);
6415
+ hooks_module_h(()=>{
6416
+ if (hasUnsavedChanges) window.addEventListener("beforeunload", SingletonInstanceRouteSkeleton_onBeforeUnload);
6417
+ else window.removeEventListener("beforeunload", SingletonInstanceRouteSkeleton_onBeforeUnload);
6418
+ return ()=>{
6419
+ window.removeEventListener("beforeunload", SingletonInstanceRouteSkeleton_onBeforeUnload);
6420
+ };
6421
+ }, [
6422
+ hasUnsavedChanges
6423
+ ]);
6424
+ hooks_module_h(()=>{
6425
+ if (hasUnsavedChanges) window.addEventListener("keydown", saveHandler);
6426
+ else window.removeEventListener("keydown", saveHandler);
6427
+ return ()=>{
6428
+ window.removeEventListener("keydown", saveHandler);
6429
+ };
6430
+ }, [
6431
+ hasUnsavedChanges,
6432
+ saveHandler
6433
+ ]);
6434
+ hooks_module_h(()=>{
6435
+ document.title = (entity && titleBuilder({
6436
+ locales,
6437
+ entity,
6438
+ instanceContent
6439
+ })) ?? "Not found — TSONDB";
6440
+ }, [
6441
+ entity,
6442
+ instanceContent,
6443
+ locales,
6444
+ titleBuilder
6445
+ ]);
6446
+ hooks_module_h(()=>{
6447
+ if (entity && void 0 === instanceContent && declsLoaded) runWithLoading(()=>init({
6448
+ locales,
6449
+ entity,
6450
+ setInstanceContent: (value)=>{
6451
+ setInstanceContent(value);
6452
+ setSavedInstanceContent(value);
6453
+ },
6454
+ getDeclFromDeclName
6455
+ })).catch((error)=>{
6456
+ console.error("Error initializing instance route skeleton:", error);
6457
+ });
6458
+ }, [
6459
+ entity,
6460
+ declsLoaded,
6461
+ getDeclFromDeclName,
6462
+ init,
6463
+ instanceContent,
6464
+ locales,
6465
+ name
6466
+ ]);
6467
+ const handleSubmit = (event)=>{
6468
+ event.preventDefault();
6469
+ if (entity && void 0 !== instanceContent) {
6470
+ const buttonName = event.submitter?.getAttribute("name") ?? void 0;
6471
+ runWithLoading(()=>onSubmit({
6472
+ locales,
6473
+ entity,
6474
+ instanceContent,
6475
+ buttonName,
6476
+ route,
6477
+ getDeclFromDeclName,
6478
+ setInstanceContent: (value)=>{
6479
+ setInstanceContent(value);
6480
+ setSavedInstanceContent(value);
6481
+ },
6482
+ updateLocalGitState: client?.updateLocalState,
6483
+ reloadSingletonEntities
6484
+ })).catch((error)=>{
6485
+ console.error("Error submitting instance data:", error);
6486
+ });
6487
+ }
6488
+ };
6489
+ if (!name) return /*#__PURE__*/ jsxRuntime_module_u(NotFound, {});
6490
+ if (!entity || void 0 === instanceContent || !instanceNamesByEntity || !declsLoaded) return /*#__PURE__*/ jsxRuntime_module_u(Layout, {
6491
+ breadcrumbs: [
6492
+ {
6493
+ url: "/",
6494
+ label: homeTitle
6495
+ }
6496
+ ],
6497
+ children: [
6498
+ /*#__PURE__*/ jsxRuntime_module_u("div", {
6499
+ class: "header-with-btns",
6500
+ children: [
6501
+ /*#__PURE__*/ jsxRuntime_module_u("h1", {
6502
+ class: "empty-name",
6503
+ children: /*#__PURE__*/ jsxRuntime_module_u("span", {
6504
+ children: entity ? entity.displayName ?? toTitleCase(entity.name) : name
6505
+ })
6506
+ }),
6507
+ /*#__PURE__*/ jsxRuntime_module_u("button", {
6508
+ class: "destructive",
6509
+ disabled: true,
6510
+ children: "Delete"
6511
+ })
6512
+ ]
6513
+ }),
6514
+ /*#__PURE__*/ jsxRuntime_module_u("p", {
6515
+ class: "loading",
6516
+ children: "Loading …"
6517
+ })
6518
+ ]
6519
+ });
6520
+ const defaultName = "edit" === mode ? entity.displayName ?? toTitleCase(entity.name) : `New ${entity.displayName ?? toTitleCase(entity.name)}`;
6521
+ return /*#__PURE__*/ jsxRuntime_module_u(Layout, {
6522
+ breadcrumbs: [
6523
+ {
6524
+ url: "/",
6525
+ label: homeTitle
6526
+ }
6527
+ ],
6528
+ children: [
6529
+ /*#__PURE__*/ jsxRuntime_module_u("div", {
6530
+ class: "header-with-btns",
6531
+ children: [
6532
+ /*#__PURE__*/ jsxRuntime_module_u("h1", {
6533
+ children: /*#__PURE__*/ jsxRuntime_module_u("span", {
6534
+ children: defaultName
6535
+ })
6536
+ }),
6537
+ "edit" === mode && /*#__PURE__*/ jsxRuntime_module_u("button", {
6538
+ class: "destructive",
6539
+ onClick: ()=>{
6540
+ if (confirm("Are you sure you want to delete this instance?")) deleteSingletonInstanceByEntityName(locales, entity.name).then(()=>reloadSingletonEntities()).then(()=>{
6541
+ route("/");
6542
+ }).catch((error)=>{
6543
+ if (error instanceof Error) alert("Error deleting instance:\n\n" + error.toString());
6544
+ });
6545
+ },
6546
+ children: "Delete"
6547
+ })
6548
+ ]
6549
+ }),
6550
+ /*#__PURE__*/ jsxRuntime_module_u("form", {
6551
+ onSubmit: handleSubmit,
6552
+ children: [
6553
+ /*#__PURE__*/ jsxRuntime_module_u(MemoizedTypeInput, {
6554
+ type: entity.type,
6555
+ value: instanceContent,
6556
+ path: void 0,
6557
+ instanceNamesByEntity: instanceNamesByEntity,
6558
+ childInstances: [],
6559
+ getDeclFromDeclName: getDeclFromDeclName,
6560
+ onChange: setInstanceContent,
6561
+ setChildInstances: ()=>void 0,
6562
+ checkIsLocaleEntity: constant(false)
6563
+ }),
6564
+ /*#__PURE__*/ jsxRuntime_module_u("div", {
6565
+ class: "form-footer btns",
6566
+ children: buttons.map((button)=>/*#__PURE__*/ jsxRuntime_module_u("button", {
6567
+ type: "submit",
6568
+ name: button.name,
6569
+ class: button.primary ? "primary" : void 0,
6570
+ disabled: !hasUnsavedChanges,
6571
+ children: button.label
6572
+ }, button.name))
6573
+ })
6574
+ ]
6575
+ })
6576
+ ]
6577
+ });
6578
+ };
6579
+ const CreateSingletonInstance_init = ({ entity, setInstanceContent, getDeclFromDeclName })=>{
6580
+ setInstanceContent(createTypeSkeleton(getDeclFromDeclName, entity.type));
6581
+ return Promise.resolve();
6582
+ };
6583
+ const CreateSingletonInstance_titleBuilder = ({ entity })=>{
6584
+ const entityName = entity.name;
6585
+ return "New " + toTitleCase(entityName) + " — TSONDB";
6586
+ };
6587
+ const CreateSingletonInstance_submit = async ({ locales, entity, action, instanceContent, setInstanceContent, route, updateLocalGitState, reloadSingletonEntities })=>{
6588
+ try {
6589
+ const createdInstance = await createSingletonInstanceByEntityName(locales, entity.name, {
6590
+ entityName: entity.name,
6591
+ content: instanceContent
6592
+ });
6593
+ await updateLocalGitState?.();
6594
+ await reloadSingletonEntities();
6595
+ switch(action){
6596
+ case "saveandcontinue":
6597
+ route(`/entities/${entity.name}/instance`);
6598
+ setInstanceContent(createdInstance.instance.content);
6599
+ break;
6600
+ case "save":
6601
+ route(`/?created=${encodeURIComponent(entity.name)}`);
6602
+ break;
6603
+ }
6604
+ } catch (error) {
6605
+ if (error instanceof Error) alert(`Error creating instance:\n\n${error.toString()}`);
6606
+ }
6607
+ };
6608
+ const CreateSingletonInstance_onSubmit = async ({ buttonName, ...other })=>{
6609
+ if ("save" === buttonName || "saveandcontinue" === buttonName) await CreateSingletonInstance_submit({
6610
+ ...other,
6611
+ action: buttonName
6612
+ });
6613
+ };
6614
+ const CreateSingletonInstance_onSave = (other)=>CreateSingletonInstance_submit({
6615
+ ...other,
6616
+ action: "saveandcontinue"
6617
+ });
6618
+ const CreateSingletonInstance = ()=>/*#__PURE__*/ jsxRuntime_module_u(SingletonInstanceRouteSkeleton, {
6619
+ mode: "create",
6620
+ buttons: [
6621
+ {
6622
+ label: "Save",
6623
+ name: "save",
6624
+ primary: true
6625
+ },
6626
+ {
6627
+ label: "Save and continue",
6628
+ name: "saveandcontinue"
6629
+ }
6630
+ ],
6631
+ init: CreateSingletonInstance_init,
6632
+ titleBuilder: CreateSingletonInstance_titleBuilder,
6633
+ onSubmit: CreateSingletonInstance_onSubmit,
6634
+ onSave: CreateSingletonInstance_onSave
6635
+ });
6271
6636
  const Entity_localeMapper = (result)=>result.instances;
6272
6637
  const mapInstances = (data)=>data.instances;
6273
6638
  const Entity = ()=>{
@@ -6670,14 +7035,78 @@ const Search = ()=>{
6670
7035
  ]
6671
7036
  });
6672
7037
  };
7038
+ const SingletonInstance_init = async ({ locales, entity, setInstanceContent })=>{
7039
+ try {
7040
+ const instanceData = await getSingletonInstanceByEntityName(locales, entity.name);
7041
+ setInstanceContent(instanceData.instance.content);
7042
+ } catch (error) {
7043
+ console.error("Error fetching entities:", error);
7044
+ }
7045
+ };
7046
+ const SingletonInstance_titleBuilder = ({ entity, instanceContent })=>{
7047
+ if (instanceContent) return toTitleCase(entity.name) + " — TSONDB";
7048
+ };
7049
+ const SingletonInstance_submit = async ({ action, locales, entity, instanceContent, route, updateLocalGitState, setInstanceContent })=>{
7050
+ try {
7051
+ await updateSingletonInstanceByEntityName(locales, entity.name, {
7052
+ entityName: entity.name,
7053
+ content: instanceContent
7054
+ });
7055
+ await updateLocalGitState?.();
7056
+ switch(action){
7057
+ case "saveandcontinue":
7058
+ setInstanceContent(instanceContent);
7059
+ break;
7060
+ case "save":
7061
+ route("/");
7062
+ break;
7063
+ }
7064
+ } catch (error) {
7065
+ if (error instanceof Error) alert(`Error updating instance:\n\n${error}`);
7066
+ }
7067
+ };
7068
+ const SingletonInstance_onSubmit = async ({ buttonName, ...other })=>{
7069
+ if ("save" === buttonName || "saveandcontinue" === buttonName) await SingletonInstance_submit({
7070
+ ...other,
7071
+ action: buttonName
7072
+ });
7073
+ };
7074
+ const SingletonInstance_onSave = (other)=>SingletonInstance_submit({
7075
+ ...other,
7076
+ action: "saveandcontinue"
7077
+ });
7078
+ const SingletonInstance = ()=>/*#__PURE__*/ jsxRuntime_module_u(SingletonInstanceRouteSkeleton, {
7079
+ mode: "edit",
7080
+ buttons: [
7081
+ {
7082
+ label: "Save",
7083
+ name: "save",
7084
+ primary: true
7085
+ },
7086
+ {
7087
+ label: "Save and continue",
7088
+ name: "saveandcontinue"
7089
+ }
7090
+ ],
7091
+ init: SingletonInstance_init,
7092
+ titleBuilder: SingletonInstance_titleBuilder,
7093
+ onSubmit: SingletonInstance_onSubmit,
7094
+ onSave: SingletonInstance_onSave
7095
+ });
6673
7096
  const mapEntities = (data)=>data.declarations.map((decl)=>({
6674
7097
  ...decl,
6675
- isLocaleEntity: decl.declaration.name === data.localeEntity
7098
+ isLocaleEntity: decl.declaration.name === data.localeEntity,
7099
+ type: Node_NodeKind.EntityDecl
7100
+ })).sort((a, b)=>a.declaration.name.localeCompare(b.declaration.name));
7101
+ const mapSingletonEntities = (data)=>data.declarations.map((decl)=>({
7102
+ ...decl,
7103
+ type: Node_NodeKind.SingletonEntityDecl
6676
7104
  })).sort((a, b)=>a.declaration.name.localeCompare(b.declaration.name));
6677
7105
  const App = ({ config })=>{
6678
7106
  const settingsContext = useSettings(config);
6679
7107
  const [isGitOpen, setIsGitOpen] = hooks_module_d(false);
6680
7108
  const [entities, reloadEntities] = useMappedAPIResource(getAllEntities, mapEntities, settingsContext.settings.displayedLocales);
7109
+ const [singletonEntities, reloadSingletonEntities] = useMappedAPIResource(getAllSingletonEntities, mapSingletonEntities, settingsContext.settings.displayedLocales);
6681
7110
  const location1 = useLocation();
6682
7111
  hooks_module_h(()=>{
6683
7112
  reloadEntities().catch((error)=>{
@@ -6702,41 +7131,55 @@ const App = ({ config })=>{
6702
7131
  entities: entities ?? [],
6703
7132
  reloadEntities
6704
7133
  },
6705
- children: /*#__PURE__*/ jsxRuntime_module_u(ContextProviderWrapper, {
6706
- context: GitClientContext,
6707
- useValue: useGitClient,
6708
- children: [
6709
- /*#__PURE__*/ jsxRuntime_module_u(LoadingOverlay, {}),
6710
- /*#__PURE__*/ jsxRuntime_module_u(Router, {
6711
- children: [
6712
- /*#__PURE__*/ jsxRuntime_module_u(Route, {
6713
- path: "/",
6714
- component: Home
6715
- }),
6716
- /*#__PURE__*/ jsxRuntime_module_u(Route, {
6717
- path: "/search",
6718
- component: Search
6719
- }),
6720
- /*#__PURE__*/ jsxRuntime_module_u(Route, {
6721
- path: "/entities/:name",
6722
- component: Entity
6723
- }),
6724
- /*#__PURE__*/ jsxRuntime_module_u(Route, {
6725
- path: "/entities/:name/instances/create",
6726
- component: CreateInstance
6727
- }),
6728
- /*#__PURE__*/ jsxRuntime_module_u(Route, {
6729
- path: "/entities/:name/instances/:id",
6730
- component: Instance
6731
- }),
6732
- /*#__PURE__*/ jsxRuntime_module_u(Route, {
6733
- default: true,
6734
- component: NotFound
6735
- })
6736
- ]
6737
- }),
6738
- /*#__PURE__*/ jsxRuntime_module_u(Git, {})
6739
- ]
7134
+ children: /*#__PURE__*/ jsxRuntime_module_u(SingletonEntitiesContext.Provider, {
7135
+ value: {
7136
+ singletonEntities: singletonEntities ?? [],
7137
+ reloadSingletonEntities
7138
+ },
7139
+ children: /*#__PURE__*/ jsxRuntime_module_u(ContextProviderWrapper, {
7140
+ context: GitClientContext,
7141
+ useValue: useGitClient,
7142
+ children: [
7143
+ /*#__PURE__*/ jsxRuntime_module_u(LoadingOverlay, {}),
7144
+ /*#__PURE__*/ jsxRuntime_module_u(Router, {
7145
+ children: [
7146
+ /*#__PURE__*/ jsxRuntime_module_u(Route, {
7147
+ path: "/",
7148
+ component: Home
7149
+ }),
7150
+ /*#__PURE__*/ jsxRuntime_module_u(Route, {
7151
+ path: "/search",
7152
+ component: Search
7153
+ }),
7154
+ /*#__PURE__*/ jsxRuntime_module_u(Route, {
7155
+ path: "/entities/:name",
7156
+ component: Entity
7157
+ }),
7158
+ /*#__PURE__*/ jsxRuntime_module_u(Route, {
7159
+ path: "/entities/:name/instances/create",
7160
+ component: CreateInstance
7161
+ }),
7162
+ /*#__PURE__*/ jsxRuntime_module_u(Route, {
7163
+ path: "/entities/:name/instances/:id",
7164
+ component: Instance
7165
+ }),
7166
+ /*#__PURE__*/ jsxRuntime_module_u(Route, {
7167
+ path: "/entities/:name/instance/create",
7168
+ component: CreateSingletonInstance
7169
+ }),
7170
+ /*#__PURE__*/ jsxRuntime_module_u(Route, {
7171
+ path: "/entities/:name/instance",
7172
+ component: SingletonInstance
7173
+ }),
7174
+ /*#__PURE__*/ jsxRuntime_module_u(Route, {
7175
+ default: true,
7176
+ component: NotFound
7177
+ })
7178
+ ]
7179
+ }),
7180
+ /*#__PURE__*/ jsxRuntime_module_u(Git, {})
7181
+ ]
7182
+ })
6740
7183
  })
6741
7184
  })
6742
7185
  })