@depup/postcss 8.5.8-depup.0 → 8.5.21-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/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
- for (let i in obj) {
12
- if (!Object.prototype.hasOwnProperty.call(obj, i)) {
13
- /* c8 ignore next 2 */
14
- continue
15
- }
16
- if (i === 'proxyCache') continue
17
- let value = obj[i]
18
- let type = typeof value
19
-
20
- if (i === 'parent' && type === 'object') {
21
- if (parent) cloned[i] = parent
22
- } else if (i === 'source') {
23
- cloned[i] = value
24
- } else if (Array.isArray(value)) {
25
- cloned[i] = value.map(j => cloneNode(j, cloned))
26
- } else {
27
- if (type === 'object' && value !== null) value = cloneNode(value)
28
- cloned[i] = value
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 in defaults) {
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
- if (typeof node.clone === 'function') {
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 pos = this.source.start
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
- if (Array.isArray(value)) {
391
- fixed[name] = value.map(i => {
392
- if (typeof i === 'object' && i.toJSON) {
393
- return i.toJSON(null, inputs)
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
- return i
442
+ fixed[name] = value.toJSON(null, inputs)
396
443
  }
397
- })
398
- } else if (typeof value === 'object' && value.toJSON) {
399
- fixed[name] = value.toJSON(null, inputs)
400
- } else if (name === 'source') {
401
- if (value == null) continue
402
- let inputId = inputs.get(value.input)
403
- if (inputId == null) {
404
- inputId = inputsNextIndex
405
- inputs.set(value.input, inputsNextIndex)
406
- inputsNextIndex++
407
- }
408
- fixed[name] = {
409
- end: value.end,
410
- inputId,
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/parse.d.ts CHANGED
@@ -4,6 +4,6 @@ interface Parse extends Parser {
4
4
  default: Parse
5
5
  }
6
6
 
7
- declare const parse: Parse
7
+ declare let parse: Parse
8
8
 
9
9
  export = parse
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 property's value.
136
- // Then we need to return the colon after that word token. [3] is the "end" colon of that word.
137
- // And because we need it after that one we do +1 to get the next one.
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
- while (tokens[0][0] !== 'word') {
211
- if (tokens.length === 1) this.unknownWord(tokens)
212
- node.raws.before += tokens.shift()[1]
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.source.start = this.getPosition(tokens[0][2])
222
+ node.raws.before += tokensToString(tokens, 0, start)
223
+ node.source.start = this.getPosition(tokens[start][2])
215
224
 
216
- node.prop = ''
217
- while (tokens.length) {
218
- let type = tokens[0][0]
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
- node.prop += tokens.shift()[1]
231
+ start++
223
232
  }
233
+ node.prop = tokensToString(tokens, propStart, start)
224
234
 
225
- node.raws.between = ''
226
-
235
+ let betweenStart = start
227
236
  let token
228
- while (tokens.length) {
229
- token = tokens.shift()
230
-
231
- if (token[0] === ':') {
232
- node.raws.between += token[1]
233
- break
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 firstSpaces = []
248
- let next
249
- while (tokens.length) {
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
- firstSpaces.push(tokens.shift())
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.mts CHANGED
@@ -1,7 +1,6 @@
1
1
  export {
2
2
  // Type-only exports
3
3
  AcceptedPlugin,
4
-
5
4
  AnyNode,
6
5
  atRule,
7
6
  AtRule,
@@ -27,7 +26,6 @@ export {
27
26
  fromJSON,
28
27
  Helpers,
29
28
  Input,
30
-
31
29
  JSONHydrator,
32
30
  // This is a class, but it’s not re-exported. That’s why it’s exported as type-only here.
33
31
  type LazyResult,
@@ -64,6 +62,5 @@ export {
64
62
  TransformCallback,
65
63
  Transformer,
66
64
  Warning,
67
-
68
65
  WarningOptions
69
66
  } from './postcss.js'
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
@@ -450,9 +458,7 @@ declare namespace postcss {
450
458
  * @param plugins PostCSS plugins.
451
459
  * @return Processor to process multiple CSS.
452
460
  */
453
- declare function postcss(
454
- plugins?: readonly postcss.AcceptedPlugin[]
455
- ): Processor
461
+ declare function postcss(plugins?: readonly postcss.AcceptedPlugin[]): Processor
456
462
  declare function postcss(...plugins: postcss.AcceptedPlugin[]): Processor
457
463
 
458
464
  export = postcss
@@ -3,7 +3,6 @@ import { SourceMapConsumer } from 'source-map-js'
3
3
  import { ProcessOptions } from './postcss.js'
4
4
 
5
5
  declare namespace PreviousMap {
6
-
7
6
  export { PreviousMap_ as default }
8
7
  }
9
8
 
@@ -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
  }
@@ -51,7 +52,8 @@ class PreviousMap {
51
52
  return fromBase64(text.substr(baseUriMatch[0].length))
52
53
  }
53
54
 
54
- let encoding = text.match(/data:application\/json;([^,]+),/)[1]
55
+ let encoding = text.slice('data:application/json;'.length)
56
+ encoding = encoding.slice(0, encoding.indexOf(','))
55
57
  throw new Error('Unsupported source map encoding ' + encoding)
56
58
  }
57
59
 
@@ -82,7 +84,22 @@ class PreviousMap {
82
84
  }
83
85
  }
84
86
 
85
- 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
+ }
86
103
  this.root = dirname(path)
87
104
  if (existsSync(path)) {
88
105
  this.mapFile = path
@@ -99,7 +116,7 @@ class PreviousMap {
99
116
  } else if (typeof prev === 'function') {
100
117
  let prevPath = prev(file)
101
118
  if (prevPath) {
102
- let map = this.loadFile(prevPath)
119
+ let map = this.loadFile(prevPath, file, true)
103
120
  if (!map) {
104
121
  throw new Error(
105
122
  'Unable to load previous source map: ' + prevPath.toString()
@@ -123,7 +140,16 @@ class PreviousMap {
123
140
  } else if (this.annotation) {
124
141
  let map = this.annotation
125
142
  if (file) map = join(dirname(file), map)
126
- return this.loadFile(map)
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
127
153
  }
128
154
  }
129
155
 
@@ -12,7 +12,6 @@ import Result from './result.js'
12
12
  import Root from './root.js'
13
13
 
14
14
  declare namespace Processor {
15
-
16
15
  export { Processor_ as default }
17
16
  }
18
17
 
package/lib/processor.js CHANGED
@@ -7,7 +7,7 @@ let Root = require('./root')
7
7
 
8
8
  class Processor {
9
9
  constructor(plugins = []) {
10
- this.version = '8.5.8'
10
+ this.version = '8.5.21'
11
11
  this.plugins = this.normalize(plugins)
12
12
  }
13
13
 
package/lib/result.d.ts CHANGED
@@ -39,7 +39,6 @@ declare namespace Result {
39
39
  plugin?: string
40
40
  }
41
41
 
42
-
43
42
  export { Result_ as default }
44
43
  }
45
44
 
package/lib/root.d.ts CHANGED
@@ -40,7 +40,6 @@ declare namespace Root {
40
40
  raws?: RootRaws
41
41
  }
42
42
 
43
-
44
43
  export { Root_ as default }
45
44
  }
46
45
 
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.before = sample.raws.before
39
+ if (!keepBefore.has(node.raws)) {
40
+ node.raws.before = sample.raws.before
41
+ }
27
42
  }
28
43
  }
29
44
  }
package/lib/rule.d.ts CHANGED
@@ -44,19 +44,19 @@ declare namespace Rule {
44
44
  /** Information used to generate byte-to-byte equal node string as it was in the origin input. */
45
45
  raws?: RuleRaws
46
46
  } & (
47
- | {
48
- /** Selector or selectors of the rule. */
49
- selector: string
50
- selectors?: never
51
- }
52
- | {
53
- selector?: never
54
- /** Selectors of the rule represented as an array of strings. */
55
- selectors: readonly string[]
56
- }
57
- ) & ContainerProps
47
+ | {
48
+ /** Selector or selectors of the rule. */
49
+ selector: string
50
+ selectors?: never
51
+ }
52
+ | {
53
+ selector?: never
54
+ /** Selectors of the rule represented as an array of strings. */
55
+ selectors: readonly string[]
56
+ }
57
+ ) &
58
+ ContainerProps
58
59
 
59
-
60
60
  export { Rule_ as default }
61
61
  }
62
62
 
@@ -11,7 +11,6 @@ import {
11
11
  } from './postcss.js'
12
12
 
13
13
  declare namespace Stringifier {
14
-
15
14
  export { Stringifier_ as default }
16
15
  }
17
16