source: imaps-frontend/node_modules/postcss/lib/container.js@ d565449

main
Last change on this file since d565449 was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

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