@ostack.tech/ui-kform-scaffolder 0.3.4 → 0.4.1

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.
@@ -139,78 +139,55 @@ function scaffoldIssueMessagesConstant(schematic, data) {
139
139
  export const ${constantCase(schematic.name)}_ISSUE_MESSAGES: Record<string, IssueMessagesByCode> = {};
140
140
  `);
141
141
  }
142
- function scaffoldFormPages(schematic, data) {
142
+ function scaffoldPageComponents(schematic, data) {
143
143
  const layout = reactAppLayout(schematic, {
144
144
  kmpModuleName: `${kebabCase(schematic.name)}-shared`,
145
145
  ...data
146
146
  });
147
147
  for (const annex of layout) {
148
148
  for (const formPage of annex.formPages) {
149
- scaffoldFormPage(formPage.schematic, formPage.data);
149
+ scaffoldPageComponent(formPage.schematic, formPage.data);
150
150
  if (formPage.data.currentPath !== "/") {
151
151
  scaffoldIssueMessages(formPage.schematic, formPage.data);
152
152
  }
153
153
  }
154
154
  }
155
155
  }
156
- function scaffoldFormPage(schematic, data) {
156
+ function scaffoldPageComponent(schematic, data) {
157
157
  const fileName = joinPaths(data.currentDir, `${schematic.name}.tsx`);
158
158
  let file = data.files.get(fileName);
159
159
  if (!file) {
160
160
  data.files.set(fileName, file = tsFile());
161
161
  }
162
- scaffoldFormPageComponent(schematic, {
162
+ scaffoldPageComponentDeclarations(schematic, {
163
163
  kmpModuleName: `${kebabCase(data.rootSchematic.name)}-shared`,
164
164
  ...data,
165
165
  currentFile: file
166
166
  });
167
167
  }
168
- function scaffoldFormPageComponent(schematic, data) {
169
- data.currentFile.imports.push(
170
- { moduleName: "@ostack.tech/ui-kform", name: "FormPage" },
171
- { moduleName: "@ostack.tech/ui", name: "Grid" }
172
- );
173
- if (data.currentPath !== "/") {
174
- data.currentFile.imports.push({
175
- moduleName: `./${schematic.name}IssueMessages.tsx`,
176
- name: `${constantCase(schematic.name)}_ISSUE_MESSAGES`
177
- });
178
- }
179
- let pathString;
180
- let preamble;
181
- const splitPath = data.currentPath.split("/");
182
- if (splitPath.some((fragment) => fragment === "*")) {
183
- data.currentFile.imports.push({
184
- moduleName: "react-router",
185
- name: "useParams"
186
- });
187
- pathString = `{\`${splitPath.map((f) => f === "*" ? "${id}" : f).join("/")}\`}`;
188
- preamble = "\n const { id } = useParams();\n";
189
- } else {
190
- pathString = `"${data.currentPath}"`;
191
- preamble = "";
192
- }
193
- const pageComponent = code`
194
- export function ${schematic.name}() {${preamble}
168
+ function scaffoldPageComponentDeclarations(schematic, data) {
169
+ data.currentFile.imports.push({
170
+ moduleName: "@ostack.tech/ui",
171
+ name: "Grid"
172
+ });
173
+ data.currentFile.declarations.push(code`
174
+ export function ${schematic.name}() {
195
175
  return (
196
- <FormPage${data.currentPath === "/" ? "" : ` path=${pathString} issueMessages={${constantCase(schematic.name)}_ISSUE_MESSAGES}`}>
197
- <Grid container>
198
- ${schematic.children.map(
176
+ <Grid container>
177
+ ${schematic.children.map(
199
178
  (child) => code`
200
- <Grid xs={12}>
201
- ${scaffoldField(child, {
179
+ <Grid xs={12}>
180
+ ${scaffoldField(child, {
202
181
  ...data,
203
182
  currentPath: child.childName
204
183
  })}
205
- </Grid>
206
- `
184
+ </Grid>
185
+ `
207
186
  ).join("\n\n")}
208
- </Grid>
209
- </FormPage>
187
+ </Grid>
210
188
  );
211
189
  }
212
- `;
213
- data.currentFile.declarations.push(pageComponent);
190
+ `);
214
191
  }
215
192
  function scaffoldField(schematic, data) {
216
193
  const schematicKind = data.schematicKinds.get(
@@ -753,6 +730,7 @@ function layoutAnnex(schematic, data) {
753
730
  }
754
731
  return { schematic, data, formPages };
755
732
  }
733
+ const DEFAULT_ACTIVE_PATH_SEARCH_PARAM = "activePath";
756
734
  function scaffoldAppComponent(schematic, data) {
757
735
  const fileName = joinPaths(data.currentDir, `${schematic.name}App.tsx`);
758
736
  let file = data.files.get(fileName);
@@ -768,10 +746,19 @@ function scaffoldAppComponent(schematic, data) {
768
746
  }
769
747
  function scaffoldAppComponentFile(schematic, data) {
770
748
  const localeVar = (data.defaultLocale ?? DEFAULT_LOCALE).replaceAll("-", "");
749
+ const activePathSearchParam = data.activePathSearchParam ?? DEFAULT_ACTIVE_PATH_SEARCH_PARAM;
771
750
  data.currentFile.imports.push(
772
751
  { moduleName: "@ostack.tech/kform", name: "ktMapToObject" },
752
+ { moduleName: "@ostack.tech/ui", name: "useSearchParam" },
773
753
  { moduleName: "@ostack.tech/ui-kform", name: "FormApp" },
774
754
  { moduleName: "@ostack.tech/ui-kform", name: localeVar },
755
+ { moduleName: "@ostack.tech/ui-kform", name: "TopBar" },
756
+ { moduleName: "@ostack.tech/ui-kform", name: "TopBarActions" },
757
+ { moduleName: "@ostack.tech/ui-kform", name: "Annexes" },
758
+ { moduleName: "@ostack.tech/ui-kform", name: "Annex" },
759
+ { moduleName: "@ostack.tech/ui-kform", name: "FormPages" },
760
+ { moduleName: "@ostack.tech/ui-kform", name: "FormPage" },
761
+ { moduleName: "@ostack.tech/ui-kform", name: "IssuesPanel" },
775
762
  { moduleName: "react", name: "useMemo" },
776
763
  { moduleName: data.kmpModuleName, name: schematic.name },
777
764
  { moduleName: data.kmpModuleName, name: `${schematic.name}FormMode` },
@@ -784,11 +771,25 @@ function scaffoldAppComponentFile(schematic, data) {
784
771
  {
785
772
  moduleName: `./${schematic.name}IssueMessages.tsx`,
786
773
  name: `${constantCase(schematic.name)}_ISSUE_MESSAGES`
787
- }
774
+ },
775
+ { moduleName: "./actions/Load.tsx", name: "Load" },
776
+ { moduleName: "./actions/Save.tsx", name: "Save" },
777
+ { moduleName: "./actions/Validate.tsx", name: "Validate" },
778
+ { moduleName: "./actions/Submit.tsx", name: "Submit" }
788
779
  );
780
+ const layout = reactAppLayout(schematic, data);
781
+ let annexesManager = "";
782
+ if (layout.length > 1) {
783
+ data.currentFile.imports.push({
784
+ moduleName: "@ostack.tech/ui-kform",
785
+ name: "AnnexesManager"
786
+ });
787
+ annexesManager = "\n <AnnexesManager />\n";
788
+ }
789
789
  data.currentFile.declarations.push(code`
790
790
  export function ${schematic.name}App() {
791
791
  const { externalContexts } = use${schematic.name}Context();
792
+ const [activePath, setActivePath] = useSearchParam("${activePathSearchParam}");
792
793
 
793
794
  return (
794
795
  <FormApp
@@ -807,79 +808,13 @@ function scaffoldAppComponentFile(schematic, data) {
807
808
  ? "manual"
808
809
  : "auto"
809
810
  }
811
+ activePath={activePath}
812
+ onActivePathChange={setActivePath}
810
813
  issueMessages={${constantCase(schematic.name)}_ISSUE_MESSAGES}
811
814
  defaultLocale={${localeVar}}
812
815
  reportError={reportError}
813
816
  >
814
- <${schematic.name}Layout />
815
- </FormApp>
816
- );
817
- }
818
- `);
819
- const layout = reactAppLayout(schematic, data);
820
- data.currentFile.imports.push(
821
- { moduleName: "react-router", name: "useNavigate" },
822
- { moduleName: "react-router", name: "useLocation" },
823
- { moduleName: "react-router", name: "Outlet" },
824
- { moduleName: "@ostack.tech/ui-kform", name: "Annexes" },
825
- { moduleName: "@ostack.tech/ui-kform", name: "Annex" },
826
- {
827
- moduleName: "@ostack.tech/ui-kform",
828
- name: "AnnexObject",
829
- isType: true
830
- },
831
- { moduleName: "@ostack.tech/ui-kform", name: "TopBar" },
832
- { moduleName: "@ostack.tech/ui-kform", name: "TopBarActions" },
833
- { moduleName: "./actions/Load.tsx", name: "Load" },
834
- { moduleName: "./actions/Save.tsx", name: "Save" },
835
- { moduleName: "./actions/Validate.tsx", name: "Validate" },
836
- { moduleName: "./actions/Submit.tsx", name: "Submit" },
837
- { moduleName: "@ostack.tech/ui-kform", name: "FormPages" },
838
- {
839
- moduleName: "@ostack.tech/ui-kform",
840
- name: "FormPageObject",
841
- isType: true
842
- },
843
- { moduleName: "@ostack.tech/ui-kform", name: "IssuesPanel" }
844
- );
845
- let annexesManager = "";
846
- if (layout.length > 1) {
847
- data.currentFile.imports.push({
848
- moduleName: "@ostack.tech/ui-kform",
849
- name: "AnnexesManager"
850
- });
851
- annexesManager = `
852
- <AnnexesManager />
853
- `;
854
- }
855
- let formPagesNavigation = "";
856
- if (layout.some((annex) => annex.formPages.length > 1)) {
857
- data.currentFile.imports.push({
858
- moduleName: "@ostack.tech/ui-kform",
859
- name: "FormPagesNavigation"
860
- });
861
- if (layout.every((annex) => annex.formPages.length > 1)) {
862
- formPagesNavigation = `
863
- <FormPagesNavigation />
864
- `;
865
- } else {
866
- formPagesNavigation = `
867
- {pages.length > 1 && <FormPagesNavigation />}
868
- `;
869
- }
870
- }
871
- data.currentFile.declarations.push(code`
872
- function ${schematic.name}Layout() {
873
- const navigate = useNavigate();
874
- const { pathname } = useLocation();
875
-
876
- const annexes: AnnexObject[] = useMemo(() => ${scaffoldAnnexesArray(layout)}, []);
877
-
878
- const pagesByAnnex: Record<string, FormPageObject[]> = useMemo(() => (${scaffoldFormPagesByAnnexObject(layout)}), []);
879
-
880
- return (
881
- <>
882
- <Annexes annexes={annexes} activeAnnex={pathname}>
817
+ <Annexes>
883
818
  <TopBar>${annexesManager}
884
819
  <TopBarActions>
885
820
  <Load />
@@ -889,64 +824,73 @@ function scaffoldAppComponentFile(schematic, data) {
889
824
  </TopBarActions>
890
825
  </TopBar>
891
826
 
892
- {Object.entries(pagesByAnnex).map(([annexPath, pages]) => (
893
- <Annex path={annexPath} key={annexPath}>
894
- <FormPages
895
- pages={pages}
896
- activePage={pathname}
897
- onActivePageChange={(activePage) => {
898
- const newPathname = activePage?.toString() ?? "/";
899
- if (pathname !== newPathname) {
900
- void navigate(newPathname, {
901
- replace: newPathname.startsWith(
902
- pathname.endsWith("/") ? pathname : \`\${pathname}/\`,
903
- )
904
- });
905
- }
906
- }}
907
- >${formPagesNavigation}
908
- <Outlet />
909
- </FormPages>
910
- </Annex>
911
- ))}
827
+ ${scaffoldAnnexes(layout, data)}
912
828
  </Annexes>
913
829
 
914
830
  <IssuesPanel />
915
- </>
831
+ </FormApp>
916
832
  );
917
833
  }
918
834
  `);
919
835
  }
920
- function scaffoldAnnexesArray(layout) {
836
+ function scaffoldAnnexes(layout, data) {
837
+ return layout.map((annex) => scaffoldAnnex(annex, data)).join("\n\n");
838
+ }
839
+ function scaffoldAnnex(annex, data) {
921
840
  return code`
922
- [
923
- ${layout.map(
924
- (annex) => `{ path: "${annex.data.currentPath}", title: "${sentenceCase(
925
- annex.schematic.name
926
- )}"${annex.formPages.length === 1 && annex.data.currentPath === annex.formPages[0].data.currentPath ? ", documentTitle: null" : ""} }`
927
- ).join(",\n")}
928
- ]
841
+ <Annex path="${annex.data.currentPath}" title="${sentenceCase(annex.schematic.name)}"${annex.formPages.length === 1 && annex.schematic === annex.formPages[0].schematic ? " documentTitle={null}" : ""}>
842
+ ${scaffoldFormPages(annex, data)}
843
+ </Annex>
929
844
  `;
930
845
  }
931
- function scaffoldFormPagesByAnnexObject(layout) {
846
+ function scaffoldFormPages(annex, data) {
847
+ let formPagesNavigation = "";
848
+ if (annex.formPages.length > 1) {
849
+ data.currentFile.imports.push({
850
+ moduleName: "@ostack.tech/ui-kform",
851
+ name: "FormPagesNavigation"
852
+ });
853
+ formPagesNavigation = "\n <FormPagesNavigation />\n";
854
+ }
932
855
  return code`
933
- {
934
- ${layout.map(
935
- (annex) => `"${annex.data.currentPath}": ` + code`
936
- [
937
- ${annex.formPages.map(
938
- (formPage) => annex.schematic === formPage.schematic ? `{ title: "${sentenceCase(
939
- formPage.schematic.name
940
- )}", code: "${formPage.schematic.name?.[0].toUpperCase()}"${formPage.data.currentPath === "/" ? ", documentTitle: null" : ""} }` : `{ path: "${formPage.data.currentPath.slice(
941
- annex.data.currentPath.length + (annex.data.currentPath.endsWith("/") ? 0 : 1)
942
- )}", title: "${sentenceCase(
856
+ <FormPages>${formPagesNavigation}
857
+ ${annex.formPages.map((formPage) => scaffoldFormPage(annex, formPage, data)).join("\n\n")}
858
+ </FormPages>
859
+ `;
860
+ }
861
+ function scaffoldFormPage(annex, formPage, data) {
862
+ data.currentFile.imports.push({
863
+ moduleName: `./${joinPaths(
864
+ formPage.data.currentDir.slice(
865
+ data.currentDir.length + (data.currentDir.endsWith("/") ? 0 : 1)
866
+ ),
867
+ formPage.schematic.name
868
+ )}.tsx`,
869
+ name: formPage.schematic.name
870
+ });
871
+ let issueMessagesProp = "";
872
+ if (formPage.data.currentPath !== "/") {
873
+ data.currentFile.imports.push({
874
+ moduleName: `./${joinPaths(
875
+ formPage.data.currentDir.slice(
876
+ data.currentDir.length + (data.currentDir.endsWith("/") ? 0 : 1)
877
+ ),
943
878
  formPage.schematic.name
944
- )}", code: "${formPage.schematic.name?.[0].toUpperCase()}" }`
945
- ).join(",\n")}
946
- ]
947
- `
948
- ).join(",\n")}
949
- }
879
+ )}IssueMessages.tsx`,
880
+ name: `${constantCase(formPage.schematic.name)}_ISSUE_MESSAGES`
881
+ });
882
+ issueMessagesProp = ` issueMessages={${constantCase(formPage.schematic.name)}_ISSUE_MESSAGES}`;
883
+ }
884
+ const pathProp = annex.schematic === formPage.schematic ? "" : ` path="${formPage.data.currentPath.slice(
885
+ annex.data.currentPath.length + (annex.data.currentPath.endsWith("/") ? 0 : 1)
886
+ )}"`;
887
+ const documentTitleProp = formPage.data.currentPath === "/" ? " documentTitle={null}" : "";
888
+ return code`
889
+ <FormPage${pathProp} title="${sentenceCase(
890
+ formPage.schematic.name
891
+ )}" code="${formPage.schematic.name?.[0].toUpperCase()}"${documentTitleProp}${issueMessagesProp}>
892
+ <${formPage.schematic.name} />
893
+ </FormPage>
950
894
  `;
951
895
  }
952
896
  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';
@@ -980,7 +924,7 @@ const gradlePropertiesEjs = "group=<%= gradlePropertiesGroup %>\nversion=0.0.1\n
980
924
  const libsVersionsTomlEjs = '[versions]\n# Plugins\nkotlin = "2.2.21"\nnodeGradle = "7.1.0"\n# Libraries\nkotlinxCoroutines = "1.10.2"\nkform = "<%= kFormVersion %>"\n<%_ if (includeKotlinxDatetime) { -%>\nkotlinxDatetime = "0.7.1"\n<%_ } -%>\n<%_ if (serializationFormat === "json") { -%>\nkotlinxSerialization = "1.9.0"\n<%_ } -%>\n<%_ if (includeKtMath) { -%>\nktMath = "0.10.2"\n<%_ } -%>\nslf4j = "2.0.17"\n<%_ if (serializationFormat === "xml") { -%>\nxmlutil = "0.91.1"\n<%_ } -%>\n# Runtimes\njvmToolchain = "<%= jvmToolchainVersion %>"\nnodejs = "<%= nodejsVersion %>"\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 (includeKotlinxDatetime) { -%>\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 (includeKtMath) { -%>\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';
981
925
  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';
982
926
  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';
983
- 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 (includeKotlinxDatetime) { -%>\n api(libs.kotlinxDatetime)\n <%_ } -%>\n <%_ if (serializationFormat === "json") { -%>\n api(libs.kotlinxSerialization.json)\n <%_ } -%>\n <%_ if (includeKtMath) { -%>\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 (includeKotlinxDatetime) { -%>\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';
927
+ 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 (includeKotlinxDatetime) { -%>\n api(libs.kotlinxDatetime)\n <%_ } -%>\n <%_ if (serializationFormat === "json") { -%>\n api(libs.kotlinxSerialization.json)\n <%_ } -%>\n <%_ if (includeKtMath) { -%>\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 (includeKotlinxDatetime) { -%>\n implementation(npm("@js-joda/timezone", "2.3.0"))\n <%_ } -%>\n }\n }\n}\n\nnode {\n download = true\n version = libs.versions.nodejs.get()\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';
984
928
  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';
985
929
  const DEFAULT_JVM_TOOLCHAIN_VERSION = "17";
986
930
  const DEFAULT_NODEJS_VERSION = "22.20.0";
@@ -990,7 +934,7 @@ function scaffoldGradleProject(schematic, data) {
990
934
  filePackage: data.currentPackage,
991
935
  formId: kebabCase(schematic.name),
992
936
  formTitle: capitalCase(schematic.name),
993
- kFormVersion: "0.31.5",
937
+ kFormVersion: "0.31.6",
994
938
  serializationFormat: data.serializationFormat ?? "json",
995
939
  includeKotlinxDatetime: data.includeKotlinxDatetime ?? usesKotlinxDatetime(schematic, data),
996
940
  includeKtMath: data.includeKtMath ?? usesKtMath(schematic),
@@ -1406,24 +1350,17 @@ function scaffoldMain(schematic, data) {
1406
1350
  if (!file) {
1407
1351
  data.files.set(fileName, file = tsFile());
1408
1352
  }
1409
- scaffoldMainFile(schematic, {
1353
+ scaffoldMainDeclarations(schematic, {
1410
1354
  kmpModuleName: `${kebabCase(schematic.name)}-shared`,
1411
1355
  ...data,
1412
1356
  currentFile: file
1413
1357
  });
1414
1358
  }
1415
- function scaffoldMainFile(schematic, data) {
1359
+ function scaffoldMainDeclarations(schematic, data) {
1416
1360
  data.currentFile.imports.push(
1417
1361
  { moduleName: "./index.scss" },
1418
- { moduleName: "react-router-dom", name: "createHashRouter" }
1419
- );
1420
- data.currentFile.declarations.push(
1421
- `const router = createHashRouter([${scaffoldRouteObject(schematic, data)}]);`
1422
- );
1423
- data.currentFile.imports.push(
1424
- { moduleName: "react-dom/client", name: "createRoot" },
1425
1362
  { moduleName: "react", name: "StrictMode" },
1426
- { moduleName: "react-router-dom", name: "RouterProvider" },
1363
+ { moduleName: "react-dom/client", name: "createRoot" },
1427
1364
  {
1428
1365
  moduleName: data.kmpModuleName,
1429
1366
  name: `decode${schematic.name}ExternalContextsFromString`
@@ -1431,6 +1368,10 @@ function scaffoldMainFile(schematic, data) {
1431
1368
  {
1432
1369
  moduleName: `./${schematic.name}Context.ts`,
1433
1370
  name: `${schematic.name}Context`
1371
+ },
1372
+ {
1373
+ moduleName: `./${schematic.name}App.tsx`,
1374
+ name: `${schematic.name}App`
1434
1375
  }
1435
1376
  );
1436
1377
  data.currentFile.declarations.push(code`
@@ -1446,51 +1387,13 @@ function scaffoldMainFile(schematic, data) {
1446
1387
  createRoot(root).render(
1447
1388
  <StrictMode>
1448
1389
  <${schematic.name}Context.Provider value={{ externalContexts }}>
1449
- <RouterProvider router={router} />
1390
+ <${schematic.name}App />
1450
1391
  </${schematic.name}Context.Provider>
1451
1392
  </StrictMode>,
1452
1393
  );
1453
1394
  };
1454
1395
  `);
1455
1396
  }
1456
- function scaffoldRouteObject(schematic, data) {
1457
- const layout = reactAppLayout(schematic, data);
1458
- const formPages = layout.flatMap((annex) => annex.formPages);
1459
- data.currentFile.imports.push({
1460
- moduleName: `./${schematic.name}App.tsx`,
1461
- name: `${schematic.name}App`
1462
- });
1463
- for (const formPage of formPages) {
1464
- data.currentFile.imports.push({
1465
- moduleName: `./${joinPaths(
1466
- formPage.data.currentDir.slice(
1467
- data.currentDir.length + (data.currentDir.endsWith("/") ? 0 : 1)
1468
- ),
1469
- pascalCase(formPage.schematic.name)
1470
- )}.tsx`,
1471
- name: pascalCase(formPage.schematic.name)
1472
- });
1473
- }
1474
- const firstFormPage = formPages.find(
1475
- (formPage) => !formPage.schematic.nullable && !formPage.data.currentPath.split("/").includes("*")
1476
- );
1477
- const routes = [
1478
- firstFormPage && `{ path: "*", element: <${pascalCase(firstFormPage.schematic.name)} /> }`,
1479
- ...formPages.filter((formPage) => formPage !== firstFormPage).map(
1480
- (formPage) => `{ path: "${formPage.data.currentPath.split("/").map((f) => f === "*" ? ":id" : f).join(
1481
- "/"
1482
- )}", element: <${pascalCase(formPage.schematic.name)} /> }`
1483
- )
1484
- ];
1485
- return code`
1486
- {
1487
- element: <${schematic.name}App />,
1488
- children: [
1489
- ${routes.filter((r) => r).join(",\n")}
1490
- ]
1491
- }
1492
- `;
1493
- }
1494
1397
  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";
1495
1398
  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";
1496
1399
  function scaffoldProjectMisc(_schematic, data) {
@@ -1532,7 +1435,7 @@ function scaffoldStyles(_schematic, data) {
1532
1435
  }
1533
1436
  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.flat.recommended,\n reactRefresh.configs.vite,\n ],\n languageOptions: {\n ecmaVersion: 2020,\n globals: globals.browser,\n },\n },\n]);\n';
1534
1437
  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';
1535
- 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';
1438
+ 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 },\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';
1536
1439
  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';
1537
1440
  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';
1538
1441
  const tsConfigJson = '{\n "files": [],\n "references": [\n { "path": "./tsconfig.app.json" },\n { "path": "./tsconfig.node.json" }\n ]\n}\n';
@@ -1545,9 +1448,9 @@ function scaffoldViteProject(schematic, data) {
1545
1448
  formId: kebabCase(schematic.name),
1546
1449
  formClass: schematic.name,
1547
1450
  formTitle: capitalCase(schematic.name),
1548
- ostackUiVersion: "0.3.4",
1549
- kFormVersion: "0.31.5",
1550
- dependencyVersions: JSON.parse('{"@eslint/js":"^9.38.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.5","@ostack.tech/kform-react":"~0.31.5","@ostack.tech/kform-scaffolder":"~0.31.5","@storybook/addon-docs":"^9.1.16","@storybook/addon-links":"^9.1.16","@storybook/react-vite":"^9.1.16","@types/node":"^22.18.13","@types/react":"^19.2.2","@types/react-dom":"^19.2.2","@vitejs/plugin-react-swc":"^4.2.0","change-case":"^5.4.4","cpy-cli":"^6.0.0","date-fns":"^4.1.0","eslint":"^9.38.0","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.4","eslint-plugin-react-hooks":"^7.0.1","eslint-plugin-react-refresh":"^0.4.24","eslint-plugin-simple-import-sort":"^12.1.1","eslint-plugin-storybook":"^9.1.16","globals":"^16.4.0","happy-dom":"^20.0.10","lint-staged":"^16.2.6","prettier":"^3.6.2","prettier-plugin-jsdoc":"^1.5.0","react":"^19.2.0","react-dom":"^19.2.0","react-router":"^7.9.5","react-router-dom":"^7.9.5","rimraf":"^6.0.1","sass-embedded":"^1.93.2","simple-git-hooks":"^2.13.1","storybook":"^9.1.16","terser":"^5.44.0","tslib":"^2.8.1","typescript":"~5.9.3","typescript-eslint":"^8.46.2","vite":"^7.1.12","vite-plugin-dts":"^4.5.4","vitest":"^4.0.5","zustand":"^5.0.8"}'),
1451
+ ostackUiVersion: "0.4.1",
1452
+ kFormVersion: "0.31.6",
1453
+ dependencyVersions: JSON.parse('{"@eslint/js":"^9.39.1","@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.6","@ostack.tech/kform-react":"~0.31.6","@ostack.tech/kform-scaffolder":"~0.31.6","@storybook/addon-docs":"^10.0.5","@storybook/addon-links":"^10.0.5","@storybook/react-vite":"^10.0.5","@types/node":"^24.10.0","@types/react":"^19.2.2","@types/react-dom":"^19.2.2","@vitejs/plugin-react-swc":"^4.2.1","change-case":"^5.4.4","cpy-cli":"^6.0.0","date-fns":"^4.1.0","eslint":"^9.39.1","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.4","eslint-plugin-react-hooks":"^7.0.1","eslint-plugin-react-refresh":"^0.4.24","eslint-plugin-simple-import-sort":"^12.1.1","eslint-plugin-storybook":"^10.0.5","globals":"^16.5.0","happy-dom":"^20.0.10","lint-staged":"^16.2.6","prettier":"^3.6.2","prettier-plugin-jsdoc":"^1.5.0","react":"^19.2.0","react-dom":"^19.2.0","rimraf":"^6.1.0","sass-embedded":"^1.93.2","simple-git-hooks":"^2.13.1","storybook":"^10.0.5","terser":"^5.44.1","tslib":"^2.8.1","typescript":"~5.9.3","typescript-eslint":"^8.46.3","vite":"^7.2.1","vite-plugin-dts":"^4.5.4","vitest":"^4.0.7","zustand":"^5.0.8"}'),
1551
1454
  externalContextsData: data.serializationFormat === "json" ? "{}" : `<${schematic.name}ExternalContexts />`,
1552
1455
  apiBasePath: data.apiBasePath ?? DEFAULT_API_BASE_PATH,
1553
1456
  viteConfigOutDir: data.viteConfigOutDir ?? DEFAULT_VITE_CONFIG_OUT_DIR,
@@ -1596,7 +1499,7 @@ function SchematicBuilder({
1596
1499
  configScaffolder(scaffoldAppContext, reactAppData),
1597
1500
  configScaffolder(scaffoldActions, reactAppData),
1598
1501
  configScaffolder(scaffoldApi, reactAppData),
1599
- configScaffolder(scaffoldFormPages, reactAppData)
1502
+ configScaffolder(scaffoldPageComponents, reactAppData)
1600
1503
  ],
1601
1504
  scaffoldingData = (schematic) => ({
1602
1505
  useFileBase64Serializer: true,
@@ -1622,6 +1525,7 @@ function SchematicBuilder({
1622
1525
  );
1623
1526
  }
1624
1527
  export {
1528
+ DEFAULT_ACTIVE_PATH_SEARCH_PARAM,
1625
1529
  DEFAULT_API_BASE_PATH,
1626
1530
  DEFAULT_JVM_TOOLCHAIN_VERSION,
1627
1531
  DEFAULT_LOCALE,
@@ -1658,21 +1562,22 @@ export {
1658
1562
  longSchematicKind,
1659
1563
  reactAppLayout,
1660
1564
  scaffoldActions,
1661
- scaffoldAnnexesArray,
1565
+ scaffoldAnnex,
1566
+ scaffoldAnnexes,
1662
1567
  scaffoldApi,
1663
1568
  scaffoldAppComponent,
1664
1569
  scaffoldAppContext,
1665
1570
  scaffoldExternalContexts,
1666
1571
  scaffoldField,
1572
+ scaffoldFormPage,
1667
1573
  scaffoldFormPages,
1668
- scaffoldFormPagesByAnnexObject,
1669
1574
  scaffoldGradleProject,
1670
1575
  scaffoldGradleWrapper,
1671
1576
  scaffoldIssueMessages,
1672
1577
  scaffoldMain,
1578
+ scaffoldPageComponents,
1673
1579
  scaffoldProjectMisc,
1674
1580
  scaffoldResponses,
1675
- scaffoldRouteObject,
1676
1581
  scaffoldSerializer,
1677
1582
  scaffoldStyles,
1678
1583
  scaffoldViteProject,