@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.
- package/.claude-plugin/marketplace.json +17 -0
- package/.claude-plugin/plugin.json +10 -0
- package/.mcp.json +8 -0
- package/dist/auth/config-manager.d.ts +13 -0
- package/dist/auth/config-manager.d.ts.map +1 -0
- package/dist/auth/config-manager.js +48 -0
- package/dist/auth/config-manager.js.map +1 -0
- package/dist/auth/usage-gate.d.ts +13 -0
- package/dist/auth/usage-gate.d.ts.map +1 -0
- package/dist/auth/usage-gate.js +69 -0
- package/dist/auth/usage-gate.js.map +1 -0
- package/dist/browser/browser-manager.d.ts +15 -0
- package/dist/browser/browser-manager.d.ts.map +1 -0
- package/dist/browser/browser-manager.js +61 -0
- package/dist/browser/browser-manager.js.map +1 -0
- package/dist/browser/viewport-manager.d.ts +8 -0
- package/dist/browser/viewport-manager.d.ts.map +1 -0
- package/dist/browser/viewport-manager.js +50 -0
- package/dist/browser/viewport-manager.js.map +1 -0
- package/dist/extraction/css-variable-resolver.d.ts +27 -0
- package/dist/extraction/css-variable-resolver.d.ts.map +1 -0
- package/dist/extraction/css-variable-resolver.js +105 -0
- package/dist/extraction/css-variable-resolver.js.map +1 -0
- package/dist/extraction/dom-labeler.d.ts +26 -0
- package/dist/extraction/dom-labeler.d.ts.map +1 -0
- package/dist/extraction/dom-labeler.js +124 -0
- package/dist/extraction/dom-labeler.js.map +1 -0
- package/dist/extraction/element-discovery.d.ts +59 -0
- package/dist/extraction/element-discovery.d.ts.map +1 -0
- package/dist/extraction/element-discovery.js +525 -0
- package/dist/extraction/element-discovery.js.map +1 -0
- package/dist/extraction/extraction-pipeline.d.ts +26 -0
- package/dist/extraction/extraction-pipeline.d.ts.map +1 -0
- package/dist/extraction/extraction-pipeline.js +200 -0
- package/dist/extraction/extraction-pipeline.js.map +1 -0
- package/dist/extraction/font-collector.d.ts +26 -0
- package/dist/extraction/font-collector.d.ts.map +1 -0
- package/dist/extraction/font-collector.js +160 -0
- package/dist/extraction/font-collector.js.map +1 -0
- package/dist/extraction/html-cleaner.d.ts +16 -0
- package/dist/extraction/html-cleaner.d.ts.map +1 -0
- package/dist/extraction/html-cleaner.js +149 -0
- package/dist/extraction/html-cleaner.js.map +1 -0
- package/dist/extraction/keyframe-collector.d.ts +16 -0
- package/dist/extraction/keyframe-collector.d.ts.map +1 -0
- package/dist/extraction/keyframe-collector.js +62 -0
- package/dist/extraction/keyframe-collector.js.map +1 -0
- package/dist/extraction/pseudo-state-handler.d.ts +36 -0
- package/dist/extraction/pseudo-state-handler.d.ts.map +1 -0
- package/dist/extraction/pseudo-state-handler.js +210 -0
- package/dist/extraction/pseudo-state-handler.js.map +1 -0
- package/dist/extraction/result-builder.d.ts +25 -0
- package/dist/extraction/result-builder.d.ts.map +1 -0
- package/dist/extraction/result-builder.js +136 -0
- package/dist/extraction/result-builder.js.map +1 -0
- package/dist/extraction/rule-deduplicator.d.ts +39 -0
- package/dist/extraction/rule-deduplicator.d.ts.map +1 -0
- package/dist/extraction/rule-deduplicator.js +107 -0
- package/dist/extraction/rule-deduplicator.js.map +1 -0
- package/dist/extraction/selector-fixer.d.ts +25 -0
- package/dist/extraction/selector-fixer.d.ts.map +1 -0
- package/dist/extraction/selector-fixer.js +111 -0
- package/dist/extraction/selector-fixer.js.map +1 -0
- package/dist/extraction/specificity.d.ts +17 -0
- package/dist/extraction/specificity.d.ts.map +1 -0
- package/dist/extraction/specificity.js +88 -0
- package/dist/extraction/specificity.js.map +1 -0
- package/dist/extraction/style-matcher.d.ts +33 -0
- package/dist/extraction/style-matcher.d.ts.map +1 -0
- package/dist/extraction/style-matcher.js +199 -0
- package/dist/extraction/style-matcher.js.map +1 -0
- package/dist/extraction/stylesheet-collector.d.ts +33 -0
- package/dist/extraction/stylesheet-collector.d.ts.map +1 -0
- package/dist/extraction/stylesheet-collector.js +71 -0
- package/dist/extraction/stylesheet-collector.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +235 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server.d.ts +3 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +349 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/tailwind/css-to-tailwind.d.ts +17 -0
- package/dist/tailwind/css-to-tailwind.d.ts.map +1 -0
- package/dist/tailwind/css-to-tailwind.js +1583 -0
- package/dist/tailwind/css-to-tailwind.js.map +1 -0
- package/dist/tailwind/shorthand-expander.d.ts +27 -0
- package/dist/tailwind/shorthand-expander.d.ts.map +1 -0
- package/dist/tailwind/shorthand-expander.js +812 -0
- package/dist/tailwind/shorthand-expander.js.map +1 -0
- package/dist/tailwind/tailwind-converter.d.ts +35 -0
- package/dist/tailwind/tailwind-converter.d.ts.map +1 -0
- package/dist/tailwind/tailwind-converter.js +1223 -0
- package/dist/tailwind/tailwind-converter.js.map +1 -0
- package/dist/tailwind/tailwind-helpers.d.ts +95 -0
- package/dist/tailwind/tailwind-helpers.d.ts.map +1 -0
- package/dist/tailwind/tailwind-helpers.js +593 -0
- package/dist/tailwind/tailwind-helpers.js.map +1 -0
- package/dist/tailwind/tailwind-reducer.d.ts +36 -0
- package/dist/tailwind/tailwind-reducer.d.ts.map +1 -0
- package/dist/tailwind/tailwind-reducer.js +189 -0
- package/dist/tailwind/tailwind-reducer.js.map +1 -0
- package/dist/types/index.d.ts +239 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +94 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/helpers.d.ts +34 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +120 -0
- package/dist/utils/helpers.js.map +1 -0
- package/dist/utils/parsel.d.ts +41 -0
- package/dist/utils/parsel.d.ts.map +1 -0
- package/dist/utils/parsel.js +314 -0
- package/dist/utils/parsel.js.map +1 -0
- package/package.json +41 -0
- 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"
|