@supericons/mcp 0.4.6

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,461 @@
1
+ export const JOB_LIBRARY_PREFIX = 'job:';
2
+
3
+ export const JOB_CATEGORY_DEFINITIONS = [
4
+ {
5
+ id: 'ai-agent-workflows',
6
+ label: 'AI & Automation',
7
+ description: 'Curated icons for models, prompts, orchestration, retrieval, and agent runtime surfaces.',
8
+ sidebarGlyph: 'smart_toy',
9
+ },
10
+ {
11
+ id: 'navigation-wayfinding',
12
+ label: 'Navigation & Wayfinding',
13
+ description: 'Core app-shell icons for menus, routing, layout, movement, and dashboard wayfinding.',
14
+ sidebarGlyph: 'dashboard',
15
+ },
16
+ {
17
+ id: 'actions-controls',
18
+ label: 'Actions & Controls',
19
+ description: 'Common commands for creating, editing, deleting, uploading, downloading, sorting, and changing settings.',
20
+ sidebarGlyph: 'touch_app',
21
+ },
22
+ {
23
+ id: 'status-feedback',
24
+ label: 'Status & Feedback',
25
+ description: 'Signals for success, warning, progress, trust, notifications, and user feedback states.',
26
+ sidebarGlyph: 'task_alt',
27
+ },
28
+ {
29
+ id: 'people-accounts',
30
+ label: 'People & Accounts',
31
+ description: 'Users, profiles, teams, contacts, identity, roles, and account surfaces.',
32
+ sidebarGlyph: 'person',
33
+ },
34
+ {
35
+ id: 'communication',
36
+ label: 'Communication',
37
+ description: 'Messages, mail, chat, comments, calls, announcements, and language tools.',
38
+ sidebarGlyph: 'chat',
39
+ },
40
+ {
41
+ id: 'files-content',
42
+ label: 'Files & Content',
43
+ description: 'Files, folders, documents, images, attachments, archives, and clipboard flows.',
44
+ sidebarGlyph: 'folder',
45
+ },
46
+ {
47
+ id: 'data-analytics',
48
+ label: 'Data & Analytics',
49
+ description: 'Databases, tables, charts, metrics, reports, dashboards, and trend analysis.',
50
+ sidebarGlyph: 'bar_chart',
51
+ },
52
+ {
53
+ id: 'commerce-finance',
54
+ label: 'Commerce & Finance',
55
+ description: 'Shopping, checkout, billing, payments, receipts, invoices, wallets, and currencies.',
56
+ sidebarGlyph: 'credit_card',
57
+ },
58
+ {
59
+ id: 'security-access',
60
+ label: 'Security & Access',
61
+ description: 'Locks, keys, shields, verification, privacy, scanning, identity checks, and blocked states.',
62
+ sidebarGlyph: 'shield',
63
+ },
64
+ {
65
+ id: 'media-playback',
66
+ label: 'Media & Playback',
67
+ description: 'Audio, video, camera, gallery, image, music, volume, and playback controls.',
68
+ sidebarGlyph: 'play_circle',
69
+ },
70
+ {
71
+ id: 'devices-hardware',
72
+ label: 'Devices & Hardware',
73
+ description: 'Phones, computers, screens, printers, chips, servers, batteries, plugs, and hardware.',
74
+ sidebarGlyph: 'devices',
75
+ },
76
+ {
77
+ id: 'code-development',
78
+ label: 'Code & Development',
79
+ description: 'Code, terminals, APIs, packages, branches, bugs, deployment, and developer tooling.',
80
+ sidebarGlyph: 'code',
81
+ },
82
+ {
83
+ id: 'design-editing',
84
+ label: 'Design & Editing',
85
+ description: 'Color, drawing, typography, crop, align, layers, swatches, and creative editing tools.',
86
+ sidebarGlyph: 'palette',
87
+ },
88
+ {
89
+ id: 'maps-places-travel',
90
+ label: 'Maps, Places & Travel',
91
+ description: 'Maps, pins, location, routes, compass, buildings, transport, and global places.',
92
+ sidebarGlyph: 'map',
93
+ },
94
+ {
95
+ id: 'time-calendar',
96
+ label: 'Time & Calendar',
97
+ description: 'Clocks, calendars, schedules, timers, history, reminders, and alarms.',
98
+ sidebarGlyph: 'calendar_month',
99
+ },
100
+ {
101
+ id: 'brands-social',
102
+ label: 'Brands & Social',
103
+ description: 'Company marks, product logos, social networks, and platform icons.',
104
+ sidebarGlyph: 'hub',
105
+ },
106
+ {
107
+ id: 'nature-weather-lifestyle',
108
+ label: 'Nature, Weather & Lifestyle',
109
+ description: 'Weather, nature, food, health, sport, lifestyle, and everyday world objects.',
110
+ sidebarGlyph: 'wb_sunny',
111
+ },
112
+ ];
113
+
114
+ const NAVIGATION_ICON_IDS = [
115
+ 'material:menu',
116
+ 'material:close',
117
+ 'material:arrow_back',
118
+ 'material:arrow_forward',
119
+ 'material:chevron_left',
120
+ 'material:chevron_right',
121
+ 'material:expand_more',
122
+ 'material:expand_less',
123
+ 'material:home',
124
+ 'material:search',
125
+ 'material:settings',
126
+ 'material:more_vert',
127
+ 'material:more_horiz',
128
+ 'material:apps',
129
+ 'material:fullscreen',
130
+ 'material:filter_list',
131
+ 'material:sort',
132
+ 'material:refresh',
133
+ 'material:tab',
134
+ 'material:drag_indicator',
135
+ 'material:arrow_upward',
136
+ 'material:arrow_downward',
137
+ 'material:swap_vert',
138
+ 'material:swap_horiz',
139
+ 'material:undo',
140
+ 'material:redo',
141
+ 'material:menu_open',
142
+ 'material:segment',
143
+ 'material:density_medium',
144
+ 'material:view_sidebar',
145
+ 'material:dock_to_right',
146
+ 'material:dock_to_left',
147
+ 'material:grid_view',
148
+ 'material:view_list',
149
+ 'material:view_module',
150
+ 'material:dashboard',
151
+ 'material:splitscreen',
152
+ 'material:picture_in_picture_alt',
153
+ 'material:open_in_new',
154
+ 'material:open_in_full',
155
+ 'material:zoom_in',
156
+ 'material:zoom_out',
157
+ 'material:first_page',
158
+ 'material:last_page',
159
+ 'material:unfold_more',
160
+ 'material:unfold_less',
161
+ 'material:fullscreen_exit',
162
+ 'material:double_arrow',
163
+ 'material:subdirectory_arrow_right',
164
+ 'material:launch',
165
+ ];
166
+
167
+ const STATUS_ICON_IDS = [
168
+ 'tabler:circle-check',
169
+ 'tabler:circle-x',
170
+ 'tabler:alert-triangle',
171
+ 'tabler:info-circle',
172
+ 'tabler:help-circle',
173
+ 'tabler:ban',
174
+ 'tabler:clock',
175
+ 'tabler:hourglass',
176
+ 'tabler:loader-2',
177
+ 'tabler:refresh',
178
+ 'tabler:progress-check',
179
+ 'tabler:bell',
180
+ 'tabler:eye',
181
+ 'tabler:eye-off',
182
+ 'tabler:thumb-up',
183
+ 'tabler:thumb-down',
184
+ 'tabler:star',
185
+ 'tabler:shield-check',
186
+ 'tabler:trophy',
187
+ 'tabler:sparkles',
188
+ 'tabler:power',
189
+ 'tabler:toggle-right',
190
+ 'tabler:bookmark',
191
+ 'tabler:pinned',
192
+ 'tabler:flag',
193
+ 'tabler:archive',
194
+ 'tabler:trash',
195
+ 'tabler:send',
196
+ 'tabler:cloud-check',
197
+ 'tabler:wifi',
198
+ 'tabler:bolt',
199
+ 'tabler:flame',
200
+ 'tabler:link',
201
+ 'tabler:lock',
202
+ 'tabler:lock-open',
203
+ 'tabler:key',
204
+ 'tabler:mail-check',
205
+ 'tabler:message-check',
206
+ 'tabler:list-check',
207
+ 'tabler:filter',
208
+ 'tabler:sort-ascending',
209
+ 'tabler:trending-up',
210
+ 'tabler:trending-down',
211
+ 'tabler:mood-smile',
212
+ 'tabler:mood-sad',
213
+ 'tabler:circle-dot',
214
+ 'tabler:clipboard-check',
215
+ 'tabler:rosette-discount-check',
216
+ 'tabler:heart',
217
+ 'tabler:alert-circle',
218
+ ];
219
+
220
+ const AI_AGENT_ICON_IDS = [
221
+ 'material:smart_toy',
222
+ 'material:robot',
223
+ 'material:psychology',
224
+ 'material:psychology_alt',
225
+ 'material:memory',
226
+ 'material:memory_alt',
227
+ 'material:database',
228
+ 'material:database_search',
229
+ 'material:webhook',
230
+ 'material:workflow',
231
+ 'material:prompt_suggestion',
232
+ 'material:model_training',
233
+ 'material:network_intelligence',
234
+ 'material:network_intelligence_history',
235
+ 'material:network_intelligence_update',
236
+ 'material:hub',
237
+ 'material:schema',
238
+ 'material:data_object',
239
+ 'material:account_tree',
240
+ 'material:auto_awesome',
241
+ 'material:generating_tokens',
242
+ 'material:token',
243
+ 'material:dataset',
244
+ 'material:dataset_linked',
245
+ 'material:terminal',
246
+ 'lucide:brain-circuit',
247
+ 'lucide:brain-cog',
248
+ 'lucide:brain',
249
+ 'lucide:bot-message-square',
250
+ 'lucide:messages-square',
251
+ 'lucide:message-square-code',
252
+ 'lucide:message-circle-code',
253
+ 'lucide:scan-search',
254
+ 'lucide:scan-eye',
255
+ 'lucide:search-code',
256
+ 'lucide:file-search',
257
+ 'lucide:folder-search',
258
+ 'lucide:workflow',
259
+ 'lucide:circuit-board',
260
+ 'lucide:waypoints',
261
+ 'lucide:layers-3',
262
+ 'lucide:blocks',
263
+ 'lucide:binary',
264
+ 'lucide:code-xml',
265
+ 'lucide:database-zap',
266
+ 'lucide:server-cog',
267
+ 'lucide:network',
268
+ 'lucide:router',
269
+ 'lucide:plug-zap',
270
+ 'lucide:wand-sparkles',
271
+ ];
272
+
273
+ function sourceLibraryFromIconId(iconId) {
274
+ return String(iconId).split(':')[0];
275
+ }
276
+
277
+ function buildEntries(jobCategory, iconIds, secondaryCategories) {
278
+ return iconIds.map((iconId, index) => ({
279
+ iconId,
280
+ sourceLibrary: sourceLibraryFromIconId(iconId),
281
+ jobCategory,
282
+ secondaryCategories: [...secondaryCategories],
283
+ rank: index + 1,
284
+ }));
285
+ }
286
+
287
+ export const JOB_ICON_TAXONOMY_SEED = [
288
+ ...buildEntries('ai-agent-workflows', AI_AGENT_ICON_IDS, ['ai', 'agents', 'automation']),
289
+ ...buildEntries('navigation-wayfinding', NAVIGATION_ICON_IDS, ['navigation', 'wayfinding', 'layout']),
290
+ ...buildEntries('status-feedback', STATUS_ICON_IDS, ['status', 'feedback', 'signals']),
291
+ ];
292
+
293
+ function normalizeIconText(value) {
294
+ return String(value || '')
295
+ .toLowerCase()
296
+ .replace(/[_:]+/g, ' ')
297
+ .replace(/[^a-z0-9\s-]/g, ' ')
298
+ .replace(/-/g, ' ')
299
+ .replace(/\s+/g, ' ')
300
+ .trim();
301
+ }
302
+
303
+ function iconText(icon = {}) {
304
+ return normalizeIconText([
305
+ icon.lib,
306
+ icon.id,
307
+ icon.name,
308
+ icon.style,
309
+ icon.type,
310
+ ].filter(Boolean).join(' '));
311
+ }
312
+
313
+ const PURPOSE_INFERENCE_RULES = [
314
+ {
315
+ jobCategory: 'brands-social',
316
+ sourceLibraries: ['simpleicons'],
317
+ secondaryCategories: ['brands', 'logos', 'social'],
318
+ },
319
+ {
320
+ jobCategory: 'ai-agent-workflows',
321
+ patterns: [/\b(ai|bot|robot|brain|model|prompt|token|memory|dataset|workflow|webhook|neural|automation)\b/],
322
+ secondaryCategories: ['ai', 'automation', 'agents'],
323
+ },
324
+ {
325
+ jobCategory: 'navigation-wayfinding',
326
+ patterns: [/\b(home|menu|arrow|chevron|sidebar|dashboard|grid|layout|route|compass|navigate|waypoint|tab|fullscreen|search|filter|sort)\b/],
327
+ secondaryCategories: ['navigation', 'layout', 'wayfinding'],
328
+ },
329
+ {
330
+ jobCategory: 'actions-controls',
331
+ patterns: [/\b(add|plus|edit|pencil|delete|trash|remove|upload|download|refresh|reload|sync|settings|cog|sliders|play|pause|stop|undo|redo|copy|save|share|send)\b/],
332
+ secondaryCategories: ['actions', 'controls', 'commands'],
333
+ },
334
+ {
335
+ jobCategory: 'status-feedback',
336
+ patterns: [/\b(check|success|alert|warning|error|info|loader|loading|progress|bell|notification|star|heart|favorite|thumb|badge|flag|pin|power|toggle)\b/],
337
+ secondaryCategories: ['status', 'feedback', 'signals'],
338
+ },
339
+ {
340
+ jobCategory: 'people-accounts',
341
+ patterns: [/\b(user|users|person|people|profile|account|avatar|contact|team|group|id|identity|face|smile|frown)\b/],
342
+ secondaryCategories: ['people', 'accounts', 'identity'],
343
+ },
344
+ {
345
+ jobCategory: 'communication',
346
+ patterns: [/\b(message|messages|mail|email|chat|comment|phone|call|mic|microphone|megaphone|announcement|language|translate|inbox)\b/],
347
+ secondaryCategories: ['communication', 'messages', 'calls'],
348
+ },
349
+ {
350
+ jobCategory: 'files-content',
351
+ patterns: [/\b(file|folder|document|clipboard|archive|paperclip|attachment|image|photo|text|book|newspaper|note|receipt|pdf)\b/],
352
+ secondaryCategories: ['files', 'content', 'documents'],
353
+ },
354
+ {
355
+ jobCategory: 'data-analytics',
356
+ patterns: [/\b(database|table|chart|graph|analytics|metric|report|trend|activity|gauge|pie|area|server|stack)\b/],
357
+ secondaryCategories: ['data', 'analytics', 'reports'],
358
+ },
359
+ {
360
+ jobCategory: 'commerce-finance',
361
+ patterns: [/\b(cart|shop|store|bag|basket|payment|credit|card|receipt|invoice|wallet|cash|money|bank|currency|dollar|euro|yen|pound|rupee|discount|tag|ticket)\b/],
362
+ secondaryCategories: ['commerce', 'finance', 'billing'],
363
+ },
364
+ {
365
+ jobCategory: 'security-access',
366
+ patterns: [/\b(lock|unlock|key|shield|security|privacy|fingerprint|scan|verified|ban|blocked|access|safe|danger|virus|bug)\b/],
367
+ secondaryCategories: ['security', 'access', 'trust'],
368
+ },
369
+ {
370
+ jobCategory: 'media-playback',
371
+ patterns: [/\b(play|pause|video|audio|camera|image|photo|gallery|music|volume|speaker|film|tv|radio|podcast|headphone)\b/],
372
+ secondaryCategories: ['media', 'playback', 'audio-video'],
373
+ },
374
+ {
375
+ jobCategory: 'devices-hardware',
376
+ patterns: [/\b(phone|mobile|desktop|laptop|monitor|tablet|printer|cpu|chip|server|battery|plug|wifi|bluetooth|keyboard|mouse|device|hardware|watch)\b/],
377
+ secondaryCategories: ['devices', 'hardware', 'technology'],
378
+ },
379
+ {
380
+ jobCategory: 'code-development',
381
+ patterns: [/\b(code|terminal|api|package|branch|git|github|webhook|deploy|deployment|bug|server|database|binary|braces|command|script|xml|json)\b/],
382
+ secondaryCategories: ['code', 'development', 'engineering'],
383
+ },
384
+ {
385
+ jobCategory: 'design-editing',
386
+ patterns: [/\b(palette|brush|pen|pencil|crop|align|typography|type|layer|layers|swatch|color|wand|sparkles|ruler|scissors|paint)\b/],
387
+ secondaryCategories: ['design', 'editing', 'creative'],
388
+ },
389
+ {
390
+ jobCategory: 'maps-places-travel',
391
+ patterns: [/\b(map|pin|location|compass|route|building|office|home|store|truck|car|plane|train|bus|globe|earth|world|flag)\b/],
392
+ secondaryCategories: ['maps', 'places', 'travel'],
393
+ },
394
+ {
395
+ jobCategory: 'time-calendar',
396
+ patterns: [/\b(clock|calendar|date|time|timer|history|alarm|schedule|hourglass|watch)\b/],
397
+ secondaryCategories: ['time', 'calendar', 'schedule'],
398
+ },
399
+ {
400
+ jobCategory: 'nature-weather-lifestyle',
401
+ patterns: [/\b(sun|moon|cloud|rain|snow|snowflake|leaf|tree|flower|food|coffee|heart|health|sport|game|shirt|home|gift|cake|smile|thermometer)\b/],
402
+ secondaryCategories: ['nature', 'weather', 'lifestyle'],
403
+ },
404
+ ];
405
+
406
+ function inferTaxonomyEntry(icon, index = 0) {
407
+ const text = iconText(icon);
408
+ if (!text) return null;
409
+
410
+ for (const rule of PURPOSE_INFERENCE_RULES) {
411
+ if (rule.sourceLibraries?.includes(icon.lib)) {
412
+ return {
413
+ iconId: `${icon.lib}:${icon.id}`,
414
+ sourceLibrary: icon.lib,
415
+ jobCategory: rule.jobCategory,
416
+ secondaryCategories: [...(rule.secondaryCategories || [])],
417
+ rank: 5000 + index,
418
+ };
419
+ }
420
+
421
+ if ((rule.patterns || []).some((pattern) => pattern.test(text))) {
422
+ return {
423
+ iconId: `${icon.lib}:${icon.id}`,
424
+ sourceLibrary: icon.lib,
425
+ jobCategory: rule.jobCategory,
426
+ secondaryCategories: [...(rule.secondaryCategories || [])],
427
+ rank: 5000 + index,
428
+ };
429
+ }
430
+ }
431
+
432
+ return null;
433
+ }
434
+
435
+ export function buildJobLibraryId(jobCategoryId) {
436
+ return `${JOB_LIBRARY_PREFIX}${jobCategoryId}`;
437
+ }
438
+
439
+ export function parseJobLibraryId(value) {
440
+ if (typeof value !== 'string' || !value.startsWith(JOB_LIBRARY_PREFIX)) {
441
+ return null;
442
+ }
443
+ return value.slice(JOB_LIBRARY_PREFIX.length);
444
+ }
445
+
446
+ export function createIconTaxonomyMap(icons = []) {
447
+ const map = new Map(JOB_ICON_TAXONOMY_SEED.map((entry) => [entry.iconId, entry]));
448
+
449
+ for (const [index, icon] of icons.entries()) {
450
+ const iconId = `${icon.lib}:${icon.id}`;
451
+ if (map.has(iconId)) continue;
452
+ const inferred = inferTaxonomyEntry(icon, index);
453
+ if (inferred) map.set(iconId, inferred);
454
+ }
455
+
456
+ return map;
457
+ }
458
+
459
+ export function createJobCategoryMap() {
460
+ return new Map(JOB_CATEGORY_DEFINITIONS.map((category) => [category.id, category]));
461
+ }
@@ -0,0 +1,171 @@
1
+ const STRIP_COMMENT_PATTERNS = [
2
+ /\bgenerated by\b/i,
3
+ /\busing\b/i,
4
+ /\bsource:\b/i,
5
+ /\bbuilt with\b/i,
6
+ /\bcurated from\b/i,
7
+ /\bdesign rule\b/i,
8
+ /\bmotion vocabulary\b/i,
9
+ /\bsocratic design\b/i,
10
+ /\bsocratic method\b/i,
11
+ /\banimation story\b/i,
12
+ /\bconcept:\s*/i,
13
+ /\bstory:\s*/i,
14
+ /\bevery keyframe is purpose-built\b/i,
15
+ /\bwhat real-world thing\?.*\bsame at rest\?/i,
16
+ /\bvisioncortex\b/i,
17
+ /\bvtracer\b/i,
18
+ /\bvectorizer\b/i,
19
+ /\bgoogle fonts cdn\b/i,
20
+ ];
21
+
22
+ const STRIP_BLOCK_START_PATTERNS = [
23
+ /\bgenerated by\b/i,
24
+ /\busing\b/i,
25
+ /\bsource:\b/i,
26
+ /\bbuilt with\b/i,
27
+ /\bcurated from\b/i,
28
+ /\bdesign rule\b/i,
29
+ /\bmotion vocabulary\b/i,
30
+ /\bsocratic design\b/i,
31
+ /\bsocratic method\b/i,
32
+ /\banimation story\b/i,
33
+ /\bconcept:\s*/i,
34
+ /\bstory:\s*/i,
35
+ /\bwhat real-world thing\?.*\bsame at rest\?/i,
36
+ ];
37
+
38
+ const PRESERVE_COMMENT_PATTERNS = [
39
+ /^\s*supericons motion lab\s*$/i,
40
+ ];
41
+
42
+ function normalizeCommentText(commentText) {
43
+ return String(commentText || '').replace(/\s+/g, ' ').trim();
44
+ }
45
+
46
+ function shouldStripCommentLine(lineText, context = {}) {
47
+ const normalized = normalizeCommentText(lineText);
48
+ if (!normalized) return false;
49
+
50
+ if (context.preserveBranding !== false) {
51
+ if (PRESERVE_COMMENT_PATTERNS.some((pattern) => pattern.test(normalized))) {
52
+ return false;
53
+ }
54
+ }
55
+
56
+ return STRIP_COMMENT_PATTERNS.some((pattern) => pattern.test(normalized));
57
+ }
58
+
59
+ function normalizeSanitizedText(text) {
60
+ return String(text || '')
61
+ .replace(/(?:\r?\n){3,}/g, '\n\n')
62
+ .trimStart();
63
+ }
64
+
65
+ function isSeparatorLikeLine(lineText) {
66
+ const normalized = normalizeCommentText(lineText);
67
+ if (!normalized) return false;
68
+ return !/[A-Za-z0-9]/.test(normalized);
69
+ }
70
+
71
+ function looksLikeIconCommentTitle(lineText) {
72
+ const normalized = normalizeCommentText(lineText);
73
+ if (!normalized) return false;
74
+ return /(?:^|\s)(?:\d+\.\s*)?[A-Z0-9][A-Z0-9\s\-&/]+(?:\s|$)/.test(normalized);
75
+ }
76
+
77
+ export function shouldStripExportMetadataComment(commentText, context = {}) {
78
+ const normalized = normalizeCommentText(commentText);
79
+ if (!normalized) return false;
80
+
81
+ if (context.preserveBranding !== false) {
82
+ if (PRESERVE_COMMENT_PATTERNS.some((pattern) => pattern.test(normalized))) {
83
+ return false;
84
+ }
85
+ }
86
+
87
+ return shouldStripCommentLine(normalized, context);
88
+ }
89
+
90
+ export function stripXmlComments(text, context = {}) {
91
+ if (!text) return text;
92
+ const stripped = String(text).replace(/<!--([\s\S]*?)-->/g, (fullMatch, innerText) => (
93
+ shouldStripExportMetadataComment(innerText, context) ? '' : fullMatch
94
+ ));
95
+ return normalizeSanitizedText(stripped);
96
+ }
97
+
98
+ function sanitizeCssCommentBody(commentText, context = {}) {
99
+ const lines = String(commentText || '').split(/\r?\n/);
100
+ const keptLines = [];
101
+ let strippingContinuation = false;
102
+
103
+ for (const line of lines) {
104
+ const normalized = normalizeCommentText(line);
105
+
106
+ if (strippingContinuation) {
107
+ if (isSeparatorLikeLine(line)) {
108
+ strippingContinuation = false;
109
+ keptLines.push(line);
110
+ }
111
+ continue;
112
+ }
113
+
114
+ if (shouldStripCommentLine(line, context)) {
115
+ strippingContinuation = STRIP_BLOCK_START_PATTERNS.some((pattern) => pattern.test(normalized));
116
+ continue;
117
+ }
118
+
119
+ keptLines.push(line);
120
+ }
121
+
122
+ const trimmedKeptLines = keptLines.filter((line, index) => {
123
+ const normalized = normalizeCommentText(line);
124
+ if (!normalized || normalized.includes(':')) return true;
125
+
126
+ const previousLine = keptLines.slice(0, index).reverse().find((value) => normalizeCommentText(value));
127
+ const nextLine = keptLines.slice(index + 1).find((value) => normalizeCommentText(value));
128
+
129
+ if (!previousLine || !nextLine) return true;
130
+ if (!looksLikeIconCommentTitle(previousLine)) return true;
131
+ if (!isSeparatorLikeLine(nextLine)) return true;
132
+
133
+ return false;
134
+ });
135
+
136
+ if (!trimmedKeptLines.some((line) => normalizeCommentText(line))) {
137
+ return '';
138
+ }
139
+
140
+ return trimmedKeptLines.join('\n');
141
+ }
142
+
143
+ export function stripCssComments(text, context = {}) {
144
+ if (!text) return text;
145
+ const stripped = String(text).replace(/\/\*([\s\S]*?)\*\//g, (fullMatch, innerText) => {
146
+ const sanitizedBody = sanitizeCssCommentBody(innerText, context);
147
+ if (sanitizedBody === innerText) {
148
+ return fullMatch;
149
+ }
150
+
151
+ if (!sanitizedBody) return '';
152
+
153
+ return `/*${sanitizedBody}*/`;
154
+ });
155
+ return normalizeSanitizedText(stripped);
156
+ }
157
+
158
+ export function sanitizeSvgExportMarkup(svgText, context = {}) {
159
+ if (!svgText) return svgText;
160
+
161
+ let sanitized = stripXmlComments(svgText, context);
162
+ sanitized = sanitized.replace(/<style([^>]*)>([\s\S]*?)<\/style>/gi, (fullMatch, attrs, cssText) => {
163
+ const cleanCss = stripCssComments(cssText, context);
164
+ return `<style${attrs}>${cleanCss}</style>`;
165
+ });
166
+ return sanitized;
167
+ }
168
+
169
+ export function sanitizeCssCommentMetadata(cssText, context = {}) {
170
+ return stripCssComments(cssText, context);
171
+ }