@ostack.tech/ui-kform-scaffolder 0.1.0
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/README.md +3 -0
- package/bin/at-ui-kform-scaffolder +3 -0
- package/dist/ostack-ui-kform-scaffolder.cjs +1754 -0
- package/dist/ostack-ui-kform-scaffolder.cjs.map +1 -0
- package/dist/ostack-ui-kform-scaffolder.css +199 -0
- package/dist/ostack-ui-kform-scaffolder.js +1737 -0
- package/dist/ostack-ui-kform-scaffolder.js.map +1 -0
- package/dist/types/SchematicBuilder.d.ts +6 -0
- package/dist/types/SchematicKind.d.ts +37 -0
- package/dist/types/configs/SerializationFormatConfig.d.ts +6 -0
- package/dist/types/configs/UseTableValuesSerializerConfig.d.ts +4 -0
- package/dist/types/index.d.ts +24 -0
- package/dist/types/main.d.ts +1 -0
- package/dist/types/scaffolding/ScaffoldingData.d.ts +7 -0
- package/dist/types/scaffolding/kotlin/KtData.d.ts +4 -0
- package/dist/types/scaffolding/reactApp/ReactAppData.d.ts +6 -0
- package/dist/types/scaffolding/reactApp/util/reactAppLayout.d.ts +12 -0
- package/dist/types/scaffolding/scaffolders/scaffoldActions.d.ts +3 -0
- package/dist/types/scaffolding/scaffolders/scaffoldApi.d.ts +3 -0
- package/dist/types/scaffolding/scaffolders/scaffoldAppComponent.d.ts +6 -0
- package/dist/types/scaffolding/scaffolders/scaffoldAppContext.d.ts +3 -0
- package/dist/types/scaffolding/scaffolders/scaffoldExternalContexts.d.ts +3 -0
- package/dist/types/scaffolding/scaffolders/scaffoldFormPages.d.ts +4 -0
- package/dist/types/scaffolding/scaffolders/scaffoldGradleProject.d.ts +3 -0
- package/dist/types/scaffolding/scaffolders/scaffoldGradleWrapper.d.ts +3 -0
- package/dist/types/scaffolding/scaffolders/scaffoldIssueMessages.d.ts +3 -0
- package/dist/types/scaffolding/scaffolders/scaffoldMain.d.ts +4 -0
- package/dist/types/scaffolding/scaffolders/scaffoldProjectMisc.d.ts +3 -0
- package/dist/types/scaffolding/scaffolders/scaffoldResponses.d.ts +3 -0
- package/dist/types/scaffolding/scaffolders/scaffoldSerializer.d.ts +3 -0
- package/dist/types/scaffolding/scaffolders/scaffoldStyles.d.ts +3 -0
- package/dist/types/scaffolding/scaffolders/scaffoldViteProject.d.ts +3 -0
- package/dist/types/scaffolding/templates/react-app/src/api/reportError.d.ts +1 -0
- package/dist/types/util/arrayify.d.ts +1 -0
- package/dist/webapp/assets/index-A9c6aN_V.js +1598 -0
- package/dist/webapp/assets/index-rLmIK8TT.css +1 -0
- package/dist/webapp/index.html +14 -0
- package/package.json +53 -0
|
@@ -0,0 +1,1754 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const kformScaffolder = require("@ostack.tech/kform-scaffolder");
|
|
5
|
+
const React = require("react");
|
|
6
|
+
function _interopNamespaceDefault(e) {
|
|
7
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
8
|
+
if (e) {
|
|
9
|
+
for (const k in e) {
|
|
10
|
+
if (k !== "default") {
|
|
11
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
12
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: () => e[k]
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
n.default = e;
|
|
20
|
+
return Object.freeze(n);
|
|
21
|
+
}
|
|
22
|
+
const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
|
|
23
|
+
function SerializationFormatConfig({
|
|
24
|
+
defaultValue = "json",
|
|
25
|
+
disabled
|
|
26
|
+
}) {
|
|
27
|
+
const [useTableValuesSerializerConfig, setUseTableValuesSerializerConfig] = kformScaffolder.useConfig("useTableValuesSerializer", false);
|
|
28
|
+
const lastUseTableValuesSerializerConfig = React__namespace.useRef(
|
|
29
|
+
useTableValuesSerializerConfig
|
|
30
|
+
);
|
|
31
|
+
const [config, setConfig] = kformScaffolder.useConfig("serializationFormat", defaultValue);
|
|
32
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "builder-config-field", children: [
|
|
33
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { children: "Serialization format" }),
|
|
34
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
35
|
+
"select",
|
|
36
|
+
{
|
|
37
|
+
value: config,
|
|
38
|
+
onChange: (evt) => {
|
|
39
|
+
setConfig(evt.target.value);
|
|
40
|
+
if (evt.target.value === "xml") {
|
|
41
|
+
lastUseTableValuesSerializerConfig.current = useTableValuesSerializerConfig;
|
|
42
|
+
setUseTableValuesSerializerConfig(true);
|
|
43
|
+
} else {
|
|
44
|
+
setUseTableValuesSerializerConfig(
|
|
45
|
+
lastUseTableValuesSerializerConfig.current
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
disabled,
|
|
50
|
+
children: [
|
|
51
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "json", children: "JSON" }),
|
|
52
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "xml", children: "XML" })
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
)
|
|
56
|
+
] });
|
|
57
|
+
}
|
|
58
|
+
function UseTableValuesSerializerConfig({
|
|
59
|
+
disabled
|
|
60
|
+
}) {
|
|
61
|
+
const [serializationFormatConfig] = kformScaffolder.useConfig("serializationFormat", "json");
|
|
62
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
63
|
+
kformScaffolder.UseTableValuesSerializerConfig,
|
|
64
|
+
{
|
|
65
|
+
disabled: disabled || serializationFormatConfig === "xml"
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
const SPLIT_LOWER_UPPER_RE = new RegExp("([\\p{Ll}\\d])(\\p{Lu})", "gu");
|
|
70
|
+
const SPLIT_UPPER_UPPER_RE = new RegExp("(\\p{Lu})([\\p{Lu}][\\p{Ll}])", "gu");
|
|
71
|
+
const SPLIT_SEPARATE_NUMBER_RE = new RegExp("(\\d)\\p{Ll}|(\\p{L})\\d", "u");
|
|
72
|
+
const DEFAULT_STRIP_REGEXP = /[^\p{L}\d]+/giu;
|
|
73
|
+
const SPLIT_REPLACE_VALUE = "$1\0$2";
|
|
74
|
+
const DEFAULT_PREFIX_SUFFIX_CHARACTERS = "";
|
|
75
|
+
function split(value) {
|
|
76
|
+
let result = value.trim();
|
|
77
|
+
result = result.replace(SPLIT_LOWER_UPPER_RE, SPLIT_REPLACE_VALUE).replace(SPLIT_UPPER_UPPER_RE, SPLIT_REPLACE_VALUE);
|
|
78
|
+
result = result.replace(DEFAULT_STRIP_REGEXP, "\0");
|
|
79
|
+
let start = 0;
|
|
80
|
+
let end = result.length;
|
|
81
|
+
while (result.charAt(start) === "\0")
|
|
82
|
+
start++;
|
|
83
|
+
if (start === end)
|
|
84
|
+
return [];
|
|
85
|
+
while (result.charAt(end - 1) === "\0")
|
|
86
|
+
end--;
|
|
87
|
+
return result.slice(start, end).split(/\0/g);
|
|
88
|
+
}
|
|
89
|
+
function splitSeparateNumbers(value) {
|
|
90
|
+
const words = split(value);
|
|
91
|
+
for (let i = 0; i < words.length; i++) {
|
|
92
|
+
const word = words[i];
|
|
93
|
+
const match = SPLIT_SEPARATE_NUMBER_RE.exec(word);
|
|
94
|
+
if (match) {
|
|
95
|
+
const offset = match.index + (match[1] ?? match[2]).length;
|
|
96
|
+
words.splice(i, 1, word.slice(0, offset), word.slice(offset));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return words;
|
|
100
|
+
}
|
|
101
|
+
function noCase(input, options) {
|
|
102
|
+
const [prefix, words, suffix] = splitPrefixSuffix(input, options);
|
|
103
|
+
return prefix + words.map(lowerFactory(options?.locale)).join(options?.delimiter ?? " ") + suffix;
|
|
104
|
+
}
|
|
105
|
+
function camelCase(input, options) {
|
|
106
|
+
const [prefix, words, suffix] = splitPrefixSuffix(input, options);
|
|
107
|
+
const lower = lowerFactory(options?.locale);
|
|
108
|
+
const upper = upperFactory(options?.locale);
|
|
109
|
+
const transform = pascalCaseTransformFactory(lower, upper);
|
|
110
|
+
return prefix + words.map((word, index) => {
|
|
111
|
+
if (index === 0)
|
|
112
|
+
return lower(word);
|
|
113
|
+
return transform(word, index);
|
|
114
|
+
}).join("") + suffix;
|
|
115
|
+
}
|
|
116
|
+
function pascalCase(input, options) {
|
|
117
|
+
const [prefix, words, suffix] = splitPrefixSuffix(input, options);
|
|
118
|
+
const lower = lowerFactory(options?.locale);
|
|
119
|
+
const upper = upperFactory(options?.locale);
|
|
120
|
+
const transform = pascalCaseTransformFactory(lower, upper);
|
|
121
|
+
return prefix + words.map(transform).join("") + suffix;
|
|
122
|
+
}
|
|
123
|
+
function capitalCase(input, options) {
|
|
124
|
+
const [prefix, words, suffix] = splitPrefixSuffix(input, options);
|
|
125
|
+
const lower = lowerFactory(options?.locale);
|
|
126
|
+
const upper = upperFactory(options?.locale);
|
|
127
|
+
return prefix + words.map(capitalCaseTransformFactory(lower, upper)).join(" ") + suffix;
|
|
128
|
+
}
|
|
129
|
+
function constantCase(input, options) {
|
|
130
|
+
const [prefix, words, suffix] = splitPrefixSuffix(input, options);
|
|
131
|
+
return prefix + words.map(upperFactory(options?.locale)).join("_") + suffix;
|
|
132
|
+
}
|
|
133
|
+
function kebabCase(input, options) {
|
|
134
|
+
return noCase(input, { delimiter: "-", ...options });
|
|
135
|
+
}
|
|
136
|
+
function sentenceCase(input, options) {
|
|
137
|
+
const [prefix, words, suffix] = splitPrefixSuffix(input, options);
|
|
138
|
+
const lower = lowerFactory(options?.locale);
|
|
139
|
+
const upper = upperFactory(options?.locale);
|
|
140
|
+
const transform = capitalCaseTransformFactory(lower, upper);
|
|
141
|
+
return prefix + words.map((word, index) => {
|
|
142
|
+
if (index === 0)
|
|
143
|
+
return transform(word);
|
|
144
|
+
return lower(word);
|
|
145
|
+
}).join(" ") + suffix;
|
|
146
|
+
}
|
|
147
|
+
function lowerFactory(locale) {
|
|
148
|
+
return locale === false ? (input) => input.toLowerCase() : (input) => input.toLocaleLowerCase(locale);
|
|
149
|
+
}
|
|
150
|
+
function upperFactory(locale) {
|
|
151
|
+
return (input) => input.toLocaleUpperCase(locale);
|
|
152
|
+
}
|
|
153
|
+
function capitalCaseTransformFactory(lower, upper) {
|
|
154
|
+
return (word) => `${upper(word[0])}${lower(word.slice(1))}`;
|
|
155
|
+
}
|
|
156
|
+
function pascalCaseTransformFactory(lower, upper) {
|
|
157
|
+
return (word, index) => {
|
|
158
|
+
const char0 = word[0];
|
|
159
|
+
const initial = index > 0 && char0 >= "0" && char0 <= "9" ? "_" + char0 : upper(char0);
|
|
160
|
+
return initial + lower(word.slice(1));
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function splitPrefixSuffix(input, options = {}) {
|
|
164
|
+
const splitFn = options.split ?? (options.separateNumbers ? splitSeparateNumbers : split);
|
|
165
|
+
const prefixCharacters = options.prefixCharacters ?? DEFAULT_PREFIX_SUFFIX_CHARACTERS;
|
|
166
|
+
const suffixCharacters = options.suffixCharacters ?? DEFAULT_PREFIX_SUFFIX_CHARACTERS;
|
|
167
|
+
let prefixIndex = 0;
|
|
168
|
+
let suffixIndex = input.length;
|
|
169
|
+
while (prefixIndex < input.length) {
|
|
170
|
+
const char = input.charAt(prefixIndex);
|
|
171
|
+
if (!prefixCharacters.includes(char))
|
|
172
|
+
break;
|
|
173
|
+
prefixIndex++;
|
|
174
|
+
}
|
|
175
|
+
while (suffixIndex > prefixIndex) {
|
|
176
|
+
const index = suffixIndex - 1;
|
|
177
|
+
const char = input.charAt(index);
|
|
178
|
+
if (!suffixCharacters.includes(char))
|
|
179
|
+
break;
|
|
180
|
+
suffixIndex = index;
|
|
181
|
+
}
|
|
182
|
+
return [
|
|
183
|
+
input.slice(0, prefixIndex),
|
|
184
|
+
splitFn(input.slice(prefixIndex, suffixIndex)),
|
|
185
|
+
input.slice(suffixIndex)
|
|
186
|
+
];
|
|
187
|
+
}
|
|
188
|
+
const loadTsxEjs = 'import { LoadAction } from "@ostack.tech/ui-kform";\nimport { decode<%= formClass %>FromString, <%= formClass %>FormMode } from "<%= kmpModuleName %>";\nimport { use<%= formClass %>Context } from "../<%= formClass %>Context.ts";\n\nexport function Load() {\n const { externalContexts } = use<%= formClass %>Context();\n\n return (\n externalContexts.mode !== <%= formClass %>FormMode.READ && (\n <LoadAction\n decode={async (file) => decode<%= formClass %>FromString(await file.text())}\n mimeTypes={["<%= serializationMimeType %>"]}\n extensions={[".<%= serializationFormat %>"]}\n />\n )\n );\n}\n';
|
|
189
|
+
const saveTsxEjs = 'import { SaveAction } from "@ostack.tech/ui-kform";\nimport { format } from "date-fns";\nimport { type <%= formClass %>, encode<%= formClass %>ToString, <%= formClass %>FormMode } from "<%= kmpModuleName %>";\nimport { use<%= formClass %>Context } from "../<%= formClass %>Context.ts";\n\nexport function Save() {\n const { externalContexts } = use<%= formClass %>Context();\n\n return (\n <SaveAction\n encode={(<%= formVar %>: <%= formClass %>) => encode<%= formClass %>ToString(<%= formVar %>, true)}\n disableOverwrite={externalContexts.mode === <%= formClass %>FormMode.READ}\n fileName={() => `<%= formTitle %> ${format(new Date(), "yyyy-MM-dd")}.<%= serializationFormat %>`}\n mimeTypes={["<%= serializationMimeType %>"]}\n extensions={[".<%= serializationFormat %>"]}\n />\n );\n}\n';
|
|
190
|
+
const submitTsxEjs = 'import { LocatedValidationWarning } from "@ostack.tech/kform";\nimport { SubmitAction } from "@ostack.tech/ui-kform";\nimport {\n type <%= formClass %>,\n <%= formClass %>FormMode,\n <%= formClass %>SubmitSuccess,\n <%= formClass %>SubmitValidationError,\n <%= formClass %>SubmitError,\n} from "<%= kmpModuleName %>";\nimport { use<%= formClass %>Context } from "../<%= formClass %>Context.ts";\nimport { submit } from "../api/submit.ts";\n\nexport function Submit() {\n const { externalContexts } = use<%= formClass %>Context();\n\n const handleSubmit = async (\n <%= formVar %>: <%= formClass %>,\n acceptedWarnings?: LocatedValidationWarning[],\n ) => {\n const response = await submit(<%= formVar %>, acceptedWarnings);\n if (response instanceof <%= formClass %>SubmitSuccess) {\n return response.redirectTo;\n } else if (response instanceof <%= formClass %>SubmitValidationError) {\n return response.issues;\n } else {\n throw response as <%= formClass %>SubmitError;\n }\n };\n\n const handleSuccessfulSubmit = (redirectTo: string) => {\n window.location.href = redirectTo;\n };\n\n return (\n externalContexts.mode !== <%= formClass %>FormMode.READ && (\n <SubmitAction\n onSubmit={handleSubmit}\n onSuccessfulSubmit={handleSuccessfulSubmit}\n <%_ if (useTableValuesSerializer) { -%>\n convertExternalIssuesTableRowIndicesToIds\n <%_ } -%>\n />\n )\n );\n}\n';
|
|
191
|
+
const validateTsxEjs = 'import { ValidateAction } from "@ostack.tech/ui-kform";\nimport { <%= formClass %>FormMode } from "<%= kmpModuleName %>";\nimport { use<%= formClass %>Context } from "../<%= formClass %>Context.ts";\n\nexport function Validate() {\n const { externalContexts } = use<%= formClass %>Context();\n\n return externalContexts.mode !== <%= formClass %>FormMode.READ && <ValidateAction />;\n}\n';
|
|
192
|
+
function scaffoldActions(schematic, data) {
|
|
193
|
+
const ejsData = {
|
|
194
|
+
kmpModuleName: data.kmpModuleName ?? `${kebabCase(schematic.name)}-shared`,
|
|
195
|
+
serializationFormat: data.serializationFormat ?? "json",
|
|
196
|
+
serializationMimeType: `application/${data.serializationFormat}`,
|
|
197
|
+
formVar: camelCase(schematic.name),
|
|
198
|
+
formClass: schematic.name,
|
|
199
|
+
formTitle: capitalCase(schematic.name),
|
|
200
|
+
useTableValuesSerializer: data.useTableValuesSerializer
|
|
201
|
+
};
|
|
202
|
+
kformScaffolder.addEjsTemplateFile(data, "actions/Load.tsx", loadTsxEjs, ejsData);
|
|
203
|
+
kformScaffolder.addEjsTemplateFile(data, "actions/Save.tsx", saveTsxEjs, ejsData);
|
|
204
|
+
kformScaffolder.addEjsTemplateFile(data, "actions/Submit.tsx", submitTsxEjs, ejsData);
|
|
205
|
+
kformScaffolder.addEjsTemplateFile(data, "actions/Validate.tsx", validateTsxEjs, ejsData);
|
|
206
|
+
}
|
|
207
|
+
const reportErrorTs = 'export const REPORT_ERROR_ENDPOINT = "/api/report-error";\n';
|
|
208
|
+
const submitTsEjs = 'import { LocatedValidationWarning } from "@ostack.tech/kform";\nimport {\n decode<%= formClass %>SubmitResponseFromString,\n encode<%= formClass %>ToString,\n <%= formClass %>,\n} from "<%= kmpModuleName %>";\n\nexport const SUBMIT_ENDPOINT = "/api/submit";\n\nexport async function submit(\n <%= formVar %>: <%= formClass %>,\n acceptedWarnings?: LocatedValidationWarning[],\n) {\n const params = new URLSearchParams();\n if (acceptedWarnings?.length) {\n const acceptedWarningCodes = new Set(acceptedWarnings.map((w) => w.code));\n params.set("acceptedWarnings", Array.from(acceptedWarningCodes).join());\n }\n\n const res = await fetch(`${SUBMIT_ENDPOINT}?${params}`, {\n method: "POST",\n headers: { "Content-Type": "<%= serializationMimeType %>" },\n body: encode<%= formClass %>ToString(<%= formVar %>, import.meta.env.DEV),\n });\n return decode<%= formClass %>SubmitResponseFromString(await res.text());\n}\n';
|
|
209
|
+
function scaffoldApi(schematic, data) {
|
|
210
|
+
const ejsData = {
|
|
211
|
+
kmpModuleName: data.kmpModuleName ?? `${kebabCase(schematic.name)}-shared`,
|
|
212
|
+
serializationFormat: data.serializationFormat ?? "json",
|
|
213
|
+
serializationMimeType: `application/${data.serializationFormat}`,
|
|
214
|
+
formVar: camelCase(schematic.name),
|
|
215
|
+
formClass: schematic.name
|
|
216
|
+
};
|
|
217
|
+
kformScaffolder.addTemplateFile(data, "api/reportError.ts", reportErrorTs);
|
|
218
|
+
kformScaffolder.addEjsTemplateFile(data, "api/submit.ts", submitTsEjs, ejsData);
|
|
219
|
+
}
|
|
220
|
+
function scaffoldIssueMessages(schematic, data) {
|
|
221
|
+
const fileName = kformScaffolder.joinPaths(
|
|
222
|
+
data.currentDir,
|
|
223
|
+
`${schematic.name}IssueMessages.tsx`
|
|
224
|
+
);
|
|
225
|
+
let file = data.files.get(fileName);
|
|
226
|
+
if (!file) {
|
|
227
|
+
data.files.set(fileName, file = kformScaffolder.tsFile());
|
|
228
|
+
}
|
|
229
|
+
scaffoldIssueMessagesConstant(schematic, {
|
|
230
|
+
kmpModuleName: `${kebabCase(data.rootSchematic.name)}-shared`,
|
|
231
|
+
...data,
|
|
232
|
+
currentFile: file
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
function scaffoldIssueMessagesConstant(schematic, data) {
|
|
236
|
+
data.currentFile.imports.push({
|
|
237
|
+
moduleName: "@ostack.tech/ui-kform",
|
|
238
|
+
name: "IssueMessagesByCode",
|
|
239
|
+
isType: true
|
|
240
|
+
});
|
|
241
|
+
data.currentFile.declarations.push(kformScaffolder.code`
|
|
242
|
+
export const ${constantCase(schematic.name)}_ISSUE_MESSAGES: Record<string, IssueMessagesByCode> = {};
|
|
243
|
+
`);
|
|
244
|
+
}
|
|
245
|
+
function scaffoldFormPages(schematic, data) {
|
|
246
|
+
const layout = reactAppLayout(schematic, {
|
|
247
|
+
kmpModuleName: `${kebabCase(schematic.name)}-shared`,
|
|
248
|
+
...data
|
|
249
|
+
});
|
|
250
|
+
for (const annex of layout) {
|
|
251
|
+
for (const formPage of annex.formPages) {
|
|
252
|
+
scaffoldFormPage(formPage.schematic, formPage.data);
|
|
253
|
+
if (formPage.data.currentPath !== "/") {
|
|
254
|
+
scaffoldIssueMessages(formPage.schematic, formPage.data);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function scaffoldFormPage(schematic, data) {
|
|
260
|
+
const fileName = kformScaffolder.joinPaths(data.currentDir, `${schematic.name}.tsx`);
|
|
261
|
+
let file = data.files.get(fileName);
|
|
262
|
+
if (!file) {
|
|
263
|
+
data.files.set(fileName, file = kformScaffolder.tsFile());
|
|
264
|
+
}
|
|
265
|
+
scaffoldFormPageComponent(schematic, {
|
|
266
|
+
kmpModuleName: `${kebabCase(data.rootSchematic.name)}-shared`,
|
|
267
|
+
...data,
|
|
268
|
+
currentFile: file
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
function scaffoldFormPageComponent(schematic, data) {
|
|
272
|
+
data.currentFile.imports.push(
|
|
273
|
+
{ moduleName: "@ostack.tech/ui-kform", name: "FormPage" },
|
|
274
|
+
{ moduleName: "@ostack.tech/ui", name: "Grid" }
|
|
275
|
+
);
|
|
276
|
+
if (data.currentPath !== "/") {
|
|
277
|
+
data.currentFile.imports.push({
|
|
278
|
+
moduleName: `./${schematic.name}IssueMessages.tsx`,
|
|
279
|
+
name: `${constantCase(schematic.name)}_ISSUE_MESSAGES`
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
let pathString;
|
|
283
|
+
let preamble;
|
|
284
|
+
const splitPath = data.currentPath.split("/");
|
|
285
|
+
if (splitPath.some((fragment) => fragment === "*")) {
|
|
286
|
+
data.currentFile.imports.push({
|
|
287
|
+
moduleName: "react-router",
|
|
288
|
+
name: "useParams"
|
|
289
|
+
});
|
|
290
|
+
pathString = `{\`${splitPath.map((f) => f === "*" ? "${id}" : f).join("/")}\`}`;
|
|
291
|
+
preamble = "\n const { id } = useParams();\n";
|
|
292
|
+
} else {
|
|
293
|
+
pathString = `"${data.currentPath}"`;
|
|
294
|
+
preamble = "";
|
|
295
|
+
}
|
|
296
|
+
const pageComponent = kformScaffolder.code`
|
|
297
|
+
export function ${schematic.name}() {${preamble}
|
|
298
|
+
return (
|
|
299
|
+
<FormPage${data.currentPath === "/" ? "" : ` path=${pathString} issueMessages={${constantCase(schematic.name)}_ISSUE_MESSAGES}`}>
|
|
300
|
+
<Grid container>
|
|
301
|
+
${schematic.children.map(
|
|
302
|
+
(child) => kformScaffolder.code`
|
|
303
|
+
<Grid xs={12}>
|
|
304
|
+
${scaffoldField(child, {
|
|
305
|
+
...data,
|
|
306
|
+
currentPath: child.childName
|
|
307
|
+
})}
|
|
308
|
+
</Grid>
|
|
309
|
+
`
|
|
310
|
+
).join("\n\n")}
|
|
311
|
+
</Grid>
|
|
312
|
+
</FormPage>
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
`;
|
|
316
|
+
data.currentFile.declarations.push(pageComponent);
|
|
317
|
+
}
|
|
318
|
+
function scaffoldField(schematic, data) {
|
|
319
|
+
const schematicKind = data.schematicKinds.get(
|
|
320
|
+
schematic.kind
|
|
321
|
+
);
|
|
322
|
+
if (!schematicKind) {
|
|
323
|
+
throw new Error(`Unknown schematic kind ${schematic.kind}`);
|
|
324
|
+
}
|
|
325
|
+
if (schematicKind.scaffoldField) {
|
|
326
|
+
return schematicKind.scaffoldField?.(schematic, data);
|
|
327
|
+
}
|
|
328
|
+
data.currentFile.imports.push({
|
|
329
|
+
moduleName: "@ostack.tech/ui-kform",
|
|
330
|
+
name: "ControlField"
|
|
331
|
+
});
|
|
332
|
+
if (schematicKind.control) {
|
|
333
|
+
const [moduleName, name] = schematicKind.control.split(".");
|
|
334
|
+
data.currentFile.imports.push({ moduleName, name });
|
|
335
|
+
}
|
|
336
|
+
let control = schematicKind.scaffoldControl?.(schematic, data);
|
|
337
|
+
if (!control) {
|
|
338
|
+
if (!data.omitLabel) {
|
|
339
|
+
data.currentFile.imports.push({
|
|
340
|
+
moduleName: "@ostack.tech/ui",
|
|
341
|
+
name: "Label"
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
control = [
|
|
345
|
+
data.omitLabel ? null : `<Label>${sentenceCase(schematic.childName)}</Label>`,
|
|
346
|
+
`<${schematicKind.control?.split(".")[1]} />`
|
|
347
|
+
].filter((s) => s).join("\n");
|
|
348
|
+
}
|
|
349
|
+
return kformScaffolder.code`
|
|
350
|
+
<ControlField path="${data.currentPath}">
|
|
351
|
+
${control}
|
|
352
|
+
</ControlField>
|
|
353
|
+
`;
|
|
354
|
+
}
|
|
355
|
+
function arrayify(value) {
|
|
356
|
+
return value == null ? [] : Array.isArray(value) ? value : [value];
|
|
357
|
+
}
|
|
358
|
+
const anySchematicKind = {
|
|
359
|
+
...kformScaffolder.anySchematicKind
|
|
360
|
+
};
|
|
361
|
+
const bigDecimalSchematicKind = {
|
|
362
|
+
...kformScaffolder.bigDecimalSchematicKind,
|
|
363
|
+
control: "@ostack.tech/ui-kform.NumericControl"
|
|
364
|
+
};
|
|
365
|
+
const bigIntegerSchematicKind = {
|
|
366
|
+
...kformScaffolder.bigIntegerSchematicKind,
|
|
367
|
+
control: "@ostack.tech/ui-kform.NumericControl"
|
|
368
|
+
};
|
|
369
|
+
const booleanSchematicKind = {
|
|
370
|
+
...kformScaffolder.booleanSchematicKind,
|
|
371
|
+
control: "@ostack.tech/ui-kform.CheckboxControl",
|
|
372
|
+
scaffoldControl: (schematic, data) => data.omitLabel ? `<CheckboxControl />` : `<CheckboxControl>${sentenceCase(schematic.childName)}</CheckboxControl>`
|
|
373
|
+
};
|
|
374
|
+
const byteSchematicKind = {
|
|
375
|
+
...kformScaffolder.byteSchematicKind,
|
|
376
|
+
control: "@ostack.tech/ui-kform.NumericControl"
|
|
377
|
+
};
|
|
378
|
+
const classAnnexSchematicKind = {
|
|
379
|
+
...kformScaffolder.classSchematicKind,
|
|
380
|
+
defaultPackageSuffix: (childName) => `annexes.${childName.toLowerCase()}`,
|
|
381
|
+
kind: "Class (Annex)"
|
|
382
|
+
};
|
|
383
|
+
const classFormPageSchematicKind = {
|
|
384
|
+
...kformScaffolder.classSchematicKind,
|
|
385
|
+
kind: "Class (FormPage)",
|
|
386
|
+
nullable: false
|
|
387
|
+
};
|
|
388
|
+
const classSchematicKind = {
|
|
389
|
+
...kformScaffolder.classSchematicKind,
|
|
390
|
+
nullable: false,
|
|
391
|
+
scaffoldModel: (schematic, data) => {
|
|
392
|
+
const baseModel = kformScaffolder.classSchematicKind.scaffoldModel(schematic, data);
|
|
393
|
+
if (data.currentPath !== "/") {
|
|
394
|
+
return baseModel;
|
|
395
|
+
}
|
|
396
|
+
data.currentFile.imports.add("kotlin.js.ExperimentalJsStatic").add("kotlin.js.JsStatic").add("kotlinx.serialization.EncodeDefault").add("kotlinx.serialization.ExperimentalSerializationApi");
|
|
397
|
+
const classAnnotations = [];
|
|
398
|
+
const versionAnnotations = [
|
|
399
|
+
"@EncodeDefault",
|
|
400
|
+
"@OptIn(ExperimentalSerializationApi::class)"
|
|
401
|
+
];
|
|
402
|
+
if (data.serializationFormat === "xml") {
|
|
403
|
+
data.currentFile.imports.add("nl.adaptivity.xmlutil.serialization.XmlChildrenName").add("nl.adaptivity.xmlutil.serialization.XmlElement").add("nl.adaptivity.xmlutil.serialization.XmlSerialName");
|
|
404
|
+
const defaultNamespace = `http://${data.currentPackage.split(".").reverse().join(".")}/schema/${(/* @__PURE__ */ new Date()).getFullYear()}`;
|
|
405
|
+
classAnnotations.push(
|
|
406
|
+
`@XmlSerialName("${schematic.name}", "${defaultNamespace}")`
|
|
407
|
+
);
|
|
408
|
+
versionAnnotations.push("@XmlElement(false)");
|
|
409
|
+
} else {
|
|
410
|
+
data.currentFile.imports.add("kotlinx.serialization.SerialName");
|
|
411
|
+
versionAnnotations.push('@SerialName($$"$version")');
|
|
412
|
+
}
|
|
413
|
+
return kformScaffolder.annotate(
|
|
414
|
+
classAnnotations,
|
|
415
|
+
`${baseModel} ${kformScaffolder.code`
|
|
416
|
+
{
|
|
417
|
+
${kformScaffolder.annotate(versionAnnotations, `internal var version = ${constantCase(schematic.name)}_SERIALIZATION_VERSION`)}
|
|
418
|
+
|
|
419
|
+
companion object {
|
|
420
|
+
@OptIn(ExperimentalJsStatic::class)
|
|
421
|
+
@JsStatic
|
|
422
|
+
fun createInitialValue(externalContexts: ${schematic.name}ExternalContexts) =
|
|
423
|
+
externalContexts.initialValue ?: ${schematic.name}()
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
`}`
|
|
427
|
+
);
|
|
428
|
+
},
|
|
429
|
+
scaffoldField: (schematic, data) => {
|
|
430
|
+
data.currentFile.imports.push(
|
|
431
|
+
{ moduleName: "@ostack.tech/ui", name: "FieldGroup" },
|
|
432
|
+
{ moduleName: "@ostack.tech/ui", name: "FieldGroupHeader" },
|
|
433
|
+
{ moduleName: "@ostack.tech/ui", name: "FieldGroupTitle" },
|
|
434
|
+
{ moduleName: "@ostack.tech/ui", name: "FieldGroupBody" },
|
|
435
|
+
{ moduleName: "@ostack.tech/ui", name: "Grid" }
|
|
436
|
+
);
|
|
437
|
+
return kformScaffolder.code`
|
|
438
|
+
<FieldGroup>
|
|
439
|
+
<FieldGroupHeader>
|
|
440
|
+
<FieldGroupTitle>${capitalCase(schematic.name)}</FieldGroupTitle>
|
|
441
|
+
</FieldGroupHeader>
|
|
442
|
+
|
|
443
|
+
<FieldGroupBody>
|
|
444
|
+
<Grid container>
|
|
445
|
+
${schematic.children.map(
|
|
446
|
+
(child) => kformScaffolder.code`
|
|
447
|
+
<Grid xs={12}>
|
|
448
|
+
${scaffoldField(child, {
|
|
449
|
+
...data,
|
|
450
|
+
currentPath: kformScaffolder.joinPaths(
|
|
451
|
+
data.currentPath,
|
|
452
|
+
child.childName
|
|
453
|
+
)
|
|
454
|
+
})}
|
|
455
|
+
</Grid>
|
|
456
|
+
`
|
|
457
|
+
).join("\n\n")}
|
|
458
|
+
</Grid>
|
|
459
|
+
</FieldGroupBody>
|
|
460
|
+
</FieldGroup>
|
|
461
|
+
`;
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
const doubleSchematicKind = {
|
|
465
|
+
...kformScaffolder.doubleSchematicKind,
|
|
466
|
+
control: "@ostack.tech/ui-kform.NumericControl"
|
|
467
|
+
};
|
|
468
|
+
const enumSchematicKind = {
|
|
469
|
+
...kformScaffolder.enumSchematicKind,
|
|
470
|
+
kind: "Enum",
|
|
471
|
+
internal: true,
|
|
472
|
+
nullable: false
|
|
473
|
+
};
|
|
474
|
+
const enumSelectSchematicKind = {
|
|
475
|
+
...kformScaffolder.enumSchematicKind,
|
|
476
|
+
kind: "Enum (Select)",
|
|
477
|
+
control: "@ostack.tech/ui-kform.SelectControl",
|
|
478
|
+
scaffoldControl: (schematic, data) => {
|
|
479
|
+
if (!data.omitLabel) {
|
|
480
|
+
data.currentFile.imports.push({
|
|
481
|
+
moduleName: "@ostack.tech/ui",
|
|
482
|
+
name: "Label"
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
data.currentFile.imports.push({
|
|
486
|
+
moduleName: data.kmpModuleName,
|
|
487
|
+
name: schematic.name
|
|
488
|
+
});
|
|
489
|
+
return [
|
|
490
|
+
data.omitLabel ? null : `<Label>${sentenceCase(schematic.childName)}</Label>`,
|
|
491
|
+
kformScaffolder.code`
|
|
492
|
+
<SelectControl
|
|
493
|
+
options={[
|
|
494
|
+
${schematic.children.map(
|
|
495
|
+
(child) => `{ value: ${schematic.name}.${child.childName}, text: ${JSON.stringify(sentenceCase(child.childName))} }`
|
|
496
|
+
).join(",\n")}
|
|
497
|
+
]}
|
|
498
|
+
/>
|
|
499
|
+
`
|
|
500
|
+
].filter((s) => s).join("\n");
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
const enumRadioGroupSchematicKind = {
|
|
504
|
+
...kformScaffolder.enumSchematicKind,
|
|
505
|
+
kind: "Enum (RadioGroup)",
|
|
506
|
+
control: "@ostack.tech/ui-kform.RadioGroupControl",
|
|
507
|
+
scaffoldControl: (schematic, data) => {
|
|
508
|
+
if (!data.omitLabel) {
|
|
509
|
+
data.currentFile.imports.push({
|
|
510
|
+
moduleName: "@ostack.tech/ui",
|
|
511
|
+
name: "Label"
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
data.currentFile.imports.push({
|
|
515
|
+
moduleName: data.kmpModuleName,
|
|
516
|
+
name: schematic.name
|
|
517
|
+
});
|
|
518
|
+
return [
|
|
519
|
+
data.omitLabel ? null : `<Label>${sentenceCase(schematic.childName)}</Label>`,
|
|
520
|
+
kformScaffolder.code`
|
|
521
|
+
<RadioGroupControl
|
|
522
|
+
options={[
|
|
523
|
+
${schematic.children.map(
|
|
524
|
+
(child) => `{ value: ${schematic.name}.${child.childName}, text: ${JSON.stringify(sentenceCase(child.childName))} }`
|
|
525
|
+
).join(",\n")}
|
|
526
|
+
]}
|
|
527
|
+
/>
|
|
528
|
+
`
|
|
529
|
+
].filter((s) => s).join("\n");
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
const fileSchematicKind = {
|
|
533
|
+
...kformScaffolder.fileSchematicKind,
|
|
534
|
+
nullable: true,
|
|
535
|
+
control: "@ostack.tech/ui-kform.FileControl"
|
|
536
|
+
};
|
|
537
|
+
const floatSchematicKind = {
|
|
538
|
+
...kformScaffolder.floatSchematicKind,
|
|
539
|
+
control: "@ostack.tech/ui-kform.NumericControl"
|
|
540
|
+
};
|
|
541
|
+
const intSchematicKind = {
|
|
542
|
+
...kformScaffolder.intSchematicKind,
|
|
543
|
+
control: "@ostack.tech/ui-kform.NumericControl"
|
|
544
|
+
};
|
|
545
|
+
const listCheckboxGroupSchematicKind = {
|
|
546
|
+
...kformScaffolder.listSchematicKind,
|
|
547
|
+
kind: "List<Enum> (CheckboxGroup)",
|
|
548
|
+
nullable: false,
|
|
549
|
+
initChildren: (childName) => [
|
|
550
|
+
kformScaffolder.createSchematic({
|
|
551
|
+
kind: "Enum",
|
|
552
|
+
name: pascalCase(childName),
|
|
553
|
+
nullable: false,
|
|
554
|
+
children: []
|
|
555
|
+
})
|
|
556
|
+
],
|
|
557
|
+
builder: kformScaffolder.ListableBuilderWithoutKindSelect,
|
|
558
|
+
control: "@ostack.tech/ui-kform.CheckboxGroupControl",
|
|
559
|
+
scaffoldControl: (schematic, data) => {
|
|
560
|
+
const childSchematic = schematic.children[0];
|
|
561
|
+
if (childSchematic.kind !== "Enum") {
|
|
562
|
+
throw new Error("Invalid child kind.");
|
|
563
|
+
}
|
|
564
|
+
if (!data.omitLabel) {
|
|
565
|
+
data.currentFile.imports.push({
|
|
566
|
+
moduleName: "@ostack.tech/ui",
|
|
567
|
+
name: "Label"
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
data.currentFile.imports.push({
|
|
571
|
+
moduleName: data.kmpModuleName,
|
|
572
|
+
name: childSchematic.name
|
|
573
|
+
});
|
|
574
|
+
return [
|
|
575
|
+
data.omitLabel ? null : `<Label>${sentenceCase(schematic.childName)}</Label>`,
|
|
576
|
+
kformScaffolder.code`
|
|
577
|
+
<CheckboxGroupControl
|
|
578
|
+
options={[
|
|
579
|
+
${childSchematic.children.map(
|
|
580
|
+
(child) => `{ value: ${childSchematic.name}.${child.childName}, text: ${JSON.stringify(sentenceCase(child.childName))} }`
|
|
581
|
+
).join(",\n")}
|
|
582
|
+
]}
|
|
583
|
+
/>
|
|
584
|
+
`
|
|
585
|
+
].filter((s) => s).join("\n");
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
const listSelectMultipleSchematicKind = {
|
|
589
|
+
...kformScaffolder.listSchematicKind,
|
|
590
|
+
kind: "List<Enum> (SelectMultiple)",
|
|
591
|
+
nullable: false,
|
|
592
|
+
initChildren: (childName) => [
|
|
593
|
+
kformScaffolder.createSchematic({
|
|
594
|
+
kind: "Enum",
|
|
595
|
+
name: pascalCase(childName),
|
|
596
|
+
nullable: false,
|
|
597
|
+
children: []
|
|
598
|
+
})
|
|
599
|
+
],
|
|
600
|
+
builder: kformScaffolder.ListableBuilderWithoutKindSelect,
|
|
601
|
+
control: "@ostack.tech/ui-kform.SelectMultipleControl",
|
|
602
|
+
scaffoldControl: (schematic, data) => {
|
|
603
|
+
const childSchematic = schematic.children[0];
|
|
604
|
+
if (childSchematic.kind !== "Enum") {
|
|
605
|
+
throw new Error("Invalid child kind.");
|
|
606
|
+
}
|
|
607
|
+
if (!data.omitLabel) {
|
|
608
|
+
data.currentFile.imports.push({
|
|
609
|
+
moduleName: "@ostack.tech/ui",
|
|
610
|
+
name: "Label"
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
data.currentFile.imports.push({
|
|
614
|
+
moduleName: data.kmpModuleName,
|
|
615
|
+
name: childSchematic.name
|
|
616
|
+
});
|
|
617
|
+
return [
|
|
618
|
+
data.omitLabel ? null : `<Label>${sentenceCase(schematic.childName)}</Label>`,
|
|
619
|
+
kformScaffolder.code`
|
|
620
|
+
<SelectMultipleControl
|
|
621
|
+
options={[
|
|
622
|
+
${childSchematic.children.map(
|
|
623
|
+
(child) => `{ value: ${childSchematic.name}.${child.childName}, text: ${JSON.stringify(sentenceCase(child.childName))} }`
|
|
624
|
+
).join(",\n")}
|
|
625
|
+
]}
|
|
626
|
+
/>
|
|
627
|
+
`
|
|
628
|
+
].filter((s) => s).join("\n");
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
const localDateSchematicKind = {
|
|
632
|
+
...kformScaffolder.localDateSchematicKind,
|
|
633
|
+
nullable: true,
|
|
634
|
+
control: "@ostack.tech/ui-kform.DateControl"
|
|
635
|
+
};
|
|
636
|
+
const longSchematicKind = {
|
|
637
|
+
...kformScaffolder.longSchematicKind,
|
|
638
|
+
control: "@ostack.tech/ui-kform.NumericControl"
|
|
639
|
+
};
|
|
640
|
+
const shortSchematicKind = {
|
|
641
|
+
...kformScaffolder.shortSchematicKind,
|
|
642
|
+
control: "@ostack.tech/ui-kform.NumericControl"
|
|
643
|
+
};
|
|
644
|
+
const stringSchematicKind = {
|
|
645
|
+
...kformScaffolder.stringSchematicKind,
|
|
646
|
+
control: "@ostack.tech/ui-kform.TextControl"
|
|
647
|
+
};
|
|
648
|
+
const tableAnnexesSchematicKind = {
|
|
649
|
+
...kformScaffolder.tableSchematicKind,
|
|
650
|
+
kind: "Table (Annexes)",
|
|
651
|
+
nullable: false,
|
|
652
|
+
builder: kformScaffolder.ListableBuilderWithoutKindSelect,
|
|
653
|
+
initChildren: (childName) => [
|
|
654
|
+
kformScaffolder.createSchematic({
|
|
655
|
+
kind: "Class (Annex)",
|
|
656
|
+
packageSuffix: `annexes.${childName.toLowerCase()}`,
|
|
657
|
+
name: pascalCase(childName),
|
|
658
|
+
nullable: false,
|
|
659
|
+
children: []
|
|
660
|
+
})
|
|
661
|
+
],
|
|
662
|
+
propertyAnnotations: (schematic, data) => {
|
|
663
|
+
const annotations = arrayify(
|
|
664
|
+
typeof kformScaffolder.tableSchematicKind.propertyAnnotations === "function" ? kformScaffolder.tableSchematicKind.propertyAnnotations?.(schematic, data) : kformScaffolder.tableSchematicKind.propertyAnnotations
|
|
665
|
+
);
|
|
666
|
+
if (data.serializationFormat === "xml") {
|
|
667
|
+
data.currentFile.imports.add(
|
|
668
|
+
"nl.adaptivity.xmlutil.serialization.XmlChildrenName"
|
|
669
|
+
);
|
|
670
|
+
annotations.push(
|
|
671
|
+
`@XmlChildrenName("${camelCase(schematic.children[0].name)}")`
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
return annotations;
|
|
675
|
+
}
|
|
676
|
+
};
|
|
677
|
+
const tableSchematicKind = {
|
|
678
|
+
...kformScaffolder.tableSchematicKind,
|
|
679
|
+
nullable: false,
|
|
680
|
+
builder: kformScaffolder.ListableBuilderWithoutKindSelect,
|
|
681
|
+
initChildren: (childName) => [
|
|
682
|
+
kformScaffolder.createSchematic({
|
|
683
|
+
kind: "Class",
|
|
684
|
+
name: `${pascalCase(childName)}Row`,
|
|
685
|
+
nullable: false,
|
|
686
|
+
children: []
|
|
687
|
+
})
|
|
688
|
+
],
|
|
689
|
+
propertyAnnotations: tableAnnexesSchematicKind.propertyAnnotations,
|
|
690
|
+
control: "@ostack.tech/ui-kform.TableControl",
|
|
691
|
+
scaffoldControl: (schematic, data) => {
|
|
692
|
+
const rowSchematic = schematic.children[0];
|
|
693
|
+
if (rowSchematic.kind !== "Class") {
|
|
694
|
+
throw new Error("Table child schematic is not of Class kind.");
|
|
695
|
+
}
|
|
696
|
+
data.currentFile.imports.push(
|
|
697
|
+
{ moduleName: "@ostack.tech/ui", name: "Label" },
|
|
698
|
+
{
|
|
699
|
+
moduleName: "@ostack.tech/ui-kform",
|
|
700
|
+
name: "tableControlIndexColumn"
|
|
701
|
+
},
|
|
702
|
+
{
|
|
703
|
+
moduleName: "@ostack.tech/ui-kform",
|
|
704
|
+
name: "tableControlActionsColumn"
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
moduleName: "@ostack.tech/ui-kform",
|
|
708
|
+
name: "TableControlAddRowTrigger"
|
|
709
|
+
},
|
|
710
|
+
{ moduleName: "@ostack.tech/ui-kform", name: "TableControlContent" }
|
|
711
|
+
);
|
|
712
|
+
return kformScaffolder.code`
|
|
713
|
+
<TableControl
|
|
714
|
+
columns={[
|
|
715
|
+
tableControlIndexColumn(),
|
|
716
|
+
${rowSchematic.children.map(
|
|
717
|
+
(child) => kformScaffolder.code`
|
|
718
|
+
{
|
|
719
|
+
label: ${JSON.stringify(sentenceCase(child.childName))},
|
|
720
|
+
render: () => (
|
|
721
|
+
${scaffoldField(child, {
|
|
722
|
+
...data,
|
|
723
|
+
omitLabel: true,
|
|
724
|
+
currentPath: child.childName
|
|
725
|
+
})}
|
|
726
|
+
)
|
|
727
|
+
}
|
|
728
|
+
`
|
|
729
|
+
).join(",\n")},
|
|
730
|
+
tableControlActionsColumn()
|
|
731
|
+
]}
|
|
732
|
+
>
|
|
733
|
+
<Label>${sentenceCase(schematic.childName)}</Label>
|
|
734
|
+
<TableControlAddRowTrigger />
|
|
735
|
+
<TableControlContent />
|
|
736
|
+
</TableControl>
|
|
737
|
+
`;
|
|
738
|
+
}
|
|
739
|
+
};
|
|
740
|
+
const defaultSchematicKinds = [
|
|
741
|
+
anySchematicKind,
|
|
742
|
+
bigDecimalSchematicKind,
|
|
743
|
+
bigIntegerSchematicKind,
|
|
744
|
+
booleanSchematicKind,
|
|
745
|
+
byteSchematicKind,
|
|
746
|
+
classSchematicKind,
|
|
747
|
+
classAnnexSchematicKind,
|
|
748
|
+
classFormPageSchematicKind,
|
|
749
|
+
doubleSchematicKind,
|
|
750
|
+
enumSchematicKind,
|
|
751
|
+
enumSelectSchematicKind,
|
|
752
|
+
enumRadioGroupSchematicKind,
|
|
753
|
+
fileSchematicKind,
|
|
754
|
+
floatSchematicKind,
|
|
755
|
+
intSchematicKind,
|
|
756
|
+
listCheckboxGroupSchematicKind,
|
|
757
|
+
listSelectMultipleSchematicKind,
|
|
758
|
+
localDateSchematicKind,
|
|
759
|
+
longSchematicKind,
|
|
760
|
+
shortSchematicKind,
|
|
761
|
+
stringSchematicKind,
|
|
762
|
+
tableAnnexesSchematicKind,
|
|
763
|
+
tableSchematicKind
|
|
764
|
+
];
|
|
765
|
+
function reactAppLayout(schematic, data) {
|
|
766
|
+
const annexes = [];
|
|
767
|
+
if (schematic.children?.every(
|
|
768
|
+
(child) => child.kind === classAnnexSchematicKind.kind || child.kind === tableAnnexesSchematicKind.kind
|
|
769
|
+
)) {
|
|
770
|
+
for (const annex of schematic.children) {
|
|
771
|
+
if (annex.kind === classAnnexSchematicKind.kind) {
|
|
772
|
+
annexes.push(
|
|
773
|
+
layoutAnnex(annex, {
|
|
774
|
+
...data,
|
|
775
|
+
currentPath: kformScaffolder.joinPaths(data.currentPath, annex.childName),
|
|
776
|
+
currentDir: kformScaffolder.joinPaths(
|
|
777
|
+
data.currentDir,
|
|
778
|
+
annex.packageSuffix?.replace(".", "/")
|
|
779
|
+
)
|
|
780
|
+
})
|
|
781
|
+
);
|
|
782
|
+
} else {
|
|
783
|
+
annexes.push(
|
|
784
|
+
layoutRepetitiveAnnex(annex, {
|
|
785
|
+
...data,
|
|
786
|
+
currentPath: kformScaffolder.joinPaths(data.currentPath, annex.childName)
|
|
787
|
+
})
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
} else if (schematic.children?.every(
|
|
792
|
+
(child) => child.kind === classFormPageSchematicKind.kind
|
|
793
|
+
)) {
|
|
794
|
+
annexes.push(layoutAnnex(schematic, data));
|
|
795
|
+
} else if (schematic.children?.some(
|
|
796
|
+
(child) => child.kind === classAnnexSchematicKind.kind || child.kind === tableAnnexesSchematicKind.kind || child.kind === classFormPageSchematicKind.kind
|
|
797
|
+
)) {
|
|
798
|
+
throw new Error(
|
|
799
|
+
"Annexes/form pages cannot be mixed with other kinds of fields."
|
|
800
|
+
);
|
|
801
|
+
} else {
|
|
802
|
+
annexes.push(layoutAnnex(schematic, data));
|
|
803
|
+
}
|
|
804
|
+
return annexes;
|
|
805
|
+
}
|
|
806
|
+
function layoutRepetitiveAnnex(schematic, data) {
|
|
807
|
+
const childSchematic = schematic.children[0];
|
|
808
|
+
return layoutAnnex(childSchematic, {
|
|
809
|
+
...data,
|
|
810
|
+
currentPath: kformScaffolder.joinPaths(data.currentPath, "*"),
|
|
811
|
+
currentDir: kformScaffolder.joinPaths(
|
|
812
|
+
data.currentDir,
|
|
813
|
+
childSchematic.packageSuffix?.replace(".", "/")
|
|
814
|
+
)
|
|
815
|
+
});
|
|
816
|
+
}
|
|
817
|
+
function layoutAnnex(schematic, data) {
|
|
818
|
+
if (schematic.children?.some(
|
|
819
|
+
(child) => child.kind === classAnnexSchematicKind.kind || child.kind === tableAnnexesSchematicKind.kind
|
|
820
|
+
)) {
|
|
821
|
+
throw new Error(
|
|
822
|
+
"Annexes must only appear at the top level of the schematic."
|
|
823
|
+
);
|
|
824
|
+
}
|
|
825
|
+
let formPages;
|
|
826
|
+
if (schematic.children?.every(
|
|
827
|
+
(child) => child.kind === classFormPageSchematicKind.kind
|
|
828
|
+
)) {
|
|
829
|
+
formPages = schematic.children?.map((formPage) => ({
|
|
830
|
+
schematic: formPage,
|
|
831
|
+
data: {
|
|
832
|
+
...data,
|
|
833
|
+
currentPath: kformScaffolder.joinPaths(
|
|
834
|
+
data.currentPath,
|
|
835
|
+
camelCase(formPage.childName)
|
|
836
|
+
),
|
|
837
|
+
currentDir: kformScaffolder.joinPaths(
|
|
838
|
+
data.currentDir,
|
|
839
|
+
formPage.packageSuffix?.replace(".", "/")
|
|
840
|
+
)
|
|
841
|
+
}
|
|
842
|
+
}));
|
|
843
|
+
} else if (schematic.children?.some(
|
|
844
|
+
(child) => child.kind === classFormPageSchematicKind.kind
|
|
845
|
+
)) {
|
|
846
|
+
throw new Error("Form pages cannot be mixed with other kinds of fields.");
|
|
847
|
+
} else {
|
|
848
|
+
formPages = [{ schematic, data }];
|
|
849
|
+
}
|
|
850
|
+
return { schematic, data, formPages };
|
|
851
|
+
}
|
|
852
|
+
function scaffoldAppComponent(schematic, data) {
|
|
853
|
+
const fileName = kformScaffolder.joinPaths(data.currentDir, `${schematic.name}App.tsx`);
|
|
854
|
+
let file = data.files.get(fileName);
|
|
855
|
+
if (!file) {
|
|
856
|
+
data.files.set(fileName, file = kformScaffolder.tsFile());
|
|
857
|
+
}
|
|
858
|
+
scaffoldAppComponentFile(schematic, {
|
|
859
|
+
kmpModuleName: `${kebabCase(schematic.name)}-shared`,
|
|
860
|
+
...data,
|
|
861
|
+
currentFile: file
|
|
862
|
+
});
|
|
863
|
+
scaffoldIssueMessages(schematic, data);
|
|
864
|
+
}
|
|
865
|
+
function scaffoldAppComponentFile(schematic, data) {
|
|
866
|
+
data.currentFile.imports.push(
|
|
867
|
+
{ moduleName: "@ostack.tech/kform", name: "ktMapToObject" },
|
|
868
|
+
{ moduleName: "@ostack.tech/ui-kform", name: "FormApp" },
|
|
869
|
+
{ moduleName: "react", name: "useMemo" },
|
|
870
|
+
{ moduleName: data.kmpModuleName, name: schematic.name },
|
|
871
|
+
{ moduleName: data.kmpModuleName, name: `${schematic.name}FormMode` },
|
|
872
|
+
{ moduleName: data.kmpModuleName, name: `${schematic.name}Schema` },
|
|
873
|
+
{ moduleName: `./api/reportError.ts`, name: "REPORT_ERROR_ENDPOINT" },
|
|
874
|
+
{
|
|
875
|
+
moduleName: `./${schematic.name}Context.ts`,
|
|
876
|
+
name: `use${schematic.name}Context`
|
|
877
|
+
},
|
|
878
|
+
{
|
|
879
|
+
moduleName: `./${schematic.name}IssueMessages.tsx`,
|
|
880
|
+
name: `${constantCase(schematic.name)}_ISSUE_MESSAGES`
|
|
881
|
+
}
|
|
882
|
+
);
|
|
883
|
+
data.currentFile.declarations.push(kformScaffolder.code`
|
|
884
|
+
export function ${schematic.name}App() {
|
|
885
|
+
const { externalContexts } = use${schematic.name}Context();
|
|
886
|
+
|
|
887
|
+
return (
|
|
888
|
+
<FormApp
|
|
889
|
+
schema={${schematic.name}Schema.get()}
|
|
890
|
+
initialValue={useMemo(
|
|
891
|
+
() => ${schematic.name}.createInitialValue(externalContexts),
|
|
892
|
+
[externalContexts],
|
|
893
|
+
)}
|
|
894
|
+
externalContexts={useMemo(
|
|
895
|
+
() => ktMapToObject(externalContexts.toMap()),
|
|
896
|
+
[externalContexts],
|
|
897
|
+
)}
|
|
898
|
+
readOnly={externalContexts.mode === ${schematic.name}FormMode.READ}
|
|
899
|
+
validationMode={
|
|
900
|
+
externalContexts.mode === ${schematic.name}FormMode.READ
|
|
901
|
+
? "manual"
|
|
902
|
+
: "auto"
|
|
903
|
+
}
|
|
904
|
+
issueMessages={${constantCase(schematic.name)}_ISSUE_MESSAGES}
|
|
905
|
+
errorReportingUrl={REPORT_ERROR_ENDPOINT}
|
|
906
|
+
>
|
|
907
|
+
<${schematic.name}Layout />
|
|
908
|
+
</FormApp>
|
|
909
|
+
);
|
|
910
|
+
}
|
|
911
|
+
`);
|
|
912
|
+
const layout = reactAppLayout(schematic, data);
|
|
913
|
+
data.currentFile.imports.push(
|
|
914
|
+
{ moduleName: "react-router", name: "useNavigate" },
|
|
915
|
+
{ moduleName: "react-router", name: "useLocation" },
|
|
916
|
+
{ moduleName: "react-router", name: "Outlet" },
|
|
917
|
+
{ moduleName: "@ostack.tech/ui-kform", name: "Annexes" },
|
|
918
|
+
{ moduleName: "@ostack.tech/ui-kform", name: "Annex" },
|
|
919
|
+
{
|
|
920
|
+
moduleName: "@ostack.tech/ui-kform",
|
|
921
|
+
name: "AnnexObject",
|
|
922
|
+
isType: true
|
|
923
|
+
},
|
|
924
|
+
{ moduleName: "@ostack.tech/ui-kform", name: "TopBar" },
|
|
925
|
+
{ moduleName: "@ostack.tech/ui-kform", name: "TopBarActions" },
|
|
926
|
+
{ moduleName: "./actions/Load.tsx", name: "Load" },
|
|
927
|
+
{ moduleName: "./actions/Save.tsx", name: "Save" },
|
|
928
|
+
{ moduleName: "./actions/Validate.tsx", name: "Validate" },
|
|
929
|
+
{ moduleName: "./actions/Submit.tsx", name: "Submit" },
|
|
930
|
+
{ moduleName: "@ostack.tech/ui-kform", name: "FormPages" },
|
|
931
|
+
{
|
|
932
|
+
moduleName: "@ostack.tech/ui-kform",
|
|
933
|
+
name: "FormPageObject",
|
|
934
|
+
isType: true
|
|
935
|
+
},
|
|
936
|
+
{ moduleName: "@ostack.tech/ui-kform", name: "IssuesPanel" }
|
|
937
|
+
);
|
|
938
|
+
let annexesManager = "";
|
|
939
|
+
if (layout.length > 1) {
|
|
940
|
+
data.currentFile.imports.push({
|
|
941
|
+
moduleName: "@ostack.tech/ui-kform",
|
|
942
|
+
name: "AnnexesManager"
|
|
943
|
+
});
|
|
944
|
+
annexesManager = `
|
|
945
|
+
<AnnexesManager />
|
|
946
|
+
`;
|
|
947
|
+
}
|
|
948
|
+
let formPagesNavigation = "";
|
|
949
|
+
if (layout.some((annex) => annex.formPages.length > 1)) {
|
|
950
|
+
data.currentFile.imports.push({
|
|
951
|
+
moduleName: "@ostack.tech/ui-kform",
|
|
952
|
+
name: "FormPagesNavigation"
|
|
953
|
+
});
|
|
954
|
+
if (layout.every((annex) => annex.formPages.length > 1)) {
|
|
955
|
+
formPagesNavigation = `
|
|
956
|
+
<FormPagesNavigation />
|
|
957
|
+
`;
|
|
958
|
+
} else {
|
|
959
|
+
formPagesNavigation = `
|
|
960
|
+
{pages.length > 1 && <FormPagesNavigation />}
|
|
961
|
+
`;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
data.currentFile.declarations.push(kformScaffolder.code`
|
|
965
|
+
function ${schematic.name}Layout() {
|
|
966
|
+
const navigate = useNavigate();
|
|
967
|
+
const { pathname } = useLocation();
|
|
968
|
+
|
|
969
|
+
const annexes: AnnexObject[] = useMemo(() => ${scaffoldAnnexesArray(layout)}, []);
|
|
970
|
+
|
|
971
|
+
const pagesByAnnex: Record<string, FormPageObject[]> = useMemo(() => (${scaffoldFormPagesByAnnexObject(layout)}), []);
|
|
972
|
+
|
|
973
|
+
return (
|
|
974
|
+
<>
|
|
975
|
+
<Annexes annexes={annexes} activeAnnex={pathname}>
|
|
976
|
+
<TopBar>${annexesManager}
|
|
977
|
+
<TopBarActions>
|
|
978
|
+
<Load />
|
|
979
|
+
<Save />
|
|
980
|
+
<Validate />
|
|
981
|
+
<Submit />
|
|
982
|
+
</TopBarActions>
|
|
983
|
+
</TopBar>
|
|
984
|
+
|
|
985
|
+
{Object.entries(pagesByAnnex).map(([annexPath, pages]) => (
|
|
986
|
+
<Annex path={annexPath} key={annexPath}>
|
|
987
|
+
<FormPages
|
|
988
|
+
pages={pages}
|
|
989
|
+
activePage={pathname}
|
|
990
|
+
onActivePageChange={(activePage) => {
|
|
991
|
+
const newPathname = activePage?.toString() ?? "/";
|
|
992
|
+
if (pathname !== newPathname) {
|
|
993
|
+
void navigate(newPathname, {
|
|
994
|
+
replace: newPathname.startsWith(
|
|
995
|
+
pathname.endsWith("/") ? pathname : \`\${pathname}/\`,
|
|
996
|
+
)
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
}}
|
|
1000
|
+
>${formPagesNavigation}
|
|
1001
|
+
<Outlet />
|
|
1002
|
+
</FormPages>
|
|
1003
|
+
</Annex>
|
|
1004
|
+
))}
|
|
1005
|
+
</Annexes>
|
|
1006
|
+
|
|
1007
|
+
<IssuesPanel />
|
|
1008
|
+
</>
|
|
1009
|
+
);
|
|
1010
|
+
}
|
|
1011
|
+
`);
|
|
1012
|
+
}
|
|
1013
|
+
function scaffoldAnnexesArray(layout) {
|
|
1014
|
+
return kformScaffolder.code`
|
|
1015
|
+
[
|
|
1016
|
+
${layout.map(
|
|
1017
|
+
(annex) => `{ path: "${annex.data.currentPath}", title: "${sentenceCase(
|
|
1018
|
+
annex.schematic.name
|
|
1019
|
+
)}"${annex.formPages.length === 1 && annex.data.currentPath === annex.formPages[0].data.currentPath ? ", documentTitle: null" : ""} }`
|
|
1020
|
+
).join(",\n")}
|
|
1021
|
+
]
|
|
1022
|
+
`;
|
|
1023
|
+
}
|
|
1024
|
+
function scaffoldFormPagesByAnnexObject(layout) {
|
|
1025
|
+
return kformScaffolder.code`
|
|
1026
|
+
{
|
|
1027
|
+
${layout.map(
|
|
1028
|
+
(annex) => `"${annex.data.currentPath}": ` + kformScaffolder.code`
|
|
1029
|
+
[
|
|
1030
|
+
${annex.formPages.map(
|
|
1031
|
+
(formPage) => annex.schematic === formPage.schematic ? `{ title: "${sentenceCase(
|
|
1032
|
+
formPage.schematic.name
|
|
1033
|
+
)}", code: "${formPage.schematic.name?.[0].toUpperCase()}"${formPage.data.currentPath === "/" ? ", documentTitle: null" : ""} }` : `{ path: "${formPage.data.currentPath.slice(
|
|
1034
|
+
annex.data.currentPath.length + (annex.data.currentPath.endsWith("/") ? 0 : 1)
|
|
1035
|
+
)}", title: "${sentenceCase(
|
|
1036
|
+
formPage.schematic.name
|
|
1037
|
+
)}", code: "${formPage.schematic.name?.[0].toUpperCase()}" }`
|
|
1038
|
+
).join(",\n")}
|
|
1039
|
+
]
|
|
1040
|
+
`
|
|
1041
|
+
).join(",\n")}
|
|
1042
|
+
}
|
|
1043
|
+
`;
|
|
1044
|
+
}
|
|
1045
|
+
const contextTsEjs = 'import { createContext, useContext } from "react";\nimport { <%= formClass %>ExternalContexts } from "<%= kmpModuleName %>";\n\nexport interface <%= formClass %>ContextValue {\n externalContexts: <%= formClass %>ExternalContexts;\n}\n\nexport const <%= formClass %>Context = createContext<<%= formClass %>ContextValue>(null as never);\n\nexport function use<%= formClass %>Context(): <%= formClass %>ContextValue {\n return useContext(<%= formClass %>Context);\n}\n';
|
|
1046
|
+
function scaffoldAppContext(schematic, data) {
|
|
1047
|
+
const ejsData = {
|
|
1048
|
+
kmpModuleName: data.kmpModuleName ?? `${kebabCase(schematic.name)}-shared`,
|
|
1049
|
+
formClass: schematic.name
|
|
1050
|
+
};
|
|
1051
|
+
kformScaffolder.addEjsTemplateFile(
|
|
1052
|
+
data,
|
|
1053
|
+
`${schematic.name}Context.ts`,
|
|
1054
|
+
contextTsEjs,
|
|
1055
|
+
ejsData
|
|
1056
|
+
);
|
|
1057
|
+
}
|
|
1058
|
+
const externalContextsKt = 'package <%= filePackage %>\n\nimport kotlin.js.JsExport\nimport kotlin.jvm.JvmOverloads\nimport kotlinx.serialization.Serializable\n\n@JsExport\n@Serializable\nenum class <%= formClass %>FormMode {\n /** Submitting a new form. */\n NEW,\n /** Reading a previously submitted form (`initialValue` should be provided as context). */\n READ,\n /** Replacing a previously submitted form (`initialValue` should be provided as context). */\n REPLACE,\n}\n\n@JsExport\n@Serializable\ndata class <%= formClass %>ExternalContexts @JvmOverloads constructor(\n val mode: <%= formClass %>FormMode = <%= formClass %>FormMode.NEW,\n val initialValue: <%= formClass %>? = null,\n) {\n fun toMap(): Map<String, Any?> = mapOf("mode" to mode, "initialValue" to initialValue)\n}\n';
|
|
1059
|
+
function scaffoldExternalContexts(schematic, data) {
|
|
1060
|
+
const ejsData = {
|
|
1061
|
+
filePackage: data.currentPackage,
|
|
1062
|
+
formClass: schematic.name
|
|
1063
|
+
};
|
|
1064
|
+
kformScaffolder.addEjsTemplateFile(
|
|
1065
|
+
data,
|
|
1066
|
+
`${schematic.name}ExternalContexts.kt`,
|
|
1067
|
+
externalContextsKt,
|
|
1068
|
+
ejsData
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
1071
|
+
const buildGradleKts = "allprojects {\n repositories { mavenCentral() }\n}\n";
|
|
1072
|
+
const gradlePropertiesEjs = "group=<%= group %>\nversion=0.0.1\n\norg.gradle.caching=true\norg.gradle.configuration-cache=true\n";
|
|
1073
|
+
const libsVersionsTomlEjs = '[versions]\n# Plugins\nkotlin = "2.2.20"\nnodeGradle = "7.1.0"\n# Libraries\nkotlinxCoroutines = "1.10.2"\nkform = "<%= kFormVersion %>"\n<%_ if (usesKotlinxDatetime) { -%>\nkotlinxDatetime = "0.7.1"\n<%_ } -%>\n<%_ if (serializationFormat === "json") { -%>\nkotlinxSerialization = "1.9.0"\n<%_ } -%>\n<%_ if (usesKtMath) { -%>\nktMath = "0.10.2"\n<%_ } -%>\nslf4j = "2.0.17"\n<%_ if (serializationFormat === "xml") { -%>\nxmlutil = "0.91.1"\n<%_ } -%>\n# Runtimes\njvmToolchain = "17"\nnodejs = "22.20.0"\n\n[libraries]\nkform = { module = "tech.ostack:kform", version.ref = "kform" }\nkform-jsBindings = { module = "tech.ostack:kform-js-bindings", version.ref = "kform" }\nkotlinxCoroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinxCoroutines" }\n<%_ if (usesKotlinxDatetime) { -%>\nkotlinxDatetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime" }\n<%_ } -%>\n<%_ if (serializationFormat === "json") { -%>\nkotlinxSerialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerialization" }\n<%_ } -%>\n<%_ if (usesKtMath) { -%>\nktMath = { module = "io.github.gciatto:kt-math", version.ref = "ktMath" }\n<%_ } -%>\nslf4j-simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j" }\n<%_ if (serializationFormat === "xml") { -%>\nxmlutil-serialization = { module = "io.github.pdvrieze.xmlutil:serialization", version.ref = "xmlutil" }\n<%_ } -%>\n\n[plugins]\nkotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }\nkotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }\nnodeGradle = { id = "com.github.node-gradle.node", version.ref = "nodeGradle" }\n';
|
|
1074
|
+
const reactAppBuildGradleKtsEjs = 'import com.github.gradle.node.npm.task.NpmTask\n\nplugins {\n alias(libs.plugins.nodeGradle)\n base\n}\n\nval isCI = System.getenv("CI") !in arrayOf(null, "0", "false")\nnode {\n download = true\n version = libs.versions.nodejs.get()\n npmInstallCommand = if (isCI) "ci" else "install"\n}\n\nval sharedPackage = project(":shared").file("build/<%= formId %>-shared-$version.tgz")\n\nval npmInstallShared by tasks.registering(NpmTask::class) {\n group = "build"\n dependsOn(":shared:packJsPackage")\n npmCommand = listOf("install", "<%= formId %>-shared@file:$sharedPackage")\n\n inputs.file(sharedPackage)\n outputs.dir("node_modules/<%= formId %>-shared")\n}\n\ntasks.npmInstall {\n dependsOn(npmInstallShared)\n}\n\nval npmRunDev by tasks.registering(NpmTask::class) {\n group = "development"\n dependsOn(tasks.npmInstall)\n npmCommand = listOf("run", "dev")\n}\n\nprivate fun NpmTask.npmRunBuild(buildReason: String) {\n group = "build"\n dependsOn(tasks.npmInstall)\n npmCommand = listOf("run", "build")\n environment = mapOf("VITE_BUILD_REASON" to buildReason)\n\n inputs.dir("src")\n inputs.file(sharedPackage)\n inputs.file("index.html")\n inputs.file("package.json")\n inputs.file("tsconfig.json")\n inputs.file("tsconfig.app.json")\n inputs.file("tsconfig.node.json")\n inputs.file("vite.config.ts")\n outputs.dir("build/dist")\n}\n\nval npmRunBuild by tasks.registering(NpmTask::class) {\n npmRunBuild("production")\n}\n\nval npmRunBuildPreview by tasks.registering(NpmTask::class) {\n npmRunBuild("preview")\n}\n\nval npmRunPreview by tasks.registering(NpmTask::class) {\n group = "development"\n dependsOn(npmRunBuildPreview)\n npmCommand = listOf("run", "preview")\n}\n\nval npmRunLint by tasks.registering(NpmTask::class) {\n group = "verification"\n dependsOn(tasks.npmInstall)\n npmCommand = listOf("run", "lint")\n\n inputs.dir("src")\n inputs.file("eslint.config.js")\n inputs.file("package.json")\n inputs.file("tsconfig.json")\n inputs.file("tsconfig.app.json")\n inputs.file("tsconfig.node.json")\n outputs.upToDateWhen { true }\n}\n\ntasks.assemble {\n dependsOn(npmRunBuild)\n}\n';
|
|
1075
|
+
const settingsGradleKtsEjs = 'plugins {\n id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"\n}\n\nrootProject.name = "<%= formId %>"\n\ninclude("shared", "react-app")\n';
|
|
1076
|
+
const sharedBuildGradleKtsEjs = 'import com.github.gradle.node.npm.task.NpmTask\n\nplugins {\n alias(libs.plugins.kotlin.multiplatform)\n alias(libs.plugins.kotlin.serialization)\n alias(libs.plugins.nodeGradle)\n}\n\nkotlin {\n jvmToolchain(libs.versions.jvmToolchain.get().toInt())\n jvm {\n testRuns["test"].executionTask.configure { useJUnitPlatform() }\n }\n js {\n compilerOptions {\n target = "es2015"\n freeCompilerArgs.add("-Xes-long-as-bigint")\n freeCompilerArgs.add("-Xwarning-level=NON_EXPORTABLE_TYPE:disabled")\n }\n binaries.library()\n browser { testTask { useMocha() } }\n generateTypeScriptDefinitions()\n }\n\n sourceSets {\n all {\n // Opt in to the experimental `JsExport` annotation\n languageSettings.optIn("kotlin.js.ExperimentalJsExport")\n }\n\n commonMain.dependencies {\n api(libs.kform)\n <%_ if (usesKotlinxDatetime) { -%>\n api(libs.kotlinxDatetime)\n <%_ } -%>\n <%_ if (serializationFormat === "json") { -%>\n api(libs.kotlinxSerialization.json)\n <%_ } -%>\n <%_ if (usesKtMath) { -%>\n api(libs.ktMath)\n <%_ } -%>\n <%_ if (serializationFormat === "xml") { -%>\n api(libs.xmlutil.serialization)\n <%_ } -%>\n }\n commonTest.dependencies {\n implementation(kotlin("test"))\n implementation(libs.kotlinxCoroutines.test)\n }\n jvmTest.dependencies {\n implementation(libs.slf4j.simple)\n }\n jsMain.dependencies {\n implementation(libs.kform.jsBindings)\n <%_ if (usesKotlinxDatetime) { -%>\n implementation(npm("@js-joda/timezone", "2.3.0"))\n <%_ } -%>\n }\n }\n}\n\nval isCI = System.getenv("CI") !in arrayOf(null, "0", "false")\nnode {\n download = true\n version = libs.versions.nodejs.get()\n npmInstallCommand = if (isCI) "ci" else "install"\n}\n\n// Packs the result of the JS compilation, for consumption by the React app\nval packJsPackage by tasks.registering(NpmTask::class) {\n group = "build"\n dependsOn("jsBrowserProductionLibraryDistribution")\n\n val libraryDir = "build/dist/js/productionLibrary"\n npmCommand = listOf("pack", libraryDir, "--pack-destination", "build")\n\n inputs.dir(libraryDir)\n outputs.file("build/<%= formId %>-shared-${version}.tgz")\n}\n';
|
|
1077
|
+
const jsJodaTimeZoneKtEjs = 'package <%= filePackage %>\n\n// See: https://github.com/Kotlin/kotlinx-datetime?tab=readme-ov-file#note-about-time-zones-in-js\n@JsModule("@js-joda/timezone")\n@JsNonModule\nexternal object JsJodaTimeZoneModule\n\n@JsExport\nval jsJodaTz = JsJodaTimeZoneModule\n';
|
|
1078
|
+
function scaffoldGradleProject(schematic, data) {
|
|
1079
|
+
const ejsData = {
|
|
1080
|
+
group: data.currentPackage,
|
|
1081
|
+
filePackage: data.currentPackage,
|
|
1082
|
+
formId: kebabCase(schematic.name),
|
|
1083
|
+
formTitle: capitalCase(schematic.name),
|
|
1084
|
+
kFormVersion: "0.31.0",
|
|
1085
|
+
serializationFormat: data.serializationFormat ?? "json",
|
|
1086
|
+
usesKotlinxDatetime: usesKotlinxDatetime(schematic, data),
|
|
1087
|
+
usesKtMath: usesKtMath(schematic)
|
|
1088
|
+
};
|
|
1089
|
+
kformScaffolder.addEjsTemplateFile(data, "gradle.properties", gradlePropertiesEjs, ejsData);
|
|
1090
|
+
kformScaffolder.addEjsTemplateFile(
|
|
1091
|
+
data,
|
|
1092
|
+
"settings.gradle.kts",
|
|
1093
|
+
settingsGradleKtsEjs,
|
|
1094
|
+
ejsData
|
|
1095
|
+
);
|
|
1096
|
+
kformScaffolder.addEjsTemplateFile(
|
|
1097
|
+
data,
|
|
1098
|
+
"gradle/libs.versions.toml",
|
|
1099
|
+
libsVersionsTomlEjs,
|
|
1100
|
+
ejsData
|
|
1101
|
+
);
|
|
1102
|
+
kformScaffolder.addTemplateFile(data, "build.gradle.kts", buildGradleKts);
|
|
1103
|
+
kformScaffolder.addEjsTemplateFile(
|
|
1104
|
+
data,
|
|
1105
|
+
"shared/build.gradle.kts",
|
|
1106
|
+
sharedBuildGradleKtsEjs,
|
|
1107
|
+
ejsData
|
|
1108
|
+
);
|
|
1109
|
+
if (ejsData.usesKotlinxDatetime) {
|
|
1110
|
+
kformScaffolder.addEjsTemplateFile(
|
|
1111
|
+
data,
|
|
1112
|
+
"shared/src/jsMain/kotlin/JsJodaTimeZone.kt",
|
|
1113
|
+
jsJodaTimeZoneKtEjs,
|
|
1114
|
+
ejsData
|
|
1115
|
+
);
|
|
1116
|
+
}
|
|
1117
|
+
kformScaffolder.addEjsTemplateFile(
|
|
1118
|
+
data,
|
|
1119
|
+
"react-app/build.gradle.kts",
|
|
1120
|
+
reactAppBuildGradleKtsEjs,
|
|
1121
|
+
ejsData
|
|
1122
|
+
);
|
|
1123
|
+
}
|
|
1124
|
+
function usesKotlinxDatetime(schematic, data) {
|
|
1125
|
+
const schematicKind = data.schematicKinds.get(schematic.kind);
|
|
1126
|
+
return schematicKind?.package === "kotlinx.datetime" || schematic.children?.some((child) => usesKotlinxDatetime(child, data)) === true;
|
|
1127
|
+
}
|
|
1128
|
+
function usesKtMath(schematic) {
|
|
1129
|
+
return ["BigInteger", "BigDecimal"].includes(schematic.kind) || schematic.children?.some((child) => usesKtMath(child)) === true;
|
|
1130
|
+
}
|
|
1131
|
+
const gradleWrapperJar = "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AAAAAAAAAAAAAAAwDgAATUVUQS1JTkYvTUFOSUZFU1QuTUZVVAUAAQAAAABQSwECFAAUAAgICAAAACEAAsIE3yIBAABwAQAAMQAJAAAAAAAAAAAAAAD2DgAAb3JnL2dyYWRsZS9jbGkvQ29tbWFuZExpbmVBcmd1bWVudEV4Y2VwdGlvbi5jbGFzc1VUBQABAAAAAFBLAQIUABQACAgIAAAAIQBsZK5NbgIAALMDAAAmAAkAAAAAAAAAAAAAAIAQAABvcmcvZ3JhZGxlL2NsaS9Db21tYW5kTGluZU9wdGlvbi5jbGFzc1VUBQABAAAAAFBLAQIUABQACAgIAAAAIQBrrAeZWwIAALYEAAAzAAkAAAAAAAAAAAAAAEsTAABvcmcvZ3JhZGxlL2NsaS9Db21tYW5kTGluZVBhcnNlciRBZnRlck9wdGlvbnMuY2xhc3NVVAUAAQAAAABQSwECFAAUAAgICAAAACEABUgOxC4DAABdBwAAPAAJAAAAAAAAAAAAAAAQFgAAb3JnL2dyYWRsZS9jbGkvQ29tbWFuZExpbmVQYXJzZXIkQmVmb3JlRmlyc3RTdWJDb21tYW5kLmNsYXNzVVQFAAEAAAAAUEsBAhQAFAAICAgAAAAhAO+A7pzcBgAAYg4AAD0ACQAAAAAAAAAAAAAAsRkAAG9yZy9ncmFkbGUvY2xpL0NvbW1hbmRMaW5lUGFyc2VyJEtub3duT3B0aW9uUGFyc2VyU3RhdGUuY2xhc3NVVAUAAQAAAABQSwECFAAUAAgICAAAACEAxIDBO00CAACXBAAAPAAJAAAAAAAAAAAAAAABIQAAb3JnL2dyYWRsZS9jbGkvQ29tbWFuZExpbmVQYXJzZXIkTWlzc2luZ09wdGlvbkFyZ1N0YXRlLmNsYXNzVVQFAAEAAAAAUEsBAhQAFAAICAgAAAAhAKUEGSPYAgAASgUAAD0ACQAAAAAAAAAAAAAAwSMAAG9yZy9ncmFkbGUvY2xpL0NvbW1hbmRMaW5lUGFyc2VyJE9wdGlvbkF3YXJlUGFyc2VyU3RhdGUuY2xhc3NVVAUAAQAAAABQSwECFAAUAAgICAAAACEAIjgzfKIBAAB9AgAAOAAJAAAAAAAAAAAAAAANJwAAb3JnL2dyYWRsZS9jbGkvQ29tbWFuZExpbmVQYXJzZXIkT3B0aW9uUGFyc2Vy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";
|
|
1132
|
+
const gradleWrapperProperties = "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.14.2-bin.zip\nnetworkTimeout=10000\nvalidateDistributionUrl=true\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n";
|
|
1133
|
+
const gradlewBat = `@rem
|
|
1134
|
+
@rem Copyright 2015 the original author or authors.
|
|
1135
|
+
@rem
|
|
1136
|
+
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
|
1137
|
+
@rem you may not use this file except in compliance with the License.
|
|
1138
|
+
@rem You may obtain a copy of the License at
|
|
1139
|
+
@rem
|
|
1140
|
+
@rem https://www.apache.org/licenses/LICENSE-2.0
|
|
1141
|
+
@rem
|
|
1142
|
+
@rem Unless required by applicable law or agreed to in writing, software
|
|
1143
|
+
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
|
1144
|
+
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1145
|
+
@rem See the License for the specific language governing permissions and
|
|
1146
|
+
@rem limitations under the License.
|
|
1147
|
+
@rem
|
|
1148
|
+
@rem SPDX-License-Identifier: Apache-2.0
|
|
1149
|
+
@rem
|
|
1150
|
+
|
|
1151
|
+
@if "%DEBUG%"=="" @echo off
|
|
1152
|
+
@rem ##########################################################################
|
|
1153
|
+
@rem
|
|
1154
|
+
@rem Gradle startup script for Windows
|
|
1155
|
+
@rem
|
|
1156
|
+
@rem ##########################################################################
|
|
1157
|
+
|
|
1158
|
+
@rem Set local scope for the variables with windows NT shell
|
|
1159
|
+
if "%OS%"=="Windows_NT" setlocal
|
|
1160
|
+
|
|
1161
|
+
set DIRNAME=%~dp0
|
|
1162
|
+
if "%DIRNAME%"=="" set DIRNAME=.
|
|
1163
|
+
@rem This is normally unused
|
|
1164
|
+
set APP_BASE_NAME=%~n0
|
|
1165
|
+
set APP_HOME=%DIRNAME%
|
|
1166
|
+
|
|
1167
|
+
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
|
1168
|
+
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
|
1169
|
+
|
|
1170
|
+
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
1171
|
+
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
|
1172
|
+
|
|
1173
|
+
@rem Find java.exe
|
|
1174
|
+
if defined JAVA_HOME goto findJavaFromJavaHome
|
|
1175
|
+
|
|
1176
|
+
set JAVA_EXE=java.exe
|
|
1177
|
+
%JAVA_EXE% -version >NUL 2>&1
|
|
1178
|
+
if %ERRORLEVEL% equ 0 goto execute
|
|
1179
|
+
|
|
1180
|
+
echo. 1>&2
|
|
1181
|
+
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
|
1182
|
+
echo. 1>&2
|
|
1183
|
+
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
|
1184
|
+
echo location of your Java installation. 1>&2
|
|
1185
|
+
|
|
1186
|
+
goto fail
|
|
1187
|
+
|
|
1188
|
+
:findJavaFromJavaHome
|
|
1189
|
+
set JAVA_HOME=%JAVA_HOME:"=%
|
|
1190
|
+
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|
1191
|
+
|
|
1192
|
+
if exist "%JAVA_EXE%" goto execute
|
|
1193
|
+
|
|
1194
|
+
echo. 1>&2
|
|
1195
|
+
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
|
1196
|
+
echo. 1>&2
|
|
1197
|
+
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
|
1198
|
+
echo location of your Java installation. 1>&2
|
|
1199
|
+
|
|
1200
|
+
goto fail
|
|
1201
|
+
|
|
1202
|
+
:execute
|
|
1203
|
+
@rem Setup the command line
|
|
1204
|
+
|
|
1205
|
+
set CLASSPATH=
|
|
1206
|
+
|
|
1207
|
+
|
|
1208
|
+
@rem Execute Gradle
|
|
1209
|
+
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar" %*
|
|
1210
|
+
|
|
1211
|
+
:end
|
|
1212
|
+
@rem End local scope for the variables with windows NT shell
|
|
1213
|
+
if %ERRORLEVEL% equ 0 goto mainEnd
|
|
1214
|
+
|
|
1215
|
+
:fail
|
|
1216
|
+
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
|
1217
|
+
rem the _cmd.exe /c_ return code!
|
|
1218
|
+
set EXIT_CODE=%ERRORLEVEL%
|
|
1219
|
+
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
|
1220
|
+
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
|
1221
|
+
exit /b %EXIT_CODE%
|
|
1222
|
+
|
|
1223
|
+
:mainEnd
|
|
1224
|
+
if "%OS%"=="Windows_NT" endlocal
|
|
1225
|
+
|
|
1226
|
+
:omega
|
|
1227
|
+
`;
|
|
1228
|
+
const gradlew = `#!/bin/sh
|
|
1229
|
+
|
|
1230
|
+
#
|
|
1231
|
+
# Copyright © 2015-2021 the original authors.
|
|
1232
|
+
#
|
|
1233
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
1234
|
+
# you may not use this file except in compliance with the License.
|
|
1235
|
+
# You may obtain a copy of the License at
|
|
1236
|
+
#
|
|
1237
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
|
1238
|
+
#
|
|
1239
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
1240
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
1241
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1242
|
+
# See the License for the specific language governing permissions and
|
|
1243
|
+
# limitations under the License.
|
|
1244
|
+
#
|
|
1245
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
1246
|
+
#
|
|
1247
|
+
|
|
1248
|
+
##############################################################################
|
|
1249
|
+
#
|
|
1250
|
+
# Gradle start up script for POSIX generated by Gradle.
|
|
1251
|
+
#
|
|
1252
|
+
# Important for running:
|
|
1253
|
+
#
|
|
1254
|
+
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
|
1255
|
+
# noncompliant, but you have some other compliant shell such as ksh or
|
|
1256
|
+
# bash, then to run this script, type that shell name before the whole
|
|
1257
|
+
# command line, like:
|
|
1258
|
+
#
|
|
1259
|
+
# ksh Gradle
|
|
1260
|
+
#
|
|
1261
|
+
# Busybox and similar reduced shells will NOT work, because this script
|
|
1262
|
+
# requires all of these POSIX shell features:
|
|
1263
|
+
# * functions;
|
|
1264
|
+
# * expansions «$var», «\${var}», «\${var:-default}», «\${var+SET}»,
|
|
1265
|
+
# «\${var#prefix}», «\${var%suffix}», and «$( cmd )»;
|
|
1266
|
+
# * compound commands having a testable exit status, especially «case»;
|
|
1267
|
+
# * various built-in commands including «command», «set», and «ulimit».
|
|
1268
|
+
#
|
|
1269
|
+
# Important for patching:
|
|
1270
|
+
#
|
|
1271
|
+
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
|
1272
|
+
# by Bash, Ksh, etc; in particular arrays are avoided.
|
|
1273
|
+
#
|
|
1274
|
+
# The "traditional" practice of packing multiple parameters into a
|
|
1275
|
+
# space-separated string is a well documented source of bugs and security
|
|
1276
|
+
# problems, so this is (mostly) avoided, by progressively accumulating
|
|
1277
|
+
# options in "$@", and eventually passing that to Java.
|
|
1278
|
+
#
|
|
1279
|
+
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
|
1280
|
+
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
|
1281
|
+
# see the in-line comments for details.
|
|
1282
|
+
#
|
|
1283
|
+
# There are tweaks for specific operating systems such as AIX, CygWin,
|
|
1284
|
+
# Darwin, MinGW, and NonStop.
|
|
1285
|
+
#
|
|
1286
|
+
# (3) This script is generated from the Groovy template
|
|
1287
|
+
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
|
1288
|
+
# within the Gradle project.
|
|
1289
|
+
#
|
|
1290
|
+
# You can find Gradle at https://github.com/gradle/gradle/.
|
|
1291
|
+
#
|
|
1292
|
+
##############################################################################
|
|
1293
|
+
|
|
1294
|
+
# Attempt to set APP_HOME
|
|
1295
|
+
|
|
1296
|
+
# Resolve links: $0 may be a link
|
|
1297
|
+
app_path=$0
|
|
1298
|
+
|
|
1299
|
+
# Need this for daisy-chained symlinks.
|
|
1300
|
+
while
|
|
1301
|
+
APP_HOME=\${app_path%"\${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
|
1302
|
+
[ -h "$app_path" ]
|
|
1303
|
+
do
|
|
1304
|
+
ls=$( ls -ld "$app_path" )
|
|
1305
|
+
link=\${ls#*' -> '}
|
|
1306
|
+
case $link in #(
|
|
1307
|
+
/*) app_path=$link ;; #(
|
|
1308
|
+
*) app_path=$APP_HOME$link ;;
|
|
1309
|
+
esac
|
|
1310
|
+
done
|
|
1311
|
+
|
|
1312
|
+
# This is normally unused
|
|
1313
|
+
# shellcheck disable=SC2034
|
|
1314
|
+
APP_BASE_NAME=\${0##*/}
|
|
1315
|
+
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
|
1316
|
+
APP_HOME=$( cd -P "\${APP_HOME:-./}" > /dev/null && printf '%s\\n' "$PWD" ) || exit
|
|
1317
|
+
|
|
1318
|
+
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
|
1319
|
+
MAX_FD=maximum
|
|
1320
|
+
|
|
1321
|
+
warn () {
|
|
1322
|
+
echo "$*"
|
|
1323
|
+
} >&2
|
|
1324
|
+
|
|
1325
|
+
die () {
|
|
1326
|
+
echo
|
|
1327
|
+
echo "$*"
|
|
1328
|
+
echo
|
|
1329
|
+
exit 1
|
|
1330
|
+
} >&2
|
|
1331
|
+
|
|
1332
|
+
# OS specific support (must be 'true' or 'false').
|
|
1333
|
+
cygwin=false
|
|
1334
|
+
msys=false
|
|
1335
|
+
darwin=false
|
|
1336
|
+
nonstop=false
|
|
1337
|
+
case "$( uname )" in #(
|
|
1338
|
+
CYGWIN* ) cygwin=true ;; #(
|
|
1339
|
+
Darwin* ) darwin=true ;; #(
|
|
1340
|
+
MSYS* | MINGW* ) msys=true ;; #(
|
|
1341
|
+
NONSTOP* ) nonstop=true ;;
|
|
1342
|
+
esac
|
|
1343
|
+
|
|
1344
|
+
CLASSPATH="\\\\\\"\\\\\\""
|
|
1345
|
+
|
|
1346
|
+
|
|
1347
|
+
# Determine the Java command to use to start the JVM.
|
|
1348
|
+
if [ -n "$JAVA_HOME" ] ; then
|
|
1349
|
+
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
|
1350
|
+
# IBM's JDK on AIX uses strange locations for the executables
|
|
1351
|
+
JAVACMD=$JAVA_HOME/jre/sh/java
|
|
1352
|
+
else
|
|
1353
|
+
JAVACMD=$JAVA_HOME/bin/java
|
|
1354
|
+
fi
|
|
1355
|
+
if [ ! -x "$JAVACMD" ] ; then
|
|
1356
|
+
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
|
1357
|
+
|
|
1358
|
+
Please set the JAVA_HOME variable in your environment to match the
|
|
1359
|
+
location of your Java installation."
|
|
1360
|
+
fi
|
|
1361
|
+
else
|
|
1362
|
+
JAVACMD=java
|
|
1363
|
+
if ! command -v java >/dev/null 2>&1
|
|
1364
|
+
then
|
|
1365
|
+
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
1366
|
+
|
|
1367
|
+
Please set the JAVA_HOME variable in your environment to match the
|
|
1368
|
+
location of your Java installation."
|
|
1369
|
+
fi
|
|
1370
|
+
fi
|
|
1371
|
+
|
|
1372
|
+
# Increase the maximum file descriptors if we can.
|
|
1373
|
+
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|
1374
|
+
case $MAX_FD in #(
|
|
1375
|
+
max*)
|
|
1376
|
+
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
|
1377
|
+
# shellcheck disable=SC2039,SC3045
|
|
1378
|
+
MAX_FD=$( ulimit -H -n ) ||
|
|
1379
|
+
warn "Could not query maximum file descriptor limit"
|
|
1380
|
+
esac
|
|
1381
|
+
case $MAX_FD in #(
|
|
1382
|
+
'' | soft) :;; #(
|
|
1383
|
+
*)
|
|
1384
|
+
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
|
1385
|
+
# shellcheck disable=SC2039,SC3045
|
|
1386
|
+
ulimit -n "$MAX_FD" ||
|
|
1387
|
+
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
|
1388
|
+
esac
|
|
1389
|
+
fi
|
|
1390
|
+
|
|
1391
|
+
# Collect all arguments for the java command, stacking in reverse order:
|
|
1392
|
+
# * args from the command line
|
|
1393
|
+
# * the main class name
|
|
1394
|
+
# * -classpath
|
|
1395
|
+
# * -D...appname settings
|
|
1396
|
+
# * --module-path (only if needed)
|
|
1397
|
+
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
|
1398
|
+
|
|
1399
|
+
# For Cygwin or MSYS, switch paths to Windows format before running java
|
|
1400
|
+
if "$cygwin" || "$msys" ; then
|
|
1401
|
+
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
|
1402
|
+
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
|
1403
|
+
|
|
1404
|
+
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
|
1405
|
+
|
|
1406
|
+
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
|
1407
|
+
for arg do
|
|
1408
|
+
if
|
|
1409
|
+
case $arg in #(
|
|
1410
|
+
-*) false ;; # don't mess with options #(
|
|
1411
|
+
/?*) t=\${arg#/} t=/\${t%%/*} # looks like a POSIX filepath
|
|
1412
|
+
[ -e "$t" ] ;; #(
|
|
1413
|
+
*) false ;;
|
|
1414
|
+
esac
|
|
1415
|
+
then
|
|
1416
|
+
arg=$( cygpath --path --ignore --mixed "$arg" )
|
|
1417
|
+
fi
|
|
1418
|
+
# Roll the args list around exactly as many times as the number of
|
|
1419
|
+
# args, so each arg winds up back in the position where it started, but
|
|
1420
|
+
# possibly modified.
|
|
1421
|
+
#
|
|
1422
|
+
# NB: a \`for\` loop captures its iteration list before it begins, so
|
|
1423
|
+
# changing the positional parameters here affects neither the number of
|
|
1424
|
+
# iterations, nor the values presented in \`arg\`.
|
|
1425
|
+
shift # remove old arg
|
|
1426
|
+
set -- "$@" "$arg" # push replacement arg
|
|
1427
|
+
done
|
|
1428
|
+
fi
|
|
1429
|
+
|
|
1430
|
+
|
|
1431
|
+
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
1432
|
+
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|
1433
|
+
|
|
1434
|
+
# Collect all arguments for the java command:
|
|
1435
|
+
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
|
1436
|
+
# and any embedded shellness will be escaped.
|
|
1437
|
+
# * For example: A user cannot expect \${Hostname} to be expanded, as it is an environment variable and will be
|
|
1438
|
+
# treated as '\${Hostname}' itself on the command line.
|
|
1439
|
+
|
|
1440
|
+
set -- \\
|
|
1441
|
+
"-Dorg.gradle.appname=$APP_BASE_NAME" \\
|
|
1442
|
+
-classpath "$CLASSPATH" \\
|
|
1443
|
+
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \\
|
|
1444
|
+
"$@"
|
|
1445
|
+
|
|
1446
|
+
# Stop when "xargs" is not available.
|
|
1447
|
+
if ! command -v xargs >/dev/null 2>&1
|
|
1448
|
+
then
|
|
1449
|
+
die "xargs is not available"
|
|
1450
|
+
fi
|
|
1451
|
+
|
|
1452
|
+
# Use "xargs" to parse quoted args.
|
|
1453
|
+
#
|
|
1454
|
+
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
|
1455
|
+
#
|
|
1456
|
+
# In Bash we could simply go:
|
|
1457
|
+
#
|
|
1458
|
+
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
|
1459
|
+
# set -- "\${ARGS[@]}" "$@"
|
|
1460
|
+
#
|
|
1461
|
+
# but POSIX shell has neither arrays nor command substitution, so instead we
|
|
1462
|
+
# post-process each arg (as a line of input to sed) to backslash-escape any
|
|
1463
|
+
# character that might be a shell metacharacter, then use eval to reverse
|
|
1464
|
+
# that process (while maintaining the separation between arguments), and wrap
|
|
1465
|
+
# the whole thing up as a single "set" statement.
|
|
1466
|
+
#
|
|
1467
|
+
# This will of course break if any of these variables contains a newline or
|
|
1468
|
+
# an unmatched quote.
|
|
1469
|
+
#
|
|
1470
|
+
|
|
1471
|
+
eval "set -- $(
|
|
1472
|
+
printf '%s\\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
|
1473
|
+
xargs -n1 |
|
|
1474
|
+
sed ' s~[^-[:alnum:]+,./:=@_]~\\\\&~g; ' |
|
|
1475
|
+
tr '\\n' ' '
|
|
1476
|
+
)" '"$@"'
|
|
1477
|
+
|
|
1478
|
+
exec "$JAVACMD" "$@"
|
|
1479
|
+
`;
|
|
1480
|
+
function scaffoldGradleWrapper(_schematic, data) {
|
|
1481
|
+
kformScaffolder.addTemplateFile(data, "gradlew", gradlew, { executable: true });
|
|
1482
|
+
kformScaffolder.addTemplateFile(data, "gradlew.bat", gradlewBat);
|
|
1483
|
+
kformScaffolder.addTemplateFile(data, "gradle/wrapper/gradle-wrapper.jar", gradleWrapperJar, {
|
|
1484
|
+
base64: true
|
|
1485
|
+
});
|
|
1486
|
+
kformScaffolder.addTemplateFile(
|
|
1487
|
+
data,
|
|
1488
|
+
"gradle/wrapper/gradle-wrapper.properties",
|
|
1489
|
+
gradleWrapperProperties
|
|
1490
|
+
);
|
|
1491
|
+
}
|
|
1492
|
+
function scaffoldMain(schematic, data) {
|
|
1493
|
+
const fileName = kformScaffolder.joinPaths(data.currentDir, "main.tsx");
|
|
1494
|
+
let file = data.files.get(fileName);
|
|
1495
|
+
if (!file) {
|
|
1496
|
+
data.files.set(fileName, file = kformScaffolder.tsFile());
|
|
1497
|
+
}
|
|
1498
|
+
scaffoldMainFile(schematic, {
|
|
1499
|
+
kmpModuleName: `${kebabCase(schematic.name)}-shared`,
|
|
1500
|
+
...data,
|
|
1501
|
+
currentFile: file
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
function scaffoldMainFile(schematic, data) {
|
|
1505
|
+
data.currentFile.imports.push(
|
|
1506
|
+
{ moduleName: "./index.scss" },
|
|
1507
|
+
{ moduleName: "react-router-dom", name: "createHashRouter" }
|
|
1508
|
+
);
|
|
1509
|
+
data.currentFile.declarations.push(
|
|
1510
|
+
`const router = createHashRouter([${scaffoldRouteObject(schematic, data)}]);`
|
|
1511
|
+
);
|
|
1512
|
+
data.currentFile.imports.push(
|
|
1513
|
+
{ moduleName: "react-dom/client", name: "createRoot" },
|
|
1514
|
+
{ moduleName: "react", name: "StrictMode" },
|
|
1515
|
+
{ moduleName: "react-router-dom", name: "RouterProvider" },
|
|
1516
|
+
{
|
|
1517
|
+
moduleName: data.kmpModuleName,
|
|
1518
|
+
name: `decode${schematic.name}ExternalContextsFromString`
|
|
1519
|
+
},
|
|
1520
|
+
{
|
|
1521
|
+
moduleName: `./${schematic.name}Context.ts`,
|
|
1522
|
+
name: `${schematic.name}Context`
|
|
1523
|
+
}
|
|
1524
|
+
);
|
|
1525
|
+
data.currentFile.declarations.push(kformScaffolder.code`
|
|
1526
|
+
declare global {
|
|
1527
|
+
function render${schematic.name}App(): void;
|
|
1528
|
+
}
|
|
1529
|
+
globalThis.render${schematic.name}App = () => {
|
|
1530
|
+
const root = document.getElementById("${kebabCase(schematic.name)}-app-root")!;
|
|
1531
|
+
const externalContexts = decode${schematic.name}ExternalContextsFromString(
|
|
1532
|
+
root.dataset.externalContexts!,
|
|
1533
|
+
);
|
|
1534
|
+
|
|
1535
|
+
createRoot(root).render(
|
|
1536
|
+
<StrictMode>
|
|
1537
|
+
<${schematic.name}Context.Provider value={{ externalContexts }}>
|
|
1538
|
+
<RouterProvider router={router} />
|
|
1539
|
+
</${schematic.name}Context.Provider>
|
|
1540
|
+
</StrictMode>,
|
|
1541
|
+
);
|
|
1542
|
+
};
|
|
1543
|
+
`);
|
|
1544
|
+
}
|
|
1545
|
+
function scaffoldRouteObject(schematic, data) {
|
|
1546
|
+
const layout = reactAppLayout(schematic, data);
|
|
1547
|
+
const formPages = layout.flatMap((annex) => annex.formPages);
|
|
1548
|
+
data.currentFile.imports.push({
|
|
1549
|
+
moduleName: `./${schematic.name}App.tsx`,
|
|
1550
|
+
name: `${schematic.name}App`
|
|
1551
|
+
});
|
|
1552
|
+
for (const formPage of formPages) {
|
|
1553
|
+
data.currentFile.imports.push({
|
|
1554
|
+
moduleName: `./${kformScaffolder.joinPaths(
|
|
1555
|
+
formPage.data.currentDir.slice(
|
|
1556
|
+
data.currentDir.length + (data.currentDir.endsWith("/") ? 0 : 1)
|
|
1557
|
+
),
|
|
1558
|
+
pascalCase(formPage.schematic.name)
|
|
1559
|
+
)}.tsx`,
|
|
1560
|
+
name: pascalCase(formPage.schematic.name)
|
|
1561
|
+
});
|
|
1562
|
+
}
|
|
1563
|
+
const firstFormPage = formPages.find(
|
|
1564
|
+
(formPage) => !formPage.schematic.nullable && !formPage.data.currentPath.split("/").includes("*")
|
|
1565
|
+
);
|
|
1566
|
+
const routes = [
|
|
1567
|
+
firstFormPage && `{ path: "*", element: <${pascalCase(firstFormPage.schematic.name)} /> }`,
|
|
1568
|
+
...formPages.filter((formPage) => formPage !== firstFormPage).map(
|
|
1569
|
+
(formPage) => `{ path: "${formPage.data.currentPath.split("/").map((f) => f === "*" ? ":id" : f).join(
|
|
1570
|
+
"/"
|
|
1571
|
+
)}", element: <${pascalCase(formPage.schematic.name)} /> }`
|
|
1572
|
+
)
|
|
1573
|
+
];
|
|
1574
|
+
return kformScaffolder.code`
|
|
1575
|
+
{
|
|
1576
|
+
element: <${schematic.name}App />,
|
|
1577
|
+
children: [
|
|
1578
|
+
${routes.filter((r) => r).join(",\n")}
|
|
1579
|
+
]
|
|
1580
|
+
}
|
|
1581
|
+
`;
|
|
1582
|
+
}
|
|
1583
|
+
const editorconfig = "# http://editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_style = space\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[{*.kt,*.kts,*.md}]\nindent_size = 4\nmax_line_length = 100\n\n[{*.js,*.jsx,*.ts,*.tsx,*.json,*.html,*.css,*.scss,*.toml}]\nindent_size = 2\nmax_line_length = 80";
|
|
1584
|
+
const gitignore = "# Gradle\n.gradle/\nbuild/\n!**/src/**/build/\n\n# Kotlin\n.kotlin/\n\n# Node.js\nnode_modules/\n.npmrc\n\n# Typescript\n*.tsbuildinfo\n\n# Local env files\n.env*.local\n\n# Logs\nlogs\n*.log\n\n# IDEs and editors\n.vscode/\n.idea/\n.project\n.classpath\n.c9/\n*.launch\n.settings/\n*.sublime-workspace\nout/\n!**/src/**/out/\n\n# Misc\n.DS_Store\n*.pem\n";
|
|
1585
|
+
function scaffoldProjectMisc(_schematic, data) {
|
|
1586
|
+
kformScaffolder.addTemplateFile(data, ".gitignore", gitignore);
|
|
1587
|
+
kformScaffolder.addTemplateFile(data, ".editorconfig", editorconfig);
|
|
1588
|
+
}
|
|
1589
|
+
const responsesKt = 'package <%= filePackage %>\n\nimport io.kform.LocatedValidationIssue\nimport kotlin.js.JsExport\nimport kotlin.jvm.JvmOverloads\nimport kotlinx.serialization.SerialName\nimport kotlinx.serialization.Serializable\n\n@JsExport\n@Serializable\nsealed interface <%= formClass %>SubmitResponse\n\n@JsExport\n@Serializable\n@SerialName("success")\nclass <%= formClass %>SubmitSuccess(val redirectTo: String) : <%= formClass %>SubmitResponse\n\n@JsExport\n@Serializable\n@SerialName("error")\nclass <%= formClass %>SubmitError @JvmOverloads constructor(override val message: String? = null) :\n Throwable(message), <%= formClass %>SubmitResponse\n\n@JsExport\n@Serializable\n@SerialName("validationError")\nclass <%= formClass %>SubmitValidationError(val issues: List<LocatedValidationIssue>) :\n <%= formClass %>SubmitResponse\n';
|
|
1590
|
+
function scaffoldResponses(schematic, data) {
|
|
1591
|
+
const ejsData = {
|
|
1592
|
+
filePackage: data.currentPackage,
|
|
1593
|
+
formClass: schematic.name
|
|
1594
|
+
};
|
|
1595
|
+
kformScaffolder.addEjsTemplateFile(
|
|
1596
|
+
data,
|
|
1597
|
+
`${schematic.name}Responses.kt`,
|
|
1598
|
+
responsesKt,
|
|
1599
|
+
ejsData
|
|
1600
|
+
);
|
|
1601
|
+
}
|
|
1602
|
+
const jsonSerializerKt = "package <%= filePackage %>\n\nimport kotlin.js.JsExport\nimport kotlin.jvm.JvmOverloads\nimport kotlinx.serialization.json.Json\n\n/** Base JSON configuration. */\nprivate val JSON_CONFIG = Json.Default\n/** Pretty JSON configuration. */\nprivate val JSON_CONFIG_PRETTY = Json(JSON_CONFIG) { prettyPrint = true }\n\n/** JSON configuration. */\n@JvmOverloads\nfun jsonConfig(prettyPrint: Boolean = false): Json =\n if (prettyPrint) JSON_CONFIG_PRETTY else JSON_CONFIG\n\n/** Version of the serialization format. */\n@JsExport\nconst val <%= formConstant %>_SERIALIZATION_VERSION = 1\n\n@JsExport\n@JvmOverloads\nfun encode<%= formClass %>ToString(<%= formVar %>: <%= formClass %>, prettyPrint: Boolean = false): String =\n jsonConfig(prettyPrint).encodeToString(<%= formVar %>)\n\n@JsExport\nfun decode<%= formClass %>FromString(json: String): <%= formClass %> =\n jsonConfig().decodeFromString(json)\n\n@JvmOverloads\nfun encode<%= formClass %>ExternalContextsToString(externalContexts: <%= formClass %>ExternalContexts, prettyPrint: Boolean = false): String =\n jsonConfig(prettyPrint).encodeToString(externalContexts)\n\n@JsExport\nfun decode<%= formClass %>ExternalContextsFromString(json: String): <%= formClass %>ExternalContexts =\n jsonConfig().decodeFromString(json)\n\n@JvmOverloads\nfun encode<%= formClass %>SubmitResponseToString(response: <%= formClass %>SubmitResponse, prettyPrint: Boolean = false): String =\n jsonConfig(prettyPrint).encodeToString(response)\n\n@JsExport\nfun decode<%= formClass %>SubmitResponseFromString(json: String): <%= formClass %>SubmitResponse =\n jsonConfig().decodeFromString(json)\n";
|
|
1603
|
+
const xmlSerializerKt = "package <%= filePackage %>\n\nimport kotlin.js.JsExport\nimport kotlin.jvm.JvmOverloads\nimport kotlinx.serialization.decodeFromString\nimport kotlinx.serialization.encodeToString\nimport nl.adaptivity.xmlutil.ExperimentalXmlUtilApi\nimport nl.adaptivity.xmlutil.QName\nimport nl.adaptivity.xmlutil.XMLConstants\nimport nl.adaptivity.xmlutil.core.XmlVersion\nimport nl.adaptivity.xmlutil.serialization.DefaultXmlSerializationPolicy\nimport nl.adaptivity.xmlutil.serialization.OutputKind\nimport nl.adaptivity.xmlutil.serialization.XML\nimport nl.adaptivity.xmlutil.serialization.XmlSerializationPolicy\nimport nl.adaptivity.xmlutil.serialization.structure.SafeParentInfo\n\n/** Base XML configuration. */\nprivate val XML_CONFIG = XML {\n recommended_0_91_0 {\n xmlVersion = XmlVersion.XML10\n autoPolymorphic = false\n encodeDefault = XmlSerializationPolicy.XmlEncodeDefault.NEVER\n }\n\n // Set policy on top of the current policy config\n @OptIn(ExperimentalXmlUtilApi::class)\n policy =\n object : DefaultXmlSerializationPolicy(policy) {\n // Serialize properties as elements instead of attributes by default\n override val defaultPrimitiveOutputKind: OutputKind = OutputKind.Element\n\n // Use property names as serial names by default\n override fun effectiveName(\n serializerParent: SafeParentInfo,\n tagParent: SafeParentInfo,\n outputKind: OutputKind,\n useName: XmlSerializationPolicy.DeclaredNameInfo,\n ): QName =\n useName.annotatedName\n ?: serializerParent.elementTypeDescriptor.typeQname\n ?: QName(\n if (outputKind == OutputKind.Element) tagParent.namespace.namespaceURI\n else XMLConstants.NULL_NS_URI,\n useName.serialName,\n )\n }\n}\n/** Pretty XML configuration. */\nprivate val XML_CONFIG_PRETTY = XML_CONFIG.copy { indent = 4 }\n\n/** XML configuration. */\n@JvmOverloads\nfun xmlConfig(prettyPrint: Boolean = false): XML =\n if (prettyPrint) XML_CONFIG_PRETTY else XML_CONFIG\n\n/** Version of the serialization format. */\n@JsExport\nconst val <%= formConstant %>_SERIALIZATION_VERSION = 1\n\n@JsExport\n@JvmOverloads\nfun encode<%= formClass %>ToString(<%= formVar %>: <%= formClass %>, prettyPrint: Boolean = false): String =\n xmlConfig(prettyPrint).encodeToString(<%= formVar %>)\n\n@JsExport\nfun decode<%= formClass %>FromString(xml: String): <%= formClass %> =\n xmlConfig().decodeFromString(xml)\n\n@JvmOverloads\nfun encode<%= formClass %>ExternalContextsToString(externalContexts: <%= formClass %>ExternalContexts, prettyPrint: Boolean = false): String =\n xmlConfig(prettyPrint).encodeToString(externalContexts)\n\n@JsExport\nfun decode<%= formClass %>ExternalContextsFromString(xml: String): <%= formClass %>ExternalContexts =\n xmlConfig().decodeFromString(xml)\n\n@JvmOverloads\nfun encode<%= formClass %>SubmitResponseToString(response: <%= formClass %>SubmitResponse, prettyPrint: Boolean = false): String =\n xmlConfig(prettyPrint).encodeToString(response)\n\n@JsExport\nfun decode<%= formClass %>SubmitResponseFromString(xml: String): <%= formClass %>SubmitResponse =\n xmlConfig().decodeFromString(xml)\n";
|
|
1604
|
+
function scaffoldSerializer(schematic, data) {
|
|
1605
|
+
const ejsData = {
|
|
1606
|
+
filePackage: data.currentPackage,
|
|
1607
|
+
formVar: camelCase(schematic.name),
|
|
1608
|
+
formClass: schematic.name,
|
|
1609
|
+
formConstant: constantCase(schematic.name)
|
|
1610
|
+
};
|
|
1611
|
+
kformScaffolder.addEjsTemplateFile(
|
|
1612
|
+
data,
|
|
1613
|
+
`${schematic.name}Serializer.kt`,
|
|
1614
|
+
data.serializationFormat === "xml" ? xmlSerializerKt : jsonSerializerKt,
|
|
1615
|
+
ejsData
|
|
1616
|
+
);
|
|
1617
|
+
}
|
|
1618
|
+
const indexScss = '@use "@ostack.tech/ui/scss" as ostack-ui;\n@use "@ostack.tech/ui-kform/scss" as ostack-ui-kform;\n';
|
|
1619
|
+
function scaffoldStyles(_schematic, data) {
|
|
1620
|
+
kformScaffolder.addTemplateFile(data, "index.scss", indexScss);
|
|
1621
|
+
}
|
|
1622
|
+
const eslintConfigJs = 'import js from "@eslint/js";\nimport { defineConfig, globalIgnores } from "eslint/config";\nimport reactHooks from "eslint-plugin-react-hooks";\nimport reactRefresh from "eslint-plugin-react-refresh";\nimport globals from "globals";\nimport tseslint from "typescript-eslint";\n\nexport default defineConfig([\n globalIgnores([".gradle", "build"]),\n {\n files: ["**/*.{ts,tsx}"],\n extends: [\n js.configs.recommended,\n tseslint.configs.recommended,\n reactHooks.configs["recommended-latest"],\n reactRefresh.configs.vite,\n ],\n languageOptions: {\n ecmaVersion: 2020,\n globals: globals.browser,\n },\n },\n]);\n';
|
|
1623
|
+
const indexHtmlEjs = '<!doctype html>\n<html lang="en">\n <head>\n <meta charset="UTF-8" />\n <link rel="icon" type="image/svg+xml" href="/vite.svg" />\n <meta name="viewport" content="width=device-width, initial-scale=1.0" />\n <title><%= formTitle %></title>\n </head>\n <body>\n <div\n id="<%= formId %>-app-root"\n data-external-contexts="<%= externalContextsData %>"\n ></div>\n <script type="module" src="/src/main.tsx"><\/script>\n <script type="module">\n render<%= formClass %>App();\n <\/script>\n </body>\n</html>\n';
|
|
1624
|
+
const packageJsonEjs = '{\n "name": "<%= formId %>-react-app",\n "private": true,\n "version": "0.0.0",\n "type": "module",\n "scripts": {\n "dev": "vite",\n "build": "tsc -b && vite build",\n "lint": "eslint .",\n "preview": "vite preview"\n },\n "dependencies": {\n "@fortawesome/fontawesome-svg-core": "<%= dependencyVersions["@fortawesome/fontawesome-svg-core"] %>",\n "@fortawesome/free-regular-svg-icons": "<%= dependencyVersions["@fortawesome/free-regular-svg-icons"] %>",\n "@fortawesome/free-solid-svg-icons": "<%= dependencyVersions["@fortawesome/free-solid-svg-icons"] %>",\n "@ostack.tech/kform-react": "~<%= kFormVersion %>",\n "@ostack.tech/ui": "~<%= ostackUiVersion %>",\n "@ostack.tech/ui-kform": "~<%= ostackUiVersion %>",\n "date-fns": "<%= dependencyVersions["date-fns"] %>",\n "<%= formId %>-shared": "file:../shared/build/<%= formId %>-shared-0.0.1.tgz",\n "react": "<%= dependencyVersions.react %>",\n "react-dom": "<%= dependencyVersions["react-dom"] %>",\n "react-router": "<%= dependencyVersions["react-router"] %>",\n "react-router-dom": "<%= dependencyVersions["react-router-dom"] %>"\n },\n "devDependencies": {\n "@eslint/js": "<%= dependencyVersions["@eslint/js"] %>",\n "@types/node": "<%= dependencyVersions["@types/node"] %>",\n "@types/ostack.tech__kform": "npm:@ostack.tech/kform@~<%= kFormVersion %>",\n "@types/react": "<%= dependencyVersions["@types/react"] %>",\n "@types/react-dom": "<%= dependencyVersions["@types/react-dom"] %>",\n "@vitejs/plugin-react-swc": "<%= dependencyVersions["@vitejs/plugin-react-swc"] %>",\n "eslint": "<%= dependencyVersions.eslint %>",\n "eslint-plugin-react-hooks": "<%= dependencyVersions["eslint-plugin-react-hooks"] %>",\n "eslint-plugin-react-refresh": "<%= dependencyVersions["eslint-plugin-react-refresh"] %>",\n "globals": "<%= dependencyVersions.globals %>",\n "sass-embedded": "<%= dependencyVersions["sass-embedded"] %>",\n "typescript": "<%= dependencyVersions.typescript %>",\n "typescript-eslint": "<%= dependencyVersions["typescript-eslint"] %>",\n "vite": "<%= dependencyVersions.vite %>"\n }\n}\n';
|
|
1625
|
+
const viteSvg = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>\n';
|
|
1626
|
+
const tsConfigAppJson = '{\n "compilerOptions": {\n "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",\n "target": "ES2022",\n "useDefineForClassFields": true,\n "lib": ["ES2022", "DOM", "DOM.Iterable"],\n "module": "ESNext",\n "types": ["vite/client"],\n "skipLibCheck": true,\n\n /* Bundler mode */\n "moduleResolution": "bundler",\n "allowImportingTsExtensions": true,\n "verbatimModuleSyntax": true,\n "moduleDetection": "force",\n "noEmit": true,\n "jsx": "react-jsx",\n\n /* Linting */\n "strict": true,\n "noUnusedLocals": true,\n "noUnusedParameters": true,\n "erasableSyntaxOnly": true,\n "noFallthroughCasesInSwitch": true,\n "noUncheckedSideEffectImports": true\n },\n "include": ["src"]\n}\n';
|
|
1627
|
+
const tsConfigJson = '{\n "files": [],\n "references": [\n { "path": "./tsconfig.app.json" },\n { "path": "./tsconfig.node.json" }\n ]\n}\n';
|
|
1628
|
+
const tsConfigNodeJson = '{\n "compilerOptions": {\n "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",\n "target": "ES2023",\n "lib": ["ES2023"],\n "module": "ESNext",\n "types": ["node"],\n "skipLibCheck": true,\n\n /* Bundler mode */\n "moduleResolution": "bundler",\n "allowImportingTsExtensions": true,\n "verbatimModuleSyntax": true,\n "moduleDetection": "force",\n "noEmit": true,\n\n /* Linting */\n "strict": true,\n "noUnusedLocals": true,\n "noUnusedParameters": true,\n "erasableSyntaxOnly": true,\n "noFallthroughCasesInSwitch": true,\n "noUncheckedSideEffectImports": true\n },\n "include": ["vite.config.ts"]\n}\n';
|
|
1629
|
+
const viteConfigTsEjs = 'import path from "node:path";\n\nimport react from "@vitejs/plugin-react-swc";\nimport { defineConfig } from "vite";\n\n// https://vite.dev/config/\nexport default defineConfig({\n plugins: [react()],\n build: {\n outDir: "build/dist",\n rollupOptions: {\n input: {\n "<%= formId %>-app":\n process.env.VITE_BUILD_REASON === "preview"\n ? "index.html"\n : "src/main.tsx",\n },\n output: {\n // Output files without hashes, making it easier to serve them in the\n // server. However, the server is expected to somehow "version" them for\n // cache busting purposes.\n entryFileNames: `assets/[name].js`,\n chunkFileNames: `assets/[name].js`,\n assetFileNames: `assets/[name].[ext]`,\n },\n },\n },\n resolve: {\n alias: [\n // Due to how Kotlin "bundles" dependencies, we need to use the\n // `@ostack.tech/kform` produced by the shared module.\n {\n find: "@ostack.tech/kform",\n replacement: path.resolve(\n import.meta.dirname,\n `node_modules/<%= formId %>-shared/ostack-kform.mjs`,\n ),\n },\n ],\n },\n server: {\n proxy: { "/api": "http://127.0.0.1:8080" },\n },\n});\n';
|
|
1630
|
+
function scaffoldViteProject(schematic, data) {
|
|
1631
|
+
const ejsData = {
|
|
1632
|
+
formId: kebabCase(schematic.name),
|
|
1633
|
+
formClass: schematic.name,
|
|
1634
|
+
formTitle: capitalCase(schematic.name),
|
|
1635
|
+
ostackUiVersion: "0.1.0",
|
|
1636
|
+
kFormVersion: "0.31.0",
|
|
1637
|
+
dependencyVersions: JSON.parse('{"@eslint/js":"^9.37.0","@fortawesome/fontawesome-svg-core":"^7.1.0","@fortawesome/free-brands-svg-icons":"^7.1.0","@fortawesome/free-regular-svg-icons":"^7.1.0","@fortawesome/free-solid-svg-icons":"^7.1.0","@ostack.tech/kform":"~0.31.0","@ostack.tech/kform-react":"~0.31.0","@ostack.tech/kform-scaffolder":"~0.31.0","@storybook/addon-docs":"^9.1.10","@storybook/addon-links":"^9.1.10","@storybook/react-vite":"^9.1.10","@types/node":"^22.18.9","@types/react":"^19.2.2","@types/react-dom":"^19.2.1","@vitejs/plugin-react-swc":"^4.1.0","colorjs.io":"^0.5.2","cpy-cli":"^6.0.0","date-fns":"^4.1.0","eslint":"^9.37.0","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.4","eslint-plugin-react-hooks":"^6.1.1","eslint-plugin-react-refresh":"^0.4.23","eslint-plugin-simple-import-sort":"^12.1.1","eslint-plugin-storybook":"^9.1.10","globals":"^16.4.0","happy-dom":"^20.0.0","http-server":"^14.1.1","lint-staged":"^16.2.3","prettier":"^3.6.2","prettier-plugin-jsdoc":"^1.3.3","react":"^19.2.0","react-dom":"^19.2.0","react-router":"^7.9.4","react-router-dom":"^7.9.4","rimraf":"^6.0.1","sass-embedded":"^1.93.2","simple-git-hooks":"^2.13.1","storybook":"^9.1.10","tslib":"^2.8.1","typescript":"~5.9.3","typescript-eslint":"^8.46.0","vite":"^7.1.9","vitest":"^3.2.4","zustand":"^5.0.8"}'),
|
|
1638
|
+
externalContextsData: data.serializationFormat === "json" ? "{}" : `<${schematic.name}ExternalContexts />`
|
|
1639
|
+
};
|
|
1640
|
+
kformScaffolder.addEjsTemplateFile(data, "react-app/package.json", packageJsonEjs, ejsData);
|
|
1641
|
+
kformScaffolder.addEjsTemplateFile(
|
|
1642
|
+
data,
|
|
1643
|
+
"react-app/vite.config.ts",
|
|
1644
|
+
viteConfigTsEjs,
|
|
1645
|
+
ejsData
|
|
1646
|
+
);
|
|
1647
|
+
kformScaffolder.addTemplateFile(data, "react-app/tsconfig.json", tsConfigJson);
|
|
1648
|
+
kformScaffolder.addTemplateFile(data, "react-app/tsconfig.app.json", tsConfigAppJson);
|
|
1649
|
+
kformScaffolder.addTemplateFile(data, "react-app/tsconfig.node.json", tsConfigNodeJson);
|
|
1650
|
+
kformScaffolder.addTemplateFile(data, "react-app/eslint.config.js", eslintConfigJs);
|
|
1651
|
+
kformScaffolder.addEjsTemplateFile(data, "react-app/index.html", indexHtmlEjs, ejsData);
|
|
1652
|
+
kformScaffolder.addTemplateFile(data, "react-app/public/vite.svg", viteSvg);
|
|
1653
|
+
}
|
|
1654
|
+
const kotlinMainData = {
|
|
1655
|
+
currentDir: "shared/src/commonMain/kotlin"
|
|
1656
|
+
};
|
|
1657
|
+
const kotlinTestData = {
|
|
1658
|
+
currentDir: "shared/src/commonTest/kotlin"
|
|
1659
|
+
};
|
|
1660
|
+
const reactAppData = {
|
|
1661
|
+
currentDir: "react-app/src"
|
|
1662
|
+
};
|
|
1663
|
+
function SchematicBuilder({
|
|
1664
|
+
name = "ostack-ui-kform",
|
|
1665
|
+
schematicKinds = defaultSchematicKinds,
|
|
1666
|
+
scaffolders = [
|
|
1667
|
+
scaffoldProjectMisc,
|
|
1668
|
+
scaffoldGradleWrapper,
|
|
1669
|
+
scaffoldGradleProject,
|
|
1670
|
+
scaffoldViteProject,
|
|
1671
|
+
kformScaffolder.configScaffolder(kformScaffolder.scaffoldSchemas, kotlinMainData),
|
|
1672
|
+
kformScaffolder.configScaffolder(kformScaffolder.scaffoldModels, kotlinMainData),
|
|
1673
|
+
kformScaffolder.configScaffolder(scaffoldResponses, kotlinMainData),
|
|
1674
|
+
kformScaffolder.configScaffolder(scaffoldExternalContexts, kotlinMainData),
|
|
1675
|
+
kformScaffolder.configScaffolder(scaffoldSerializer, kotlinMainData),
|
|
1676
|
+
kformScaffolder.configScaffolder(kformScaffolder.scaffoldValidator, kotlinTestData),
|
|
1677
|
+
kformScaffolder.configScaffolder(scaffoldMain, reactAppData),
|
|
1678
|
+
kformScaffolder.configScaffolder(scaffoldStyles, reactAppData),
|
|
1679
|
+
kformScaffolder.configScaffolder(scaffoldAppComponent, reactAppData),
|
|
1680
|
+
kformScaffolder.configScaffolder(scaffoldAppContext, reactAppData),
|
|
1681
|
+
kformScaffolder.configScaffolder(scaffoldActions, reactAppData),
|
|
1682
|
+
kformScaffolder.configScaffolder(scaffoldApi, reactAppData),
|
|
1683
|
+
kformScaffolder.configScaffolder(scaffoldFormPages, reactAppData)
|
|
1684
|
+
],
|
|
1685
|
+
scaffoldingData = (schematic) => ({
|
|
1686
|
+
useFileBase64Serializer: true,
|
|
1687
|
+
...schematic.config
|
|
1688
|
+
}),
|
|
1689
|
+
configs = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1690
|
+
/* @__PURE__ */ jsxRuntime.jsx(SerializationFormatConfig, {}),
|
|
1691
|
+
/* @__PURE__ */ jsxRuntime.jsx(UseTableValuesSerializerConfig, {})
|
|
1692
|
+
] }),
|
|
1693
|
+
...otherProps
|
|
1694
|
+
}) {
|
|
1695
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1696
|
+
kformScaffolder.SchematicBuilder,
|
|
1697
|
+
{
|
|
1698
|
+
name,
|
|
1699
|
+
schematicKinds,
|
|
1700
|
+
scaffolders,
|
|
1701
|
+
scaffoldingData,
|
|
1702
|
+
configs,
|
|
1703
|
+
...otherProps
|
|
1704
|
+
}
|
|
1705
|
+
);
|
|
1706
|
+
}
|
|
1707
|
+
exports.SchematicBuilder = SchematicBuilder;
|
|
1708
|
+
exports.SerializationFormatConfig = SerializationFormatConfig;
|
|
1709
|
+
exports.UseTableValuesSerializerConfig = UseTableValuesSerializerConfig;
|
|
1710
|
+
exports.anySchematicKind = anySchematicKind;
|
|
1711
|
+
exports.bigDecimalSchematicKind = bigDecimalSchematicKind;
|
|
1712
|
+
exports.bigIntegerSchematicKind = bigIntegerSchematicKind;
|
|
1713
|
+
exports.booleanSchematicKind = booleanSchematicKind;
|
|
1714
|
+
exports.byteSchematicKind = byteSchematicKind;
|
|
1715
|
+
exports.classAnnexSchematicKind = classAnnexSchematicKind;
|
|
1716
|
+
exports.classFormPageSchematicKind = classFormPageSchematicKind;
|
|
1717
|
+
exports.classSchematicKind = classSchematicKind;
|
|
1718
|
+
exports.defaultSchematicKinds = defaultSchematicKinds;
|
|
1719
|
+
exports.doubleSchematicKind = doubleSchematicKind;
|
|
1720
|
+
exports.enumRadioGroupSchematicKind = enumRadioGroupSchematicKind;
|
|
1721
|
+
exports.enumSchematicKind = enumSchematicKind;
|
|
1722
|
+
exports.enumSelectSchematicKind = enumSelectSchematicKind;
|
|
1723
|
+
exports.fileSchematicKind = fileSchematicKind;
|
|
1724
|
+
exports.floatSchematicKind = floatSchematicKind;
|
|
1725
|
+
exports.intSchematicKind = intSchematicKind;
|
|
1726
|
+
exports.listCheckboxGroupSchematicKind = listCheckboxGroupSchematicKind;
|
|
1727
|
+
exports.listSelectMultipleSchematicKind = listSelectMultipleSchematicKind;
|
|
1728
|
+
exports.localDateSchematicKind = localDateSchematicKind;
|
|
1729
|
+
exports.longSchematicKind = longSchematicKind;
|
|
1730
|
+
exports.reactAppLayout = reactAppLayout;
|
|
1731
|
+
exports.scaffoldActions = scaffoldActions;
|
|
1732
|
+
exports.scaffoldAnnexesArray = scaffoldAnnexesArray;
|
|
1733
|
+
exports.scaffoldApi = scaffoldApi;
|
|
1734
|
+
exports.scaffoldAppComponent = scaffoldAppComponent;
|
|
1735
|
+
exports.scaffoldAppContext = scaffoldAppContext;
|
|
1736
|
+
exports.scaffoldExternalContexts = scaffoldExternalContexts;
|
|
1737
|
+
exports.scaffoldField = scaffoldField;
|
|
1738
|
+
exports.scaffoldFormPages = scaffoldFormPages;
|
|
1739
|
+
exports.scaffoldFormPagesByAnnexObject = scaffoldFormPagesByAnnexObject;
|
|
1740
|
+
exports.scaffoldGradleProject = scaffoldGradleProject;
|
|
1741
|
+
exports.scaffoldGradleWrapper = scaffoldGradleWrapper;
|
|
1742
|
+
exports.scaffoldIssueMessages = scaffoldIssueMessages;
|
|
1743
|
+
exports.scaffoldMain = scaffoldMain;
|
|
1744
|
+
exports.scaffoldProjectMisc = scaffoldProjectMisc;
|
|
1745
|
+
exports.scaffoldResponses = scaffoldResponses;
|
|
1746
|
+
exports.scaffoldRouteObject = scaffoldRouteObject;
|
|
1747
|
+
exports.scaffoldSerializer = scaffoldSerializer;
|
|
1748
|
+
exports.scaffoldStyles = scaffoldStyles;
|
|
1749
|
+
exports.scaffoldViteProject = scaffoldViteProject;
|
|
1750
|
+
exports.shortSchematicKind = shortSchematicKind;
|
|
1751
|
+
exports.stringSchematicKind = stringSchematicKind;
|
|
1752
|
+
exports.tableAnnexesSchematicKind = tableAnnexesSchematicKind;
|
|
1753
|
+
exports.tableSchematicKind = tableSchematicKind;
|
|
1754
|
+
//# sourceMappingURL=ostack-ui-kform-scaffolder.cjs.map
|