-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstringifier.ts
More file actions
161 lines (134 loc) · 4.45 KB
/
stringifier.ts
File metadata and controls
161 lines (134 loc) · 4.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import { CSSStylesheet, CSSRule, CSSDeclaration, CSSAtRule, ParserOptions } from './types';
/**
* CSS Stringifier that converts JavaScript objects to CSS strings
*/
export class CSSStringifier {
private options: ParserOptions;
constructor(options: ParserOptions = {}) {
this.options = options;
}
/**
* Stringify a CSS object into a CSS string
* @param stylesheet CSS object to stringify
* @returns CSS string
*/
stringify(stylesheet: CSSStylesheet): string {
if (!stylesheet.rules || stylesheet.rules.length === 0) {
if (!stylesheet.atRules || stylesheet.atRules.length === 0) {
return '';
}
}
const parts: string[] = [];
// Stringify regular rules
if (stylesheet.rules && stylesheet.rules.length > 0) {
const rulesString = stylesheet.rules
.map(rule => this.stringifyRule(rule))
.join(this.options.compress ? '' : '\n\n');
if (rulesString) {
parts.push(rulesString);
}
}
// Stringify at-rules
if (stylesheet.atRules && stylesheet.atRules.length > 0) {
const atRulesString = stylesheet.atRules
.map(atRule => this.stringifyAtRule(atRule))
.join(this.options.compress ? '' : '\n\n');
if (atRulesString) {
parts.push(atRulesString);
}
}
return parts.join(this.options.compress ? '' : '\n\n');
}
/**
* Stringify a CSS @-rule
* @param atRule CSS @-rule object
* @returns CSS @-rule string
*/
private stringifyAtRule(atRule: CSSAtRule): string {
const { name, params } = atRule;
// Simple at-rules like @import
if ((!atRule.rules || atRule.rules.length === 0) &&
(!atRule.declarations || atRule.declarations.length === 0) &&
(!atRule.nestedAtRules || atRule.nestedAtRules.length === 0)) {
return `@${name} ${params};`;
}
// At-rules with declarations like @font-face
if (atRule.declarations && atRule.declarations.length > 0) {
const declarations = this.stringifyDeclarations(atRule.declarations);
if (this.options.compress) {
return `@${name}${params ? ' ' + params : ''}{${declarations}}`;
} else {
return `@${name}${params ? ' ' + params : ''} {\n${declarations}\n}`;
}
}
// Start building the at-rule string
let result = `@${name}${params ? ' ' + params : ''}`;
if (this.options.compress) {
result += '{';
} else {
result += ' {\n';
}
// Add nested rules
if (atRule.rules && atRule.rules.length > 0) {
const nestedRules = atRule.rules
.map(rule => this.stringifyRule(rule))
.join(this.options.compress ? '' : '\n\n');
if (this.options.compress) {
result += nestedRules;
} else {
// Indent nested rules
result += nestedRules.replace(/^/gm, ' ').replace(/^\s\s$/gm, '');
}
}
// Add nested at-rules
if (atRule.nestedAtRules && atRule.nestedAtRules.length > 0) {
const nestedAtRules = atRule.nestedAtRules
.map(rule => this.stringifyAtRule(rule))
.join(this.options.compress ? '' : '\n\n');
if (this.options.compress) {
result += nestedAtRules;
} else {
// Indent nested at-rules
result += nestedAtRules.replace(/^/gm, ' ').replace(/^\s\s$/gm, '');
}
}
if (this.options.compress) {
result += '}';
} else {
result += '\n}';
}
return result;
}
/**
* Stringify a CSS rule
* @param rule CSS rule object
* @returns CSS rule string
*/
private stringifyRule(rule: CSSRule): string {
const declarations = this.stringifyDeclarations(rule.declarations);
if (this.options.compress) {
return `${rule.selector}{${declarations}}`;
} else {
return `${rule.selector} {\n${declarations}\n}`;
}
}
/**
* Stringify CSS declarations
* @param declarations Array of CSS declarations
* @returns CSS declarations string
*/
private stringifyDeclarations(declarations: CSSDeclaration[]): string {
if (!declarations || declarations.length === 0) {
return '';
}
const declarationStrings = declarations.map(declaration => {
const { property, value } = declaration;
if (this.options.compress) {
return `${property}:${value};`;
} else {
return ` ${property}: ${value};`;
}
});
return declarationStrings.join(this.options.compress ? '' : '\n');
}
}