AK-21/Graphite-Industrial-Intelligence
0
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, Rule9 10function cleanSource(nodes) {11 return nodes.map(i => {12 if (i.nodes) i.nodes = cleanSource(i.nodes)13 delete i.source14 return i15 })16}17 18function markTreeDirty(node) {19 node[isClean] = false20 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 undefined30 return this.proxyOf.nodes[0]31 }32 33 get last() {34 if (!this.proxyOf.nodes) return undefined35 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 this47 }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 undefined58 let iterator = this.getIterator()59 60 let index, result61 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) break65 66 this.indexes[iterator] += 167 }68 69 delete this.indexes[iterator]70 return result71 }72 73 every(condition) {74 return this.nodes.every(condition)75 }76 77 getIterator() {78 if (!this.lastEach) this.lastEach = 079 if (!this.indexes) this.indexes = {}80 81 this.lastEach += 182 let iterator = this.lastEach83 this.indexes[iterator] = 084 85 return iterator86 }87 88 getProxyProcessor() {89 return {90 get(node, prop) {91 if (prop === 'proxyOf') {92 return node93 } 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 i106 }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 true129 node[prop] = value130 if (prop === 'name' || prop === 'params' || prop === 'selector') {131 node.markDirty()132 }133 return true134 }135 }136 }137 138 index(child) {139 if (typeof child === 'number') return child140 if (child.proxyOf) child = child.proxyOf141 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 index151 for (let id in this.indexes) {152 index = this.indexes[id]153 if (existIndex < index) {154 this.indexes[id] = index + nodes.length155 }156 }157 158 this.markDirty()159 160 return this161 }162 163 insertBefore(exist, add) {164 let existIndex = this.index(exist)165 let type = existIndex === 0 ? 'prepend' : false166 let nodes = this.normalize(167 add,168 this.proxyOf.nodes[existIndex],169 type170 ).reverse()171 existIndex = this.index(exist)172 for (let node of nodes) this.proxyOf.nodes.splice(existIndex, 0, node)173 174 let index175 for (let id in this.indexes) {176 index = this.indexes[id]177 if (existIndex <= index) {178 this.indexes[id] = index + nodes.length179 }180 }181 182 this.markDirty()183 184 return this185 }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.proxyOf225 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.proxyOf235 return i236 })237 238 return processed239 }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.length248 }249 }250 251 this.markDirty()252 253 return this254 }255 256 push(child) {257 child.parent = this258 this.proxyOf.nodes.push(child)259 return this260 }261 262 removeAll() {263 for (let node of this.proxyOf.nodes) node.parent = undefined264 this.proxyOf.nodes = []265 266 this.markDirty()267 268 return this269 }270 271 removeChild(child) {272 child = this.index(child)273 this.proxyOf.nodes[child].parent = undefined274 this.proxyOf.nodes.splice(child, 1)275 276 let index277 for (let id in this.indexes) {278 index = this.indexes[id]279 if (index >= child) {280 this.indexes[id] = index - 1281 }282 }283 284 this.markDirty()285 286 return this287 }288 289 replaceValues(pattern, opts, callback) {290 if (!callback) {291 callback = opts292 opts = {}293 }294 295 this.walkDecls(decl => {296 if (opts.props && !opts.props.includes(decl.prop)) return297 if (opts.fast && !decl.value.includes(opts.fast)) return298 299 decl.value = decl.value.replace(pattern, callback)300 })301 302 this.markDirty()303 304 return this305 }306 307 some(condition) {308 return this.nodes.some(condition)309 }310 311 walk(callback) {312 return this.each((child, i) => {313 let result314 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 result324 })325 }326 327 walkAtRules(name, callback) {328 if (!callback) {329 callback = name330 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 = prop361 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 = selector384 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 = dependant408}409 410Container.registerRule = dependant => {411 Rule = dependant412}413 414Container.registerAtRule = dependant => {415 AtRule = dependant416}417 418Container.registerRoot = dependant => {419 Root = dependant420}421 422module.exports = Container423Container.default = Container424 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] = true440 441 if (node.nodes) {442 node.nodes.forEach(child => {443 Container.rebuild(child)444 })445 }446}447/* c8 ignore stop */448 