postcss-discard-comments 8.0.2 → 8.0.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "postcss-discard-comments",
3
- "version": "8.0.2",
3
+ "version": "8.0.3",
4
4
  "description": "Discard comments in your CSS files with PostCSS.",
5
5
  "exports": {
6
6
  ".": {
@@ -37,7 +37,7 @@
37
37
  "url": "cssnano/cssnano"
38
38
  },
39
39
  "dependencies": {
40
- "postcss-selector-parser": "^7.1.4"
40
+ "postcss-selector-parser": "^7.1.5"
41
41
  },
42
42
  "bugs": {
43
43
  "url": "https://github.com/cssnano/cssnano/issues"
@@ -46,11 +46,14 @@
46
46
  "node": "^22.11.0 || ^24.11.0 || >=26.0"
47
47
  },
48
48
  "devDependencies": {
49
- "postcss": "^8.5.25",
49
+ "postcss": "^8.5.26",
50
50
  "postcss-scss": "^4.0.9",
51
51
  "postcss-simple-vars": "^7.0.1"
52
52
  },
53
53
  "peerDependencies": {
54
- "postcss": "^8.5.25"
54
+ "postcss": "^8.5.26"
55
+ },
56
+ "scripts": {
57
+ "test": "node --test"
55
58
  }
56
59
  }
package/src/index.js CHANGED
@@ -146,93 +146,102 @@ function pluginCreator(opts = {}) {
146
146
  return result;
147
147
  }
148
148
 
