CoolFace
Apppublic

AK-21/Graphite-Industrial-Intelligence

sourceHugging Faceupdated 3mo agoView on Hugging Face
0likes
node.js457 linesDownload Raw Back to lib
1'use strict'2 3let CssSyntaxError = require('./css-syntax-error')4let Stringifier = require('./stringifier')5let stringify = require('./stringify')6let { isClean, my } = require('./symbols')7 8function cloneNode(obj, parent) {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      continue15    }16    if (i === 'proxyCache') continue17    let value = obj[i]18    let type = typeof value19 20    if (i === 'parent' && type === 'object') {21      if (parent) cloned[i] = parent22    } else if (i === 'source') {23      cloned[i] = value24    } 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] = value29    }30  }31 32  return cloned33}34 35function sourceOffset(inputCSS, position) {36  // Not all custom syntaxes support `offset` in `source.start` and `source.end`37  if (position && typeof position.offset !== 'undefined') {38    return position.offset39  }40 41  let column = 142  let line = 143  let offset = 044 45  for (let i = 0; i < inputCSS.length; i++) {46    if (line === position.line && column === position.column) {47      offset = i48      break49    }50 51    if (inputCSS[i] === '\n') {52      column = 153      line += 154    } else {55      column += 156    }57  }58 59  return offset60}61 62class Node {63  get proxyOf() {64    return this65  }66 67  constructor(defaults = {}) {68    this.raws = {}69    this[isClean] = false70    this[my] = true71 72    for (let name in defaults) {73      if (name === 'nodes') {74        this.nodes = []75        for (let node of defaults[name]) {76          // Clone only nodes that already belong to another tree, so passing a77          // freshly created (parent-less) node adopts that instance instead of78          // a copy and keeps the caller's reference usable. See #1987.79          if (typeof node.clone === 'function' && node.parent) {80            this.append(node.clone())81          } else {82            this.append(node)83          }84        }85      } else {86        this[name] = defaults[name]87      }88    }89  }90 91  addToError(error) {92    error.postcssNode = this93    if (error.stack && this.source && /\n\s{4}at /.test(error.stack)) {94      let s = this.source95      error.stack = error.stack.replace(96        /\n\s{4}at /,97        `$&${s.input.from}:${s.start.line}:${s.start.column}$&`98      )99    }100    return error101  }102 103  after(add) {104    this.parent.insertAfter(this, add)105    return this106  }107 108  assign(overrides = {}) {109    for (let name in overrides) {110      this[name] = overrides[name]111    }112    return this113  }114 115  before(add) {116    this.parent.insertBefore(this, add)117    return this118  }119 120  cleanRaws(keepBetween) {121    delete this.raws.before122    delete this.raws.after123    if (!keepBetween) delete this.raws.between124  }125 126  clone(overrides = {}) {127    let cloned = cloneNode(this)128    for (let name in overrides) {129      cloned[name] = overrides[name]130    }131    return cloned132  }133 134  cloneAfter(overrides = {}) {135    let cloned = this.clone(overrides)136    this.parent.insertAfter(this, cloned)137    return cloned138  }139 140  cloneBefore(overrides = {}) {141    let cloned = this.clone(overrides)142    this.parent.insertBefore(this, cloned)143    return cloned144  }145 146  error(message, opts = {}) {147    if (this.source) {148      let { end, start } = this.rangeBy(opts)149      return this.source.input.error(150        message,151        { column: start.column, line: start.line },152        { column: end.column, line: end.line },153        opts154      )155    }156    return new CssSyntaxError(message)157  }158 159  getProxyProcessor() {160    return {161      get(node, prop) {162        if (prop === 'proxyOf') {163          return node164        } else if (prop === 'root') {165          return () => node.root().toProxy()166        } else {167          return node[prop]168        }169      },170 171      set(node, prop, value) {172        if (node[prop] === value) return true173        node[prop] = value174        if (175          prop === 'prop' ||176          prop === 'value' ||177          prop === 'name' ||178          prop === 'params' ||179          prop === 'important' ||180          /* c8 ignore next */181          prop === 'text'182        ) {183          node.markDirty()184        }185        return true186      }187    }188  }189 190  /* c8 ignore next 3 */191  markClean() {192    this[isClean] = true193  }194 195  markDirty() {196    if (this[isClean]) {197      this[isClean] = false198      let next = this199      while ((next = next.parent)) {200        next[isClean] = false201      }202    }203  }204 205  next() {206    if (!this.parent) return undefined207    let index = this.parent.index(this)208    return this.parent.nodes[index + 1]209  }210 211  positionBy(opts = {}) {212    let inputString =213      'document' in this.source.input214        ? this.source.input.document215        : this.source.input.css216    let pos = {217      column: this.source.start.column,218      line: this.source.start.line,219      offset: sourceOffset(inputString, this.source.start)220    }221    if (opts.index) {222      pos = this.positionInside(opts.index)223    } else if (opts.word) {224      let stringRepresentation = inputString.slice(225        sourceOffset(inputString, this.source.start),226        sourceOffset(inputString, this.source.end)227      )228      let index = stringRepresentation.indexOf(opts.word)229      if (index !== -1) pos = this.positionInside(index)230    }231    return pos232  }233 234  positionInside(index) {235    let column = this.source.start.column236    let line = this.source.start.line237    let inputString =238      'document' in this.source.input239        ? this.source.input.document240        : this.source.input.css241    let offset = sourceOffset(inputString, this.source.start)242    let end = offset + index243 244    for (let i = offset; i < end; i++) {245      if (inputString[i] === '\n') {246        column = 1247        line += 1248      } else {249        column += 1250      }251    }252 253    return { column, line, offset: end }254  }255 256  prev() {257    if (!this.parent) return undefined258    let index = this.parent.index(this)259    return this.parent.nodes[index - 1]260  }261 262  rangeBy(opts = {}) {263    let inputString =264      'document' in this.source.input265        ? this.source.input.document266        : this.source.input.css267    let start = {268      column: this.source.start.column,269      line: this.source.start.line,270      offset: sourceOffset(inputString, this.source.start)271    }272    let end = this.source.end273      ? {274          column: this.source.end.column + 1,275          line: this.source.end.line,276          offset:277            typeof this.source.end.offset === 'number'278              ? // `source.end.offset` is exclusive, so we don't need to add 1279                this.source.end.offset280              : // Since line/column in this.source.end is inclusive,281                // the `sourceOffset(... , this.source.end)` returns an inclusive offset.282                // So, we add 1 to convert it to exclusive.283                sourceOffset(inputString, this.source.end) + 1284        }285      : {286          column: start.column + 1,287          line: start.line,288          offset: start.offset + 1289        }290 291    if (opts.word) {292      let stringRepresentation = inputString.slice(293        sourceOffset(inputString, this.source.start),294        sourceOffset(inputString, this.source.end)295      )296      let index = stringRepresentation.indexOf(opts.word)297      if (index !== -1) {298        start = this.positionInside(index)299        end = this.positionInside(index + opts.word.length)300      }301    } else {302      if (opts.start) {303        start = {304          column: opts.start.column,305          line: opts.start.line,306          offset: sourceOffset(inputString, opts.start)307        }308      } else if (typeof opts.index === 'number') {309        start = this.positionInside(opts.index)310      }311 312      if (opts.end) {313        end = {314          column: opts.end.column,315          line: opts.end.line,316          offset: sourceOffset(inputString, opts.end)317        }318      } else if (typeof opts.endIndex === 'number') {319        end = this.positionInside(opts.endIndex)320      } else if (typeof opts.index === 'number') {321        end = this.positionInside(opts.index + 1)322      }323    }324 325    if (326      end.line < start.line ||327      (end.line === start.line && end.column <= start.column)328    ) {329      end = {330        column: start.column + 1,331        line: start.line,332        offset: start.offset + 1333      }334    }335 336    return { end, start }337  }338 339  raw(prop, defaultType) {340    let str = new Stringifier()341    return str.raw(this, prop, defaultType)342  }343 344  remove() {345    if (this.parent) {346      this.parent.removeChild(this)347    }348    this.parent = undefined349    return this350  }351 352  replaceWith(...nodes) {353    if (this.parent) {354      let bookmark = this355      let foundSelf = false356      for (let node of nodes) {357        if (node === this) {358          foundSelf = true359        } else if (foundSelf) {360          this.parent.insertAfter(bookmark, node)361          bookmark = node362        } else {363          this.parent.insertBefore(bookmark, node)364        }365      }366 367      if (!foundSelf) {368        this.remove()369      }370    }371 372    return this373  }374 375  root() {376    let result = this377    while (result.parent && result.parent.type !== 'document') {378      result = result.parent379    }380    return result381  }382 383  toJSON(_, inputs) {384    let fixed = {}385    let emitInputs = inputs == null386    inputs = inputs || new Map()387    let inputsNextIndex = 0388 389    for (let name in this) {390      if (!Object.prototype.hasOwnProperty.call(this, name)) {391        /* c8 ignore next 2 */392        continue393      }394      if (name === 'parent' || name === 'proxyCache') continue395      let value = this[name]396 397      if (Array.isArray(value)) {398        fixed[name] = value.map(i => {399          if (typeof i === 'object' && i.toJSON) {400            return i.toJSON(null, inputs)401          } else {402            return i403          }404        })405      } else if (typeof value === 'object' && value.toJSON) {406        fixed[name] = value.toJSON(null, inputs)407      } else if (name === 'source') {408        if (value == null) continue409        let inputId = inputs.get(value.input)410        if (inputId == null) {411          inputId = inputsNextIndex412          inputs.set(value.input, inputsNextIndex)413          inputsNextIndex++414        }415        fixed[name] = {416          end: value.end,417          inputId,418          start: value.start419        }420      } else {421        fixed[name] = value422      }423    }424 425    if (emitInputs) {426      fixed.inputs = [...inputs.keys()].map(input => input.toJSON())427    }428 429    return fixed430  }431 432  toProxy() {433    if (!this.proxyCache) {434      this.proxyCache = new Proxy(this, this.getProxyProcessor())435    }436    return this.proxyCache437  }438 439  toString(stringifier = stringify) {440    if (stringifier.stringify) stringifier = stringifier.stringify441    let result = ''442    stringifier(this, i => {443      result += i444    })445    return result446  }447 448  warn(result, text, opts = {}) {449    let data = { node: this }450    for (let i in opts) data[i] = opts[i]451    return result.warn(text, data)452  }453}454 455module.exports = Node456Node.default = Node457