This repository has been archived on 2020-11-02. You can view files and clone it, but cannot push or open issues or pull requests.
TripSit_Suite/node_modules/postcss/lib/node.js
2020-11-01 22:46:04 +00:00

291 lines
6.1 KiB
JavaScript

'use strict'
let CssSyntaxError = require('./css-syntax-error')
let Stringifier = require('./stringifier')
let { isClean } = require('./symbols')
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)) {
// istanbul ignore next
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
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 pos = this.positionBy(opts)
return this.source.input.error(message, pos.line, pos.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
}
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 = 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 () {
let fixed = {}
for (let name in this) {
if (!Object.prototype.hasOwnProperty.call(this, name)) {
// istanbul ignore next
continue
}
if (name === 'parent') continue
let value = this[name]
if (Array.isArray(value)) {
fixed[name] = value.map(i => {
if (typeof i === 'object' && i.toJSON) {
return i.toJSON()
} else {
return i
}
})
} else if (typeof value === 'object' && value.toJSON) {
fixed[name] = value.toJSON()
} else {
fixed[name] = value
}
}
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
}
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' ||
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 = Node