@sealcode/sealgen 0.15.2 → 0.15.4

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 (200) hide show
  1. package/.eslintrc.cjs +38 -0
  2. package/.xunit +53 -0
  3. package/@types/src/page/stateful-page.d.ts +4 -2
  4. package/build.js +1 -1
  5. package/{dist → lib}/add-route.test.js +2 -2
  6. package/{dist → lib}/build.js +3 -3
  7. package/{dist → lib}/builder.js +3 -0
  8. package/lib/cli.js +39 -0
  9. package/{dist → lib}/esbuild-plugins/load-assets.js +2 -2
  10. package/{dist → lib}/forms/controls/array.js +1 -2
  11. package/{dist → lib}/forms/controls/autocomplete.js +8 -10
  12. package/{dist → lib}/forms/controls/checkboxed-list-input.test.js +3 -2
  13. package/{dist → lib}/forms/controls/collapsible-field-group.js +2 -1
  14. package/{dist → lib}/forms/controls/editable-collection-subset.js +6 -4
  15. package/{dist → lib}/forms/controls/field-group.js +1 -1
  16. package/{dist → lib}/forms/controls/file.js +2 -5
  17. package/{dist → lib}/forms/controls/form-control.js +2 -1
  18. package/{dist → lib}/forms/controls/photo.js +1 -1
  19. package/{dist → lib}/forms/controls/photo.test.js +5 -7
  20. package/{dist → lib}/forms/controls/textarea.js +1 -1
  21. package/{dist → lib}/forms/fields/boolean.test.js +0 -1
  22. package/{dist → lib}/forms/fields/field.js +2 -5
  23. package/{dist → lib}/forms/fields/file.js +8 -2
  24. package/{dist → lib}/forms/fields/structured-array.js +1 -1
  25. package/{dist → lib}/forms/form.test.js +8 -9
  26. package/{dist → lib}/forms/multiform.test.js +14 -14
  27. package/{dist → lib}/generate-components.js +1 -1
  28. package/{dist → lib}/generate-routes.test.js +1 -0
  29. package/{dist → lib}/generate-stimulus.js +1 -1
  30. package/{dist → lib}/mount.js +4 -3
  31. package/{dist → lib}/notifier.js +3 -1
  32. package/{dist → lib}/page/list.js +1 -1
  33. package/{dist → lib}/page/mountable-with-fields.js +1 -1
  34. package/{dist → lib}/page/sealious-list.js +2 -2
  35. package/{dist → lib}/page/stateful-page.js +34 -17
  36. package/{dist → lib}/templates/jdd-component.js +2 -2
  37. package/{dist → lib}/utils/extract-fields-from-collection.js +16 -1
  38. package/package.json +20 -15
  39. package/src/add-route.test.ts +2 -2
  40. package/src/add-route.ts +2 -2
  41. package/src/build.ts +3 -3
  42. package/src/builder.ts +3 -2
  43. package/src/esbuild-plugins/load-assets.ts +5 -4
  44. package/src/esbuild-plugins/rewrite-asset-imports.ts +4 -3
  45. package/src/forms/controls/array.ts +5 -3
  46. package/src/forms/controls/autocomplete.ts +2 -2
  47. package/src/forms/controls/checkbox-group.ts +1 -5
  48. package/src/forms/controls/checkboxed-list-input.test.ts +3 -2
  49. package/src/forms/controls/checkboxed-list-input.ts +0 -1
  50. package/src/forms/controls/collapsible-field-group.ts +4 -2
  51. package/src/forms/controls/derived.ts +1 -1
  52. package/src/forms/controls/dropdown.ts +3 -3
  53. package/src/forms/controls/editable-collection-subset.ts +10 -4
  54. package/src/forms/controls/field-group.ts +1 -1
  55. package/src/forms/controls/file.ts +1 -1
  56. package/src/forms/controls/form-control.ts +2 -1
  57. package/src/forms/controls/hidden-input.ts +0 -2
  58. package/src/forms/controls/multiple-files.ts +8 -5
  59. package/src/forms/controls/number.ts +1 -1
  60. package/src/forms/controls/photo.test.ts +6 -7
  61. package/src/forms/controls/photo.ts +3 -6
  62. package/src/forms/controls/simple-input.ts +3 -5
  63. package/src/forms/controls/textarea.ts +3 -8
  64. package/src/forms/controls/tickable.ts +2 -4
  65. package/src/forms/fields/boolean.test.ts +0 -1
  66. package/src/forms/fields/existing-sealious-value.ts +1 -0
  67. package/src/forms/fields/field.ts +5 -8
  68. package/src/forms/fields/file.ts +13 -6
  69. package/src/forms/fields/structured-array.ts +2 -2
  70. package/src/forms/form.test.ts +9 -10
  71. package/src/forms/form.ts +1 -1
  72. package/src/forms/multiform.test.ts +14 -14
  73. package/src/forms/multiform.ts +2 -1
  74. package/src/generate-components.ts +1 -2
  75. package/src/generate-routes.test.ts +1 -0
  76. package/src/generate-stimulus.ts +1 -1
  77. package/src/get-fonts.ts +2 -0
  78. package/src/mount.ts +8 -3
  79. package/src/notifier.ts +3 -1
  80. package/src/page/list.ts +1 -1
  81. package/src/page/mountable-with-fields.ts +3 -1
  82. package/src/page/sealious-list.ts +3 -2
  83. package/src/page/stateful-page.ts +50 -22
  84. package/src/templates/jdd-component.ts +2 -2
  85. package/src/utils/extract-fields-from-collection.ts +19 -1
  86. package/src/utils/translate.ts +1 -1
  87. package/src/utils/utils.ts +2 -0
  88. package/test.cjs +54 -0
  89. package/tsconfig.json +3 -4
  90. package/dist/back/routes/sample.page.js +0 -17
  91. package/dist/back/routes/sample.test.js +0 -39
  92. package/dist/hehe.test.js +0 -7
  93. package/dist/sample-index.js +0 -3
  94. package/dist/sample-lib.js +0 -9
  95. package/dist/vitest.config.js +0 -23
  96. package/src/vitest.config.ts +0 -21
  97. /package/{dist → lib}/add-collection.js +0 -0
  98. /package/{dist → lib}/add-jdd-component.js +0 -0
  99. /package/{dist → lib}/add-route.js +0 -0
  100. /package/{dist → lib}/components/components.js +0 -0
  101. /package/{dist → lib}/components/tabs.js +0 -0
  102. /package/{dist → lib}/components/toggle-modal.js +0 -0
  103. /package/{dist → lib}/embeddable-file-extensions.js +0 -0
  104. /package/{dist → lib}/esbuild-plugins/rewrite-asset-imports.js +0 -0
  105. /package/{dist → lib}/example.test.js +0 -0
  106. /package/{dist → lib}/find-css-includes.js +0 -0
  107. /package/{dist → lib}/forms/controls/big-radio-group.js +0 -0
  108. /package/{dist → lib}/forms/controls/checkbox-group.js +0 -0
  109. /package/{dist → lib}/forms/controls/checkbox.js +0 -0
  110. /package/{dist → lib}/forms/controls/checkboxed-list-input.js +0 -0
  111. /package/{dist → lib}/forms/controls/collapsible-checkbox-group.js +0 -0
  112. /package/{dist → lib}/forms/controls/controls.js +0 -0
  113. /package/{dist → lib}/forms/controls/derived-frame.js +0 -0
  114. /package/{dist → lib}/forms/controls/derived.js +0 -0
  115. /package/{dist → lib}/forms/controls/dropdown.js +0 -0
  116. /package/{dist → lib}/forms/controls/form-field-control.js +0 -0
  117. /package/{dist → lib}/forms/controls/form-header.js +0 -0
  118. /package/{dist → lib}/forms/controls/form-paragraph.js +0 -0
  119. /package/{dist → lib}/forms/controls/frame.js +0 -0
  120. /package/{dist → lib}/forms/controls/hidden-input.js +0 -0
  121. /package/{dist → lib}/forms/controls/html.js +0 -0
  122. /package/{dist → lib}/forms/controls/multiple-files.js +0 -0
  123. /package/{dist → lib}/forms/controls/multiple-photos.js +0 -0
  124. /package/{dist → lib}/forms/controls/number.js +0 -0
  125. /package/{dist → lib}/forms/controls/radio.js +0 -0
  126. /package/{dist → lib}/forms/controls/reverse-single-reference.js +0 -0
  127. /package/{dist → lib}/forms/controls/simple-input.js +0 -0
  128. /package/{dist → lib}/forms/controls/tickable.js +0 -0
  129. /package/{dist → lib}/forms/fields/boolean.js +0 -0
  130. /package/{dist → lib}/forms/fields/checkboxed-list.js +0 -0
  131. /package/{dist → lib}/forms/fields/collection-field.js +0 -0
  132. /package/{dist → lib}/forms/fields/email.js +0 -0
  133. /package/{dist → lib}/forms/fields/email.test.js +0 -0
  134. /package/{dist → lib}/forms/fields/enum-multiple.js +0 -0
  135. /package/{dist → lib}/forms/fields/enum-multiple.test.js +0 -0
  136. /package/{dist → lib}/forms/fields/enum.js +0 -0
  137. /package/{dist → lib}/forms/fields/enum.test.js +0 -0
  138. /package/{dist → lib}/forms/fields/existing-sealious-value.js +0 -0
  139. /package/{dist → lib}/forms/fields/fields.js +0 -0
  140. /package/{dist → lib}/forms/fields/multiple-files.js +0 -0
  141. /package/{dist → lib}/forms/fields/number.js +0 -0
  142. /package/{dist → lib}/forms/fields/number.test.js +0 -0
  143. /package/{dist → lib}/forms/fields/pick-from-list.js +0 -0
  144. /package/{dist → lib}/forms/fields/pick-from-list.test.js +0 -0
  145. /package/{dist → lib}/forms/fields/proxy-field.js +0 -0
  146. /package/{dist → lib}/forms/fields/regexp.js +0 -0
  147. /package/{dist → lib}/forms/fields/regexp.test.js +0 -0
  148. /package/{dist → lib}/forms/fields/reverse-single-reference.js +0 -0
  149. /package/{dist → lib}/forms/fields/simple-form-field.js +0 -0
  150. /package/{dist → lib}/forms/form-types.js +0 -0
  151. /package/{dist → lib}/forms/form.js +0 -0
  152. /package/{dist → lib}/forms/multiform.js +0 -0
  153. /package/{dist → lib}/generate-collections.js +0 -0
  154. /package/{dist → lib}/generate-routes.js +0 -0
  155. /package/{dist → lib}/get-fonts.js +0 -0
  156. /package/{dist → lib}/index.js +0 -0
  157. /package/{dist → lib}/koa.d.js +0 -0
  158. /package/{dist → lib}/make-env.js +0 -0
  159. /package/{dist → lib}/make-hidden-inputs.js +0 -0
  160. /package/{dist → lib}/page/access-control.js +0 -0
  161. /package/{dist → lib}/page/default-list-filters.js +0 -0
  162. /package/{dist → lib}/page/mountable.js +0 -0
  163. /package/{dist → lib}/page/page.js +0 -0
  164. /package/{dist → lib}/page/props-parser.js +0 -0
  165. /package/{dist → lib}/run.js +0 -0
  166. /package/{dist → lib}/sanitize.js +0 -0
  167. /package/{dist → lib}/target-locreq.js +0 -0
  168. /package/{dist → lib}/templates/collection.js +0 -0
  169. /package/{dist → lib}/templates/form.js +0 -0
  170. /package/{dist → lib}/templates/list.js +0 -0
  171. /package/{dist → lib}/templates/long-running-process.js +0 -0
  172. /package/{dist → lib}/templates/multiform.js +0 -0
  173. /package/{dist → lib}/templates/page.js +0 -0
  174. /package/{dist → lib}/templates/post.js +0 -0
  175. /package/{dist → lib}/templates/redirect.js +0 -0
  176. /package/{dist → lib}/templates/route-test.js +0 -0
  177. /package/{dist → lib}/templates/stateful-page.js +0 -0
  178. /package/{dist → lib}/templates/stimulus-controller.js +0 -0
  179. /package/{dist → lib}/templates/templates.js +0 -0
  180. /package/{dist → lib}/test_utils/locator_is_visible.js +0 -0
  181. /package/{dist → lib}/utils/assert-throws.js +0 -0
  182. /package/{dist → lib}/utils/base64.js +0 -0
  183. /package/{dist → lib}/utils/browser-creator.js +0 -0
  184. /package/{dist → lib}/utils/escape-url-params.js +0 -0
  185. /package/{dist → lib}/utils/exec.js +0 -0
  186. /package/{dist → lib}/utils/format-external-url.js +0 -0
  187. /package/{dist → lib}/utils/import-path.js +0 -0
  188. /package/{dist → lib}/utils/input-wrapper.js +0 -0
  189. /package/{dist → lib}/utils/list-collections.js +0 -0
  190. /package/{dist → lib}/utils/make-slug.js +0 -0
  191. /package/{dist → lib}/utils/module-dirname.js +0 -0
  192. /package/{dist → lib}/utils/natural-numbers.js +0 -0
  193. /package/{dist → lib}/utils/prettier.js +0 -0
  194. /package/{dist → lib}/utils/question.js +0 -0
  195. /package/{dist → lib}/utils/render-attributes.js +0 -0
  196. /package/{dist → lib}/utils/sleep.js +0 -0
  197. /package/{dist → lib}/utils/translate.js +0 -0
  198. /package/{dist → lib}/utils/url-with-new-params.js +0 -0
  199. /package/{dist → lib}/utils/utils.js +0 -0
  200. /package/{dist → lib}/utils/walk.js +0 -0
