iwgt 2.4.9 → 2.4.10

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.
@@ -0,0 +1,68 @@
1
+ {
2
+ "description": "Постоянные ссылки InSales для основных разделов сайта",
3
+ "links": {
4
+ "cart": {
5
+ "url": "{{ cart_url }}",
6
+ "description": "Ссылка на корзину покупок",
7
+ "usage": "Используется в виджетах для перехода в корзину",
8
+ "examples": [
9
+ "href=\"{{ cart_url }}\"",
10
+ "action=\"{{ cart_url }}\""
11
+ ]
12
+ },
13
+ "cart_items": {
14
+ "url": "/cart_items",
15
+ "description": "Ссылка на страницу корзины (для форм)",
16
+ "usage": "Используется в формах для обновления корзины",
17
+ "examples": [
18
+ "action=\"/cart_items\""
19
+ ]
20
+ },
21
+ "compare": {
22
+ "url": "/compares",
23
+ "description": "Ссылка на страницу сравнения товаров",
24
+ "usage": "Используется в шапке и других виджетах для перехода к сравнению",
25
+ "examples": [
26
+ "href=\"/compares\""
27
+ ]
28
+ },
29
+ "favorites": {
30
+ "url": "/favorites",
31
+ "description": "Ссылка на страницу избранных товаров",
32
+ "usage": "Используется в шапке и других виджетах для перехода к избранному",
33
+ "examples": [
34
+ "href=\"/favorites\""
35
+ ]
36
+ },
37
+ "personal_account": {
38
+ "url": "/client_account/orders",
39
+ "description": "Ссылка на личный кабинет (заказы)",
40
+ "usage": "Используется в шапке для перехода в личный кабинет",
41
+ "examples": [
42
+ "href=\"/client_account/orders\""
43
+ ]
44
+ },
45
+ "personal_feedback": {
46
+ "url": "/client_account/feedback",
47
+ "description": "Ссылка на форму обратной связи в личном кабинете",
48
+ "usage": "Используется в формах обратной связи",
49
+ "examples": [
50
+ "action=\"/client_account/feedback\""
51
+ ]
52
+ },
53
+ "search": {
54
+ "url": "/search",
55
+ "description": "Ссылка на страницу поиска",
56
+ "usage": "Используется в формах поиска",
57
+ "examples": [
58
+ "action=\"/search\""
59
+ ]
60
+ }
61
+ },
62
+ "notes": [
63
+ "Эти ссылки являются постоянными в системе InSales и не должны изменяться",
64
+ "cart_url - это переменная Liquid, которая автоматически генерирует правильную ссылку на корзину",
65
+ "Все остальные ссылки являются статическими путями",
66
+ "При создании виджетов используйте эти ссылки вместо выдуманных типа pages.favorite.url"
67
+ ]
68
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "2.0",
3
- "generatedAt": "2025-10-08T21:45:54.929Z",
3
+ "generatedAt": "2025-10-08T23:00:14.856Z",
4
4
  "description": "Справочник по библиотеке common.v2.js для InSales - набор готовых скриптов для разработки шаблонов",
5
5
  "installation": {
6
6
  "method": "liquid_tag",
@@ -289,6 +289,27 @@
289
289
  "hide"
290
290
  ]
291
291
  },
292
+ {
293
+ "name": "favorites",
294
+ "file": "favorites.svg",
295
+ "keywords": [
296
+ "favorites"
297
+ ]
298
+ },
299
+ {
300
+ "name": "favorites-f",
301
+ "file": "favorites-f.svg",
302
+ "keywords": [
303
+ "favorites-f"
304
+ ]
305
+ },
306
+ {
307
+ "name": "favorites-o",
308
+ "file": "favorites-o.svg",
309
+ "keywords": [
310
+ "favorites-o"
311
+ ]
312
+ },
292
313
  {
293
314
  "name": "file-code-o",
294
315
  "file": "file-code-o.svg",
@@ -312,28 +333,10 @@
312
333
  ]
313
334
  },
314
335
  {
315
- "name": "heart",
316
- "file": "heart.svg",
336
+ "name": "home",
337
+ "file": "home.svg",
317
338
  "keywords": [
318
- "избранное",
319
- "лайк",
320
- "сердце",
321
- "favorite",
322
- "like",
323
- "heart"
324
- ]
325
- },
326
- {
327
- "name": "heart-o",
328
- "file": "heart-o.svg",
329
- "keywords": [
330
- "избранное",
331
- "лайк",
332
- "сердце",
333
- "favorite",
334
- "like",
335
- "heart",
336
- "empty"
339
+ "home"
337
340
  ]
338
341
  },
339
342
  {
@@ -431,6 +434,13 @@
431
434
  "phone"
432
435
  ]
433
436
  },
437
+ {
438
+ "name": "order",
439
+ "file": "order.svg",
440
+ "keywords": [
441
+ "order"
442
+ ]
443
+ },
434
444
  {
435
445
  "name": "paper-plane",
436
446
  "file": "paper-plane.svg",
@@ -485,6 +495,13 @@
485
495
  "plus-circle"
486
496
  ]
487
497
  },
498
+ {
499
+ "name": "preorder",
500
+ "file": "preorder.svg",
501
+ "keywords": [
502
+ "preorder"
503
+ ]
504
+ },
488
505
  {
489
506
  "name": "question",
490
507
  "file": "question.svg",
@@ -653,7 +670,7 @@
653
670
  ]
654
671
  }
655
672
  ],
656
- "total": 76
673
+ "total": 80
657
674
  }
658
675
  },
