summaryrefslogtreecommitdiff
path: root/node_modules/postcss/lib/stringifier.js
diff options
context:
space:
mode:
authorPhilipp Tanlak <philipp.tanlak@gmail.com>2025-11-24 20:54:57 +0100
committerPhilipp Tanlak <philipp.tanlak@gmail.com>2025-11-24 20:57:48 +0100
commitb1e2c8fd5cb5dfa46bc440a12eafaf56cd844b1c (patch)
tree49d360fd6cbc6a2754efe93524ac47ff0fbe0f7d /node_modules/postcss/lib/stringifier.js
Docs
Diffstat (limited to 'node_modules/postcss/lib/stringifier.js')
-rw-r--r--node_modules/postcss/lib/stringifier.js353
1 files changed, 353 insertions, 0 deletions
diff --git a/node_modules/postcss/lib/stringifier.js b/node_modules/postcss/lib/stringifier.js
new file mode 100644
index 0000000..e07ad12
--- /dev/null
+++ b/node_modules/postcss/lib/stringifier.js
@@ -0,0 +1,353 @@
+'use strict'
+
+const DEFAULT_RAW = {
+ after: '\n',
+ beforeClose: '\n',
+ beforeComment: '\n',
+ beforeDecl: '\n',
+ beforeOpen: ' ',
+ beforeRule: '\n',
+ colon: ': ',
+ commentLeft: ' ',
+ commentRight: ' ',
+ emptyBody: '',
+ indent: ' ',
+ semicolon: false
+}
+
+function capitalize(str) {
+ return str[0].toUpperCase() + str.slice(1)
+}
+
+class Stringifier {
+ constructor(builder) {
+ this.builder = builder
+ }
+
+ atrule(node, semicolon) {
+ let name = '@' + node.name
+ let params = node.params ? this.rawValue(node, 'params') : ''
+
+ if (typeof node.raws.afterName !== 'undefined') {
+ name += node.raws.afterName
+ } else if (params) {
+ name += ' '
+ }
+
+ if (node.nodes) {
+ this.block(node, name + params)
+ } else {
+ let end = (node.raws.between || '') + (semicolon ? ';' : '')
+ this.builder(name + params + end, node)
+ }
+ }
+
+ beforeAfter(node, detect) {
+ let value
+ if (node.type === 'decl') {
+ value = this.raw(node, null, 'beforeDecl')
+ } else if (node.type === 'comment') {
+ value = this.raw(node, null, 'beforeComment')
+ } else if (detect === 'before') {
+ value = this.raw(node, null, 'beforeRule')
+ } else {
+ value = this.raw(node, null, 'beforeClose')
+ }
+
+ let buf = node.parent
+ let depth = 0
+ while (buf && buf.type !== 'root') {
+ depth += 1
+ buf = buf.parent
+ }
+
+ if (value.includes('\n')) {
+ let indent = this.raw(node, null, 'indent')
+ if (indent.length) {
+ for (let step = 0; step < depth; step++) value += indent
+ }
+ }
+
+ return value
+ }
+
+ block(node, start) {
+ let between = this.raw(node, 'between', 'beforeOpen')
+ this.builder(start + between + '{', node, 'start')
+
+ let after
+ if (node.nodes && node.nodes.length) {
+ this.body(node)
+ after = this.raw(node, 'after')
+ } else {
+ after = this.raw(node, 'after', 'emptyBody')
+ }
+
+ if (after) this.builder(after)
+ this.builder('}', node, 'end')
+ }
+
+ body(node) {
+ let last = node.nodes.length - 1
+ while (last > 0) {
+ if (node.nodes[last].type !== 'comment') break
+ last -= 1
+ }
+
+ let semicolon = this.raw(node, 'semicolon')
+ for (let i = 0; i < node.nodes.length; i++) {
+ let child = node.nodes[i]
+ let before = this.raw(child, 'before')
+ if (before) this.builder(before)
+ this.stringify(child, last !== i || semicolon)
+ }
+ }
+
+ comment(node) {
+ let left = this.raw(node, 'left', 'commentLeft')
+ let right = this.raw(node, 'right', 'commentRight')
+ this.builder('/*' + left + node.text + right + '*/', node)
+ }
+
+ decl(node, semicolon) {
+ let between = this.raw(node, 'between', 'colon')
+ let string = node.prop + between + this.rawValue(node, 'value')
+
+ if (node.important) {
+ string += node.raws.important || ' !important'
+ }
+
+ if (semicolon) string += ';'
+ this.builder(string, node)
+ }
+
+ document(node) {
+ this.body(node)
+ }
+
+ raw(node, own, detect) {
+ let value
+ if (!detect) detect = own
+
+ // Already had
+ if (own) {
+ value = node.raws[own]
+ if (typeof value !== 'undefined') return value
+ }
+
+ let parent = node.parent
+
+ if (detect === 'before') {
+ // Hack for first rule in CSS
+ if (!parent || (parent.type === 'root' && parent.first === node)) {
+ return ''
+ }
+
+ // `root` nodes in `document` should use only their own raws
+ if (parent && parent.type === 'document') {
+ return ''
+ }
+ }
+
+ // Floating child without parent
+ if (!parent) return DEFAULT_RAW[detect]
+
+ // Detect style by other nodes
+ let root = node.root()
+ if (!root.rawCache) root.rawCache = {}
+ if (typeof root.rawCache[detect] !== 'undefined') {
+ return root.rawCache[detect]
+ }
+
+ if (detect === 'before' || detect === 'after') {
+ return this.beforeAfter(node, detect)
+ } else {
+ let method = 'raw' + capitalize(detect)
+ if (this[method]) {
+ value = this[method](root, node)
+ } else {
+ root.walk(i => {
+ value = i.raws[own]
+ if (typeof value !== 'undefined') return false
+ })
+ }
+ }
+
+ if (typeof value === 'undefined') value = DEFAULT_RAW[detect]
+
+ root.rawCache[detect] = value
+ return value
+ }
+
+ rawBeforeClose(root) {
+ let value
+ root.walk(i => {
+ if (i.nodes && i.nodes.length > 0) {
+ if (typeof i.raws.after !== 'undefined') {
+ value = i.raws.after
+ if (value.includes('\n')) {
+ value = value.replace(/[^\n]+$/, '')
+ }
+ return false
+ }
+ }
+ })
+ if (value) value = value.replace(/\S/g, '')
+ return value
+ }
+
+ rawBeforeComment(root, node) {
+ let value
+ root.walkComments(i => {
+ if (typeof i.raws.before !== 'undefined') {
+ value = i.raws.before
+ if (value.includes('\n')) {
+ value = value.replace(/[^\n]+$/, '')
+ }
+ return false
+ }
+ })
+ if (typeof value === 'undefined') {
+ value = this.raw(node, null, 'beforeDecl')
+ } else if (value) {
+ value = value.replace(/\S/g, '')
+ }
+ return value
+ }
+
+ rawBeforeDecl(root, node) {
+ let value
+ root.walkDecls(i => {
+ if (typeof i.raws.before !== 'undefined') {
+ value = i.raws.before
+ if (value.includes('\n')) {
+ value = value.replace(/[^\n]+$/, '')
+ }
+ return false
+ }
+ })
+ if (typeof value === 'undefined') {
+ value = this.raw(node, null, 'beforeRule')
+ } else if (value) {
+ value = value.replace(/\S/g, '')
+ }
+ return value
+ }
+
+ rawBeforeOpen(root) {
+ let value
+ root.walk(i => {
+ if (i.type !== 'decl') {
+ value = i.raws.between
+ if (typeof value !== 'undefined') return false
+ }
+ })
+ return value
+ }
+
+ rawBeforeRule(root) {
+ let value
+ root.walk(i => {
+ if (i.nodes && (i.parent !== root || root.first !== i)) {
+ if (typeof i.raws.before !== 'undefined') {
+ value = i.raws.before
+ if (value.includes('\n')) {
+ value = value.replace(/[^\n]+$/, '')
+ }
+ return false
+ }
+ }
+ })
+ if (value) value = value.replace(/\S/g, '')
+ return value
+ }
+
+ rawColon(root) {
+ let value
+ root.walkDecls(i => {
+ if (typeof i.raws.between !== 'undefined') {
+ value = i.raws.between.replace(/[^\s:]/g, '')
+ return false
+ }
+ })
+ return value
+ }
+
+ rawEmptyBody(root) {
+ let value
+ root.walk(i => {
+ if (i.nodes && i.nodes.length === 0) {
+ value = i.raws.after
+ if (typeof value !== 'undefined') return false
+ }
+ })
+ return value
+ }
+
+ rawIndent(root) {
+ if (root.raws.indent) return root.raws.indent
+ let value
+ root.walk(i => {
+ let p = i.parent
+ if (p && p !== root && p.parent && p.parent === root) {
+ if (typeof i.raws.before !== 'undefined') {
+ let parts = i.raws.before.split('\n')
+ value = parts[parts.length - 1]
+ value = value.replace(/\S/g, '')
+ return false
+ }
+ }
+ })
+ return value
+ }
+
+ rawSemicolon(root) {
+ let value
+ root.walk(i => {
+ if (i.nodes && i.nodes.length && i.last.type === 'decl') {
+ value = i.raws.semicolon
+ if (typeof value !== 'undefined') return false
+ }
+ })
+ return value
+ }
+
+ rawValue(node, prop) {
+ let value = node[prop]
+ let raw = node.raws[prop]
+ if (raw && raw.value === value) {
+ return raw.raw
+ }
+
+ return value
+ }
+
+ root(node) {
+ this.body(node)
+ if (node.raws.after) this.builder(node.raws.after)
+ }
+
+ rule(node) {
+ this.block(node, this.rawValue(node, 'selector'))
+ if (node.raws.ownSemicolon) {
+ this.builder(node.raws.ownSemicolon, node, 'end')
+ }
+ }
+
+ stringify(node, semicolon) {
+ /* c8 ignore start */
+ if (!this[node.type]) {
+ throw new Error(
+ 'Unknown AST node type ' +
+ node.type +
+ '. ' +
+ 'Maybe you need to change PostCSS stringifier.'
+ )
+ }
+ /* c8 ignore stop */
+ this[node.type](node, semicolon)
+ }
+}
+
+module.exports = Stringifier
+Stringifier.default = Stringifier