@@ -77,7 +77,7 @@ function multiform_factory(
77
77
  async function tests(js_enabled: boolean) {
78
78
  let page: Page;
79
79
 
80
- beforeAll(async () => {
80
+ before(async () => {
81
81
  const browser = await getBrowser();
82
82
  const context = await browser.newContext({
83
83
  javaScriptEnabled: js_enabled,
@@ -127,7 +127,7 @@ async function individual_field_validation_e2e_tests(javaScriptEnabled: boolean)
127
127
  let browser: Browser;
128
128
  let page: Page;
129
129
 
130
- beforeAll(async () => {
130
+ before(async () => {
131
131
  browser = await getBrowser();
132
132
  const context = await browser.newContext({
133
133
  javaScriptEnabled,
@@ -157,7 +157,7 @@ describe("multiform test", () => {
157
157
  describe("basic tests", async () => {
158
158
  let server: ReturnType<Koa["listen"]>;
159
159
 
160
- beforeAll(async () => {
160
+ before(async () => {
161
161
  const app = new Koa();
162
162
  const router = new Router();
163
163
 
@@ -198,7 +198,7 @@ describe("multiform test", () => {
198
198
  server = app.listen(port);
199
199
  });
200
200
 
201
- afterAll(() => {
201
+ after(() => {
202
202
  server.close();
203
203
  });
204
204
 
@@ -211,7 +211,7 @@ describe("multiform test", () => {
211
211
  let server: ReturnType<Koa["listen"]>;
212
212
 
213
213
  describe("allow access to both forms when both canAccess return true", async () => {
214
- beforeAll(async () => {
214
+ before(async () => {
215
215
  const app = new Koa();
216
216
  const router = new Router();
217
217
 
@@ -239,7 +239,7 @@ describe("multiform test", () => {
239
239
  page = await context.newPage();
240
240
  });
241
241
 
242
- afterAll(async () => {
242
+ after(async () => {
243
243
  server.close();
244
244
  });
245
245
 
@@ -272,7 +272,7 @@ describe("multiform test", () => {
272
272
  });
273
273
 
274
274
  describe("deny access to both forms", async () => {
275
- beforeAll(async () => {
275
+ before(async () => {
276
276
  const app = new Koa();
277
277
  const router = new Router();
278
278
 
@@ -300,7 +300,7 @@ describe("multiform test", () => {
300
300
  page = await context.newPage();
301
301
  });
302
302
 
303
- afterAll(async () => {
303
+ after(async () => {
304
304
  server.close();
305
305
  });
306
306
 
@@ -331,7 +331,7 @@ describe("multiform test", () => {
331
331
  });
332
332
 
333
333
  describe("allow access to one form, deny to the other", async () => {
334
- beforeAll(async () => {
334
+ before(async () => {
335
335
  const app = new Koa();
336
336
  const router = new Router();
337
337
 
@@ -359,7 +359,7 @@ describe("multiform test", () => {
359
359
  page = await context.newPage();
360
360
  });
361
361
 
362
- afterAll(async () => {
362
+ after(async () => {
363
363
  server.close();
364
364
  });
365
365
 
@@ -414,7 +414,7 @@ describe("multiform test", () => {
414
414
  describe("basic tests", async () => {
415
415
  let server: ReturnType<Koa["listen"]>;
416
416
 
417
- beforeAll(async () => {
417
+ before(async () => {
418
418
  const app = new Koa();
419
419
  const router = new Router();
420
420
 
@@ -475,7 +475,7 @@ describe("multiform test", () => {
475
475
  server = app.listen(port);
476
476
  });
477
477
 
478
- afterAll(async () => {
478
+ after(async () => {
479
479
  server.close();
480
480
  });
481
481
 
@@ -486,7 +486,7 @@ describe("multiform test", () => {
486
486
  describe("field specific validation", async () => {
487
487
  let server: ReturnType<Koa["listen"]>;
488
488
 
489
- beforeAll(async () => {
489
+ before(async () => {
490
490
  const app = new Koa();
491
491
  const router = new Router();
492
492
  const fields = {
@@ -538,7 +538,7 @@ describe("multiform test", () => {
538
538
  server = app.listen(port);
539
539
  });
540
540
 
541
- afterAll(async () => {
541
+ after(async () => {
542
542
  server.close();
543
543
  });
544
544
 
@@ -1,10 +1,11 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
1
2
  import Router from "@koa/router";
2
3
  import { is, predicates } from "@sealcode/ts-predicates";
3
4
  import { Context } from "koa";
4
5
  import { FlatTemplatable, tempstream } from "tempstream";
5
6
  import { Fields, MountableWithFields } from "../page/mountable-with-fields.js";
6
7
  import { attribute } from "../sanitize.js";
7
- import type { FormDataValue, FormMessage, FormData } from "./form-types.js";
8
+ import type { FormDataValue, FormMessage } from "./form-types.js";
8
9
  import { Form } from "./form.js";
9
10
 
10
11
  const FIELD_PREFIX_SEPARATOR = "___";
@@ -1,7 +1,6 @@
1
1
  import _locreq from "locreq";
2
2
  import * as prettier from "prettier";
3
3
  import { promises as fs } from "fs";
4
- import { assertType, predicates } from "@sealcode/ts-predicates";
5
4
  import { getPrettierConfig } from "./utils/prettier.js";
6
5
  import recursive from "recursive-readdir";
7
6
  import path from "path";
@@ -23,7 +22,7 @@ export async function generateComponents(): Promise<void> {
23
22
  path.relative(components_dir, p).replace(/\.[tj]sx?$/, ".js")
24
23
  )
25
24
  .map((relative_path) => {
26
- const name = relative_path.match(/\/([^\/]+).jdd/)?.[1];
25
+ const name = relative_path.match(/\/([^/]+).jdd/)?.[1];
27
26
  return { name, relative_path };
28
27
  });
29
28
 
@@ -1,6 +1,7 @@
1
1
  import { generateURL } from "./generate-routes.js";
2
2
  import * as prettier from "prettier";
3
3
  import { getPrettierConfig } from "./utils/prettier.js";
4
+ import assert from "node:assert";
4
5
 
5
6
  describe("generate routes", () => {
6
7
  it("handles a url with params", async () => {
@@ -23,7 +23,7 @@ export async function generateStimulusControllers(): Promise<void> {
23
23
  .replace(/\.[tj]sx?$/, ".js")
24
24
  )
25
25
  .map((relative_path) => {
26
- const name = relative_path.match(/\/([^\/]+).stimulus/)?.[1];
26
+ const name = relative_path.match(/\/([^/]+).stimulus/)?.[1];
27
27
  return { name, relative_path };
28
28
  });
29
29
 
package/src/get-fonts.ts CHANGED
@@ -7,7 +7,9 @@ export const FONTS_CONFIG_PATH = "src/fonts.json";
7
7
  export async function getFonts(_: Record<string, string | boolean> = {}) {
8
8
  const fonts_config_path = target_locreq.resolve(FONTS_CONFIG_PATH);
9
9
 
10
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
10
11
  const fonts_config = JSON.parse(await readFile(fonts_config_path, "utf8"));
12
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
11
13
  const fonts_url = constructURL(fonts_config.googleFonts);
12
14
  if (!fonts_url) {
13
15
  throw new Error("Invalid font config");
package/src/mount.ts CHANGED
@@ -1,4 +1,6 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
1
2
  import Router from "@koa/router";
3
+ import { FileManager } from "@sealcode/file-manager";
2
4
  import Koa, { BaseContext, Context } from "koa";
3
5
  import { Middlewares as SealiousMiddlewares } from "sealious";
4
6
  import { Mountable } from "./page/mountable.js";
@@ -16,7 +18,10 @@ export function mount(
16
18
  router: Router,
17
19
  url: string | { rawURL: string },
18
20
  mountable: Mountable,
19
- use_dummy_app = false
21
+ use_dummy_app = false,
22
+ file_manager: FileManager | undefined = use_dummy_app
23
+ ? new FileManager("/tmp", "/uploaded_files")
24
+ : undefined
20
25
  ): void {
21
26
  const raw_url = typeof url === "string" ? url : url.rawURL;
22
27
  const args = use_dummy_app
@@ -48,12 +53,12 @@ export function mount(
48
53
  // eslint-disable-next-line @typescript-eslint/no-unsafe-call
49
54
  await next();
50
55
  },
51
- SealiousMiddlewares.parseBody(),
56
+ SealiousMiddlewares.parseBody(file_manager),
52
57
  handleHtmlPromise,
53
58
  ]
54
59
  : [
55
60
  SealiousMiddlewares.extractContext(),
56
- SealiousMiddlewares.parseBody(),
61
+ SealiousMiddlewares.parseBody(file_manager),
57
62
  handleHtmlPromise,
58
63
  ];
59
64
 
package/src/notifier.ts CHANGED
@@ -15,7 +15,9 @@ export function make_notifier(port: number) {
15
15
  });
16
16
  });
17
17
 
18
- console.log("build notifier listening on websocket at port " + port);
18
+ console.log(
19
+ "build notifier listening on websocket at port " + port.toString()
20
+ );
19
21
  return function notify(message: string) {
20
22
  sockets.forEach((s) => s.send(message));
21
23
  };
package/src/page/list.ts CHANGED
@@ -73,7 +73,7 @@ export abstract class ListPage<
73
73
  init(): void {
74
74
  super.init();
75
75
  for (const [fieldname, field] of Object.entries(this.filterFields)) {
76
- field.init(fieldname);
76
+ void field.init(fieldname);
77
77
  }
78
78
  }
79
79
 
@@ -15,6 +15,7 @@ import { Mountable } from "./mountable.js";
15
15
 
16
16
  export type PageErrorMessage = { type: "access" | "internal"; message: string };
17
17
 
18
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
19
  export type Fields = Record<string, FormField<boolean, any>>;
19
20
 
20
21
  export abstract class MountableWithFields<
@@ -32,7 +33,7 @@ export abstract class MountableWithFields<
32
33
 
33
34
  init(): void {
34
35
  for (const [name, field] of Object.entries(this.fields)) {
35
- field.init(name);
36
+ void field.init(name);
36
37
  }
37
38
  }
38
39
 
@@ -141,6 +142,7 @@ export abstract class MountableWithFields<
141
142
  const result: Record<string, unknown> = {};
142
143
  const promises = Object.entries(this.fields).map(
143
144
  async ([key, field]) => {
145
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
144
146
  const { parsed } = await field.getValue(ctx, raw_values);
145
147
  result[key] = parsed;
146
148
  }
@@ -48,6 +48,7 @@ export abstract class SealiousItemListPage<
48
48
  const query = this.collection.list(await this.getContextForList(ctx));
49
49
  const sort = await this.getSort(ctx);
50
50
  if (sort) {
51
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
51
52
  query.sort({ [sort.field]: sort.order } as any);
52
53
  }
53
54
  return query;
@@ -69,7 +70,7 @@ export abstract class SealiousItemListPage<
69
70
  async getFilterValues(ctx: Context) {
70
71
  const query_params = qs.parse(ctx.search.slice(1));
71
72
  const _filter_values = query_params?.filter || {};
72
- let filter_values: Record<string, string | undefined> = is(
73
+ const filter_values: Record<string, string | undefined> = is(
73
74
  _filter_values,
74
75
  predicates.record(predicates.string, predicates.string)
75
76
  )
@@ -81,7 +82,7 @@ export abstract class SealiousItemListPage<
81
82
  async renderItem(
82
83
  _: Context,
83
84
  item: CollectionItem<C>,
84
- index: number
85
+ _index: number
85
86
  ): Promise<FlatTemplatable> {
86
87
  return `<div>${item.id}</div>`;
87
88
  }
@@ -1,11 +1,13 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
1
2
  import Router from "@koa/router";
2
- import { predicates, hasShape, is, hasField } from "@sealcode/ts-predicates";
3
+ import { predicates, hasShape, is } from "@sealcode/ts-predicates";
3
4
  import deepmerge, { ArrayMergeOptions } from "deepmerge";
4
- import { BaseContext } from "koa";
5
+ import { BaseContext, Context } from "koa";
5
6
  import { Templatable, tempstream } from "tempstream";
6
7
  import { from_base64, to_base64 } from "../utils/base64.js";
7
8
  import { ExtractTail } from "../utils/utils.js";
8
9
  import { Mountable } from "./mountable.js";
10
+ import { isPlainObject } from "is-what";
9
11
 
10
12
  export type StatefulPageActionDescription<ActionName> =
11
13
  | {
@@ -55,7 +57,7 @@ export abstract class StatefulPage<
55
57
 
56
58
  constructor() {
57
59
  super();
58
- const original_render = this.render.bind(this);
60
+ const original_render = this.render.bind(this) as typeof this.render;
59
61
  this.render = async (
60
62
  ctx: BaseContext,
61
63
  state: State,
@@ -63,7 +65,8 @@ export abstract class StatefulPage<
63
65
  ) => {
64
66
  return this.wrapInLayout(
65
67
  ctx,
66
- this.wrapInForm(
68
+ await this.wrapInForm(
69
+ ctx as Context,
67
70
  state,
68
71
  await original_render(ctx, state, inputs)
69
72
  ),
@@ -78,12 +81,20 @@ export abstract class StatefulPage<
78
81
  state: State
79
82
  ): Templatable;
80
83
 
81
- wrapInForm(state: State, content: Templatable): Templatable {
82
- return tempstream/* HTML */ `<form action="./" method="POST">
84
+ async wrapInForm(
85
+ context: Context,
86
+ state: State,
87
+ content: Templatable
88
+ ): Promise<Templatable> {
89
+ return tempstream/* HTML */ `<form
90
+ action="./"
91
+ method="POST"
92
+ enctype="multipart/form-data"
93
+ >
83
94
  <input
84
95
  name="state"
85
96
  type="hidden"
86
- value="${to_base64(JSON.stringify(state))}"
97
+ value="${to_base64(await this.serializeState(context, state))}"
87
98
  />
88
99
  ${content}
89
100
  </form>`;
@@ -121,7 +132,8 @@ export abstract class StatefulPage<
121
132
  action_description: StatefulPageActionDescription<ActionName>,
122
133
  ...args: ExtractTail<ExtractTail<Parameters<Actions[ActionName]>>>
123
134
  ) {
124
- let { label, content } = this.extractActionAndLabel(action_description);
135
+ const { label, content } =
136
+ this.extractActionAndLabel(action_description);
125
137
  return /* HTML */ `
126
138
  <button
127
139
  type="submit"
@@ -157,15 +169,27 @@ export abstract class StatefulPage<
157
169
  }
158
170
 
159
171
  async preprocessOverrides(
160
- state: State,
172
+ _state: State,
161
173
  values: Record<string, unknown>
162
174
  ): Promise<Record<string, unknown>> {
163
175
  return values;
164
176
  }
165
177
 
178
+ async serializeState(_context: BaseContext, state: State): Promise<string> {
179
+ return JSON.stringify(state);
180
+ }
181
+
182
+ async deserializeState(_context: BaseContext, s: string): Promise<State> {
183
+ const deserialized = JSON.parse(s) as unknown;
184
+ console.log("stateful-page.ts:183", "deserialized:");
185
+ console.dir(deserialized, { depth: 10 });
186
+ return deserialized as State;
187
+ }
188
+
166
189
  async extractState(
167
190
  ctx: BaseContext
168
191
  ): Promise<StateAndMetadata<State, Actions>> {
192
+ console.log("stateful-page.ts:188", "EXTRACT STATE");
169
193
  if (
170
194
  !hasShape(
171
195
  {
@@ -189,7 +213,8 @@ export abstract class StatefulPage<
189
213
  // the "$" key is parsed as dot notation and overrides the state
190
214
 
191
215
  const original_state_string = ctx.$body.state;
192
- const original_state = JSON.parse(
216
+ const original_state = await this.deserializeState(
217
+ ctx,
193
218
  typeof original_state_string == "string"
194
219
  ? from_base64(original_state_string)
195
220
  : "{}"
@@ -202,6 +227,7 @@ export abstract class StatefulPage<
202
227
  state_overrides
203
228
  );
204
229
  let modified_state = deepmerge(original_state, state_overrides, {
230
+ isMergeableObject: isPlainObject,
205
231
  arrayMerge: (
206
232
  target: any[],
207
233
  source: any[],
@@ -209,7 +235,7 @@ export abstract class StatefulPage<
209
235
  ) => {
210
236
  // https://github.com/TehShrike/deepmerge?tab=readme-ov-file#arraymerge-example-combine-arrays
211
237
  const destination = target.slice();
212
-
238
+ /* eslint-disable @typescript-eslint/no-unsafe-argument */
213
239
  source.forEach((item, index) => {
214
240
  if (typeof destination[index] === "undefined") {
215
241
  destination[index] =
@@ -218,15 +244,18 @@ export abstract class StatefulPage<
218
244
  options
219
245
  );
220
246
  } else if (options.isMergeableObject(item)) {
247
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
221
248
  destination[index] = deepmerge(
222
249
  target[index],
223
250
  item,
224
251
  options
225
252
  );
226
253
  } else if (target.indexOf(item) === -1) {
254
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
227
255
  destination[index] = item;
228
256
  }
229
257
  });
258
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
230
259
  return destination;
231
260
  },
232
261
  }) as State;
@@ -237,7 +266,7 @@ export abstract class StatefulPage<
237
266
  if (ctx.$body.action && ctx.$body.action_args) {
238
267
  return {
239
268
  state: modified_state,
240
- action: ctx.$body.action as string,
269
+ action: ctx.$body.action,
241
270
  inputs,
242
271
  action_args: ctx.$body.action_args,
243
272
  };
@@ -261,17 +290,16 @@ export abstract class StatefulPage<
261
290
  const { action, state, inputs, action_args } =
262
291
  await this.extractState(ctx);
263
292
  if (action) {
264
- ctx.body = this.render(
265
- ctx,
266
- await this.actions[action](
267
- state,
268
- inputs,
269
- ...(JSON.parse(
270
- from_base64(action_args as string)
271
- ) as unknown[])
272
- ),
273
- inputs
293
+ const new_state = await this.actions[action](
294
+ state,
295
+ inputs,
296
+ ...(JSON.parse(
297
+ from_base64(action_args as string)
298
+ ) as unknown[])
274
299
  );
300
+ console.log("stateful-page.ts:291", "new_state:");
301
+ console.dir(new_state, { depth: 10 });
302
+ ctx.body = this.render(ctx, new_state, inputs);
275
303
  } else {
276
304
  ctx.body = this.render(ctx, state, inputs);
277
305
  }
@@ -4,7 +4,7 @@ export function jddComponentTemplate(component_name: string) {
4
4
  return `import type { FlatTemplatable } from "tempstream";
5
5
  import { TempstreamJSX } from "tempstream";
6
6
  import type {
7
- ExtractStructuredComponentArgumentsValues,
7
+ ExtractStructuredComponentArgumentsParsed,
8
8
  JDDContext,
9
9
  } from "@sealcode/jdd";
10
10
  import { Component, ComponentArguments } from "@sealcode/jdd";
@@ -25,7 +25,7 @@ export class ${toPascalCase(
25
25
  {
26
26
  title,
27
27
  content,
28
- }: ExtractStructuredComponentArgumentsValues<typeof component_arguments>,
28
+ }: ExtractStructuredComponentArgumentsParsed<typeof component_arguments>,
29
29
  { render_markdown }: JDDContext
30
30
  ): FlatTemplatable {
31
31
  return (
@@ -2,6 +2,7 @@ import _locreq from "locreq";
2
2
  import { exec } from "./utils.js";
3
3
  const target_locreq = _locreq(process.cwd());
4
4
  import { promises as fs } from "fs";
5
+ import { is, predicates } from "@sealcode/ts-predicates";
5
6
 
6
7
  export default async function extract_fields_from_collection(
7
8
  collection_name: string
@@ -25,5 +26,22 @@ console.log(JSON.stringify(fields));
25
26
  await fs.writeFile(extractor_code_path, extractor_code);
26
27
  const { stdout } = await exec("node", [extractor_code_path]);
27
28
  await fs.unlink(extractor_code_path);
28
- return JSON.parse(stdout);
29
+ const ret = JSON.parse(stdout) as unknown;
30
+ if (
31
+ !is(
32
+ ret,
33
+ predicates.array(
34
+ predicates.shape({
35
+ name: predicates.string,
36
+ type: predicates.string,
37
+ })
38
+ )
39
+ )
40
+ ) {
41
+ throw new Error(
42
+ "Encountered a problem while extracting the names of fields from collection. Got: " +
43
+ stdout
44
+ );
45
+ }
46
+ return ret;
29
47
  }
@@ -4,7 +4,7 @@ import { Translation } from "sealious";
4
4
  export function t(
5
5
  ctx: Context,
6
6
  key: string,
7
- props: any[],
7
+ props: unknown[],
8
8
  default_translation: Translation
9
9
  ) {
10
10
  return /* HTML */ `<span translation-key="${key.replace('"', '\\"')}"
@@ -2,9 +2,11 @@ export type Awaited<T> = T extends Promise<infer U> ? U : T;
2
2
  export type UnwrapArray<T> = T extends Array<infer U> ? U : T;
3
3
 
4
4
  export function keys<S extends string>(object: Record<S, unknown>): S[] {
5
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-explicit-any
5
6
  return Object.keys(object) as any;
6
7
  }
7
8
 
9
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
10
  export type ExtractTail<T extends any[]> = T extends [infer _, ...infer Tail]
9
11
  ? Tail
10
12
  : never;
package/test.cjs ADDED
@@ -0,0 +1,54 @@
1
+ const mri = require("mri");
2
+ const { spawn } = require("child_process");
3
+
4
+ const argv = process.argv.slice(2);
5
+ const args = mri(argv);
6
+
7
+ const bin_dir = "./node_modules/.bin/";
8
+
9
+ const mocha = bin_dir + "mocha";
10
+
11
+ let mocha_options = [
12
+ "--recursive",
13
+ "--timeout=10000",
14
+ "--require",
15
+ "source-map-support/register",
16
+ "--exit",
17
+ ];
18
+
19
+ if (args["test-report"]) {
20
+ mocha_options = [
21
+ ...mocha_options,
22
+ // "--require",
23
+ // "ts-node/register",
24
+ // "--require",
25
+ // "./src/http/type-overrides.ts",
26
+ "--reporter",
27
+ "xunit",
28
+ "--reporter-option",
29
+ "output=.xunit",
30
+ ];
31
+ }
32
+
33
+ const mocha_files = ["lib/**/*.test.js"];
34
+
35
+ let command = [mocha, ...mocha_options, ...mocha_files];
36
+
37
+ if (args.debug) {
38
+ command = ["node", "inspect", ...command];
39
+ }
40
+
41
+ console.log("spawning mocha...", command.join(" "));
42
+
43
+ const proc = spawn(command[0], command.slice(1), {
44
+ stdio: "inherit",
45
+ env: process.env,
46
+ });
47
+
48
+ proc.on("exit", function (code) {
49
+ if (args["test-report"]) {
50
+ process.exit(0);
51
+ } else {
52
+ process.exit(code);
53
+ }
54
+ });
package/tsconfig.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "module": "es2022",
4
- "moduleResolution": "node16",
3
+ "module": "nodenext",
4
+ "moduleResolution": "nodenext",
5
5
  "noImplicitAny": true,
6
6
  "noImplicitThis": true,
7
7
  "strictNullChecks": true,
@@ -9,7 +9,7 @@
9
9
  "declaration": true,
10
10
  "esModuleInterop": true,
11
11
  "lib": ["ES6", "ESNext"],
12
- "outDir": "dist",
12
+ "outDir": "lib",
13
13
  "checkJs": false,
14
14
  "allowJs": true,
15
15
  "declarationDir": "@types",
@@ -17,7 +17,6 @@
17
17
  "sourceMap": true,
18
18
  "allowSyntheticDefaultImports": true,
19
19
  "skipLibCheck": true,
20
- "types": ["vitest/globals"]
21
20
  },
22
21
 
23
22
  "include": ["src/**/*"],
@@ -1,17 +0,0 @@
1
- import { Page } from "@sealcode/sealgen";
2
- import html from "../html.js";
3
- const actionName = "Sample";
4
- var sample_page_default = new class SamplePage extends Page {
5
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
6
- async canAccess(_) {
7
- return { canAccess: true, message: "" };
8
- }
9
- async render(ctx) {
10
- return html(ctx, "Sample", /* @__PURE__ */ React.createElement("div", null));
11
- }
12
- }();
13
- export {
14
- actionName,
15
- sample_page_default as default
16
- };
17
- //# sourceMappingURL=sample.page.js.map
@@ -1,39 +0,0 @@
1
- import { withProdApp } from "../test_utils/with-prod-app.js";
2
- import { VERY_LONG_TEST_TIMEOUT, webhintURL } from "../test_utils/webhint.js";
3
- import { SampleURL } from "./urls.js";
4
- import { getBrowser } from "../test_utils/browser-creator.js";
5
- describe("Sample webhint", () => {
6
- it(
7
- "doesn't crash",
8
- async function() {
9
- return withProdApp(async ({ base_url, rest_api }) => {
10
- await rest_api.get(SampleURL);
11
- await webhintURL(base_url + SampleURL);
12
- });
13
- },
14
- VERY_LONG_TEST_TIMEOUT
15
- );
16
- });
17
- describe("Sample", () => {
18
- let page;
19
- let browser;
20
- let context;
21
- beforeEach(async () => {
22
- browser = await getBrowser();
23
- context = await browser.newContext();
24
- page = await context.newPage();
25
- });
26
- afterEach(async () => {
27
- await context.close();
28
- });
29
- it(
30
- "works as expected",
31
- async function() {
32
- return withProdApp(async ({ base_url }) => {
33
- await page.goto(base_url + SampleURL);
34
- });
35
- },
36
- VERY_LONG_TEST_TIMEOUT
37
- );
38
- });
39
- //# sourceMappingURL=sample.test.js.map