| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379 | 'use strict'let { isClean, my } = require('./symbols')let CssSyntaxError = require('./css-syntax-error')let Stringifier = require('./stringifier')let stringify = require('./stringify')function cloneNode(obj, parent) {  let cloned = new obj.constructor()  for (let i in obj) {    if (!Object.prototype.hasOwnProperty.call(obj, i)) {      /* c8 ignore next 2 */      continue    }    if (i === 'proxyCache') continue    let value = obj[i]    let type = typeof value    if (i === 'parent' && type === 'object') {      if (parent) cloned[i] = parent    } else if (i === 'source') {      cloned[i] = value    } else if (Array.isArray(value)) {      cloned[i] = value.map(j => cloneNode(j, cloned))    } else {      if (type === 'object' && value !== null) value = cloneNode(value)      cloned[i] = value    }  }  return cloned}class Node {  constructor(defaults = {}) {    this.raws = {}    this[isClean] = false    this[my] = true    for (let name in defaults) {      if (name === 'nodes') {        this.nodes = []        for (let node of defaults[name]) {          if (typeof node.clone === 'function') {            this.append(node.clone())          } else {            this.append(node)          }        }      } else {        this[name] = defaults[name]      }    }  }  error(message, opts = {}) {    if (this.source) {      let { start, end } = this.rangeBy(opts)      return this.source.input.error(        message,        { line: start.line, column: start.column },        { line: end.line, column: end.column },        opts      )    }    return new CssSyntaxError(message)  }  warn(result, text, opts) {    let data = { node: this }    for (let i in opts) data[i] = opts[i]    return result.warn(text, data)  }  remove() {    if (this.parent) {      this.parent.removeChild(this)    }    this.parent = undefined    return this  }  toString(stringifier = stringify) {    if (stringifier.stringify) stringifier = stringifier.stringify    let result = ''    stringifier(this, i => {      result += i    })    return result  }  assign(overrides = {}) {    for (let name in overrides) {      this[name] = overrides[name]    }    return this  }  clone(overrides = {}) {    let cloned = cloneNode(this)    for (let name in overrides) {      cloned[name] = overrides[name]    }    return cloned  }  cloneBefore(overrides = {}) {    let cloned = this.clone(overrides)    this.parent.insertBefore(this, cloned)    return cloned  }  cloneAfter(overrides = {}) {    let cloned = this.clone(overrides)    this.parent.insertAfter(this, cloned)    return cloned  }  replaceWith(...nodes) {    if (this.parent) {      let bookmark = this      let foundSelf = false      for (let node of nodes) {        if (node === this) {          foundSelf = true        } else if (foundSelf) {          this.parent.insertAfter(bookmark, node)          bookmark = node        } else {          this.parent.insertBefore(bookmark, node)        }      }      if (!foundSelf) {        this.remove()      }    }    return this  }  next() {    if (!this.parent) return undefined    let index = this.parent.index(this)    return this.parent.nodes[index + 1]  }  prev() {    if (!this.parent) return undefined    let index = this.parent.index(this)    return this.parent.nodes[index - 1]  }  before(add) {    this.parent.insertBefore(this, add)    return this  }  after(add) {    this.parent.insertAfter(this, add)    return this  }  root() {    let result = this    while (result.parent && result.parent.type !== 'document') {      result = result.parent    }    return result  }  raw(prop, defaultType) {    let str = new Stringifier()    return str.raw(this, prop, defaultType)  }  cleanRaws(keepBetween) {    delete this.raws.before    delete this.raws.after    if (!keepBetween) delete this.raws.between  }  toJSON(_, inputs) {    let fixed = {}    let emitInputs = inputs == null    inputs = inputs || new Map()    let inputsNextIndex = 0    for (let name in this) {      if (!Object.prototype.hasOwnProperty.call(this, name)) {        /* c8 ignore next 2 */        continue      }      if (name === 'parent' || name === 'proxyCache') continue      let value = this[name]      if (Array.isArray(value)) {        fixed[name] = value.map(i => {          if (typeof i === 'object' && i.toJSON) {            return i.toJSON(null, inputs)          } else {            return i          }        })      } else if (typeof value === 'object' && value.toJSON) {        fixed[name] = value.toJSON(null, inputs)      } else if (name === 'source') {        let inputId = inputs.get(value.input)        if (inputId == null) {          inputId = inputsNextIndex          inputs.set(value.input, inputsNextIndex)          inputsNextIndex++        }        fixed[name] = {          inputId,          start: value.start,          end: value.end        }      } else {        fixed[name] = value      }    }    if (emitInputs) {      fixed.inputs = [...inputs.keys()].map(input => input.toJSON())    }    return fixed  }  positionInside(index) {    let string = this.toString()    let column = this.source.start.column    let line = this.source.start.line    for (let i = 0; i < index; i++) {      if (string[i] === '\n') {        column = 1        line += 1      } else {        column += 1      }    }    return { line, column }  }  positionBy(opts) {    let pos = this.source.start    if (opts.index) {      pos = this.positionInside(opts.index)    } else if (opts.word) {      let index = this.toString().indexOf(opts.word)      if (index !== -1) pos = this.positionInside(index)    }    return pos  }  rangeBy(opts) {    let start = {      line: this.source.start.line,      column: this.source.start.column    }    let end = this.source.end      ? {          line: this.source.end.line,          column: this.source.end.column + 1        }      : {          line: start.line,          column: start.column + 1        }    if (opts.word) {      let index = this.toString().indexOf(opts.word)      if (index !== -1) {        start = this.positionInside(index)        end = this.positionInside(index + opts.word.length)      }    } else {      if (opts.start) {        start = {          line: opts.start.line,          column: opts.start.column        }      } else if (opts.index) {        start = this.positionInside(opts.index)      }      if (opts.end) {        end = {          line: opts.end.line,          column: opts.end.column        }      } else if (opts.endIndex) {        end = this.positionInside(opts.endIndex)      } else if (opts.index) {        end = this.positionInside(opts.index + 1)      }    }    if (      end.line < start.line ||      (end.line === start.line && end.column <= start.column)    ) {      end = { line: start.line, column: start.column + 1 }    }    return { start, end }  }  getProxyProcessor() {    return {      set(node, prop, value) {        if (node[prop] === value) return true        node[prop] = value        if (          prop === 'prop' ||          prop === 'value' ||          prop === 'name' ||          prop === 'params' ||          prop === 'important' ||          /* c8 ignore next */          prop === 'text'        ) {          node.markDirty()        }        return true      },      get(node, prop) {        if (prop === 'proxyOf') {          return node        } else if (prop === 'root') {          return () => node.root().toProxy()        } else {          return node[prop]        }      }    }  }  toProxy() {    if (!this.proxyCache) {      this.proxyCache = new Proxy(this, this.getProxyProcessor())    }    return this.proxyCache  }  addToError(error) {    error.postcssNode = this    if (error.stack && this.source && /\n\s{4}at /.test(error.stack)) {      let s = this.source      error.stack = error.stack.replace(        /\n\s{4}at /,        `$&${s.input.from}:${s.start.line}:${s.start.column}$&`      )    }    return error  }  markDirty() {    if (this[isClean]) {      this[isClean] = false      let next = this      while ((next = next.parent)) {        next[isClean] = false      }    }  }  get proxyOf() {    return this  }}module.exports = NodeNode.default = Node
 |