@sealcode/sealgen 0.19.4 → 0.19.6

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 (67) hide show
  1. package/@types/forms/fields/field.d.ts +1 -0
  2. package/@types/forms/fields/fields.d.ts +2 -1
  3. package/@types/forms/fields/get-field-for-sealious.d.ts +3 -1
  4. package/@types/forms/fields/hybrid.d.ts +11 -0
  5. package/@types/forms/fields/item-draft.d.ts +20 -0
  6. package/@types/forms/form.d.ts +1 -0
  7. package/@types/forms/multiform.d.ts +2 -2
  8. package/@types/page/list.d.ts +5 -4
  9. package/@types/page/mountable-with-fields.d.ts +9 -2
  10. package/@types/page/mountable.d.ts +1 -1
  11. package/@types/page/page.d.ts +1 -1
  12. package/@types/templates/form.d.ts +2 -2
  13. package/lib/forms/controls/checkboxed-list-input.test.js +16 -12
  14. package/lib/forms/controls/file.test.js +2 -2
  15. package/lib/forms/controls/image.test.js +4 -4
  16. package/lib/forms/controls/single-reference.test.js +2 -2
  17. package/lib/forms/fields/field.js +1 -1
  18. package/lib/forms/fields/field.test.js +9 -6
  19. package/lib/forms/fields/fields.js +2 -1
  20. package/lib/forms/fields/file.test.js +2 -2
  21. package/lib/forms/fields/get-field-for-sealious.js +14 -0
  22. package/lib/forms/fields/hybrid.js +37 -0
  23. package/lib/forms/fields/item-draft.js +34 -0
  24. package/lib/forms/form.js +11 -5
  25. package/lib/forms/form.test.js +9 -9
  26. package/lib/forms/multiform.js +7 -4
  27. package/lib/forms/multiform.test.js +7 -7
  28. package/lib/mount.js +4 -1
  29. package/lib/page/list.js +9 -6
  30. package/lib/page/mountable-with-fields.js +16 -1
  31. package/lib/page/mountable-with-fields.test.js +2 -2
  32. package/lib/page/mountable.js +1 -1
  33. package/lib/page/page.js +1 -1
  34. package/lib/templates/form.js +9 -18
  35. package/lib/templates/shared/collection-create-form.js +8 -8
  36. package/lib/templates/shared/collection-edit-form.js +9 -9
  37. package/lib/templates/shared/collection-list.js +2 -1
  38. package/lib/templates/shared/shared-crud-form-fields.js +4 -4
  39. package/lib/utils/extract-fields-from-collection.js +3 -0
  40. package/package.json +1 -1
  41. package/src/forms/controls/checkboxed-list-input.test.ts +16 -12
  42. package/src/forms/controls/file.test.ts +2 -2
  43. package/src/forms/controls/image.test.ts +4 -4
  44. package/src/forms/controls/single-reference.test.ts +2 -2
  45. package/src/forms/fields/field.test.ts +9 -6
  46. package/src/forms/fields/field.ts +6 -7
  47. package/src/forms/fields/fields.ts +2 -1
  48. package/src/forms/fields/file.test.ts +2 -2
  49. package/src/forms/fields/get-field-for-sealious.ts +66 -100
  50. package/src/forms/fields/hybrid.ts +47 -0
  51. package/src/forms/fields/item-draft.ts +44 -0
  52. package/src/forms/form.test.ts +15 -15
  53. package/src/forms/form.ts +34 -26
  54. package/src/forms/multiform.test.ts +7 -7
  55. package/src/forms/multiform.ts +10 -7
  56. package/src/mount.ts +11 -7
  57. package/src/page/list.ts +33 -28
  58. package/src/page/mountable-with-fields.test.ts +2 -2
  59. package/src/page/mountable-with-fields.ts +26 -5
  60. package/src/page/mountable.ts +1 -1
  61. package/src/page/page.ts +1 -1
  62. package/src/templates/form.ts +9 -18
  63. package/src/templates/shared/collection-create-form.ts +8 -8
  64. package/src/templates/shared/collection-edit-form.ts +9 -9
  65. package/src/templates/shared/collection-list.ts +5 -4
  66. package/src/templates/shared/shared-crud-form-fields.ts +5 -5
  67. package/src/utils/extract-fields-from-collection.ts +3 -0
