postcss 8.5.27 → 8.5.29
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/lib/declaration.d.ts +1 -1
- package/lib/list.js +19 -1
- package/lib/map-generator.js +9 -3
- package/lib/parser.js +6 -1
- package/lib/processor.js +1 -1
- package/lib/stringifier.js +16 -28
- package/lib/stringify.js +60 -2
- package/package.json +3 -3
package/lib/declaration.d.ts
CHANGED
package/lib/list.js
CHANGED
|
@@ -20,8 +20,21 @@ let list = {
|
|
|
20
20
|
let inQuote = false
|
|
21
21
|
let prevQuote = ''
|
|
22
22
|
let escape = false
|
|
23
|
+
let inComment = false
|
|
24
|
+
|
|
25
|
+
for (let i = 0; i < string.length; i++) {
|
|
26
|
+
let letter = string[i]
|
|
27
|
+
|
|
28
|
+
if (inComment) {
|
|
29
|
+
current += letter
|
|
30
|
+
if (letter === '*' && string[i + 1] === '/') {
|
|
31
|
+
current += '/'
|
|
32
|
+
i += 1
|
|
33
|
+
inComment = false
|
|
34
|
+
}
|
|
35
|
+
continue
|
|
36
|
+
}
|
|
23
37
|
|
|
24
|
-
for (let letter of string) {
|
|
25
38
|
if (escape) {
|
|
26
39
|
escape = false
|
|
27
40
|
} else if (letter === '\\') {
|
|
@@ -33,6 +46,11 @@ let list = {
|
|
|
33
46
|
} else if (letter === '"' || letter === "'") {
|
|
34
47
|
inQuote = true
|
|
35
48
|
prevQuote = letter
|
|
49
|
+
} else if (letter === '/' && string[i + 1] === '*') {
|
|
50
|
+
current += '/*'
|
|
51
|
+
i += 1
|
|
52
|
+
inComment = true
|
|
53
|
+
continue
|
|
36
54
|
} else if (letter === '(') {
|
|
37
55
|
func += 1
|
|
38
56
|
} else if (letter === ')') {
|
package/lib/map-generator.js
CHANGED
|
@@ -75,16 +75,22 @@ class MapGenerator {
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
} else if (this.css) {
|
|
78
|
+
// Single forward pass. Removing every annotation from the whole
|
|
79
|
+
// string separately would be O(n^2) on many annotations.
|
|
78
80
|
let annotation = '/*# sourceMappingURL='
|
|
81
|
+
let css = ''
|
|
82
|
+
let cursor = 0
|
|
79
83
|
let startIndex
|
|
80
|
-
while ((startIndex = this.css.
|
|
84
|
+
while ((startIndex = this.css.indexOf(annotation, cursor)) !== -1) {
|
|
81
85
|
let endIndex = this.css.indexOf('*/', startIndex + annotation.length)
|
|
82
86
|
if (endIndex === -1) break
|
|
83
|
-
while (startIndex >
|
|
87
|
+
while (startIndex > cursor && this.css[startIndex - 1] === '\n') {
|
|
84
88
|
startIndex--
|
|
85
89
|
}
|
|
86
|
-
|
|
90
|
+
css += this.css.slice(cursor, startIndex)
|
|
91
|
+
cursor = endIndex + 2
|
|
87
92
|
}
|
|
93
|
+
if (cursor > 0) this.css = css + this.css.slice(cursor)
|
|
88
94
|
}
|
|
89
95
|
}
|
|
90
96
|
|
package/lib/parser.js
CHANGED
|
@@ -494,6 +494,9 @@ class Parser {
|
|
|
494
494
|
let token, type
|
|
495
495
|
let length = tokens.length
|
|
496
496
|
let value = ''
|
|
497
|
+
// Last character of `value`. Reading it from `value` would flatten
|
|
498
|
+
// the string concatenation on every comment and make parsing O(n^2).
|
|
499
|
+
let last = ''
|
|
497
500
|
let clean = true
|
|
498
501
|
let next, prev
|
|
499
502
|
|
|
@@ -506,16 +509,18 @@ class Parser {
|
|
|
506
509
|
prev = tokens[i - 1] ? tokens[i - 1][0] : 'empty'
|
|
507
510
|
next = tokens[i + 1] ? tokens[i + 1][0] : 'empty'
|
|
508
511
|
if (!SAFE_COMMENT_NEIGHBOR[prev] && !SAFE_COMMENT_NEIGHBOR[next]) {
|
|
509
|
-
if (
|
|
512
|
+
if (last === ',') {
|
|
510
513
|
clean = false
|
|
511
514
|
} else {
|
|
512
515
|
value += token[1]
|
|
516
|
+
last = token[1].slice(-1)
|
|
513
517
|
}
|
|
514
518
|
} else {
|
|
515
519
|
clean = false
|
|
516
520
|
}
|
|
517
521
|
} else {
|
|
518
522
|
value += token[1]
|
|
523
|
+
last = token[1].slice(-1)
|
|
519
524
|
}
|
|
520
525
|
}
|
|
521
526
|
if (!clean) {
|
package/lib/processor.js
CHANGED
package/lib/stringifier.js
CHANGED
|
@@ -1,21 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
// Escapes sequences that could break out of an HTML <style> context.
|
|
4
|
-
// Uses CSS unicode escaping (\3c = '<') which is valid CSS and parsed
|
|
5
|
-
// correctly by all compliant CSS consumers.
|
|
6
|
-
const STYLE_TAG = /(<)(\/?style\b)/gi
|
|
7
|
-
const COMMENT_OPEN = /(<)(!--)/g
|
|
8
|
-
|
|
9
3
|
// Characters that end an at-rule name, mirroring RE_AT_END in the tokenizer.
|
|
10
4
|
// Params starting with anything else need a space to stay separate tokens.
|
|
11
5
|
const AT_NAME_END = /[\t\n\f\r "#'()/;[\\\]{}]/
|
|
12
6
|
|
|
13
|
-
function escapeHTMLInCSS(str) {
|
|
14
|
-
if (typeof str !== 'string') return str
|
|
15
|
-
if (!str.includes('<')) return str
|
|
16
|
-
return str.replace(STYLE_TAG, '\\3c $2').replace(COMMENT_OPEN, '\\3c $2')
|
|
17
|
-
}
|
|
18
|
-
|
|
19
7
|
const DEFAULT_RAW = {
|
|
20
8
|
after: '\n',
|
|
21
9
|
beforeClose: '\n',
|
|
@@ -50,11 +38,12 @@ function atruleStart(str, node) {
|
|
|
50
38
|
}
|
|
51
39
|
|
|
52
40
|
// `*--x` is not a custom property: the parser checks the first token, and the
|
|
53
|
-
// `*`/`_` hack prefix moves from `prop` into `before` only after that.
|
|
41
|
+
// `*`/`_` hack prefix moves from `prop` into `before` only after that. A free
|
|
42
|
+
// semicolon in front of the declaration also ends up in `before`.
|
|
54
43
|
function isCustomProperty(node) {
|
|
55
44
|
if (!node.prop.startsWith('--')) return false
|
|
56
45
|
let before = node.raws.before
|
|
57
|
-
return typeof before === 'undefined' ||
|
|
46
|
+
return typeof before === 'undefined' || !/[^\s;]$/.test(before)
|
|
58
47
|
}
|
|
59
48
|
|
|
60
49
|
function pushBody(str, stack, node) {
|
|
@@ -92,17 +81,17 @@ function pushBody(str, stack, node) {
|
|
|
92
81
|
|
|
93
82
|
function pushBlock(str, stack, node, start) {
|
|
94
83
|
let between = str.raw(node, 'between', 'beforeOpen')
|
|
95
|
-
str.builder(
|
|
84
|
+
str.builder(start + between + '{', node, 'start')
|
|
96
85
|
|
|
97
86
|
let hasNodes = node.nodes && node.nodes.length
|
|
98
87
|
let close = () => {
|
|
99
88
|
let after = hasNodes
|
|
100
89
|
? str.raw(node, 'after')
|
|
101
90
|
: str.raw(node, 'after', 'emptyBody')
|
|
102
|
-
if (after) str.builder(
|
|
91
|
+
if (after) str.builder(after)
|
|
103
92
|
str.builder('}', node, 'end')
|
|
104
93
|
if (node.type === 'rule' && node.raws.ownSemicolon) {
|
|
105
|
-
str.builder(
|
|
94
|
+
str.builder(node.raws.ownSemicolon, node, 'end')
|
|
106
95
|
}
|
|
107
96
|
}
|
|
108
97
|
|
|
@@ -125,7 +114,7 @@ class Stringifier {
|
|
|
125
114
|
this.block(node, start)
|
|
126
115
|
} else {
|
|
127
116
|
let end = (node.raws.between || '') + (semicolon ? ';' : '')
|
|
128
|
-
this.builder(
|
|
117
|
+
this.builder(start + end, node)
|
|
129
118
|
}
|
|
130
119
|
}
|
|
131
120
|
|
|
@@ -160,7 +149,7 @@ class Stringifier {
|
|
|
160
149
|
|
|
161
150
|
block(node, start) {
|
|
162
151
|
let between = this.raw(node, 'between', 'beforeOpen')
|
|
163
|
-
this.builder(
|
|
152
|
+
this.builder(start + between + '{', node, 'start')
|
|
164
153
|
|
|
165
154
|
let after
|
|
166
155
|
if (node.nodes && node.nodes.length) {
|
|
@@ -170,7 +159,7 @@ class Stringifier {
|
|
|
170
159
|
after = this.raw(node, 'after', 'emptyBody')
|
|
171
160
|
}
|
|
172
161
|
|
|
173
|
-
if (after) this.builder(
|
|
162
|
+
if (after) this.builder(after)
|
|
174
163
|
this.builder('}', node, 'end')
|
|
175
164
|
}
|
|
176
165
|
|
|
@@ -197,7 +186,7 @@ class Stringifier {
|
|
|
197
186
|
let child = entry.node
|
|
198
187
|
let before = this.raw(child, 'before')
|
|
199
188
|
if (before) {
|
|
200
|
-
this.builder(
|
|
189
|
+
this.builder(before)
|
|
201
190
|
}
|
|
202
191
|
|
|
203
192
|
if (expandable && child.type === 'rule') {
|
|
@@ -213,7 +202,7 @@ class Stringifier {
|
|
|
213
202
|
comment(node) {
|
|
214
203
|
let left = this.raw(node, 'left', 'commentLeft')
|
|
215
204
|
let right = this.raw(node, 'right', 'commentRight')
|
|
216
|
-
this.builder(
|
|
205
|
+
this.builder('/*' + left + node.text + right + '*/', node)
|
|
217
206
|
}
|
|
218
207
|
|
|
219
208
|
decl(node, semicolon) {
|
|
@@ -227,7 +216,7 @@ class Stringifier {
|
|
|
227
216
|
}
|
|
228
217
|
|
|
229
218
|
if (semicolon) string += ';'
|
|
230
|
-
this.builder(
|
|
219
|
+
this.builder(string, node)
|
|
231
220
|
}
|
|
232
221
|
|
|
233
222
|
document(node) {
|
|
@@ -432,21 +421,20 @@ class Stringifier {
|
|
|
432
421
|
}
|
|
433
422
|
|
|
434
423
|
root(node) {
|
|
435
|
-
|
|
424
|
+
let inDocument = node.parent && node.parent.type === 'document'
|
|
425
|
+
if (!inDocument && node.source && node.source.input.hasBOM) {
|
|
436
426
|
this.builder('\uFEFF', node, 'start')
|
|
437
427
|
}
|
|
438
428
|
this.body(node)
|
|
439
429
|
if (node.raws.after) {
|
|
440
|
-
|
|
441
|
-
let isDocument = node.parent && node.parent.type === 'document'
|
|
442
|
-
this.builder(isDocument ? after : escapeHTMLInCSS(after))
|
|
430
|
+
this.builder(node.raws.after)
|
|
443
431
|
}
|
|
444
432
|
}
|
|
445
433
|
|
|
446
434
|
rule(node) {
|
|
447
435
|
this.block(node, this.rawValue(node, 'selector'))
|
|
448
436
|
if (node.raws.ownSemicolon) {
|
|
449
|
-
this.builder(
|
|
437
|
+
this.builder(node.raws.ownSemicolon, node, 'end')
|
|
450
438
|
}
|
|
451
439
|
}
|
|
452
440
|
|
package/lib/stringify.js
CHANGED
|
@@ -2,9 +2,67 @@
|
|
|
2
2
|
|
|
3
3
|
let Stringifier = require('./stringifier')
|
|
4
4
|
|
|
5
|
+
const STYLE_TAG = /(<)(\/?style\b)/gi
|
|
6
|
+
const COMMENT_OPEN = /(<)(!--)/g
|
|
7
|
+
|
|
8
|
+
function escapeHTMLInCSS(str) {
|
|
9
|
+
if (!str.includes('<')) return str
|
|
10
|
+
return str.replace(STYLE_TAG, '\\3c $2').replace(COMMENT_OPEN, '\\3c $2')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
class SafeStringifier extends Stringifier {
|
|
14
|
+
escapeHTML(node, print) {
|
|
15
|
+
let builder = this.builder
|
|
16
|
+
let chunks, css
|
|
17
|
+
this.builder = (str, child, type) => {
|
|
18
|
+
if (chunks) {
|
|
19
|
+
css += str
|
|
20
|
+
chunks.push(str, child, type)
|
|
21
|
+
} else if (str.includes('<')) {
|
|
22
|
+
// Dangerous sequences start with `<`, so everything before
|
|
23
|
+
// the first `<` is safe to pass through. The rest is buffered
|
|
24
|
+
// to escape it as a whole.
|
|
25
|
+
css = str
|
|
26
|
+
chunks = [str, child, type]
|
|
27
|
+
} else {
|
|
28
|
+
builder(str, child, type)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
print()
|
|
32
|
+
this.builder = builder
|
|
33
|
+
if (!chunks) return
|
|
34
|
+
|
|
35
|
+
let escaped = escapeHTMLInCSS(css)
|
|
36
|
+
if (escaped === css) {
|
|
37
|
+
// Keep the chunks to get a precise source map
|
|
38
|
+
for (let i = 0; i < chunks.length; i += 3) {
|
|
39
|
+
builder(chunks[i], chunks[i + 1], chunks[i + 2])
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
// Escaping happens only on a hack attempt, source map is not important
|
|
43
|
+
builder(escaped, node)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
root(node) {
|
|
48
|
+
if (node.parent && node.parent.type === 'document') {
|
|
49
|
+
// Document raws around the Root hold markup and are kept as is since CSS in Document can be marked with <style>
|
|
50
|
+
this.escapeHTML(node, () => this.body(node))
|
|
51
|
+
if (node.raws.after) this.builder(node.raws.after)
|
|
52
|
+
} else {
|
|
53
|
+
this.escapeHTML(node, () => super.root(node))
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
5
58
|
function stringify(node, builder) {
|
|
6
|
-
let str = new
|
|
7
|
-
|
|
59
|
+
let str = new SafeStringifier(builder)
|
|
60
|
+
// Root escapes its own output and keeps markup in Document raws
|
|
61
|
+
if (node.type === 'root' || node.type === 'document') {
|
|
62
|
+
str.stringify(node)
|
|
63
|
+
} else {
|
|
64
|
+
str.escapeHTML(node, () => str.stringify(node))
|
|
65
|
+
}
|
|
8
66
|
}
|
|
9
67
|
|
|
10
68
|
module.exports = stringify
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "postcss",
|
|
3
|
-
"version": "8.5.
|
|
3
|
+
"version": "8.5.29",
|
|
4
4
|
"description": "Tool for transforming styles with JS plugins",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"css",
|
|
@@ -78,9 +78,9 @@
|
|
|
78
78
|
"./package.json": "./package.json"
|
|
79
79
|
},
|
|
80
80
|
"dependencies": {
|
|
81
|
-
"nanoid": "^3.3.
|
|
81
|
+
"nanoid": "^3.3.19",
|
|
82
82
|
"picocolors": "^1.1.1",
|
|
83
|
-
"source-map-js": "^1.2.
|
|
83
|
+
"source-map-js": "^1.2.2"
|
|
84
84
|
},
|
|
85
85
|
"engines": {
|
|
86
86
|
"node": "^10 || ^12 || >=14"
|