@productivemark/snipcss 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/.claude-plugin/marketplace.json +17 -0
  2. package/.claude-plugin/plugin.json +10 -0
  3. package/.mcp.json +8 -0
  4. package/dist/auth/config-manager.d.ts +13 -0
  5. package/dist/auth/config-manager.d.ts.map +1 -0
  6. package/dist/auth/config-manager.js +48 -0
  7. package/dist/auth/config-manager.js.map +1 -0
  8. package/dist/auth/usage-gate.d.ts +13 -0
  9. package/dist/auth/usage-gate.d.ts.map +1 -0
  10. package/dist/auth/usage-gate.js +69 -0
  11. package/dist/auth/usage-gate.js.map +1 -0
  12. package/dist/browser/browser-manager.d.ts +15 -0
  13. package/dist/browser/browser-manager.d.ts.map +1 -0
  14. package/dist/browser/browser-manager.js +61 -0
  15. package/dist/browser/browser-manager.js.map +1 -0
  16. package/dist/browser/viewport-manager.d.ts +8 -0
  17. package/dist/browser/viewport-manager.d.ts.map +1 -0
  18. package/dist/browser/viewport-manager.js +50 -0
  19. package/dist/browser/viewport-manager.js.map +1 -0
  20. package/dist/extraction/css-variable-resolver.d.ts +27 -0
  21. package/dist/extraction/css-variable-resolver.d.ts.map +1 -0
  22. package/dist/extraction/css-variable-resolver.js +105 -0
  23. package/dist/extraction/css-variable-resolver.js.map +1 -0
  24. package/dist/extraction/dom-labeler.d.ts +26 -0
  25. package/dist/extraction/dom-labeler.d.ts.map +1 -0
  26. package/dist/extraction/dom-labeler.js +124 -0
  27. package/dist/extraction/dom-labeler.js.map +1 -0
  28. package/dist/extraction/element-discovery.d.ts +59 -0
  29. package/dist/extraction/element-discovery.d.ts.map +1 -0
  30. package/dist/extraction/element-discovery.js +525 -0
  31. package/dist/extraction/element-discovery.js.map +1 -0
  32. package/dist/extraction/extraction-pipeline.d.ts +26 -0
  33. package/dist/extraction/extraction-pipeline.d.ts.map +1 -0
  34. package/dist/extraction/extraction-pipeline.js +200 -0
  35. package/dist/extraction/extraction-pipeline.js.map +1 -0
  36. package/dist/extraction/font-collector.d.ts +26 -0
  37. package/dist/extraction/font-collector.d.ts.map +1 -0
  38. package/dist/extraction/font-collector.js +160 -0
  39. package/dist/extraction/font-collector.js.map +1 -0
  40. package/dist/extraction/html-cleaner.d.ts +16 -0
  41. package/dist/extraction/html-cleaner.d.ts.map +1 -0
  42. package/dist/extraction/html-cleaner.js +149 -0
  43. package/dist/extraction/html-cleaner.js.map +1 -0
  44. package/dist/extraction/keyframe-collector.d.ts +16 -0
  45. package/dist/extraction/keyframe-collector.d.ts.map +1 -0
  46. package/dist/extraction/keyframe-collector.js +62 -0
  47. package/dist/extraction/keyframe-collector.js.map +1 -0
  48. package/dist/extraction/pseudo-state-handler.d.ts +36 -0
  49. package/dist/extraction/pseudo-state-handler.d.ts.map +1 -0
  50. package/dist/extraction/pseudo-state-handler.js +210 -0
  51. package/dist/extraction/pseudo-state-handler.js.map +1 -0
  52. package/dist/extraction/result-builder.d.ts +25 -0
  53. package/dist/extraction/result-builder.d.ts.map +1 -0
  54. package/dist/extraction/result-builder.js +136 -0
  55. package/dist/extraction/result-builder.js.map +1 -0
  56. package/dist/extraction/rule-deduplicator.d.ts +39 -0
  57. package/dist/extraction/rule-deduplicator.d.ts.map +1 -0
  58. package/dist/extraction/rule-deduplicator.js +107 -0
  59. package/dist/extraction/rule-deduplicator.js.map +1 -0
  60. package/dist/extraction/selector-fixer.d.ts +25 -0
  61. package/dist/extraction/selector-fixer.d.ts.map +1 -0
  62. package/dist/extraction/selector-fixer.js +111 -0
  63. package/dist/extraction/selector-fixer.js.map +1 -0
  64. package/dist/extraction/specificity.d.ts +17 -0
  65. package/dist/extraction/specificity.d.ts.map +1 -0
  66. package/dist/extraction/specificity.js +88 -0
  67. package/dist/extraction/specificity.js.map +1 -0
  68. package/dist/extraction/style-matcher.d.ts +33 -0
  69. package/dist/extraction/style-matcher.d.ts.map +1 -0
  70. package/dist/extraction/style-matcher.js +199 -0
  71. package/dist/extraction/style-matcher.js.map +1 -0
  72. package/dist/extraction/stylesheet-collector.d.ts +33 -0
  73. package/dist/extraction/stylesheet-collector.d.ts.map +1 -0
  74. package/dist/extraction/stylesheet-collector.js +71 -0
  75. package/dist/extraction/stylesheet-collector.js.map +1 -0
  76. package/dist/index.d.ts +3 -0
  77. package/dist/index.d.ts.map +1 -0
  78. package/dist/index.js +235 -0
  79. package/dist/index.js.map +1 -0
  80. package/dist/mcp-server.d.ts +3 -0
  81. package/dist/mcp-server.d.ts.map +1 -0
  82. package/dist/mcp-server.js +349 -0
  83. package/dist/mcp-server.js.map +1 -0
  84. package/dist/tailwind/css-to-tailwind.d.ts +17 -0
  85. package/dist/tailwind/css-to-tailwind.d.ts.map +1 -0
  86. package/dist/tailwind/css-to-tailwind.js +1583 -0
  87. package/dist/tailwind/css-to-tailwind.js.map +1 -0
  88. package/dist/tailwind/shorthand-expander.d.ts +27 -0
  89. package/dist/tailwind/shorthand-expander.d.ts.map +1 -0
  90. package/dist/tailwind/shorthand-expander.js +812 -0
  91. package/dist/tailwind/shorthand-expander.js.map +1 -0
  92. package/dist/tailwind/tailwind-converter.d.ts +35 -0
  93. package/dist/tailwind/tailwind-converter.d.ts.map +1 -0
  94. package/dist/tailwind/tailwind-converter.js +1223 -0
  95. package/dist/tailwind/tailwind-converter.js.map +1 -0
  96. package/dist/tailwind/tailwind-helpers.d.ts +95 -0
  97. package/dist/tailwind/tailwind-helpers.d.ts.map +1 -0
  98. package/dist/tailwind/tailwind-helpers.js +593 -0
  99. package/dist/tailwind/tailwind-helpers.js.map +1 -0
  100. package/dist/tailwind/tailwind-reducer.d.ts +36 -0
  101. package/dist/tailwind/tailwind-reducer.d.ts.map +1 -0
  102. package/dist/tailwind/tailwind-reducer.js +189 -0
  103. package/dist/tailwind/tailwind-reducer.js.map +1 -0
  104. package/dist/types/index.d.ts +239 -0
  105. package/dist/types/index.d.ts.map +1 -0
  106. package/dist/types/index.js +94 -0
  107. package/dist/types/index.js.map +1 -0
  108. package/dist/utils/helpers.d.ts +34 -0
  109. package/dist/utils/helpers.d.ts.map +1 -0
  110. package/dist/utils/helpers.js +120 -0
  111. package/dist/utils/helpers.js.map +1 -0
  112. package/dist/utils/parsel.d.ts +41 -0
  113. package/dist/utils/parsel.d.ts.map +1 -0
  114. package/dist/utils/parsel.js +314 -0
  115. package/dist/utils/parsel.js.map +1 -0
  116. package/package.json +41 -0
  117. package/skills/workflow/SKILL.md +95 -0