149
- return {
150
- postcssPlugin: 'postcss-discard-comments',
151
- /**
152
- * @param {import('postcss').Root} css
153
- * @param {import('postcss').Helpers} helpers
154
- */
155
- OnceExit(css, { list }) {
156
- css.walk((node) => {
157
- if (node.type === 'comment' && remover.canRemove(node.text)) {
158
- node.remove();
149
+ /**
150
+ * @param {import('postcss').Declaration} node
151
+ * @param {(s: string) => string[]} space
152
+ */
153
+ function processDeclaration(node, space) {
154
+ if (node.raws.value && node.raws.value.raw) {
155
+ if (node.raws.value.value === node.value) {
156
+ node.value = replaceComments(node.raws.value.raw, space);
157
+ } else {
158
+ node.value = replaceComments(node.value, space);
159
+ }
159
160
 
160
- return;
161
- }
161
+ /** @type {null | {value: string, raw: string}} */ (node.raws.value) =
162
+ null;
163
+ }
162
164
 
163
- if (typeof node.raws.between === 'string') {
164
- node.raws.between = replaceComments(node.raws.between, list.space);
165
- }
165
+ if (node.raws.important) {
166
+ node.raws.important = replaceComments(node.raws.important, space);
166
167
 
167
- if (node.type === 'decl') {
168
- if (node.raws.value && node.raws.value.raw) {
169
- if (node.raws.value.value === node.value) {
170
- node.value = replaceComments(node.raws.value.raw, list.space);
171
- } else {
172
- node.value = replaceComments(node.value, list.space);
173
- }
174
-
175
- /** @type {null | {value: string, raw: string}} */ (
176
- node.raws.value
177
- ) = null;
178
- }
168
+ const b = matchesComments(node.raws.important);
179
169
 
180
- if (node.raws.important) {
181
- node.raws.important = replaceComments(
182
- node.raws.important,
183
- list.space
184
- );
170
+ node.raws.important = b.length ? node.raws.important : '!important';
171
+ } else {
172
+ node.value = replaceComments(node.value, space);
173
+ }
174
+ }
185
175
 
186
- const b = matchesComments(node.raws.important);
176
+ /**
177
+ * @param {import('postcss').Rule} node
178
+ * @param {(s: string) => string[]} space
179
+ */
180
+ function processRule(node, space) {
181
+ if (node.raws.selector && node.raws.selector.raw) {
182
+ node.raws.selector.raw = replaceCommentsInSelector(
183
+ node.raws.selector.raw,
184
+ space
185
+ );
186
+ } else if (node.selector && node.selector.includes('/*')) {
187
+ node.selector = replaceCommentsInSelector(node.selector, space);
188
+ }
189
+ }
187
190
 
188
- node.raws.important = b.length ? node.raws.important : '!important';
189
- } else {
190
- node.value = replaceComments(node.value, list.space);
191
- }
191
+ /**
192
+ * @param {import('postcss').AtRule} node
193
+ * @param {(s: string) => string[]} space
194
+ */
195
+ function processAtRule(node, space) {
196
+ if (node.raws.afterName) {
197
+ const commentsReplaced = replaceComments(node.raws.afterName, space);
198
+
199
+ if (!commentsReplaced.length) {
200
+ node.raws.afterName = commentsReplaced + ' ';
201
+ } else {
202
+ node.raws.afterName = ' ' + commentsReplaced + ' ';
203
+ }
204
+ }
192
205
 
193
- return;
194
- }
206
+ if (node.raws.params && node.raws.params.raw) {
207
+ node.raws.params.raw = replaceComments(node.raws.params.raw, space);
208
+ } else if (node.params && node.params.includes('/*')) {
209
+ node.params = replaceComments(node.params, space);
210
+ }
211
+ }
195
212
 
196
- if (node.type === 'rule') {
197
- if (node.raws.selector && node.raws.selector.raw) {
198
- node.raws.selector.raw = replaceCommentsInSelector(
199
- node.raws.selector.raw,
200
- list.space
201
- );
202
- } else if (node.selector && node.selector.includes('/*')) {
203
- node.selector = replaceCommentsInSelector(
204
- node.selector,
205
- list.space
206
- );
207
- }
213
+ /**
214
+ * @param {import('postcss').ChildNode} node
215
+ * @param {(s: string) => string[]} space
216
+ */
217
+ function processNode(node, space) {
218
+ if (node.type === 'comment' && remover.canRemove(node.text)) {
219
+ node.remove();
208
220
 
209
- return;
210
- }
221
+ return;
222
+ }
211
223
 
212
- if (node.type === 'atrule') {
213
- if (node.raws.afterName) {
214
- const commentsReplaced = replaceComments(
215
- node.raws.afterName,
216
- list.space
217
- );
218
-
219
- if (!commentsReplaced.length) {
220
- node.raws.afterName = commentsReplaced + ' ';
221
- } else {
222
- node.raws.afterName = ' ' + commentsReplaced + ' ';
223
- }
224
- }
224
+ if (typeof node.raws.between === 'string') {
225
+ node.raws.between = replaceComments(node.raws.between, space);
226
+ }
225
227
 
226
- if (node.raws.params && node.raws.params.raw) {
227
- node.raws.params.raw = replaceComments(
228
- node.raws.params.raw,
229
- list.space
230
- );
231
- } else if (node.params && node.params.includes('/*')) {
232
- node.params = replaceComments(node.params, list.space);
233
- }
234
- }
235
- });
228
+ if (node.type === 'decl') {
229
+ processDeclaration(node, space);
230
+ } else if (node.type === 'rule') {
231
+ processRule(node, space);
232
+ } else if (node.type === 'atrule') {
233
+ processAtRule(node, space);
234
+ }
235
+ }
236
+
237
+ return {
238
+ postcssPlugin: 'postcss-discard-comments',
239
+ /**
240
+ * @param {import('postcss').Root} css
241
+ * @param {import('postcss').Helpers} helpers
242
+ */
243
+ OnceExit(css, { list }) {
244
+ css.walk((node) => processNode(node, list.space));
236
245
  },
237
246
  };
238
247
  }
@@ -8,6 +8,85 @@ const STATES = {
8
8
  IN_COMMENT: 3,
9
9
  };
10
10
 
11
+ /**
12
+ * @typedef {object} ParserContext
13
+ * @property {string} input
14
+ * @property {[number, number, number][]} tokens
15
+ * @property {number} length
16
+ * @property {number} pos
17
+ * @property {number} state
18
+ * @property {number} tokenStart
19
+ * @property {number} commentStart
20
+ */
21
+
22
+ /**
23
+ * @param {ParserContext} context
24
+ * @param {string} nextChar
25
+ * @return {boolean}
26
+ */
27
+ function handleNormalState(context, nextChar) {
28
+ const { input, pos } = context;
29
+ const char = input[pos];
30
+
31
+ if (char === '/' && nextChar === '*') {
32
+ if (pos > context.tokenStart) {
33
+ context.tokens.push([0, context.tokenStart, pos]);
34
+ }
35
+ context.commentStart = pos;
36
+ context.state = STATES.IN_COMMENT;
37
+ context.pos += 2;
38
+ return true;
39
+ }
40
+
41
+ if (char === '"') {
42
+ context.state = STATES.IN_DOUBLE_QUOTE;
43
+ } else if (char === "'") {
44
+ context.state = STATES.IN_SINGLE_QUOTE;
45
+ }
46
+
47
+ return false;
48
+ }
49
+
50
+ /**
51
+ * @param {ParserContext} context
52
+ * @param {string} nextChar
53
+ * @param {string} quote
54
+ * @return {boolean}
55
+ */
56
+ function handleQuoteState(context, nextChar, quote) {
57
+ const char = context.input[context.pos];
58
+
59
+ if (char === '\\' && nextChar) {
60
+ context.pos += 2;
61
+ return true;
62
+ }
63
+
64
+ if (char === quote) {
65
+ context.state = STATES.NORMAL;
66
+ }
67
+
68
+ return false;
69
+ }
70
+
71
+ /**
72
+ * @param {ParserContext} context
73
+ * @param {string} nextChar
74
+ * @return {boolean}
75
+ */
76
+ function handleCommentState(context, nextChar) {
77
+ const { input, pos } = context;
78
+
79
+ if (input[pos] === '*' && nextChar === '/') {
80
+ context.tokens.push([1, context.commentStart + 2, pos]);
81
+ context.tokenStart = pos + 2;
82
+ context.state = STATES.NORMAL;
83
+ context.pos += 2;
84
+ return true;
85
+ }
86
+
87
+ return false;
88
+ }
89
+
11
90
  /**
12
91
  * CSS Comment Parser with context awareness
13
92
  * Properly handles comments inside strings, URLs, and escaped characters
@@ -16,80 +95,55 @@ const STATES = {
16
95
  * @return {[number, number, number][]}
17
96
  */
18
97
  module.exports = function commentParser(input) {
19
- /** @type {[number, number, number][]} */
20
- const tokens = [];
21
- const length = input.length;
22
- let pos = 0;
98
+ /** @type {ParserContext} */
99
+ const context = {
100
+ input,
101
+ tokens: [],
102
+ length: input.length,
103
+ pos: 0,
104
+ state: STATES.NORMAL,
105
+ tokenStart: 0,
106
+ commentStart: 0,
107
+ };
23
108
 
24
- let state = STATES.NORMAL;
25
- let tokenStart = 0;
26
- let commentStart = 0;
109
+ while (context.pos < context.length) {
110
+ const nextChar =
111
+ context.pos + 1 < context.length ? context.input[context.pos + 1] : '';
112
+ let handled;
27
113
 
28
- while (pos < length) {
29
- const char = input[pos];
30
- const nextChar = pos + 1 < length ? input[pos + 1] : '';
31
-
32
- switch (state) {
114
+ switch (context.state) {
33
115
  case STATES.NORMAL:
34
- if (char === '/' && nextChar === '*') {
35
- // Found comment start - add non-comment token if needed
36
- if (pos > tokenStart) {
37
- tokens.push([0, tokenStart, pos]);
38
- }
39
- commentStart = pos;
40
- state = STATES.IN_COMMENT;
41
- pos += 2; // Skip /*
42
- continue;
43
- } else if (char === '"') {
44
- state = STATES.IN_DOUBLE_QUOTE;
45
- } else if (char === "'") {
46
- state = STATES.IN_SINGLE_QUOTE;
47
- }
116
+ handled = handleNormalState(context, nextChar);
48
117
  break;
49
118
 
50
119
  case STATES.IN_SINGLE_QUOTE:
51
- if (char === '\\' && nextChar) {
52
- // Skip escaped character
53
- pos += 2;
54
- continue;
55
- } else if (char === "'") {
56
- state = STATES.NORMAL;
57
- }
120
+ handled = handleQuoteState(context, nextChar, "'");
58
121
  break;
59
122
 
60
123
  case STATES.IN_DOUBLE_QUOTE:
61
- if (char === '\\' && nextChar) {
62
- // Skip escaped character
63
- pos += 2;
64
- continue;
65
- } else if (char === '"') {
66
- state = STATES.NORMAL;
67
- }
124
+ handled = handleQuoteState(context, nextChar, '"');
68
125
  break;
69
126
 
70
127
  case STATES.IN_COMMENT:
71
- if (char === '*' && nextChar === '/') {
72
- // Found comment end
73
- tokens.push([1, commentStart + 2, pos]);
74
- tokenStart = pos + 2;
75
- state = STATES.NORMAL;
76
- pos += 2; // Skip */
77
- continue;
78
- }
128
+ handled = handleCommentState(context, nextChar);
79
129
  break;
80
130
  }
81
131
 
82
- pos++;
132
+ if (handled) {
133
+ continue;
134
+ }
135
+
136
+ context.pos++;
83
137
  }
84
138
 
85
139
  // Handle remaining content
86
- if (state === STATES.IN_COMMENT) {
140
+ if (context.state === STATES.IN_COMMENT) {
87
141
  // Unclosed comment - treat as comment to end
88
- tokens.push([1, commentStart + 2, length]);
89
- } else if (tokenStart < length) {
142
+ context.tokens.push([1, context.commentStart + 2, context.length]);
143
+ } else if (context.tokenStart < context.length) {
90
144
  // Add final non-comment token
91
- tokens.push([0, tokenStart, length]);
145
+ context.tokens.push([0, context.tokenStart, context.length]);
92
146
  }
93
147
 
94
- return tokens;
148
+ return context.tokens;
95
149
  };
@@ -28,6 +28,7 @@ class CommentRemover {
28
28
  return false;
29
29
  }
30
30
  }
31
+ return false;
31
32
  }
32
33
  }
33
34
 
@@ -7,4 +7,13 @@ export = commentParser;
7
7
  * @return {[number, number, number][]}
8
8
  */
9
9
  declare function commentParser(input: string): [number, number, number][];
10
+ export type ParserContext = {
11
+ input: string;
12
+ tokens: [number, number, number][];
13
+ length: number;
14
+ pos: number;
15
+ state: number;
16
+ tokenStart: number;
17
+ commentStart: number;
18
+ };
10
19
  //# sourceMappingURL=commentParser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"commentParser.d.ts","sourceRoot":"","sources":["../../src/lib/commentParser.js"],"names":[],"mappings":";AAUA;;;;;;GAMG;+BACqC,KAAK,EAHlC,MAGkC,GAFjC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE"}
1
+ {"version":3,"file":"commentParser.d.ts","sourceRoot":"","sources":["../../src/lib/commentParser.js"],"names":[],"mappings":";AAyFA;;;;;;GAMG;+BACqC,KAAK,EAHlC,MAGkC,GAFjC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE;AAnFnC,YAAkB,aAAa,GAC/B;IAAmB,KAAK,EAAb,MAAM,CACjB;IAAuC,MAAM,EAAlC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CACrC;IAAmB,MAAM,EAAd,MAAM,CACjB;IAAmB,GAAG,EAAX,MAAM,CACjB;IAAmB,KAAK,EAAb,MAAM,CACjB;IAAmB,UAAU,EAAlB,MAAM,CACjB;IAAmB,YAAY,EAApB,MAAM,CACnB;CAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"commentRemover.d.ts","sourceRoot":"","sources":["../../src/lib/commentRemover.js"],"names":[],"mappings":"SAiCiB,cAAc;AA/B/B,cAAM,cAAc;IAGX,OAAO;IAqBH,SAAS;IAvBpB,qDAAqD;IACrD,YAAY,OAAO,EADP,OAAO,aAAa,EAAE,OACf,EAElB;IACD;;;OAGG;IACH,SAAS,CAAC,OAAO,EAHN,MAGM,GAFL,OAAO,GAAG,SAAS,CAqB9B;CACF"}
1
+ {"version":3,"file":"commentRemover.d.ts","sourceRoot":"","sources":["../../src/lib/commentRemover.js"],"names":[],"mappings":"SAkCiB,cAAc;AAhC/B,cAAM,cAAc;IAGX,OAAO;IAqBH,SAAS;IAvBpB,qDAAqD;IACrD,YAAY,OAAO,EADP,OAAO,aAAa,EAAE,OACf,EAElB;IACD;;;OAGG;IACH,SAAS,CAAC,OAAO,EAHN,MAGM,GAFL,OAAO,GAAG,SAAS,CAsB9B;CACF"}