@carlonicora/nextjs-jsonapi 1.2.0 → 1.3.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/dist/scripts/generate-web-module/generator.d.ts +15 -0
- package/dist/scripts/generate-web-module/generator.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/generator.js +320 -0
- package/dist/scripts/generate-web-module/generator.js.map +1 -0
- package/dist/scripts/generate-web-module/index.d.ts +16 -0
- package/dist/scripts/generate-web-module/index.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/index.js +80 -0
- package/dist/scripts/generate-web-module/index.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/container.template.d.ts +14 -0
- package/dist/scripts/generate-web-module/templates/components/container.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/container.template.js +124 -0
- package/dist/scripts/generate-web-module/templates/components/container.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/content.template.d.ts +15 -0
- package/dist/scripts/generate-web-module/templates/components/content.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/content.template.js +39 -0
- package/dist/scripts/generate-web-module/templates/components/content.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/deleter.template.d.ts +14 -0
- package/dist/scripts/generate-web-module/templates/components/deleter.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/deleter.template.js +51 -0
- package/dist/scripts/generate-web-module/templates/components/deleter.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/details.template.d.ts +14 -0
- package/dist/scripts/generate-web-module/templates/components/details.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/details.template.js +109 -0
- package/dist/scripts/generate-web-module/templates/components/details.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/editor.template.d.ts +14 -0
- package/dist/scripts/generate-web-module/templates/components/editor.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/editor.template.js +459 -0
- package/dist/scripts/generate-web-module/templates/components/editor.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/index.d.ts +15 -0
- package/dist/scripts/generate-web-module/templates/components/index.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/index.js +29 -0
- package/dist/scripts/generate-web-module/templates/components/index.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/list-container.template.d.ts +14 -0
- package/dist/scripts/generate-web-module/templates/components/list-container.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/list-container.template.js +30 -0
- package/dist/scripts/generate-web-module/templates/components/list-container.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/list.template.d.ts +14 -0
- package/dist/scripts/generate-web-module/templates/components/list.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/list.template.js +84 -0
- package/dist/scripts/generate-web-module/templates/components/list.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/multi-selector.template.d.ts +14 -0
- package/dist/scripts/generate-web-module/templates/components/multi-selector.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/multi-selector.template.js +184 -0
- package/dist/scripts/generate-web-module/templates/components/multi-selector.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/selector.template.d.ts +14 -0
- package/dist/scripts/generate-web-module/templates/components/selector.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/components/selector.template.js +199 -0
- package/dist/scripts/generate-web-module/templates/components/selector.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/context.template.d.ts +14 -0
- package/dist/scripts/generate-web-module/templates/context.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/context.template.js +121 -0
- package/dist/scripts/generate-web-module/templates/context.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/data/fields.template.d.ts +14 -0
- package/dist/scripts/generate-web-module/templates/data/fields.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/data/fields.template.js +55 -0
- package/dist/scripts/generate-web-module/templates/data/fields.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/data/index.d.ts +10 -0
- package/dist/scripts/generate-web-module/templates/data/index.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/data/index.js +26 -0
- package/dist/scripts/generate-web-module/templates/data/index.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/data/interface.template.d.ts +14 -0
- package/dist/scripts/generate-web-module/templates/data/interface.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/data/interface.template.js +116 -0
- package/dist/scripts/generate-web-module/templates/data/interface.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/data/model.template.d.ts +14 -0
- package/dist/scripts/generate-web-module/templates/data/model.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/data/model.template.js +274 -0
- package/dist/scripts/generate-web-module/templates/data/model.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/data/service.template.d.ts +14 -0
- package/dist/scripts/generate-web-module/templates/data/service.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/data/service.template.js +168 -0
- package/dist/scripts/generate-web-module/templates/data/service.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/index.d.ts +12 -0
- package/dist/scripts/generate-web-module/templates/index.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/index.js +37 -0
- package/dist/scripts/generate-web-module/templates/index.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/module.template.d.ts +14 -0
- package/dist/scripts/generate-web-module/templates/module.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/module.template.js +64 -0
- package/dist/scripts/generate-web-module/templates/module.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/pages/detail-page.template.d.ts +14 -0
- package/dist/scripts/generate-web-module/templates/pages/detail-page.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/pages/detail-page.template.js +65 -0
- package/dist/scripts/generate-web-module/templates/pages/detail-page.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/pages/index.d.ts +8 -0
- package/dist/scripts/generate-web-module/templates/pages/index.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/pages/index.js +13 -0
- package/dist/scripts/generate-web-module/templates/pages/index.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/pages/list-page.template.d.ts +14 -0
- package/dist/scripts/generate-web-module/templates/pages/list-page.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/pages/list-page.template.js +37 -0
- package/dist/scripts/generate-web-module/templates/pages/list-page.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/table-hook.template.d.ts +14 -0
- package/dist/scripts/generate-web-module/templates/table-hook.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/table-hook.template.js +174 -0
- package/dist/scripts/generate-web-module/templates/table-hook.template.js.map +1 -0
- package/dist/scripts/generate-web-module/transformers/field-mapper.d.ts +55 -0
- package/dist/scripts/generate-web-module/transformers/field-mapper.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/transformers/field-mapper.js +179 -0
- package/dist/scripts/generate-web-module/transformers/field-mapper.js.map +1 -0
- package/dist/scripts/generate-web-module/transformers/i18n-generator.d.ts +78 -0
- package/dist/scripts/generate-web-module/transformers/i18n-generator.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/transformers/i18n-generator.js +182 -0
- package/dist/scripts/generate-web-module/transformers/i18n-generator.js.map +1 -0
- package/dist/scripts/generate-web-module/transformers/import-resolver.d.ts +106 -0
- package/dist/scripts/generate-web-module/transformers/import-resolver.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/transformers/import-resolver.js +193 -0
- package/dist/scripts/generate-web-module/transformers/import-resolver.js.map +1 -0
- package/dist/scripts/generate-web-module/transformers/index.d.ts +12 -0
- package/dist/scripts/generate-web-module/transformers/index.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/transformers/index.js +28 -0
- package/dist/scripts/generate-web-module/transformers/index.js.map +1 -0
- package/dist/scripts/generate-web-module/transformers/name-transformer.d.ts +60 -0
- package/dist/scripts/generate-web-module/transformers/name-transformer.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/transformers/name-transformer.js +115 -0
- package/dist/scripts/generate-web-module/transformers/name-transformer.js.map +1 -0
- package/dist/scripts/generate-web-module/transformers/parent-detector.d.ts +57 -0
- package/dist/scripts/generate-web-module/transformers/parent-detector.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/transformers/parent-detector.js +88 -0
- package/dist/scripts/generate-web-module/transformers/parent-detector.js.map +1 -0
- package/dist/scripts/generate-web-module/transformers/relationship-resolver.d.ts +68 -0
- package/dist/scripts/generate-web-module/transformers/relationship-resolver.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/transformers/relationship-resolver.js +219 -0
- package/dist/scripts/generate-web-module/transformers/relationship-resolver.js.map +1 -0
- package/dist/scripts/generate-web-module/types/field-mapping.types.d.ts +68 -0
- package/dist/scripts/generate-web-module/types/field-mapping.types.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/types/field-mapping.types.js +129 -0
- package/dist/scripts/generate-web-module/types/field-mapping.types.js.map +1 -0
- package/dist/scripts/generate-web-module/types/index.d.ts +9 -0
- package/dist/scripts/generate-web-module/types/index.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/types/index.js +25 -0
- package/dist/scripts/generate-web-module/types/index.js.map +1 -0
- package/dist/scripts/generate-web-module/types/json-schema.interface.d.ts +40 -0
- package/dist/scripts/generate-web-module/types/json-schema.interface.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/types/json-schema.interface.js +10 -0
- package/dist/scripts/generate-web-module/types/json-schema.interface.js.map +1 -0
- package/dist/scripts/generate-web-module/types/template-data.interface.d.ts +128 -0
- package/dist/scripts/generate-web-module/types/template-data.interface.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/types/template-data.interface.js +9 -0
- package/dist/scripts/generate-web-module/types/template-data.interface.js.map +1 -0
- package/dist/scripts/generate-web-module/utils/bootstrapper-updater.d.ts +29 -0
- package/dist/scripts/generate-web-module/utils/bootstrapper-updater.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/utils/bootstrapper-updater.js +153 -0
- package/dist/scripts/generate-web-module/utils/bootstrapper-updater.js.map +1 -0
- package/dist/scripts/generate-web-module/utils/file-writer.d.ts +38 -0
- package/dist/scripts/generate-web-module/utils/file-writer.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/utils/file-writer.js +126 -0
- package/dist/scripts/generate-web-module/utils/file-writer.js.map +1 -0
- package/dist/scripts/generate-web-module/utils/i18n-updater.d.ts +28 -0
- package/dist/scripts/generate-web-module/utils/i18n-updater.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/utils/i18n-updater.js +122 -0
- package/dist/scripts/generate-web-module/utils/i18n-updater.js.map +1 -0
- package/dist/scripts/generate-web-module/utils/index.d.ts +9 -0
- package/dist/scripts/generate-web-module/utils/index.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/utils/index.js +20 -0
- package/dist/scripts/generate-web-module/utils/index.js.map +1 -0
- package/dist/scripts/generate-web-module/validators/json-schema-validator.d.ts +46 -0
- package/dist/scripts/generate-web-module/validators/json-schema-validator.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/validators/json-schema-validator.js +265 -0
- package/dist/scripts/generate-web-module/validators/json-schema-validator.js.map +1 -0
- package/package.json +27 -21
- package/scripts/generate-web-module/generator.ts +363 -0
- package/scripts/generate-web-module/index.ts +49 -0
- package/scripts/generate-web-module/templates/components/container.template.ts +129 -0
- package/scripts/generate-web-module/templates/components/content.template.ts +40 -0
- package/scripts/generate-web-module/templates/components/deleter.template.ts +51 -0
- package/scripts/generate-web-module/templates/components/details.template.ts +115 -0
- package/scripts/generate-web-module/templates/components/editor.template.ts +495 -0
- package/scripts/generate-web-module/templates/components/index.ts +18 -0
- package/scripts/generate-web-module/templates/components/list-container.template.ts +30 -0
- package/scripts/generate-web-module/templates/components/list.template.ts +91 -0
- package/scripts/generate-web-module/templates/components/multi-selector.template.ts +184 -0
- package/scripts/generate-web-module/templates/components/selector.template.ts +199 -0
- package/scripts/generate-web-module/templates/context.template.ts +121 -0
- package/scripts/generate-web-module/templates/data/fields.template.ts +64 -0
- package/scripts/generate-web-module/templates/data/index.ts +10 -0
- package/scripts/generate-web-module/templates/data/interface.template.ts +136 -0
- package/scripts/generate-web-module/templates/data/model.template.ts +327 -0
- package/scripts/generate-web-module/templates/data/service.template.ts +185 -0
- package/scripts/generate-web-module/templates/index.ts +34 -0
- package/scripts/generate-web-module/templates/module.template.ts +69 -0
- package/scripts/generate-web-module/templates/pages/detail-page.template.ts +65 -0
- package/scripts/generate-web-module/templates/pages/index.ts +8 -0
- package/scripts/generate-web-module/templates/pages/list-page.template.ts +37 -0
- package/scripts/generate-web-module/templates/table-hook.template.ts +182 -0
- package/scripts/generate-web-module/transformers/field-mapper.ts +201 -0
- package/scripts/generate-web-module/transformers/i18n-generator.ts +199 -0
- package/scripts/generate-web-module/transformers/import-resolver.ts +250 -0
- package/scripts/generate-web-module/transformers/index.ts +12 -0
- package/scripts/generate-web-module/transformers/name-transformer.ts +115 -0
- package/scripts/generate-web-module/transformers/parent-detector.ts +87 -0
- package/scripts/generate-web-module/transformers/relationship-resolver.ts +221 -0
- package/scripts/generate-web-module/tsconfig.json +24 -0
- package/scripts/generate-web-module/types/field-mapping.types.ts +141 -0
- package/scripts/generate-web-module/types/index.ts +9 -0
- package/scripts/generate-web-module/types/json-schema.interface.ts +42 -0
- package/scripts/generate-web-module/types/template-data.interface.ts +164 -0
- package/scripts/generate-web-module/utils/bootstrapper-updater.ts +145 -0
- package/scripts/generate-web-module/utils/file-writer.ts +115 -0
- package/scripts/generate-web-module/utils/i18n-updater.ts +108 -0
- package/scripts/generate-web-module/utils/index.ts +9 -0
- package/scripts/generate-web-module/validators/json-schema-validator.ts +306 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@carlonicora/nextjs-jsonapi",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Next.js JSON:API client with server/client support and caching",
|
|
5
5
|
"author": "Carlo Nicora",
|
|
6
6
|
"license": "GPL-3.0-or-later",
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
"main": "./dist/index.js",
|
|
9
9
|
"module": "./dist/index.mjs",
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
|
+
"bin": {
|
|
12
|
+
"generate-web-module": "./dist/scripts/generate-web-module/index.js"
|
|
13
|
+
},
|
|
11
14
|
"exports": {
|
|
12
15
|
".": {
|
|
13
16
|
"types": "./dist/index.d.ts",
|
|
@@ -81,16 +84,18 @@
|
|
|
81
84
|
}
|
|
82
85
|
},
|
|
83
86
|
"scripts": {
|
|
84
|
-
"build": "tsup",
|
|
87
|
+
"build": "tsup && tsc -p scripts/generate-web-module/tsconfig.json",
|
|
85
88
|
"dev": "tsup --watch",
|
|
86
89
|
"clean": "rm -rf dist",
|
|
87
90
|
"lint": "eslint \"src/**/*.ts\" --fix",
|
|
88
91
|
"format": "prettier --write \"src/**/*.ts\"",
|
|
89
|
-
"prepublishOnly": "pnpm build"
|
|
92
|
+
"prepublishOnly": "pnpm build",
|
|
93
|
+
"generate-web-module": "node dist/scripts/generate-web-module/index.js"
|
|
90
94
|
},
|
|
91
95
|
"files": [
|
|
92
96
|
"dist",
|
|
93
97
|
"src",
|
|
98
|
+
"scripts",
|
|
94
99
|
"README.md"
|
|
95
100
|
],
|
|
96
101
|
"peerDependencies": {
|
|
@@ -113,9 +118,10 @@
|
|
|
113
118
|
}
|
|
114
119
|
},
|
|
115
120
|
"dependencies": {
|
|
116
|
-
"
|
|
117
|
-
"@blocknote/
|
|
118
|
-
"@blocknote/
|
|
121
|
+
"commander": "^13.1.0",
|
|
122
|
+
"@blocknote/core": "^0.44.2",
|
|
123
|
+
"@blocknote/react": "^0.44.2",
|
|
124
|
+
"@blocknote/shadcn": "^0.44.2",
|
|
119
125
|
"@dnd-kit/core": "^6.3.1",
|
|
120
126
|
"@dnd-kit/sortable": "^10.0.0",
|
|
121
127
|
"@dnd-kit/utilities": "^3.2.2",
|
|
@@ -151,10 +157,10 @@
|
|
|
151
157
|
"d3": "^7.9.0",
|
|
152
158
|
"date-fns": "^4.1.0",
|
|
153
159
|
"embla-carousel-react": "^8.6.0",
|
|
154
|
-
"jotai": "^2.
|
|
155
|
-
"lucide-react": "^0.
|
|
160
|
+
"jotai": "^2.16.0",
|
|
161
|
+
"lucide-react": "^0.561.0",
|
|
156
162
|
"next-themes": "^0.4.6",
|
|
157
|
-
"react-day-picker": "^9.
|
|
163
|
+
"react-day-picker": "^9.12.0",
|
|
158
164
|
"react-dropzone": "^14.3.8",
|
|
159
165
|
"react-hook-form": "^7.68.0",
|
|
160
166
|
"react-markdown": "^10.1.0",
|
|
@@ -165,7 +171,7 @@
|
|
|
165
171
|
"sonner": "^2.0.7",
|
|
166
172
|
"tailwind-merge": "^3.4.0",
|
|
167
173
|
"uuid": "^13.0.0",
|
|
168
|
-
"vaul": "^1.1.
|
|
174
|
+
"vaul": "^1.1.2",
|
|
169
175
|
"zod": "^4.1.13"
|
|
170
176
|
},
|
|
171
177
|
"devDependencies": {
|
|
@@ -177,22 +183,22 @@
|
|
|
177
183
|
"@eslint/js": "^9.39.1",
|
|
178
184
|
"@tanstack/react-table": "^8.21.3",
|
|
179
185
|
"@types/d3": "^7.4.3",
|
|
180
|
-
"@types/node": "^
|
|
181
|
-
"@types/react": "^19.
|
|
182
|
-
"@types/react-dom": "^19.
|
|
183
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
184
|
-
"@typescript-eslint/parser": "^8.
|
|
186
|
+
"@types/node": "^25.0.1",
|
|
187
|
+
"@types/react": "^19.2.7",
|
|
188
|
+
"@types/react-dom": "^19.2.3",
|
|
189
|
+
"@typescript-eslint/eslint-plugin": "^8.49.0",
|
|
190
|
+
"@typescript-eslint/parser": "^8.49.0",
|
|
185
191
|
"eslint": "^9.39.1",
|
|
186
192
|
"eslint-config-prettier": "^10.1.8",
|
|
187
193
|
"eslint-plugin-prettier": "^5.5.4",
|
|
188
194
|
"globals": "^16.5.0",
|
|
189
|
-
"next": "^16.0.
|
|
190
|
-
"next-intl": "^4.
|
|
195
|
+
"next": "^16.0.10",
|
|
196
|
+
"next-intl": "^4.5.8",
|
|
191
197
|
"prettier": "^3.7.4",
|
|
192
|
-
"react": "^19.
|
|
193
|
-
"react-dom": "^19.
|
|
194
|
-
"tsup": "^8.5.
|
|
195
|
-
"typescript": "^5.9.
|
|
198
|
+
"react": "^19.2.3",
|
|
199
|
+
"react-dom": "^19.2.3",
|
|
200
|
+
"tsup": "^8.5.1",
|
|
201
|
+
"typescript": "^5.9.3"
|
|
196
202
|
},
|
|
197
203
|
"keywords": [
|
|
198
204
|
"nextjs",
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frontend Module Generator
|
|
3
|
+
*
|
|
4
|
+
* Main orchestrator for generating frontend modules from JSON schema.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
import {
|
|
10
|
+
JsonModuleDefinition,
|
|
11
|
+
FrontendTemplateData,
|
|
12
|
+
GeneratedFile,
|
|
13
|
+
GenerateWebModuleOptions,
|
|
14
|
+
} from "./types";
|
|
15
|
+
import { transformNames, toCamelCase, pluralize, toTitleCase } from "./transformers/name-transformer";
|
|
16
|
+
import { detectExtendsContent } from "./transformers/parent-detector";
|
|
17
|
+
import { mapFields, filterInheritedFields } from "./transformers/field-mapper";
|
|
18
|
+
import { resolveRelationships, generateServiceMethods } from "./transformers/relationship-resolver";
|
|
19
|
+
import { buildImportStatements, buildFilePaths } from "./transformers/import-resolver";
|
|
20
|
+
import { generateI18nKeys } from "./transformers/i18n-generator";
|
|
21
|
+
import { parseAndValidate, validationPassed } from "./validators/json-schema-validator";
|
|
22
|
+
import {
|
|
23
|
+
generateInterfaceTemplate,
|
|
24
|
+
generateModelTemplate,
|
|
25
|
+
generateServiceTemplate,
|
|
26
|
+
generateFieldsTemplate,
|
|
27
|
+
generateEditorTemplate,
|
|
28
|
+
generateDeleterTemplate,
|
|
29
|
+
generateSelectorTemplate,
|
|
30
|
+
generateMultiSelectorTemplate,
|
|
31
|
+
generateListTemplate,
|
|
32
|
+
generateDetailsTemplate,
|
|
33
|
+
generateContentTemplate,
|
|
34
|
+
generateContainerTemplate,
|
|
35
|
+
generateListContainerTemplate,
|
|
36
|
+
generateContextTemplate,
|
|
37
|
+
generateTableHookTemplate,
|
|
38
|
+
generateModuleTemplate,
|
|
39
|
+
generateListPageTemplate,
|
|
40
|
+
generateDetailPageTemplate,
|
|
41
|
+
} from "./templates";
|
|
42
|
+
import { writeFiles, printResults, updateBootstrapper, updateI18n } from "./utils";
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Generate all frontend module files from JSON schema
|
|
46
|
+
*
|
|
47
|
+
* @param options - Generator options
|
|
48
|
+
* @returns True if generation succeeded
|
|
49
|
+
*/
|
|
50
|
+
export async function generateWebModule(options: GenerateWebModuleOptions): Promise<boolean> {
|
|
51
|
+
const { jsonPath, dryRun = false, force = false, noRegister = false } = options;
|
|
52
|
+
|
|
53
|
+
console.log(`\n🔧 Frontend Module Generator`);
|
|
54
|
+
console.log(` JSON Schema: ${jsonPath}`);
|
|
55
|
+
console.log(` Dry Run: ${dryRun}`);
|
|
56
|
+
console.log(` Force: ${force}`);
|
|
57
|
+
console.log(` No Register: ${noRegister}`);
|
|
58
|
+
|
|
59
|
+
// Step 1: Validate JSON schema
|
|
60
|
+
console.log("\n📋 Validating JSON schema...");
|
|
61
|
+
const validation = parseAndValidate(jsonPath);
|
|
62
|
+
|
|
63
|
+
if (!validationPassed(validation)) {
|
|
64
|
+
console.error("\n❌ Validation failed:");
|
|
65
|
+
validation.errors.forEach((e) => console.error(` - ${e}`));
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (validation.warnings.length > 0) {
|
|
70
|
+
console.log("\n⚠️ Validation warnings (non-blocking):");
|
|
71
|
+
validation.warnings.forEach((w) => console.log(` - ${w}`));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const schema = validation.data!;
|
|
75
|
+
console.log(` ✅ Schema valid: ${schema.moduleName}`);
|
|
76
|
+
|
|
77
|
+
// Step 2: Build template data
|
|
78
|
+
console.log("\n🔨 Building template data...");
|
|
79
|
+
const templateData = buildTemplateData(schema);
|
|
80
|
+
console.log(` Module: ${templateData.names.pascalCase}`);
|
|
81
|
+
console.log(` Target: ${templateData.targetDir}`);
|
|
82
|
+
console.log(` Extends Content: ${templateData.extendsContent}`);
|
|
83
|
+
console.log(` Fields: ${templateData.fields.length}`);
|
|
84
|
+
console.log(` Relationships: ${templateData.relationships.length}`);
|
|
85
|
+
|
|
86
|
+
// Step 3: Generate all files
|
|
87
|
+
console.log("\n📝 Generating files...");
|
|
88
|
+
const files = generateAllFiles(templateData, schema);
|
|
89
|
+
console.log(` Generated ${files.length} file templates`);
|
|
90
|
+
|
|
91
|
+
// Step 4: Determine web base path
|
|
92
|
+
const webBasePath = findWebBasePath(jsonPath);
|
|
93
|
+
if (!webBasePath) {
|
|
94
|
+
console.error("\n❌ Could not determine web app base path");
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
console.log(` Web base path: ${webBasePath}`);
|
|
98
|
+
|
|
99
|
+
// Step 5: Write files
|
|
100
|
+
console.log("\n💾 Writing files...");
|
|
101
|
+
const results = writeFiles(files, { dryRun, force });
|
|
102
|
+
printResults(results);
|
|
103
|
+
|
|
104
|
+
// Step 6: Update Bootstrapper (unless --no-register)
|
|
105
|
+
if (!noRegister) {
|
|
106
|
+
console.log("\n🔧 Updating Bootstrapper.ts...");
|
|
107
|
+
const bootstrapResult = updateBootstrapper(templateData, webBasePath, dryRun);
|
|
108
|
+
console.log(` ${bootstrapResult.success ? "✅" : "❌"} ${bootstrapResult.message}`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Step 7: Update i18n (unless --no-register)
|
|
112
|
+
if (!noRegister) {
|
|
113
|
+
console.log("\n🌐 Updating messages/en.json...");
|
|
114
|
+
const i18nResult = updateI18n(templateData, webBasePath, dryRun);
|
|
115
|
+
console.log(` ${i18nResult.success ? "✅" : "❌"} ${i18nResult.message}`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
console.log("\n✅ Generation complete!");
|
|
119
|
+
|
|
120
|
+
if (dryRun) {
|
|
121
|
+
console.log("\n📝 This was a dry run. No files were actually written.");
|
|
122
|
+
console.log(" Remove --dry-run to generate files.");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Build template data from JSON schema
|
|
130
|
+
*/
|
|
131
|
+
function buildTemplateData(schema: JsonModuleDefinition): FrontendTemplateData {
|
|
132
|
+
const names = transformNames(schema.moduleName, schema.endpointName);
|
|
133
|
+
const targetDir = schema.targetDir as "features" | "foundations";
|
|
134
|
+
const extendsContent = detectExtendsContent(schema.fields);
|
|
135
|
+
|
|
136
|
+
// Map fields
|
|
137
|
+
const allFields = mapFields(schema.fields, names.camelCase);
|
|
138
|
+
|
|
139
|
+
// Get inherited fields to filter out for forms (Content fields are handled specially)
|
|
140
|
+
const inheritedFields = extendsContent ? ["name", "tldr", "abstract", "content"] : [];
|
|
141
|
+
const fields = filterInheritedFields(allFields, inheritedFields);
|
|
142
|
+
|
|
143
|
+
// Resolve relationships
|
|
144
|
+
const relationships = resolveRelationships(schema.relationships);
|
|
145
|
+
const relationshipServiceMethods = generateServiceMethods(relationships);
|
|
146
|
+
|
|
147
|
+
// Build imports
|
|
148
|
+
const imports = buildImportStatements(relationships, extendsContent);
|
|
149
|
+
|
|
150
|
+
// Generate i18n keys
|
|
151
|
+
const i18nKeys = generateI18nKeys(names, fields, relationships);
|
|
152
|
+
|
|
153
|
+
// Build table field names
|
|
154
|
+
const tableFieldNames = buildTableFieldNames(schema, extendsContent);
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
names,
|
|
158
|
+
moduleId: schema.moduleId,
|
|
159
|
+
endpoint: schema.endpointName,
|
|
160
|
+
targetDir,
|
|
161
|
+
extendsContent,
|
|
162
|
+
fields: allFields, // Keep all fields for interface generation
|
|
163
|
+
relationships,
|
|
164
|
+
i18nKeys,
|
|
165
|
+
imports,
|
|
166
|
+
tableFieldNames,
|
|
167
|
+
relationshipServiceMethods,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Build field names for table display
|
|
173
|
+
*/
|
|
174
|
+
function buildTableFieldNames(schema: JsonModuleDefinition, extendsContent: boolean): string[] {
|
|
175
|
+
const fieldNames: string[] = [`${toCamelCase(schema.moduleName)}Id`];
|
|
176
|
+
|
|
177
|
+
// Add name for all modules
|
|
178
|
+
fieldNames.push("name");
|
|
179
|
+
|
|
180
|
+
// Add authors for content modules
|
|
181
|
+
if (extendsContent) {
|
|
182
|
+
fieldNames.push("authors");
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Add custom fields (excluding certain ones)
|
|
186
|
+
schema.fields.forEach((f) => {
|
|
187
|
+
if (!["id", "name", "tldr", "abstract", "content", "createdAt", "updatedAt"].includes(f.name)) {
|
|
188
|
+
fieldNames.push(f.name);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Add standard date fields
|
|
193
|
+
fieldNames.push("createdAt", "updatedAt");
|
|
194
|
+
|
|
195
|
+
return fieldNames;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Generate all module files
|
|
200
|
+
*/
|
|
201
|
+
function generateAllFiles(data: FrontendTemplateData, schema: JsonModuleDefinition): GeneratedFile[] {
|
|
202
|
+
const files: GeneratedFile[] = [];
|
|
203
|
+
const paths = buildFilePaths(data, findWebBasePath(""));
|
|
204
|
+
|
|
205
|
+
// Data layer (4 files)
|
|
206
|
+
files.push({
|
|
207
|
+
path: paths.interface,
|
|
208
|
+
content: generateInterfaceTemplate(data),
|
|
209
|
+
type: "data",
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
files.push({
|
|
213
|
+
path: paths.model,
|
|
214
|
+
content: generateModelTemplate(data),
|
|
215
|
+
type: "data",
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
files.push({
|
|
219
|
+
path: paths.service,
|
|
220
|
+
content: generateServiceTemplate(data),
|
|
221
|
+
type: "data",
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
files.push({
|
|
225
|
+
path: paths.fields,
|
|
226
|
+
content: generateFieldsTemplate(data),
|
|
227
|
+
type: "data",
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Form components (4 files)
|
|
231
|
+
files.push({
|
|
232
|
+
path: paths.editor,
|
|
233
|
+
content: generateEditorTemplate(data),
|
|
234
|
+
type: "component",
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
files.push({
|
|
238
|
+
path: paths.deleter,
|
|
239
|
+
content: generateDeleterTemplate(data),
|
|
240
|
+
type: "component",
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
files.push({
|
|
244
|
+
path: paths.selector,
|
|
245
|
+
content: generateSelectorTemplate(data),
|
|
246
|
+
type: "component",
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
files.push({
|
|
250
|
+
path: paths.multiSelector,
|
|
251
|
+
content: generateMultiSelectorTemplate(data),
|
|
252
|
+
type: "component",
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// Display components (4-5 files)
|
|
256
|
+
files.push({
|
|
257
|
+
path: paths.list,
|
|
258
|
+
content: generateListTemplate(data),
|
|
259
|
+
type: "component",
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
files.push({
|
|
263
|
+
path: paths.details,
|
|
264
|
+
content: generateDetailsTemplate(data),
|
|
265
|
+
type: "component",
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
// Content component only for Content-extending modules
|
|
269
|
+
const contentTemplate = generateContentTemplate(data);
|
|
270
|
+
if (contentTemplate) {
|
|
271
|
+
files.push({
|
|
272
|
+
path: paths.content,
|
|
273
|
+
content: contentTemplate,
|
|
274
|
+
type: "component",
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
files.push({
|
|
279
|
+
path: paths.container,
|
|
280
|
+
content: generateContainerTemplate(data),
|
|
281
|
+
type: "component",
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
files.push({
|
|
285
|
+
path: paths.listContainer,
|
|
286
|
+
content: generateListContainerTemplate(data),
|
|
287
|
+
type: "component",
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// Context & hooks (2 files)
|
|
291
|
+
files.push({
|
|
292
|
+
path: paths.context,
|
|
293
|
+
content: generateContextTemplate(data),
|
|
294
|
+
type: "context",
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
files.push({
|
|
298
|
+
path: paths.tableHook,
|
|
299
|
+
content: generateTableHookTemplate(data),
|
|
300
|
+
type: "hook",
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// Module (1 file)
|
|
304
|
+
files.push({
|
|
305
|
+
path: paths.module,
|
|
306
|
+
content: generateModuleTemplate(data),
|
|
307
|
+
type: "module",
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// Pages (2 files)
|
|
311
|
+
files.push({
|
|
312
|
+
path: paths.listPage,
|
|
313
|
+
content: generateListPageTemplate(data),
|
|
314
|
+
type: "page",
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
files.push({
|
|
318
|
+
path: paths.detailPage,
|
|
319
|
+
content: generateDetailPageTemplate(data),
|
|
320
|
+
type: "page",
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
return files;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Find the web app base path from the JSON path
|
|
328
|
+
* Assumes JSON is in /structure folder and web app is in /apps/web
|
|
329
|
+
*/
|
|
330
|
+
function findWebBasePath(jsonPath: string): string {
|
|
331
|
+
// Try to find apps/web relative to current working directory
|
|
332
|
+
const cwd = process.cwd();
|
|
333
|
+
|
|
334
|
+
// Check if we're in the monorepo root
|
|
335
|
+
if (fs.existsSync(path.join(cwd, "apps/web"))) {
|
|
336
|
+
return cwd;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Check if we're in packages/nextjs-jsonapi
|
|
340
|
+
if (fs.existsSync(path.join(cwd, "../../apps/web"))) {
|
|
341
|
+
return path.join(cwd, "../..");
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Try to derive from jsonPath
|
|
345
|
+
if (jsonPath) {
|
|
346
|
+
const resolved = path.resolve(jsonPath);
|
|
347
|
+
// Look for monorepo root by finding apps/web
|
|
348
|
+
let current = path.dirname(resolved);
|
|
349
|
+
for (let i = 0; i < 10; i++) {
|
|
350
|
+
if (fs.existsSync(path.join(current, "apps/web"))) {
|
|
351
|
+
return current;
|
|
352
|
+
}
|
|
353
|
+
const parent = path.dirname(current);
|
|
354
|
+
if (parent === current) break;
|
|
355
|
+
current = parent;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Default to current directory
|
|
360
|
+
return cwd;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export default generateWebModule;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Frontend Module Generator CLI
|
|
4
|
+
*
|
|
5
|
+
* Generates Next.js frontend modules from JSON schema definitions.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* pnpm generate-web-module <json-path> [options]
|
|
9
|
+
*
|
|
10
|
+
* Options:
|
|
11
|
+
* --dry-run Preview without writing files
|
|
12
|
+
* --force Overwrite existing files
|
|
13
|
+
* --no-register Skip Bootstrapper and i18n updates
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { Command } from "commander";
|
|
17
|
+
import * as path from "path";
|
|
18
|
+
import { generateWebModule } from "./generator";
|
|
19
|
+
|
|
20
|
+
const program = new Command();
|
|
21
|
+
|
|
22
|
+
program
|
|
23
|
+
.name("generate-web-module")
|
|
24
|
+
.description("Generate Next.js frontend module from JSON schema")
|
|
25
|
+
.version("1.0.0")
|
|
26
|
+
.argument("<json-path>", "Path to JSON schema file (relative or absolute)")
|
|
27
|
+
.option("-d, --dry-run", "Preview files without writing them", false)
|
|
28
|
+
.option("-f, --force", "Overwrite existing files", false)
|
|
29
|
+
.option("-n, --no-register", "Skip Bootstrapper.ts and i18n updates", false)
|
|
30
|
+
.action(async (jsonPath: string, options: { dryRun: boolean; force: boolean; register: boolean }) => {
|
|
31
|
+
// Resolve path
|
|
32
|
+
const resolvedPath = path.isAbsolute(jsonPath) ? jsonPath : path.resolve(process.cwd(), jsonPath);
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const success = await generateWebModule({
|
|
36
|
+
jsonPath: resolvedPath,
|
|
37
|
+
dryRun: options.dryRun,
|
|
38
|
+
force: options.force,
|
|
39
|
+
noRegister: !options.register,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
process.exit(success ? 0 : 1);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error("\n❌ Error:", error instanceof Error ? error.message : error);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
program.parse();
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Container Template
|
|
3
|
+
*
|
|
4
|
+
* Generates {Module}Container.tsx component for displaying item detail page.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { FrontendTemplateData } from "../../types/template-data.interface";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Generate the container component file content
|
|
11
|
+
*
|
|
12
|
+
* @param data - Frontend template data
|
|
13
|
+
* @returns Generated file content
|
|
14
|
+
*/
|
|
15
|
+
export function generateContainerTemplate(data: FrontendTemplateData): string {
|
|
16
|
+
const { names, extendsContent } = data;
|
|
17
|
+
|
|
18
|
+
// Content-extending modules get full tabs with relevant content/users
|
|
19
|
+
if (extendsContent) {
|
|
20
|
+
return generateContentContainerTemplate(data);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Non-content modules get simpler container
|
|
24
|
+
return generateSimpleContainerTemplate(data);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Generate container for Content-extending modules
|
|
29
|
+
*/
|
|
30
|
+
function generateContentContainerTemplate(data: FrontendTemplateData): string {
|
|
31
|
+
const { names } = data;
|
|
32
|
+
|
|
33
|
+
return `"use client";
|
|
34
|
+
|
|
35
|
+
import ${names.pascalCase}Content from "@/features/${data.targetDir}/${names.kebabCase}/components/details/${names.pascalCase}Content";
|
|
36
|
+
import ${names.pascalCase}Details from "@/features/${data.targetDir}/${names.kebabCase}/components/details/${names.pascalCase}Details";
|
|
37
|
+
import { use${names.pascalCase}Context } from "@/features/${data.targetDir}/${names.kebabCase}/contexts/${names.pascalCase}Context";
|
|
38
|
+
import { ${names.pascalCase}Interface } from "@/features/${data.targetDir}/${names.kebabCase}/data/${names.pascalCase}Interface";
|
|
39
|
+
import {
|
|
40
|
+
AllowedUsersDetails,
|
|
41
|
+
PageContentContainer,
|
|
42
|
+
RelevantContentsList,
|
|
43
|
+
RelevantUsersList,
|
|
44
|
+
} from "@carlonicora/nextjs-jsonapi/components";
|
|
45
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@carlonicora/nextjs-jsonapi/shadcnui";
|
|
46
|
+
import { useTranslations } from "next-intl";
|
|
47
|
+
|
|
48
|
+
type ${names.pascalCase}ContainerProps = {
|
|
49
|
+
${names.camelCase}: ${names.pascalCase}Interface;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
function ${names.pascalCase}ContainerInternal({ ${names.camelCase} }: ${names.pascalCase}ContainerProps) {
|
|
53
|
+
const t = useTranslations();
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<PageContentContainer
|
|
57
|
+
details={<${names.pascalCase}Details />}
|
|
58
|
+
footer={
|
|
59
|
+
<AllowedUsersDetails showTitle content={${names.camelCase}} />
|
|
60
|
+
}
|
|
61
|
+
content={
|
|
62
|
+
<Tabs defaultValue={\`${names.camelCase}\`}>
|
|
63
|
+
<TabsList className="mb-4">
|
|
64
|
+
<TabsTrigger value="${names.camelCase}">{t(\`types.${names.pluralCamel}\`, { count: 1 })}</TabsTrigger>
|
|
65
|
+
<TabsTrigger value="contents">{t(\`generic.relevant\`)}</TabsTrigger>
|
|
66
|
+
<TabsTrigger value="users">{t(\`generic.relevant_users\`)}</TabsTrigger>
|
|
67
|
+
</TabsList>
|
|
68
|
+
<TabsContent value="${names.camelCase}">
|
|
69
|
+
<${names.pascalCase}Content />
|
|
70
|
+
</TabsContent>
|
|
71
|
+
<TabsContent value="contents">
|
|
72
|
+
<RelevantContentsList id={${names.camelCase}.id} />
|
|
73
|
+
</TabsContent>
|
|
74
|
+
<TabsContent value="users">
|
|
75
|
+
<RelevantUsersList id={${names.camelCase}.id} />
|
|
76
|
+
</TabsContent>
|
|
77
|
+
</Tabs>
|
|
78
|
+
}
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export default function ${names.pascalCase}Container() {
|
|
84
|
+
const { ${names.camelCase} } = use${names.pascalCase}Context();
|
|
85
|
+
if (!${names.camelCase}) return null;
|
|
86
|
+
|
|
87
|
+
return <${names.pascalCase}ContainerInternal ${names.camelCase}={${names.camelCase}} />;
|
|
88
|
+
}
|
|
89
|
+
`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Generate container for non-Content modules
|
|
94
|
+
*/
|
|
95
|
+
function generateSimpleContainerTemplate(data: FrontendTemplateData): string {
|
|
96
|
+
const { names } = data;
|
|
97
|
+
|
|
98
|
+
return `"use client";
|
|
99
|
+
|
|
100
|
+
import ${names.pascalCase}Details from "@/features/${data.targetDir}/${names.kebabCase}/components/details/${names.pascalCase}Details";
|
|
101
|
+
import { use${names.pascalCase}Context } from "@/features/${data.targetDir}/${names.kebabCase}/contexts/${names.pascalCase}Context";
|
|
102
|
+
import { ${names.pascalCase}Interface } from "@/features/${data.targetDir}/${names.kebabCase}/data/${names.pascalCase}Interface";
|
|
103
|
+
import { PageContentContainer } from "@carlonicora/nextjs-jsonapi/components";
|
|
104
|
+
|
|
105
|
+
type ${names.pascalCase}ContainerProps = {
|
|
106
|
+
${names.camelCase}: ${names.pascalCase}Interface;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
function ${names.pascalCase}ContainerInternal({ ${names.camelCase} }: ${names.pascalCase}ContainerProps) {
|
|
110
|
+
return (
|
|
111
|
+
<PageContentContainer
|
|
112
|
+
details={<${names.pascalCase}Details />}
|
|
113
|
+
content={
|
|
114
|
+
<div className="flex w-full flex-col gap-y-4">
|
|
115
|
+
{/* Add custom content sections here */}
|
|
116
|
+
</div>
|
|
117
|
+
}
|
|
118
|
+
/>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export default function ${names.pascalCase}Container() {
|
|
123
|
+
const { ${names.camelCase} } = use${names.pascalCase}Context();
|
|
124
|
+
if (!${names.camelCase}) return null;
|
|
125
|
+
|
|
126
|
+
return <${names.pascalCase}ContainerInternal ${names.camelCase}={${names.camelCase}} />;
|
|
127
|
+
}
|
|
128
|
+
`;
|
|
129
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Template
|
|
3
|
+
*
|
|
4
|
+
* Generates {Module}Content.tsx component for displaying BlockNote content.
|
|
5
|
+
* Only generated for Content-extending modules.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { FrontendTemplateData } from "../../types/template-data.interface";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Generate the content display component file content
|
|
12
|
+
*
|
|
13
|
+
* @param data - Frontend template data
|
|
14
|
+
* @returns Generated file content or null if not Content-extending
|
|
15
|
+
*/
|
|
16
|
+
export function generateContentTemplate(data: FrontendTemplateData): string | null {
|
|
17
|
+
const { names, extendsContent } = data;
|
|
18
|
+
|
|
19
|
+
// Only generate for Content-extending modules
|
|
20
|
+
if (!extendsContent) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return `"use client";
|
|
25
|
+
|
|
26
|
+
import { use${names.pascalCase}Context } from "@/features/${data.targetDir}/${names.kebabCase}/contexts/${names.pascalCase}Context";
|
|
27
|
+
import { BlockNoteEditorContainer } from "@carlonicora/nextjs-jsonapi/components";
|
|
28
|
+
import { Card } from "@carlonicora/nextjs-jsonapi/shadcnui";
|
|
29
|
+
|
|
30
|
+
export default function ${names.pascalCase}Content() {
|
|
31
|
+
const { ${names.camelCase} } = use${names.pascalCase}Context();
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<Card className="flex w-full flex-col p-4">
|
|
35
|
+
<BlockNoteEditorContainer id={${names.camelCase}.id} type="${names.camelCase}" initialContent={${names.camelCase}.content} />
|
|
36
|
+
</Card>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
}
|