@sealcode/sealgen 0.18.2 → 0.18.5
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/add-collection.d.ts +1 -0
- package/@types/add-crud.d.ts +3 -0
- package/@types/add-jdd-component.d.ts +1 -0
- package/@types/add-list-route.test.d.ts +1 -0
- package/@types/add-route.d.ts +3 -0
- package/@types/add-route.test.d.ts +1 -0
- package/@types/add-verbose-crud.d.ts +3 -0
- package/@types/build.d.ts +3 -0
- package/@types/builders/backend-ts-builder.d.ts +7 -0
- package/@types/builders/builder.d.ts +11 -0
- package/@types/builders/colors-builder.d.ts +10 -0
- package/@types/builders/css-builder.d.ts +19 -0
- package/@types/builders/fonts-builder.d.ts +7 -0
- package/@types/builders/frontend-ts-builder.d.ts +11 -0
- package/@types/cli.d.ts +2 -0
- package/@types/components/components.d.ts +2 -0
- package/@types/components/tabs.d.ts +2 -0
- package/@types/components/toggle-modal.d.ts +6 -0
- package/@types/crud-field-snippets.d.ts +3 -0
- package/@types/embeddable-file-extensions.d.ts +1 -0
- package/@types/esbuild-plugins/load-assets.d.ts +5 -0
- package/@types/esbuild-plugins/rewrite-asset-imports.d.ts +5 -0
- package/@types/example.test.d.ts +1 -0
- package/@types/find-css-includes.d.ts +1 -0
- package/@types/forms/controls/array.d.ts +35 -0
- package/@types/forms/controls/autocomplete.d.ts +22 -0
- package/@types/forms/controls/big-radio-group.d.ts +14 -0
- package/@types/forms/controls/checkbox-group.d.ts +21 -0
- package/@types/forms/controls/checkbox.d.ts +17 -0
- package/@types/forms/controls/checkboxed-list-input.d.ts +21 -0
- package/@types/forms/controls/checkboxed-list-input.test.d.ts +1 -0
- package/@types/forms/controls/collapsible-checkbox-group.d.ts +11 -0
- package/@types/forms/controls/collapsible-field-group.d.ts +21 -0
- package/@types/forms/controls/controls.d.ts +31 -0
- package/@types/forms/controls/derived-frame.d.ts +21 -0
- package/@types/forms/controls/derived.d.ts +13 -0
- package/@types/forms/controls/dropdown.d.ts +30 -0
- package/@types/forms/controls/editable-collection-subset.d.ts +20 -0
- package/@types/forms/controls/field-group.d.ts +23 -0
- package/@types/forms/controls/file.d.ts +13 -0
- package/@types/forms/controls/file.test.d.ts +1 -0
- package/@types/forms/controls/form-control.d.ts +20 -0
- package/@types/forms/controls/form-field-control.d.ts +13 -0
- package/@types/forms/controls/form-header.d.ts +8 -0
- package/@types/forms/controls/form-paragraph.d.ts +7 -0
- package/@types/forms/controls/frame.d.ts +17 -0
- package/@types/forms/controls/hidden-input.d.ts +9 -0
- package/@types/forms/controls/html.d.ts +11 -0
- package/@types/forms/controls/multiple-files.d.ts +40 -0
- package/@types/forms/controls/multiple-photos.d.ts +19 -0
- package/@types/forms/controls/number.d.ts +13 -0
- package/@types/forms/controls/photo.d.ts +21 -0
- package/@types/forms/controls/photo.test.d.ts +1 -0
- package/@types/forms/controls/radio.d.ts +16 -0
- package/@types/forms/controls/reverse-single-reference.d.ts +1 -0
- package/@types/forms/controls/simple-input.d.ts +33 -0
- package/@types/forms/controls/single-reference.d.ts +13 -0
- package/@types/forms/controls/single-reference.test.d.ts +1 -0
- package/@types/forms/controls/table.d.ts +34 -0
- package/@types/forms/controls/textarea.d.ts +25 -0
- package/@types/forms/controls/tickable.d.ts +25 -0
- package/@types/forms/fields/boolean.d.ts +17 -0
- package/@types/forms/fields/boolean.test.d.ts +1 -0
- package/@types/forms/fields/checkboxed-list.d.ts +21 -0
- package/@types/forms/fields/collection-field.d.ts +15 -0
- package/@types/forms/fields/email.d.ts +7 -0
- package/@types/forms/fields/email.test.d.ts +1 -0
- package/@types/forms/fields/enum-multiple.d.ts +18 -0
- package/@types/forms/fields/enum-multiple.test.d.ts +1 -0
- package/@types/forms/fields/enum.d.ts +18 -0
- package/@types/forms/fields/enum.test.d.ts +1 -0
- package/@types/forms/fields/existing-sealious-value.d.ts +6 -0
- package/@types/forms/fields/field.d.ts +48 -0
- package/@types/forms/fields/field.test.d.ts +1 -0
- package/@types/forms/fields/fields.d.ts +16 -0
- package/@types/forms/fields/file.d.ts +19 -0
- package/@types/forms/fields/file.test.d.ts +1 -0
- package/@types/forms/fields/multiple-files.d.ts +14 -0
- package/@types/forms/fields/number.d.ts +23 -0
- package/@types/forms/fields/number.test.d.ts +1 -0
- package/@types/forms/fields/pick-from-list.d.ts +14 -0
- package/@types/forms/fields/pick-from-list.test.d.ts +1 -0
- package/@types/forms/fields/proxy-field.d.ts +13 -0
- package/@types/forms/fields/regexp.d.ts +16 -0
- package/@types/forms/fields/regexp.test.d.ts +1 -0
- package/@types/forms/fields/reverse-single-reference.d.ts +13 -0
- package/@types/forms/fields/simple-form-field.d.ts +9 -0
- package/@types/forms/fields/structured-array.d.ts +14 -0
- package/@types/forms/fields/table.d.ts +13 -0
- package/@types/forms/form-types.d.ts +26 -0
- package/@types/forms/form.d.ts +31 -0
- package/@types/forms/form.test.d.ts +6 -0
- package/@types/forms/multiform.d.ts +24 -0
- package/@types/forms/multiform.test.d.ts +1 -0
- package/@types/generate-collections.d.ts +2 -0
- package/@types/generate-components.d.ts +1 -0
- package/@types/generate-routes.d.ts +5 -0
- package/@types/generate-routes.test.d.ts +1 -0
- package/@types/generate-stimulus.d.ts +1 -0
- package/@types/get-fonts.d.ts +2 -0
- package/@types/index.d.ts +46 -0
- package/@types/make-env.d.ts +1 -0
- package/@types/make-hidden-inputs.d.ts +5 -0
- package/@types/mount.d.ts +7 -0
- package/@types/notifier.d.ts +2 -0
- package/@types/page/access-control.d.ts +6 -0
- package/@types/page/default-list-filters.d.ts +18 -0
- package/@types/page/list.d.ts +48 -0
- package/@types/page/mountable-with-fields.d.ts +42 -0
- package/@types/page/mountable-with-fields.test.d.ts +1 -0
- package/@types/page/mountable.d.ts +11 -0
- package/@types/page/page.d.ts +19 -0
- package/@types/page/props-parser.d.ts +16 -0
- package/@types/page/sealious-list.d.ts +20 -0
- package/@types/page/sealious-list.test.d.ts +1 -0
- package/@types/page/stateful-page.d.ts +63 -0
- package/@types/page/stateful-page.test.d.ts +1 -0
- package/@types/register-external.d.ts +2 -0
- package/@types/register-external.test.d.ts +1 -0
- package/@types/run.d.ts +1 -0
- package/@types/sanitize.d.ts +1 -0
- package/@types/src/builder.d.ts +9 -7
- package/@types/src/crud-field-snippets.d.ts +3 -0
- package/@types/src/page/stateful-page.d.ts +1 -1
- package/@types/src/register-external.d.ts +2 -0
- package/@types/src/register-external.test.d.ts +1 -0
- package/@types/src/templates/shared/handlers/settable-by.d.ts +2 -0
- package/@types/src/templates/shared/shared-crud-form-fields.d.ts +1 -1
- package/@types/target-locreq.d.ts +4 -0
- package/@types/templates/collection.d.ts +1 -0
- package/@types/templates/form.d.ts +16 -0
- package/@types/templates/jdd-component.d.ts +1 -0
- package/@types/templates/jdd-editor.d.ts +1 -0
- package/@types/templates/list.d.ts +1 -0
- package/@types/templates/long-running-process.d.ts +1 -0
- package/@types/templates/multiform.d.ts +1 -0
- package/@types/templates/page.d.ts +1 -0
- package/@types/templates/post.d.ts +1 -0
- package/@types/templates/redirect.d.ts +1 -0
- package/@types/templates/route-test.d.ts +1 -0
- package/@types/templates/shared/collection-create-form.d.ts +1 -0
- package/@types/templates/shared/collection-edit-form.d.ts +1 -0
- package/@types/templates/shared/collection-list.d.ts +16 -0
- package/@types/templates/shared/handlers/boolean.d.ts +2 -0
- package/@types/templates/shared/handlers/date.d.ts +2 -0
- package/@types/templates/shared/handlers/deep-reverse-single-reference.d.ts +2 -0
- package/@types/templates/shared/handlers/default.d.ts +2 -0
- package/@types/templates/shared/handlers/enum.d.ts +2 -0
- package/@types/templates/shared/handlers/file.d.ts +2 -0
- package/@types/templates/shared/handlers/image.d.ts +2 -0
- package/@types/templates/shared/handlers/int.d.ts +2 -0
- package/@types/templates/shared/handlers/jdd.d.ts +2 -0
- package/@types/templates/shared/handlers/single-reference.d.ts +2 -0
- package/@types/templates/shared/handlers/structured-array.d.ts +2 -0
- package/@types/templates/shared/item-delete.d.ts +1 -0
- package/@types/templates/shared/shared-crud-form-fields.d.ts +68 -0
- package/@types/templates/stateful-page.d.ts +1 -0
- package/@types/templates/stimulus-controller.d.ts +1 -0
- package/@types/templates/templates.d.ts +21 -0
- package/@types/test_utils/exec_async.d.ts +1 -0
- package/@types/test_utils/locator_is_visible.d.ts +2 -0
- package/@types/test_utils/test-on-real-app.d.ts +27 -0
- package/@types/utils/assert-throws.d.ts +1 -0
- package/@types/utils/base64.d.ts +2 -0
- package/@types/utils/browser-creator.d.ts +1 -0
- package/@types/utils/escape-url-params.d.ts +2 -0
- package/@types/utils/exec.d.ts +5 -0
- package/@types/utils/extract-fields-from-collection.d.ts +14 -0
- package/@types/utils/format-external-url.d.ts +1 -0
- package/@types/utils/import-path.d.ts +2 -0
- package/@types/utils/input-wrapper.d.ts +3 -0
- package/@types/utils/list-collections.d.ts +1 -0
- package/@types/utils/make-slug.d.ts +1 -0
- package/@types/utils/module-dirname.d.ts +1 -0
- package/@types/utils/natural-numbers.d.ts +1 -0
- package/@types/utils/prettier.d.ts +3 -0
- package/@types/utils/question.d.ts +1 -0
- package/@types/utils/render-attributes.d.ts +1 -0
- package/@types/utils/sleep.d.ts +1 -0
- package/@types/utils/translate.d.ts +3 -0
- package/@types/utils/url-with-new-params.d.ts +2 -0
- package/@types/utils/utils.d.ts +17 -0
- package/@types/utils/walk.d.ts +1 -0
- package/@types/utils/with-fallback.d.ts +2 -0
- package/@types/utils/write-file.d.ts +1 -0
- package/README.md +57 -0
- package/lib/cli.js +13 -5
- package/lib/crud-field-snippets.js +52 -0
- package/lib/esbuild-plugins/rewrite-asset-imports.js +0 -2
- package/lib/page/list.js +6 -2
- package/lib/page/stateful-page.js +1 -1
- package/lib/register-external.js +105 -0
- package/lib/register-external.test.js +340 -0
- package/lib/templates/shared/handlers/default.js +1 -1
- package/lib/templates/shared/shared-crud-form-fields.js +2 -0
- package/lib/utils/extract-fields-from-collection.js +3 -3
- package/package.json +1 -1
- package/src/cli.ts +12 -4
- package/src/crud-field-snippets.ts +57 -0
- package/src/esbuild-plugins/rewrite-asset-imports.ts +0 -2
- package/src/find-css-includes.ts +0 -3
- package/src/page/list.ts +16 -3
- package/src/page/stateful-page.ts +3 -1
- package/src/register-external.test.ts +469 -0
- package/src/register-external.ts +148 -0
- package/src/templates/shared/handlers/default.ts +1 -0
- package/src/templates/shared/shared-crud-form-fields.ts +8 -0
- package/src/utils/extract-fields-from-collection.ts +3 -3
- package/remove-named-imports.js +0 -68
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
import assert from "assert";
|
|
2
|
+
import { promises as fs } from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { RealAppTest } from "./test_utils/test-on-real-app.js";
|
|
5
|
+
async function ensureSealgenConfig(test_app) {
|
|
6
|
+
const packageJsonPath = path.join(test_app.app_path, "package.json");
|
|
7
|
+
let packageJsonContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
8
|
+
let packageJson = JSON.parse(packageJsonContent);
|
|
9
|
+
if (!packageJson.sealgen) {
|
|
10
|
+
packageJson.sealgen = {};
|
|
11
|
+
}
|
|
12
|
+
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
13
|
+
}
|
|
14
|
+
async function createMockExternalModule(test_app, moduleName, subdirectory, files) {
|
|
15
|
+
const externalModulePath = path.join(test_app.app_path, "node_modules", moduleName);
|
|
16
|
+
const targetPath = path.join(externalModulePath, subdirectory);
|
|
17
|
+
await fs.mkdir(targetPath, { recursive: true });
|
|
18
|
+
for (const file of files) {
|
|
19
|
+
await fs.writeFile(path.join(targetPath, file.name), file.content);
|
|
20
|
+
if (file.name.endsWith(".ts") && file.name.includes("stimulus")) {
|
|
21
|
+
const jsName = file.name.replace(/\.ts$/, ".js");
|
|
22
|
+
const exportName = file.name.replace(/\.stimulus\.ts$/, "");
|
|
23
|
+
await fs.writeFile(
|
|
24
|
+
path.join(targetPath, jsName),
|
|
25
|
+
`export default { connect() { console.log('Dummy JS for ${exportName}'); } }`
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
describe("register-external CLI commands", () => {
|
|
31
|
+
describe("package.json configuration", () => {
|
|
32
|
+
it("registers external controllers and verifies package.json is updated", async function() {
|
|
33
|
+
const test_app = await RealAppTest.init();
|
|
34
|
+
await ensureSealgenConfig(test_app);
|
|
35
|
+
const moduleName = "test-controller-module";
|
|
36
|
+
const subdirectory = "controllers";
|
|
37
|
+
await test_app.runSealgenCommand(
|
|
38
|
+
`register-external-controllers ${moduleName} ${subdirectory}`
|
|
39
|
+
);
|
|
40
|
+
const packageJsonPath = path.join(test_app.app_path, "package.json");
|
|
41
|
+
const packageJsonContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
42
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
43
|
+
assert(packageJson.sealgen, "sealgen configuration should exist");
|
|
44
|
+
assert(packageJson.sealgen.controllerDirs, "controllerDirs should exist");
|
|
45
|
+
assert(
|
|
46
|
+
Array.isArray(packageJson.sealgen.controllerDirs),
|
|
47
|
+
"controllerDirs should be an array"
|
|
48
|
+
);
|
|
49
|
+
const expectedPath = `node_modules/${moduleName}/${subdirectory}`;
|
|
50
|
+
assert(
|
|
51
|
+
packageJson.sealgen.controllerDirs.includes(expectedPath),
|
|
52
|
+
`controllerDirs should contain ${expectedPath}`
|
|
53
|
+
);
|
|
54
|
+
await test_app.close();
|
|
55
|
+
}).timeout(100 * 1e3);
|
|
56
|
+
it("registers external styles and verifies package.json is updated", async function() {
|
|
57
|
+
const test_app = await RealAppTest.init();
|
|
58
|
+
await ensureSealgenConfig(test_app);
|
|
59
|
+
const moduleName = "test-style-module";
|
|
60
|
+
const subdirectory = "styles";
|
|
61
|
+
await test_app.runSealgenCommand(
|
|
62
|
+
`register-external-styles ${moduleName} ${subdirectory}`
|
|
63
|
+
);
|
|
64
|
+
const packageJsonPath = path.join(test_app.app_path, "package.json");
|
|
65
|
+
const packageJsonContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
66
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
67
|
+
assert(packageJson.sealgen, "sealgen configuration should exist");
|
|
68
|
+
assert(packageJson.sealgen.styleDirs, "styleDirs should exist");
|
|
69
|
+
assert(Array.isArray(packageJson.sealgen.styleDirs), "styleDirs should be an array");
|
|
70
|
+
const expectedPath = `node_modules/${moduleName}/${subdirectory}`;
|
|
71
|
+
assert(
|
|
72
|
+
packageJson.sealgen.styleDirs.includes(expectedPath),
|
|
73
|
+
`styleDirs should contain ${expectedPath}`
|
|
74
|
+
);
|
|
75
|
+
await test_app.close();
|
|
76
|
+
}).timeout(100 * 1e3);
|
|
77
|
+
it("registers both controllers and styles in the same project", async function() {
|
|
78
|
+
const test_app = await RealAppTest.init();
|
|
79
|
+
await ensureSealgenConfig(test_app);
|
|
80
|
+
const controllerModule = "test-controller-module";
|
|
81
|
+
const controllerSubdir = "controllers";
|
|
82
|
+
const styleModule = "test-style-module";
|
|
83
|
+
const styleSubdir = "styles";
|
|
84
|
+
await test_app.runSealgenCommand(
|
|
85
|
+
`register-external-controllers ${controllerModule} ${controllerSubdir}`
|
|
86
|
+
);
|
|
87
|
+
await test_app.runSealgenCommand(
|
|
88
|
+
`register-external-styles ${styleModule} ${styleSubdir}`
|
|
89
|
+
);
|
|
90
|
+
const packageJsonPath = path.join(test_app.app_path, "package.json");
|
|
91
|
+
const packageJsonContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
92
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
93
|
+
assert(packageJson.sealgen, "sealgen configuration should exist");
|
|
94
|
+
assert(packageJson.sealgen.controllerDirs, "controllerDirs should exist");
|
|
95
|
+
assert(packageJson.sealgen.styleDirs, "styleDirs should exist");
|
|
96
|
+
const expectedControllerPath = `node_modules/${controllerModule}/${controllerSubdir}`;
|
|
97
|
+
const expectedStylePath = `node_modules/${styleModule}/${styleSubdir}`;
|
|
98
|
+
assert(
|
|
99
|
+
packageJson.sealgen.controllerDirs.includes(expectedControllerPath),
|
|
100
|
+
`controllerDirs should contain ${expectedControllerPath}`
|
|
101
|
+
);
|
|
102
|
+
assert(
|
|
103
|
+
packageJson.sealgen.styleDirs.includes(expectedStylePath),
|
|
104
|
+
`styleDirs should contain ${expectedStylePath}`
|
|
105
|
+
);
|
|
106
|
+
await test_app.close();
|
|
107
|
+
}).timeout(100 * 1e3);
|
|
108
|
+
it("handles duplicate registrations gracefully", async function() {
|
|
109
|
+
const test_app = await RealAppTest.init();
|
|
110
|
+
await ensureSealgenConfig(test_app);
|
|
111
|
+
const moduleName = "test-duplicate-module";
|
|
112
|
+
const subdirectory = "controllers";
|
|
113
|
+
await test_app.runSealgenCommand(
|
|
114
|
+
`register-external-controllers ${moduleName} ${subdirectory}`
|
|
115
|
+
);
|
|
116
|
+
await test_app.runSealgenCommand(
|
|
117
|
+
`register-external-controllers ${moduleName} ${subdirectory}`
|
|
118
|
+
);
|
|
119
|
+
const packageJsonPath = path.join(test_app.app_path, "package.json");
|
|
120
|
+
const packageJsonContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
121
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
122
|
+
assert(packageJson.sealgen, "sealgen configuration should exist");
|
|
123
|
+
assert(packageJson.sealgen.controllerDirs, "controllerDirs should exist");
|
|
124
|
+
const expectedPath = `node_modules/${moduleName}/${subdirectory}`;
|
|
125
|
+
const controllerDirs = packageJson.sealgen.controllerDirs;
|
|
126
|
+
const occurrences = controllerDirs.filter((dir) => dir === expectedPath).length;
|
|
127
|
+
assert(
|
|
128
|
+
occurrences === 1,
|
|
129
|
+
`controllerDirs should contain ${expectedPath} exactly once, found ${occurrences} times`
|
|
130
|
+
);
|
|
131
|
+
await test_app.close();
|
|
132
|
+
}).timeout(100 * 1e3);
|
|
133
|
+
it("preserves existing sealgen configuration when adding new entries", async function() {
|
|
134
|
+
const test_app = await RealAppTest.init();
|
|
135
|
+
const packageJsonPath = path.join(test_app.app_path, "package.json");
|
|
136
|
+
const packageJsonContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
137
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
138
|
+
packageJson.sealgen = {
|
|
139
|
+
controllerDirs: ["node_modules/existing-controller/controllers"],
|
|
140
|
+
styleDirs: ["node_modules/existing-style/styles"]
|
|
141
|
+
};
|
|
142
|
+
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
143
|
+
const newControllerModule = "new-controller-module";
|
|
144
|
+
const newStyleModule = "new-style-module";
|
|
145
|
+
await test_app.runSealgenCommand(
|
|
146
|
+
`register-external-controllers ${newControllerModule} controllers`
|
|
147
|
+
);
|
|
148
|
+
await test_app.runSealgenCommand(`register-external-styles ${newStyleModule} styles`);
|
|
149
|
+
const updatedPackageJsonContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
150
|
+
const updatedPackageJson = JSON.parse(updatedPackageJsonContent);
|
|
151
|
+
assert(updatedPackageJson.sealgen, "sealgen configuration should exist");
|
|
152
|
+
assert(updatedPackageJson.sealgen.controllerDirs, "controllerDirs should exist");
|
|
153
|
+
assert(updatedPackageJson.sealgen.styleDirs, "styleDirs should exist");
|
|
154
|
+
assert(
|
|
155
|
+
updatedPackageJson.sealgen.controllerDirs.includes(
|
|
156
|
+
"node_modules/existing-controller/controllers"
|
|
157
|
+
),
|
|
158
|
+
"Existing controller directory should be preserved"
|
|
159
|
+
);
|
|
160
|
+
assert(
|
|
161
|
+
updatedPackageJson.sealgen.styleDirs.includes("node_modules/existing-style/styles"),
|
|
162
|
+
"Existing style directory should be preserved"
|
|
163
|
+
);
|
|
164
|
+
assert(
|
|
165
|
+
updatedPackageJson.sealgen.controllerDirs.includes(
|
|
166
|
+
`node_modules/${newControllerModule}/controllers`
|
|
167
|
+
),
|
|
168
|
+
"New controller directory should be added"
|
|
169
|
+
);
|
|
170
|
+
assert(
|
|
171
|
+
updatedPackageJson.sealgen.styleDirs.includes(
|
|
172
|
+
`node_modules/${newStyleModule}/styles`
|
|
173
|
+
),
|
|
174
|
+
"New style directory should be added"
|
|
175
|
+
);
|
|
176
|
+
await test_app.close();
|
|
177
|
+
}).timeout(100 * 1e3);
|
|
178
|
+
});
|
|
179
|
+
describe("build integration", () => {
|
|
180
|
+
it("registers external controllers and verifies they are included in build", async function() {
|
|
181
|
+
const test_app = await RealAppTest.init();
|
|
182
|
+
await ensureSealgenConfig(test_app);
|
|
183
|
+
const externalModuleName = "test-external-controllers";
|
|
184
|
+
await createMockExternalModule(test_app, externalModuleName, "controllers", [
|
|
185
|
+
{
|
|
186
|
+
name: "test-external.stimulus.ts",
|
|
187
|
+
content: `
|
|
188
|
+
import { Controller } from "stimulus";
|
|
189
|
+
|
|
190
|
+
export default class TestExternalController extends Controller {
|
|
191
|
+
static targets = ["output"];
|
|
192
|
+
|
|
193
|
+
connect() {
|
|
194
|
+
console.log("External controller connected!");
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
`
|
|
198
|
+
}
|
|
199
|
+
]);
|
|
200
|
+
await test_app.runSealgenCommand(
|
|
201
|
+
`register-external-controllers ${externalModuleName} controllers`
|
|
202
|
+
);
|
|
203
|
+
await test_app.runSealgenCommand("build");
|
|
204
|
+
const controllersFilePath = path.join(test_app.app_path, "src/front/controllers.ts");
|
|
205
|
+
const controllersContent = await fs.readFile(controllersFilePath, "utf-8");
|
|
206
|
+
assert(
|
|
207
|
+
controllersContent.includes(
|
|
208
|
+
`import { default as TestExternal } from "./../../node_modules/${externalModuleName}/controllers/test-external.stimulus.js"`
|
|
209
|
+
),
|
|
210
|
+
"External controller should be imported in generated controllers file"
|
|
211
|
+
);
|
|
212
|
+
assert(
|
|
213
|
+
controllersContent.includes(`application.register("test-external", TestExternal);`),
|
|
214
|
+
"External controller should be registered in generated controllers file"
|
|
215
|
+
);
|
|
216
|
+
const bundlePath = path.join(test_app.app_path, "public/dist/bundle.js");
|
|
217
|
+
assert(
|
|
218
|
+
await fs.stat(bundlePath).then(() => true).catch(() => false),
|
|
219
|
+
"Bundle should be generated"
|
|
220
|
+
);
|
|
221
|
+
await test_app.close();
|
|
222
|
+
}).timeout(100 * 1e3);
|
|
223
|
+
it("registers external styles and verifies they are included in build", async function() {
|
|
224
|
+
const test_app = await RealAppTest.init();
|
|
225
|
+
await ensureSealgenConfig(test_app);
|
|
226
|
+
const externalModuleName = "test-external-styles";
|
|
227
|
+
await createMockExternalModule(test_app, externalModuleName, "styles", [
|
|
228
|
+
{
|
|
229
|
+
name: "external.css",
|
|
230
|
+
content: `
|
|
231
|
+
.external-style {
|
|
232
|
+
color: red;
|
|
233
|
+
background: blue;
|
|
234
|
+
}
|
|
235
|
+
`
|
|
236
|
+
}
|
|
237
|
+
]);
|
|
238
|
+
await test_app.runSealgenCommand(
|
|
239
|
+
`register-external-styles ${externalModuleName} styles`
|
|
240
|
+
);
|
|
241
|
+
await test_app.runSealgenCommand("build");
|
|
242
|
+
const styleEntrypointPath = path.join(
|
|
243
|
+
test_app.app_path,
|
|
244
|
+
"src/style-entrypoints/default.entrypoint.css"
|
|
245
|
+
);
|
|
246
|
+
const styleEntrypointContent = await fs.readFile(styleEntrypointPath, "utf-8");
|
|
247
|
+
assert(
|
|
248
|
+
styleEntrypointContent.includes(
|
|
249
|
+
`@import "../../node_modules/${externalModuleName}/styles/external.css"`
|
|
250
|
+
),
|
|
251
|
+
"External CSS should be imported in generated style entrypoint"
|
|
252
|
+
);
|
|
253
|
+
const cssOutputPath = path.join(
|
|
254
|
+
test_app.app_path,
|
|
255
|
+
"public/dist/default.entrypoint.css"
|
|
256
|
+
);
|
|
257
|
+
assert(
|
|
258
|
+
await fs.stat(cssOutputPath).then(() => true).catch(() => false),
|
|
259
|
+
"CSS should be generated"
|
|
260
|
+
);
|
|
261
|
+
await test_app.close();
|
|
262
|
+
}).timeout(100 * 1e3);
|
|
263
|
+
it("registers both external controllers and styles and verifies complete build integration", async function() {
|
|
264
|
+
const test_app = await RealAppTest.init();
|
|
265
|
+
await ensureSealgenConfig(test_app);
|
|
266
|
+
const controllerModuleName = "test-external-controllers";
|
|
267
|
+
const styleModuleName = "test-external-styles";
|
|
268
|
+
await createMockExternalModule(test_app, controllerModuleName, "controllers", [
|
|
269
|
+
{
|
|
270
|
+
name: "combined-test.stimulus.ts",
|
|
271
|
+
content: `
|
|
272
|
+
import { Controller } from "stimulus";
|
|
273
|
+
|
|
274
|
+
export default class CombinedTestController extends Controller {
|
|
275
|
+
static targets = ["output"];
|
|
276
|
+
|
|
277
|
+
connect() {
|
|
278
|
+
console.log("Combined test controller connected!");
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
`
|
|
282
|
+
}
|
|
283
|
+
]);
|
|
284
|
+
await createMockExternalModule(test_app, styleModuleName, "styles", [
|
|
285
|
+
{
|
|
286
|
+
name: "combined-external.css",
|
|
287
|
+
content: `
|
|
288
|
+
.combined-external-style {
|
|
289
|
+
color: green;
|
|
290
|
+
background: yellow;
|
|
291
|
+
}
|
|
292
|
+
`
|
|
293
|
+
}
|
|
294
|
+
]);
|
|
295
|
+
await test_app.runSealgenCommand(
|
|
296
|
+
`register-external-controllers ${controllerModuleName} controllers`
|
|
297
|
+
);
|
|
298
|
+
await test_app.runSealgenCommand(`register-external-styles ${styleModuleName} styles`);
|
|
299
|
+
await test_app.runSealgenCommand("build");
|
|
300
|
+
const controllersFilePath = path.join(test_app.app_path, "src/front/controllers.ts");
|
|
301
|
+
const controllersContent = await fs.readFile(controllersFilePath, "utf-8");
|
|
302
|
+
assert(
|
|
303
|
+
controllersContent.includes(
|
|
304
|
+
`import { default as CombinedTest } from "./../../node_modules/${controllerModuleName}/controllers/combined-test.stimulus.js"`
|
|
305
|
+
),
|
|
306
|
+
"Combined test controller should be imported"
|
|
307
|
+
);
|
|
308
|
+
assert(
|
|
309
|
+
controllersContent.includes(`application.register("combined-test", CombinedTest);`),
|
|
310
|
+
"Combined test controller should be registered"
|
|
311
|
+
);
|
|
312
|
+
const styleEntrypointPath = path.join(
|
|
313
|
+
test_app.app_path,
|
|
314
|
+
"src/style-entrypoints/default.entrypoint.css"
|
|
315
|
+
);
|
|
316
|
+
const styleEntrypointContent = await fs.readFile(styleEntrypointPath, "utf-8");
|
|
317
|
+
assert(
|
|
318
|
+
styleEntrypointContent.includes(
|
|
319
|
+
`@import "../../node_modules/${styleModuleName}/styles/combined-external.css"`
|
|
320
|
+
),
|
|
321
|
+
"Combined external CSS should be imported"
|
|
322
|
+
);
|
|
323
|
+
const bundlePath = path.join(test_app.app_path, "public/dist/bundle.js");
|
|
324
|
+
const cssOutputPath = path.join(
|
|
325
|
+
test_app.app_path,
|
|
326
|
+
"public/dist/default.entrypoint.css"
|
|
327
|
+
);
|
|
328
|
+
assert(
|
|
329
|
+
await fs.stat(bundlePath).then(() => true).catch(() => false),
|
|
330
|
+
"Bundle should be generated"
|
|
331
|
+
);
|
|
332
|
+
assert(
|
|
333
|
+
await fs.stat(cssOutputPath).then(() => true).catch(() => false),
|
|
334
|
+
"CSS should be generated"
|
|
335
|
+
);
|
|
336
|
+
await test_app.close();
|
|
337
|
+
}).timeout(100 * 1e3);
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
//# sourceMappingURL=register-external.test.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { toPascalCase } from "js-convert-case";
|
|
2
|
-
const default_handler = async (collection_name, { name, is_readonly, is_required }, _, __, fields_var = `${toPascalCase(collection_name)}FormFields`) => {
|
|
2
|
+
const default_handler = async (collection_name, { name, is_readonly, is_required }, _, __, ___, fields_var = `${toPascalCase(collection_name)}FormFields`) => {
|
|
3
3
|
const required_s = `${toPascalCase(
|
|
4
4
|
collection_name
|
|
5
5
|
)}.fields.${name}.required`;
|
|
@@ -36,6 +36,7 @@ async function getFieldHandler(collection_name, field, importPath, fields_var) {
|
|
|
36
36
|
field,
|
|
37
37
|
importPath,
|
|
38
38
|
{},
|
|
39
|
+
field_handlers,
|
|
39
40
|
fields_var
|
|
40
41
|
);
|
|
41
42
|
const result = {
|
|
@@ -45,6 +46,7 @@ async function getFieldHandler(collection_name, field, importPath, fields_var) {
|
|
|
45
46
|
field,
|
|
46
47
|
importPath,
|
|
47
48
|
defaults,
|
|
49
|
+
field_handlers,
|
|
48
50
|
fields_var
|
|
49
51
|
) || {}
|
|
50
52
|
};
|
|
@@ -14,7 +14,7 @@ async function extract_fields_from_collection(collection_name) {
|
|
|
14
14
|
const c = new the_app().collections["${collection_name}"];
|
|
15
15
|
const fields = [];
|
|
16
16
|
for (const field_name in c.fields){
|
|
17
|
-
|
|
17
|
+
let field = c.fields[field_name];
|
|
18
18
|
let type = field.typeName;
|
|
19
19
|
let target = null;
|
|
20
20
|
let referencing_collection = null;
|
|
@@ -23,7 +23,7 @@ for (const field_name in c.fields){
|
|
|
23
23
|
let is_readonly = false;
|
|
24
24
|
let is_required = field.required;
|
|
25
25
|
let subfields = [];
|
|
26
|
-
if(["derived-value", "cached-value"].includes(type)){
|
|
26
|
+
if(["derived-value", "cached-value", "settable-by"].includes(type)){
|
|
27
27
|
type = field.virtual_field.typeName;
|
|
28
28
|
}
|
|
29
29
|
if(["derived-value", "cached-value", "reverse-single-reference"].includes(field.typeName)){
|
|
@@ -36,7 +36,7 @@ for (const field_name in c.fields){
|
|
|
36
36
|
intermediary_field_that_points_there = field.intermediary_field_that_points_there
|
|
37
37
|
}
|
|
38
38
|
if( type == "structured-array" ) {
|
|
39
|
-
subfields = Object.keys(field.subfields).map(key=>({name: key}));
|
|
39
|
+
subfields = Object.keys(field.subfields || field.virtual_field.subfields).map(key=>({name: key}));
|
|
40
40
|
}
|
|
41
41
|
fields.push({ name: field_name, type, target, referencing_collection, referencing_field, intermediary_field_that_points_there, is_readonly, is_required, subfields })
|
|
42
42
|
}
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import yargs from "yargs/yargs";
|
|
2
3
|
import { addCollection } from "./add-collection.js";
|
|
4
|
+
import { addCRUD } from "./add-crud.js";
|
|
3
5
|
import { addJDDComponent } from "./add-jdd-component.js";
|
|
4
6
|
import { addRoute } from "./add-route.js";
|
|
7
|
+
import { addVerboseCRUD } from "./add-verbose-crud.js";
|
|
5
8
|
import { buildProject } from "./build.js";
|
|
6
9
|
import { generateCollections } from "./generate-collections.js";
|
|
7
10
|
import { generateComponents } from "./generate-components.js";
|
|
8
11
|
import { generateRoutes } from "./generate-routes.js";
|
|
9
|
-
import { makeEnv } from "./make-env.js";
|
|
10
|
-
import yargs from "yargs/yargs";
|
|
11
12
|
import { getFonts } from "./get-fonts.js";
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
13
|
+
import { makeEnv } from "./make-env.js";
|
|
14
|
+
import { crudFieldSnippets } from "./crud-field-snippets.js";
|
|
15
|
+
import {
|
|
16
|
+
registerExternalControllers,
|
|
17
|
+
registerExternalStyles,
|
|
18
|
+
} from "./register-external.js";
|
|
14
19
|
|
|
15
20
|
const actions: Record<
|
|
16
21
|
string,
|
|
@@ -35,6 +40,9 @@ const actions: Record<
|
|
|
35
40
|
"make-env": makeEnv,
|
|
36
41
|
"add-component": addJDDComponent,
|
|
37
42
|
"get-fonts": getFonts,
|
|
43
|
+
"crud-field-snippets": crudFieldSnippets,
|
|
44
|
+
"register-external-controllers": registerExternalControllers,
|
|
45
|
+
"register-external-styles": registerExternalStyles,
|
|
38
46
|
};
|
|
39
47
|
|
|
40
48
|
void (async function () {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import _locreq from "locreq";
|
|
2
|
+
import prompts from "prompts";
|
|
3
|
+
import { getFieldHandler } from "./templates/shared/shared-crud-form-fields.js";
|
|
4
|
+
import extract_fields_from_collection from "./utils/extract-fields-from-collection.js";
|
|
5
|
+
import { listCollections } from "./utils/list-collections.js";
|
|
6
|
+
import { formatWithPrettier } from "./utils/prettier.js";
|
|
7
|
+
|
|
8
|
+
export async function crudFieldSnippets(
|
|
9
|
+
params: Partial<{ [key in "collection" | "url"]: string }>,
|
|
10
|
+
app_directory: string = process.cwd()
|
|
11
|
+
) {
|
|
12
|
+
const target_locreq = _locreq(app_directory);
|
|
13
|
+
prompts.override(params);
|
|
14
|
+
const { collection_name } = (await prompts([
|
|
15
|
+
{
|
|
16
|
+
type: "autocomplete",
|
|
17
|
+
name: "collection_name",
|
|
18
|
+
message:
|
|
19
|
+
"Which sealious collection do you like to show a CRUD field config for?",
|
|
20
|
+
choices: (
|
|
21
|
+
await listCollections()
|
|
22
|
+
).map((collection) => ({
|
|
23
|
+
title: collection,
|
|
24
|
+
value: collection,
|
|
25
|
+
})),
|
|
26
|
+
},
|
|
27
|
+
])) as { collection_name: string };
|
|
28
|
+
const all_fields = await extract_fields_from_collection(collection_name);
|
|
29
|
+
const { field_name } = (await prompts([
|
|
30
|
+
{
|
|
31
|
+
type: "autocomplete",
|
|
32
|
+
name: "field_name",
|
|
33
|
+
message: `Which field do you want to show CRUD config for??`,
|
|
34
|
+
choices: all_fields.map((field) => ({
|
|
35
|
+
title: field.name,
|
|
36
|
+
value: field.name,
|
|
37
|
+
})),
|
|
38
|
+
},
|
|
39
|
+
])) as { field_name: string };
|
|
40
|
+
|
|
41
|
+
const handler = await getFieldHandler(
|
|
42
|
+
collection_name,
|
|
43
|
+
all_fields.find((e) => e.name == field_name)!,
|
|
44
|
+
(p) => p
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
console.log(`
|
|
48
|
+
|
|
49
|
+
### Field in shared.ts
|
|
50
|
+
|
|
51
|
+
${handler.field}
|
|
52
|
+
|
|
53
|
+
### Control in shared.ts
|
|
54
|
+
|
|
55
|
+
${await formatWithPrettier(handler.controls)}
|
|
56
|
+
`);
|
|
57
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { promises as fs } from "fs";
|
|
2
2
|
import { extname, resolve } from "node:path";
|
|
3
3
|
import { embeddable_file_extensions } from "../embeddable-file-extensions.js";
|
|
4
|
-
import { removeNamedImports } from "../../remove-named-imports.js";
|
|
5
4
|
import { PluginBuild } from "esbuild";
|
|
6
5
|
|
|
7
6
|
export const rewrite_asset_imports_plugin = (project_dir: string) => ({
|
|
@@ -34,7 +33,6 @@ export const rewrite_asset_imports_plugin = (project_dir: string) => ({
|
|
|
34
33
|
}
|
|
35
34
|
);
|
|
36
35
|
|
|
37
|
-
contents = removeNamedImports(contents) as string;
|
|
38
36
|
return {
|
|
39
37
|
contents,
|
|
40
38
|
loader: extname(args.path) === ".tsx" ? "tsx" : "ts",
|
package/src/find-css-includes.ts
CHANGED
package/src/page/list.ts
CHANGED
|
@@ -198,10 +198,18 @@ export abstract class ListPage<
|
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
200
|
|
|
201
|
-
makeSortLink(
|
|
201
|
+
makeSortLink(
|
|
202
|
+
ctx: Context,
|
|
203
|
+
field: string,
|
|
204
|
+
order: "asc" | "desc" | null
|
|
205
|
+
): string {
|
|
202
206
|
const url = new URL(ctx.url, "https://example.com");
|
|
203
207
|
const params = qs.parse(url.search.slice(1));
|
|
204
|
-
|
|
208
|
+
if (order === null) {
|
|
209
|
+
delete params.sort;
|
|
210
|
+
} else {
|
|
211
|
+
params.sort = encodeSort(field, order);
|
|
212
|
+
}
|
|
205
213
|
url.search = qs.stringify(params);
|
|
206
214
|
return url.pathname + url.search;
|
|
207
215
|
}
|
|
@@ -234,7 +242,12 @@ export abstract class ListPage<
|
|
|
234
242
|
const current_sort = await this.getSort(ctx);
|
|
235
243
|
const current_order =
|
|
236
244
|
current_sort?.field == field ? current_sort.order : null;
|
|
237
|
-
const order =
|
|
245
|
+
const order =
|
|
246
|
+
current_order === "asc" // cycles the sort order: null → "asc" → "desc" → null → ...
|
|
247
|
+
? "desc"
|
|
248
|
+
: current_order === null
|
|
249
|
+
? "asc"
|
|
250
|
+
: null;
|
|
238
251
|
return /* HTML */ `<th>
|
|
239
252
|
<a href="${this.makeSortLink(ctx, field, order)}"
|
|
240
253
|
>${label}
|
|
@@ -67,7 +67,9 @@ export abstract class StatefulPage<
|
|
|
67
67
|
inputs: Record<string, string>
|
|
68
68
|
): Templatable | Promise<Templatable>;
|
|
69
69
|
|
|
70
|
-
async canAccess(
|
|
70
|
+
async canAccess(
|
|
71
|
+
_ctx: Context
|
|
72
|
+
): Promise<{ canAccess: boolean; message: string }> {
|
|
71
73
|
return <const>{ canAccess: true, message: "" };
|
|
72
74
|
}
|
|
73
75
|
|