@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,469 @@
|
|
|
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
|
+
|
|
6
|
+
// Helper function to ensure sealgen configuration exists
|
|
7
|
+
async function ensureSealgenConfig(test_app: RealAppTest): Promise<void> {
|
|
8
|
+
const packageJsonPath = path.join(test_app.app_path, "package.json");
|
|
9
|
+
let packageJsonContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
10
|
+
let packageJson = JSON.parse(packageJsonContent);
|
|
11
|
+
|
|
12
|
+
if (!packageJson.sealgen) {
|
|
13
|
+
packageJson.sealgen = {};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Helper function to create mock external module
|
|
20
|
+
async function createMockExternalModule(
|
|
21
|
+
test_app: RealAppTest,
|
|
22
|
+
moduleName: string,
|
|
23
|
+
subdirectory: string,
|
|
24
|
+
files: Array<{ name: string; content: string }>
|
|
25
|
+
): Promise<void> {
|
|
26
|
+
const externalModulePath = path.join(test_app.app_path, "node_modules", moduleName);
|
|
27
|
+
const targetPath = path.join(externalModulePath, subdirectory);
|
|
28
|
+
|
|
29
|
+
await fs.mkdir(targetPath, { recursive: true });
|
|
30
|
+
|
|
31
|
+
for (const file of files) {
|
|
32
|
+
await fs.writeFile(path.join(targetPath, file.name), file.content);
|
|
33
|
+
// If the file is a .ts controller, also create a .js file for build import
|
|
34
|
+
if (file.name.endsWith(".ts") && file.name.includes("stimulus")) {
|
|
35
|
+
const jsName = file.name.replace(/\.ts$/, ".js");
|
|
36
|
+
const exportName = file.name.replace(/\.stimulus\.ts$/, "");
|
|
37
|
+
await fs.writeFile(
|
|
38
|
+
path.join(targetPath, jsName),
|
|
39
|
+
`export default { connect() { console.log('Dummy JS for ${exportName}'); } }`
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
describe("register-external CLI commands", () => {
|
|
46
|
+
describe("package.json configuration", () => {
|
|
47
|
+
it("registers external controllers and verifies package.json is updated", async function () {
|
|
48
|
+
const test_app = await RealAppTest.init();
|
|
49
|
+
await ensureSealgenConfig(test_app);
|
|
50
|
+
|
|
51
|
+
const moduleName = "test-controller-module";
|
|
52
|
+
const subdirectory = "controllers";
|
|
53
|
+
|
|
54
|
+
await test_app.runSealgenCommand(
|
|
55
|
+
`register-external-controllers ${moduleName} ${subdirectory}`
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
// Verify package.json was updated correctly
|
|
59
|
+
const packageJsonPath = path.join(test_app.app_path, "package.json");
|
|
60
|
+
const packageJsonContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
61
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
62
|
+
|
|
63
|
+
assert(packageJson.sealgen, "sealgen configuration should exist");
|
|
64
|
+
assert(packageJson.sealgen.controllerDirs, "controllerDirs should exist");
|
|
65
|
+
assert(
|
|
66
|
+
Array.isArray(packageJson.sealgen.controllerDirs),
|
|
67
|
+
"controllerDirs should be an array"
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const expectedPath = `node_modules/${moduleName}/${subdirectory}`;
|
|
71
|
+
assert(
|
|
72
|
+
packageJson.sealgen.controllerDirs.includes(expectedPath),
|
|
73
|
+
`controllerDirs should contain ${expectedPath}`
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
await test_app.close();
|
|
77
|
+
}).timeout(100 * 1000);
|
|
78
|
+
|
|
79
|
+
it("registers external styles and verifies package.json is updated", async function () {
|
|
80
|
+
const test_app = await RealAppTest.init();
|
|
81
|
+
await ensureSealgenConfig(test_app);
|
|
82
|
+
|
|
83
|
+
const moduleName = "test-style-module";
|
|
84
|
+
const subdirectory = "styles";
|
|
85
|
+
|
|
86
|
+
await test_app.runSealgenCommand(
|
|
87
|
+
`register-external-styles ${moduleName} ${subdirectory}`
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
// Verify package.json was updated correctly
|
|
91
|
+
const packageJsonPath = path.join(test_app.app_path, "package.json");
|
|
92
|
+
const packageJsonContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
93
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
94
|
+
|
|
95
|
+
assert(packageJson.sealgen, "sealgen configuration should exist");
|
|
96
|
+
assert(packageJson.sealgen.styleDirs, "styleDirs should exist");
|
|
97
|
+
assert(Array.isArray(packageJson.sealgen.styleDirs), "styleDirs should be an array");
|
|
98
|
+
|
|
99
|
+
const expectedPath = `node_modules/${moduleName}/${subdirectory}`;
|
|
100
|
+
assert(
|
|
101
|
+
packageJson.sealgen.styleDirs.includes(expectedPath),
|
|
102
|
+
`styleDirs should contain ${expectedPath}`
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
await test_app.close();
|
|
106
|
+
}).timeout(100 * 1000);
|
|
107
|
+
|
|
108
|
+
it("registers both controllers and styles in the same project", async function () {
|
|
109
|
+
const test_app = await RealAppTest.init();
|
|
110
|
+
await ensureSealgenConfig(test_app);
|
|
111
|
+
|
|
112
|
+
const controllerModule = "test-controller-module";
|
|
113
|
+
const controllerSubdir = "controllers";
|
|
114
|
+
const styleModule = "test-style-module";
|
|
115
|
+
const styleSubdir = "styles";
|
|
116
|
+
|
|
117
|
+
await test_app.runSealgenCommand(
|
|
118
|
+
`register-external-controllers ${controllerModule} ${controllerSubdir}`
|
|
119
|
+
);
|
|
120
|
+
await test_app.runSealgenCommand(
|
|
121
|
+
`register-external-styles ${styleModule} ${styleSubdir}`
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
// Verify package.json was updated correctly for both
|
|
125
|
+
const packageJsonPath = path.join(test_app.app_path, "package.json");
|
|
126
|
+
const packageJsonContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
127
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
128
|
+
|
|
129
|
+
assert(packageJson.sealgen, "sealgen configuration should exist");
|
|
130
|
+
assert(packageJson.sealgen.controllerDirs, "controllerDirs should exist");
|
|
131
|
+
assert(packageJson.sealgen.styleDirs, "styleDirs should exist");
|
|
132
|
+
|
|
133
|
+
const expectedControllerPath = `node_modules/${controllerModule}/${controllerSubdir}`;
|
|
134
|
+
const expectedStylePath = `node_modules/${styleModule}/${styleSubdir}`;
|
|
135
|
+
|
|
136
|
+
assert(
|
|
137
|
+
packageJson.sealgen.controllerDirs.includes(expectedControllerPath),
|
|
138
|
+
`controllerDirs should contain ${expectedControllerPath}`
|
|
139
|
+
);
|
|
140
|
+
assert(
|
|
141
|
+
packageJson.sealgen.styleDirs.includes(expectedStylePath),
|
|
142
|
+
`styleDirs should contain ${expectedStylePath}`
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
await test_app.close();
|
|
146
|
+
}).timeout(100 * 1000);
|
|
147
|
+
|
|
148
|
+
it("handles duplicate registrations gracefully", async function () {
|
|
149
|
+
const test_app = await RealAppTest.init();
|
|
150
|
+
await ensureSealgenConfig(test_app);
|
|
151
|
+
|
|
152
|
+
const moduleName = "test-duplicate-module";
|
|
153
|
+
const subdirectory = "controllers";
|
|
154
|
+
|
|
155
|
+
// Register the same module twice
|
|
156
|
+
await test_app.runSealgenCommand(
|
|
157
|
+
`register-external-controllers ${moduleName} ${subdirectory}`
|
|
158
|
+
);
|
|
159
|
+
await test_app.runSealgenCommand(
|
|
160
|
+
`register-external-controllers ${moduleName} ${subdirectory}`
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// Verify package.json was updated correctly (should not have duplicates)
|
|
164
|
+
const packageJsonPath = path.join(test_app.app_path, "package.json");
|
|
165
|
+
const packageJsonContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
166
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
167
|
+
|
|
168
|
+
assert(packageJson.sealgen, "sealgen configuration should exist");
|
|
169
|
+
assert(packageJson.sealgen.controllerDirs, "controllerDirs should exist");
|
|
170
|
+
|
|
171
|
+
const expectedPath = `node_modules/${moduleName}/${subdirectory}`;
|
|
172
|
+
const controllerDirs = packageJson.sealgen.controllerDirs as string[];
|
|
173
|
+
|
|
174
|
+
// Should only appear once
|
|
175
|
+
const occurrences = controllerDirs.filter((dir) => dir === expectedPath).length;
|
|
176
|
+
assert(
|
|
177
|
+
occurrences === 1,
|
|
178
|
+
`controllerDirs should contain ${expectedPath} exactly once, found ${occurrences} times`
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
await test_app.close();
|
|
182
|
+
}).timeout(100 * 1000);
|
|
183
|
+
|
|
184
|
+
it("preserves existing sealgen configuration when adding new entries", async function () {
|
|
185
|
+
const test_app = await RealAppTest.init();
|
|
186
|
+
|
|
187
|
+
// First, manually add some existing configuration to package.json
|
|
188
|
+
const packageJsonPath = path.join(test_app.app_path, "package.json");
|
|
189
|
+
const packageJsonContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
190
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
191
|
+
|
|
192
|
+
// Add existing sealgen configuration
|
|
193
|
+
packageJson.sealgen = {
|
|
194
|
+
controllerDirs: ["node_modules/existing-controller/controllers"],
|
|
195
|
+
styleDirs: ["node_modules/existing-style/styles"],
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
199
|
+
|
|
200
|
+
// Now register new external modules
|
|
201
|
+
const newControllerModule = "new-controller-module";
|
|
202
|
+
const newStyleModule = "new-style-module";
|
|
203
|
+
|
|
204
|
+
await test_app.runSealgenCommand(
|
|
205
|
+
`register-external-controllers ${newControllerModule} controllers`
|
|
206
|
+
);
|
|
207
|
+
await test_app.runSealgenCommand(`register-external-styles ${newStyleModule} styles`);
|
|
208
|
+
|
|
209
|
+
// Verify both old and new configurations are preserved
|
|
210
|
+
const updatedPackageJsonContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
211
|
+
const updatedPackageJson = JSON.parse(updatedPackageJsonContent);
|
|
212
|
+
|
|
213
|
+
assert(updatedPackageJson.sealgen, "sealgen configuration should exist");
|
|
214
|
+
assert(updatedPackageJson.sealgen.controllerDirs, "controllerDirs should exist");
|
|
215
|
+
assert(updatedPackageJson.sealgen.styleDirs, "styleDirs should exist");
|
|
216
|
+
|
|
217
|
+
// Check that existing entries are preserved
|
|
218
|
+
assert(
|
|
219
|
+
updatedPackageJson.sealgen.controllerDirs.includes(
|
|
220
|
+
"node_modules/existing-controller/controllers"
|
|
221
|
+
),
|
|
222
|
+
"Existing controller directory should be preserved"
|
|
223
|
+
);
|
|
224
|
+
assert(
|
|
225
|
+
updatedPackageJson.sealgen.styleDirs.includes("node_modules/existing-style/styles"),
|
|
226
|
+
"Existing style directory should be preserved"
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
// Check that new entries are added
|
|
230
|
+
assert(
|
|
231
|
+
updatedPackageJson.sealgen.controllerDirs.includes(
|
|
232
|
+
`node_modules/${newControllerModule}/controllers`
|
|
233
|
+
),
|
|
234
|
+
"New controller directory should be added"
|
|
235
|
+
);
|
|
236
|
+
assert(
|
|
237
|
+
updatedPackageJson.sealgen.styleDirs.includes(
|
|
238
|
+
`node_modules/${newStyleModule}/styles`
|
|
239
|
+
),
|
|
240
|
+
"New style directory should be added"
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
await test_app.close();
|
|
244
|
+
}).timeout(100 * 1000);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
describe("build integration", () => {
|
|
248
|
+
it("registers external controllers and verifies they are included in build", async function () {
|
|
249
|
+
const test_app = await RealAppTest.init();
|
|
250
|
+
await ensureSealgenConfig(test_app);
|
|
251
|
+
|
|
252
|
+
// Create a mock external module with controllers
|
|
253
|
+
const externalModuleName = "test-external-controllers";
|
|
254
|
+
await createMockExternalModule(test_app, externalModuleName, "controllers", [
|
|
255
|
+
{
|
|
256
|
+
name: "test-external.stimulus.ts",
|
|
257
|
+
content: `
|
|
258
|
+
import { Controller } from "stimulus";
|
|
259
|
+
|
|
260
|
+
export default class TestExternalController extends Controller {
|
|
261
|
+
static targets = ["output"];
|
|
262
|
+
|
|
263
|
+
connect() {
|
|
264
|
+
console.log("External controller connected!");
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
`,
|
|
268
|
+
},
|
|
269
|
+
]);
|
|
270
|
+
|
|
271
|
+
// Register the external controllers
|
|
272
|
+
await test_app.runSealgenCommand(
|
|
273
|
+
`register-external-controllers ${externalModuleName} controllers`
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
// Run the build process
|
|
277
|
+
await test_app.runSealgenCommand("build");
|
|
278
|
+
|
|
279
|
+
// Verify the controllers are included in the build
|
|
280
|
+
const controllersFilePath = path.join(test_app.app_path, "src/front/controllers.ts");
|
|
281
|
+
const controllersContent = await fs.readFile(controllersFilePath, "utf-8");
|
|
282
|
+
|
|
283
|
+
// Check that the external controller is imported
|
|
284
|
+
assert(
|
|
285
|
+
controllersContent.includes(
|
|
286
|
+
`import { default as TestExternal } from "./../../node_modules/${externalModuleName}/controllers/test-external.stimulus.js"`
|
|
287
|
+
),
|
|
288
|
+
"External controller should be imported in generated controllers file"
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
// Check that the controller is registered
|
|
292
|
+
assert(
|
|
293
|
+
controllersContent.includes(`application.register("test-external", TestExternal);`),
|
|
294
|
+
"External controller should be registered in generated controllers file"
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
// Verify the build output exists
|
|
298
|
+
const bundlePath = path.join(test_app.app_path, "public/dist/bundle.js");
|
|
299
|
+
assert(
|
|
300
|
+
await fs
|
|
301
|
+
.stat(bundlePath)
|
|
302
|
+
.then(() => true)
|
|
303
|
+
.catch(() => false),
|
|
304
|
+
"Bundle should be generated"
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
await test_app.close();
|
|
308
|
+
}).timeout(100 * 1000);
|
|
309
|
+
|
|
310
|
+
it("registers external styles and verifies they are included in build", async function () {
|
|
311
|
+
const test_app = await RealAppTest.init();
|
|
312
|
+
await ensureSealgenConfig(test_app);
|
|
313
|
+
|
|
314
|
+
// Create a mock external module with styles
|
|
315
|
+
const externalModuleName = "test-external-styles";
|
|
316
|
+
await createMockExternalModule(test_app, externalModuleName, "styles", [
|
|
317
|
+
{
|
|
318
|
+
name: "external.css",
|
|
319
|
+
content: `
|
|
320
|
+
.external-style {
|
|
321
|
+
color: red;
|
|
322
|
+
background: blue;
|
|
323
|
+
}
|
|
324
|
+
`,
|
|
325
|
+
},
|
|
326
|
+
]);
|
|
327
|
+
|
|
328
|
+
// Register the external styles
|
|
329
|
+
await test_app.runSealgenCommand(
|
|
330
|
+
`register-external-styles ${externalModuleName} styles`
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
// Run the build process
|
|
334
|
+
await test_app.runSealgenCommand("build");
|
|
335
|
+
|
|
336
|
+
// Verify the styles are included in the build
|
|
337
|
+
const styleEntrypointPath = path.join(
|
|
338
|
+
test_app.app_path,
|
|
339
|
+
"src/style-entrypoints/default.entrypoint.css"
|
|
340
|
+
);
|
|
341
|
+
const styleEntrypointContent = await fs.readFile(styleEntrypointPath, "utf-8");
|
|
342
|
+
|
|
343
|
+
// Check that the external CSS is imported
|
|
344
|
+
assert(
|
|
345
|
+
styleEntrypointContent.includes(
|
|
346
|
+
`@import "../../node_modules/${externalModuleName}/styles/external.css"`
|
|
347
|
+
),
|
|
348
|
+
"External CSS should be imported in generated style entrypoint"
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
// Verify the CSS build output exists
|
|
352
|
+
const cssOutputPath = path.join(
|
|
353
|
+
test_app.app_path,
|
|
354
|
+
"public/dist/default.entrypoint.css"
|
|
355
|
+
);
|
|
356
|
+
assert(
|
|
357
|
+
await fs
|
|
358
|
+
.stat(cssOutputPath)
|
|
359
|
+
.then(() => true)
|
|
360
|
+
.catch(() => false),
|
|
361
|
+
"CSS should be generated"
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
await test_app.close();
|
|
365
|
+
}).timeout(100 * 1000);
|
|
366
|
+
|
|
367
|
+
it("registers both external controllers and styles and verifies complete build integration", async function () {
|
|
368
|
+
const test_app = await RealAppTest.init();
|
|
369
|
+
await ensureSealgenConfig(test_app);
|
|
370
|
+
|
|
371
|
+
// Create mock external modules
|
|
372
|
+
const controllerModuleName = "test-external-controllers";
|
|
373
|
+
const styleModuleName = "test-external-styles";
|
|
374
|
+
|
|
375
|
+
// Create controller module
|
|
376
|
+
await createMockExternalModule(test_app, controllerModuleName, "controllers", [
|
|
377
|
+
{
|
|
378
|
+
name: "combined-test.stimulus.ts",
|
|
379
|
+
content: `
|
|
380
|
+
import { Controller } from "stimulus";
|
|
381
|
+
|
|
382
|
+
export default class CombinedTestController extends Controller {
|
|
383
|
+
static targets = ["output"];
|
|
384
|
+
|
|
385
|
+
connect() {
|
|
386
|
+
console.log("Combined test controller connected!");
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
`,
|
|
390
|
+
},
|
|
391
|
+
]);
|
|
392
|
+
|
|
393
|
+
// Create style module
|
|
394
|
+
await createMockExternalModule(test_app, styleModuleName, "styles", [
|
|
395
|
+
{
|
|
396
|
+
name: "combined-external.css",
|
|
397
|
+
content: `
|
|
398
|
+
.combined-external-style {
|
|
399
|
+
color: green;
|
|
400
|
+
background: yellow;
|
|
401
|
+
}
|
|
402
|
+
`,
|
|
403
|
+
},
|
|
404
|
+
]);
|
|
405
|
+
|
|
406
|
+
// Register both external modules
|
|
407
|
+
await test_app.runSealgenCommand(
|
|
408
|
+
`register-external-controllers ${controllerModuleName} controllers`
|
|
409
|
+
);
|
|
410
|
+
await test_app.runSealgenCommand(`register-external-styles ${styleModuleName} styles`);
|
|
411
|
+
|
|
412
|
+
// Run the build process
|
|
413
|
+
await test_app.runSealgenCommand("build");
|
|
414
|
+
|
|
415
|
+
// Verify controllers are included
|
|
416
|
+
const controllersFilePath = path.join(test_app.app_path, "src/front/controllers.ts");
|
|
417
|
+
const controllersContent = await fs.readFile(controllersFilePath, "utf-8");
|
|
418
|
+
|
|
419
|
+
assert(
|
|
420
|
+
controllersContent.includes(
|
|
421
|
+
`import { default as CombinedTest } from "./../../node_modules/${controllerModuleName}/controllers/combined-test.stimulus.js"`
|
|
422
|
+
),
|
|
423
|
+
"Combined test controller should be imported"
|
|
424
|
+
);
|
|
425
|
+
assert(
|
|
426
|
+
controllersContent.includes(`application.register("combined-test", CombinedTest);`),
|
|
427
|
+
"Combined test controller should be registered"
|
|
428
|
+
);
|
|
429
|
+
|
|
430
|
+
// Verify styles are included
|
|
431
|
+
const styleEntrypointPath = path.join(
|
|
432
|
+
test_app.app_path,
|
|
433
|
+
"src/style-entrypoints/default.entrypoint.css"
|
|
434
|
+
);
|
|
435
|
+
const styleEntrypointContent = await fs.readFile(styleEntrypointPath, "utf-8");
|
|
436
|
+
|
|
437
|
+
assert(
|
|
438
|
+
styleEntrypointContent.includes(
|
|
439
|
+
`@import "../../node_modules/${styleModuleName}/styles/combined-external.css"`
|
|
440
|
+
),
|
|
441
|
+
"Combined external CSS should be imported"
|
|
442
|
+
);
|
|
443
|
+
|
|
444
|
+
// Verify build outputs exist
|
|
445
|
+
const bundlePath = path.join(test_app.app_path, "public/dist/bundle.js");
|
|
446
|
+
const cssOutputPath = path.join(
|
|
447
|
+
test_app.app_path,
|
|
448
|
+
"public/dist/default.entrypoint.css"
|
|
449
|
+
);
|
|
450
|
+
|
|
451
|
+
assert(
|
|
452
|
+
await fs
|
|
453
|
+
.stat(bundlePath)
|
|
454
|
+
.then(() => true)
|
|
455
|
+
.catch(() => false),
|
|
456
|
+
"Bundle should be generated"
|
|
457
|
+
);
|
|
458
|
+
assert(
|
|
459
|
+
await fs
|
|
460
|
+
.stat(cssOutputPath)
|
|
461
|
+
.then(() => true)
|
|
462
|
+
.catch(() => false),
|
|
463
|
+
"CSS should be generated"
|
|
464
|
+
);
|
|
465
|
+
|
|
466
|
+
await test_app.close();
|
|
467
|
+
}).timeout(100 * 1000);
|
|
468
|
+
});
|
|
469
|
+
});
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { promises as fs, existsSync, readFileSync } from "fs";
|
|
2
|
+
import { resolve, dirname } from "path";
|
|
3
|
+
|
|
4
|
+
import { formatWithPrettier } from "./utils/prettier.js";
|
|
5
|
+
|
|
6
|
+
interface PackageJson {
|
|
7
|
+
sealgen?: {
|
|
8
|
+
controllerDirs?: string[];
|
|
9
|
+
styleDirs?: string[];
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
};
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function findParentProjectWithSealgen(): string {
|
|
16
|
+
let currentDir = process.cwd();
|
|
17
|
+
|
|
18
|
+
while (currentDir !== dirname(currentDir)) {
|
|
19
|
+
const packageJsonPath = resolve(currentDir, "package.json");
|
|
20
|
+
|
|
21
|
+
if (existsSync(packageJsonPath)) {
|
|
22
|
+
try {
|
|
23
|
+
const packageJsonContent = readFileSync(
|
|
24
|
+
packageJsonPath,
|
|
25
|
+
"utf-8"
|
|
26
|
+
);
|
|
27
|
+
const packageJson = JSON.parse(
|
|
28
|
+
packageJsonContent
|
|
29
|
+
) as PackageJson;
|
|
30
|
+
|
|
31
|
+
// Check if this package.json has a sealgen configuration
|
|
32
|
+
if (packageJson.sealgen) {
|
|
33
|
+
return currentDir;
|
|
34
|
+
}
|
|
35
|
+
} catch (error) {
|
|
36
|
+
// If we can't read or parse the package.json, continue to parent
|
|
37
|
+
console.warn(
|
|
38
|
+
`Warning: Could not read package.json at ${packageJsonPath}:`,
|
|
39
|
+
error
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
currentDir = dirname(currentDir);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
throw new Error(
|
|
48
|
+
"Could not find a parent project with sealgen configuration"
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function updatePackageJson(
|
|
53
|
+
projectDir: string,
|
|
54
|
+
moduleName: string,
|
|
55
|
+
subdirectory: string,
|
|
56
|
+
type: "controllerDirs" | "styleDirs"
|
|
57
|
+
): Promise<void> {
|
|
58
|
+
const packageJsonPath = resolve(projectDir, "package.json");
|
|
59
|
+
const packageJsonContent = await fs.readFile(packageJsonPath, "utf-8");
|
|
60
|
+
const packageJson = JSON.parse(packageJsonContent) as PackageJson;
|
|
61
|
+
|
|
62
|
+
// Initialize sealgen configuration if it doesn't exist
|
|
63
|
+
if (!packageJson.sealgen) {
|
|
64
|
+
packageJson.sealgen = {};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Initialize the specific array if it doesn't exist
|
|
68
|
+
if (!packageJson.sealgen[type]) {
|
|
69
|
+
packageJson.sealgen[type] = [];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const pathToAdd = `node_modules/${moduleName}/${subdirectory}`;
|
|
73
|
+
const existingPaths = packageJson.sealgen[type] as string[];
|
|
74
|
+
|
|
75
|
+
// Check if the path is already present
|
|
76
|
+
if (existingPaths.includes(pathToAdd)) {
|
|
77
|
+
console.log(`${type} already contains: ${pathToAdd}`);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Add the new path
|
|
82
|
+
existingPaths.push(pathToAdd);
|
|
83
|
+
|
|
84
|
+
// Write back the updated package.json with proper formatting
|
|
85
|
+
const updatedContent = await formatWithPrettier(
|
|
86
|
+
JSON.stringify(packageJson, null, 2),
|
|
87
|
+
"json"
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
await fs.writeFile(packageJsonPath, updatedContent);
|
|
91
|
+
console.log(`Added ${pathToAdd} to ${type} in ${packageJsonPath}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export async function registerExternalControllers(
|
|
95
|
+
args: Record<string, string | boolean>
|
|
96
|
+
): Promise<void> {
|
|
97
|
+
// Extract positional arguments from process.argv since yargs doesn't handle them for these commands
|
|
98
|
+
const moduleName = process.argv.at(3);
|
|
99
|
+
const subdirectory = process.argv.at(4);
|
|
100
|
+
|
|
101
|
+
if (!moduleName || !subdirectory) {
|
|
102
|
+
console.error(
|
|
103
|
+
"Usage: npx sealgen register-external-controllers <module-name> <subdirectory>"
|
|
104
|
+
);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
const projectDir = findParentProjectWithSealgen();
|
|
110
|
+
await updatePackageJson(
|
|
111
|
+
projectDir,
|
|
112
|
+
moduleName,
|
|
113
|
+
subdirectory,
|
|
114
|
+
"controllerDirs"
|
|
115
|
+
);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export async function registerExternalStyles(
|
|
123
|
+
args: Record<string, string | boolean>
|
|
124
|
+
): Promise<void> {
|
|
125
|
+
// Extract positional arguments from process.argv since yargs doesn't handle them for these commands
|
|
126
|
+
const moduleName = process.argv.at(3);
|
|
127
|
+
const subdirectory = process.argv.at(4);
|
|
128
|
+
|
|
129
|
+
if (!moduleName || !subdirectory) {
|
|
130
|
+
console.error(
|
|
131
|
+
"Usage: npx sealgen register-external-styles <module-name> <subdirectory>"
|
|
132
|
+
);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
const projectDir = findParentProjectWithSealgen();
|
|
138
|
+
await updatePackageJson(
|
|
139
|
+
projectDir,
|
|
140
|
+
moduleName,
|
|
141
|
+
subdirectory,
|
|
142
|
+
"styleDirs"
|
|
143
|
+
);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -61,6 +61,11 @@ export type FieldHandler<
|
|
|
61
61
|
field: ExtractedFieldInfo,
|
|
62
62
|
importPath: (path: string) => string,
|
|
63
63
|
defaults: Defaults,
|
|
64
|
+
all_other_handlers: Record<
|
|
65
|
+
string,
|
|
66
|
+
| FieldHandler<FieldHandlerResult, Partial<FieldHandlerResult>>
|
|
67
|
+
| undefined
|
|
68
|
+
>,
|
|
64
69
|
fields_var?: string
|
|
65
70
|
) => Promise<Result>;
|
|
66
71
|
|
|
@@ -95,8 +100,10 @@ export async function getFieldHandler(
|
|
|
95
100
|
field,
|
|
96
101
|
importPath,
|
|
97
102
|
{},
|
|
103
|
+
field_handlers,
|
|
98
104
|
fields_var
|
|
99
105
|
);
|
|
106
|
+
|
|
100
107
|
const result = {
|
|
101
108
|
...defaults,
|
|
102
109
|
...((await field_handlers[field.type]?.(
|
|
@@ -104,6 +111,7 @@ export async function getFieldHandler(
|
|
|
104
111
|
field,
|
|
105
112
|
importPath,
|
|
106
113
|
defaults,
|
|
114
|
+
field_handlers,
|
|
107
115
|
fields_var
|
|
108
116
|
)) || {}),
|
|
109
117
|
};
|
|
@@ -30,7 +30,7 @@ export default async function extract_fields_from_collection(
|
|
|
30
30
|
const c = new the_app().collections["${collection_name}"];
|
|
31
31
|
const fields = [];
|
|
32
32
|
for (const field_name in c.fields){
|
|
33
|
-
|
|
33
|
+
let field = c.fields[field_name];
|
|
34
34
|
let type = field.typeName;
|
|
35
35
|
let target = null;
|
|
36
36
|
let referencing_collection = null;
|
|
@@ -39,7 +39,7 @@ for (const field_name in c.fields){
|
|
|
39
39
|
let is_readonly = false;
|
|
40
40
|
let is_required = field.required;
|
|
41
41
|
let subfields = [];
|
|
42
|
-
if(["derived-value", "cached-value"].includes(type)){
|
|
42
|
+
if(["derived-value", "cached-value", "settable-by"].includes(type)){
|
|
43
43
|
type = field.virtual_field.typeName;
|
|
44
44
|
}
|
|
45
45
|
if(["derived-value", "cached-value", "reverse-single-reference"].includes(field.typeName)){
|
|
@@ -52,7 +52,7 @@ for (const field_name in c.fields){
|
|
|
52
52
|
intermediary_field_that_points_there = field.intermediary_field_that_points_there
|
|
53
53
|
}
|
|
54
54
|
if( type == "structured-array" ) {
|
|
55
|
-
subfields = Object.keys(field.subfields).map(key=>({name: key}));
|
|
55
|
+
subfields = Object.keys(field.subfields || field.virtual_field.subfields).map(key=>({name: key}));
|
|
56
56
|
}
|
|
57
57
|
fields.push({ name: field_name, type, target, referencing_collection, referencing_field, intermediary_field_that_points_there, is_readonly, is_required, subfields })
|
|
58
58
|
}
|