esm-styles 0.2.8 → 0.3.1
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/README.md +26 -6
- package/dist/build.js +0 -0
- package/dist/lib/build.js +19 -4
- package/doc/ai-guide.md +29 -2
- package/doc/api-reference.md +30 -14
- package/doc/best-practices.md +793 -0
- package/doc/usage-guide.md +66 -15
- package/package.json +1 -1
- package/dist/lib/getCss.d.ts +0 -14
- package/dist/lib/getCss.js +0 -260
- package/dist/lib/utils/common.d.ts +0 -28
- package/dist/lib/utils/common.js +0 -47
- package/dist/lib/utils/endValue.d.ts +0 -2
- package/dist/lib/utils/endValue.js +0 -10
- package/dist/lib/utils/media.d.ts +0 -24
- package/dist/lib/utils/media.js +0 -93
- package/dist/lib/utils/obj2css.d.ts +0 -15
- package/dist/lib/utils/obj2css.js +0 -79
- package/dist/lib/utils/selectors.d.ts +0 -15
- package/dist/lib/utils/selectors.js +0 -87
- package/dist/lib/utils/tags.d.ts +0 -10
- package/dist/lib/utils/tags.js +0 -128
- package/dist/lib/utils/traversal.d.ts +0 -25
- package/dist/lib/utils/traversal.js +0 -78
- package/dist/watch.js +0 -37
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utilities for converting JavaScript objects to CSS strings
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Converts a CSS object to a string representation
|
|
6
|
-
* @param cssObject - Object with CSS selectors and properties
|
|
7
|
-
* @returns CSS string
|
|
8
|
-
*/
|
|
9
|
-
export function obj2css(cssObject) {
|
|
10
|
-
// Convert object to JSON string with indentation
|
|
11
|
-
const json = JSON.stringify(cssObject, null, 2);
|
|
12
|
-
// Process the JSON string to convert to valid CSS
|
|
13
|
-
const css = json
|
|
14
|
-
// Replace double quotes with single quotes for strings
|
|
15
|
-
.replace(/\\"/g, "'")
|
|
16
|
-
// Convert object keys to CSS selectors
|
|
17
|
-
.replace(/"([^"]+)":\s*{/g, '$1 {')
|
|
18
|
-
// Remove commas between rule sets and add empty line
|
|
19
|
-
.replace(/},/g, '}')
|
|
20
|
-
// Remove remaining double quotes
|
|
21
|
-
.replace(/"/g, '')
|
|
22
|
-
// Restore quotes for inlined URLs
|
|
23
|
-
.replace(/url\('(.+)'\)/g, 'url("$1")')
|
|
24
|
-
// Convert property-value commas to semicolons
|
|
25
|
-
.replace(/,(\s*})/g, ';$1')
|
|
26
|
-
// Remove the outermost curly braces
|
|
27
|
-
.replace(/^{|}$/g, '')
|
|
28
|
-
// Convert commas between property values to semicolons
|
|
29
|
-
.replace(/,\s*(?=[a-z-]+:)/g, ';\n ')
|
|
30
|
-
// Remove indentation from the start of lines
|
|
31
|
-
.replace(/^( {2})/gm, '')
|
|
32
|
-
// Add semicolons before closing brackets if missing
|
|
33
|
-
.replace(/([^;])\s*}/g, '$1;\n}')
|
|
34
|
-
// Ensure space between property name and value
|
|
35
|
-
.replace(/:\s*/g, ': ')
|
|
36
|
-
// Clean up extra spaces
|
|
37
|
-
.replace(/\s+/g, ' ')
|
|
38
|
-
// Fix colon spacing in selectors
|
|
39
|
-
.replace(/([:#]) /g, '$1');
|
|
40
|
-
// Split into lines for additional processing
|
|
41
|
-
const lines = css.split('\n');
|
|
42
|
-
const result = [];
|
|
43
|
-
for (let i = 0; i < lines.length; i++) {
|
|
44
|
-
const line = lines[i];
|
|
45
|
-
// Handle property lines
|
|
46
|
-
if (line.includes(': ')) {
|
|
47
|
-
result.push(' ' + line.trim());
|
|
48
|
-
}
|
|
49
|
-
// Handle selector lines
|
|
50
|
-
else if (line.includes('{')) {
|
|
51
|
-
result.push(line.trim());
|
|
52
|
-
}
|
|
53
|
-
// Handle closing bracket lines
|
|
54
|
-
else if (line.includes('}')) {
|
|
55
|
-
result.push('}');
|
|
56
|
-
}
|
|
57
|
-
// Other lines
|
|
58
|
-
else {
|
|
59
|
-
result.push(line);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return result.join('\n');
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Prettifies a CSS string by ensuring consistent spacing and formatting
|
|
66
|
-
* @param cssString - CSS string to prettify
|
|
67
|
-
* @returns Prettified CSS string
|
|
68
|
-
*/
|
|
69
|
-
export function prettifyCss(cssString) {
|
|
70
|
-
return (cssString
|
|
71
|
-
// Ensure consistent newlines between rule sets
|
|
72
|
-
.replace(/}\s*/g, '}\n\n')
|
|
73
|
-
// Fix spacing inside brackets
|
|
74
|
-
.replace(/{\s*/g, ' {\n')
|
|
75
|
-
// Clean up extra newlines
|
|
76
|
-
.replace(/\n{3,}/g, '\n\n')
|
|
77
|
-
// Trim the string
|
|
78
|
-
.trim());
|
|
79
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utilities for working with CSS selectors
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Joins selector parts into a valid CSS selector
|
|
6
|
-
* @param path - Array of selector parts or a single selector
|
|
7
|
-
* @returns Combined CSS selector
|
|
8
|
-
*/
|
|
9
|
-
export declare function joinSelectors(path: string | string[]): string;
|
|
10
|
-
/**
|
|
11
|
-
* Creates a Cartesian product of selector parts and joins them
|
|
12
|
-
* @param parts - Array of selector parts arrays
|
|
13
|
-
* @returns Array of all possible combined selectors
|
|
14
|
-
*/
|
|
15
|
-
export declare function cartesianSelectors(parts: string[][]): string[];
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utilities for working with CSS selectors
|
|
3
|
-
*/
|
|
4
|
-
import { isHtmlTag } from './tags.js';
|
|
5
|
-
/**
|
|
6
|
-
* Joins selector parts into a valid CSS selector
|
|
7
|
-
* @param path - Array of selector parts or a single selector
|
|
8
|
-
* @returns Combined CSS selector
|
|
9
|
-
*/
|
|
10
|
-
export function joinSelectors(path) {
|
|
11
|
-
const array = typeof path === 'string' ? [path] : path;
|
|
12
|
-
let result = '';
|
|
13
|
-
for (const keyStr of array) {
|
|
14
|
-
// Skip empty key strings
|
|
15
|
-
if (!keyStr.trim())
|
|
16
|
-
continue;
|
|
17
|
-
const key = keyStr.replace(/&/g, '').trim();
|
|
18
|
-
if (isHtmlTag(key)) {
|
|
19
|
-
// If it's an HTML tag, just add it with a space
|
|
20
|
-
result += ` ${key}`;
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
let prefix = '';
|
|
24
|
-
let selector = key;
|
|
25
|
-
// Handle reference to parent selector with &
|
|
26
|
-
if (/^&/.test(keyStr)) {
|
|
27
|
-
prefix += ' ';
|
|
28
|
-
}
|
|
29
|
-
// Handle double underscore for descendant of any level (T6)
|
|
30
|
-
if (/^__/.test(key)) {
|
|
31
|
-
prefix += ' ';
|
|
32
|
-
selector = selector.replace(/^__/, '');
|
|
33
|
-
}
|
|
34
|
-
// Handle single underscore for class selector (T5)
|
|
35
|
-
if (/^_/.test(key)) {
|
|
36
|
-
selector = selector.replace(/^_/, '');
|
|
37
|
-
if (!isHtmlTag(selector)) {
|
|
38
|
-
// If not a tag, increase level
|
|
39
|
-
prefix += ' ';
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
// Add dot for class selectors if needed
|
|
43
|
-
if (!/^[.:#*[~+>]/.test(selector)) {
|
|
44
|
-
if (!/\./.test(prefix))
|
|
45
|
-
prefix += '.';
|
|
46
|
-
}
|
|
47
|
-
// Special handling for universal selector
|
|
48
|
-
if (/^\*/.test(selector)) {
|
|
49
|
-
prefix = ' ' + prefix;
|
|
50
|
-
}
|
|
51
|
-
result += prefix + selector;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
// Fix any double dots that might have been created
|
|
55
|
-
result = result.replace(/\.\s*\./g, '.');
|
|
56
|
-
// Clean up whitespace
|
|
57
|
-
result = result
|
|
58
|
-
// Remove extra spaces
|
|
59
|
-
.replace(/\s+/g, ' ')
|
|
60
|
-
// Preserve proper spacing around combinators
|
|
61
|
-
.replace(/\s*([>+~])\s*/g, ' $1 ')
|
|
62
|
-
// Fix pseudo-classes and pseudo-elements
|
|
63
|
-
.replace(/\s+:/g, ':')
|
|
64
|
-
// Fix attribute selectors
|
|
65
|
-
.replace(/\s+\[/g, '[')
|
|
66
|
-
// Trim whitespace
|
|
67
|
-
.trim();
|
|
68
|
-
return result;
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Creates a Cartesian product of selector parts and joins them
|
|
72
|
-
* @param parts - Array of selector parts arrays
|
|
73
|
-
* @returns Array of all possible combined selectors
|
|
74
|
-
*/
|
|
75
|
-
export function cartesianSelectors(parts) {
|
|
76
|
-
// Base case: If empty or just one part, return it flattened
|
|
77
|
-
if (parts.length === 0)
|
|
78
|
-
return [];
|
|
79
|
-
if (parts.length === 1)
|
|
80
|
-
return parts[0];
|
|
81
|
-
// Implementation of cartesian product
|
|
82
|
-
const result = parts.reduce((acc, curr) => acc.flatMap((x) => curr.map((y) => [...x, y])), [[]]);
|
|
83
|
-
return result.map((selectors) => {
|
|
84
|
-
// Handle comma-separated selectors by creating real CSS selector lists
|
|
85
|
-
return joinSelectors(selectors.filter(Boolean));
|
|
86
|
-
});
|
|
87
|
-
}
|
package/dist/lib/utils/tags.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* List of all HTML tags used to identify selectors
|
|
3
|
-
*/
|
|
4
|
-
export declare const htmlTags: string[];
|
|
5
|
-
/**
|
|
6
|
-
* Checks if a string is an HTML tag name
|
|
7
|
-
* @param key - String to check
|
|
8
|
-
* @returns True if the string is an HTML tag name
|
|
9
|
-
*/
|
|
10
|
-
export declare function isHtmlTag(key: string): boolean;
|
package/dist/lib/utils/tags.js
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* List of all HTML tags used to identify selectors
|
|
3
|
-
*/
|
|
4
|
-
export const htmlTags = [
|
|
5
|
-
'a',
|
|
6
|
-
'abbr',
|
|
7
|
-
'address',
|
|
8
|
-
'area',
|
|
9
|
-
'article',
|
|
10
|
-
'aside',
|
|
11
|
-
'audio',
|
|
12
|
-
'b',
|
|
13
|
-
'base',
|
|
14
|
-
'bdi',
|
|
15
|
-
'bdo',
|
|
16
|
-
'blockquote',
|
|
17
|
-
'body',
|
|
18
|
-
'br',
|
|
19
|
-
'button',
|
|
20
|
-
'canvas',
|
|
21
|
-
'caption',
|
|
22
|
-
'cite',
|
|
23
|
-
'code',
|
|
24
|
-
'col',
|
|
25
|
-
'colgroup',
|
|
26
|
-
'data',
|
|
27
|
-
'datalist',
|
|
28
|
-
'dd',
|
|
29
|
-
'del',
|
|
30
|
-
'details',
|
|
31
|
-
'dfn',
|
|
32
|
-
'dialog',
|
|
33
|
-
'div',
|
|
34
|
-
'dl',
|
|
35
|
-
'dt',
|
|
36
|
-
'em',
|
|
37
|
-
'embed',
|
|
38
|
-
'fieldset',
|
|
39
|
-
'figcaption',
|
|
40
|
-
'figure',
|
|
41
|
-
'footer',
|
|
42
|
-
'form',
|
|
43
|
-
'h1',
|
|
44
|
-
'h2',
|
|
45
|
-
'h3',
|
|
46
|
-
'h4',
|
|
47
|
-
'h5',
|
|
48
|
-
'h6',
|
|
49
|
-
'head',
|
|
50
|
-
'header',
|
|
51
|
-
'hgroup',
|
|
52
|
-
'hr',
|
|
53
|
-
'html',
|
|
54
|
-
'i',
|
|
55
|
-
'iframe',
|
|
56
|
-
'img',
|
|
57
|
-
'input',
|
|
58
|
-
'ins',
|
|
59
|
-
'kbd',
|
|
60
|
-
'label',
|
|
61
|
-
'legend',
|
|
62
|
-
'li',
|
|
63
|
-
'link',
|
|
64
|
-
'main',
|
|
65
|
-
'map',
|
|
66
|
-
'mark',
|
|
67
|
-
'meta',
|
|
68
|
-
'meter',
|
|
69
|
-
'nav',
|
|
70
|
-
'noscript',
|
|
71
|
-
'object',
|
|
72
|
-
'ol',
|
|
73
|
-
'optgroup',
|
|
74
|
-
'option',
|
|
75
|
-
'output',
|
|
76
|
-
'p',
|
|
77
|
-
'param',
|
|
78
|
-
'picture',
|
|
79
|
-
'pre',
|
|
80
|
-
'progress',
|
|
81
|
-
'q',
|
|
82
|
-
'rp',
|
|
83
|
-
'rt',
|
|
84
|
-
'ruby',
|
|
85
|
-
's',
|
|
86
|
-
'samp',
|
|
87
|
-
'script',
|
|
88
|
-
'section',
|
|
89
|
-
'select',
|
|
90
|
-
'slot',
|
|
91
|
-
'small',
|
|
92
|
-
'source',
|
|
93
|
-
'span',
|
|
94
|
-
'strong',
|
|
95
|
-
'style',
|
|
96
|
-
'sub',
|
|
97
|
-
'summary',
|
|
98
|
-
'sup',
|
|
99
|
-
'svg',
|
|
100
|
-
'table',
|
|
101
|
-
'tbody',
|
|
102
|
-
'td',
|
|
103
|
-
'template',
|
|
104
|
-
'textarea',
|
|
105
|
-
'tfoot',
|
|
106
|
-
'th',
|
|
107
|
-
'thead',
|
|
108
|
-
'time',
|
|
109
|
-
'title',
|
|
110
|
-
'tr',
|
|
111
|
-
'track',
|
|
112
|
-
'u',
|
|
113
|
-
'ul',
|
|
114
|
-
'var',
|
|
115
|
-
'video',
|
|
116
|
-
'wbr',
|
|
117
|
-
];
|
|
118
|
-
/**
|
|
119
|
-
* Checks if a string is an HTML tag name
|
|
120
|
-
* @param key - String to check
|
|
121
|
-
* @returns True if the string is an HTML tag name
|
|
122
|
-
*/
|
|
123
|
-
export function isHtmlTag(key) {
|
|
124
|
-
if (/^\w+[.#:[~+ ]/.test(key)) {
|
|
125
|
-
return htmlTags.includes(key.split(/[.#:[~+ ]/)[0]);
|
|
126
|
-
}
|
|
127
|
-
return htmlTags.includes(key);
|
|
128
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utility for traversing and transforming nested objects
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Type for node visitor functions
|
|
6
|
-
*/
|
|
7
|
-
export type NodeVisitor<T> = (node: any, path: string, root: any, index: number) => T;
|
|
8
|
-
/**
|
|
9
|
-
* Traverses a nested object and applies a visitor function to each node
|
|
10
|
-
* @param node - The object to traverse
|
|
11
|
-
* @param visitor - Function to call for each node
|
|
12
|
-
* @param path - Current path in the object (for tracking)
|
|
13
|
-
* @param root - Root object (for reference)
|
|
14
|
-
* @param index - Current index in array (if applicable)
|
|
15
|
-
* @param separator - Path separator character
|
|
16
|
-
* @returns The result of the visitor function on the current node
|
|
17
|
-
*/
|
|
18
|
-
export declare function traverseObject<T>(node: any, visitor: NodeVisitor<T>, path?: string, root?: any, index?: number, separator?: string): T;
|
|
19
|
-
/**
|
|
20
|
-
* Determines the type of a node in the CSS object
|
|
21
|
-
* @param node - The node to check
|
|
22
|
-
* @param path - Current path in the object
|
|
23
|
-
* @returns The identified node type as a string
|
|
24
|
-
*/
|
|
25
|
-
export declare function determineNodeType(node: any, path?: string): string;
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utility for traversing and transforming nested objects
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Traverses a nested object and applies a visitor function to each node
|
|
6
|
-
* @param node - The object to traverse
|
|
7
|
-
* @param visitor - Function to call for each node
|
|
8
|
-
* @param path - Current path in the object (for tracking)
|
|
9
|
-
* @param root - Root object (for reference)
|
|
10
|
-
* @param index - Current index in array (if applicable)
|
|
11
|
-
* @param separator - Path separator character
|
|
12
|
-
* @returns The result of the visitor function on the current node
|
|
13
|
-
*/
|
|
14
|
-
export function traverseObject(node, visitor, path = '', root, index = -1, separator = '\\') {
|
|
15
|
-
const realRoot = root || node;
|
|
16
|
-
// Handle arrays
|
|
17
|
-
if (Array.isArray(node)) {
|
|
18
|
-
const processedItems = node.map((item, idx) => traverseObject(item, visitor, path, realRoot, idx, separator));
|
|
19
|
-
return visitor(processedItems, path, realRoot, index);
|
|
20
|
-
}
|
|
21
|
-
// Handle objects (but not null)
|
|
22
|
-
if (node !== null && typeof node === 'object') {
|
|
23
|
-
const processedObject = Object.keys(node).reduce((result, key) => {
|
|
24
|
-
const newPath = path ? `${path}${separator}${key}` : key;
|
|
25
|
-
const processedValue = traverseObject(node[key], visitor, newPath, realRoot, index, separator);
|
|
26
|
-
result[key] = processedValue;
|
|
27
|
-
return result;
|
|
28
|
-
}, {});
|
|
29
|
-
return visitor(processedObject, path, realRoot, index);
|
|
30
|
-
}
|
|
31
|
-
// Handle primitive values
|
|
32
|
-
return visitor(node, path, realRoot, index);
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Determines the type of a node in the CSS object
|
|
36
|
-
* @param node - The node to check
|
|
37
|
-
* @param path - Current path in the object
|
|
38
|
-
* @returns The identified node type as a string
|
|
39
|
-
*/
|
|
40
|
-
export function determineNodeType(node, path) {
|
|
41
|
-
if (!path)
|
|
42
|
-
return 'unknown';
|
|
43
|
-
const lastKey = path.split('\\').pop() || '';
|
|
44
|
-
// Layer statement
|
|
45
|
-
if (/^@layer/.test(lastKey) && typeof node === 'string') {
|
|
46
|
-
return 'layer statement';
|
|
47
|
-
}
|
|
48
|
-
// Layer block
|
|
49
|
-
if (/^@layer/.test(lastKey) && typeof node === 'object' && node !== null) {
|
|
50
|
-
return 'layer block';
|
|
51
|
-
}
|
|
52
|
-
// Container query
|
|
53
|
-
if (/^@container/.test(lastKey) &&
|
|
54
|
-
typeof node === 'object' &&
|
|
55
|
-
node !== null) {
|
|
56
|
-
return 'container query block';
|
|
57
|
-
}
|
|
58
|
-
// Media query or prefix
|
|
59
|
-
if (/^@/.test(lastKey)) {
|
|
60
|
-
return 'media query or prefix';
|
|
61
|
-
}
|
|
62
|
-
// CSS property-value pair (end value)
|
|
63
|
-
if (isPrimitiveValue(node)) {
|
|
64
|
-
return 'selector';
|
|
65
|
-
}
|
|
66
|
-
return 'unknown';
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Checks if a value is a primitive that can be used as a CSS property value
|
|
70
|
-
* @param value - Value to check
|
|
71
|
-
* @returns True if the value is a primitive
|
|
72
|
-
*/
|
|
73
|
-
function isPrimitiveValue(value) {
|
|
74
|
-
return (value === null ||
|
|
75
|
-
typeof value === 'string' ||
|
|
76
|
-
typeof value === 'number' ||
|
|
77
|
-
typeof value === 'boolean');
|
|
78
|
-
}
|
package/dist/watch.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { spawn } from 'child_process'
|
|
3
|
-
import path from 'path'
|
|
4
|
-
import process from 'process'
|
|
5
|
-
|
|
6
|
-
const configPath = process.argv[2] || 'esm-styles.config.js'
|
|
7
|
-
const configModule = await import(
|
|
8
|
-
path.isAbsolute(configPath)
|
|
9
|
-
? configPath
|
|
10
|
-
: path.resolve(process.cwd(), configPath)
|
|
11
|
-
)
|
|
12
|
-
const config = configModule.default
|
|
13
|
-
|
|
14
|
-
const basePath = path.resolve(process.cwd(), config.basePath || '.')
|
|
15
|
-
const sourcePath = path.join(basePath, config.sourcePath || '')
|
|
16
|
-
|
|
17
|
-
const buildJsPath = path.resolve(
|
|
18
|
-
path.dirname(new URL(import.meta.url).pathname),
|
|
19
|
-
'build.js'
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
const nodemonArgs = [
|
|
23
|
-
'--watch',
|
|
24
|
-
sourcePath,
|
|
25
|
-
'--ext',
|
|
26
|
-
'mjs',
|
|
27
|
-
'--ignore',
|
|
28
|
-
path.join(sourcePath, '$*.mjs'),
|
|
29
|
-
'--exec',
|
|
30
|
-
`node ${buildJsPath} ${configPath}`,
|
|
31
|
-
]
|
|
32
|
-
|
|
33
|
-
console.log('[esm-styles] Running:', 'nodemon', ...nodemonArgs)
|
|
34
|
-
|
|
35
|
-
const nodemon = spawn('nodemon', nodemonArgs, { stdio: 'inherit' })
|
|
36
|
-
|
|
37
|
-
nodemon.on('exit', (code) => process.exit(code))
|