@depup/postcss 8.5.9-depup.0 → 8.5.22-depup.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/README.md +3 -3
- package/changes.json +3 -3
- package/lib/container.js +81 -34
- package/lib/fromJSON.js +76 -23
- package/lib/input.js +13 -4
- package/lib/lazy-result.js +68 -13
- package/lib/node.d.ts +2 -2
- package/lib/node.js +105 -60
- package/lib/parser.js +36 -29
- package/lib/postcss.d.ts +9 -1
- package/lib/previous-map.js +30 -5
- package/lib/processor.js +1 -1
- package/lib/root.js +16 -1
- package/lib/stringifier.js +137 -32
- package/lib/tokenize.js +4 -0
- package/lib/warning.js +10 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -13,8 +13,8 @@ npm install @depup/postcss
|
|
|
13
13
|
|
|
14
14
|
| Field | Value |
|
|
15
15
|
|-------|-------|
|
|
16
|
-
| Original | [postcss](https://www.npmjs.com/package/postcss) @ 8.5.
|
|
17
|
-
| Processed | 2026-
|
|
16
|
+
| Original | [postcss](https://www.npmjs.com/package/postcss) @ 8.5.22 |
|
|
17
|
+
| Processed | 2026-07-22 |
|
|
18
18
|
| Smoke test | passed |
|
|
19
19
|
| Deps updated | 1 |
|
|
20
20
|
|
|
@@ -22,7 +22,7 @@ npm install @depup/postcss
|
|
|
22
22
|
|
|
23
23
|
| Dependency | From | To |
|
|
24
24
|
|------------|------|-----|
|
|
25
|
-
| nanoid | ^3.3.
|
|
25
|
+
| nanoid | ^3.3.16 | ^6.0.0 |
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
package/changes.json
CHANGED
package/lib/container.js
CHANGED
|
@@ -8,18 +8,25 @@ let { isClean, my } = require('./symbols')
|
|
|
8
8
|
let AtRule, parse, Root, Rule
|
|
9
9
|
|
|
10
10
|
function cleanSource(nodes) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
let stack = nodes.slice()
|
|
12
|
+
while (stack.length > 0) {
|
|
13
|
+
let node = stack.pop()
|
|
14
|
+
delete node.source
|
|
15
|
+
if (node.nodes) {
|
|
16
|
+
node.nodes = node.nodes.slice()
|
|
17
|
+
for (let i of node.nodes) stack.push(i)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return nodes.slice()
|
|
16
21
|
}
|
|
17
22
|
|
|
18
23
|
function markTreeDirty(node) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
let stack = [node]
|
|
25
|
+
while (stack.length > 0) {
|
|
26
|
+
let next = stack.pop()
|
|
27
|
+
next[isClean] = false
|
|
28
|
+
if (next.proxyOf.nodes) {
|
|
29
|
+
for (let i of next.proxyOf.nodes) stack.push(i)
|
|
23
30
|
}
|
|
24
31
|
}
|
|
25
32
|
}
|
|
@@ -47,9 +54,18 @@ class Container extends Node {
|
|
|
47
54
|
}
|
|
48
55
|
|
|
49
56
|
cleanRaws(keepBetween) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
57
|
+
let stack = [this]
|
|
58
|
+
while (stack.length > 0) {
|
|
59
|
+
let node = stack.pop()
|
|
60
|
+
if (node !== this && node.cleanRaws !== Container.prototype.cleanRaws) {
|
|
61
|
+
// Subclass with own logic; let it handle its subtree
|
|
62
|
+
node.cleanRaws(keepBetween)
|
|
63
|
+
continue
|
|
64
|
+
}
|
|
65
|
+
Node.prototype.cleanRaws.call(node, keepBetween)
|
|
66
|
+
if (node.nodes) {
|
|
67
|
+
for (let child of node.nodes) stack.push(child)
|
|
68
|
+
}
|
|
53
69
|
}
|
|
54
70
|
}
|
|
55
71
|
|
|
@@ -309,19 +325,48 @@ class Container extends Node {
|
|
|
309
325
|
}
|
|
310
326
|
|
|
311
327
|
walk(callback) {
|
|
312
|
-
|
|
328
|
+
if (!this.proxyOf.nodes) return undefined
|
|
329
|
+
|
|
330
|
+
// An explicit stack instead of recursive `each()` calls to survive
|
|
331
|
+
// deeply nested trees. Each frame keeps a live `indexes` slot, so
|
|
332
|
+
// insertion and removal during the walk behave like `each()`: the
|
|
333
|
+
// slot stays at the current child until its subtree is finished.
|
|
334
|
+
let stack = [{ iterator: this.getIterator(), node: this.proxyOf }]
|
|
335
|
+
|
|
336
|
+
while (stack.length > 0) {
|
|
337
|
+
let { iterator, node } = stack[stack.length - 1]
|
|
338
|
+
let index = node.indexes[iterator]
|
|
339
|
+
|
|
340
|
+
if (index >= node.proxyOf.nodes.length) {
|
|
341
|
+
delete node.indexes[iterator]
|
|
342
|
+
stack.pop()
|
|
343
|
+
let parent = stack[stack.length - 1]
|
|
344
|
+
// Finish the parent’s step for the child subtree we just left
|
|
345
|
+
if (parent) parent.node.indexes[parent.iterator] += 1
|
|
346
|
+
continue
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
let child = node.proxyOf.nodes[index]
|
|
313
350
|
let result
|
|
314
351
|
try {
|
|
315
|
-
result = callback(child,
|
|
352
|
+
result = callback(child, index)
|
|
316
353
|
} catch (e) {
|
|
317
354
|
throw child.addToError(e)
|
|
318
355
|
}
|
|
319
|
-
if (result
|
|
320
|
-
|
|
356
|
+
if (result === false) {
|
|
357
|
+
for (let opened of stack) {
|
|
358
|
+
delete opened.node.indexes[opened.iterator]
|
|
359
|
+
}
|
|
360
|
+
return false
|
|
361
|
+
}
|
|
362
|
+
if (child.walk && child.proxyOf.nodes) {
|
|
363
|
+
stack.push({ iterator: child.getIterator(), node: child })
|
|
364
|
+
} else {
|
|
365
|
+
node.indexes[iterator] += 1
|
|
321
366
|
}
|
|
367
|
+
}
|
|
322
368
|
|
|
323
|
-
|
|
324
|
-
})
|
|
369
|
+
return undefined
|
|
325
370
|
}
|
|
326
371
|
|
|
327
372
|
walkAtRules(name, callback) {
|
|
@@ -424,24 +469,26 @@ Container.default = Container
|
|
|
424
469
|
|
|
425
470
|
/* c8 ignore start */
|
|
426
471
|
Container.rebuild = node => {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
472
|
+
let stack = [node]
|
|
473
|
+
while (stack.length > 0) {
|
|
474
|
+
let next = stack.pop()
|
|
475
|
+
if (next.type === 'atrule') {
|
|
476
|
+
Object.setPrototypeOf(next, AtRule.prototype)
|
|
477
|
+
} else if (next.type === 'rule') {
|
|
478
|
+
Object.setPrototypeOf(next, Rule.prototype)
|
|
479
|
+
} else if (next.type === 'decl') {
|
|
480
|
+
Object.setPrototypeOf(next, Declaration.prototype)
|
|
481
|
+
} else if (next.type === 'comment') {
|
|
482
|
+
Object.setPrototypeOf(next, Comment.prototype)
|
|
483
|
+
} else if (next.type === 'root') {
|
|
484
|
+
Object.setPrototypeOf(next, Root.prototype)
|
|
485
|
+
}
|
|
438
486
|
|
|
439
|
-
|
|
487
|
+
next[my] = true
|
|
440
488
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
})
|
|
489
|
+
if (next.nodes) {
|
|
490
|
+
for (let child of next.nodes) stack.push(child)
|
|
491
|
+
}
|
|
445
492
|
}
|
|
446
493
|
}
|
|
447
494
|
/* c8 ignore stop */
|
package/lib/fromJSON.js
CHANGED
|
@@ -8,26 +8,24 @@ let PreviousMap = require('./previous-map')
|
|
|
8
8
|
let Root = require('./root')
|
|
9
9
|
let Rule = require('./rule')
|
|
10
10
|
|
|
11
|
-
function
|
|
12
|
-
if (
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (inputHydrated.map) {
|
|
20
|
-
inputHydrated.map = {
|
|
21
|
-
...inputHydrated.map,
|
|
22
|
-
__proto__: PreviousMap.prototype
|
|
23
|
-
}
|
|
11
|
+
function hydrateInputs(json, inputs) {
|
|
12
|
+
if (!json.inputs) return inputs
|
|
13
|
+
return json.inputs.map(input => {
|
|
14
|
+
let inputHydrated = { ...input, __proto__: Input.prototype }
|
|
15
|
+
if (inputHydrated.map) {
|
|
16
|
+
inputHydrated.map = {
|
|
17
|
+
...inputHydrated.map,
|
|
18
|
+
__proto__: PreviousMap.prototype
|
|
24
19
|
}
|
|
25
|
-
inputs.push(inputHydrated)
|
|
26
20
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
return inputHydrated
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function constructNode(json, inputs, children) {
|
|
26
|
+
let defaults = { ...json }
|
|
27
|
+
delete defaults.inputs
|
|
28
|
+
delete defaults.nodes
|
|
31
29
|
if (defaults.source) {
|
|
32
30
|
let { inputId, ...source } = defaults.source
|
|
33
31
|
defaults.source = source
|
|
@@ -35,19 +33,74 @@ function fromJSON(json, inputs) {
|
|
|
35
33
|
defaults.source.input = inputs[inputId]
|
|
36
34
|
}
|
|
37
35
|
}
|
|
36
|
+
|
|
37
|
+
let node
|
|
38
38
|
if (defaults.type === 'root') {
|
|
39
|
-
|
|
39
|
+
node = new Root(defaults)
|
|
40
40
|
} else if (defaults.type === 'decl') {
|
|
41
|
-
|
|
41
|
+
node = new Declaration(defaults)
|
|
42
42
|
} else if (defaults.type === 'rule') {
|
|
43
|
-
|
|
43
|
+
node = new Rule(defaults)
|
|
44
44
|
} else if (defaults.type === 'comment') {
|
|
45
|
-
|
|
45
|
+
node = new Comment(defaults)
|
|
46
46
|
} else if (defaults.type === 'atrule') {
|
|
47
|
-
|
|
47
|
+
node = new AtRule(defaults)
|
|
48
48
|
} else {
|
|
49
49
|
throw new Error('Unknown node type: ' + json.type)
|
|
50
50
|
}
|
|
51
|
+
|
|
52
|
+
// Rehydrated children are attached after construction. Passing them
|
|
53
|
+
// through the container constructor would re-run insertion spacing
|
|
54
|
+
// normalization and overwrite each child's own `raws.before`.
|
|
55
|
+
if (children) {
|
|
56
|
+
node.nodes = children
|
|
57
|
+
for (let child of children) child.parent = node
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return node
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function fromJSON(json, inputs) {
|
|
64
|
+
if (Array.isArray(json)) return json.map(n => fromJSON(n))
|
|
65
|
+
|
|
66
|
+
// An explicit stack instead of recursive calls to survive deeply
|
|
67
|
+
// nested trees. Children are rehydrated before their parent node
|
|
68
|
+
// is constructed.
|
|
69
|
+
let result
|
|
70
|
+
let stack = [
|
|
71
|
+
{ childIndex: 0, children: [], inputs: hydrateInputs(json, inputs), json }
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
while (stack.length > 0) {
|
|
75
|
+
let frame = stack[stack.length - 1]
|
|
76
|
+
let jsonNodes = frame.json.nodes
|
|
77
|
+
|
|
78
|
+
if (jsonNodes && frame.childIndex < jsonNodes.length) {
|
|
79
|
+
let childJson = jsonNodes[frame.childIndex]
|
|
80
|
+
frame.childIndex += 1
|
|
81
|
+
stack.push({
|
|
82
|
+
childIndex: 0,
|
|
83
|
+
children: [],
|
|
84
|
+
inputs: hydrateInputs(childJson, frame.inputs),
|
|
85
|
+
json: childJson
|
|
86
|
+
})
|
|
87
|
+
continue
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
stack.pop()
|
|
91
|
+
let node = constructNode(
|
|
92
|
+
frame.json,
|
|
93
|
+
frame.inputs,
|
|
94
|
+
jsonNodes ? frame.children : undefined
|
|
95
|
+
)
|
|
96
|
+
if (stack.length > 0) {
|
|
97
|
+
stack[stack.length - 1].children.push(node)
|
|
98
|
+
} else {
|
|
99
|
+
result = node
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return result
|
|
51
104
|
}
|
|
52
105
|
|
|
53
106
|
module.exports = fromJSON
|
package/lib/input.js
CHANGED
|
@@ -206,12 +206,21 @@ class Input {
|
|
|
206
206
|
if (!this.map) return false
|
|
207
207
|
let consumer = this.map.consumer()
|
|
208
208
|
|
|
209
|
-
let from = consumer.originalPositionFor({ column, line })
|
|
209
|
+
let from = consumer.originalPositionFor({ column: column - 1, line })
|
|
210
210
|
if (!from.source) return false
|
|
211
211
|
|
|
212
212
|
let to
|
|
213
213
|
if (typeof endLine === 'number') {
|
|
214
|
-
|
|
214
|
+
let toPosition = consumer.originalPositionFor({
|
|
215
|
+
column: endColumn - 1,
|
|
216
|
+
line: endLine
|
|
217
|
+
})
|
|
218
|
+
// The source map may not have a mapping that covers the end position
|
|
219
|
+
// (`originalPositionFor()` then returns `null` for `line`/`column`
|
|
220
|
+
// instead of omitting them). Treat that the same as not requesting
|
|
221
|
+
// an end position at all, so `endLine`/`endColumn` stay a consistent
|
|
222
|
+
// `undefined` pair instead of a mix of `null` and a bogus number.
|
|
223
|
+
if (toPosition.source) to = toPosition
|
|
215
224
|
}
|
|
216
225
|
|
|
217
226
|
let fromUrl
|
|
@@ -226,8 +235,8 @@ class Input {
|
|
|
226
235
|
}
|
|
227
236
|
|
|
228
237
|
let result = {
|
|
229
|
-
column: from.column,
|
|
230
|
-
endColumn: to && to.column,
|
|
238
|
+
column: from.column + 1,
|
|
239
|
+
endColumn: to && to.column + 1,
|
|
231
240
|
endLine: to && to.line,
|
|
232
241
|
line: from.line,
|
|
233
242
|
url: fromUrl.toString()
|
package/lib/lazy-result.js
CHANGED
|
@@ -97,8 +97,14 @@ function toStack(node) {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
function cleanMarks(node) {
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
let stack = [node]
|
|
101
|
+
while (stack.length > 0) {
|
|
102
|
+
let next = stack.pop()
|
|
103
|
+
next[isClean] = false
|
|
104
|
+
if (next.nodes) {
|
|
105
|
+
for (let i of next.nodes) stack.push(i)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
102
108
|
return node
|
|
103
109
|
}
|
|
104
110
|
|
|
@@ -378,6 +384,19 @@ class LazyResult {
|
|
|
378
384
|
if (opts.stringifier) str = opts.stringifier
|
|
379
385
|
if (str.stringify) str = str.stringify
|
|
380
386
|
|
|
387
|
+
let rootSource = this.result.root.source
|
|
388
|
+
if (
|
|
389
|
+
opts.map === undefined &&
|
|
390
|
+
!(rootSource && rootSource.input && rootSource.input.map)
|
|
391
|
+
) {
|
|
392
|
+
let result = ''
|
|
393
|
+
str(this.result.root, i => {
|
|
394
|
+
result += i
|
|
395
|
+
})
|
|
396
|
+
this.result.css = result
|
|
397
|
+
return this.result
|
|
398
|
+
}
|
|
399
|
+
|
|
381
400
|
let map = new MapGenerator(str, this.result.root, this.result.opts)
|
|
382
401
|
let data = map.generate()
|
|
383
402
|
this.result.css = data[0]
|
|
@@ -516,21 +535,57 @@ class LazyResult {
|
|
|
516
535
|
}
|
|
517
536
|
|
|
518
537
|
walkSync(node) {
|
|
538
|
+
// An explicit stack like in async `visitTick()` to survive deeply
|
|
539
|
+
// nested trees. Unlike `visitTick()`, nodes are marked clean only
|
|
540
|
+
// on entering, so a node dirtied by its own visitors is revisited
|
|
541
|
+
// on the next pass.
|
|
519
542
|
node[isClean] = true
|
|
520
|
-
let
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
543
|
+
let stack = [{ eventIndex: 0, events: getEvents(node), iterator: 0, node }]
|
|
544
|
+
|
|
545
|
+
while (stack.length > 0) {
|
|
546
|
+
let visit = stack[stack.length - 1]
|
|
547
|
+
let visitNode = visit.node
|
|
548
|
+
|
|
549
|
+
if (visit.iterator !== 0) {
|
|
550
|
+
let iterator = visit.iterator
|
|
551
|
+
let child
|
|
552
|
+
let descended = false
|
|
553
|
+
while ((child = visitNode.nodes[visitNode.indexes[iterator]])) {
|
|
554
|
+
visitNode.indexes[iterator] += 1
|
|
555
|
+
if (!child[isClean]) {
|
|
556
|
+
child[isClean] = true
|
|
557
|
+
stack.push({
|
|
558
|
+
eventIndex: 0,
|
|
559
|
+
events: getEvents(child),
|
|
560
|
+
iterator: 0,
|
|
561
|
+
node: child
|
|
562
|
+
})
|
|
563
|
+
descended = true
|
|
564
|
+
break
|
|
565
|
+
}
|
|
527
566
|
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
567
|
+
if (descended) continue
|
|
568
|
+
visit.iterator = 0
|
|
569
|
+
delete visitNode.indexes[iterator]
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
if (visit.eventIndex < visit.events.length) {
|
|
573
|
+
let event = visit.events[visit.eventIndex]
|
|
574
|
+
visit.eventIndex += 1
|
|
575
|
+
if (event === CHILDREN) {
|
|
576
|
+
if (visitNode.nodes && visitNode.nodes.length) {
|
|
577
|
+
visit.iterator = visitNode.getIterator()
|
|
578
|
+
}
|
|
579
|
+
} else {
|
|
580
|
+
let visitors = this.listeners[event]
|
|
581
|
+
if (visitors) {
|
|
582
|
+
if (this.visitSync(visitors, visitNode.toProxy())) stack.pop()
|
|
583
|
+
}
|
|
532
584
|
}
|
|
585
|
+
continue
|
|
533
586
|
}
|
|
587
|
+
|
|
588
|
+
stack.pop()
|
|
534
589
|
}
|
|
535
590
|
}
|
|
536
591
|
|
package/lib/node.d.ts
CHANGED
|
@@ -31,12 +31,12 @@ declare namespace Node {
|
|
|
31
31
|
|
|
32
32
|
export interface Position {
|
|
33
33
|
/**
|
|
34
|
-
* Source
|
|
34
|
+
* Source column in file. It starts from 1.
|
|
35
35
|
*/
|
|
36
36
|
column: number
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
|
-
* Source
|
|
39
|
+
* Source line in file. It starts from 1.
|
|
40
40
|
*/
|
|
41
41
|
line: number
|
|
42
42
|
|
package/lib/node.js
CHANGED
|
@@ -7,25 +7,41 @@ let { isClean, my } = require('./symbols')
|
|
|
7
7
|
|
|
8
8
|
function cloneNode(obj, parent) {
|
|
9
9
|
let cloned = new obj.constructor()
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (
|
|
28
|
-
|
|
10
|
+
// An explicit stack instead of recursive calls to survive deeply
|
|
11
|
+
// nested trees. Each entry is [source, its clone, clone's parent].
|
|
12
|
+
let stack = [[obj, cloned, parent]]
|
|
13
|
+
|
|
14
|
+
while (stack.length > 0) {
|
|
15
|
+
let [source, target, targetParent] = stack.pop()
|
|
16
|
+
for (let i in source) {
|
|
17
|
+
if (!Object.prototype.hasOwnProperty.call(source, i)) {
|
|
18
|
+
/* c8 ignore next 2 */
|
|
19
|
+
continue
|
|
20
|
+
}
|
|
21
|
+
if (i === 'proxyCache') continue
|
|
22
|
+
let value = source[i]
|
|
23
|
+
let type = typeof value
|
|
24
|
+
|
|
25
|
+
if (i === 'parent' && type === 'object') {
|
|
26
|
+
if (targetParent) target[i] = targetParent
|
|
27
|
+
} else if (i === 'source') {
|
|
28
|
+
target[i] = value
|
|
29
|
+
} else if (Array.isArray(value)) {
|
|
30
|
+
let children = []
|
|
31
|
+
target[i] = children
|
|
32
|
+
for (let j of value) {
|
|
33
|
+
let childClone = new j.constructor()
|
|
34
|
+
children.push(childClone)
|
|
35
|
+
stack.push([j, childClone, target])
|
|
36
|
+
}
|
|
37
|
+
} else {
|
|
38
|
+
if (type === 'object' && value !== null) {
|
|
39
|
+
let valueClone = new value.constructor()
|
|
40
|
+
stack.push([value, valueClone, undefined])
|
|
41
|
+
value = valueClone
|
|
42
|
+
}
|
|
43
|
+
target[i] = value
|
|
44
|
+
}
|
|
29
45
|
}
|
|
30
46
|
}
|
|
31
47
|
|
|
@@ -69,11 +85,15 @@ class Node {
|
|
|
69
85
|
this[isClean] = false
|
|
70
86
|
this[my] = true
|
|
71
87
|
|
|
72
|
-
for (let name
|
|
88
|
+
for (let name of Object.keys(defaults)) {
|
|
89
|
+
if (name === '__proto__') continue
|
|
73
90
|
if (name === 'nodes') {
|
|
74
91
|
this.nodes = []
|
|
75
92
|
for (let node of defaults[name]) {
|
|
76
|
-
|
|
93
|
+
// Clone only nodes that already belong to another tree, so passing a
|
|
94
|
+
// freshly created (parent-less) node adopts that instance instead of
|
|
95
|
+
// a copy and keeps the caller's reference usable. See #1987.
|
|
96
|
+
if (typeof node.clone === 'function' && node.parent) {
|
|
77
97
|
this.append(node.clone())
|
|
78
98
|
} else {
|
|
79
99
|
this.append(node)
|
|
@@ -206,14 +226,18 @@ class Node {
|
|
|
206
226
|
}
|
|
207
227
|
|
|
208
228
|
positionBy(opts = {}) {
|
|
209
|
-
let
|
|
229
|
+
let inputString =
|
|
230
|
+
'document' in this.source.input
|
|
231
|
+
? this.source.input.document
|
|
232
|
+
: this.source.input.css
|
|
233
|
+
let pos = {
|
|
234
|
+
column: this.source.start.column,
|
|
235
|
+
line: this.source.start.line,
|
|
236
|
+
offset: sourceOffset(inputString, this.source.start)
|
|
237
|
+
}
|
|
210
238
|
if (opts.index) {
|
|
211
239
|
pos = this.positionInside(opts.index)
|
|
212
240
|
} else if (opts.word) {
|
|
213
|
-
let inputString =
|
|
214
|
-
'document' in this.source.input
|
|
215
|
-
? this.source.input.document
|
|
216
|
-
: this.source.input.css
|
|
217
241
|
let stringRepresentation = inputString.slice(
|
|
218
242
|
sourceOffset(inputString, this.source.start),
|
|
219
243
|
sourceOffset(inputString, this.source.end)
|
|
@@ -298,7 +322,7 @@ class Node {
|
|
|
298
322
|
line: opts.start.line,
|
|
299
323
|
offset: sourceOffset(inputString, opts.start)
|
|
300
324
|
}
|
|
301
|
-
} else if (opts.index) {
|
|
325
|
+
} else if (typeof opts.index === 'number') {
|
|
302
326
|
start = this.positionInside(opts.index)
|
|
303
327
|
}
|
|
304
328
|
|
|
@@ -310,7 +334,7 @@ class Node {
|
|
|
310
334
|
}
|
|
311
335
|
} else if (typeof opts.endIndex === 'number') {
|
|
312
336
|
end = this.positionInside(opts.endIndex)
|
|
313
|
-
} else if (opts.index) {
|
|
337
|
+
} else if (typeof opts.index === 'number') {
|
|
314
338
|
end = this.positionInside(opts.index + 1)
|
|
315
339
|
}
|
|
316
340
|
}
|
|
@@ -374,47 +398,68 @@ class Node {
|
|
|
374
398
|
}
|
|
375
399
|
|
|
376
400
|
toJSON(_, inputs) {
|
|
377
|
-
let fixed = {}
|
|
378
401
|
let emitInputs = inputs == null
|
|
379
402
|
inputs = inputs || new Map()
|
|
380
|
-
let inputsNextIndex = 0
|
|
381
|
-
|
|
382
|
-
for (let name in this) {
|
|
383
|
-
if (!Object.prototype.hasOwnProperty.call(this, name)) {
|
|
384
|
-
/* c8 ignore next 2 */
|
|
385
|
-
continue
|
|
386
|
-
}
|
|
387
|
-
if (name === 'parent' || name === 'proxyCache') continue
|
|
388
|
-
let value = this[name]
|
|
389
403
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
404
|
+
// A worklist instead of recursive `toJSON()` calls to survive deeply
|
|
405
|
+
// nested trees. Each entry converts one node and writes the result
|
|
406
|
+
// into the already converted parent by [holder, key].
|
|
407
|
+
let holderOfRoot = []
|
|
408
|
+
let queue = [[this, holderOfRoot, 0]]
|
|
409
|
+
|
|
410
|
+
for (let step = 0; step < queue.length; step++) {
|
|
411
|
+
let [node, holder, key] = queue[step]
|
|
412
|
+
let fixed = {}
|
|
413
|
+
holder[key] = fixed
|
|
414
|
+
|
|
415
|
+
for (let name in node) {
|
|
416
|
+
if (!Object.prototype.hasOwnProperty.call(node, name)) {
|
|
417
|
+
/* c8 ignore next 2 */
|
|
418
|
+
continue
|
|
419
|
+
}
|
|
420
|
+
if (name === 'parent' || name === 'proxyCache') continue
|
|
421
|
+
let value = node[name]
|
|
422
|
+
|
|
423
|
+
if (Array.isArray(value)) {
|
|
424
|
+
let fixedArray = []
|
|
425
|
+
fixed[name] = fixedArray
|
|
426
|
+
for (let i = 0; i < value.length; i++) {
|
|
427
|
+
let item = value[i]
|
|
428
|
+
if (typeof item === 'object' && item.toJSON) {
|
|
429
|
+
if (item.toJSON === Node.prototype.toJSON) {
|
|
430
|
+
queue.push([item, fixedArray, i])
|
|
431
|
+
} else {
|
|
432
|
+
fixedArray[i] = item.toJSON(null, inputs)
|
|
433
|
+
}
|
|
434
|
+
} else {
|
|
435
|
+
fixedArray[i] = item
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
} else if (typeof value === 'object' && value.toJSON) {
|
|
439
|
+
if (value.toJSON === Node.prototype.toJSON) {
|
|
440
|
+
queue.push([value, fixed, name])
|
|
394
441
|
} else {
|
|
395
|
-
|
|
442
|
+
fixed[name] = value.toJSON(null, inputs)
|
|
396
443
|
}
|
|
397
|
-
})
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
start: value.start
|
|
444
|
+
} else if (name === 'source') {
|
|
445
|
+
if (value == null) continue
|
|
446
|
+
let inputId = inputs.get(value.input)
|
|
447
|
+
if (inputId == null) {
|
|
448
|
+
inputId = inputs.size
|
|
449
|
+
inputs.set(value.input, inputId)
|
|
450
|
+
}
|
|
451
|
+
fixed[name] = {
|
|
452
|
+
end: value.end,
|
|
453
|
+
inputId,
|
|
454
|
+
start: value.start
|
|
455
|
+
}
|
|
456
|
+
} else {
|
|
457
|
+
fixed[name] = value
|
|
412
458
|
}
|
|
413
|
-
} else {
|
|
414
|
-
fixed[name] = value
|
|
415
459
|
}
|
|
416
460
|
}
|
|
417
461
|
|
|
462
|
+
let fixed = holderOfRoot[0]
|
|
418
463
|
if (emitInputs) {
|
|
419
464
|
fixed.inputs = [...inputs.keys()].map(input => input.toJSON())
|
|
420
465
|
}
|
package/lib/parser.js
CHANGED
|
@@ -20,6 +20,12 @@ function findLastWithPosition(tokens) {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
function tokensToString(tokens, from, to) {
|
|
24
|
+
let result = ''
|
|
25
|
+
for (let i = from; i < to; i++) result += tokens[i][1]
|
|
26
|
+
return result
|
|
27
|
+
}
|
|
28
|
+
|
|
23
29
|
class Parser {
|
|
24
30
|
constructor(input) {
|
|
25
31
|
this.input = input
|
|
@@ -132,9 +138,10 @@ class Parser {
|
|
|
132
138
|
if (founded === 2) break
|
|
133
139
|
}
|
|
134
140
|
}
|
|
135
|
-
// If the token is a word, e.g. `!important`, `red` or any other valid
|
|
136
|
-
// Then we need to return the colon after that word
|
|
137
|
-
//
|
|
141
|
+
// If the token is a word, e.g. `!important`, `red` or any other valid
|
|
142
|
+
// property's value. Then we need to return the colon after that word
|
|
143
|
+
// token. [3] is the "end" colon of that word. And because we need it
|
|
144
|
+
// after that one we do +1 to get the next one.
|
|
138
145
|
throw this.input.error(
|
|
139
146
|
'Missed semicolon',
|
|
140
147
|
token[0] === 'word' ? token[3] + 1 : token[2]
|
|
@@ -207,50 +214,50 @@ class Parser {
|
|
|
207
214
|
)
|
|
208
215
|
node.source.end.offset++
|
|
209
216
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
217
|
+
let start = 0
|
|
218
|
+
while (tokens[start][0] !== 'word') {
|
|
219
|
+
if (start === tokens.length - 1) this.unknownWord([tokens[start]])
|
|
220
|
+
start++
|
|
213
221
|
}
|
|
214
|
-
node.
|
|
222
|
+
node.raws.before += tokensToString(tokens, 0, start)
|
|
223
|
+
node.source.start = this.getPosition(tokens[start][2])
|
|
215
224
|
|
|
216
|
-
|
|
217
|
-
while (tokens.length) {
|
|
218
|
-
let type = tokens[
|
|
225
|
+
let propStart = start
|
|
226
|
+
while (start < tokens.length) {
|
|
227
|
+
let type = tokens[start][0]
|
|
219
228
|
if (type === ':' || type === 'space' || type === 'comment') {
|
|
220
229
|
break
|
|
221
230
|
}
|
|
222
|
-
|
|
231
|
+
start++
|
|
223
232
|
}
|
|
233
|
+
node.prop = tokensToString(tokens, propStart, start)
|
|
224
234
|
|
|
225
|
-
|
|
226
|
-
|
|
235
|
+
let betweenStart = start
|
|
227
236
|
let token
|
|
228
|
-
while (tokens.length) {
|
|
229
|
-
token = tokens
|
|
230
|
-
|
|
231
|
-
if (token[0] === ':')
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
} else {
|
|
235
|
-
if (token[0] === 'word' && /\w/.test(token[1])) {
|
|
236
|
-
this.unknownWord([token])
|
|
237
|
-
}
|
|
238
|
-
node.raws.between += token[1]
|
|
237
|
+
while (start < tokens.length) {
|
|
238
|
+
token = tokens[start]
|
|
239
|
+
start++
|
|
240
|
+
if (token[0] === ':') break
|
|
241
|
+
if (token[0] === 'word' && /\w/.test(token[1])) {
|
|
242
|
+
this.unknownWord([token])
|
|
239
243
|
}
|
|
240
244
|
}
|
|
245
|
+
node.raws.between = tokensToString(tokens, betweenStart, start)
|
|
241
246
|
|
|
242
247
|
if (node.prop[0] === '_' || node.prop[0] === '*') {
|
|
243
248
|
node.raws.before += node.prop[0]
|
|
244
249
|
node.prop = node.prop.slice(1)
|
|
245
250
|
}
|
|
246
251
|
|
|
247
|
-
let
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
next = tokens[0][0]
|
|
252
|
+
let firstSpacesStart = start
|
|
253
|
+
while (start < tokens.length) {
|
|
254
|
+
let next = tokens[start][0]
|
|
251
255
|
if (next !== 'space' && next !== 'comment') break
|
|
252
|
-
|
|
256
|
+
start++
|
|
253
257
|
}
|
|
258
|
+
let firstSpaces = tokens.slice(firstSpacesStart, start)
|
|
259
|
+
|
|
260
|
+
tokens = tokens.slice(start)
|
|
254
261
|
|
|
255
262
|
this.precheckMissedSemicolon(tokens)
|
|
256
263
|
|
package/lib/postcss.d.ts
CHANGED
|
@@ -229,7 +229,7 @@ declare namespace postcss {
|
|
|
229
229
|
export interface Parser<RootNode = Document | Root> {
|
|
230
230
|
(
|
|
231
231
|
css: { toString(): string } | string,
|
|
232
|
-
opts?: Pick<ProcessOptions, 'document' | 'from' | 'map'>
|
|
232
|
+
opts?: Pick<ProcessOptions, 'document' | 'from' | 'map' | 'unsafeMap'>
|
|
233
233
|
): RootNode
|
|
234
234
|
}
|
|
235
235
|
|
|
@@ -351,6 +351,14 @@ declare namespace postcss {
|
|
|
351
351
|
* to generate correct source maps.
|
|
352
352
|
*/
|
|
353
353
|
to?: string
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Disable source map file protections.
|
|
357
|
+
*
|
|
358
|
+
* By default source map is limited only for `.map` files
|
|
359
|
+
* in the `from` folder.
|
|
360
|
+
*/
|
|
361
|
+
unsafeMap?: boolean
|
|
354
362
|
}
|
|
355
363
|
|
|
356
364
|
export type Postcss = typeof postcss
|
package/lib/previous-map.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
let { existsSync, readFileSync } = require('fs')
|
|
4
|
-
let { dirname, join } = require('path')
|
|
4
|
+
let { dirname, isAbsolute, join, relative, sep } = require('path')
|
|
5
5
|
let { SourceMapConsumer, SourceMapGenerator } = require('source-map-js')
|
|
6
6
|
|
|
7
7
|
function fromBase64(str) {
|
|
@@ -16,6 +16,7 @@ function fromBase64(str) {
|
|
|
16
16
|
class PreviousMap {
|
|
17
17
|
constructor(css, opts) {
|
|
18
18
|
if (opts.map === false) return
|
|
19
|
+
if (opts.unsafeMap) this.unsafeMap = true
|
|
19
20
|
this.loadAnnotation(css)
|
|
20
21
|
this.inline = this.startWith(this.annotation, 'data:')
|
|
21
22
|
|
|
@@ -30,7 +31,7 @@ class PreviousMap {
|
|
|
30
31
|
|
|
31
32
|
consumer() {
|
|
32
33
|
if (!this.consumerCache) {
|
|
33
|
-
this.consumerCache = new SourceMapConsumer(this.text)
|
|
34
|
+
this.consumerCache = new SourceMapConsumer(this.json || this.text)
|
|
34
35
|
}
|
|
35
36
|
return this.consumerCache
|
|
36
37
|
}
|
|
@@ -83,7 +84,22 @@ class PreviousMap {
|
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
86
|
|
|
86
|
-
loadFile(path) {
|
|
87
|
+
loadFile(path, cssFile, trusted) {
|
|
88
|
+
if (!trusted && !this.unsafeMap) {
|
|
89
|
+
if (!/\.map$/i.test(path)) {
|
|
90
|
+
return undefined
|
|
91
|
+
}
|
|
92
|
+
if (cssFile) {
|
|
93
|
+
let relativePath = relative(dirname(cssFile), path)
|
|
94
|
+
if (
|
|
95
|
+
relativePath === '..' ||
|
|
96
|
+
relativePath.startsWith('..' + sep) ||
|
|
97
|
+
isAbsolute(relativePath)
|
|
98
|
+
) {
|
|
99
|
+
return undefined
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
87
103
|
this.root = dirname(path)
|
|
88
104
|
if (existsSync(path)) {
|
|
89
105
|
this.mapFile = path
|
|
@@ -100,7 +116,7 @@ class PreviousMap {
|
|
|
100
116
|
} else if (typeof prev === 'function') {
|
|
101
117
|
let prevPath = prev(file)
|
|
102
118
|
if (prevPath) {
|
|
103
|
-
let map = this.loadFile(prevPath)
|
|
119
|
+
let map = this.loadFile(prevPath, file, true)
|
|
104
120
|
if (!map) {
|
|
105
121
|
throw new Error(
|
|
106
122
|
'Unable to load previous source map: ' + prevPath.toString()
|
|
@@ -124,7 +140,16 @@ class PreviousMap {
|
|
|
124
140
|
} else if (this.annotation) {
|
|
125
141
|
let map = this.annotation
|
|
126
142
|
if (file) map = join(dirname(file), map)
|
|
127
|
-
|
|
143
|
+
let unknown = this.loadFile(map, file, false)
|
|
144
|
+
if (unknown) {
|
|
145
|
+
try {
|
|
146
|
+
/* c8 ignore next 4 */
|
|
147
|
+
this.json = JSON.parse(unknown.replace(/^\)]}'[^\n]*\n/, ''))
|
|
148
|
+
} catch {
|
|
149
|
+
return undefined
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return unknown
|
|
128
153
|
}
|
|
129
154
|
}
|
|
130
155
|
|
package/lib/processor.js
CHANGED
package/lib/root.js
CHANGED
|
@@ -12,6 +12,19 @@ class Root extends Container {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
normalize(child, sample, type) {
|
|
15
|
+
let keepBefore = new Set()
|
|
16
|
+
for (let node of Array.isArray(child) ? child : [child]) {
|
|
17
|
+
if (
|
|
18
|
+
node &&
|
|
19
|
+
typeof node === 'object' &&
|
|
20
|
+
!node.parent &&
|
|
21
|
+
node.raws &&
|
|
22
|
+
typeof node.raws.before !== 'undefined'
|
|
23
|
+
) {
|
|
24
|
+
keepBefore.add(node.raws)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
15
28
|
let nodes = super.normalize(child)
|
|
16
29
|
|
|
17
30
|
if (sample) {
|
|
@@ -23,7 +36,9 @@ class Root extends Container {
|
|
|
23
36
|
}
|
|
24
37
|
} else if (this.first !== sample) {
|
|
25
38
|
for (let node of nodes) {
|
|
26
|
-
node.raws
|
|
39
|
+
if (!keepBefore.has(node.raws)) {
|
|
40
|
+
node.raws.before = sample.raws.before
|
|
41
|
+
}
|
|
27
42
|
}
|
|
28
43
|
}
|
|
29
44
|
}
|
package/lib/stringifier.js
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
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
|
+
// Characters that end an at-rule name, mirroring RE_AT_END in the tokenizer.
|
|
10
|
+
// Params starting with anything else need a space to stay separate tokens.
|
|
11
|
+
const AT_NAME_END = /[\t\n\f\r "#'()/;[\\\]{}]/
|
|
12
|
+
|
|
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
|
+
|
|
3
19
|
const DEFAULT_RAW = {
|
|
4
20
|
after: '\n',
|
|
5
21
|
beforeClose: '\n',
|
|
@@ -19,26 +35,89 @@ function capitalize(str) {
|
|
|
19
35
|
return str[0].toUpperCase() + str.slice(1)
|
|
20
36
|
}
|
|
21
37
|
|
|
38
|
+
function atruleStart(str, node) {
|
|
39
|
+
let name = '@' + node.name
|
|
40
|
+
let params = node.params ? str.rawValue(node, 'params') : ''
|
|
41
|
+
let afterName = node.raws.afterName
|
|
42
|
+
|
|
43
|
+
if (typeof afterName === 'undefined') {
|
|
44
|
+
afterName = params ? ' ' : ''
|
|
45
|
+
} else if (afterName === '' && params && !AT_NAME_END.test(params[0])) {
|
|
46
|
+
afterName = ' '
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return name + afterName + params
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function pushBody(str, stack, node) {
|
|
53
|
+
let nodes = node.nodes
|
|
54
|
+
let last = nodes.length - 1
|
|
55
|
+
while (last > 0) {
|
|
56
|
+
if (nodes[last].type !== 'comment') break
|
|
57
|
+
last -= 1
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let semicolon = str.raw(node, 'semicolon')
|
|
61
|
+
let isDocument = node.type === 'document'
|
|
62
|
+
for (let i = nodes.length - 1; i >= 0; i--) {
|
|
63
|
+
let child = nodes[i]
|
|
64
|
+
let childSemicolon = last !== i || semicolon
|
|
65
|
+
// A childless at-rule or a custom property declaration that still has
|
|
66
|
+
// following siblings must be terminated. Without the semicolon those
|
|
67
|
+
// trailing comments are folded into the at-rule's prelude or the custom
|
|
68
|
+
// property's value and disappear when the output is re-parsed.
|
|
69
|
+
if (
|
|
70
|
+
!childSemicolon &&
|
|
71
|
+
i < nodes.length - 1 &&
|
|
72
|
+
((child.type === 'atrule' && !child.nodes) ||
|
|
73
|
+
(child.type === 'decl' && child.prop.startsWith('--')))
|
|
74
|
+
) {
|
|
75
|
+
childSemicolon = true
|
|
76
|
+
}
|
|
77
|
+
stack.push({
|
|
78
|
+
document: isDocument,
|
|
79
|
+
node: child,
|
|
80
|
+
semicolon: childSemicolon
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function pushBlock(str, stack, node, start) {
|
|
86
|
+
let between = str.raw(node, 'between', 'beforeOpen')
|
|
87
|
+
str.builder(escapeHTMLInCSS(start + between) + '{', node, 'start')
|
|
88
|
+
|
|
89
|
+
let hasNodes = node.nodes && node.nodes.length
|
|
90
|
+
let close = () => {
|
|
91
|
+
let after = hasNodes
|
|
92
|
+
? str.raw(node, 'after')
|
|
93
|
+
: str.raw(node, 'after', 'emptyBody')
|
|
94
|
+
if (after) str.builder(escapeHTMLInCSS(after))
|
|
95
|
+
str.builder('}', node, 'end')
|
|
96
|
+
if (node.type === 'rule' && node.raws.ownSemicolon) {
|
|
97
|
+
str.builder(escapeHTMLInCSS(node.raws.ownSemicolon), node, 'end')
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (hasNodes) {
|
|
102
|
+
stack.push(close)
|
|
103
|
+
pushBody(str, stack, node)
|
|
104
|
+
} else {
|
|
105
|
+
close()
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
22
109
|
class Stringifier {
|
|
23
110
|
constructor(builder) {
|
|
24
111
|
this.builder = builder
|
|
25
112
|
}
|
|
26
113
|
|
|
27
114
|
atrule(node, semicolon) {
|
|
28
|
-
let
|
|
29
|
-
let params = node.params ? this.rawValue(node, 'params') : ''
|
|
30
|
-
|
|
31
|
-
if (typeof node.raws.afterName !== 'undefined') {
|
|
32
|
-
name += node.raws.afterName
|
|
33
|
-
} else if (params) {
|
|
34
|
-
name += ' '
|
|
35
|
-
}
|
|
36
|
-
|
|
115
|
+
let start = atruleStart(this, node)
|
|
37
116
|
if (node.nodes) {
|
|
38
|
-
this.block(node,
|
|
117
|
+
this.block(node, start)
|
|
39
118
|
} else {
|
|
40
119
|
let end = (node.raws.between || '') + (semicolon ? ';' : '')
|
|
41
|
-
this.builder(
|
|
120
|
+
this.builder(escapeHTMLInCSS(start + end), node)
|
|
42
121
|
}
|
|
43
122
|
}
|
|
44
123
|
|
|
@@ -73,7 +152,7 @@ class Stringifier {
|
|
|
73
152
|
|
|
74
153
|
block(node, start) {
|
|
75
154
|
let between = this.raw(node, 'between', 'beforeOpen')
|
|
76
|
-
this.builder(start + between + '{', node, 'start')
|
|
155
|
+
this.builder(escapeHTMLInCSS(start + between) + '{', node, 'start')
|
|
77
156
|
|
|
78
157
|
let after
|
|
79
158
|
if (node.nodes && node.nodes.length) {
|
|
@@ -83,42 +162,64 @@ class Stringifier {
|
|
|
83
162
|
after = this.raw(node, 'after', 'emptyBody')
|
|
84
163
|
}
|
|
85
164
|
|
|
86
|
-
if (after) this.builder(after)
|
|
165
|
+
if (after) this.builder(escapeHTMLInCSS(after))
|
|
87
166
|
this.builder('}', node, 'end')
|
|
88
167
|
}
|
|
89
168
|
|
|
90
169
|
body(node) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
170
|
+
// Rules and at-rules are expanded into an explicit stack instead of
|
|
171
|
+
// recursive `stringify()` calls to survive deeply nested trees.
|
|
172
|
+
// If a subclass changes the traversal methods, its children go
|
|
173
|
+
// through `stringify()` to keep the override in charge.
|
|
174
|
+
let proto = Stringifier.prototype
|
|
175
|
+
let expandable = ['atrule', 'block', 'body', 'rule', 'stringify'].every(
|
|
176
|
+
method => this[method] === proto[method]
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
let stack = []
|
|
180
|
+
pushBody(this, stack, node)
|
|
181
|
+
|
|
182
|
+
while (stack.length > 0) {
|
|
183
|
+
let entry = stack.pop()
|
|
184
|
+
if (typeof entry === 'function') {
|
|
185
|
+
entry()
|
|
186
|
+
continue
|
|
187
|
+
}
|
|
96
188
|
|
|
97
|
-
|
|
98
|
-
for (let i = 0; i < node.nodes.length; i++) {
|
|
99
|
-
let child = node.nodes[i]
|
|
189
|
+
let child = entry.node
|
|
100
190
|
let before = this.raw(child, 'before')
|
|
101
|
-
if (before)
|
|
102
|
-
|
|
191
|
+
if (before) {
|
|
192
|
+
this.builder(entry.document ? before : escapeHTMLInCSS(before))
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (expandable && child.type === 'rule') {
|
|
196
|
+
pushBlock(this, stack, child, this.rawValue(child, 'selector'))
|
|
197
|
+
} else if (expandable && child.type === 'atrule' && child.nodes) {
|
|
198
|
+
pushBlock(this, stack, child, atruleStart(this, child))
|
|
199
|
+
} else {
|
|
200
|
+
this.stringify(child, entry.semicolon)
|
|
201
|
+
}
|
|
103
202
|
}
|
|
104
203
|
}
|
|
105
204
|
|
|
106
205
|
comment(node) {
|
|
107
206
|
let left = this.raw(node, 'left', 'commentLeft')
|
|
108
207
|
let right = this.raw(node, 'right', 'commentRight')
|
|
109
|
-
this.builder('/*' + left + node.text + right + '*/', node)
|
|
208
|
+
this.builder(escapeHTMLInCSS('/*' + left + node.text + right + '*/'), node)
|
|
110
209
|
}
|
|
111
210
|
|
|
112
211
|
decl(node, semicolon) {
|
|
212
|
+
let raws = node.raws
|
|
113
213
|
let between = this.raw(node, 'between', 'colon')
|
|
214
|
+
|
|
114
215
|
let string = node.prop + between + this.rawValue(node, 'value')
|
|
115
216
|
|
|
116
217
|
if (node.important) {
|
|
117
|
-
string +=
|
|
218
|
+
string += raws.important || ' !important'
|
|
118
219
|
}
|
|
119
220
|
|
|
120
221
|
if (semicolon) string += ';'
|
|
121
|
-
this.builder(string, node)
|
|
222
|
+
this.builder(escapeHTMLInCSS(string), node)
|
|
122
223
|
}
|
|
123
224
|
|
|
124
225
|
document(node) {
|
|
@@ -154,9 +255,9 @@ class Stringifier {
|
|
|
154
255
|
|
|
155
256
|
// Detect style by other nodes
|
|
156
257
|
let root = node.root()
|
|
157
|
-
|
|
158
|
-
if (typeof
|
|
159
|
-
return
|
|
258
|
+
let cache = root.rawCache || (root.rawCache = {})
|
|
259
|
+
if (typeof cache[detect] !== 'undefined') {
|
|
260
|
+
return cache[detect]
|
|
160
261
|
}
|
|
161
262
|
|
|
162
263
|
if (detect === 'before' || detect === 'after') {
|
|
@@ -175,7 +276,7 @@ class Stringifier {
|
|
|
175
276
|
|
|
176
277
|
if (typeof value === 'undefined') value = DEFAULT_RAW[detect]
|
|
177
278
|
|
|
178
|
-
|
|
279
|
+
cache[detect] = value
|
|
179
280
|
return value
|
|
180
281
|
}
|
|
181
282
|
|
|
@@ -324,13 +425,17 @@ class Stringifier {
|
|
|
324
425
|
|
|
325
426
|
root(node) {
|
|
326
427
|
this.body(node)
|
|
327
|
-
if (node.raws.after)
|
|
428
|
+
if (node.raws.after) {
|
|
429
|
+
let after = node.raws.after
|
|
430
|
+
let isDocument = node.parent && node.parent.type === 'document'
|
|
431
|
+
this.builder(isDocument ? after : escapeHTMLInCSS(after))
|
|
432
|
+
}
|
|
328
433
|
}
|
|
329
434
|
|
|
330
435
|
rule(node) {
|
|
331
436
|
this.block(node, this.rawValue(node, 'selector'))
|
|
332
437
|
if (node.raws.ownSemicolon) {
|
|
333
|
-
this.builder(node.raws.ownSemicolon, node, 'end')
|
|
438
|
+
this.builder(escapeHTMLInCSS(node.raws.ownSemicolon), node, 'end')
|
|
334
439
|
}
|
|
335
440
|
}
|
|
336
441
|
|
package/lib/tokenize.js
CHANGED
|
@@ -36,6 +36,7 @@ module.exports = function tokenizer(input, options = {}) {
|
|
|
36
36
|
let pos = 0
|
|
37
37
|
let buffer = []
|
|
38
38
|
let returned = []
|
|
39
|
+
let lastBadParen = -1
|
|
39
40
|
|
|
40
41
|
function position() {
|
|
41
42
|
return pos
|
|
@@ -127,11 +128,14 @@ module.exports = function tokenizer(input, options = {}) {
|
|
|
127
128
|
currentToken = ['brackets', css.slice(pos, next + 1), pos, next]
|
|
128
129
|
|
|
129
130
|
pos = next
|
|
131
|
+
} else if (pos <= lastBadParen) {
|
|
132
|
+
currentToken = ['(', '(', pos]
|
|
130
133
|
} else {
|
|
131
134
|
next = css.indexOf(')', pos + 1)
|
|
132
135
|
content = css.slice(pos, next + 1)
|
|
133
136
|
|
|
134
137
|
if (next === -1 || RE_BAD_BRACKET.test(content)) {
|
|
138
|
+
lastBadParen = next === -1 ? length : next
|
|
135
139
|
currentToken = ['(', '(', pos]
|
|
136
140
|
} else {
|
|
137
141
|
currentToken = ['brackets', content, pos, next]
|
package/lib/warning.js
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
let Container = require('./container')
|
|
4
|
+
let { my } = require('./symbols')
|
|
5
|
+
|
|
3
6
|
class Warning {
|
|
4
7
|
constructor(text, opts = {}) {
|
|
5
8
|
this.type = 'warning'
|
|
6
9
|
this.text = text
|
|
7
10
|
|
|
8
11
|
if (opts.node && opts.node.source) {
|
|
12
|
+
if (!opts.node[my]) {
|
|
13
|
+
// The node comes from another PostCSS copy in node_modules, so it does
|
|
14
|
+
// not have this copy’s methods. Container#normalize() rebuilds such
|
|
15
|
+
// nodes on insert, but a node passed straight to Result#warn() never
|
|
16
|
+
// goes through it.
|
|
17
|
+
Container.rebuild(opts.node)
|
|
18
|
+
}
|
|
9
19
|
let range = opts.node.rangeBy(opts)
|
|
10
20
|
this.line = range.start.line
|
|
11
21
|
this.column = range.start.column
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@depup/postcss",
|
|
3
|
-
"version": "8.5.
|
|
3
|
+
"version": "8.5.22-depup.0",
|
|
4
4
|
"description": "Tool for transforming styles with JS plugins (with updated dependencies)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"postcss",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"./package.json": "./package.json"
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
|
86
|
-
"nanoid": "^
|
|
86
|
+
"nanoid": "^6.0.0",
|
|
87
87
|
"picocolors": "^1.1.1",
|
|
88
88
|
"source-map-js": "^1.2.1"
|
|
89
89
|
},
|
|
@@ -93,14 +93,14 @@
|
|
|
93
93
|
"depup": {
|
|
94
94
|
"changes": {
|
|
95
95
|
"nanoid": {
|
|
96
|
-
"from": "^3.3.
|
|
97
|
-
"to": "^
|
|
96
|
+
"from": "^3.3.16",
|
|
97
|
+
"to": "^6.0.0"
|
|
98
98
|
}
|
|
99
99
|
},
|
|
100
100
|
"depsUpdated": 1,
|
|
101
101
|
"originalPackage": "postcss",
|
|
102
|
-
"originalVersion": "8.5.
|
|
103
|
-
"processedAt": "2026-
|
|
102
|
+
"originalVersion": "8.5.22",
|
|
103
|
+
"processedAt": "2026-07-22T08:55:34.234Z",
|
|
104
104
|
"smokeTest": "passed"
|
|
105
105
|
}
|
|
106
106
|
}
|