@@ -37,107 +37,61 @@ import extract_fields_from_collection, {
37
37
  import { EnumMultipleSealious } from "./enum-multiple-sealious.js";
38
38
  import { URLField } from "./url.js";
39
39
  import { Image } from "./image.js";
40
+ import { PhoneNumberWithCountryCode } from "./phone-number-with-country-code.js";
41
+ import { ItemDraft } from "./item-draft.js";
40
42
 
41
- export type SealiousToFormField<T> = T extends SealiousFieldTypes.Boolean
42
- ? BooleanField<false>
43
- : T extends SealiousFieldTypes.Color
44
- ? Color<false>
45
- : T extends SealiousFieldTypes.ControlAccess<infer R>
46
- ? SealiousToFormField<R>
47
- : T extends SealiousFieldTypes.Date
48
- ? DateField<false>
49
- : T extends SealiousFieldTypes.DateTime
50
- ? DateTime<false>
51
- : T extends SealiousFieldTypes.DeepReverseSingleReference
52
- ?
53
- | DeepReverseSingleReferenceList
54
- | DeepReverseSingleReferenceTable
55
- : T extends SealiousFieldTypes.DisallowUpdate<
56
- any,
57
- any,
58
- any,
59
- infer R
60
- >
61
- ? SealiousToFormField<R>
62
- : T extends SealiousFieldTypes.Email
63
- ? EmailField<false>
64
- : T extends SealiousFieldTypes.Enum<any>
65
- ? PickFromListSealious<false>
66
- : T extends SealiousFieldTypes.EnumMultiple<
67
- infer R
68
- >
69
- ? R extends string[]
70
- ? EnumMultipleSealious<R>
71
- : TextBasedSimpleField<false>
72
- : T extends SealiousFieldTypes.File
73
- ? File<false>
74
- : T extends SealiousFieldTypes.Float
75
- ? Float<false>
76
- : T extends SealiousFieldTypes.HTML
77
- ? HTML<false>
78
- : T extends SealiousFieldTypes.Image
79
- ? Image<false>
80
- : T extends SealiousFieldTypes.Int
81
- ? Int<false>
82
- : T extends SealiousFieldTypes.JsonObject
83
- ? JSONField<false>
84
- : T extends SealiousFieldTypes.JDD
85
- ? TextBasedSimpleField<
86
- false,
87
- SimpleInput
88
- >
89
- : T extends SealiousFieldTypes.Password
90
- ? Password<false>
91
- : T extends SealiousFieldTypes.ReverseSingleReference
92
- ? TextBasedSimpleField<
93
- false,
94
- SimpleInput
95
- >
96
- : T extends SealiousFieldTypes.SecretToken
97
- ? TextBasedSimpleField<
98
- false,
99
- SimpleInput
100
- >
101
- : T extends SealiousFieldTypes.SettableBy<
102
- infer R
103
- >
104
- ? SealiousToFormField<R>
105
- : T extends SealiousFieldTypes.SingleReference
106
- ? SingleReference<
107
- Collection,
108
- boolean,
109
- T
110
- >
111
- : T extends SealiousFieldTypes.Text
112
- ? Text<false>
113
- : T extends SealiousFieldTypes.Username
114
- ? CollectionField<
115
- SealiousFieldTypes.Username,
116
- false
117
- >
118
- : T extends SealiousFieldTypes.ValueExistingInCollection
119
- ? SimpleFormField<false>
120
- : T extends SealiousFieldTypes.ValueNotExistingInCollection
121
- ? SimpleFormField<false>
122
- : T extends SealiousRequiredField<
123
- any,
124
- any,
125
- any
126
- >
127
- ? SimpleFormField<false>
128
- : T extends SealiousFieldTypes.Url
129
- ? URLField<false>
130
- : T extends SealiousFieldTypes.Money
131
- ? SimpleFormField<false>
132
- : T extends SealiousFieldTypes.Markdown
133
- ? Markdown<false>
134
- : T extends SealiousFieldTypes.Coordinates
135
- ? Coordinates<false>
136
- : T extends SealiousFieldTypes.StructuredArray<
137
- infer R
138
- >
139
- ? StructuredArrayField<R>
140
- : TextBasedSimpleField<any>;
43
+ export type SealiousToFormField<T> =
44
+ T extends SealiousFieldTypes.Boolean ? BooleanField<false>
45
+ : T extends SealiousFieldTypes.Color ? Color<false>
46
+ : T extends SealiousFieldTypes.ControlAccess<infer R> ?
47
+ SealiousToFormField<R>
48
+ : T extends SealiousFieldTypes.Date ? DateField<false>
49
+ : T extends SealiousFieldTypes.DateTime ? DateTime<false>
50
+ : T extends SealiousFieldTypes.DeepReverseSingleReference ?
51
+ DeepReverseSingleReferenceList | DeepReverseSingleReferenceTable
52
+ : T extends SealiousFieldTypes.DisallowUpdate<any, any, any, infer R> ?
53
+ SealiousToFormField<R>
54
+ : T extends SealiousFieldTypes.Email ? EmailField<false>
55
+ : T extends SealiousFieldTypes.Enum<any> ? PickFromListSealious<false>
56
+ : T extends SealiousFieldTypes.EnumMultiple<infer R> ?
57
+ R extends string[] ?
58
+ EnumMultipleSealious<R>
59
+ : TextBasedSimpleField<false>
60
+ : T extends SealiousFieldTypes.File ? File<false>
61
+ : T extends SealiousFieldTypes.Float ? Float<false>
62
+ : T extends SealiousFieldTypes.HTML ? HTML<false>
63
+ : T extends SealiousFieldTypes.Image ? Image<false>
64
+ : T extends SealiousFieldTypes.Int ? Int<false>
65
+ : T extends SealiousFieldTypes.ItemDraft<infer C extends Collection> ?
66
+ ItemDraft<C>
67
+ : T extends SealiousFieldTypes.JsonObject ? JSONField<false>
68
+ : T extends SealiousFieldTypes.JDD ?
69
+ TextBasedSimpleField<false, SimpleInput>
70
+ : T extends SealiousFieldTypes.Password ? Password<false>
71
+ : T extends SealiousFieldTypes.PhoneNumber ?
72
+ PhoneNumberWithCountryCode<false>
73
+ : T extends SealiousFieldTypes.ReverseSingleReference ?
74
+ TextBasedSimpleField<false, SimpleInput>
75
+ : T extends SealiousFieldTypes.SecretToken ?
76
+ TextBasedSimpleField<false, SimpleInput>
77
+ : T extends SealiousFieldTypes.SettableBy<infer R> ? SealiousToFormField<R>
78
+ : T extends SealiousFieldTypes.SingleReference ?
79
+ SingleReference<Collection, boolean, T>
80
+ : T extends SealiousFieldTypes.Text ? Text<false>
81
+ : T extends SealiousFieldTypes.Username ?
82
+ CollectionField<SealiousFieldTypes.Username, false>
83
+ : T extends SealiousFieldTypes.ValueExistingInCollection ?
84
+ SimpleFormField<false>
85
+ : T extends SealiousFieldTypes.ValueNotExistingInCollection ?
86
+ SimpleFormField<false>
87
+ : T extends SealiousRequiredField<any, any, any> ? SimpleFormField<false>
88
+ : T extends SealiousFieldTypes.Url ? URLField<false>
89
+ : T extends SealiousFieldTypes.Money ? SimpleFormField<false>
90
+ : T extends SealiousFieldTypes.Markdown ? Markdown<false>
91
+ : T extends SealiousFieldTypes.Coordinates ? Coordinates<false>
92
+ : T extends SealiousFieldTypes.StructuredArray<infer R> ?
93
+ StructuredArrayField<R>
94
+ : TextBasedSimpleField<any>;
141
95
 
142
96
  export function sealiousToFormField<SF extends SealiousField<any>>(
143
97
  sealious_field: SF
@@ -219,6 +173,9 @@ export function sealiousToFormField<SF extends SealiousField<any>>(
219
173
  if (sealious_field instanceof SealiousFieldTypes.Int) {
220
174
  return new Int(sealious_field.required) as SealiousToFormField<SF>;
221
175
  }
176
+ if (sealious_field instanceof SealiousFieldTypes.ItemDraft) {
177
+ return new ItemDraft(sealious_field) as SealiousToFormField<SF>;
178
+ }
222
179
  if (sealious_field instanceof SealiousFieldTypes.JsonObject) {
223
180
  return new JSONField(
224
181
  sealious_field.required
@@ -227,6 +184,11 @@ export function sealiousToFormField<SF extends SealiousField<any>>(
227
184
  if (sealious_field instanceof SealiousFieldTypes.Password) {
228
185
  return new Password(sealious_field.required) as SealiousToFormField<SF>;
229
186
  }
187
+ if (sealious_field instanceof SealiousFieldTypes.PhoneNumber) {
188
+ return new PhoneNumberWithCountryCode(
189
+ sealious_field.required
190
+ ) as SealiousToFormField<SF>;
191
+ }
230
192
  if (sealious_field instanceof SealiousFieldTypes.SettableBy) {
231
193
  return sealiousToFormField(
232
194
  sealious_field.virtual_field
@@ -304,10 +266,14 @@ export async function sealiousFieldInfoToFormField(
304
266
  return new Image(field_info.is_required);
305
267
  case "int":
306
268
  return new Int(field_info.is_required);
269
+ case "item-draft":
270
+ return new ItemDraft({ target_collection: { fields: {} } } as any);
307
271
  case "json-object":
308
272
  return new JSONField(field_info.is_required);
309
273
  case "password":
310
274
  return new Password(field_info.is_required);
275
+ case "phone-number":
276
+ return new PhoneNumberWithCountryCode(field_info.is_required);
311
277
  case "single-reference":
312
278
  return new SingleReference(false, {} as any);
313
279
  case "text":
@@ -0,0 +1,47 @@
1
+ /* eslint @typescript-eslint/no-unsafe-argument: off, @typescript-eslint/no-explicit-any: off, @typescript-eslint/no-unsafe-member-access: off */
2
+ import { Context } from "koa";
3
+ import { Hybrid as HybridControl } from "../controls/hybrid.js";
4
+ import { FormDataValue } from "../form-types.js";
5
+ import { FieldParseResult, FormField } from "./field.js";
6
+
7
+ export class Hybrid<Fields extends Record<string, FormField>> extends FormField<
8
+ true,
9
+ Record<string, unknown>
10
+ > {
11
+ constructor(public subfields: Fields) {
12
+ super(true);
13
+ }
14
+
15
+ public getEmptyValue(): Record<string, unknown> {
16
+ return {};
17
+ }
18
+
19
+ async parse(
20
+ ctx: Context,
21
+ raw_value: FormDataValue
22
+ ): Promise<FieldParseResult<Record<string, unknown>>> {
23
+ return {
24
+ parsable: true,
25
+ error: null,
26
+ parsed_value: Object.fromEntries(
27
+ await Promise.all(
28
+ Object.entries(this.subfields).map(
29
+ async ([key, subfield]) => [
30
+ key,
31
+ (
32
+ await subfield.getParsedValue(
33
+ ctx,
34
+ (raw_value as any)[key]
35
+ )
36
+ ).parsed as FormDataValue,
37
+ ]
38
+ )
39
+ )
40
+ ) as Record<string, unknown>,
41
+ };
42
+ }
43
+
44
+ getControl(): HybridControl {
45
+ return new HybridControl(this, this.subfields);
46
+ }
47
+ }
@@ -0,0 +1,44 @@
1
+ import { Collection, FieldTypes as SealiousFieldTypes } from "sealious";
2
+ import { sealiousToFormField } from "./get-field-for-sealious.js";
3
+ import { Hybrid } from "./hybrid.js";
4
+ import { FormField } from "./field.js";
5
+ import { ExtractedFieldInfo } from "../../utils/extract-fields-from-collection.js";
6
+ import { toPascalCase } from "js-convert-case";
7
+
8
+ export class ItemDraft<C extends Collection> extends Hybrid<{
9
+ [name in keyof C["fields"]]: FormField;
10
+ }> {
11
+ constructor(public sealious_field: SealiousFieldTypes.ItemDraft<C>) {
12
+ super(
13
+ Object.fromEntries(
14
+ Object.entries(sealious_field.target_collection.fields).map(
15
+ ([field_name, sealious_field]) => [
16
+ field_name,
17
+ sealiousToFormField(sealious_field),
18
+ ]
19
+ )
20
+ ) as unknown as {
21
+ [name in keyof C["fields"]]: FormField;
22
+ }
23
+ );
24
+ }
25
+
26
+ generateFieldDeclaration(
27
+ field_info: ExtractedFieldInfo,
28
+ vars: { form_field_types: string; sealious_field: string }
29
+ ): string {
30
+ return `new ${vars.form_field_types}.${this.constructor.name}<typeof ${toPascalCase(field_info.target!)}>(${vars.sealious_field})`;
31
+ }
32
+
33
+ generateImportsForFieldList(
34
+ field_info: ExtractedFieldInfo
35
+ ): { what: string; from: string; as?: string; type?: boolean }[] {
36
+ return [
37
+ {
38
+ what: toPascalCase(field_info.target!),
39
+ from: "src/back/collections/collections.js",
40
+ type: true,
41
+ },
42
+ ];
43
+ }
44
+ }
@@ -18,9 +18,9 @@ const fields = {
18
18
 
19
19
  export function form_factory(canAccessFun?: Mountable["canAccess"]): Form<typeof fields, void> {
20
20
  const result = new (class extends Form<typeof fields, void> {
21
- fields = fields;
21
+ getFields = () => fields;
22
22
  submitButtonText = "Submit";
23
- controls = [
23
+ getControls = () => [
24
24
  new Controls.SimpleInput(fields.text, {
25
25
  label: "This is a test:",
26
26
  type: "password",
@@ -112,7 +112,7 @@ describe("form test", () => {
112
112
  router,
113
113
  "/",
114
114
  form_factory(
115
- async (ctx: Koa.Context): Promise<{ canAccess: boolean; message: string }> => {
115
+ async (_ctx: Koa.Context): Promise<{ canAccess: boolean; message: string }> => {
116
116
  return { canAccess: true, message: "" };
117
117
  }
118
118
  ),
@@ -184,9 +184,9 @@ describe("form test", () => {
184
184
  "/",
185
185
  form_factory(
186
186
  async (ctx: Koa.Context): Promise<{ canAccess: boolean; message: string }> => {
187
- return ctx.$context && ctx.$context.user_id
188
- ? { canAccess: true, message: "" }
189
- : { canAccess: false, message: "" };
187
+ return ctx.$context && ctx.$context.user_id ?
188
+ { canAccess: true, message: "" }
189
+ : { canAccess: false, message: "" };
190
190
  }
191
191
  ),
192
192
  true
@@ -214,9 +214,9 @@ describe("form test", () => {
214
214
  "/",
215
215
  form_factory(
216
216
  async (ctx: Koa.Context): Promise<{ canAccess: boolean; message: string }> => {
217
- return ctx.$context && ctx.$context.user_id
218
- ? { canAccess: true, message: "" }
219
- : { canAccess: false, message: "" };
217
+ return ctx.$context && ctx.$context.user_id ?
218
+ { canAccess: true, message: "" }
219
+ : { canAccess: false, message: "" };
220
220
  }
221
221
  ),
222
222
  true
@@ -242,9 +242,9 @@ describe("form test", () => {
242
242
  router,
243
243
  "/",
244
244
  new (class extends Form<typeof fields, void> {
245
- fields = fields;
245
+ getFields = () => fields;
246
246
  submitButtonText = "Submit";
247
- controls = [
247
+ getControls = () => [
248
248
  new Controls.SimpleInput(fields.text, {
249
249
  label: "This is a test:",
250
250
  type: "password",
@@ -311,9 +311,9 @@ describe("form test", () => {
311
311
  router,
312
312
  "/",
313
313
  new (class extends Form<typeof fields, void> {
314
- fields = fields;
314
+ getFields = () => fields;
315
315
  submitButtonText = "Submit";
316
- controls = [
316
+ getControls = () => [
317
317
  new Controls.SimpleInput(fields.text, {
318
318
  label: "This is a test:",
319
319
  type: "text",
@@ -375,8 +375,8 @@ describe("form test", () => {
375
375
  router,
376
376
  "/",
377
377
  new (class extends Form<typeof fields, null> {
378
- fields = fields;
379
- controls = [new Controls.SimpleInput(fields.title)];
378
+ getFields = () => fields;
379
+ getControls = () => [new Controls.SimpleInput(fields.title)];
380
380
 
381
381
  async getInitialValues() {
382
382
  return { title: "Hello" };
package/src/forms/form.ts CHANGED
@@ -66,15 +66,15 @@ export abstract class Form<
66
66
  ): Promise<JSX.Element | Readable> {
67
67
  return tempstream /* HTML */ `<div class="form-container">
68
68
  ${this.makeOpenFormTag(ctx)}
69
- ${!this.controls.some((control) => control.role == "messages")
70
- ? this.renderMessages(ctx, data)
71
- : ""}
69
+ ${!this.controls.some((control) => control.role == "messages") ?
70
+ this.renderMessages(ctx, data)
71
+ : ""}
72
72
  ${this.renderControls(
73
73
  this.makeFormControlContext(ctx, data, show_field_errors)
74
74
  )}
75
- ${this.controls.some((control) => control.role == "submit")
76
- ? ""
77
- : this.makeSubmitButton()}
75
+ ${this.controls.some((control) => control.role == "submit") ?
76
+ ""
77
+ : this.makeSubmitButton()}
78
78
  ${this.makeCloseFormTag()}
79
79
  </div>`;
80
80
  }
@@ -102,9 +102,10 @@ export abstract class Form<
102
102
  form_messages: FormMessage[],
103
103
  field_errors: FieldMessages<keyof Fields>
104
104
  ): Promise<FormReaction> {
105
- const messages = form_messages.length
106
- ? form_messages
107
- : [<const>{ type: "error", text: "Some fields are invalid" }];
105
+ const messages =
106
+ form_messages.length ? form_messages : (
107
+ [<const>{ type: "error", text: "Some fields are invalid" }]
108
+ );
108
109
  return {
109
110
  action: "stay",
110
111
  content: await this.render(
@@ -217,12 +218,13 @@ export abstract class Form<
217
218
  // eslint-disable-next-line no-console
218
219
  console.dir(e, { depth: 5 });
219
220
  const message =
220
- is(e, predicates.object) &&
221
- hasFieldOfType(e, "message", predicates.string)
222
- ? e?.message
223
- : is(e, predicates.string)
224
- ? e
225
- : "Wystąpił błąd";
221
+ (
222
+ is(e, predicates.object) &&
223
+ hasFieldOfType(e, "message", predicates.string)
224
+ ) ?
225
+ e?.message
226
+ : is(e, predicates.string) ? e
227
+ : "Wystąpił błąd";
226
228
 
227
229
  return this.onError(
228
230
  ctx,
@@ -241,6 +243,20 @@ export abstract class Form<
241
243
  }
242
244
  }
243
245
 
246
+ init(path: string, router: Router) {
247
+ super.init(path, router);
248
+ if (this.initialized) {
249
+ return;
250
+ }
251
+ // for use with other subroutes or middlewares that individual controls
252
+ // might register
253
+ const subrouter = new Router();
254
+ for (const control of this.controls) {
255
+ control.mount(subrouter, this);
256
+ }
257
+ router.use(path, subrouter.routes(), subrouter.allowedMethods());
258
+ }
259
+
244
260
  public mount(router: Router, path: string): void {
245
261
  router.use(path, async (ctx, next) => {
246
262
  const result = await this.canAccess(ctx);
@@ -255,14 +271,6 @@ export abstract class Form<
255
271
  await next();
256
272
  });
257
273
 
258
- // for use with other subroutes or middlewares that individual controls
259
- // might register
260
- const subrouter = new Router();
261
- for (const control of this.controls) {
262
- control.mount(subrouter, this);
263
- }
264
- router.use(path, subrouter.routes(), subrouter.allowedMethods());
265
-
266
274
  router.get(path, async (ctx) => {
267
275
  ctx.type = "html";
268
276
  ctx.body = await this.render(
@@ -292,9 +300,9 @@ export abstract class Form<
292
300
  async extractRawValues(
293
301
  ctx: Context
294
302
  ): Promise<Record<string, FormDataValue>> {
295
- return Object.keys(ctx.$body).length
296
- ? ctx.$body
297
- : this.getInitialValues(ctx);
303
+ return Object.keys(ctx.$body).length ?
304
+ ctx.$body
305
+ : this.getInitialValues(ctx);
298
306
  }
299
307
 
300
308
  static initFieldNames(fields: Record<string, FormField>): void {
@@ -27,8 +27,8 @@ const fields1 = {
27
27
 
28
28
  const form1 = new (class extends Form<typeof fields1, void> {
29
29
  defaultSuccessMessage = "Form1 done!";
30
- controls = [new FormHeader("form1"), new SimpleInput(fields1.email)];
31
- fields = fields1;
30
+ getControls = () => [new FormHeader("form1"), new SimpleInput(fields1.email)];
31
+ getFields = () => fields1;
32
32
  onSubmit() {
33
33
  return;
34
34
  }
@@ -40,8 +40,8 @@ const fields2 = {
40
40
 
41
41
  const form2 = new (class extends Form<Record<never, unknown>, void> {
42
42
  defaultSuccessMessage = "Form2 done!";
43
- controls = [new FormHeader("form2"), new SimpleInput(fields2.name)];
44
- fields = fields2;
43
+ getControls = () => [new FormHeader("form2"), new SimpleInput(fields2.name)];
44
+ getFields = () => fields2;
45
45
  onSubmit() {
46
46
  return;
47
47
  }
@@ -427,7 +427,7 @@ describe("multiform test", () => {
427
427
  form1: new (class extends Form<typeof fields1, void> {
428
428
  fields = fields1;
429
429
  submitButtonText = "Submit";
430
- controls = [
430
+ getControls = () => [
431
431
  new SimpleInput(fields1.email, {
432
432
  label: "This is a test:",
433
433
  type: "text",
@@ -500,9 +500,9 @@ describe("multiform test", () => {
500
500
  name = "multiform_test";
501
501
  forms = {
502
502
  form1: new (class extends Form<typeof fields, void> {
503
- fields = fields;
503
+ getFields = () => fields;
504
504
  submitButtonText = "Submit";
505
- controls = [
505
+ getControls = () => [
506
506
  new SimpleInput(fields.text, {
507
507
  label: "This is a test:",
508
508
  type: "text",
@@ -11,12 +11,15 @@ import { Form } from "./form.js";
11
11
  const FIELD_PREFIX_SEPARATOR = "___";
12
12
 
13
13
  export class Multiform extends MountableWithFields {
14
- controls = [];
14
+ getControls = () => [];
15
15
  public name: string;
16
16
  public forms: Record<string, Form<Fields, unknown>>;
17
17
 
18
- init(): void {
19
- super.init();
18
+ init(path: string, router: Router): void {
19
+ if (this.initialized) {
20
+ return;
21
+ }
22
+ super.init(path, router);
20
23
  for (const [key, form] of Object.entries(this.forms)) {
21
24
  if (key !== attribute(key)) {
22
25
  throw new Error(
@@ -30,7 +33,7 @@ export class Multiform extends MountableWithFields {
30
33
  form.field_names_prefix = key + FIELD_PREFIX_SEPARATOR;
31
34
  form.form_id = this.name;
32
35
  form.action = "./" + key;
33
- form.init();
36
+ form.init(path, router);
34
37
  form.extractRawValues = async (context) =>
35
38
  this.getSubformRawValues(context, key);
36
39
  const submit_button_id = this.name + "_" + key + "_submit";
@@ -82,9 +85,9 @@ export class Multiform extends MountableWithFields {
82
85
  throw new Error("Wrong turbo-frame header value type");
83
86
  }
84
87
  const forms_to_render =
85
- requested_frame && this.forms[requested_frame]
86
- ? [<const>[requested_frame, this.forms[requested_frame]]]
87
- : Object.entries(this.forms);
88
+ requested_frame && this.forms[requested_frame] ?
89
+ [<const>[requested_frame, this.forms[requested_frame]]]
90
+ : Object.entries(this.forms);
88
91
  return forms_to_render;
89
92
  }
90
93
 
package/src/mount.ts CHANGED
@@ -19,9 +19,9 @@ export function mount(
19
19
  url: string | { rawURL: string },
20
20
  mountable: Mountable,
21
21
  use_dummy_app = false,
22
- file_manager: FileManager | undefined = use_dummy_app
23
- ? new FileManager("/tmp", "/uploaded_files")
24
- : undefined
22
+ file_manager: FileManager | undefined = use_dummy_app ?
23
+ new FileManager("/tmp", "/uploaded_files")
24
+ : undefined
25
25
  ): void {
26
26
  const raw_url = typeof url === "string" ? url : url.rawURL;
27
27
 
@@ -35,8 +35,9 @@ export function mount(
35
35
 
36
36
  const fileManager = new FileManager("/tmp", "/uploaded_files");
37
37
 
38
- const args = use_dummy_app
39
- ? [
38
+ const args =
39
+ use_dummy_app ?
40
+ [
40
41
  async (ctx: Context, next: any) => {
41
42
  // this dummy is a temporary solution it's ilustrating the ways that
42
43
  // sealgen is coupled with sealious. Definitely room for improvement in this
@@ -66,14 +67,17 @@ export function mount(
66
67
  SealiousMiddlewares.parseBody(file_manager),
67
68
  handleHtmlPromise,
68
69
  ]
69
- : [
70
+ : [
70
71
  SealiousMiddlewares.extractContext(),
71
72
  SealiousMiddlewares.parseBody(file_manager),
72
73
  handleHtmlPromise,
73
74
  ];
74
75
 
75
76
  router.use(raw_url, ...args);
76
- mountable.init();
77
+ router.use(raw_url, async (_ctx, next) => {
78
+ mountable.init(raw_url, router);
79
+ await next();
80
+ });
77
81
 
78
82
  // to automatically add trailing slashes:
79
83
  router.get(raw_url.slice(0, -1), async (ctx, next) => {