source: node_modules/postcss/lib/container.js@ 2058e5c

Last change on this file since 2058e5c was 2058e5c, checked in by istevanoska <ilinastevanoska@…>, 6 months ago

Working / before login

  • Property mode set to 100644
File size: 10.4 KB
Line 
1'use strict'
2
3let Comment = require('./comment')
4let Declaration = require('./declaration')
5let Node = require('./node')
6let { isClean, my } = require('./symbols')
7
8let AtRule, parse, Root, Rule
9
10function cleanSource(nodes) {
11 return nodes.map(i => {
12 if (i.nodes) i.nodes = cleanSource(i.nodes)
13 delete i.source
14 return i
15 })
16}
17
18function markTreeDirty(node) {
19 node[isClean] = false
20 if (node.proxyOf.nodes) {
21 for (let i of node.proxyOf.nodes) {
22 markTreeDirty(i)
23 }
24 }
25}
26
27class Container extends Node {
28 get first() {
29 if (!this.proxyOf.nodes) return undefined
30 return this.proxyOf.nodes[0]
31 }
32
33 get last() {
34 if (!this.proxyOf.nodes) return undefined
35 return this.proxyOf.nodes[this.proxyOf.nodes.length - 1]
36 }
37
38 append(...children) {
39 for (let child of children) {
40 let nodes = this.normalize(child, this.last)
41 for (let node of nodes) this.proxyOf.nodes.push(node)
42 }
43
44 this.markDirty()
45
46 return this
47 }
48
49 cleanRaws(keepBetween) {
50 super.cleanRaws(keepBetween)
51 if (this.nodes) {
52 for (let node of this.nodes) node.cleanRaws(keepBetween)
53 }
54 }
55
56 each(callback) {
57 if (!this.proxyOf.nodes) return undefined
58 let iterator = this.getIterator()
59
60 let index, result
61 while (this.indexes[iterator] < this.proxyOf.nodes.length) {
62 index = this.indexes[iterator]
63 result = callback(this.proxyOf.nodes[index], index)
64 if (result === false) break
65
66 this.indexes[iterator] += 1
67 }
68
69 delete this.indexes[iterator]
70 return result
71 }
72
73 every(condition) {
74 return this.nodes.every(condition)
75 }
76
77 getIterator() {
78 if (!this.lastEach) this.lastEach = 0
79 if (!this.indexes) this.indexes = {}
80
81 this.lastEach += 1
82 let iterator = this.lastEach
83 this.indexes[iterator] = 0
84
85 return iterator
86 }
87
88 getProxyProcessor() {
89 return {
90 get(node, prop) {
91 if (prop === 'proxyOf') {
92 return node
93 } else if (!node[prop]) {
94 return node[prop]
95 } else if (
96 prop === 'each' ||
97 (typeof prop === 'string' && prop.startsWith('walk'))
98 ) {
99 return (...args) => {
100 return node[prop](
101 ...args.map(i => {
102 if (typeof i === 'function') {
103 return (child, index) => i(child.toProxy(), index)
104 } else {
105 return i
106 }
107 })
108 )
109 }
110 } else if (prop === 'every' || prop === 'some') {
111 return cb => {
112 return node[prop]((child, ...other) =>
113 cb(child.toProxy(), ...other)
114 )
115 }
116 } else if (prop === 'root') {
117 return () => node.root().toProxy()
118 } else if (prop === 'nodes') {
119 return node.nodes.map(i => i.toProxy())
120 } else if (prop === 'first' || prop === 'last') {
121 return node[prop].toProxy()
122 } else {
123 return node[prop]
124 }
125 },
126
127 set(node, prop, value) {
128 if (node[prop] === value) return true
129 node[prop] = value
130 if (prop === 'name' || prop === 'params' || prop === 'selector') {
131 node.markDirty()
132 }
133 return true
134 }
135 }
136 }
137
138 index(child) {
139 if (typeof child === 'number') return child
140 if (child.proxyOf) child = child.proxyOf
141 return this.proxyOf.nodes.indexOf(child)
142 }
143
144 insertAfter(exist, add) {
145 let existIndex = this.index(exist)
146 let nodes = this.normalize(add, this.proxyOf.nodes[existIndex]).reverse()
147 existIndex = this.index(exist)
148 for (let node of nodes) this.proxyOf.nodes.splice(existIndex + 1, 0, node)
149
150 let index
151 for (let id in this.indexes) {
152 index = this.indexes[id]
153 if (existIndex < index) {
154 this.indexes[id] = index + nodes.length
155 }
156 }
157
158 this.markDirty()
159
160 return this
161 }
162
163 insertBefore(exist, add) {
164 let existIndex = this.index(exist)
165 let type = existIndex === 0 ? 'prepend' : false
166 let nodes = this.normalize(
167 add,
168 this.proxyOf.nodes[existIndex],
169 type
170 ).reverse()
171 existIndex = this.index(exist)
172 for (let node of nodes) this.proxyOf.nodes.splice(existIndex, 0, node)
173
174 let index
175 for (let id in this.indexes) {
176 index = this.indexes[id]
177 if (existIndex <= index) {
178 this.indexes[id] = index + nodes.length
179 }
180 }
181
182 this.markDirty()
183
184 return this
185 }
186
187 normalize(nodes, sample) {
188 if (typeof nodes === 'string') {
189 nodes = cleanSource(parse(nodes).nodes)
190 } else if (typeof nodes === 'undefined') {
191 nodes = []
192 } else if (Array.isArray(nodes)) {
193 nodes = nodes.slice(0)
194 for (let i of nodes) {
195 if (i.parent) i.parent.removeChild(i, 'ignore')
196 }
197 } else if (nodes.type === 'root' && this.type !== 'document') {
198 nodes = nodes.nodes.slice(0)
199 for (let i of nodes) {
200 if (i.parent) i.parent.removeChild(i, 'ignore')
201 }
202 } else if (nodes.type) {
203 nodes = [nodes]
204 } else if (nodes.prop) {
205 if (typeof nodes.value === 'undefined') {
206 throw new Error('Value field is missed in node creation')
207 } else if (typeof nodes.value !== 'string') {
208 nodes.value = String(nodes.value)
209 }
210 nodes = [new Declaration(nodes)]
211 } else if (nodes.selector || nodes.selectors) {
212 nodes = [new Rule(nodes)]
213 } else if (nodes.name) {
214 nodes = [new AtRule(nodes)]
215 } else if (nodes.text) {
216 nodes = [new Comment(nodes)]
217 } else {
218 throw new Error('Unknown node type in node creation')
219 }
220
221 let processed = nodes.map(i => {
222 /* c8 ignore next */
223 if (!i[my]) Container.rebuild(i)
224 i = i.proxyOf
225 if (i.parent) i.parent.removeChild(i)
226 if (i[isClean]) markTreeDirty(i)
227
228 if (!i.raws) i.raws = {}
229 if (typeof i.raws.before === 'undefined') {
230 if (sample && typeof sample.raws.before !== 'undefined') {
231 i.raws.before = sample.raws.before.replace(/\S/g, '')
232 }
233 }
234 i.parent = this.proxyOf
235 return i
236 })
237
238 return processed
239 }
240
241 prepend(...children) {
242 children = children.reverse()
243 for (let child of children) {
244 let nodes = this.normalize(child, this.first, 'prepend').reverse()
245 for (let node of nodes) this.proxyOf.nodes.unshift(node)
246 for (let id in this.indexes) {
247 this.indexes[id] = this.indexes[id] + nodes.length
248 }
249 }
250
251 this.markDirty()
252
253 return this
254 }
255
256 push(child) {
257 child.parent = this
258 this.proxyOf.nodes.push(child)
259 return this
260 }
261
262 removeAll() {
263 for (let node of this.proxyOf.nodes) node.parent = undefined
264 this.proxyOf.nodes = []
265
266 this.markDirty()
267
268 return this
269 }
270
271 removeChild(child) {
272 child = this.index(child)
273 this.proxyOf.nodes[child].parent = undefined
274 this.proxyOf.nodes.splice(child, 1)
275
276 let index
277 for (let id in this.indexes) {
278 index = this.indexes[id]
279 if (index >= child) {
280 this.indexes[id] = index - 1
281 }
282 }
283
284 this.markDirty()
285
286 return this
287 }
288
289 replaceValues(pattern, opts, callback) {
290 if (!callback) {
291 callback = opts
292 opts = {}
293 }
294
295 this.walkDecls(decl => {
296 if (opts.props && !opts.props.includes(decl.prop)) return
297 if (opts.fast && !decl.value.includes(opts.fast)) return
298
299 decl.value = decl.value.replace(pattern, callback)
300 })
301
302 this.markDirty()
303
304 return this
305 }
306
307 some(condition) {
308 return this.nodes.some(condition)
309 }
310
311 walk(callback) {
312 return this.each((child, i) => {
313 let result
314 try {
315 result = callback(child, i)
316 } catch (e) {
317 throw child.addToError(e)
318 }
319 if (result !== false && child.walk) {
320 result = child.walk(callback)
321 }
322
323 return result
324 })
325 }
326
327 walkAtRules(name, callback) {
328 if (!callback) {
329 callback = name
330 return this.walk((child, i) => {
331 if (child.type === 'atrule') {
332 return callback(child, i)
333 }
334 })
335 }
336 if (name instanceof RegExp) {
337 return this.walk((child, i) => {
338 if (child.type === 'atrule' && name.test(child.name)) {
339 return callback(child, i)
340 }
341 })
342 }
343 return this.walk((child, i) => {
344 if (child.type === 'atrule' && child.name === name) {
345 return callback(child, i)
346 }
347 })
348 }
349
350 walkComments(callback) {
351 return this.walk((child, i) => {
352 if (child.type === 'comment') {
353 return callback(child, i)
354 }
355 })
356 }
357
358 walkDecls(prop, callback) {
359 if (!callback) {
360 callback = prop
361 return this.walk((child, i) => {
362 if (child.type === 'decl') {
363 return callback(child, i)
364 }
365 })
366 }
367 if (prop instanceof RegExp) {
368 return this.walk((child, i) => {
369 if (child.type === 'decl' && prop.test(child.prop)) {
370 return callback(child, i)
371 }
372 })
373 }
374 return this.walk((child, i) => {
375 if (child.type === 'decl' && child.prop === prop) {
376 return callback(child, i)
377 }
378 })
379 }
380
381 walkRules(selector, callback) {
382 if (!callback) {
383 callback = selector
384
385 return this.walk((child, i) => {
386 if (child.type === 'rule') {
387 return callback(child, i)
388 }
389 })
390 }
391 if (selector instanceof RegExp) {
392 return this.walk((child, i) => {
393 if (child.type === 'rule' && selector.test(child.selector)) {
394 return callback(child, i)
395 }
396 })
397 }
398 return this.walk((child, i) => {
399 if (child.type === 'rule' && child.selector === selector) {
400 return callback(child, i)
401 }
402 })
403 }
404}
405
406Container.registerParse = dependant => {
407 parse = dependant
408}
409
410Container.registerRule = dependant => {
411 Rule = dependant
412}
413
414Container.registerAtRule = dependant => {
415 AtRule = dependant
416}
417
418Container.registerRoot = dependant => {
419 Root = dependant
420}
421
422module.exports = Container
423Container.default = Container
424
425/* c8 ignore start */
426Container.rebuild = node => {
427 if (node.type === 'atrule') {
428 Object.setPrototypeOf(node, AtRule.prototype)
429 } else if (node.type === 'rule') {
430 Object.setPrototypeOf(node, Rule.prototype)
431 } else if (node.type === 'decl') {
432 Object.setPrototypeOf(node, Declaration.prototype)
433 } else if (node.type === 'comment') {
434 Object.setPrototypeOf(node, Comment.prototype)
435 } else if (node.type === 'root') {
436 Object.setPrototypeOf(node, Root.prototype)
437 }
438
439 node[my] = true
440
441 if (node.nodes) {
442 node.nodes.forEach(child => {
443 Container.rebuild(child)
444 })
445 }
446}
447/* c8 ignore stop */
Note: See TracBrowser for help on using the repository browser.