@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,120 @@
1
+ // Utility functions ported from snipbackground.js
2
+ export function escapeRegExp(str) {
3
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
4
+ }
5
+ export function randomLetters(length) {
6
+ const chars = 'abcdefghijklmnopqrstuvwxyz';
7
+ let result = '';
8
+ for (let i = 0; i < length; i++) {
9
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
10
+ }
11
+ return result;
12
+ }
13
+ export function getTimestamp() {
14
+ return new Date().toISOString().replace(/[:.]/g, '-');
15
+ }
16
+ /**
17
+ * Split a string by a separator but not inside parentheses
18
+ * Port of splitNoParen from snipbackground.js
19
+ */
20
+ export function splitNoParen(str, separator) {
21
+ const result = [];
22
+ let current = '';
23
+ let depth = 0;
24
+ for (let i = 0; i < str.length; i++) {
25
+ const char = str[i];
26
+ if (char === '(')
27
+ depth++;
28
+ else if (char === ')')
29
+ depth--;
30
+ if (depth === 0 && str.substring(i, i + separator.length) === separator) {
31
+ result.push(current);
32
+ current = '';
33
+ i += separator.length - 1;
34
+ }
35
+ else {
36
+ current += char;
37
+ }
38
+ }
39
+ result.push(current);
40
+ return result;
41
+ }
42
+ /**
43
+ * Check if a string looks like a URL
44
+ */
45
+ export function isUrl(str) {
46
+ return /^https?:\/\//i.test(str) || str.startsWith('//');
47
+ }
48
+ /**
49
+ * Resolve a relative URL against a base URL
50
+ */
51
+ export function resolveUrl(relative, base) {
52
+ if (!relative || isUrl(relative) || relative.startsWith('data:')) {
53
+ return relative;
54
+ }
55
+ try {
56
+ return new URL(relative, base).href;
57
+ }
58
+ catch {
59
+ return relative;
60
+ }
61
+ }
62
+ /**
63
+ * Strip snipcss marker classes from HTML
64
+ */
65
+ export function stripMarkerClasses(html) {
66
+ // Remove snipcssN-... class names
67
+ return html.replace(/\s*snipcss\d+-[a-z0-9-]+/g, '')
68
+ .replace(/\s*class=""/g, '');
69
+ }
70
+ /**
71
+ * Check if a CSS selector matches icon font patterns
72
+ */
73
+ export function isIconFontSelector(selector) {
74
+ if (!selector)
75
+ return false;
76
+ const patterns = [
77
+ /\.fa[srldb]?(?:\s|,|:|{|\[|$)/,
78
+ /\.fa-/,
79
+ /\.ti(?:\s|,|:|{|\[|$)/,
80
+ /\.ti-/,
81
+ /\.bi(?:\s|,|:|{|\[|$)/,
82
+ /\.bi-/,
83
+ /\.material-icons/,
84
+ /\.glyphicon/,
85
+ /\.icon-/,
86
+ /\.icofont-/,
87
+ /\.ri-/,
88
+ /\.bx-?/,
89
+ /\.la-?/,
90
+ ];
91
+ return patterns.some(pattern => pattern.test(selector));
92
+ }
93
+ /**
94
+ * Check if CSS body contains icon font-family
95
+ */
96
+ export function hasIconFontFamily(body) {
97
+ if (!body)
98
+ return false;
99
+ const fontMatch = body.match(/font-family\s*:\s*([^;]+)/i);
100
+ if (fontMatch) {
101
+ const fontValue = fontMatch[1].toLowerCase();
102
+ const iconFonts = [
103
+ 'font awesome', 'fontawesome', 'tabler', 'bootstrap-icons',
104
+ 'material icons', 'glyphicons', 'icomoon', 'icofont',
105
+ 'remixicon', 'boxicons', 'line awesome'
106
+ ];
107
+ return iconFonts.some(font => fontValue.includes(font));
108
+ }
109
+ return false;
110
+ }
111
+ export function isIconFontRule(selector, body) {
112
+ return isIconFontSelector(selector) || hasIconFontFamily(body);
113
+ }
114
+ /**
115
+ * Delay helper
116
+ */
117
+ export function delay(ms) {
118
+ return new Promise(resolve => setTimeout(resolve, ms));
119
+ }
120
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/utils/helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ export interface Token {
2
+ type: string;
3
+ content: string;
4
+ name?: string;
5
+ namespace?: string;
6
+ value?: string;
7
+ operator?: string;
8
+ argument?: string;
9
+ caseSensitive?: string;
10
+ pos: [number, number];
11
+ subtree?: ASTNode;
12
+ index?: string;
13
+ }
14
+ export type ASTNode = Token | {
15
+ type: 'list';
16
+ list: ASTNode[];
17
+ } | {
18
+ type: 'complex';
19
+ combinator: string;
20
+ left: ASTNode;
21
+ right: ASTNode;
22
+ } | {
23
+ type: 'relative';
24
+ combinator: string;
25
+ right: ASTNode;
26
+ } | {
27
+ type: 'compound';
28
+ list: Token[];
29
+ };
30
+ export declare const RECURSIVE_PSEUDO_CLASSES: Set<string>;
31
+ export declare function tokenize(selector: string, grammar?: Record<string, RegExp>): Token[];
32
+ export declare function flatten(node: ASTNode, parent?: ASTNode): Generator<[Token, ASTNode | undefined]>;
33
+ export declare function walk(node: ASTNode, visit: (token: Token, ast: ASTNode | undefined) => void, parent?: ASTNode): void;
34
+ export declare function parse(selector: string, { recursive, list }?: {
35
+ recursive?: boolean | undefined;
36
+ list?: boolean | undefined;
37
+ }): ASTNode | undefined;
38
+ export declare function stringify(listOrNode: Token[] | ASTNode): string;
39
+ export declare function specificityToNumber(spec: number[], base?: number): number;
40
+ export declare function specificity(selector: string | ASTNode): number[];
41
+ //# sourceMappingURL=parsel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parsel.d.ts","sourceRoot":"","sources":["../../src/utils/parsel.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,OAAO,GACf,KAAK,GACL;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,EAAE,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,KAAK,EAAE,CAAA;CAAE,CAAC;AAgBxC,eAAO,MAAM,wBAAwB,aAGnC,CAAC;AAoFH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAU,GAAG,KAAK,EAAE,CAoD5F;AA4CD,wBAAiB,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,CAAC,CAAC,CAsBjG;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,GAAG,SAAS,KAAK,IAAI,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAKnH;AAED,wBAAgB,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,SAAgB,EAAE,IAAW,EAAE;;;CAAK,GAAG,OAAO,GAAG,SAAS,CA4BnG;AAED,wBAAgB,SAAS,CAAC,UAAU,EAAE,KAAK,EAAE,GAAG,OAAO,GAAG,MAAM,CAiB/D;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAGzE;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,CAiDhE"}
@@ -0,0 +1,314 @@
1
+ // Port of parsel.js - CSS selector parser
2
+ // Original: /snip-extension/js/parsel.js (433 lines)
3
+ // This is a direct port to ES module with TypeScript types
4
+ const TOKENS = {
5
+ attribute: /\[\s*(?:(?<namespace>\*|[-\w\P{ASCII}]*)\|)?(?<name>[-\w\P{ASCII}]+)\s*(?:(?<operator>\W?=)\s*(?<value>.+?)\s*(\s(?<caseSensitive>[iIsS]))?\s*)?\]/gu,
6
+ id: /#(?<name>[-\w\P{ASCII}]+)/gu,
7
+ class: /\.(?<name>[-\w\P{ASCII}]+)/gu,
8
+ comma: /\s*,\s*/g,
9
+ combinator: /\s*[\s>+~]\s*/g,
10
+ 'pseudo-element': /::(?<name>[-\w\P{ASCII}]+)(?:\((?<argument>\xB6*)\))?/gu,
11
+ 'pseudo-class': /:(?<name>[-\w\P{ASCII}]+)(?:\((?<argument>\xB6*)\))?/gu,
12
+ universal: /(?:(?<namespace>\*|[-\w\P{ASCII}]*)\|)?\*/gu,
13
+ type: /(?:(?<namespace>\*|[-\w\P{ASCII}]*)\|)?(?<name>[-\w\P{ASCII}]+)/gu,
14
+ };
15
+ const TRIM_TOKENS = new Set(['combinator', 'comma']);
16
+ export const RECURSIVE_PSEUDO_CLASSES = new Set([
17
+ 'not', 'is', 'where', 'has', 'matches',
18
+ '-moz-any', '-webkit-any', 'nth-child', 'nth-last-child',
19
+ ]);
20
+ const nthChildRegExp = /(?<index>[\dn+-]+)\s+of\s+(?<subtree>.+)/;
21
+ const RECURSIVE_PSEUDO_CLASSES_ARGS = {
22
+ 'nth-child': nthChildRegExp,
23
+ 'nth-last-child': nthChildRegExp,
24
+ };
25
+ const getArgumentPatternByType = (type) => {
26
+ switch (type) {
27
+ case 'pseudo-element':
28
+ case 'pseudo-class':
29
+ return new RegExp(TOKENS[type].source.replace('(?<argument>\xB6*)', '(?<argument>.*)'), 'gu');
30
+ default:
31
+ return TOKENS[type];
32
+ }
33
+ };
34
+ function gobbleParens(text, offset) {
35
+ let nesting = 0;
36
+ let result = '';
37
+ for (; offset < text.length; offset++) {
38
+ const char = text[offset];
39
+ if (char === '(')
40
+ ++nesting;
41
+ else if (char === ')')
42
+ --nesting;
43
+ result += char;
44
+ if (nesting === 0)
45
+ return result;
46
+ }
47
+ return result;
48
+ }
49
+ function tokenizeBy(text, grammar = TOKENS) {
50
+ if (!text)
51
+ return [];
52
+ const tokens = [text];
53
+ for (const [type, pattern] of Object.entries(grammar)) {
54
+ for (let i = 0; i < tokens.length; i++) {
55
+ const token = tokens[i];
56
+ if (typeof token !== 'string')
57
+ continue;
58
+ pattern.lastIndex = 0;
59
+ const match = pattern.exec(token);
60
+ if (!match)
61
+ continue;
62
+ const from = match.index - 1;
63
+ const args = [];
64
+ const content = match[0];
65
+ const before = token.slice(0, from + 1);
66
+ if (before)
67
+ args.push(before);
68
+ args.push({
69
+ ...match.groups,
70
+ type,
71
+ content,
72
+ pos: [0, 0],
73
+ });
74
+ const after = token.slice(from + content.length + 1);
75
+ if (after)
76
+ args.push(after);
77
+ tokens.splice(i, 1, ...args);
78
+ }
79
+ }
80
+ let offset = 0;
81
+ for (const token of tokens) {
82
+ if (typeof token === 'string') {
83
+ throw new Error(`Unexpected sequence ${token} found at index ${offset}`);
84
+ }
85
+ offset += token.content.length;
86
+ token.pos = [offset - token.content.length, offset];
87
+ if (TRIM_TOKENS.has(token.type)) {
88
+ token.content = token.content.trim() || ' ';
89
+ }
90
+ }
91
+ return tokens;
92
+ }
93
+ const STRING_PATTERN = /(['"])([^\\\n]+?)\1/g;
94
+ const ESCAPE_PATTERN = /\\./g;
95
+ export function tokenize(selector, grammar = TOKENS) {
96
+ selector = selector.trim();
97
+ if (selector === '')
98
+ return [];
99
+ const replacements = [];
100
+ selector = selector.replace(ESCAPE_PATTERN, (value, offset) => {
101
+ replacements.push({ value, offset });
102
+ return '\uE000'.repeat(value.length);
103
+ });
104
+ selector = selector.replace(STRING_PATTERN, (value, _quote, content, offset) => {
105
+ replacements.push({ value, offset });
106
+ return `${_quote}${'\uE001'.repeat(content.length)}${_quote}`;
107
+ });
108
+ {
109
+ let pos = 0;
110
+ let offset;
111
+ while ((offset = selector.indexOf('(', pos)) > -1) {
112
+ const value = gobbleParens(selector, offset);
113
+ replacements.push({ value, offset });
114
+ selector = `${selector.substring(0, offset)}(${'¶'.repeat(value.length - 2)})${selector.substring(offset + value.length)}`;
115
+ pos = offset + value.length;
116
+ }
117
+ }
118
+ const tokens = tokenizeBy(selector, grammar);
119
+ const changedTokens = new Set();
120
+ for (const replacement of replacements.reverse()) {
121
+ for (const token of tokens) {
122
+ const { offset, value } = replacement;
123
+ if (!(token.pos[0] <= offset && offset + value.length <= token.pos[1]))
124
+ continue;
125
+ const { content } = token;
126
+ const tokenOffset = offset - token.pos[0];
127
+ token.content = content.slice(0, tokenOffset) + value + content.slice(tokenOffset + value.length);
128
+ if (token.content !== content)
129
+ changedTokens.add(token);
130
+ }
131
+ }
132
+ for (const token of changedTokens) {
133
+ const pattern = getArgumentPatternByType(token.type);
134
+ if (!pattern)
135
+ throw new Error(`Unknown token type: ${token.type}`);
136
+ pattern.lastIndex = 0;
137
+ const match = pattern.exec(token.content);
138
+ if (!match)
139
+ throw new Error(`Unable to parse content for ${token.type}: ${token.content}`);
140
+ Object.assign(token, match.groups);
141
+ }
142
+ return tokens;
143
+ }
144
+ function nestTokens(tokens, { list = true } = {}) {
145
+ if (list && tokens.find(t => t.type === 'comma')) {
146
+ const selectors = [];
147
+ const temp = [];
148
+ for (let i = 0; i < tokens.length; i++) {
149
+ if (tokens[i].type === 'comma') {
150
+ if (temp.length === 0)
151
+ throw new Error('Incorrect comma at ' + i);
152
+ selectors.push(nestTokens(temp, { list: false }));
153
+ temp.length = 0;
154
+ }
155
+ else {
156
+ temp.push(tokens[i]);
157
+ }
158
+ }
159
+ if (temp.length === 0)
160
+ throw new Error('Trailing comma');
161
+ selectors.push(nestTokens(temp, { list: false }));
162
+ return { type: 'list', list: selectors };
163
+ }
164
+ for (let i = tokens.length - 1; i >= 0; i--) {
165
+ const token = tokens[i];
166
+ if (token.type === 'combinator') {
167
+ const left = tokens.slice(0, i);
168
+ const right = tokens.slice(i + 1);
169
+ if (left.length === 0) {
170
+ return { type: 'relative', combinator: token.content, right: nestTokens(right) };
171
+ }
172
+ return {
173
+ type: 'complex',
174
+ combinator: token.content,
175
+ left: nestTokens(left),
176
+ right: nestTokens(right),
177
+ };
178
+ }
179
+ }
180
+ switch (tokens.length) {
181
+ case 0: throw new Error('Could not build AST.');
182
+ case 1: return tokens[0];
183
+ default: return { type: 'compound', list: [...tokens] };
184
+ }
185
+ }
186
+ export function* flatten(node, parent) {
187
+ switch (node.type) {
188
+ case 'list':
189
+ for (const child of node.list) {
190
+ yield* flatten(child, node);
191
+ }
192
+ break;
193
+ case 'complex':
194
+ yield* flatten(node.left, node);
195
+ yield* flatten(node.right, node);
196
+ break;
197
+ case 'relative':
198
+ yield* flatten(node.right, node);
199
+ break;
200
+ case 'compound':
201
+ for (const token of node.list) {
202
+ yield [token, node];
203
+ }
204
+ break;
205
+ default:
206
+ yield [node, parent];
207
+ }
208
+ }
209
+ export function walk(node, visit, parent) {
210
+ if (!node)
211
+ return;
212
+ for (const [token, ast] of flatten(node, parent)) {
213
+ visit(token, ast);
214
+ }
215
+ }
216
+ export function parse(selector, { recursive = true, list = true } = {}) {
217
+ const tokens = tokenize(selector);
218
+ if (!tokens || tokens.length === 0)
219
+ return undefined;
220
+ const ast = nestTokens(tokens, { list });
221
+ if (!recursive)
222
+ return ast;
223
+ for (const [token] of flatten(ast)) {
224
+ if (token.type !== 'pseudo-class' || !token.argument)
225
+ continue;
226
+ if (!RECURSIVE_PSEUDO_CLASSES.has(token.name || ''))
227
+ continue;
228
+ let argument = token.argument;
229
+ const childArg = RECURSIVE_PSEUDO_CLASSES_ARGS[token.name || ''];
230
+ if (childArg) {
231
+ const match = childArg.exec(argument);
232
+ if (!match)
233
+ continue;
234
+ Object.assign(token, match.groups);
235
+ argument = match.groups?.['subtree'] || '';
236
+ }
237
+ if (!argument)
238
+ continue;
239
+ Object.assign(token, {
240
+ subtree: parse(argument, { recursive: true, list: true }),
241
+ });
242
+ }
243
+ return ast;
244
+ }
245
+ export function stringify(listOrNode) {
246
+ if (Array.isArray(listOrNode)) {
247
+ return listOrNode.map(token => token.content).join('');
248
+ }
249
+ switch (listOrNode.type) {
250
+ case 'list':
251
+ return listOrNode.list.map(stringify).join(',');
252
+ case 'relative':
253
+ return listOrNode.combinator + stringify(listOrNode.right);
254
+ case 'complex':
255
+ return stringify(listOrNode.left) + listOrNode.combinator + stringify(listOrNode.right);
256
+ case 'compound':
257
+ return listOrNode.list.map(stringify).join('');
258
+ default:
259
+ return listOrNode.content;
260
+ }
261
+ }
262
+ export function specificityToNumber(spec, base) {
263
+ base = base || Math.max(...spec) + 1;
264
+ return spec[0] * (base << 1) + spec[1] * base + spec[2];
265
+ }
266
+ export function specificity(selector) {
267
+ let ast = selector;
268
+ if (typeof ast === 'string') {
269
+ ast = parse(ast, { recursive: true });
270
+ }
271
+ if (!ast)
272
+ return [];
273
+ if (ast.type === 'list' && 'list' in ast) {
274
+ let base = 10;
275
+ const listNode = ast;
276
+ const specificities = listNode.list.map(a => {
277
+ const sp = specificity(a);
278
+ base = Math.max(base, ...specificity(a));
279
+ return sp;
280
+ });
281
+ const numbers = specificities.map(s => specificityToNumber(s, base));
282
+ return specificities[numbers.indexOf(Math.max(...numbers))];
283
+ }
284
+ const ret = [0, 0, 0];
285
+ for (const [token] of flatten(ast)) {
286
+ switch (token.type) {
287
+ case 'id':
288
+ ret[0]++;
289
+ break;
290
+ case 'class':
291
+ case 'attribute':
292
+ ret[1]++;
293
+ break;
294
+ case 'pseudo-element':
295
+ case 'type':
296
+ ret[2]++;
297
+ break;
298
+ case 'pseudo-class':
299
+ if (token.name === 'where')
300
+ break;
301
+ if (!RECURSIVE_PSEUDO_CLASSES.has(token.name || '') || !token.subtree) {
302
+ ret[1]++;
303
+ break;
304
+ }
305
+ const sub = specificity(token.subtree);
306
+ sub.forEach((s, i) => (ret[i] += s));
307
+ if (token.name === 'nth-child' || token.name === 'nth-last-child') {
308
+ ret[1]++;
309
+ }
310
+ }
311
+ }
312
+ return ret;
313
+ }
314
+ //# sourceMappingURL=parsel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parsel.js","sourceRoot":"","sources":["../../src/utils/parsel.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@productivemark/snipcss",
3
+ "version": "1.0.0",
4
+ "description": "Snipcss tools are the most accurate way to convert a repo to tailwind or extract designs from existing websites. This plugin allows Claude to use SnipCSS however needed - whether it's Tailwind conversion or importing pixel-perfect designs.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "snipcss": "dist/mcp-server.js",
9
+ "snipcss-extract": "dist/index.js"
10
+ },
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "dev": "tsc --watch",
14
+ "start": "node dist/index.js",
15
+ "mcp": "node dist/mcp-server.js"
16
+ },
17
+ "author": "Productive Mark LLC",
18
+ "license": "UNLICENSED",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/mrieck/snipcss-playwright-claudeplugin"
22
+ },
23
+ "keywords": ["snipcss", "css", "tailwind", "extraction", "playwright", "mcp", "claude-code"],
24
+ "files": [
25
+ "dist/",
26
+ "skills/",
27
+ ".claude-plugin/",
28
+ ".mcp.json"
29
+ ],
30
+ "dependencies": {
31
+ "playwright": "^1.48.2",
32
+ "cheerio": "1.0.0",
33
+ "yargs": "^17.7.2",
34
+ "@modelcontextprotocol/sdk": "^1.0.0"
35
+ },
36
+ "devDependencies": {
37
+ "typescript": "^5.3.0",
38
+ "@types/node": "^20.10.0",
39
+ "@types/yargs": "^17.0.32"
40
+ }
41
+ }
@@ -0,0 +1,95 @@
1
+ ---
2
+ name: workflow
3
+ description: Use snipcss tools to find elements, extract CSS or convert ANY ELEMENT to tailwind. You can use the tools to convert existing code to tailwind, or take code from other websites and receive both CSS and tailwind. Just describe what you want.
4
+ argument-hint: "<description of what to extract, including URL>"
5
+ user-invocable: true
6
+ allowed-tools: Bash(node *), Bash(npm *), Bash(npx tsc *)
7
+ ---
8
+
9
+ # SnipCSS Design Extraction & Integration
10
+
11
+ Extract a design component from an external website and autonomously integrate it into the user's current project.
12
+
13
+ ## Workflow
14
+
15
+ ### Step 1: DISCOVER
16
+
17
+ Call the `screenshot_page` MCP tool with the target URL. This returns:
18
+ - An annotated screenshot with numbered labels (#1, #2, #3...) overlaid on page elements
19
+ - A text legend mapping each number to its CSS selector, semantic type, size, and content preview
20
+
21
+ Look at the screenshot visually to understand the page layout.
22
+
23
+ ### Step 2: IDENTIFY
24
+
25
+ Match the user's natural language description to the numbered elements:
26
+ - "the sidebar" → look for elements labeled as Sidebar, aside tags, or side-positioned elements
27
+ - "the pricing cards" → look for Card-type elements with pricing-related text
28
+ - "the navigation" → look for Navigation/Header type elements
29
+ - "the hero section" → look for Hero Section type elements near the top
30
+
31
+ If the match is ambiguous (multiple possible elements), ask the user to clarify by referencing the numbered labels:
32
+ > "I see several card-like elements: #4 (Card, 350x280) and #7 (Card, 350x280). Which one did you mean, or should I extract the whole section containing them?"
33
+
34
+ If the user didn't specify a URL, ask for one.
35
+
36
+ ### Step 3: EXTRACT
37
+
38
+ Call the `extract_css_convert_tailwind` MCP tool with:
39
+ - `url`: the target URL
40
+ - `selector`: the CSS selector from the identified element
41
+ - `viewport`: `"all"` for responsive extraction (default)
42
+ - `resolveVariables`: `true`
43
+ - `includeHoverStates`: `true`
44
+
45
+ The tool returns:
46
+ - `html` — clean extracted HTML
47
+ - `css` — complete CSS with fonts, variables, keyframes, media queries
48
+ - `tailwindHtml` — HTML with Tailwind utility classes
49
+ - `tailwindBodyClasses` — body-level Tailwind classes
50
+ - `fonts` — font definitions used
51
+ - `cssVariables` — resolved CSS custom properties
52
+
53
+ ### Step 4: INTEGRATE
54
+
55
+ You have full context of the user's project. Read the codebase to understand:
56
+ - What language/framework is used (React, Vue, Svelte, Rails, Django, plain HTML, etc.)
57
+ - What styling approach is used (Tailwind, CSS Modules, styled-components, plain CSS, SCSS, etc.)
58
+ - What the component/file structure looks like
59
+ - What existing patterns to follow
60
+
61
+ Then adapt and integrate the extracted design:
62
+
63
+ **Styling decision:**
64
+ - If the project uses Tailwind → use the `tailwindHtml` output
65
+ - If the project uses plain CSS/SCSS → use the `html` + `css` output
66
+ - If the project uses CSS Modules/styled-components → convert the CSS to that format
67
+
68
+ **Framework adaptation:**
69
+ - React/Next.js → Convert to JSX (className, self-closing tags, camelCase style props)
70
+ - Vue → Convert to SFC template syntax
71
+ - Svelte → Convert to .svelte component format
72
+ - Rails ERB/HAML → Convert to template format
73
+ - Any other framework → adapt accordingly using your knowledge of that framework
74
+
75
+ **Integration:**
76
+ - Place the component where it makes sense in the project structure
77
+ - Adapt image URLs (note which ones need replacing with local assets)
78
+ - Add font imports if the extracted design uses fonts not already in the project
79
+ - Match the project's naming conventions, export patterns, and coding style
80
+ - Wire up the component where the user needs it (if the placement is clear)
81
+
82
+ ### Step 5: REPORT
83
+
84
+ After integration, briefly tell the user:
85
+ - What was extracted and from where
86
+ - Where the component was placed in their project
87
+ - Any manual steps needed (e.g., "Replace the placeholder images at lines X-Y with your own assets")
88
+ - Any fonts or dependencies that may need to be added
89
+
90
+ ## Notes
91
+
92
+ - The `screenshot_page` and `list_page_elements` tools share the same element discovery — the numbered labels match between them
93
+ - If extraction fails on a selector, try a broader parent selector or a more specific child
94
+ - For complex multi-part designs (e.g., an entire page section with nested cards), extract the outermost container to get everything
95
+ - The extraction tool handles responsive styles automatically when viewport is set to "all"