postcss 8.5.16 → 8.5.18
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/container.js +81 -34
- package/lib/fromJSON.js +65 -26
- package/lib/input.js +7 -1
- package/lib/lazy-result.js +55 -13
- package/lib/node.js +90 -52
- package/lib/postcss.d.ts +4 -1
- package/lib/previous-map.js +11 -2
- package/lib/processor.js +1 -1
- package/lib/stringifier.js +90 -25
- package/package.json +1 -1
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,31 +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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
21
|
+
return inputHydrated
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function constructNode(json, inputs, children) {
|
|
26
|
+
let defaults = { ...json }
|
|
27
|
+
delete defaults.inputs
|
|
28
|
+
delete defaults.nodes
|
|
36
29
|
if (defaults.source) {
|
|
37
30
|
let { inputId, ...source } = defaults.source
|
|
38
31
|
defaults.source = source
|
|
@@ -56,13 +49,59 @@ function fromJSON(json, inputs) {
|
|
|
56
49
|
throw new Error('Unknown node type: ' + json.type)
|
|
57
50
|
}
|
|
58
51
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
|
62
58
|
}
|
|
63
59
|
|
|
64
60
|
return node
|
|
65
61
|
}
|
|
66
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
|
|
104
|
+
}
|
|
105
|
+
|
|
67
106
|
module.exports = fromJSON
|
|
68
107
|
fromJSON.default = fromJSON
|
package/lib/input.js
CHANGED
|
@@ -211,10 +211,16 @@ class Input {
|
|
|
211
211
|
|
|
212
212
|
let to
|
|
213
213
|
if (typeof endLine === 'number') {
|
|
214
|
-
|
|
214
|
+
let toPosition = consumer.originalPositionFor({
|
|
215
215
|
column: endColumn - 1,
|
|
216
216
|
line: endLine
|
|
217
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
|
|
218
224
|
}
|
|
219
225
|
|
|
220
226
|
let fromUrl
|
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
|
|
|
@@ -529,21 +535,57 @@ class LazyResult {
|
|
|
529
535
|
}
|
|
530
536
|
|
|
531
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.
|
|
532
542
|
node[isClean] = true
|
|
533
|
-
let
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
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
|
+
}
|
|
540
566
|
}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
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
|
+
}
|
|
545
584
|
}
|
|
585
|
+
continue
|
|
546
586
|
}
|
|
587
|
+
|
|
588
|
+
stack.pop()
|
|
547
589
|
}
|
|
548
590
|
}
|
|
549
591
|
|
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,7 +85,8 @@ 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]) {
|
|
@@ -381,47 +398,68 @@ class Node {
|
|
|
381
398
|
}
|
|
382
399
|
|
|
383
400
|
toJSON(_, inputs) {
|
|
384
|
-
let fixed = {}
|
|
385
401
|
let emitInputs = inputs == null
|
|
386
402
|
inputs = inputs || new Map()
|
|
387
|
-
let inputsNextIndex = 0
|
|
388
403
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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])
|
|
401
441
|
} else {
|
|
402
|
-
|
|
442
|
+
fixed[name] = value.toJSON(null, inputs)
|
|
403
443
|
}
|
|
404
|
-
})
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
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
|
|
419
458
|
}
|
|
420
|
-
} else {
|
|
421
|
-
fixed[name] = value
|
|
422
459
|
}
|
|
423
460
|
}
|
|
424
461
|
|
|
462
|
+
let fixed = holderOfRoot[0]
|
|
425
463
|
if (emitInputs) {
|
|
426
464
|
fixed.inputs = [...inputs.keys()].map(input => input.toJSON())
|
|
427
465
|
}
|
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
|
|
|
@@ -354,6 +354,9 @@ declare namespace postcss {
|
|
|
354
354
|
|
|
355
355
|
/**
|
|
356
356
|
* Disable source map file protections.
|
|
357
|
+
*
|
|
358
|
+
* By default source map is limited only for `.map` files
|
|
359
|
+
* in the `from` folder.
|
|
357
360
|
*/
|
|
358
361
|
unsafeMap?: boolean
|
|
359
362
|
}
|
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) {
|
|
@@ -85,11 +85,20 @@ class PreviousMap {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
loadFile(path, cssFile, trusted) {
|
|
88
|
-
/* c8 ignore next 5 */
|
|
89
88
|
if (!trusted && !this.unsafeMap) {
|
|
90
89
|
if (!/\.map$/i.test(path)) {
|
|
91
90
|
return undefined
|
|
92
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
|
+
}
|
|
93
102
|
}
|
|
94
103
|
this.root = dirname(path)
|
|
95
104
|
if (existsSync(path)) {
|
package/lib/processor.js
CHANGED
package/lib/stringifier.js
CHANGED
|
@@ -31,27 +31,74 @@ function capitalize(str) {
|
|
|
31
31
|
return str[0].toUpperCase() + str.slice(1)
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
function atruleStart(str, node) {
|
|
35
|
+
let name = '@' + node.name
|
|
36
|
+
let params = node.params ? str.rawValue(node, 'params') : ''
|
|
37
|
+
|
|
38
|
+
if (typeof node.raws.afterName !== 'undefined') {
|
|
39
|
+
name += node.raws.afterName
|
|
40
|
+
} else if (params) {
|
|
41
|
+
name += ' '
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return name + params
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function pushBody(str, stack, node) {
|
|
48
|
+
let nodes = node.nodes
|
|
49
|
+
let last = nodes.length - 1
|
|
50
|
+
while (last > 0) {
|
|
51
|
+
if (nodes[last].type !== 'comment') break
|
|
52
|
+
last -= 1
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let semicolon = str.raw(node, 'semicolon')
|
|
56
|
+
let isDocument = node.type === 'document'
|
|
57
|
+
for (let i = nodes.length - 1; i >= 0; i--) {
|
|
58
|
+
stack.push({
|
|
59
|
+
document: isDocument,
|
|
60
|
+
node: nodes[i],
|
|
61
|
+
semicolon: last !== i || semicolon
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function pushBlock(str, stack, node, start) {
|
|
67
|
+
let between = str.raw(node, 'between', 'beforeOpen')
|
|
68
|
+
str.builder(escapeHTMLInCSS(start + between) + '{', node, 'start')
|
|
69
|
+
|
|
70
|
+
let hasNodes = node.nodes && node.nodes.length
|
|
71
|
+
let close = () => {
|
|
72
|
+
let after = hasNodes
|
|
73
|
+
? str.raw(node, 'after')
|
|
74
|
+
: str.raw(node, 'after', 'emptyBody')
|
|
75
|
+
if (after) str.builder(escapeHTMLInCSS(after))
|
|
76
|
+
str.builder('}', node, 'end')
|
|
77
|
+
if (node.type === 'rule' && node.raws.ownSemicolon) {
|
|
78
|
+
str.builder(escapeHTMLInCSS(node.raws.ownSemicolon), node, 'end')
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (hasNodes) {
|
|
83
|
+
stack.push(close)
|
|
84
|
+
pushBody(str, stack, node)
|
|
85
|
+
} else {
|
|
86
|
+
close()
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
34
90
|
class Stringifier {
|
|
35
91
|
constructor(builder) {
|
|
36
92
|
this.builder = builder
|
|
37
93
|
}
|
|
38
94
|
|
|
39
95
|
atrule(node, semicolon) {
|
|
40
|
-
let
|
|
41
|
-
let name = '@' + node.name
|
|
42
|
-
let params = node.params ? this.rawValue(node, 'params') : ''
|
|
43
|
-
|
|
44
|
-
if (typeof raws.afterName !== 'undefined') {
|
|
45
|
-
name += raws.afterName
|
|
46
|
-
} else if (params) {
|
|
47
|
-
name += ' '
|
|
48
|
-
}
|
|
49
|
-
|
|
96
|
+
let start = atruleStart(this, node)
|
|
50
97
|
if (node.nodes) {
|
|
51
|
-
this.block(node,
|
|
98
|
+
this.block(node, start)
|
|
52
99
|
} else {
|
|
53
|
-
let end = (raws.between || '') + (semicolon ? ';' : '')
|
|
54
|
-
this.builder(escapeHTMLInCSS(
|
|
100
|
+
let end = (node.raws.between || '') + (semicolon ? ';' : '')
|
|
101
|
+
this.builder(escapeHTMLInCSS(start + end), node)
|
|
55
102
|
}
|
|
56
103
|
}
|
|
57
104
|
|
|
@@ -101,20 +148,38 @@ class Stringifier {
|
|
|
101
148
|
}
|
|
102
149
|
|
|
103
150
|
body(node) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
151
|
+
// Rules and at-rules are expanded into an explicit stack instead of
|
|
152
|
+
// recursive `stringify()` calls to survive deeply nested trees.
|
|
153
|
+
// If a subclass changes the traversal methods, its children go
|
|
154
|
+
// through `stringify()` to keep the override in charge.
|
|
155
|
+
let proto = Stringifier.prototype
|
|
156
|
+
let expandable = ['atrule', 'block', 'body', 'rule', 'stringify'].every(
|
|
157
|
+
method => this[method] === proto[method]
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
let stack = []
|
|
161
|
+
pushBody(this, stack, node)
|
|
162
|
+
|
|
163
|
+
while (stack.length > 0) {
|
|
164
|
+
let entry = stack.pop()
|
|
165
|
+
if (typeof entry === 'function') {
|
|
166
|
+
entry()
|
|
167
|
+
continue
|
|
168
|
+
}
|
|
110
169
|
|
|
111
|
-
|
|
112
|
-
let isDocument = node.type === 'document'
|
|
113
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
114
|
-
let child = nodes[i]
|
|
170
|
+
let child = entry.node
|
|
115
171
|
let before = this.raw(child, 'before')
|
|
116
|
-
if (before)
|
|
117
|
-
|
|
172
|
+
if (before) {
|
|
173
|
+
this.builder(entry.document ? before : escapeHTMLInCSS(before))
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (expandable && child.type === 'rule') {
|
|
177
|
+
pushBlock(this, stack, child, this.rawValue(child, 'selector'))
|
|
178
|
+
} else if (expandable && child.type === 'atrule' && child.nodes) {
|
|
179
|
+
pushBlock(this, stack, child, atruleStart(this, child))
|
|
180
|
+
} else {
|
|
181
|
+
this.stringify(child, entry.semicolon)
|
|
182
|
+
}
|
|
118
183
|
}
|
|
119
184
|
}
|
|
120
185
|
|