@maxisoft/instantcms-mcp 1.2.3
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/LICENSE +21 -0
- package/README.md +308 -0
- package/dist/__tests__/artifact-tool.test.js +196 -0
- package/dist/__tests__/db-tool.test.js +152 -0
- package/dist/__tests__/define-tool.test.js +106 -0
- package/dist/__tests__/find-tool.test.js +185 -0
- package/dist/__tests__/get-component-api.test.js +144 -0
- package/dist/__tests__/hardening.test.js +73 -0
- package/dist/__tests__/hooks-tool.test.js +173 -0
- package/dist/__tests__/mcp-integration-extra.test.js +166 -0
- package/dist/__tests__/mcp-integration.test.js +53 -0
- package/dist/__tests__/pagination.test.js +114 -0
- package/dist/__tests__/performance-baseline.test.js +56 -0
- package/dist/__tests__/project-patch.test.js +144 -0
- package/dist/__tests__/project-source.test.js +44 -0
- package/dist/__tests__/project-workflows-extra.test.js +165 -0
- package/dist/__tests__/project-workflows.test.js +51 -0
- package/dist/__tests__/scaffold-addon-roundtrip.test.js +287 -0
- package/dist/__tests__/serialization.test.js +170 -0
- package/dist/__tests__/source-knowledge-parsers.test.js +42 -0
- package/dist/__tests__/template-development.test.js +78 -0
- package/dist/__tests__/template-productivity.test.js +87 -0
- package/dist/__tests__/tools.test.js +2143 -0
- package/dist/data/components.js +2818 -0
- package/dist/data/controllers-map.js +7571 -0
- package/dist/data/core-api.js +9356 -0
- package/dist/data/database-schema.js +4555 -0
- package/dist/data/events-map.js +1339 -0
- package/dist/data/fields-map.js +3692 -0
- package/dist/data/hooks.js +2257 -0
- package/dist/data/js-api.js +123 -0
- package/dist/data/libs-api.js +264 -0
- package/dist/data/routes-map.js +203 -0
- package/dist/data/schemas-validation.js +255 -0
- package/dist/data/schemas.js +1404 -0
- package/dist/data/traits-map.js +1004 -0
- package/dist/data/version-profiles.js +41 -0
- package/dist/data/widgets-map.js +131 -0
- package/dist/data/wysiwyg-map.js +486 -0
- package/dist/generated/components-source.js +14748 -0
- package/dist/generated/hooks-source.js +3399 -0
- package/dist/generated/knowledge-meta.js +101 -0
- package/dist/index.js +13 -0
- package/dist/registry/database-tools.js +112 -0
- package/dist/registry/extension-tools.js +473 -0
- package/dist/registry/generator-tools.js +506 -0
- package/dist/registry/knowledge-tools.js +441 -0
- package/dist/registry/language-tools.js +99 -0
- package/dist/registry/meta-tools.js +152 -0
- package/dist/registry/project-tools.js +48 -0
- package/dist/registry/resources.js +98 -0
- package/dist/registry/source-tools.js +211 -0
- package/dist/registry/template-development-tools.js +79 -0
- package/dist/server.js +32 -0
- package/dist/tools/addon-tool.js +1437 -0
- package/dist/tools/admin-partial-tool.js +498 -0
- package/dist/tools/api-tool.js +294 -0
- package/dist/tools/artifact-tool.js +95 -0
- package/dist/tools/cache-tool.js +360 -0
- package/dist/tools/component-tool.js +415 -0
- package/dist/tools/controllers-tool.js +125 -0
- package/dist/tools/cron-tool.js +197 -0
- package/dist/tools/crud-tool.js +659 -0
- package/dist/tools/db-tool.js +198 -0
- package/dist/tools/email-tool.js +222 -0
- package/dist/tools/external-api-tool.js +596 -0
- package/dist/tools/filter-tool.js +341 -0
- package/dist/tools/form-tool.js +275 -0
- package/dist/tools/grid-tool.js +189 -0
- package/dist/tools/hooks-tool.js +104 -0
- package/dist/tools/import-export-tool.js +548 -0
- package/dist/tools/lang-tool.js +251 -0
- package/dist/tools/layout-override-tool.js +125 -0
- package/dist/tools/layout-tool.js +548 -0
- package/dist/tools/maria-tool.js +127 -0
- package/dist/tools/mariadb.js +201 -0
- package/dist/tools/migration-tool.js +329 -0
- package/dist/tools/oauth-tool.js +520 -0
- package/dist/tools/parser/components-parser.js +76 -0
- package/dist/tools/parser/controllers-parser.js +313 -0
- package/dist/tools/parser/core-parser.js +294 -0
- package/dist/tools/parser/coverage-generator.js +424 -0
- package/dist/tools/parser/events-parser.js +127 -0
- package/dist/tools/parser/fields-parser.js +382 -0
- package/dist/tools/parser/hooks-parser.js +106 -0
- package/dist/tools/parser/sql-parser.js +197 -0
- package/dist/tools/parser/traits-parser.js +161 -0
- package/dist/tools/parser/widgets-parser.js +150 -0
- package/dist/tools/permission-tool.js +348 -0
- package/dist/tools/project-patch-tool.js +73 -0
- package/dist/tools/project-source-tool.js +188 -0
- package/dist/tools/project-workflow-tool.js +186 -0
- package/dist/tools/requirement-tool.js +212 -0
- package/dist/tools/scaffold-tool.js +815 -0
- package/dist/tools/seo-tool.js +412 -0
- package/dist/tools/source-tool.js +155 -0
- package/dist/tools/template-development-tool.js +271 -0
- package/dist/tools/template-overrides-tool.js +294 -0
- package/dist/tools/template-productivity-tool.js +319 -0
- package/dist/tools/template-tool.js +665 -0
- package/dist/tools/test-tool.js +183 -0
- package/dist/tools/webhook-tool.js +427 -0
- package/dist/tools/widget-tool.js +331 -0
- package/dist/tools/wysiwyg-tool.js +137 -0
- package/dist/types/scaffold.js +68 -0
- package/dist/utils/define-tool.js +37 -0
- package/dist/utils/find-tool.js +97 -0
- package/dist/utils/mcp-result.js +18 -0
- package/dist/utils/pagination.js +27 -0
- package/dist/utils/serialization.js +27 -0
- package/package.json +94 -0
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Component scaffolding tool for InstantCMS
|
|
4
|
+
* Generates complete components with backend, frontend, model, and routes
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.componentToolSchema = void 0;
|
|
8
|
+
exports.scaffoldComponent = scaffoldComponent;
|
|
9
|
+
const zod_1 = require("zod");
|
|
10
|
+
const scaffold_1 = require("../types/scaffold");
|
|
11
|
+
/**
|
|
12
|
+
* Generates component manifest
|
|
13
|
+
*/
|
|
14
|
+
function generateManifest(name, Name, controllers, options) {
|
|
15
|
+
return `<?php
|
|
16
|
+
// InstantCMS 2. manifest.json
|
|
17
|
+
|
|
18
|
+
return [
|
|
19
|
+
'type' => 'component',
|
|
20
|
+
'name' => '${name}',
|
|
21
|
+
'title' => '${Name}',
|
|
22
|
+
'description' => '${Name} component',
|
|
23
|
+
'icon' => 'component_${name}',
|
|
24
|
+
'version' => '1.0.0',
|
|
25
|
+
'category' => 'content',
|
|
26
|
+
'files' => [
|
|
27
|
+
'backend.php',
|
|
28
|
+
'frontend.php',
|
|
29
|
+
'model.php',
|
|
30
|
+
'routes.php',
|
|
31
|
+
],
|
|
32
|
+
'controllers' => ['${controllers.map(c => c.name).join("', '")}'],
|
|
33
|
+
'options' => [
|
|
34
|
+
'frontend' => ${options.with_frontend},
|
|
35
|
+
'admin' => ${options.with_admin},
|
|
36
|
+
],
|
|
37
|
+
'dependencies' => [],
|
|
38
|
+
];`;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Generates backend controller
|
|
42
|
+
*/
|
|
43
|
+
function generateBackend(name, Name, _controllers, _options) {
|
|
44
|
+
return `<?php
|
|
45
|
+
// InstantCMS 2. ${name}/backend.php
|
|
46
|
+
|
|
47
|
+
class ${Name}Backend extends cmsBackend {
|
|
48
|
+
|
|
49
|
+
protected $useOptions = true;
|
|
50
|
+
protected $showTaxonomy = true;
|
|
51
|
+
|
|
52
|
+
public function __construct($request) {
|
|
53
|
+
parent::__construct($request);
|
|
54
|
+
|
|
55
|
+
cmsTemplate::getInstance()->addChainLinks(
|
|
56
|
+
'Настройки',
|
|
57
|
+
$this->cms_config->href_to('controllers', '${name}')
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public function getBackendMenu() {
|
|
62
|
+
return [
|
|
63
|
+
[
|
|
64
|
+
'title' => '${Name}',
|
|
65
|
+
'url' => $this->cms_config->href_to(''),
|
|
66
|
+
'options' => ['icon' => 'component_${name}'],
|
|
67
|
+
],
|
|
68
|
+
[
|
|
69
|
+
'title' => 'Настройки',
|
|
70
|
+
'url' => $this->cms_config->href_to('options'),
|
|
71
|
+
'icon' => 'settings',
|
|
72
|
+
],
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public function validateVariants($${name}_item) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public function getContentDescription($item) {
|
|
81
|
+
return '';
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public function actionToggleEnabled($${name}_item) {
|
|
85
|
+
return $this->redirectToAction('index');
|
|
86
|
+
}
|
|
87
|
+
}`;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Generates frontend controller
|
|
91
|
+
*/
|
|
92
|
+
function generateFrontend(name, Name, controllers) {
|
|
93
|
+
const firstController = controllers[0]?.name || 'index';
|
|
94
|
+
return `<?php
|
|
95
|
+
// InstantCMS 2. ${name}/frontend.php
|
|
96
|
+
|
|
97
|
+
class ${Name}Frontend extends cmsFrontend {
|
|
98
|
+
|
|
99
|
+
protected $useOptions = false;
|
|
100
|
+
|
|
101
|
+
public function __construct($request) {
|
|
102
|
+
parent::__construct($request);
|
|
103
|
+
|
|
104
|
+
$this->setContext('${Name}', '${firstController}');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public function routes() {
|
|
108
|
+
return include __DIR__ . '/routes.php';
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
public function beforeWallPost($item, $user) {
|
|
112
|
+
return $item;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public function getSeoPatterns() {
|
|
116
|
+
return [
|
|
117
|
+
'index' => [
|
|
118
|
+
'title' => '{${name}_page}.title | {site.name}',
|
|
119
|
+
'description' => '{${name}_page}.description',
|
|
120
|
+
'keywords' => '{${name}_page}.keywords',
|
|
121
|
+
],
|
|
122
|
+
];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
public function getTagCategory() {
|
|
126
|
+
return [
|
|
127
|
+
'name' => '${name}',
|
|
128
|
+
'title' => '${Name}',
|
|
129
|
+
];
|
|
130
|
+
}
|
|
131
|
+
}`;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Generates model class
|
|
135
|
+
*/
|
|
136
|
+
function generateModel(name, Name, _controllers) {
|
|
137
|
+
return `<?php
|
|
138
|
+
// InstantCMS 2. ${name}/model.php
|
|
139
|
+
|
|
140
|
+
class ${Name}Model extends cmsModel {
|
|
141
|
+
|
|
142
|
+
public $table = '${name}';
|
|
143
|
+
public $cat_table = '${name}_cats';
|
|
144
|
+
|
|
145
|
+
public function __construct() {
|
|
146
|
+
parent::__construct();
|
|
147
|
+
|
|
148
|
+
$this->useCategories = true;
|
|
149
|
+
$this->cats_table = $this->cat_table;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public function get${Name}($id, $field = 'id') {
|
|
153
|
+
return $this->getItem($this->table, function ($item) {
|
|
154
|
+
$item['user'] = cmsModel::getInstance('users')->getUser($item['user_id']);
|
|
155
|
+
return $item;
|
|
156
|
+
}, [$field => $id]);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
public function get${Name}s($filters = [], $order = 'id DESC', $page = 1, $perpage = 20) {
|
|
160
|
+
$this->filterColumns($filters);
|
|
161
|
+
|
|
162
|
+
return $this->get($this->table, function ($item) {
|
|
163
|
+
$item['user'] = cmsModel::getInstance('users')->getUser($item['user_id']);
|
|
164
|
+
return $item;
|
|
165
|
+
}, $filters, $order, $page, $perpage);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
public function getCategories() {
|
|
169
|
+
return $this->get($this->cat_table, function ($item) {
|
|
170
|
+
return $item;
|
|
171
|
+
}, [], 'ordering ASC');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
public function add${Name}($data) {
|
|
175
|
+
$data['user_id'] = cmsUser::getInstance()->id;
|
|
176
|
+
$data['date_pub'] = date('Y-m-d H:i:s');
|
|
177
|
+
|
|
178
|
+
return $this->insert($this->table, $data);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
public function update${Name}($id, $data) {
|
|
182
|
+
$data['updated_at'] = date('Y-m-d H:i:s');
|
|
183
|
+
|
|
184
|
+
return $this->update($this->table, $id, $data);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
public function delete${Name}($id) {
|
|
188
|
+
return $this->delete($this->table, $id, [
|
|
189
|
+
'images' => ['path' => 'upload/${name}/', 'field' => 'image'],
|
|
190
|
+
]);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
public function countItems($category_id = null) {
|
|
194
|
+
$this->filterIsNull('is_deleted');
|
|
195
|
+
|
|
196
|
+
if ($category_id) {
|
|
197
|
+
$this->filterEqual('category_id', $category_id);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return $this->getCount($this->table);
|
|
201
|
+
}
|
|
202
|
+
}`;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Generates routes configuration
|
|
206
|
+
*/
|
|
207
|
+
function generateRoutes(name, Name, controllers) {
|
|
208
|
+
const routes = controllers
|
|
209
|
+
.map(c => {
|
|
210
|
+
return ` '${c.name}' => [
|
|
211
|
+
'/' => ['${Name}Frontend', 'actionIndex', '{${c.name}_page}'],
|
|
212
|
+
'/{slug}' => ['${Name}Frontend', 'actionView', '{slug}'],
|
|
213
|
+
],`;
|
|
214
|
+
})
|
|
215
|
+
.join('\n');
|
|
216
|
+
return `<?php
|
|
217
|
+
// InstantCMS 2. ${name}/routes.php
|
|
218
|
+
|
|
219
|
+
return [
|
|
220
|
+
${routes}
|
|
221
|
+
];`;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Generates backend index controller
|
|
225
|
+
*/
|
|
226
|
+
function generateBackendIndex(name, Name) {
|
|
227
|
+
return `<?php
|
|
228
|
+
// InstantCMS 2. ${name}/backend/index.php
|
|
229
|
+
|
|
230
|
+
class ${Name}Backend extends cmsBackend {
|
|
231
|
+
|
|
232
|
+
public function actionIndex() {
|
|
233
|
+
$grid = $this->loadDataGrid('${name}');
|
|
234
|
+
|
|
235
|
+
$this->renderTemplate('index', [
|
|
236
|
+
'grid' => $grid,
|
|
237
|
+
]);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
public function actionAdd() {
|
|
241
|
+
$form = $this->getForm('${name}');
|
|
242
|
+
|
|
243
|
+
if ($this->request->has('submit')) {
|
|
244
|
+
$data = $form->parse($this->request, ['submit']);
|
|
245
|
+
|
|
246
|
+
if ($form->validate($this, $data)) {
|
|
247
|
+
$id = $this->model->add${Name}($data);
|
|
248
|
+
|
|
249
|
+
cmsUser::addSessionMessage('Запись добавлена', 'success');
|
|
250
|
+
$this->redirectToAction('edit', $id);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
$this->renderTemplate('form', [
|
|
255
|
+
'form' => $form,
|
|
256
|
+
]);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
public function actionEdit($id) {
|
|
260
|
+
$item = $this->model->get${Name}($id);
|
|
261
|
+
|
|
262
|
+
if (!$item) {
|
|
263
|
+
cmsCore::error404();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
$form = $this->getForm('${name}');
|
|
267
|
+
|
|
268
|
+
if ($this->request->has('submit')) {
|
|
269
|
+
$data = $form->parse($this->request, ['submit']);
|
|
270
|
+
|
|
271
|
+
if ($form->validate($this, $data)) {
|
|
272
|
+
$this->model->update${Name}($id, $data);
|
|
273
|
+
|
|
274
|
+
cmsUser::addSessionMessage('Запись сохранена', 'success');
|
|
275
|
+
$this->redirectToAction('edit', $id);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
$this->renderTemplate('form', [
|
|
280
|
+
'item' => $item,
|
|
281
|
+
'form' => $form,
|
|
282
|
+
]);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
public function actionDelete($id) {
|
|
286
|
+
$this->model->delete${Name}($id);
|
|
287
|
+
|
|
288
|
+
cmsUser::addSessionMessage('Запись удалена', 'success');
|
|
289
|
+
$this->redirectToAction('index');
|
|
290
|
+
}
|
|
291
|
+
}`;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Generates menu configuration
|
|
295
|
+
*/
|
|
296
|
+
function generateMenu(name, Name, controllers) {
|
|
297
|
+
const firstController = controllers[0]?.name || name;
|
|
298
|
+
return `<?php
|
|
299
|
+
// InstantCMS 2. ${name}/menu.php
|
|
300
|
+
|
|
301
|
+
return [
|
|
302
|
+
'url' => href_to('${firstController}'),
|
|
303
|
+
'title' => '${Name}',
|
|
304
|
+
'icon' => 'component_${name}',
|
|
305
|
+
'visibility' => ['0' => 'all', '1' => 'auth', '2' => 'nonauth'],
|
|
306
|
+
];`;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Generates controller configuration
|
|
310
|
+
*/
|
|
311
|
+
function generateConfig(name, _Name, controllers) {
|
|
312
|
+
return `<?php
|
|
313
|
+
// InstantCMS 2. system/config/controllers/${name}.php
|
|
314
|
+
|
|
315
|
+
return [
|
|
316
|
+
'enabled' => true,
|
|
317
|
+
'controllers' => ['${controllers.map(c => c.name).join("', '")}'],
|
|
318
|
+
'options' => [
|
|
319
|
+
'is_premod' => false,
|
|
320
|
+
'is_tags' => true,
|
|
321
|
+
'is_rs' => true,
|
|
322
|
+
'hits_to_top' => true,
|
|
323
|
+
'profile_on' => true,
|
|
324
|
+
'pub_days' => 0,
|
|
325
|
+
'front_edit' => false,
|
|
326
|
+
],
|
|
327
|
+
];`;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Generates a complete component for InstantCMS
|
|
331
|
+
*
|
|
332
|
+
* @param opts - Configuration options for the component
|
|
333
|
+
* @returns Object containing generated files and metadata
|
|
334
|
+
*
|
|
335
|
+
* @example
|
|
336
|
+
* ```typescript
|
|
337
|
+
* const result = scaffoldComponent({
|
|
338
|
+
* addon_name: 'board',
|
|
339
|
+
* controllers: [{ name: 'index', actions: ['index', 'view', 'add', 'edit'], use_model: true }],
|
|
340
|
+
* options: { with_frontend: true, with_model: true }
|
|
341
|
+
* });
|
|
342
|
+
* ```
|
|
343
|
+
*/
|
|
344
|
+
function scaffoldComponent(opts) {
|
|
345
|
+
const { lowercase, UpperCamelCase } = (0, scaffold_1.normalizeAddonName)(opts.addon_name);
|
|
346
|
+
const files = {};
|
|
347
|
+
const options = {
|
|
348
|
+
with_frontend: opts.options?.with_frontend ?? true,
|
|
349
|
+
with_admin: opts.options?.with_admin ?? true,
|
|
350
|
+
with_model: opts.options?.with_model ?? true,
|
|
351
|
+
with_routes: opts.options?.with_routes ?? true,
|
|
352
|
+
with_menu: opts.options?.with_menu ?? true,
|
|
353
|
+
};
|
|
354
|
+
const controllers = opts.controllers || [
|
|
355
|
+
{ name: 'index', actions: ['index', 'view'], use_model: true },
|
|
356
|
+
];
|
|
357
|
+
files[`${lowercase}/manifest.json`] = generateManifest(lowercase, UpperCamelCase, controllers, options);
|
|
358
|
+
files[`${lowercase}/backend.php`] = generateBackend(lowercase, UpperCamelCase, controllers, options);
|
|
359
|
+
if (options.with_frontend) {
|
|
360
|
+
files[`${lowercase}/frontend.php`] = generateFrontend(lowercase, UpperCamelCase, controllers);
|
|
361
|
+
}
|
|
362
|
+
if (options.with_model || controllers.some(c => c.use_model)) {
|
|
363
|
+
files[`${lowercase}/model.php`] = generateModel(lowercase, UpperCamelCase, controllers);
|
|
364
|
+
}
|
|
365
|
+
if (options.with_routes) {
|
|
366
|
+
files[`${lowercase}/routes.php`] = generateRoutes(lowercase, UpperCamelCase, controllers);
|
|
367
|
+
}
|
|
368
|
+
files[`${lowercase}/backend/index.php`] = generateBackendIndex(lowercase, UpperCamelCase);
|
|
369
|
+
if (options.with_menu) {
|
|
370
|
+
files[`${lowercase}/menu.php`] = generateMenu(lowercase, UpperCamelCase, controllers);
|
|
371
|
+
}
|
|
372
|
+
files[`system/config/controllers/${lowercase}.php`] = generateConfig(lowercase, UpperCamelCase, controllers);
|
|
373
|
+
return {
|
|
374
|
+
addon_name: lowercase,
|
|
375
|
+
files,
|
|
376
|
+
controllers_count: controllers.length,
|
|
377
|
+
options,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
exports.componentToolSchema = {
|
|
381
|
+
name: 'scaffold_component',
|
|
382
|
+
description: 'Генерация полного компонента InstantCMS с backend, frontend, model',
|
|
383
|
+
inputSchema: {
|
|
384
|
+
type: 'object',
|
|
385
|
+
properties: {
|
|
386
|
+
addon_name: { type: 'string', description: 'Имя компонента' },
|
|
387
|
+
controllers: zod_1.z
|
|
388
|
+
.array(zod_1.z.object({
|
|
389
|
+
name: zod_1.z.string().describe('Имя контроллера'),
|
|
390
|
+
actions: zod_1.z.array(zod_1.z.string()).describe('Экшены'),
|
|
391
|
+
use_model: zod_1.z.boolean().optional().describe('Использовать модель'),
|
|
392
|
+
}))
|
|
393
|
+
.optional()
|
|
394
|
+
.describe('Контроллеры'),
|
|
395
|
+
options: zod_1.z
|
|
396
|
+
.object({
|
|
397
|
+
with_frontend: zod_1.z.boolean().optional().describe('С frontend'),
|
|
398
|
+
with_admin: zod_1.z.boolean().optional().describe('С админкой'),
|
|
399
|
+
with_model: zod_1.z.boolean().optional().describe('С моделью'),
|
|
400
|
+
with_routes: zod_1.z.boolean().optional().describe('С роутами'),
|
|
401
|
+
with_menu: zod_1.z.boolean().optional().describe('С меню'),
|
|
402
|
+
})
|
|
403
|
+
.optional()
|
|
404
|
+
.describe('Опции'),
|
|
405
|
+
},
|
|
406
|
+
required: ['addon_name'],
|
|
407
|
+
},
|
|
408
|
+
inputExamples: [
|
|
409
|
+
{
|
|
410
|
+
addon_name: 'board',
|
|
411
|
+
controllers: [{ name: 'index', actions: ['index', 'view', 'add', 'edit'], use_model: true }],
|
|
412
|
+
options: { with_frontend: true, with_model: true },
|
|
413
|
+
},
|
|
414
|
+
],
|
|
415
|
+
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.analyzeController = analyzeController;
|
|
4
|
+
exports.listControllers = listControllers;
|
|
5
|
+
exports.getControllerActionsList = getControllerActionsList;
|
|
6
|
+
exports.listSystemTraits = listSystemTraits;
|
|
7
|
+
const controllers_map_js_1 = require("../data/controllers-map.js");
|
|
8
|
+
function analyzeController(name, type) {
|
|
9
|
+
const controller = (0, controllers_map_js_1.getController)(name, type);
|
|
10
|
+
if (!controller) {
|
|
11
|
+
const suggestions = controllers_map_js_1.controllersMap.controllers
|
|
12
|
+
.filter(c => c.name.includes(name.toLowerCase()))
|
|
13
|
+
.slice(0, 5)
|
|
14
|
+
.map(c => ({ name: c.name, type: c.type }));
|
|
15
|
+
return {
|
|
16
|
+
error: `Контроллер "${name}" не найден`,
|
|
17
|
+
suggestions,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const traits = new Set();
|
|
21
|
+
for (const action of controller.actions) {
|
|
22
|
+
for (const trait of action.traits) {
|
|
23
|
+
traits.add(trait);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
name: controller.name,
|
|
28
|
+
className: controller.className,
|
|
29
|
+
type: controller.type,
|
|
30
|
+
extends: controller.extends,
|
|
31
|
+
filePath: controller.filePath,
|
|
32
|
+
actions: {
|
|
33
|
+
count: controller.actions.length,
|
|
34
|
+
list: controller.actions.map(a => ({
|
|
35
|
+
name: a.name,
|
|
36
|
+
className: a.className,
|
|
37
|
+
filePath: a.filePath,
|
|
38
|
+
hasParams: a.hasParams,
|
|
39
|
+
params: a.params,
|
|
40
|
+
visibility: a.visibility,
|
|
41
|
+
})),
|
|
42
|
+
},
|
|
43
|
+
traits: Array.from(traits),
|
|
44
|
+
hasBackendFolder: controller.hasBackendFolder,
|
|
45
|
+
hasModel: controller.hasModel,
|
|
46
|
+
modelFile: controller.modelFile,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function listControllers(filter) {
|
|
50
|
+
let controllers = controllers_map_js_1.controllersMap.controllers;
|
|
51
|
+
if (filter === 'frontend') {
|
|
52
|
+
controllers = controllers.filter(c => c.type === 'frontend');
|
|
53
|
+
}
|
|
54
|
+
else if (filter === 'backend') {
|
|
55
|
+
controllers = controllers.filter(c => c.type === 'backend');
|
|
56
|
+
}
|
|
57
|
+
const byType = {
|
|
58
|
+
frontend: [],
|
|
59
|
+
backend: [],
|
|
60
|
+
};
|
|
61
|
+
for (const ctrl of controllers) {
|
|
62
|
+
byType[ctrl.type].push({
|
|
63
|
+
name: ctrl.name,
|
|
64
|
+
className: ctrl.className,
|
|
65
|
+
actionsCount: ctrl.actions.length,
|
|
66
|
+
hasBackend: ctrl.hasBackendFolder,
|
|
67
|
+
hasModel: ctrl.hasModel,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
total: controllers.length,
|
|
72
|
+
byType,
|
|
73
|
+
allControllers: controllers.map(c => ({
|
|
74
|
+
name: c.name,
|
|
75
|
+
type: c.type,
|
|
76
|
+
extends: c.extends,
|
|
77
|
+
actionsCount: c.actions.length,
|
|
78
|
+
hasBackendFolder: c.hasBackendFolder,
|
|
79
|
+
hasModel: c.hasModel,
|
|
80
|
+
})),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function getControllerActionsList(name, type) {
|
|
84
|
+
const controller = (0, controllers_map_js_1.getController)(name, type);
|
|
85
|
+
if (!controller) {
|
|
86
|
+
return { error: `Контроллер "${name}" не найден` };
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
controller: controller.name,
|
|
90
|
+
type: controller.type,
|
|
91
|
+
actions: controller.actions.map(a => ({
|
|
92
|
+
name: a.name,
|
|
93
|
+
className: a.className,
|
|
94
|
+
filePath: a.filePath,
|
|
95
|
+
visibility: a.visibility,
|
|
96
|
+
hasParams: a.hasParams,
|
|
97
|
+
params: a.params,
|
|
98
|
+
traits: a.traits,
|
|
99
|
+
})),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function listSystemTraits() {
|
|
103
|
+
const allTraits = {};
|
|
104
|
+
for (const controller of controllers_map_js_1.controllersMap.controllers) {
|
|
105
|
+
for (const action of controller.actions) {
|
|
106
|
+
for (const trait of action.traits) {
|
|
107
|
+
const parts = trait.split('\\');
|
|
108
|
+
const namespace = parts.slice(0, -1).join('\\');
|
|
109
|
+
const traitName = parts[parts.length - 1];
|
|
110
|
+
if (!allTraits[namespace]) {
|
|
111
|
+
allTraits[namespace] = new Set();
|
|
112
|
+
}
|
|
113
|
+
allTraits[namespace].add(traitName);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const result = {};
|
|
118
|
+
for (const [ns, traits] of Object.entries(allTraits)) {
|
|
119
|
+
result[ns] = Array.from(traits).sort();
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
namespaces: Object.keys(result).length,
|
|
123
|
+
traits: result,
|
|
124
|
+
};
|
|
125
|
+
}
|