@sealcode/sealgen 0.19.0 → 0.19.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.
- package/@types/forms/fields/deep-reverse-single-reference-list.d.ts +1 -5
- package/@types/forms/fields/file.d.ts +1 -1
- package/@types/forms/fields/password.d.ts +1 -2
- package/@types/forms/fields/simple-form-field.d.ts +1 -1
- package/@types/forms/fields/single-reference.d.ts +1 -1
- package/@types/register-external.d.ts +2 -2
- package/@types/templates/form.d.ts +1 -3
- package/@types/templates/jdd-component.d.ts +1 -1
- package/@types/templates/page.d.ts +1 -1
- package/@types/templates/shared/shared-crud-form-fields.d.ts +1 -1
- package/@types/templates/templates.d.ts +1 -21
- package/eslint.config.mjs +56 -0
- package/lib/add-crud.js +1 -4
- package/lib/add-jdd-component.js +3 -3
- package/lib/add-route.js +2 -2
- package/lib/build.js +3 -3
- package/lib/builders/backend-ts-builder.js +0 -1
- package/lib/builders/colors-builder.js +11 -8
- package/lib/builders/fonts-builder.js +0 -1
- package/lib/builders/frontend-ts-builder.js +0 -1
- package/lib/cli.js +2 -2
- package/lib/components/tabs.js +36 -36
- package/lib/esbuild-plugins/rewrite-asset-imports.js +7 -10
- package/lib/forms/controls/array.js +5 -6
- package/lib/forms/controls/checkboxed-list-input.js +1 -2
- package/lib/forms/controls/checkboxed-list-input.test.js +6 -6
- package/lib/forms/controls/derived-frame.js +3 -3
- package/lib/forms/controls/dropdown.js +1 -2
- package/lib/forms/controls/file.test.js +1 -1
- package/lib/forms/controls/form-control.js +1 -1
- package/lib/forms/controls/image.test.js +2 -2
- package/lib/forms/controls/single-reference.test.js +1 -1
- package/lib/forms/controls/table.js +10 -15
- package/lib/forms/controls/textarea.js +1 -1
- package/lib/forms/fields/deep-reverse-single-reference-list.js +1 -1
- package/lib/forms/fields/field.test.js +3 -3
- package/lib/forms/fields/file.js +1 -1
- package/lib/forms/fields/file.test.js +1 -1
- package/lib/forms/fields/password.js +1 -1
- package/lib/forms/fields/simple-form-field.js +2 -1
- package/lib/forms/fields/single-reference.js +1 -1
- package/lib/forms/fields/structured-array.js +0 -2
- package/lib/forms/fields/table.js +1 -1
- package/lib/forms/form.js +0 -1
- package/lib/forms/form.test.js +2 -3
- package/lib/forms/multiform.js +6 -7
- package/lib/forms/multiform.test.js +2 -2
- package/lib/generate-collections.js +2 -3
- package/lib/generate-components.js +2 -3
- package/lib/generate-routes.js +3 -5
- package/lib/generate-routes.test.js +7 -16
- package/lib/generate-stimulus.js +4 -5
- package/lib/get-fonts.js +29 -27
- package/lib/make-env.js +1 -1
- package/lib/make-hidden-inputs.js +4 -4
- package/lib/mount.js +0 -1
- package/lib/notifier.js +3 -3
- package/lib/page/list.js +5 -7
- package/lib/page/mountable.js +0 -1
- package/lib/page/page.js +0 -1
- package/lib/register-external.js +4 -4
- package/lib/templates/form.js +1 -1
- package/lib/templates/jdd-component.js +1 -1
- package/lib/templates/jdd-editor.js +1 -1
- package/lib/templates/page.js +1 -1
- package/lib/templates/shared/collection-create-form.js +4 -5
- package/lib/templates/shared/collection-edit-form.js +4 -5
- package/lib/templates/shared/collection-list.js +2 -2
- package/lib/templates/shared/shared-crud-form-fields.js +3 -5
- package/lib/test_utils/exec_async.js +3 -3
- package/lib/test_utils/test-on-real-app.js +9 -11
- package/lib/utils/write-file.js +1 -1
- package/package.json +9 -8
- package/src/add-collection.ts +1 -3
- package/src/add-crud.ts +2 -7
- package/src/add-jdd-component.ts +4 -5
- package/src/add-route.ts +3 -6
- package/src/build.ts +3 -3
- package/src/builders/backend-ts-builder.ts +0 -1
- package/src/builders/builder.ts +4 -1
- package/src/builders/colors-builder.ts +11 -9
- package/src/builders/css-builder.ts +4 -1
- package/src/builders/fonts-builder.ts +0 -1
- package/src/builders/frontend-ts-builder.ts +0 -1
- package/src/cli.ts +2 -2
- package/src/components/tabs.ts +38 -37
- package/src/components/toggle-modal.ts +1 -1
- package/src/controllers/table-add-button.stimulus.ts +1 -1
- package/src/esbuild-plugins/rewrite-asset-imports.ts +7 -10
- package/src/forms/controls/array.ts +12 -16
- package/src/forms/controls/autocomplete.ts +1 -1
- package/src/forms/controls/big-radio-group.ts +2 -2
- package/src/forms/controls/checkbox-group.ts +1 -1
- package/src/forms/controls/checkboxed-list-input.test.ts +6 -6
- package/src/forms/controls/checkboxed-list-input.ts +18 -22
- package/src/forms/controls/derived-frame.ts +11 -10
- package/src/forms/controls/derived.ts +6 -5
- package/src/forms/controls/dropdown.ts +8 -11
- package/src/forms/controls/editable-collection-subset.ts +2 -1
- package/src/forms/controls/field-group.ts +1 -1
- package/src/forms/controls/file.test.ts +1 -1
- package/src/forms/controls/file.ts +4 -7
- package/src/forms/controls/form-control.ts +1 -1
- package/src/forms/controls/hidden-input.ts +1 -0
- package/src/forms/controls/html.ts +1 -0
- package/src/forms/controls/image.test.ts +2 -2
- package/src/forms/controls/image.ts +1 -1
- package/src/forms/controls/multiple-files.ts +5 -7
- package/src/forms/controls/multiple-images.ts +1 -1
- package/src/forms/controls/simple-input.ts +8 -4
- package/src/forms/controls/single-reference.test.ts +1 -1
- package/src/forms/controls/single-reference.ts +1 -1
- package/src/forms/controls/table.ts +16 -21
- package/src/forms/controls/textarea.ts +1 -1
- package/src/forms/controls/tickable.ts +0 -2
- package/src/forms/fields/boolean.ts +4 -1
- package/src/forms/fields/checkboxed-list.ts +1 -1
- package/src/forms/fields/collection-field.ts +5 -2
- package/src/forms/fields/color.ts +1 -1
- package/src/forms/fields/coordinates.ts +2 -2
- package/src/forms/fields/deep-reverse-single-reference-list.ts +2 -8
- package/src/forms/fields/deep-reverse-single-reference-table.ts +1 -1
- package/src/forms/fields/email.ts +1 -1
- package/src/forms/fields/enum-multiple-sealious.ts +1 -1
- package/src/forms/fields/existing-sealious-value.ts +1 -1
- package/src/forms/fields/field.test.ts +3 -3
- package/src/forms/fields/field.ts +6 -5
- package/src/forms/fields/file.test.ts +1 -1
- package/src/forms/fields/file.ts +2 -2
- package/src/forms/fields/float.ts +1 -1
- package/src/forms/fields/get-field-for-sealious.ts +97 -64
- package/src/forms/fields/int.ts +1 -1
- package/src/forms/fields/number.ts +2 -2
- package/src/forms/fields/password.ts +2 -6
- package/src/forms/fields/pick-from-list-sealious.ts +1 -1
- package/src/forms/fields/pick-from-list.ts +1 -1
- package/src/forms/fields/proxy-field.ts +1 -0
- package/src/forms/fields/simple-form-field.ts +13 -5
- package/src/forms/fields/single-reference.ts +2 -2
- package/src/forms/fields/structured-array.ts +2 -6
- package/src/forms/fields/table.ts +7 -15
- package/src/forms/fields/text.ts +1 -1
- package/src/forms/fields/url.ts +1 -1
- package/src/forms/form-types.ts +3 -4
- package/src/forms/form.test.ts +2 -3
- package/src/forms/form.ts +5 -7
- package/src/forms/multiform.test.ts +6 -6
- package/src/forms/multiform.ts +10 -10
- package/src/generate-collections.ts +2 -3
- package/src/generate-components.ts +2 -3
- package/src/generate-routes.test.ts +7 -16
- package/src/generate-routes.ts +6 -10
- package/src/generate-stimulus.ts +4 -6
- package/src/get-fonts.ts +32 -30
- package/src/make-env.ts +1 -1
- package/src/make-hidden-inputs.ts +8 -7
- package/src/mount.ts +2 -7
- package/src/notifier.ts +4 -6
- package/src/page/default-list-filters.ts +1 -0
- package/src/page/list.ts +18 -20
- package/src/page/mountable-with-fields.ts +3 -3
- package/src/page/mountable.ts +0 -1
- package/src/page/page.ts +2 -3
- package/src/page/props-parser.ts +1 -1
- package/src/page/sealious-list.ts +1 -1
- package/src/page/stateful-page.ts +6 -10
- package/src/register-external.ts +4 -4
- package/src/templates/form.ts +1 -2
- package/src/templates/jdd-component.ts +1 -1
- package/src/templates/jdd-editor.ts +2 -4
- package/src/templates/list.ts +0 -1
- package/src/templates/page.ts +1 -4
- package/src/templates/shared/collection-create-form.ts +5 -6
- package/src/templates/shared/collection-edit-form.ts +5 -6
- package/src/templates/shared/collection-list.ts +2 -2
- package/src/templates/shared/shared-crud-form-fields.ts +4 -9
- package/src/templates/templates.ts +5 -1
- package/src/test_utils/exec_async.ts +3 -4
- package/src/test_utils/test-on-real-app.ts +9 -11
- package/src/utils/browser-creator.js +0 -1
- package/src/utils/exec.ts +0 -1
- package/src/utils/input-wrapper.ts +1 -1
- package/src/utils/wrap-attributes.ts +1 -1
- package/src/utils/write-file.ts +1 -1
- package/.eslintrc.cjs +0 -44
package/src/forms/form.ts
CHANGED
|
@@ -29,7 +29,7 @@ import { Errors as SealiousErrors } from "sealious";
|
|
|
29
29
|
|
|
30
30
|
export abstract class Form<
|
|
31
31
|
F extends Fields,
|
|
32
|
-
SubmitResult
|
|
32
|
+
SubmitResult,
|
|
33
33
|
> extends MountableWithFields<F> {
|
|
34
34
|
defaultSuccessMessage = "Done";
|
|
35
35
|
submitButtonText = "Wyślij";
|
|
@@ -38,7 +38,6 @@ export abstract class Form<
|
|
|
38
38
|
form_id = randomUUID() as string;
|
|
39
39
|
|
|
40
40
|
async canAccess(
|
|
41
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
42
41
|
_: Context
|
|
43
42
|
): Promise<{ canAccess: boolean; message: string }> {
|
|
44
43
|
return { canAccess: true, message: "" };
|
|
@@ -48,7 +47,7 @@ export abstract class Form<
|
|
|
48
47
|
_: Context,
|
|
49
48
|
error: PageErrorMessage
|
|
50
49
|
): Promise<JSX.Element | Readable> {
|
|
51
|
-
return tempstream/* HTML */ `<div>${error.message}</div>`;
|
|
50
|
+
return tempstream /* HTML */ `<div>${error.message}</div>`;
|
|
52
51
|
}
|
|
53
52
|
|
|
54
53
|
makeSubmitButton(): JSX.Element {
|
|
@@ -65,7 +64,7 @@ export abstract class Form<
|
|
|
65
64
|
data: FormData,
|
|
66
65
|
show_field_errors: boolean
|
|
67
66
|
): Promise<JSX.Element | Readable> {
|
|
68
|
-
return tempstream/* HTML */ `<div class="form-container">
|
|
67
|
+
return tempstream /* HTML */ `<div class="form-container">
|
|
69
68
|
${this.makeOpenFormTag(ctx)}
|
|
70
69
|
${!this.controls.some((control) => control.role == "messages")
|
|
71
70
|
? this.renderMessages(ctx, data)
|
|
@@ -80,7 +79,6 @@ export abstract class Form<
|
|
|
80
79
|
</div>`;
|
|
81
80
|
}
|
|
82
81
|
|
|
83
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
84
82
|
public async makeFormClasses(_ctx: Context): Promise<string[]> {
|
|
85
83
|
return [];
|
|
86
84
|
}
|
|
@@ -223,8 +221,8 @@ export abstract class Form<
|
|
|
223
221
|
hasFieldOfType(e, "message", predicates.string)
|
|
224
222
|
? e?.message
|
|
225
223
|
: is(e, predicates.string)
|
|
226
|
-
|
|
227
|
-
|
|
224
|
+
? e
|
|
225
|
+
: "Wystąpił błąd";
|
|
228
226
|
|
|
229
227
|
return this.onError(
|
|
230
228
|
ctx,
|
|
@@ -19,7 +19,7 @@ import { EmailField } from "./fields/email.js";
|
|
|
19
19
|
import getPort from "get-port";
|
|
20
20
|
|
|
21
21
|
const port = await getPort();
|
|
22
|
-
console.
|
|
22
|
+
console.info(`Using port ${port} form multiform.test.ts`);
|
|
23
23
|
|
|
24
24
|
const fields1 = {
|
|
25
25
|
email: new TextBasedSimpleField(true),
|
|
@@ -58,7 +58,7 @@ function multiform_factory(
|
|
|
58
58
|
form2: form_factory(canAccessFun2),
|
|
59
59
|
};
|
|
60
60
|
async render(...args: Parameters<Multiform["render"]>): Promise<FlatTemplatable> {
|
|
61
|
-
return tempstream/* HTML */ `<!DOCTYPE html>
|
|
61
|
+
return tempstream /* HTML */ `<!DOCTYPE html>
|
|
62
62
|
<html>
|
|
63
63
|
<head>
|
|
64
64
|
<title>Multiform Test - Sealgen</title>
|
|
@@ -147,7 +147,7 @@ async function individual_field_validation_e2e_tests(javaScriptEnabled: boolean)
|
|
|
147
147
|
await page.getByPlaceholder("text").click();
|
|
148
148
|
await page.getByPlaceholder("text").fill("yes@an.email");
|
|
149
149
|
await page.locator("#multiform_test_form1_submit").click();
|
|
150
|
-
assertThrowsAsync(async () => {
|
|
150
|
+
await assertThrowsAsync(async () => {
|
|
151
151
|
return page.getByText("Please enter a proper email address").click({ timeout: 500 });
|
|
152
152
|
});
|
|
153
153
|
});
|
|
@@ -173,7 +173,7 @@ describe("multiform test", () => {
|
|
|
173
173
|
prerenderedForms?: Record<string, FlatTemplatable | undefined>,
|
|
174
174
|
show_field_errors = true
|
|
175
175
|
): Promise<FlatTemplatable> {
|
|
176
|
-
return tempstream/* HTML */ `<!DOCTYPE html>
|
|
176
|
+
return tempstream /* HTML */ `<!DOCTYPE html>
|
|
177
177
|
<html>
|
|
178
178
|
<head>
|
|
179
179
|
<title>Multiform Test - Sealgen</title>
|
|
@@ -455,7 +455,7 @@ describe("multiform test", () => {
|
|
|
455
455
|
async render(
|
|
456
456
|
...args: Parameters<Multiform["render"]>
|
|
457
457
|
): Promise<FlatTemplatable> {
|
|
458
|
-
return tempstream/* HTML */ `<!DOCTYPE html>
|
|
458
|
+
return tempstream /* HTML */ `<!DOCTYPE html>
|
|
459
459
|
<html>
|
|
460
460
|
<head>
|
|
461
461
|
<title>Multiform Test - Sealgen</title>
|
|
@@ -518,7 +518,7 @@ describe("multiform test", () => {
|
|
|
518
518
|
async render(
|
|
519
519
|
...args: Parameters<Multiform["render"]>
|
|
520
520
|
): Promise<FlatTemplatable> {
|
|
521
|
-
return tempstream/* HTML */ `<!DOCTYPE html>
|
|
521
|
+
return tempstream /* HTML */ `<!DOCTYPE html>
|
|
522
522
|
<html>
|
|
523
523
|
<head>
|
|
524
524
|
<title>Multiform Test - Sealgen</title>
|
package/src/forms/multiform.ts
CHANGED
|
@@ -35,13 +35,14 @@ export class Multiform extends MountableWithFields {
|
|
|
35
35
|
this.getSubformRawValues(context, key);
|
|
36
36
|
const submit_button_id = this.name + "_" + key + "_submit";
|
|
37
37
|
|
|
38
|
-
form.makeSubmitButton = () =>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
form.makeSubmitButton = () =>
|
|
39
|
+
/* HTML */ `<input
|
|
40
|
+
type="submit"
|
|
41
|
+
value="${form.submitButtonText}"
|
|
42
|
+
formaction="${form.action}"
|
|
43
|
+
id="${submit_button_id}"
|
|
44
|
+
${form.form_id ? `form="${form.form_id}"` : ""}
|
|
45
|
+
/> `;
|
|
45
46
|
}
|
|
46
47
|
for (const form of Object.values(this.forms)) {
|
|
47
48
|
for (const field of Object.values(form.fields)) {
|
|
@@ -68,7 +69,6 @@ export class Multiform extends MountableWithFields {
|
|
|
68
69
|
};
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
72
72
|
getSubformsToRender(
|
|
73
73
|
ctx: Context
|
|
74
74
|
): Array<readonly [string, Form<any, unknown>]> {
|
|
@@ -132,7 +132,7 @@ export class Multiform extends MountableWithFields {
|
|
|
132
132
|
prerenderedForms: Record<string, FlatTemplatable | undefined> = {},
|
|
133
133
|
show_field_errors: boolean
|
|
134
134
|
): Promise<FlatTemplatable> {
|
|
135
|
-
return tempstream/* HTML */ `${this.renderMessages(ctx, {
|
|
135
|
+
return tempstream /* HTML */ `${this.renderMessages(ctx, {
|
|
136
136
|
raw_values: {},
|
|
137
137
|
messages,
|
|
138
138
|
field_messages: {},
|
|
@@ -149,7 +149,7 @@ export class Multiform extends MountableWithFields {
|
|
|
149
149
|
${this.getSubformsToRender(ctx).map(([form_name]) => {
|
|
150
150
|
const frame_form_id =
|
|
151
151
|
this.name + "_" + form_name + "_frame_form";
|
|
152
|
-
return tempstream/* HTML */ `<turbo-frame
|
|
152
|
+
return tempstream /* HTML */ `<turbo-frame
|
|
153
153
|
id="${form_name}"
|
|
154
154
|
contains-subform
|
|
155
155
|
subform-id="${frame_form_id}"
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import _locreq from "locreq";
|
|
2
|
-
import * as prettier from "prettier";
|
|
3
2
|
import { promises as fs } from "fs";
|
|
4
3
|
import { assertType, predicates } from "@sealcode/ts-predicates";
|
|
5
|
-
import {
|
|
4
|
+
import { formatWithPrettier } from "./utils/prettier.js";
|
|
6
5
|
|
|
7
6
|
const target_locreq = _locreq(process.cwd());
|
|
8
7
|
|
|
@@ -69,7 +68,7 @@ ${file_data
|
|
|
69
68
|
};`;
|
|
70
69
|
await fs.writeFile(
|
|
71
70
|
target_locreq.resolve("src/back/collections/collections.ts"),
|
|
72
|
-
|
|
71
|
+
await formatWithPrettier(content)
|
|
73
72
|
);
|
|
74
73
|
// eslint-disable-next-line no-console
|
|
75
74
|
console.log(
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import _locreq from "locreq";
|
|
2
|
-
import * as prettier from "prettier";
|
|
3
2
|
import { promises as fs } from "fs";
|
|
4
|
-
import {
|
|
3
|
+
import { formatWithPrettier } from "./utils/prettier.js";
|
|
5
4
|
import recursive from "recursive-readdir";
|
|
6
5
|
import path from "path";
|
|
7
6
|
import { toKebabCase, toPascalCase } from "js-convert-case";
|
|
@@ -40,7 +39,7 @@ ${component_data
|
|
|
40
39
|
const target = "src/back/jdd-components/components.ts";
|
|
41
40
|
await fs.writeFile(
|
|
42
41
|
target_locreq.resolve(target),
|
|
43
|
-
|
|
42
|
+
await formatWithPrettier(content)
|
|
44
43
|
);
|
|
45
44
|
// eslint-disable-next-line no-console
|
|
46
45
|
console.log(`Successfuly generated new ${target} file`);
|
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
import { generateURL, sortRoutes } from "./generate-routes.js";
|
|
2
|
-
import
|
|
3
|
-
import { getPrettierConfig } from "./utils/prettier.js";
|
|
2
|
+
import { formatWithPrettier } from "./utils/prettier.js";
|
|
4
3
|
import assert from "node:assert";
|
|
5
4
|
|
|
6
5
|
describe("generate routes", () => {
|
|
7
6
|
it("handles a url with params", async () => {
|
|
8
7
|
assert.strictEqual(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
await getPrettierConfig()
|
|
12
|
-
),
|
|
13
|
-
prettier.format(
|
|
8
|
+
await formatWithPrettier(generateURL("EditUser", "/admin/users/:id/edit/")),
|
|
9
|
+
await formatWithPrettier(
|
|
14
10
|
`export const EditUserURL = (id: string) => \`/admin/users/\${id}/edit/\`;
|
|
15
11
|
EditUserURL.params = ["id"];
|
|
16
|
-
EditUserURL.rawURL = "/admin/users/:id/edit/"
|
|
17
|
-
await getPrettierConfig()
|
|
12
|
+
EditUserURL.rawURL = "/admin/users/:id/edit/";`
|
|
18
13
|
)
|
|
19
14
|
);
|
|
20
15
|
});
|
|
@@ -28,15 +23,11 @@ EditUserURL.rawURL = "/admin/users/:id/edit/";`,
|
|
|
28
23
|
|
|
29
24
|
it("handles a url with params and diacritics", async () => {
|
|
30
25
|
assert.strictEqual(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
await getPrettierConfig()
|
|
34
|
-
),
|
|
35
|
-
prettier.format(
|
|
26
|
+
await formatWithPrettier(generateURL("EditUser", "/admin/użytkownicy/:id/edit/")),
|
|
27
|
+
await formatWithPrettier(
|
|
36
28
|
`export const EditUserURL = (id: string) => \`/admin/u%C5%BCytkownicy/\${id}/edit/\`;
|
|
37
29
|
EditUserURL.params = ["id"];
|
|
38
|
-
EditUserURL.rawURL = "/admin/u%C5%BCytkownicy/:id/edit/"
|
|
39
|
-
await getPrettierConfig()
|
|
30
|
+
EditUserURL.rawURL = "/admin/u%C5%BCytkownicy/:id/edit/";`
|
|
40
31
|
)
|
|
41
32
|
);
|
|
42
33
|
});
|
package/src/generate-routes.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { promises as fs } from "fs";
|
|
2
|
-
import * as prettier from "prettier";
|
|
3
2
|
import { relative, resolve, basename } from "path";
|
|
4
3
|
import _locreq from "locreq";
|
|
5
4
|
import { walkDir } from "./utils/walk.js";
|
|
6
5
|
import { importPath } from "./utils/import-path.js";
|
|
7
6
|
import { assertType, predicates } from "@sealcode/ts-predicates";
|
|
8
7
|
import { unescape_url_params } from "./utils/escape-url-params.js";
|
|
9
|
-
import {
|
|
8
|
+
import { formatWithPrettier } from "./utils/prettier.js";
|
|
10
9
|
import { Templates } from "./templates/templates.js";
|
|
11
10
|
|
|
12
11
|
const target_locreq = _locreq(process.cwd());
|
|
@@ -42,8 +41,8 @@ export function generateURL(actionName: string, url: string) {
|
|
|
42
41
|
)
|
|
43
42
|
.join("/")}\`;
|
|
44
43
|
${actionName}URL.params = [${params
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
.map((param) => `"${param}"`)
|
|
45
|
+
.join(",")}];
|
|
47
46
|
${actionName}URL.rawURL = "${encodeURI(url)}";`;
|
|
48
47
|
}
|
|
49
48
|
|
|
@@ -70,9 +69,7 @@ export function sortRoutes<T extends { url: string }>(urls: T[]): T[] {
|
|
|
70
69
|
|
|
71
70
|
export async function generateRoutes(): Promise<void> {
|
|
72
71
|
const files = await Promise.all(
|
|
73
|
-
(
|
|
74
|
-
await walkDir(target_locreq.resolve("src/back/routes"))
|
|
75
|
-
)
|
|
72
|
+
(await walkDir(target_locreq.resolve("src/back/routes")))
|
|
76
73
|
.filter((f) =>
|
|
77
74
|
Object.keys(Templates).some(
|
|
78
75
|
(key) =>
|
|
@@ -129,15 +126,14 @@ ${sortRoutes(files)
|
|
|
129
126
|
.join("\n")}
|
|
130
127
|
`;
|
|
131
128
|
|
|
132
|
-
const prettier_config = await getPrettierConfig();
|
|
133
129
|
await fs.writeFile(
|
|
134
130
|
target_locreq.resolve("src/back/routes/routes.ts"),
|
|
135
|
-
|
|
131
|
+
await formatWithPrettier(routes_content)
|
|
136
132
|
);
|
|
137
133
|
|
|
138
134
|
await fs.writeFile(
|
|
139
135
|
target_locreq.resolve("src/back/routes/urls.ts"),
|
|
140
|
-
|
|
136
|
+
await formatWithPrettier(urls_content)
|
|
141
137
|
);
|
|
142
138
|
// eslint-disable-next-line no-console
|
|
143
139
|
console.log(
|
package/src/generate-stimulus.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import _locreq from "locreq";
|
|
2
|
-
import * as prettier from "prettier";
|
|
3
2
|
import { promises as fs } from "fs";
|
|
4
|
-
import {
|
|
3
|
+
import { formatWithPrettier } from "./utils/prettier.js";
|
|
5
4
|
import recursive from "recursive-readdir";
|
|
6
5
|
import path, { dirname } from "path";
|
|
7
6
|
import { toKebabCase, toPascalCase } from "js-convert-case";
|
|
@@ -16,7 +15,7 @@ export async function generateStimulusControllers(
|
|
|
16
15
|
target_locreq.resolve("src/"),
|
|
17
16
|
...controller_dirs,
|
|
18
17
|
];
|
|
19
|
-
console.
|
|
18
|
+
console.info("Looking for controllers in ", stimulus_search_dirs);
|
|
20
19
|
const controller_names = (
|
|
21
20
|
await Promise.all(stimulus_search_dirs.map((dir) => recursive(dir)))
|
|
22
21
|
)
|
|
@@ -54,8 +53,7 @@ export { Turbo };
|
|
|
54
53
|
|
|
55
54
|
await fs.writeFile(
|
|
56
55
|
target_locreq.resolve(output_file),
|
|
57
|
-
|
|
56
|
+
await formatWithPrettier(content)
|
|
58
57
|
);
|
|
59
|
-
|
|
60
|
-
console.log(`Successfuly generated new ${output_file} file`);
|
|
58
|
+
console.info(`Successfuly generated new ${output_file} file`);
|
|
61
59
|
}
|
package/src/get-fonts.ts
CHANGED
|
@@ -34,12 +34,12 @@ export async function getFonts(_: Record<string, string | boolean> = {}) {
|
|
|
34
34
|
});
|
|
35
35
|
await downloader.execute();
|
|
36
36
|
|
|
37
|
-
console.
|
|
37
|
+
console.info("Downloaded new fonts pack from google fonts");
|
|
38
38
|
|
|
39
39
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment
|
|
40
40
|
const squirrel_fonts = fonts_config.fontSquirrel;
|
|
41
41
|
if (
|
|
42
|
-
|
|
42
|
+
is(
|
|
43
43
|
squirrel_fonts,
|
|
44
44
|
predicates.record(
|
|
45
45
|
predicates.string,
|
|
@@ -47,39 +47,41 @@ export async function getFonts(_: Record<string, string | boolean> = {}) {
|
|
|
47
47
|
)
|
|
48
48
|
)
|
|
49
49
|
) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
await mkdir(target_locreq.resolve("public/dist/fontsquirrel/"), {
|
|
54
|
-
recursive: true,
|
|
55
|
-
});
|
|
50
|
+
await mkdir(target_locreq.resolve("public/dist/fontsquirrel/"), {
|
|
51
|
+
recursive: true,
|
|
52
|
+
});
|
|
56
53
|
|
|
57
|
-
|
|
54
|
+
const config_file = `{
|
|
58
55
|
"tmpDir": "/tmp/fonts",
|
|
59
56
|
"fontsDir": "/dist/fontsquirrel/fonts",
|
|
60
57
|
"cssDir": "/dist/fontsquirrel/css",
|
|
61
58
|
"cssFile": "fonts.css"
|
|
62
59
|
}`;
|
|
63
|
-
|
|
60
|
+
await writeFile("public/fonsta.config.json", config_file);
|
|
61
|
+
|
|
62
|
+
await Promise.all(
|
|
63
|
+
Object.keys(squirrel_fonts).map((font) => {
|
|
64
|
+
if (squirrel_fonts[font].length) {
|
|
65
|
+
return execPromise(
|
|
66
|
+
`node ${path_to_fonsta} install ${font}:${squirrel_fonts[
|
|
67
|
+
font
|
|
68
|
+
].join(",")}`,
|
|
69
|
+
{
|
|
70
|
+
cwd: target_locreq.resolve("public"),
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
} else {
|
|
74
|
+
return execPromise(
|
|
75
|
+
`node ${path_to_fonsta} install ${font}`,
|
|
76
|
+
{
|
|
77
|
+
cwd: target_locreq.resolve("public"),
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
);
|
|
83
|
+
}
|
|
64
84
|
|
|
65
|
-
await Promise.all(
|
|
66
|
-
Object.keys(squirrel_fonts).map((font) => {
|
|
67
|
-
if (squirrel_fonts[font].length) {
|
|
68
|
-
return execPromise(
|
|
69
|
-
`node ${path_to_fonsta} install ${font}:${squirrel_fonts[
|
|
70
|
-
font
|
|
71
|
-
].join(",")}`,
|
|
72
|
-
{
|
|
73
|
-
cwd: target_locreq.resolve("public"),
|
|
74
|
-
}
|
|
75
|
-
);
|
|
76
|
-
} else {
|
|
77
|
-
return execPromise(`node ${path_to_fonsta} install ${font}`, {
|
|
78
|
-
cwd: target_locreq.resolve("public"),
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
})
|
|
82
|
-
);
|
|
83
85
|
const fonts_css_file_path = resolve(
|
|
84
86
|
target_locreq.resolve("public/dist/fonts"),
|
|
85
87
|
"fonts.css"
|
|
@@ -93,7 +95,7 @@ export async function getFonts(_: Record<string, string | boolean> = {}) {
|
|
|
93
95
|
|
|
94
96
|
await unlink("public/fonsta.config.json");
|
|
95
97
|
await rmdir("public/tmp");
|
|
96
|
-
console.
|
|
98
|
+
console.info("Downloaded new fonts pack from Font Squirrel");
|
|
97
99
|
|
|
98
|
-
console.
|
|
100
|
+
console.info("Downloaded new fonts pack");
|
|
99
101
|
}
|
package/src/make-env.ts
CHANGED
|
@@ -13,12 +13,13 @@ export function makeHiddenInputs(
|
|
|
13
13
|
return tempstream`${Object.entries(fields)
|
|
14
14
|
.filter(([key]) => !fields_to_skip.includes(key))
|
|
15
15
|
.map(
|
|
16
|
-
([key, field]) =>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
([key, field]) =>
|
|
17
|
+
tempstream /* HTML */ `<input
|
|
18
|
+
type="hidden"
|
|
19
|
+
name="${key}"
|
|
20
|
+
value="${field
|
|
21
|
+
.getParsedValue(ctx, values)
|
|
22
|
+
.then((r) => attribute(JSON.stringify(r.raw) || ""))}"
|
|
23
|
+
/>`
|
|
23
24
|
)}`;
|
|
24
25
|
}
|
package/src/mount.ts
CHANGED
|
@@ -9,7 +9,6 @@ import { KoaResponsiveImageRouter } from "koa-responsive-image-router";
|
|
|
9
9
|
async function handleHtmlPromise(ctx: Context, next: Koa.Next) {
|
|
10
10
|
await next();
|
|
11
11
|
if (ctx.body instanceof Promise) {
|
|
12
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
13
12
|
ctx.body = await ctx.body;
|
|
14
13
|
}
|
|
15
14
|
ctx.set("content-type", "text/html;charset=utf-8");
|
|
@@ -52,31 +51,27 @@ export function mount(
|
|
|
52
51
|
{
|
|
53
52
|
get: (_target: any, prop: any) => {
|
|
54
53
|
if (prop === "info") {
|
|
55
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
56
54
|
return () => {};
|
|
57
55
|
} else {
|
|
58
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
59
56
|
return () => {};
|
|
60
57
|
}
|
|
61
58
|
},
|
|
62
59
|
}
|
|
63
60
|
),
|
|
64
61
|
getString: (x: string) => x,
|
|
65
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
66
62
|
} as any;
|
|
67
63
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
68
64
|
await next();
|
|
69
65
|
},
|
|
70
66
|
SealiousMiddlewares.parseBody(file_manager),
|
|
71
67
|
handleHtmlPromise,
|
|
72
|
-
|
|
68
|
+
]
|
|
73
69
|
: [
|
|
74
70
|
SealiousMiddlewares.extractContext(),
|
|
75
71
|
SealiousMiddlewares.parseBody(file_manager),
|
|
76
72
|
handleHtmlPromise,
|
|
77
|
-
|
|
73
|
+
];
|
|
78
74
|
|
|
79
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
80
75
|
router.use(raw_url, ...args);
|
|
81
76
|
mountable.init();
|
|
82
77
|
|
package/src/notifier.ts
CHANGED
|
@@ -12,7 +12,6 @@ async function get_status(
|
|
|
12
12
|
app_port: number
|
|
13
13
|
): Promise<{ started_at: number; status: string }> {
|
|
14
14
|
const r = await fetch(`http://127.0.0.1:${app_port}/status.json`);
|
|
15
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
16
15
|
return (await r.json()) as { started_at: number; status: string };
|
|
17
16
|
}
|
|
18
17
|
|
|
@@ -21,7 +20,7 @@ async function wait_for_run_id_to_change(app_port: number) {
|
|
|
21
20
|
try {
|
|
22
21
|
const { started_at } = await get_status(app_port);
|
|
23
22
|
first_timestamp = started_at;
|
|
24
|
-
} catch (
|
|
23
|
+
} catch (_e) {
|
|
25
24
|
await wait_for_app_to_be_stable(app_port);
|
|
26
25
|
return;
|
|
27
26
|
}
|
|
@@ -30,7 +29,6 @@ async function wait_for_run_id_to_change(app_port: number) {
|
|
|
30
29
|
throw new Error(APP_DOWN_ERROR_MESSAGE);
|
|
31
30
|
}
|
|
32
31
|
|
|
33
|
-
// eslint-disable-next-line no-constant-condition
|
|
34
32
|
while (true) {
|
|
35
33
|
// eslint-disable-next-line no-await-in-loop
|
|
36
34
|
const { started_at } = await get_status(app_port).catch(() => ({
|
|
@@ -48,7 +46,7 @@ async function wait_for_app_to_be_stable(app_port: number, n = 3) {
|
|
|
48
46
|
// eslint-disable-next-line no-console
|
|
49
47
|
console.log("Waiting for app to be stable....");
|
|
50
48
|
let counter = 0;
|
|
51
|
-
|
|
49
|
+
|
|
52
50
|
while (true) {
|
|
53
51
|
// eslint-disable-next-line no-await-in-loop
|
|
54
52
|
const { status } = await get_status(app_port).catch(() => ({
|
|
@@ -103,8 +101,8 @@ export function make_notifier(port: number, app_port: number) {
|
|
|
103
101
|
});
|
|
104
102
|
});
|
|
105
103
|
|
|
106
|
-
console.
|
|
107
|
-
"
|
|
104
|
+
console.info(
|
|
105
|
+
"🔔 Build notifier listening on websocket at port " + port.toString()
|
|
108
106
|
);
|
|
109
107
|
return function notify(message: string) {
|
|
110
108
|
sockets.forEach((s) => s.send(message));
|
package/src/page/list.ts
CHANGED
|
@@ -48,7 +48,7 @@ function encodeSort(field: string, order: "asc" | "desc"): string {
|
|
|
48
48
|
|
|
49
49
|
export abstract class ListPage<
|
|
50
50
|
ItemType,
|
|
51
|
-
F extends typeof BaseListPageFields
|
|
51
|
+
F extends typeof BaseListPageFields,
|
|
52
52
|
> extends Page<F> {
|
|
53
53
|
abstract getItems(
|
|
54
54
|
ctx: Context,
|
|
@@ -126,7 +126,7 @@ export abstract class ListPage<
|
|
|
126
126
|
values
|
|
127
127
|
);
|
|
128
128
|
|
|
129
|
-
return tempstream/* HTML */ `<div class="list-pagination">
|
|
129
|
+
return tempstream /* HTML */ `<div class="list-pagination">
|
|
130
130
|
<div class="list-pagination__left">
|
|
131
131
|
${page > 1
|
|
132
132
|
? this.renderPageButton(ctx, 1, "Pierwsza strona")
|
|
@@ -141,18 +141,18 @@ export abstract class ListPage<
|
|
|
141
141
|
onchange="if (this.value) Turbo.visit(this.value)"
|
|
142
142
|
>
|
|
143
143
|
${Array.from(naturalNumbers(1, totalIems)).map(
|
|
144
|
-
(n) =>
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
144
|
+
(n) =>
|
|
145
|
+
/* HTML */ `<option
|
|
146
|
+
value="${UrlWithNewParams(
|
|
147
|
+
ctx,
|
|
148
|
+
this.propsParser.overwriteProp(ctx, {
|
|
149
|
+
page: n,
|
|
150
|
+
} as Partial<Record<string, unknown>>)
|
|
151
|
+
)}"
|
|
152
|
+
${page === n ? "selected" : ""}
|
|
153
|
+
>
|
|
154
|
+
${n}
|
|
155
|
+
</option>`
|
|
156
156
|
)}
|
|
157
157
|
</select>
|
|
158
158
|
</div>
|
|
@@ -171,7 +171,6 @@ export abstract class ListPage<
|
|
|
171
171
|
return /* HTML */ `<a
|
|
172
172
|
href="${UrlWithNewParams(
|
|
173
173
|
ctx,
|
|
174
|
-
//eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
175
174
|
this.propsParser.overwriteProp(ctx, {
|
|
176
175
|
page,
|
|
177
176
|
} as Partial<Record<string, unknown>>)
|
|
@@ -219,13 +218,12 @@ export abstract class ListPage<
|
|
|
219
218
|
|
|
220
219
|
async renderFilters(ctx: Context): Promise<FlatTemplatable> {
|
|
221
220
|
const values = await this.extractRawValues(ctx);
|
|
222
|
-
return tempstream/* HTML */ `<form method="GET">
|
|
221
|
+
return tempstream /* HTML */ `<form method="GET">
|
|
223
222
|
${makeHiddenInputs(ctx, this.fields, values, [
|
|
224
223
|
"page",
|
|
225
224
|
...Object.values(this.filterFields).map((f) => f.name),
|
|
226
225
|
])}
|
|
227
226
|
${this.filterControls.map((control) => {
|
|
228
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
229
227
|
return control.render(
|
|
230
228
|
this.makeFormControlContext(
|
|
231
229
|
ctx,
|
|
@@ -253,8 +251,8 @@ export abstract class ListPage<
|
|
|
253
251
|
current_order === "asc" // cycles the sort order: null → "asc" → "desc" → null → ...
|
|
254
252
|
? "desc"
|
|
255
253
|
: current_order === null
|
|
256
|
-
|
|
257
|
-
|
|
254
|
+
? "asc"
|
|
255
|
+
: null;
|
|
258
256
|
return /* HTML */ `<th data-field="${field}">
|
|
259
257
|
<a href="${this.makeSortLink(ctx, field, order)}"
|
|
260
258
|
>${label}
|
|
@@ -272,7 +270,7 @@ export abstract class ListPage<
|
|
|
272
270
|
ctx: Context,
|
|
273
271
|
fields: { field: string; label?: string }[]
|
|
274
272
|
): FlatTemplatable {
|
|
275
|
-
return tempstream/* HTML */ `<thead>
|
|
273
|
+
return tempstream /* HTML */ `<thead>
|
|
276
274
|
<tr>
|
|
277
275
|
${fields.map(({ label, field }) =>
|
|
278
276
|
this.renderHeading(ctx, field, label)
|
|
@@ -25,7 +25,7 @@ type ParsedValue<T extends FormField> = Resolved<
|
|
|
25
25
|
>["parsed"];
|
|
26
26
|
|
|
27
27
|
export abstract class MountableWithFields<
|
|
28
|
-
F extends Fields = Fields
|
|
28
|
+
F extends Fields = Fields,
|
|
29
29
|
> extends Mountable {
|
|
30
30
|
fields: F;
|
|
31
31
|
field_names_prefix = ""; // useful for multiform, where many forms are merged into one and field assignment is made using the prefix
|
|
@@ -116,7 +116,7 @@ export abstract class MountableWithFields<
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
public renderControls(fctx: FormControlContext): FlatTemplatable {
|
|
119
|
-
return tempstream/* HTML */ `${this.controls.map((control) =>
|
|
119
|
+
return tempstream /* HTML */ `${this.controls.map((control) =>
|
|
120
120
|
control.render(fctx)
|
|
121
121
|
)}`;
|
|
122
122
|
}
|
|
@@ -132,7 +132,7 @@ export abstract class MountableWithFields<
|
|
|
132
132
|
_: Context,
|
|
133
133
|
data: FormData<keyof Fields>
|
|
134
134
|
): FlatTemplatable {
|
|
135
|
-
return tempstream/* HTML */ `<div class="form-messages">
|
|
135
|
+
return tempstream /* HTML */ `<div class="form-messages">
|
|
136
136
|
${data.messages.map(
|
|
137
137
|
(message) =>
|
|
138
138
|
`<div class="form-message form-message--${message.type}">${message.text}</div>`
|
package/src/page/mountable.ts
CHANGED