659
676
  "categories": {
@@ -676,8 +693,6 @@
676
693
  "commerce": [
677
694
  "cart",
678
695
  "credit-card",
679
- "heart",
680
- "heart-o",
681
696
  "shopping-cart"
682
697
  ],
683
698
  "communication": [
@@ -4,7 +4,7 @@
4
4
  "description": "Liquid фильтры InSales",
5
5
  "totalCategories": 7,
6
6
  "totalFilters": 53,
7
- "generatedAt": "2025-10-08T21:45:54.918Z"
7
+ "generatedAt": "2025-10-08T23:00:14.836Z"
8
8
  },
9
9
  "categories": [
10
10
  {
@@ -4,7 +4,7 @@
4
4
  "description": "Liquid переменные InSales",
5
5
  "totalCategories": 19,
6
6
  "totalVariables": 436,
7
- "generatedAt": "2025-10-08T21:45:54.712Z"
7
+ "generatedAt": "2025-10-08T23:00:14.500Z"
8
8
  },
9
9
  "categories": [
10
10
  {
@@ -84,4 +84,27 @@ export declare function generateCollectionsMenu(args: {
84
84
  * Генерирует все файлы виджета
85
85
  */
86
86
  export declare function generateWidgetFiles(config: WidgetConfig): Record<string, any>;
87
+ /**
88
+ * Валидирует Liquid код на наличие несуществующих фильтров
89
+ */
90
+ export declare function validateLiquidFilters(liquidCode: string): {
91
+ isValid: boolean;
92
+ errors: Array<{
93
+ filter: string;
94
+ line: number;
95
+ column: number;
96
+ suggestion: string;
97
+ }>;
98
+ };
99
+ /**
100
+ * Проверяет и исправляет несуществующие фильтры в Liquid коде
101
+ */
102
+ export declare function fixInvalidFilters(liquidCode: string): {
103
+ fixedCode: string;
104
+ fixes: Array<{
105
+ filter: string;
106
+ line: number;
107
+ suggestion: string;
108
+ }>;
109
+ };
87
110
  //# sourceMappingURL=index.d.ts.map
@@ -1038,7 +1038,30 @@ export function generateWidgetFiles(config) {
1038
1038
  files['settings_form.json'] = settingsForm.form;
1039
1039
  files['settings_form'] = { settingsCount: settingsForm.count }; // метаинформация
1040
1040
  // snippet.liquid
1041
- files['snippet.liquid'] = generateSnippetLiquid(config);
1041
+ const liquidCode = generateSnippetLiquid(config);
1042
+ // Валидируем Liquid код на несуществующие фильтры
1043
+ const validation = validateLiquidFilters(liquidCode);
1044
+ if (!validation.isValid) {
1045
+ console.warn('⚠️ Обнаружены несуществующие фильтры в Liquid коде:');
1046
+ validation.errors.forEach(error => {
1047
+ console.warn(` - Строка ${error.line}: фильтр '${error.filter}' - ${error.suggestion}`);
1048
+ });
1049
+ // Автоматически исправляем несуществующие фильтры
1050
+ const fixed = fixInvalidFilters(liquidCode);
1051
+ if (fixed.fixes.length > 0) {
1052
+ console.log('✅ Автоматически исправлены несуществующие фильтры:');
1053
+ fixed.fixes.forEach(fix => {
1054
+ console.log(` - Строка ${fix.line}: ${fix.suggestion}`);
1055
+ });
1056
+ files['snippet.liquid'] = fixed.fixedCode;
1057
+ }
1058
+ else {
1059
+ files['snippet.liquid'] = liquidCode;
1060
+ }
1061
+ }
1062
+ else {
1063
+ files['snippet.liquid'] = liquidCode;
1064
+ }
1042
1065
  // snippet.scss
1043
1066
  files['snippet.scss'] = generateSnippetScss(config);
1044
1067
  // snippet.js
@@ -1049,4 +1072,71 @@ export function generateWidgetFiles(config) {
1049
1072
  }
1050
1073
  return files;
1051
1074
  }
1075
+ /**
1076
+ * Валидирует Liquid код на наличие несуществующих фильтров
1077
+ */
1078
+ export function validateLiquidFilters(liquidCode) {
1079
+ const invalidFiltersList = [
1080
+ { name: 't', suggestion: 'Используйте messages или widget_messages для переводов' },
1081
+ { name: 'translate', suggestion: 'Используйте messages для переводов' },
1082
+ { name: 'i18n', suggestion: 'Используйте messages для переводов' },
1083
+ { name: 'l', suggestion: 'Используйте messages для переводов' },
1084
+ { name: 'localize', suggestion: 'Используйте messages для переводов' },
1085
+ { name: 'tr', suggestion: 'Используйте messages для переводов' }
1086
+ ];
1087
+ const errors = [];
1088
+ const lines = liquidCode.split('\n');
1089
+ lines.forEach((line, lineIndex) => {
1090
+ invalidFiltersList.forEach(invalidFilter => {
1091
+ // Ищем паттерн | filter_name
1092
+ const regex = new RegExp(`\\|\\s*${invalidFilter.name}\\b`, 'g');
1093
+ let match;
1094
+ while ((match = regex.exec(line)) !== null) {
1095
+ errors.push({
1096
+ filter: invalidFilter.name,
1097
+ line: lineIndex + 1,
1098
+ column: match.index + 1,
1099
+ suggestion: invalidFilter.suggestion
1100
+ });
1101
+ }
1102
+ });
1103
+ });
1104
+ return {
1105
+ isValid: errors.length === 0,
1106
+ errors
1107
+ };
1108
+ }
1109
+ /**
1110
+ * Проверяет и исправляет несуществующие фильтры в Liquid коде
1111
+ */
1112
+ export function fixInvalidFilters(liquidCode) {
1113
+ const fixes = [];
1114
+ let fixedCode = liquidCode;
1115
+ // Исправляем фильтр 't' на messages
1116
+ const tRegex = /\|\s*t\b/g;
1117
+ let match;
1118
+ while ((match = tRegex.exec(fixedCode)) !== null) {
1119
+ const beforeMatch = fixedCode.substring(0, match.index);
1120
+ const afterMatch = fixedCode.substring(match.index + match[0].length);
1121
+ // Определяем, что это за контекст
1122
+ const contextBefore = beforeMatch.substring(Math.max(0, beforeMatch.length - 50));
1123
+ if (contextBefore.includes('widget_messages')) {
1124
+ // Если это в контексте widget_messages, оставляем как есть
1125
+ continue;
1126
+ }
1127
+ else {
1128
+ // Заменяем на messages
1129
+ fixedCode = beforeMatch + '| messages' + afterMatch;
1130
+ fixes.push({
1131
+ filter: 't',
1132
+ line: fixedCode.substring(0, match.index).split('\n').length,
1133
+ suggestion: 'Заменен на messages'
1134
+ });
1135
+ }
1136
+ }
1137
+ return {
1138
+ fixedCode,
1139
+ fixes
1140
+ };
1141
+ }
1052
1142
  //# sourceMappingURL=index.js.map
@@ -57,7 +57,7 @@ const httpServer = createServer(async (req, res) => {
57
57
  res.end(JSON.stringify({
58
58
  status: 'ok',
59
59
  service: 'InSales Widgets MCP Server',
60
- version: '2.4.7',
60
+ version: '2.4.10',
61
61
  transport: 'SSE',
62
62
  endpoints: {
63
63
  sse: '/sse',
package/dist/server.js CHANGED
@@ -26,7 +26,7 @@ export class WidgetServer {
26
26
  constructor() {
27
27
  this.server = new Server({
28
28
  name: 'insales-widgets',
29
- version: '2.4.9',
29
+ version: '2.4.10',
30
30
  }, {
31
31
  capabilities: {
32
32
  tools: {},
@@ -238,6 +238,19 @@ export class WidgetServer {
238
238
  },
239
239
  },
240
240
  },
241
+ {
242
+ name: 'get_insales_permanent_links',
243
+ description: 'Получить постоянные ссылки InSales для основных разделов сайта (корзина, избранное, сравнение, личный кабинет). Используйте эти ссылки вместо выдуманных типа pages.favorite.url',
244
+ inputSchema: {
245
+ type: 'object',
246
+ properties: {
247
+ search: {
248
+ type: 'string',
249
+ description: 'Поиск ссылок по названию или описанию',
250
+ },
251
+ },
252
+ },
253
+ },
241
254
  ],
242
255
  }));
243
256
  // Список ресурсов
@@ -521,6 +534,15 @@ export class WidgetServer {
521
534
  },
522
535
  ],
523
536
  };
537
+ case 'get_insales_permanent_links':
538
+ return {
539
+ content: [
540
+ {
541
+ type: 'text',
542
+ text: JSON.stringify(tools.getInsalesPermanentLinks(args || {}), null, 2),
543
+ },
544
+ ],
545
+ };
524
546
  default:
525
547
  throw new Error(`Unknown tool: ${name}`);
526
548
  }
@@ -14,22 +14,17 @@ export declare function getAvailableIcons(args?: any): any;
14
14
  /**
15
15
  * Получить информацию о категории виджетов
16
16
  */
17
- export declare function getCategoryInfo(args: any): any;
17
+ export declare function getCategoryInfo(args?: any): any;
18
18
  /**
19
19
  * Получить информацию о библиотеках
20
20
  */
21
21
  export declare function getLibrariesInfo(args?: any): any;
22
- /**
23
- * Получить справочник Liquid переменных
24
- */
25
- export declare function getLiquidVariables(args?: any): any;
26
22
  /**
27
23
  * Получить справочник Liquid фильтров
28
24
  */
29
25
  export declare function getLiquidFilters(args?: any): any;
30
26
  /**
31
- * Получить справочник CommonJS API v2 для InSales
32
- * ОБНОВЛЕНО: использует commonjs-api-complete.json с акцентом на глобальные переменные
27
+ * Получить справочник CommonJS API
33
28
  */
34
29
  export declare function getCommonJSAPI(args?: any): any;
35
30
  /**
@@ -37,8 +32,15 @@ export declare function getCommonJSAPI(args?: any): any;
37
32
  */
38
33
  export declare function getCollectionsMenuPatterns(args?: any): any;
39
34
  /**
40
- * Получить справочник API библиотек
41
- * Объединяет информацию из libraries-registry и libraries-api-reference
35
+ * Получить API библиотек
42
36
  */
43
37
  export declare function getLibrariesAPI(args?: any): any;
38
+ /**
39
+ * Получить справочник Liquid переменных
40
+ */
41
+ export declare function getLiquidVariables(args?: any): any;
42
+ /**
43
+ * Получить постоянные ссылки InSales
44
+ */
45
+ export declare function getInsalesPermanentLinks(args?: any): any;
44
46
  //# sourceMappingURL=index.d.ts.map
@@ -12,6 +12,7 @@ import liquidFilters from '../data/references/liquid-filters.json' with { type:
12
12
  import commonjsApiComplete from '../data/references/commonjs-api-complete.json' with { type: 'json' };
13
13
  import collectionsMenuPatterns from '../data/references/collections-menu-patterns.json' with { type: 'json' };
14
14
  import librariesApiReference from '../data/references/libraries-api-reference.json' with { type: 'json' };
15
+ import insalesPermanentLinks from '../data/insales-permanent-links.json' with { type: 'json' };
15
16
  /**
16
17
  * Получить список блок-темплейтов с фильтрацией
17
18
  */
@@ -31,17 +32,15 @@ export function getBlockTemplates(args = {}) {
31
32
  }
32
33
  return {
33
34
  total: templates.length,
34
- category: category || 'all',
35
35
  templates: templates.map((t) => ({
36
36
  handle: t.handle,
37
37
  name: t.name,
38
+ description: t.description,
38
39
  keywords: t.keywords,
39
- fields: t.fields.map((f) => ({
40
- name: f.name,
41
- handle: f.handle,
42
- kind: f.kind,
43
- })),
44
- })),
40
+ category: t.category,
41
+ type: t.type,
42
+ usage: t.usage
43
+ }))
45
44
  };
46
45
  }
47
46
  /**
@@ -50,12 +49,10 @@ export function getBlockTemplates(args = {}) {
50
49
  */
51
50
  export function getAvailableIcons(args = {}) {
52
51
  const { search, category } = args;
53
- const iconsData = iconsRegistry;
54
- const defaultIcons = iconsData.iconSets?.default?.icons || [];
55
- let icons = defaultIcons;
52
+ const data = iconsRegistry;
53
+ let icons = data.icons || [];
56
54
  if (category) {
57
- const categoryIcons = iconsData.categories?.[category] || [];
58
- icons = icons.filter((icon) => categoryIcons.includes(icon.name));
55
+ icons = icons.filter((icon) => icon.category === category);
59
56
  }
60
57
  if (search) {
61
58
  const searchLower = search.toLowerCase();
@@ -64,46 +61,35 @@ export function getAvailableIcons(args = {}) {
64
61
  }
65
62
  return {
66
63
  total: icons.length,
67
- description: 'Иконки используются через иконочный шрифт, который уже подключен в шаблоне',
68
- usage: {
69
- liquid: 'В Liquid шаблонах: <i class="icon icon-название"></i>',
70
- html: 'В HTML/JS: <i class="icon icon-название"></i>',
71
- example: '<i class="icon icon-cart"></i> <!-- выведет иконку корзины -->',
72
- note: 'Фильтра | icon НЕ СУЩЕСТВУЕТ в InSales. Используйте только HTML классы.'
73
- },
74
64
  icons: icons.map((icon) => ({
75
65
  name: icon.name,
66
+ class: `icon-${icon.name}`,
76
67
  keywords: icon.keywords,
77
- htmlClass: `<i class="icon icon-${icon.name}"></i>`,
78
- className: `icon icon-${icon.name}`,
79
- })),
68
+ category: icon.category,
69
+ usage: `<i class="icon icon-${icon.name}"></i>`
70
+ }))
80
71
  };
81
72
  }
82
73
  /**
83
74
  * Получить информацию о категории виджетов
84
75
  */
85
- export function getCategoryInfo(args) {
76
+ export function getCategoryInfo(args = {}) {
86
77
  const { category } = args;
87
78
  if (!category) {
88
- const categories = Object.keys(categorySettings);
89
79
  return {
90
- available_categories: categories,
91
- message: "Укажите category для получения детальной информации",
80
+ error: 'Не указана категория'
92
81
  };
93
82
  }
94
- const categoryData = categorySettings[category];
83
+ const data = categorySettings;
84
+ const categoryData = data.categories?.[category];
95
85
  if (!categoryData) {
96
86
  return {
97
- error: `Категория "${category}" не найдена`,
98
- available_categories: Object.keys(categorySettings),
87
+ error: `Категория '${category}' не найдена`
99
88
  };
100
89
  }
101
90
  return {
102
91
  category,
103
- libraries: categoryData.libraries,
104
- common_settings: categoryData.commonSettings,
105
- examples: categoryData.examples || [],
106
- block_templates: (categoryBlockTemplates[category] || []).map((t) => t.handle),
92
+ ...categoryData
107
93
  };
108
94
  }
109
95
  /**
@@ -111,339 +97,79 @@ export function getCategoryInfo(args) {
111
97
  */
112
98
  export function getLibrariesInfo(args = {}) {
113
99
  const { category } = args;
100
+ const data = librariesRegistry;
101
+ let libraries = data.libraries || [];
114
102
  if (category) {
115
- const categoryData = categorySettings[category];
116
- if (!categoryData) {
117
- return { error: `Категория "${category}" не найдена` };
118
- }
119
- const categoryLibraries = categoryData.libraries;
120
- const librariesData = librariesRegistry.libraries || [];
121
- const libraries = librariesData.filter((lib) => categoryLibraries.includes(lib.name));
122
- return {
123
- category,
124
- libraries: libraries.map((lib) => ({
125
- name: lib.name,
126
- description: lib.description,
127
- documentation: lib.documentation,
128
- })),
129
- };
103
+ libraries = libraries.filter((lib) => lib.category === category);
130
104
  }
131
- const librariesData = librariesRegistry.libraries || [];
132
105
  return {
133
- libraries: librariesData.map((lib) => ({
106
+ total: libraries.length,
107
+ libraries: libraries.map((lib) => ({
134
108
  name: lib.name,
109
+ handle: lib.handle,
135
110
  description: lib.description,
136
- documentation: lib.documentation,
137
- categories: lib.categories,
138
- })),
111
+ category: lib.category,
112
+ type: lib.type,
113
+ usage: lib.usage
114
+ }))
139
115
  };
140
116
  }
141
- /**
142
- * Получить справочник Liquid переменных
143
- */
144
- export function getLiquidVariables(args = {}) {
145
- const { category, search } = args;
146
- const data = liquidVariables;
147
- if (!category && !search) {
148
- return {
149
- categories: data.categories.map(cat => ({
150
- name: cat.name,
151
- count: cat.variables.length,
152
- })),
153
- total_variables: data.categories.reduce((sum, cat) => sum + cat.variables.length, 0),
154
- message: "Укажите category или search для получения переменных",
155
- };
156
- }
157
- if (category) {
158
- const cat = data.categories.find(c => c.name.toLowerCase() === category.toLowerCase());
159
- if (!cat) {
160
- return {
161
- error: `Категория "${category}" не найдена`,
162
- available_categories: data.categories.map(c => c.name),
163
- };
164
- }
165
- return {
166
- category: cat.name,
167
- count: cat.variables.length,
168
- variables: cat.variables,
169
- };
170
- }
171
- if (search) {
172
- const searchLower = search.toLowerCase();
173
- const results = [];
174
- data.categories.forEach(cat => {
175
- cat.variables.forEach(v => {
176
- if (v.name.toLowerCase().includes(searchLower) ||
177
- v.description?.toLowerCase().includes(searchLower)) {
178
- results.push({
179
- ...v,
180
- category: cat.name,
181
- });
182
- }
183
- });
184
- });
185
- return {
186
- search,
187
- count: results.length,
188
- variables: results,
189
- };
190
- }
191
- }
192
117
  /**
193
118
  * Получить справочник Liquid фильтров
194
119
  */
195
120
  export function getLiquidFilters(args = {}) {
196
121
  const { category, search } = args;
197
122
  const data = liquidFilters;
198
- if (!category && !search) {
199
- return {
200
- categories: data.categories.map(cat => ({
201
- name: cat.name,
202
- count: cat.filters.length,
203
- })),
204
- total_filters: data.categories.reduce((sum, cat) => sum + cat.filters.length, 0),
205
- message: "Укажите category или search для получения фильтров",
206
- };
207
- }
123
+ let filters = data.filters || [];
208
124
  if (category) {
209
- const cat = data.categories.find(c => c.name.toLowerCase() === category.toLowerCase());
210
- if (!cat) {
211
- return {
212
- error: `Категория "${category}" не найдена`,
213
- available_categories: data.categories.map(c => c.name),
214
- };
215
- }
216
- return {
217
- category: cat.name,
218
- count: cat.filters.length,
219
- filters: cat.filters,
220
- };
125
+ filters = filters.filter((filter) => filter.category === category);
221
126
  }
222
127
  if (search) {
223
128
  const searchLower = search.toLowerCase();
224
- const results = [];
225
- data.categories.forEach(cat => {
226
- cat.filters.forEach(f => {
227
- if (f.name.toLowerCase().includes(searchLower) ||
228
- f.description?.toLowerCase().includes(searchLower)) {
229
- results.push({
230
- ...f,
231
- category: cat.name,
232
- });
233
- }
234
- });
235
- });
236
- return {
237
- search,
238
- count: results.length,
239
- filters: results,
240
- };
129
+ filters = filters.filter((filter) => filter.name.toLowerCase().includes(searchLower) ||
130
+ filter.description?.toLowerCase().includes(searchLower));
241
131
  }
132
+ return {
133
+ total: filters.length,
134
+ categories: data.categories || [],
135
+ filters: filters.map((filter) => ({
136
+ name: filter.name,
137
+ description: filter.description,
138
+ category: filter.category,
139
+ syntax: filter.syntax,
140
+ examples: filter.examples
141
+ }))
142
+ };
242
143
  }
243
144
  /**
244
- * Получить справочник CommonJS API v2 для InSales
245
- * ОБНОВЛЕНО: использует commonjs-api-complete.json с акцентом на глобальные переменные
145
+ * Получить справочник CommonJS API
246
146
  */
247
147
  export function getCommonJSAPI(args = {}) {
248
148
  const { category, module, search } = args;
249
- const completeData = commonjsApiComplete;
250
- // Без параметров - критическая информация и обзор
251
- if (!category && !module && !search) {
252
- return {
253
- version: completeData.version,
254
- title: completeData.title,
255
- description: completeData.description,
256
- critical_info: completeData.critical_info,
257
- installation: completeData.installation,
258
- global_modules: Object.keys(completeData.global_modules).map(name => ({
259
- name,
260
- description: completeData.global_modules[name].description,
261
- global_access: completeData.global_modules[name].global_access,
262
- declarative: completeData.global_modules[name].declarative || false,
263
- has_data_attributes: Object.keys(completeData.global_modules[name].data_attributes || {}).length > 0,
264
- methods_count: Object.keys(completeData.global_modules[name].methods || {}).length,
265
- events_count: Object.keys(completeData.global_modules[name].events || {}).length,
266
- })),
267
- ui_components: Object.keys(completeData.ui_components || {}).map(key => ({
268
- name: completeData.ui_components[key].name,
269
- description: completeData.ui_components[key].description,
270
- declarative: completeData.ui_components[key].declarative,
271
- no_js_needed: completeData.ui_components[key].no_js_needed,
272
- })),
273
- quick_reference: completeData.quick_reference,
274
- message: "⚠️ ВСЕ модули доступны ГЛОБАЛЬНО! НЕ используйте import. Укажите module или search для детальной информации."
275
- };
149
+ const data = commonjsApiComplete;
150
+ let modules = data.modules || [];
151
+ if (module) {
152
+ modules = modules.filter((mod) => mod.name === module);
276
153
  }
277
- // Поиск по категории (для UI компонентов)
278
154
  if (category) {
279
- const categoryMap = {
280
- 'product': ['Cart', 'Products', 'ajax_products', 'ajax_product', 'accessories'],
281
- 'cart': ['Cart'],
282
- 'lists': ['Compare', 'FavoritesProducts'],
283
- 'search': ['AjaxSearch'],
284
- 'forms': ['feedback_form', 'reviews_form', 'comments_form'],
285
- 'events': ['EventBus'],
286
- 'helpers': ['Shop', 'Template', 'ajaxAPI'],
287
- 'checkout': ['quick_checkout']
288
- };
289
- const modulesInCategory = categoryMap[category] || [];
290
- const results = {
291
- category,
292
- global_modules: [],
293
- ui_components: [],
294
- };
295
- modulesInCategory.forEach((modName) => {
296
- if (completeData.global_modules[modName]) {
297
- results.global_modules.push({
298
- name: modName,
299
- ...completeData.global_modules[modName]
300
- });
301
- }
302
- if (completeData.ui_components[modName]) {
303
- results.ui_components.push({
304
- key: modName,
305
- ...completeData.ui_components[modName]
306
- });
307
- }
308
- });
309
- return results;
310
- }
311
- // Поиск по модулю
312
- if (module) {
313
- // Сначала ищем в глобальных модулях
314
- if (completeData.global_modules[module]) {
315
- const mod = completeData.global_modules[module];
316
- return {
317
- type: 'global_module',
318
- name: module,
319
- ...mod,
320
- usage_note: mod.declarative ?
321
- "💡 Этот модуль поддерживает декларативную работу через data-атрибуты. Используйте их вместо JavaScript где возможно." :
322
- "⚠️ Этот модуль требует JavaScript для работы.",
323
- best_practices: completeData.best_practices,
324
- };
325
- }
326
- // Затем ищем в UI компонентах
327
- if (completeData.ui_components[module]) {
328
- const comp = completeData.ui_components[module];
329
- return {
330
- type: 'ui_component',
331
- key: module,
332
- ...comp,
333
- usage_note: comp.no_js_needed ?
334
- "✅ Этот компонент работает ПОЛНОСТЬЮ без JavaScript!" :
335
- "⚠️ Этот компонент требует инициализации через JavaScript.",
336
- };
337
- }
338
- return {
339
- error: `Модуль "${module}" не найден`,
340
- available_global_modules: Object.keys(completeData.global_modules),
341
- available_ui_components: Object.keys(completeData.ui_components || {}),
342
- };
155
+ modules = modules.filter((mod) => mod.category === category);
343
156
  }
344
- // Поиск по ключевому слову
345
157
  if (search) {
346
158
  const searchLower = search.toLowerCase();
347
- const results = {
348
- global_modules: [],
349
- data_attributes: [],
350
- methods: [],
351
- events: [],
352
- ui_components: [],
353
- patterns: [],
354
- };
355
- // Поиск в глобальных модулях
356
- Object.entries(completeData.global_modules).forEach(([name, mod]) => {
357
- // Поиск по имени и описанию модуля
358
- if (name.toLowerCase().includes(searchLower) ||
359
- mod.description?.toLowerCase().includes(searchLower)) {
360
- results.global_modules.push({
361
- name,
362
- description: mod.description,
363
- global_access: mod.global_access,
364
- declarative: mod.declarative,
365
- });
366
- }
367
- // Поиск по data-атрибутам
368
- if (mod.data_attributes) {
369
- Object.entries(mod.data_attributes).forEach(([attrName, attr]) => {
370
- if (attrName.toLowerCase().includes(searchLower) ||
371
- attr.description?.toLowerCase().includes(searchLower)) {
372
- results.data_attributes.push({
373
- name: attrName,
374
- module: name,
375
- ...attr,
376
- });
377
- }
378
- });
379
- }
380
- // Поиск по методам
381
- if (mod.methods) {
382
- Object.entries(mod.methods).forEach(([methodName, method]) => {
383
- if (methodName.toLowerCase().includes(searchLower) ||
384
- method.description?.toLowerCase().includes(searchLower)) {
385
- results.methods.push({
386
- name: methodName,
387
- module: name,
388
- ...method,
389
- });
390
- }
391
- });
392
- }
393
- // Поиск по событиям
394
- if (mod.events) {
395
- Object.entries(mod.events).forEach(([eventName, event]) => {
396
- if (eventName.toLowerCase().includes(searchLower) ||
397
- event.description?.toLowerCase().includes(searchLower)) {
398
- results.events.push({
399
- name: eventName,
400
- module: name,
401
- ...event,
402
- });
403
- }
404
- });
405
- }
406
- });
407
- // Поиск в UI компонентах
408
- if (completeData.ui_components) {
409
- Object.entries(completeData.ui_components).forEach(([key, comp]) => {
410
- if (key.toLowerCase().includes(searchLower) ||
411
- comp.name?.toLowerCase().includes(searchLower) ||
412
- comp.description?.toLowerCase().includes(searchLower)) {
413
- results.ui_components.push({
414
- key,
415
- ...comp,
416
- });
417
- }
418
- });
419
- }
420
- // Поиск в паттернах
421
- if (completeData.common_patterns) {
422
- Object.entries(completeData.common_patterns).forEach(([key, pattern]) => {
423
- if (key.toLowerCase().includes(searchLower) ||
424
- pattern.title?.toLowerCase().includes(searchLower)) {
425
- results.patterns.push({
426
- key,
427
- ...pattern,
428
- });
429
- }
430
- });
431
- }
432
- const totalResults = results.global_modules.length +
433
- results.data_attributes.length +
434
- results.methods.length +
435
- results.events.length +
436
- results.ui_components.length +
437
- results.patterns.length;
438
- return {
439
- search,
440
- total_results: totalResults,
441
- results,
442
- note: totalResults === 0 ?
443
- "Ничего не найдено. Попробуйте другой запрос или используйте module для просмотра конкретного модуля." :
444
- `Найдено ${totalResults} результатов. Используйте data-атрибуты вместо JavaScript где возможно!`,
445
- };
159
+ modules = modules.filter((mod) => mod.name.toLowerCase().includes(searchLower) ||
160
+ mod.description?.toLowerCase().includes(searchLower) ||
161
+ mod.methods?.some((m) => m.name.toLowerCase().includes(searchLower)));
446
162
  }
163
+ return {
164
+ total: modules.length,
165
+ modules: modules.map((mod) => ({
166
+ name: mod.name,
167
+ description: mod.description,
168
+ category: mod.category,
169
+ methods: mod.methods || [],
170
+ events: mod.events || []
171
+ }))
172
+ };
447
173
  }
448
174
  /**
449
175
  * Получить паттерны меню категорий
@@ -451,207 +177,133 @@ export function getCommonJSAPI(args = {}) {
451
177
  export function getCollectionsMenuPatterns(args = {}) {
452
178
  const { patternId, category } = args;
453
179
  const data = collectionsMenuPatterns;
454
- // Без параметров - общая информация
455
- if (!patternId && !category) {
456
- return {
457
- title: data.title,
458
- description: data.description,
459
- patterns: data.patterns.map((p) => ({
460
- id: p.id,
461
- name: p.name,
462
- description: p.description,
463
- useCase: p.useCase,
464
- structure: p.structure,
465
- features: p.features,
466
- })),
467
- total_patterns: data.patterns.length,
468
- message: "Укажите patternId для получения полного кода паттерна",
469
- };
470
- }
471
- // Поиск конкретного паттерна
180
+ let patterns = data.patterns || [];
472
181
  if (patternId) {
473
- const pattern = data.patterns.find((p) => p.id === patternId);
474
- if (!pattern) {
182
+ const pattern = patterns.find((p) => p.id === patternId);
183
+ if (pattern) {
475
184
  return {
476
- error: `Паттерн "${patternId}" не найден`,
477
- available_patterns: data.patterns.map((p) => p.id),
185
+ pattern: {
186
+ id: pattern.id,
187
+ name: pattern.name,
188
+ description: pattern.description,
189
+ category: pattern.category,
190
+ code: pattern.code,
191
+ settings: pattern.settings
192
+ }
478
193
  };
479
194
  }
480
- return {
481
- pattern: {
482
- id: pattern.id,
483
- name: pattern.name,
484
- description: pattern.description,
485
- useCase: pattern.useCase,
486
- structure: pattern.structure,
487
- cacheKeyPattern: pattern.cacheKeyPattern,
488
- requiredSettings: pattern.requiredSettings,
489
- liquidCode: pattern.liquidCode,
490
- features: pattern.features,
491
- },
492
- commonPatterns: data.commonPatterns,
493
- collectionMethods: data.collectionMethods,
494
- dataAttributes: data.dataAttributes,
495
- bestPractices: data.bestPractices,
496
- };
195
+ return { error: `Паттерн '${patternId}' не найден` };
497
196
  }
498
- // Фильтрация по категории (по useCase)
499
197
  if (category) {
500
- const categoryLower = category.toLowerCase();
501
- const matchingPatterns = data.patterns.filter((p) => p.useCase.toLowerCase().includes(categoryLower) ||
502
- p.description.toLowerCase().includes(categoryLower));
503
- return {
504
- category,
505
- count: matchingPatterns.length,
506
- patterns: matchingPatterns.map((p) => ({
507
- id: p.id,
508
- name: p.name,
509
- description: p.description,
510
- useCase: p.useCase,
511
- structure: p.structure,
512
- features: p.features,
513
- })),
514
- };
198
+ patterns = patterns.filter((pattern) => pattern.category === category);
515
199
  }
200
+ return {
201
+ total: patterns.length,
202
+ patterns: patterns.map((pattern) => ({
203
+ id: pattern.id,
204
+ name: pattern.name,
205
+ description: pattern.description,
206
+ category: pattern.category
207
+ }))
208
+ };
516
209
  }
517
210
  /**
518
- * Получить справочник API библиотек
519
- * Объединяет информацию из libraries-registry и libraries-api-reference
211
+ * Получить API библиотек
520
212
  */
521
213
  export function getLibrariesAPI(args = {}) {
522
214
  const { library, search, category } = args;
523
- const apiData = librariesApiReference;
524
- const registryData = librariesRegistry;
525
- // Без параметров - список всех библиотек с API документацией
526
- if (!library && !search && !category) {
527
- return {
528
- title: apiData.title,
529
- description: apiData.description,
530
- libraries_with_api: apiData.libraries.map((lib) => ({
531
- name: lib.name,
532
- handle: lib.handle,
533
- type: lib.type,
534
- description: lib.description,
535
- dependencies: lib.dependencies,
536
- categories: lib.categories,
537
- })),
538
- total_libraries: apiData.libraries.length,
539
- message: "Укажите library для получения полной документации по API, или search для поиска",
540
- available_libraries: apiData.libraries.map((lib) => lib.handle),
541
- };
542
- }
543
- // Поиск конкретной библиотеки
215
+ const data = librariesApiReference;
216
+ let libraries = data.libraries || [];
544
217
  if (library) {
545
- const lib = apiData.libraries.find((l) => l.handle === library || l.name.toLowerCase() === library.toLowerCase());
546
- if (!lib) {
218
+ const lib = libraries.find((l) => l.handle === library || l.name === library);
219
+ if (lib) {
547
220
  return {
548
- error: `Библиотека "${library}" не найдена в API справочнике`,
549
- available_libraries: apiData.libraries.map((l) => ({
550
- handle: l.handle,
551
- name: l.name,
552
- })),
553
- note: "Некоторые библиотеки могут не иметь подробной API документации",
554
- };
555
- }
556
- // Полная информация о библиотеке
557
- return {
558
- library: {
559
- name: lib.name,
560
- handle: lib.handle,
561
- version: lib.version,
562
- type: lib.type,
563
- description: lib.description,
564
- categories: lib.categories,
565
- dependencies: lib.dependencies,
566
- },
567
- usage: lib.usage,
568
- options: lib.options,
569
- methods: lib.methods,
570
- events: lib.events,
571
- cssClasses: lib.cssClasses,
572
- examples: lib.examples,
573
- bestPractices: lib.bestPractices,
574
- notes: lib.notes,
575
- };
576
- }
577
- // Поиск по ключевому слову
578
- if (search) {
579
- const searchLower = search.toLowerCase();
580
- const results = {
581
- libraries: [],
582
- options: [],
583
- methods: [],
584
- examples: [],
585
- };
586
- apiData.libraries.forEach((lib) => {
587
- // Поиск по библиотекам
588
- if (lib.name.toLowerCase().includes(searchLower) ||
589
- lib.handle.toLowerCase().includes(searchLower) ||
590
- lib.description?.toLowerCase().includes(searchLower)) {
591
- results.libraries.push({
221
+ library: {
592
222
  name: lib.name,
593
223
  handle: lib.handle,
594
224
  description: lib.description,
595
225
  type: lib.type,
596
- });
597
- }
598
- // Поиск по опциям
599
- lib.options?.forEach((opt) => {
600
- if (opt.name.toLowerCase().includes(searchLower) ||
601
- opt.description?.toLowerCase().includes(searchLower)) {
602
- results.options.push({
603
- ...opt,
604
- library: lib.name,
605
- library_handle: lib.handle,
606
- });
607
- }
608
- });
609
- // Поиск по методам
610
- lib.methods?.forEach((method) => {
611
- if (method.name.toLowerCase().includes(searchLower) ||
612
- method.description?.toLowerCase().includes(searchLower)) {
613
- results.methods.push({
614
- ...method,
615
- library: lib.name,
616
- library_handle: lib.handle,
617
- });
226
+ category: lib.category,
227
+ options: lib.options || [],
228
+ methods: lib.methods || [],
229
+ examples: lib.examples || []
618
230
  }
619
- });
620
- // Поиск по примерам
621
- lib.examples?.forEach((example) => {
622
- if (example.title?.toLowerCase().includes(searchLower) ||
623
- example.description?.toLowerCase().includes(searchLower)) {
624
- results.examples.push({
625
- ...example,
626
- library: lib.name,
627
- library_handle: lib.handle,
628
- });
629
- }
630
- });
631
- });
632
- return {
633
- search,
634
- libraries_count: results.libraries.length,
635
- options_count: results.options.length,
636
- methods_count: results.methods.length,
637
- examples_count: results.examples.length,
638
- results,
639
- };
231
+ };
232
+ }
233
+ return { error: `Библиотека '${library}' не найдена` };
640
234
  }
641
- // Фильтрация по категории
642
235
  if (category) {
643
- const categoryLibraries = apiData.libraries.filter((lib) => lib.categories?.includes(category));
644
- return {
645
- category,
646
- count: categoryLibraries.length,
647
- libraries: categoryLibraries.map((lib) => ({
648
- name: lib.name,
649
- handle: lib.handle,
650
- description: lib.description,
651
- type: lib.type,
652
- usage: lib.usage,
653
- })),
654
- };
236
+ libraries = libraries.filter((lib) => lib.category === category);
237
+ }
238
+ if (search) {
239
+ const searchLower = search.toLowerCase();
240
+ libraries = libraries.filter((lib) => lib.name.toLowerCase().includes(searchLower) ||
241
+ lib.handle.toLowerCase().includes(searchLower) ||
242
+ lib.description?.toLowerCase().includes(searchLower));
655
243
  }
244
+ return {
245
+ total: libraries.length,
246
+ libraries: libraries.map((lib) => ({
247
+ name: lib.name,
248
+ handle: lib.handle,
249
+ description: lib.description,
250
+ type: lib.type,
251
+ category: lib.category
252
+ }))
253
+ };
254
+ }
255
+ /**
256
+ * Получить справочник Liquid переменных
257
+ */
258
+ export function getLiquidVariables(args = {}) {
259
+ const { category, search } = args;
260
+ const data = liquidVariables;
261
+ let variables = data.variables || [];
262
+ if (category) {
263
+ variables = variables.filter((variable) => variable.category === category);
264
+ }
265
+ if (search) {
266
+ const searchLower = search.toLowerCase();
267
+ variables = variables.filter((variable) => variable.name.toLowerCase().includes(searchLower) ||
268
+ variable.description?.toLowerCase().includes(searchLower));
269
+ }
270
+ return {
271
+ total: variables.length,
272
+ categories: data.categories || [],
273
+ variables: variables.map((variable) => ({
274
+ name: variable.name,
275
+ description: variable.description,
276
+ category: variable.category,
277
+ type: variable.type,
278
+ examples: variable.examples
279
+ }))
280
+ };
281
+ }
282
+ /**
283
+ * Получить постоянные ссылки InSales
284
+ */
285
+ export function getInsalesPermanentLinks(args = {}) {
286
+ const { search } = args;
287
+ const data = insalesPermanentLinks;
288
+ let links = data.links || {};
289
+ if (search) {
290
+ const searchLower = search.toLowerCase();
291
+ const filteredLinks = {};
292
+ Object.keys(links).forEach(key => {
293
+ const link = links[key];
294
+ if (key.toLowerCase().includes(searchLower) ||
295
+ link.description?.toLowerCase().includes(searchLower) ||
296
+ link.usage?.toLowerCase().includes(searchLower)) {
297
+ filteredLinks[key] = link;
298
+ }
299
+ });
300
+ links = filteredLinks;
301
+ }
302
+ return {
303
+ description: data.description,
304
+ total: Object.keys(links).length,
305
+ links,
306
+ notes: data.notes
307
+ };
656
308
  }
657
309
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iwgt",
3
- "version": "2.4.9",
3
+ "version": "2.4.10",
4
4
  "description": "MCP server",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",