@@ -0,0 +1,200 @@
1
+ import { ExtractionContext, } from '../types/index.js';
2
+ import { ViewportManager } from '../browser/viewport-manager.js';
3
+ import { StylesheetCollector } from './stylesheet-collector.js';
4
+ import { DomLabeler } from './dom-labeler.js';
5
+ import { StyleMatcher } from './style-matcher.js';
6
+ import { PseudoStateHandler } from './pseudo-state-handler.js';
7
+ import { KeyframeCollector } from './keyframe-collector.js';
8
+ import { FontCollector } from './font-collector.js';
9
+ import { CssVariableResolver } from './css-variable-resolver.js';
10
+ import { SelectorFixer } from './selector-fixer.js';
11
+ import { RuleDeduplicator } from './rule-deduplicator.js';
12
+ import { ResultBuilder } from './result-builder.js';
13
+ import { removeExtraAttributes } from './html-cleaner.js';
14
+ import { getTailwindHtml, getTailwindBodyClasses } from '../tailwind/tailwind-converter.js';
15
+ const BATCH_SIZE = 5; // Number of elements to process in parallel
16
+ /**
17
+ * Main extraction pipeline orchestrator.
18
+ * Replaces the doSnipper() function from snipbackground.js.
19
+ */
20
+ export class ExtractionPipeline {
21
+ browserManager;
22
+ viewportManager = new ViewportManager();
23
+ stylesheetCollector = new StylesheetCollector();
24
+ domLabeler = new DomLabeler();
25
+ styleMatcher = new StyleMatcher();
26
+ pseudoStateHandler = new PseudoStateHandler();
27
+ keyframeCollector = new KeyframeCollector();
28
+ fontCollector = new FontCollector();
29
+ variableResolver = new CssVariableResolver();
30
+ selectorFixer = new SelectorFixer();
31
+ ruleDeduplicator = new RuleDeduplicator();
32
+ resultBuilder = new ResultBuilder();
33
+ constructor(browserManager) {
34
+ this.browserManager = browserManager;
35
+ }
36
+ /**
37
+ * Extract CSS from a page element and optionally convert to Tailwind.
38
+ */
39
+ async extract(url, selector, options = {}) {
40
+ const ctx = new ExtractionContext();
41
+ ctx.siteUrl = url;
42
+ const resolveVariables = options.resolveVariables !== false;
43
+ const includeHoverStates = options.includeHoverStates !== false;
44
+ const doRemoveClasses = options.removeUnusedClasses ?? true;
45
+ const doRemoveAttrs = options.removeUnusedAttributes ?? true;
46
+ const viewportOption = options.viewport || 'all';
47
+ let bp = null;
48
+ try {
49
+ // STEP 1: Create page and CDP session
50
+ bp = await this.browserManager.createPage(url);
51
+ const { page, cdp } = bp;
52
+ // STEP 2: Start collecting stylesheets
53
+ await this.stylesheetCollector.startCollecting(cdp);
54
+ // Wait a moment for stylesheets to be collected
55
+ await page.waitForLoadState('networkidle');
56
+ // STEP 3: Get DOM document
57
+ const doc = await cdp.send('DOM.getDocument');
58
+ const docRootNodeId = doc.root.nodeId;
59
+ // STEP 4: Stop collecting and get stylesheets
60
+ const stylesheets = this.stylesheetCollector.stopCollecting();
61
+ ctx.stylesheetArr = stylesheets;
62
+ // STEP 5: Label elements in the DOM
63
+ const labelResult = await this.domLabeler.labelElements(page, selector);
64
+ ctx.allClassnamesArr = labelResult.allClassnamesArr;
65
+ console.log(`Labeled ${labelResult.allClassnamesArr.length} elements`);
66
+ // STEP 6: Parse fonts and CSS variables from stylesheets
67
+ await this.fontCollector.collectAll(cdp, stylesheets, url, ctx);
68
+ // STEP 7: Determine viewports to process
69
+ const viewports = this.viewportManager.getViewportsForOption(viewportOption, options.customWidth);
70
+ // STEP 8: For each viewport, extract matched styles
71
+ for (const viewport of viewports) {
72
+ console.log(`Processing viewport: ${viewport.name} (${viewport.width}x${viewport.height})`);
73
+ // Set viewport (skip for default)
74
+ if (viewport.name !== 'default') {
75
+ await this.viewportManager.setViewport(cdp, viewport);
76
+ // Wait for layout to stabilize
77
+ await page.waitForTimeout(500);
78
+ }
79
+ // Refresh DOM document after viewport change
80
+ const vpDoc = await cdp.send('DOM.getDocument');
81
+ // Process elements in batches for parallelization
82
+ // NOTE: getMatchedStylesForNode is parallelizable, but
83
+ // forcePseudoState is NOT (it mutates global state)
84
+ for (let i = 0; i < ctx.allClassnamesArr.length; i += BATCH_SIZE) {
85
+ const batch = ctx.allClassnamesArr.slice(i, i + BATCH_SIZE);
86
+ // Parallel: Get matched styles for batch
87
+ const batchResults = await Promise.all(batch.map(async (classname) => {
88
+ try {
89
+ // Query DOM for the element
90
+ const node = await cdp.send('DOM.querySelector', {
91
+ nodeId: vpDoc.root.nodeId,
92
+ selector: '.' + classname,
93
+ });
94
+ if (!node.nodeId || node.nodeId === 0) {
95
+ console.log(`Element not found: .${classname}`);
96
+ return null;
97
+ }
98
+ // Get matched styles (THE core CDP call)
99
+ const allMatchedStyles = await this.styleMatcher.getMatchedStyles(cdp, node.nodeId);
100
+ return { classname, nodeId: node.nodeId, allMatchedStyles };
101
+ }
102
+ catch (e) {
103
+ console.error(`Error matching styles for .${classname}:`, e);
104
+ return null;
105
+ }
106
+ }));
107
+ // Process results (sequential for state-dependent operations)
108
+ for (const result of batchResults) {
109
+ if (!result)
110
+ continue;
111
+ const { classname, nodeId, allMatchedStyles } = result;
112
+ // Process matched rules
113
+ const matchedRules = this.styleMatcher.processMatchedStyles(allMatchedStyles, classname, ctx, { resolveVariables, mediaQueriesOnly: viewport.name !== 'default' && viewport.name.startsWith('custom') });
114
+ // Extract CSS variables
115
+ this.styleMatcher.extractCssVariables(matchedRules, classname, ctx);
116
+ // Collect keyframes
117
+ this.keyframeCollector.collect(allMatchedStyles, ctx);
118
+ // Convert to SnippedRules and add (deduplicated)
119
+ for (const ruleMatch of matchedRules) {
120
+ const snippedRule = this.styleMatcher.toSnippedRule(ruleMatch, classname, viewport.name, ctx);
121
+ if (snippedRule) {
122
+ this.ruleDeduplicator.addRule(snippedRule, ctx);
123
+ }
124
+ }
125
+ }
126
+ // Sequential: Extract hover/checked styles (mutates page state)
127
+ if (includeHoverStates) {
128
+ for (const result of batchResults) {
129
+ if (!result)
130
+ continue;
131
+ const { classname, nodeId } = result;
132
+ // Hover styles
133
+ const hoverRules = await this.pseudoStateHandler.extractHoverStyles(cdp, page, nodeId, classname, vpDoc.root.nodeId);
134
+ for (const ruleMatch of hoverRules) {
135
+ const snippedRule = this.styleMatcher.toSnippedRule(ruleMatch, classname, viewport.name, ctx);
136
+ if (snippedRule) {
137
+ snippedRule.is_hover = true;
138
+ this.ruleDeduplicator.addRule(snippedRule, ctx);
139
+ }
140
+ }
141
+ // Checked styles (for checkboxes/radios)
142
+ const checkedRules = await this.pseudoStateHandler.extractCheckedStyles(cdp, page, nodeId, classname, vpDoc.root.nodeId);
143
+ for (const ruleMatch of checkedRules) {
144
+ const snippedRule = this.styleMatcher.toSnippedRule(ruleMatch, classname, viewport.name, ctx);
145
+ if (snippedRule) {
146
+ this.ruleDeduplicator.addRule(snippedRule, ctx);
147
+ }
148
+ }
149
+ }
150
+ }
151
+ }
152
+ // Reset viewport
153
+ if (viewport.name !== 'default') {
154
+ await this.viewportManager.clearViewport(cdp);
155
+ }
156
+ }
157
+ console.log(`Extracted ${ctx.snippedArr.length} CSS rules`);
158
+ // STEP 9: Build final result
159
+ const result = this.resultBuilder.buildResult(ctx, labelResult.allElementOuterHtml, {
160
+ resolveVariables,
161
+ });
162
+ // STEP 10: Tailwind conversion
163
+ try {
164
+ const labeledHtml = labelResult.allElementOuterHtml;
165
+ result.tailwindHtml = getTailwindHtml(labeledHtml, result.css, ctx.snippedArr, false, // forceBreakpoints
166
+ resolveVariables, ctx);
167
+ result.tailwindBodyClasses = getTailwindBodyClasses(ctx.snippedArr, false, resolveVariables, [], // tailwindUltimateArr - populated inside getTailwindBodyClasses
168
+ ctx);
169
+ }
170
+ catch (e) {
171
+ console.error('Tailwind conversion error:', e);
172
+ // Non-fatal: CSS output is still valid
173
+ }
174
+ // STEP 11: Get clean HTML (without marker classes)
175
+ result.html = await this.domLabeler.getCleanHtml(page, selector);
176
+ // STEP 12: Remove unused attributes and classes from HTML
177
+ if (doRemoveClasses || doRemoveAttrs) {
178
+ const cleanOpts = {
179
+ removeUnusedClasses: doRemoveClasses,
180
+ removeUnusedAttributes: doRemoveAttrs,
181
+ keepTailwindLabels: false,
182
+ };
183
+ result.html = removeExtraAttributes(result.html, ctx.snippedArr, cleanOpts);
184
+ if (result.tailwindHtml) {
185
+ result.tailwindHtml = removeExtraAttributes(result.tailwindHtml, ctx.snippedArr, { ...cleanOpts, keepTailwindLabels: true });
186
+ }
187
+ }
188
+ // STEP 13: Remove labels from DOM
189
+ await this.domLabeler.removeLabels(page);
190
+ return result;
191
+ }
192
+ finally {
193
+ // Cleanup
194
+ if (bp) {
195
+ await this.browserManager.closePage(bp);
196
+ }
197
+ }
198
+ }
199
+ }
200
+ //# sourceMappingURL=extraction-pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extraction-pipeline.js","sourceRoot":"","sources":["../../src/extraction/extraction-pipeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { CDPSession } from 'playwright';
2
+ import { FontData, StylesheetInfo, ExtractionContext } from '../types/index.js';
3
+ /**
4
+ * Parses @font-face declarations and CSS variables from stylesheets.
5
+ * Port of snipbackground.js:1343-1627
6
+ */
7
+ export declare class FontCollector {
8
+ /**
9
+ * Parse @font-face rules from stylesheet text.
10
+ */
11
+ parseFontFaces(cssText: string, baseUrl: string): FontData[];
12
+ /**
13
+ * Extract Google Font imports from stylesheet text.
14
+ */
15
+ parseGoogleFontImports(cssText: string): string[];
16
+ /**
17
+ * Extract global CSS variables from stylesheet text.
18
+ * Looks for :root, :host, *, html, body selectors.
19
+ */
20
+ parseGlobalCssVariables(cssText: string, ctx: ExtractionContext): void;
21
+ /**
22
+ * Collect all font data and CSS variables from all stylesheets.
23
+ */
24
+ collectAll(cdp: CDPSession, stylesheets: StylesheetInfo[], siteUrl: string, ctx: ExtractionContext): Promise<void>;
25
+ }
26
+ //# sourceMappingURL=font-collector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"font-collector.d.ts","sourceRoot":"","sources":["../../src/extraction/font-collector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,iBAAiB,EAAoB,MAAM,mBAAmB,CAAC;AAGlG;;;GAGG;AACH,qBAAa,aAAa;IACxB;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,EAAE;IA6D5D;;OAEG;IACH,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAcjD;;;OAGG;IACH,uBAAuB,CACrB,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,iBAAiB,GACrB,IAAI;IA0CP;;OAEG;IACG,UAAU,CACd,GAAG,EAAE,UAAU,EACf,WAAW,EAAE,cAAc,EAAE,EAC7B,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,IAAI,CAAC;CAqDjB"}
@@ -0,0 +1,160 @@
1
+ import { resolveUrl } from '../utils/helpers.js';
2
+ /**
3
+ * Parses @font-face declarations and CSS variables from stylesheets.
4
+ * Port of snipbackground.js:1343-1627
5
+ */
6
+ export class FontCollector {
7
+ /**
8
+ * Parse @font-face rules from stylesheet text.
9
+ */
10
+ parseFontFaces(cssText, baseUrl) {
11
+ const fonts = [];
12
+ // Regex to find @font-face blocks
13
+ const fontFaceRegex = /@font-face\s*\{([^}]+)\}/gi;
14
+ let match;
15
+ while ((match = fontFaceRegex.exec(cssText)) !== null) {
16
+ const block = match[1];
17
+ const font = {
18
+ font_family: '',
19
+ font_url: '',
20
+ full_rule: '@font-face {' + block + '}',
21
+ };
22
+ // Extract font-family
23
+ const familyMatch = block.match(/font-family\s*:\s*(['"]?)([^;'"]+)\1/i);
24
+ if (familyMatch) {
25
+ font.font_family = familyMatch[2].trim();
26
+ }
27
+ // Extract src URLs
28
+ const srcMatch = block.match(/src\s*:\s*([^;]+)/i);
29
+ if (srcMatch) {
30
+ const urlMatch = srcMatch[1].match(/url\(['"]?([^'")\s]+)['"]?\)/);
31
+ if (urlMatch) {
32
+ font.font_url = resolveUrl(urlMatch[1], baseUrl);
33
+ }
34
+ // Extract format
35
+ const formatMatch = srcMatch[1].match(/format\(['"]?([^'")\s]+)['"]?\)/);
36
+ if (formatMatch) {
37
+ font.font_format = formatMatch[1];
38
+ }
39
+ }
40
+ // Extract font-weight
41
+ const weightMatch = block.match(/font-weight\s*:\s*([^;]+)/i);
42
+ if (weightMatch) {
43
+ font.font_weight = weightMatch[1].trim();
44
+ }
45
+ // Extract font-style
46
+ const styleMatch = block.match(/font-style\s*:\s*([^;]+)/i);
47
+ if (styleMatch) {
48
+ font.font_style = styleMatch[1].trim();
49
+ }
50
+ // Extract font-display
51
+ const displayMatch = block.match(/font-display\s*:\s*([^;]+)/i);
52
+ if (displayMatch) {
53
+ font.font_display = displayMatch[1].trim();
54
+ }
55
+ if (font.font_family) {
56
+ fonts.push(font);
57
+ }
58
+ }
59
+ return fonts;
60
+ }
61
+ /**
62
+ * Extract Google Font imports from stylesheet text.
63
+ */
64
+ parseGoogleFontImports(cssText) {
65
+ const imports = [];
66
+ const importRegex = /@import\s+url\(['"]?(https?:\/\/fonts\.googleapis\.com[^'")\s]+)['"]?\)/gi;
67
+ let match;
68
+ while ((match = importRegex.exec(cssText)) !== null) {
69
+ if (!imports.includes(match[1])) {
70
+ imports.push(match[1]);
71
+ }
72
+ }
73
+ return imports;
74
+ }
75
+ /**
76
+ * Extract global CSS variables from stylesheet text.
77
+ * Looks for :root, :host, *, html, body selectors.
78
+ */
79
+ parseGlobalCssVariables(cssText, ctx) {
80
+ // Match :root, :host, *, html, body blocks
81
+ const globalBlockRegex = /(?::root|:host|\*|html|body)\s*\{([^}]+)\}/gi;
82
+ let match;
83
+ while ((match = globalBlockRegex.exec(cssText)) !== null) {
84
+ const block = match[1];
85
+ const selector = match[0].split('{')[0].trim();
86
+ // Find all --var declarations
87
+ const varRegex = /(--[a-zA-Z0-9_-]+)\s*:\s*([^;]+)/g;
88
+ let varMatch;
89
+ while ((varMatch = varRegex.exec(block)) !== null) {
90
+ const prop = varMatch[1];
91
+ const val = varMatch[2].trim();
92
+ ctx.cssvarAllArr[prop] = val + ';';
93
+ if (!ctx.cssvarDefinedArr[prop]) {
94
+ ctx.cssvarDefinedArr[prop] = [];
95
+ }
96
+ const globalKey = `__global__${selector}${prop}`;
97
+ const exists = ctx.cssvarDefinedArr[prop].some((item) => item.key === globalKey);
98
+ if (!exists) {
99
+ ctx.cssvarDefinedArr[prop].push({
100
+ key: globalKey,
101
+ label: '__global__',
102
+ value: val,
103
+ media: '',
104
+ selector,
105
+ source: 'stylesheet',
106
+ });
107
+ }
108
+ }
109
+ }
110
+ }
111
+ /**
112
+ * Collect all font data and CSS variables from all stylesheets.
113
+ */
114
+ async collectAll(cdp, stylesheets, siteUrl, ctx) {
115
+ // Fetch all stylesheet texts in parallel
116
+ const results = await Promise.all(stylesheets
117
+ .filter(ss => ss.origin !== 'user-agent')
118
+ .map(async (ss) => {
119
+ try {
120
+ const result = await cdp.send('CSS.getStyleSheetText', {
121
+ styleSheetId: ss.stylesheet_id,
122
+ });
123
+ return { ss, text: result.text || '' };
124
+ }
125
+ catch {
126
+ return { ss, text: '' };
127
+ }
128
+ }));
129
+ for (const { ss, text } of results) {
130
+ if (!text)
131
+ continue;
132
+ const baseUrl = ss.source_url || siteUrl;
133
+ // Parse @font-face rules
134
+ if (text.includes('@font-face')) {
135
+ const fonts = this.parseFontFaces(text, baseUrl);
136
+ for (const font of fonts) {
137
+ // Deduplicate by font_family + font_weight + font_style
138
+ const exists = ctx.customfontsArr.some((f) => f.font_family === font.font_family &&
139
+ f.font_weight === font.font_weight &&
140
+ f.font_style === font.font_style);
141
+ if (!exists) {
142
+ ctx.customfontsArr.push(font);
143
+ }
144
+ }
145
+ }
146
+ // Parse Google Font imports
147
+ const imports = this.parseGoogleFontImports(text);
148
+ for (const imp of imports) {
149
+ if (!ctx.importfontsArr.includes(imp)) {
150
+ ctx.importfontsArr.push(imp);
151
+ }
152
+ }
153
+ // Parse global CSS variables
154
+ if (text.includes('--')) {
155
+ this.parseGlobalCssVariables(text, ctx);
156
+ }
157
+ }
158
+ }
159
+ }
160
+ //# sourceMappingURL=font-collector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"font-collector.js","sourceRoot":"","sources":["../../src/extraction/font-collector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { SnippedRule } from '../types/index.js';
2
+ export interface CleanupOptions {
3
+ removeUnusedClasses?: boolean;
4
+ removeUnusedAttributes?: boolean;
5
+ keepTailwindLabels?: boolean;
6
+ }
7
+ /**
8
+ * Remove unused attributes and CSS classes from extracted HTML.
9
+ *
10
+ * @param html The extracted HTML string
11
+ * @param snippedArr The array of extracted CSS rules
12
+ * @param options What to clean up
13
+ * @returns Cleaned HTML string
14
+ */
15
+ export declare function removeExtraAttributes(html: string, snippedArr: SnippedRule[], options?: CleanupOptions): string;
16
+ //# sourceMappingURL=html-cleaner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-cleaner.d.ts","sourceRoot":"","sources":["../../src/extraction/html-cleaner.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AA8CrD,MAAM,WAAW,cAAc;IAC7B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,WAAW,EAAE,EACzB,OAAO,GAAE,cAAmB,GAC3B,MAAM,CAoGR"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Removes unused attributes and CSS classes from extracted HTML.
3
+ * Port of removeExtraAttributes() from snipbackground.js:5613-5800
4
+ */
5
+ import * as cheerio from 'cheerio';
6
+ const KEEP_ATTRS = new Set([
7
+ 'align', 'for', 'type', 'value', 'valign', 'bgcolor', 'background',
8
+ 'width', 'height', 'style', 'src', 'href', 'source', 'dir', 'viewbox',
9
+ 'xmlns', 'placeholder', 'd', 'colspan', 'rowspan', 'span', 'headers',
10
+ 'scope', 'alt', 'title', 'role', 'aria-label', 'aria-hidden',
11
+ 'loading', 'decoding', 'srcset', 'sizes', 'media', 'rel', 'target',
12
+ 'action', 'method', 'enctype', 'name',
13
+ ]);
14
+ const SVG_TAGS = new Set([
15
+ 'path', 'rect', 'circle', 'ellipse', 'line', 'polyline', 'polygon', 'svg',
16
+ 'g', 'defs', 'use', 'symbol', 'clippath', 'mask', 'filter',
17
+ ]);
18
+ const FORM_TAGS = new Set(['input', 'select', 'meter', 'progress', 'textarea', 'label']);
19
+ const ICON_PREFIXES = [
20
+ 'fa-', 'fa ', 'fas ', 'far ', 'fab ', 'fal ', 'fad ',
21
+ 'bi-', 'bi ',
22
+ 'icon-', 'icon ',
23
+ 'ti-', 'ti ',
24
+ 'material-icons',
25
+ 'glyphicon',
26
+ ];
27
+ function isIconFontClass(cls) {
28
+ const lower = cls.toLowerCase();
29
+ return ICON_PREFIXES.some(p => lower.startsWith(p)) || lower === 'fa';
30
+ }
31
+ /**
32
+ * Extract the base class name for selector matching.
33
+ * Strips pseudo-selectors, escapes, brackets, dots.
34
+ */
35
+ function baseClassName(cls) {
36
+ let base = cls;
37
+ if (base.includes(':'))
38
+ base = base.split(':')[0];
39
+ if (base.includes('\\'))
40
+ base = base.split('\\')[0];
41
+ if (base.includes('/'))
42
+ base = base.split('/')[0];
43
+ if (base.includes('['))
44
+ base = base.split('[')[0];
45
+ if (base.includes('.'))
46
+ base = base.split('.')[0];
47
+ return base.trim();
48
+ }
49
+ /**
50
+ * Remove unused attributes and CSS classes from extracted HTML.
51
+ *
52
+ * @param html The extracted HTML string
53
+ * @param snippedArr The array of extracted CSS rules
54
+ * @param options What to clean up
55
+ * @returns Cleaned HTML string
56
+ */
57
+ export function removeExtraAttributes(html, snippedArr, options = {}) {
58
+ const { removeUnusedClasses = true, removeUnusedAttributes = true, keepTailwindLabels = false, } = options;
59
+ if (!removeUnusedClasses && !removeUnusedAttributes)
60
+ return html;
61
+ // Collect all selectors for matching
62
+ const allSelectors = snippedArr.map(r => r.selector);
63
+ const $ = cheerio.load(html, { xml: { xmlMode: false, decodeEntities: false } }, false);
64
+ // Remove HTML comments
65
+ $.root().find('*').contents().filter((_i, node) => node.type === 'comment').remove();
66
+ // Also remove top-level comments
67
+ $.root().contents().filter((_i, node) => node.type === 'comment').remove();
68
+ $.root().find('*').each((_i, elem) => {
69
+ if (elem.type !== 'tag')
70
+ return;
71
+ const el = elem;
72
+ const tagName = (el.tagName || el.name || '').toLowerCase();
73
+ if (!tagName)
74
+ return;
75
+ // Skip SVG elements
76
+ if (SVG_TAGS.has(tagName))
77
+ return;
78
+ const attribs = el.attribs || {};
79
+ for (const attrName of Object.keys(attribs)) {
80
+ const lowerAttr = attrName.toLowerCase();
81
+ // Always keep essential attributes
82
+ if (KEEP_ATTRS.has(lowerAttr))
83
+ continue;
84
+ // Handle data-* attributes
85
+ if (lowerAttr.startsWith('data')) {
86
+ if (!removeUnusedAttributes)
87
+ continue;
88
+ // Keep if any selector references this attribute
89
+ const inSelector = allSelectors.some(s => s.includes(attrName));
90
+ if (inSelector)
91
+ continue;
92
+ // Remove it
93
+ $(elem).removeAttr(attrName);
94
+ continue;
95
+ }
96
+ // Handle class attribute
97
+ if (lowerAttr === 'class') {
98
+ if (!removeUnusedClasses)
99
+ continue;
100
+ // In Tailwind mode, don't touch classes - they're utility classes, not CSS selectors
101
+ if (keepTailwindLabels)
102
+ continue;
103
+ const classList = (attribs[attrName] || '').split(/\s+/).filter(Boolean);
104
+ const removeList = [];
105
+ for (const cls of classList) {
106
+ // Keep icon font classes
107
+ if (isIconFontClass(cls))
108
+ continue;
109
+ const base = baseClassName(cls);
110
+ if (base === '')
111
+ continue;
112
+ // Check if this class appears in any selector
113
+ const found = allSelectors.some(s => s.includes(base));
114
+ if (!found) {
115
+ removeList.push(cls);
116
+ }
117
+ }
118
+ for (const cls of removeList) {
119
+ $(elem).removeClass(cls);
120
+ }
121
+ continue;
122
+ }
123
+ // Handle id and name
124
+ if (lowerAttr === 'id' || lowerAttr === 'name') {
125
+ if (!removeUnusedAttributes)
126
+ continue;
127
+ // Keep on form elements
128
+ if (FORM_TAGS.has(tagName))
129
+ continue;
130
+ // Keep if any selector references this value
131
+ const attrVal = attribs[attrName];
132
+ const inSelector = allSelectors.some(s => s.includes(attrVal));
133
+ if (inSelector)
134
+ continue;
135
+ $(elem).removeAttr(attrName);
136
+ continue;
137
+ }
138
+ // All other non-essential attributes
139
+ if (removeUnusedAttributes) {
140
+ $(elem).removeAttr(attrName);
141
+ }
142
+ }
143
+ });
144
+ let result = $.root().html() || '';
145
+ // Clean up empty class attributes
146
+ result = result.replace(/\s*class=""\s*/g, ' ').replace(/\s+>/g, '>');
147
+ return result;
148
+ }
149
+ //# sourceMappingURL=html-cleaner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-cleaner.js","sourceRoot":"","sources":["../../src/extraction/html-cleaner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { CDPMatchedStyles, ExtractionContext } from '../types/index.js';
2
+ /**
3
+ * Collects @keyframes animation rules from matched styles.
4
+ * Port of snipbackground.js:1997-2035
5
+ */
6
+ export declare class KeyframeCollector {
7
+ /**
8
+ * Extract keyframe animations from matched styles.
9
+ */
10
+ collect(allMatchedStyles: CDPMatchedStyles, ctx: ExtractionContext): void;
11
+ /**
12
+ * Generate CSS text for all collected keyframes.
13
+ */
14
+ generateCss(ctx: ExtractionContext): string;
15
+ }
16
+ //# sourceMappingURL=keyframe-collector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyframe-collector.d.ts","sourceRoot":"","sources":["../../src/extraction/keyframe-collector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAExE;;;GAGG;AACH,qBAAa,iBAAiB;IAC5B;;OAEG;IACH,OAAO,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,GAAG,EAAE,iBAAiB,GAAG,IAAI;IAuCzE;;OAEG;IACH,WAAW,CAAC,GAAG,EAAE,iBAAiB,GAAG,MAAM;CAgB5C"}