@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.
Files changed (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +308 -0
  3. package/dist/__tests__/artifact-tool.test.js +196 -0
  4. package/dist/__tests__/db-tool.test.js +152 -0
  5. package/dist/__tests__/define-tool.test.js +106 -0
  6. package/dist/__tests__/find-tool.test.js +185 -0
  7. package/dist/__tests__/get-component-api.test.js +144 -0
  8. package/dist/__tests__/hardening.test.js +73 -0
  9. package/dist/__tests__/hooks-tool.test.js +173 -0
  10. package/dist/__tests__/mcp-integration-extra.test.js +166 -0
  11. package/dist/__tests__/mcp-integration.test.js +53 -0
  12. package/dist/__tests__/pagination.test.js +114 -0
  13. package/dist/__tests__/performance-baseline.test.js +56 -0
  14. package/dist/__tests__/project-patch.test.js +144 -0
  15. package/dist/__tests__/project-source.test.js +44 -0
  16. package/dist/__tests__/project-workflows-extra.test.js +165 -0
  17. package/dist/__tests__/project-workflows.test.js +51 -0
  18. package/dist/__tests__/scaffold-addon-roundtrip.test.js +287 -0
  19. package/dist/__tests__/serialization.test.js +170 -0
  20. package/dist/__tests__/source-knowledge-parsers.test.js +42 -0
  21. package/dist/__tests__/template-development.test.js +78 -0
  22. package/dist/__tests__/template-productivity.test.js +87 -0
  23. package/dist/__tests__/tools.test.js +2143 -0
  24. package/dist/data/components.js +2818 -0
  25. package/dist/data/controllers-map.js +7571 -0
  26. package/dist/data/core-api.js +9356 -0
  27. package/dist/data/database-schema.js +4555 -0
  28. package/dist/data/events-map.js +1339 -0
  29. package/dist/data/fields-map.js +3692 -0
  30. package/dist/data/hooks.js +2257 -0
  31. package/dist/data/js-api.js +123 -0
  32. package/dist/data/libs-api.js +264 -0
  33. package/dist/data/routes-map.js +203 -0
  34. package/dist/data/schemas-validation.js +255 -0
  35. package/dist/data/schemas.js +1404 -0
  36. package/dist/data/traits-map.js +1004 -0
  37. package/dist/data/version-profiles.js +41 -0
  38. package/dist/data/widgets-map.js +131 -0
  39. package/dist/data/wysiwyg-map.js +486 -0
  40. package/dist/generated/components-source.js +14748 -0
  41. package/dist/generated/hooks-source.js +3399 -0
  42. package/dist/generated/knowledge-meta.js +101 -0
  43. package/dist/index.js +13 -0
  44. package/dist/registry/database-tools.js +112 -0
  45. package/dist/registry/extension-tools.js +473 -0
  46. package/dist/registry/generator-tools.js +506 -0
  47. package/dist/registry/knowledge-tools.js +441 -0
  48. package/dist/registry/language-tools.js +99 -0
  49. package/dist/registry/meta-tools.js +152 -0
  50. package/dist/registry/project-tools.js +48 -0
  51. package/dist/registry/resources.js +98 -0
  52. package/dist/registry/source-tools.js +211 -0
  53. package/dist/registry/template-development-tools.js +79 -0
  54. package/dist/server.js +32 -0
  55. package/dist/tools/addon-tool.js +1437 -0
  56. package/dist/tools/admin-partial-tool.js +498 -0
  57. package/dist/tools/api-tool.js +294 -0
  58. package/dist/tools/artifact-tool.js +95 -0
  59. package/dist/tools/cache-tool.js +360 -0
  60. package/dist/tools/component-tool.js +415 -0
  61. package/dist/tools/controllers-tool.js +125 -0
  62. package/dist/tools/cron-tool.js +197 -0
  63. package/dist/tools/crud-tool.js +659 -0
  64. package/dist/tools/db-tool.js +198 -0
  65. package/dist/tools/email-tool.js +222 -0
  66. package/dist/tools/external-api-tool.js +596 -0
  67. package/dist/tools/filter-tool.js +341 -0
  68. package/dist/tools/form-tool.js +275 -0
  69. package/dist/tools/grid-tool.js +189 -0
  70. package/dist/tools/hooks-tool.js +104 -0
  71. package/dist/tools/import-export-tool.js +548 -0
  72. package/dist/tools/lang-tool.js +251 -0
  73. package/dist/tools/layout-override-tool.js +125 -0
  74. package/dist/tools/layout-tool.js +548 -0
  75. package/dist/tools/maria-tool.js +127 -0
  76. package/dist/tools/mariadb.js +201 -0
  77. package/dist/tools/migration-tool.js +329 -0
  78. package/dist/tools/oauth-tool.js +520 -0
  79. package/dist/tools/parser/components-parser.js +76 -0
  80. package/dist/tools/parser/controllers-parser.js +313 -0
  81. package/dist/tools/parser/core-parser.js +294 -0
  82. package/dist/tools/parser/coverage-generator.js +424 -0
  83. package/dist/tools/parser/events-parser.js +127 -0
  84. package/dist/tools/parser/fields-parser.js +382 -0
  85. package/dist/tools/parser/hooks-parser.js +106 -0
  86. package/dist/tools/parser/sql-parser.js +197 -0
  87. package/dist/tools/parser/traits-parser.js +161 -0
  88. package/dist/tools/parser/widgets-parser.js +150 -0
  89. package/dist/tools/permission-tool.js +348 -0
  90. package/dist/tools/project-patch-tool.js +73 -0
  91. package/dist/tools/project-source-tool.js +188 -0
  92. package/dist/tools/project-workflow-tool.js +186 -0
  93. package/dist/tools/requirement-tool.js +212 -0
  94. package/dist/tools/scaffold-tool.js +815 -0
  95. package/dist/tools/seo-tool.js +412 -0
  96. package/dist/tools/source-tool.js +155 -0
  97. package/dist/tools/template-development-tool.js +271 -0
  98. package/dist/tools/template-overrides-tool.js +294 -0
  99. package/dist/tools/template-productivity-tool.js +319 -0
  100. package/dist/tools/template-tool.js +665 -0
  101. package/dist/tools/test-tool.js +183 -0
  102. package/dist/tools/webhook-tool.js +427 -0
  103. package/dist/tools/widget-tool.js +331 -0
  104. package/dist/tools/wysiwyg-tool.js +137 -0
  105. package/dist/types/scaffold.js +68 -0
  106. package/dist/utils/define-tool.js +37 -0
  107. package/dist/utils/find-tool.js +97 -0
  108. package/dist/utils/mcp-result.js +18 -0
  109. package/dist/utils/pagination.js +27 -0
  110. package/dist/utils/serialization.js +27 -0
  111. package/package.json +94 -0
@@ -0,0 +1,271 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.scaffoldCompleteTemplate = scaffoldCompleteTemplate;
4
+ exports.analyzeInstantCmsTemplate = analyzeInstantCmsTemplate;
5
+ exports.scaffoldTemplateOverride = scaffoldTemplateOverride;
6
+ exports.validateLayoutScheme = validateLayoutScheme;
7
+ exports.checkTemplateOverrideCompatibility = checkTemplateOverrideCompatibility;
8
+ const yaml_1 = require("yaml");
9
+ const scaffold_tool_js_1 = require("./scaffold-tool.js");
10
+ const layout_tool_js_1 = require("./layout-tool.js");
11
+ const safeNamePattern = /^[a-z][a-z0-9_]{1,63}$/;
12
+ function normalizeFiles(files) {
13
+ return Object.fromEntries(Object.entries(files).map(([path, content]) => [
14
+ path.replace(/\\/g, '/').replace(/^\.\//, ''),
15
+ content,
16
+ ]));
17
+ }
18
+ function assertSafeName(value, label) {
19
+ if (!safeNamePattern.test(value))
20
+ throw new Error(`${label} must match ${safeNamePattern}`);
21
+ }
22
+ function scaffoldCompleteTemplate(options) {
23
+ assertSafeName(options.name, 'Template name');
24
+ const base = (0, scaffold_tool_js_1.scaffoldTemplate)({
25
+ name: options.name,
26
+ title: options.title,
27
+ author: options.author,
28
+ });
29
+ const files = { ...base.files };
30
+ files['manifest.php'] = files['manifest.php'].replace("'has_options' => true", "'has_options' => false");
31
+ const inherits = (options.inherit ?? []).filter(Boolean);
32
+ if (inherits.length) {
33
+ for (const item of inherits)
34
+ assertSafeName(item, 'Inherited template name');
35
+ files['manifest.php'] = files['manifest.php'].replace('return [', `return [\n 'inherit' => [${inherits.map(item => `'${item}'`).join(', ')}],`);
36
+ }
37
+ files['js/main.js'] =
38
+ `(() => {\n 'use strict';\n document.documentElement.classList.add('js');\n})();\n`;
39
+ files['widgets/wrapper.tpl.php'] =
40
+ `<section class="widget<?= !empty($widget->css_class) ? ' ' . html($widget->css_class) : '' ?>">\n <?php if (!empty($widget->title)): ?>\n <h2 class="widget-title"><?= html($widget->title) ?></h2>\n <?php endif ?>\n <div class="widget-body"><?= $widget->body ?></div>\n</section>\n`;
41
+ files['main.tpl.php'] = files['main.tpl.php'].replace("<?= $this->linkCSS('css/main.css') ?>", "<?= $this->linkCSS('css/main.css') ?>\n <?= $this->linkJS('js/main.js') ?>");
42
+ const layout = options.with_layout_scheme === false
43
+ ? null
44
+ : (0, layout_tool_js_1.scaffoldLayoutScheme)({
45
+ template: options.name,
46
+ rows: [
47
+ {
48
+ title: 'Header',
49
+ outer_tag: 'header',
50
+ cols: [{ title: 'Header', position: 'header', col_class: 'col-12' }],
51
+ },
52
+ {
53
+ title: 'Content',
54
+ tag: 'main',
55
+ cols: [
56
+ { title: 'Main', position: 'content', col_class: 'col-lg-8' },
57
+ { title: 'Sidebar', position: 'right-top', col_class: 'col-lg-4' },
58
+ ],
59
+ },
60
+ {
61
+ title: 'Footer',
62
+ outer_tag: 'footer',
63
+ cols: [{ title: 'Footer', position: 'footer', col_class: 'col-12' }],
64
+ },
65
+ ],
66
+ });
67
+ return {
68
+ ...base,
69
+ files,
70
+ layout_scheme: layout,
71
+ checklist: [
72
+ `Install files into /templates/${options.name}/.`,
73
+ 'Import layout_scheme.yaml through the template layout administration UI if required.',
74
+ 'Run analyze_instantcms_template and validate_layout_scheme before packaging.',
75
+ ],
76
+ };
77
+ }
78
+ function analyzeInstantCmsTemplate(filesInput, theme) {
79
+ const normalized = normalizeFiles(filesInput);
80
+ if (theme)
81
+ assertSafeName(theme, 'Theme name');
82
+ const discovered = [
83
+ ...new Set(Object.keys(normalized).flatMap(path => path.match(/(?:^|\/)templates\/([^/]+)\/manifest\.php$/)?.[1] ?? [])),
84
+ ];
85
+ const selectedTheme = theme ?? (discovered.length === 1 ? discovered[0] : null);
86
+ const prefix = selectedTheme ? `templates/${selectedTheme}/` : '';
87
+ const files = prefix
88
+ ? Object.fromEntries(Object.entries(normalized)
89
+ .filter(([path]) => path.startsWith(prefix))
90
+ .map(([path, content]) => [path.slice(prefix.length), content]))
91
+ : normalized;
92
+ const paths = Object.keys(files);
93
+ const diagnostics = [];
94
+ if (!theme && discovered.length > 1) {
95
+ diagnostics.push({
96
+ code: 'MULTIPLE_TEMPLATES_FOUND',
97
+ severity: 'error',
98
+ path: 'templates/',
99
+ message: `Multiple templates found (${discovered.join(', ')}); select one with the theme parameter.`,
100
+ });
101
+ }
102
+ for (const required of ['manifest.php', 'main.tpl.php']) {
103
+ if (!(required in files))
104
+ diagnostics.push({
105
+ code: 'MISSING_TEMPLATE_FILE',
106
+ severity: 'error',
107
+ path: required,
108
+ message: `Required template file ${required} is missing.`,
109
+ });
110
+ }
111
+ if (files['manifest.json'])
112
+ diagnostics.push({
113
+ code: 'INVALID_TEMPLATE_MANIFEST',
114
+ severity: 'error',
115
+ path: 'manifest.json',
116
+ message: 'InstantCMS templates use manifest.php, not manifest.json.',
117
+ });
118
+ if (files['main.tpl.php'] && !files['main.tpl.php'].includes('$this->body()'))
119
+ diagnostics.push({
120
+ code: 'MISSING_TEMPLATE_BODY',
121
+ severity: 'error',
122
+ path: 'main.tpl.php',
123
+ message: 'Main template does not render $this->body().',
124
+ });
125
+ const phpTemplates = paths.filter(path => path.endsWith('.tpl.php'));
126
+ for (const path of phpTemplates) {
127
+ const content = files[path];
128
+ if (/echo\s+\$(?!this\b)[a-z_][a-z0-9_]*(?:\[[^\]]+\])?\s*;/i.test(content))
129
+ diagnostics.push({
130
+ code: 'POSSIBLE_UNESCAPED_TEMPLATE_OUTPUT',
131
+ severity: 'warning',
132
+ path,
133
+ message: 'Variable output may require context-aware escaping.',
134
+ });
135
+ }
136
+ const positions = [
137
+ ...new Set(Object.values(files).flatMap(content => [...content.matchAll(/(?:widgets|hasWidgetsOn)\(\s*['"]([^'"]+)['"]/g)].map(match => match[1]))),
138
+ ].sort();
139
+ const overrides = paths.filter(path => /^controllers\/[^/]+\/(?:backend\/)?[^/]+\.tpl\.php$/.test(path));
140
+ const layoutFiles = paths.filter(path => /(?:^|\/)layout[^/]*\.(?:ya?ml)$/i.test(path));
141
+ return {
142
+ theme: selectedTheme,
143
+ discovered_themes: discovered,
144
+ is_valid: !diagnostics.some(item => item.severity === 'error'),
145
+ summary: {
146
+ files: paths.length,
147
+ php_templates: phpTemplates.length,
148
+ overrides: overrides.length,
149
+ positions: positions.length,
150
+ layouts: layoutFiles.length,
151
+ },
152
+ widget_positions: positions,
153
+ overrides,
154
+ layout_files: layoutFiles,
155
+ diagnostics,
156
+ };
157
+ }
158
+ function scaffoldTemplateOverride(options) {
159
+ assertSafeName(options.theme, 'Theme name');
160
+ const source = options.source_path.replace(/\\/g, '/').replace(/^\.\//, '');
161
+ const match = source.match(/(?:^|\/)(?:templates\/[^/]+\/)?controllers\/([^/]+)\/(backend\/)?([^/]+\.tpl\.php)$/);
162
+ const controller = options.controller ?? match?.[1];
163
+ const actionFile = options.action ? `${options.action}.tpl.php` : match?.[3];
164
+ const backend = options.backend ?? Boolean(match?.[2]);
165
+ if (!controller || !actionFile)
166
+ throw new Error('Controller and action could not be derived from source_path');
167
+ assertSafeName(controller, 'Controller name');
168
+ if (!/^[a-z][a-z0-9_]{0,63}\.tpl\.php$/.test(actionFile))
169
+ throw new Error('Invalid template action');
170
+ const relative = `controllers/${controller}/${backend ? 'backend/' : ''}${actionFile}`;
171
+ return {
172
+ theme: options.theme,
173
+ source_path: source,
174
+ target_path: `templates/${options.theme}/${relative}`,
175
+ files: { [relative]: options.source_content },
176
+ review_notes: [
177
+ 'Keep the override as small as possible.',
178
+ 'Record the upstream InstantCMS version or commit used as the source.',
179
+ 'Recheck this override when the upstream source template changes.',
180
+ ],
181
+ };
182
+ }
183
+ function collectLayoutPositions(value, positions) {
184
+ if (Array.isArray(value))
185
+ return value.forEach(item => collectLayoutPositions(item, positions));
186
+ if (!value || typeof value !== 'object')
187
+ return;
188
+ for (const [key, child] of Object.entries(value)) {
189
+ if (key === 'position' && typeof child === 'string')
190
+ positions.push(child);
191
+ collectLayoutPositions(child, positions);
192
+ }
193
+ }
194
+ function validateLayoutScheme(yaml) {
195
+ const diagnostics = [];
196
+ let document;
197
+ try {
198
+ document = (0, yaml_1.parse)(yaml);
199
+ }
200
+ catch (error) {
201
+ return {
202
+ is_valid: false,
203
+ positions: [],
204
+ diagnostics: [
205
+ {
206
+ code: 'INVALID_LAYOUT_YAML',
207
+ severity: 'error',
208
+ message: error instanceof Error ? error.message : 'Invalid YAML',
209
+ },
210
+ ],
211
+ };
212
+ }
213
+ if (!document || typeof document !== 'object' || !('layout' in document))
214
+ diagnostics.push({
215
+ code: 'MISSING_LAYOUT_ROOT',
216
+ severity: 'error',
217
+ message: 'Layout YAML must contain a layout root.',
218
+ });
219
+ const positions = [];
220
+ collectLayoutPositions(document, positions);
221
+ const duplicates = [
222
+ ...new Set(positions.filter((item, index) => positions.indexOf(item) !== index)),
223
+ ];
224
+ if (duplicates.length)
225
+ diagnostics.push({
226
+ code: 'DUPLICATE_LAYOUT_POSITION',
227
+ severity: 'warning',
228
+ message: `Duplicate positions: ${duplicates.join(', ')}`,
229
+ });
230
+ if (!positions.length)
231
+ diagnostics.push({
232
+ code: 'MISSING_LAYOUT_POSITIONS',
233
+ severity: 'warning',
234
+ message: 'No widget positions were found.',
235
+ });
236
+ return {
237
+ is_valid: !diagnostics.some(item => item.severity === 'error'),
238
+ positions: [...new Set(positions)],
239
+ diagnostics,
240
+ };
241
+ }
242
+ function checkTemplateOverrideCompatibility(themeFilesInput, upstreamBeforeInput, upstreamAfterInput) {
243
+ const themeFiles = normalizeFiles(themeFilesInput);
244
+ const before = normalizeFiles(upstreamBeforeInput);
245
+ const after = normalizeFiles(upstreamAfterInput);
246
+ const overrides = Object.keys(themeFiles).filter(path => /^controllers\/[^/]+\/(?:backend\/)?[^/]+\.tpl\.php$/.test(path));
247
+ const findSource = (files, override) => Object.keys(files).find(path => path === override || path.endsWith(`/${override}`));
248
+ const results = overrides.map(path => {
249
+ const beforePath = findSource(before, path);
250
+ const afterPath = findSource(after, path);
251
+ const status = !afterPath
252
+ ? 'missing_upstream'
253
+ : !beforePath
254
+ ? 'untracked'
255
+ : before[beforePath] !== after[afterPath]
256
+ ? 'upstream_changed'
257
+ : 'compatible';
258
+ return {
259
+ path,
260
+ status,
261
+ upstream_before: beforePath ?? null,
262
+ upstream_after: afterPath ?? null,
263
+ requires_review: status !== 'compatible',
264
+ };
265
+ });
266
+ return {
267
+ overrides_checked: overrides.length,
268
+ requires_review: results.filter(item => item.requires_review).length,
269
+ results,
270
+ };
271
+ }
@@ -0,0 +1,294 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listTemplateOverrides = listTemplateOverrides;
4
+ exports.getTemplateOverrideInfo = getTemplateOverrideInfo;
5
+ function listTemplateOverrides(controller) {
6
+ const templateOverrides = getTemplateOverrides();
7
+ let filtered = templateOverrides;
8
+ if (controller) {
9
+ const controllerLower = controller.toLowerCase();
10
+ filtered = templateOverrides.filter(t => t.controller.toLowerCase() === controllerLower);
11
+ }
12
+ return {
13
+ total: filtered.length,
14
+ controller: controller || 'all',
15
+ overrides: filtered.map(t => ({
16
+ controller: t.controller,
17
+ action: t.action,
18
+ path: t.path,
19
+ description: t.description,
20
+ category: t.category,
21
+ })),
22
+ };
23
+ }
24
+ function getTemplateOverrideInfo(controller, action) {
25
+ const templateOverrides = getTemplateOverrides();
26
+ const controllerLower = controller.toLowerCase();
27
+ const found = templateOverrides.find(t => t.controller.toLowerCase() === controllerLower &&
28
+ (action ? t.action?.toLowerCase() === action.toLowerCase() : !t.action));
29
+ if (!found) {
30
+ return {
31
+ error: `Override not found for controller "${controller}"${action ? ` and action "${action}"` : ''}`,
32
+ available: templateOverrides
33
+ .filter(t => t.controller.toLowerCase() === controllerLower)
34
+ .map(t => ({
35
+ action: t.action || 'index',
36
+ path: t.path,
37
+ })),
38
+ };
39
+ }
40
+ return {
41
+ controller: found.controller,
42
+ action: found.action,
43
+ path: found.path,
44
+ description: found.description,
45
+ category: found.category,
46
+ example: `<?php
47
+ // В вашем шаблоне: templates/{theme}/controllers/${found.controller}/${found.action || 'index'}.tpl.php
48
+ // Или через renderPartial:
49
+ echo $this->renderPartial('${found.controller}', '${found.action || 'index'}', $vars);
50
+ `,
51
+ };
52
+ }
53
+ function getTemplateOverrides() {
54
+ return [
55
+ {
56
+ controller: 'content',
57
+ action: 'index',
58
+ path: 'templates/default/controllers/content/index.tpl.php',
59
+ description: 'Страница списка контента',
60
+ category: 'content',
61
+ },
62
+ {
63
+ controller: 'content',
64
+ action: 'view',
65
+ path: 'templates/default/controllers/content/view.tpl.php',
66
+ description: 'Страница просмотра материала',
67
+ category: 'content',
68
+ },
69
+ {
70
+ controller: 'content',
71
+ action: 'item',
72
+ path: 'templates/default/controllers/content/item.tpl.php',
73
+ description: 'Карточка материала в списке',
74
+ category: 'content',
75
+ },
76
+ {
77
+ controller: 'content',
78
+ action: 'category',
79
+ path: 'templates/default/controllers/content/category.tpl.php',
80
+ description: 'Страница категории',
81
+ category: 'content',
82
+ },
83
+ {
84
+ controller: 'users',
85
+ action: 'index',
86
+ path: 'templates/default/controllers/users/index.tpl.php',
87
+ description: 'Профили пользователей',
88
+ category: 'users',
89
+ },
90
+ {
91
+ controller: 'users',
92
+ action: 'profile',
93
+ path: 'templates/default/controllers/users/profile.tpl.php',
94
+ description: 'Страница профиля пользователя',
95
+ category: 'users',
96
+ },
97
+ {
98
+ controller: 'users',
99
+ action: 'registration',
100
+ path: 'templates/default/controllers/users/registration.tpl.php',
101
+ description: 'Форма регистрации',
102
+ category: 'users',
103
+ },
104
+ {
105
+ controller: 'users',
106
+ action: 'auth',
107
+ path: 'templates/default/controllers/users/auth.tpl.php',
108
+ description: 'Форма авторизации',
109
+ category: 'users',
110
+ },
111
+ {
112
+ controller: 'comments',
113
+ action: 'index',
114
+ path: 'templates/default/controllers/comments/index.tpl.php',
115
+ description: 'Список комментариев',
116
+ category: 'comments',
117
+ },
118
+ {
119
+ controller: 'comments',
120
+ action: 'item',
121
+ path: 'templates/default/controllers/comments/item.tpl.php',
122
+ description: 'Один комментарий',
123
+ category: 'comments',
124
+ },
125
+ {
126
+ controller: 'photos',
127
+ action: 'index',
128
+ path: 'templates/default/controllers/photos/index.tpl.php',
129
+ description: 'Альбомы фотографий',
130
+ category: 'photos',
131
+ },
132
+ {
133
+ controller: 'photos',
134
+ action: 'album',
135
+ path: 'templates/default/controllers/photos/album.tpl.php',
136
+ description: 'Фотографии альбома',
137
+ category: 'photos',
138
+ },
139
+ {
140
+ controller: 'photos',
141
+ action: 'image',
142
+ path: 'templates/default/controllers/photos/image.tpl.php',
143
+ description: 'Просмотр одного фото',
144
+ category: 'photos',
145
+ },
146
+ {
147
+ controller: 'blogs',
148
+ action: 'index',
149
+ path: 'templates/default/controllers/blogs/index.tpl.php',
150
+ description: 'Список блогов',
151
+ category: 'blogs',
152
+ },
153
+ {
154
+ controller: 'blogs',
155
+ action: 'post',
156
+ path: 'templates/default/controllers/blogs/post.tpl.php',
157
+ description: 'Пост в блоге',
158
+ category: 'blogs',
159
+ },
160
+ {
161
+ controller: 'forums',
162
+ action: 'index',
163
+ path: 'templates/default/controllers/forums/index.tpl.php',
164
+ description: 'Список форумов',
165
+ category: 'forums',
166
+ },
167
+ {
168
+ controller: 'forums',
169
+ action: 'thread',
170
+ path: 'templates/default/controllers/forums/thread.tpl.php',
171
+ description: 'Тема форума',
172
+ category: 'forums',
173
+ },
174
+ {
175
+ controller: 'forums',
176
+ action: 'post',
177
+ path: 'templates/default/controllers/forums/post.tpl.php',
178
+ description: 'Пост на форуме',
179
+ category: 'forums',
180
+ },
181
+ {
182
+ controller: 'messages',
183
+ action: 'index',
184
+ path: 'templates/default/controllers/messages/index.tpl.php',
185
+ description: 'Личные сообщения',
186
+ category: 'messages',
187
+ },
188
+ {
189
+ controller: 'messages',
190
+ action: 'chat',
191
+ path: 'templates/default/controllers/messages/chat.tpl.php',
192
+ description: 'Чат сообщений',
193
+ category: 'messages',
194
+ },
195
+ {
196
+ controller: 'wall',
197
+ action: 'index',
198
+ path: 'templates/default/controllers/wall/index.tpl.php',
199
+ description: 'Записи на стене',
200
+ category: 'wall',
201
+ },
202
+ {
203
+ controller: 'wall',
204
+ action: 'entry',
205
+ path: 'templates/default/controllers/wall/entry.tpl.php',
206
+ description: 'Одна запись на стене',
207
+ category: 'wall',
208
+ },
209
+ {
210
+ controller: 'activity',
211
+ action: 'index',
212
+ path: 'templates/default/controllers/activity/index.tpl.php',
213
+ description: 'Лента активности',
214
+ category: 'activity',
215
+ },
216
+ {
217
+ controller: 'groups',
218
+ action: 'index',
219
+ path: 'templates/default/controllers/groups/index.tpl.php',
220
+ description: 'Список групп',
221
+ category: 'groups',
222
+ },
223
+ {
224
+ controller: 'groups',
225
+ action: 'view',
226
+ path: 'templates/default/controllers/groups/view.tpl.php',
227
+ description: 'Страница группы',
228
+ category: 'groups',
229
+ },
230
+ {
231
+ controller: 'board',
232
+ action: 'index',
233
+ path: 'templates/default/controllers/board/index.tpl.php',
234
+ description: 'Доска объявлений',
235
+ category: 'board',
236
+ },
237
+ {
238
+ controller: 'board',
239
+ action: 'item',
240
+ path: 'templates/default/controllers/board/item.tpl.php',
241
+ description: 'Объявление',
242
+ category: 'board',
243
+ },
244
+ {
245
+ controller: 'board',
246
+ action: 'add',
247
+ path: 'templates/default/controllers/board/add.tpl.php',
248
+ description: 'Форма добавления объявления',
249
+ category: 'board',
250
+ },
251
+ {
252
+ controller: 'catalog',
253
+ action: 'index',
254
+ path: 'templates/default/controllers/catalog/index.tpl.php',
255
+ description: 'Каталог товаров',
256
+ category: 'catalog',
257
+ },
258
+ {
259
+ controller: 'catalog',
260
+ action: 'item',
261
+ path: 'templates/default/controllers/catalog/item.tpl.php',
262
+ description: 'Страница товара',
263
+ category: 'catalog',
264
+ },
265
+ {
266
+ controller: 'search',
267
+ action: 'index',
268
+ path: 'templates/default/controllers/search/index.tpl.php',
269
+ description: 'Результаты поиска',
270
+ category: 'search',
271
+ },
272
+ {
273
+ controller: 'tags',
274
+ action: 'index',
275
+ path: 'templates/default/controllers/tags/index.tpl.php',
276
+ description: 'Страница тега',
277
+ category: 'tags',
278
+ },
279
+ {
280
+ controller: 'favorites',
281
+ action: 'index',
282
+ path: 'templates/default/controllers/favorites/index.tpl.php',
283
+ description: 'Избранное пользователя',
284
+ category: 'favorites',
285
+ },
286
+ {
287
+ controller: 'feed',
288
+ action: 'index',
289
+ path: 'templates/default/controllers/feed/index.tpl.php',
290
+ description: 'Лента контента',
291
+ category: 'feed',
292
+ },
293
+ ];
294
+ }