Socket
Socket
Sign inDemoInstall

postcss

Package Overview
Dependencies
3
Maintainers
1
Versions
252
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 8.4.24 to 8.4.25

38

lib/at-rule.d.ts

@@ -6,8 +6,2 @@ import Container, { ContainerProps } from './container.js'

/**
* The space symbols before the node. It also stores `*`
* and `_` symbols before the declaration (IE hack).
*/
before?: string
/**
* The space symbols after the last child of the node to the end of the node.

@@ -23,10 +17,11 @@ */

/**
* The symbols between the last parameter and `{` for rules.
* The space symbols before the node. It also stores `*`
* and `_` symbols before the declaration (IE hack).
*/
between?: string
before?: string
/**
* Contains `true` if the last child has an (optional) semicolon.
* The symbols between the last parameter and `{` for rules.
*/
semicolon?: boolean
between?: string

@@ -37,5 +32,10 @@ /**

params?: {
raw: string
value: string
raw: string
}
/**
* Contains `true` if the last child has an (optional) semicolon.
*/
semicolon?: boolean
}

@@ -47,3 +47,3 @@

/** Parameters following the name of the at-rule. */
params?: string | number
params?: number | string
/** Information used to generate byte-to-byte equal node string as it was in the origin input. */

@@ -83,6 +83,2 @@ raws?: AtRuleRaws

declare class AtRule_ extends Container {
type: 'atrule'
parent: Container | undefined
raws: AtRule.AtRuleRaws
/**

@@ -98,3 +94,2 @@ * The at-rule’s name immediately follows the `@`.

name: string
/**

@@ -111,8 +106,13 @@ * The at-rule’s parameters, the values that follow the at-rule’s name

params: string
parent: Container | undefined
raws: AtRule.AtRuleRaws
type: 'atrule'
constructor(defaults?: AtRule.AtRuleProps)
assign(overrides: object | AtRule.AtRuleProps): this
assign(overrides: AtRule.AtRuleProps | object): this
clone(overrides?: Partial<AtRule.AtRuleProps>): this
cloneAfter(overrides?: Partial<AtRule.AtRuleProps>): this
cloneBefore(overrides?: Partial<AtRule.AtRuleProps>): this
cloneAfter(overrides?: Partial<AtRule.AtRuleProps>): this
}

@@ -119,0 +119,0 @@

@@ -23,6 +23,6 @@ import Container from './container.js'

export interface CommentProps extends NodeProps {
/** Information used to generate byte-to-byte equal node string as it was in the origin input. */
raws?: CommentRaws
/** Content of the comment. */
text: string
/** Information used to generate byte-to-byte equal node string as it was in the origin input. */
raws?: CommentRaws
}

@@ -35,7 +35,8 @@

/**
* Represents a comment between declarations or statements (rule and at-rules).
* It represents a class that handles
* [CSS comments](https://developer.mozilla.org/en-US/docs/Web/CSS/Comments)
*
* ```js
* Once (root, { Comment }) {
* let note = new Comment({ text: 'Note: …' })
* const note = new Comment({ text: 'Note: …' })
* root.append(note)

@@ -45,10 +46,9 @@ * }

*
* Comments inside selectors, at-rule parameters, or declaration values
* will be stored in the `raws` properties explained above.
* Remember that CSS comments inside selectors, at-rule parameters,
* or declaration values will be stored in the `raws` properties
* explained above.
*/
declare class Comment_ extends Node {
type: 'comment'
parent: Container | undefined
raws: Comment.CommentRaws
/**

@@ -59,7 +59,9 @@ * The comment's text.

type: 'comment'
constructor(defaults?: Comment.CommentProps)
assign(overrides: object | Comment.CommentProps): this
assign(overrides: Comment.CommentProps | object): this
clone(overrides?: Partial<Comment.CommentProps>): this
cloneAfter(overrides?: Partial<Comment.CommentProps>): this
cloneBefore(overrides?: Partial<Comment.CommentProps>): this
cloneAfter(overrides?: Partial<Comment.CommentProps>): this
}

@@ -66,0 +68,0 @@

@@ -1,5 +0,5 @@

import Node, { ChildNode, NodeProps, ChildProps } from './node.js'
import AtRule from './at-rule.js'
import Comment from './comment.js'
import Declaration from './declaration.js'
import Comment from './comment.js'
import AtRule from './at-rule.js'
import Node, { ChildNode, ChildProps, NodeProps } from './node.js'
import Rule from './rule.js'

@@ -10,10 +10,10 @@

/**
* An array of property names.
* String that’s used to narrow down values and speed up the regexp search.
*/
props?: string[]
fast?: string
/**
* String that’s used to narrow down values and speed up the regexp search.
* An array of property names.
*/
fast?: string
props?: string[]
}

@@ -52,18 +52,24 @@

/**
* The container’s first child.
* Inserts new nodes to the end of the container.
*
* ```js
* rule.first === rules.nodes[0]
* const decl1 = new Declaration({ prop: 'color', value: 'black' })
* const decl2 = new Declaration({ prop: 'background-color', value: 'white' })
* rule.append(decl1, decl2)
*
* root.append({ name: 'charset', params: '"UTF-8"' }) // at-rule
* root.append({ selector: 'a' }) // rule
* rule.append({ prop: 'color', value: 'black' }) // declaration
* rule.append({ text: 'Comment' }) // comment
*
* root.append('a {}')
* root.first.append('color: black; z-index: 1')
* ```
*/
get first(): Child | undefined
/**
* The container’s last child.
*
* ```js
* rule.last === rule.nodes[rule.nodes.length - 1]
* ```
* @param nodes New nodes.
* @return This node for methods chain.
*/
get last(): Child | undefined
append(
...nodes: (ChildProps | ChildProps[] | Node | Node[] | string | string[])[]
): this

@@ -108,175 +114,71 @@ /**

/**
* Traverses the container’s descendant nodes, calling callback
* for each node.
* Returns `true` if callback returns `true`
* for all of the container’s children.
*
* Like container.each(), this method is safe to use
* if you are mutating arrays during iteration.
*
* If you only need to iterate through the container’s immediate children,
* use `Container#each`.
*
* ```js
* root.walk(node => {
* // Traverses all descendant nodes.
* })
* const noPrefixes = rule.every(i => i.prop[0] !== '-')
* ```
*
* @param callback Iterator receives each node and index.
* @return Returns `false` if iteration was broke.
* @param condition Iterator returns true or false.
* @return Is every child pass condition.
*/
walk(
callback: (node: ChildNode, index: number) => false | void
): false | undefined
every(
condition: (node: Child, index: number, nodes: Child[]) => boolean
): boolean
/**
* Traverses the container’s descendant nodes, calling callback
* for each declaration node.
* The container’s first child.
*
* If you pass a filter, iteration will only happen over declarations
* with matching properties.
*
* ```js
* root.walkDecls(decl => {
* checkPropertySupport(decl.prop)
* })
*
* root.walkDecls('border-radius', decl => {
* decl.remove()
* })
*
* root.walkDecls(/^background/, decl => {
* decl.value = takeFirstColorFromGradient(decl.value)
* })
* rule.first === rules.nodes[0]
* ```
*
* Like `Container#each`, this method is safe
* to use if you are mutating arrays during iteration.
*
* @param prop String or regular expression to filter declarations
* by property name.
* @param callback Iterator receives each node and index.
* @return Returns `false` if iteration was broke.
*/
walkDecls(
propFilter: string | RegExp,
callback: (decl: Declaration, index: number) => false | void
): false | undefined
walkDecls(
callback: (decl: Declaration, index: number) => false | void
): false | undefined
get first(): Child | undefined
/**
* Traverses the container’s descendant nodes, calling callback
* for each rule node.
* Returns a `child`’s index within the `Container#nodes` array.
*
* If you pass a filter, iteration will only happen over rules
* with matching selectors.
*
* Like `Container#each`, this method is safe
* to use if you are mutating arrays during iteration.
*
* ```js
* const selectors = []
* root.walkRules(rule => {
* selectors.push(rule.selector)
* })
* console.log(`Your CSS uses ${ selectors.length } selectors`)
* rule.index( rule.nodes[2] ) //=> 2
* ```
*
* @param selector String or regular expression to filter rules by selector.
* @param callback Iterator receives each node and index.
* @return Returns `false` if iteration was broke.
* @param child Child of the current container.
* @return Child index.
*/
walkRules(
selectorFilter: string | RegExp,
callback: (rule: Rule, index: number) => false | void
): false | undefined
walkRules(
callback: (rule: Rule, index: number) => false | void
): false | undefined
index(child: Child | number): number
/**
* Traverses the container’s descendant nodes, calling callback
* for each at-rule node.
* Insert new node after old node within the container.
*
* If you pass a filter, iteration will only happen over at-rules
* that have matching names.
*
* Like `Container#each`, this method is safe
* to use if you are mutating arrays during iteration.
*
* ```js
* root.walkAtRules(rule => {
* if (isOld(rule.name)) rule.remove()
* })
*
* let first = false
* root.walkAtRules('charset', rule => {
* if (!first) {
* first = true
* } else {
* rule.remove()
* }
* })
* ```
*
* @param name String or regular expression to filter at-rules by name.
* @param callback Iterator receives each node and index.
* @return Returns `false` if iteration was broke.
* @param oldNode Child or child’s index.
* @param newNode New node.
* @return This node for methods chain.
*/
walkAtRules(
nameFilter: string | RegExp,
callback: (atRule: AtRule, index: number) => false | void
): false | undefined
walkAtRules(
callback: (atRule: AtRule, index: number) => false | void
): false | undefined
insertAfter(
oldNode: Child | number,
newNode: Child | Child[] | ChildProps | ChildProps[] | string | string[]
): this
/**
* Traverses the container’s descendant nodes, calling callback
* for each comment node.
* Insert new node before old node within the container.
*
* Like `Container#each`, this method is safe
* to use if you are mutating arrays during iteration.
*
* ```js
* root.walkComments(comment => {
* comment.remove()
* })
* rule.insertBefore(decl, decl.clone({ prop: '-webkit-' + decl.prop }))
* ```
*
* @param callback Iterator receives each node and index.
* @return Returns `false` if iteration was broke.
* @param oldNode Child or child’s index.
* @param newNode New node.
* @return This node for methods chain.
*/
walkComments(
callback: (comment: Comment, indexed: number) => false | void
): false | undefined
walkComments(
callback: (comment: Comment, indexed: number) => false | void
): false | undefined
insertBefore(
oldNode: Child | number,
newNode: Child | Child[] | ChildProps | ChildProps[] | string | string[]
): this
/**
* Inserts new nodes to the end of the container.
* The container’s last child.
*
* ```js
* const decl1 = new Declaration({ prop: 'color', value: 'black' })
* const decl2 = new Declaration({ prop: 'background-color', value: 'white' })
* rule.append(decl1, decl2)
*
* root.append({ name: 'charset', params: '"UTF-8"' }) // at-rule
* root.append({ selector: 'a' }) // rule
* rule.append({ prop: 'color', value: 'black' }) // declaration
* rule.append({ text: 'Comment' }) // comment
*
* root.append('a {}')
* root.first.append('color: black; z-index: 1')
* rule.last === rule.nodes[rule.nodes.length - 1]
* ```
*
* @param nodes New nodes.
* @return This node for methods chain.
*/
append(
...nodes: (Node | Node[] | ChildProps | ChildProps[] | string | string[])[]
): this
get last(): Child | undefined

@@ -304,5 +206,4 @@ /**

prepend(
...nodes: (Node | Node[] | ChildProps | ChildProps[] | string | string[])[]
...nodes: (ChildProps | ChildProps[] | Node | Node[] | string | string[])[]
): this
/**

@@ -321,29 +222,30 @@ * Add child to the end of the node.

/**
* Insert new node before old node within the container.
* Traverses the container’s descendant nodes, calling callback
* for each comment node.
*
* Like `Container#each`, this method is safe
* to use if you are mutating arrays during iteration.
*
* ```js
* rule.insertBefore(decl, decl.clone({ prop: '-webkit-' + decl.prop }))
* root.walkComments(comment => {
* comment.remove()
* })
* ```
*
* @param oldNode Child or child’s index.
* @param newNode New node.
* @return This node for methods chain.
* @param callback Iterator receives each node and index.
* @return Returns `false` if iteration was broke.
*/
insertBefore(
oldNode: Child | number,
newNode: Child | ChildProps | string | Child[] | ChildProps[] | string[]
): this
/**
* Insert new node after old node within the container.
* Removes all children from the container
* and cleans their parent properties.
*
* @param oldNode Child or child’s index.
* @param newNode New node.
* ```js
* rule.removeAll()
* rule.nodes.length //=> 0
* ```
*
* @return This node for methods chain.
*/
insertAfter(
oldNode: Child | number,
newNode: Child | ChildProps | string | Child[] | ChildProps[] | string[]
): this
removeAll(): this
/**

@@ -366,15 +268,2 @@ * Removes node from the container and cleans the parent properties

/**
* Removes all children from the container
* and cleans their parent properties.
*
* ```js
* rule.removeAll()
* rule.nodes.length //=> 0
* ```
*
* @return This node for methods chain.
*/
removeAll(): this
/**
* Passes all declaration values within the container that match pattern

@@ -403,23 +292,24 @@ * through callback, replacing those values with the returned result

replaceValues(
pattern: string | RegExp,
pattern: RegExp | string,
options: Container.ValueOptions,
replaced: string | { (substring: string, ...args: any[]): string }
replaced: { (substring: string, ...args: any[]): string } | string
): this
replaceValues(
pattern: string | RegExp,
replaced: string | { (substring: string, ...args: any[]): string }
pattern: RegExp | string,
replaced: { (substring: string, ...args: any[]): string } | string
): this
/**
* Returns `true` if callback returns `true`
* for all of the container’s children.
* Returns `true` if callback returns `true` for (at least) one
* of the container’s children.
*
* ```js
* const noPrefixes = rule.every(i => i.prop[0] !== '-')
* const hasPrefix = rule.some(i => i.prop[0] === '-')
* ```
*
* @param condition Iterator returns true or false.
* @return Is every child pass condition.
* @return Is some child pass condition.
*/
every(
some(
condition: (node: Child, index: number, nodes: Child[]) => boolean

@@ -429,27 +319,137 @@ ): boolean

/**
* Returns `true` if callback returns `true` for (at least) one
* of the container’s children.
* Traverses the container’s descendant nodes, calling callback
* for each node.
*
* Like container.each(), this method is safe to use
* if you are mutating arrays during iteration.
*
* If you only need to iterate through the container’s immediate children,
* use `Container#each`.
*
* ```js
* const hasPrefix = rule.some(i => i.prop[0] === '-')
* root.walk(node => {
* // Traverses all descendant nodes.
* })
* ```
*
* @param condition Iterator returns true or false.
* @return Is some child pass condition.
* @param callback Iterator receives each node and index.
* @return Returns `false` if iteration was broke.
*/
some(
condition: (node: Child, index: number, nodes: Child[]) => boolean
): boolean
walk(
callback: (node: ChildNode, index: number) => false | void
): false | undefined
walkAtRules(
callback: (atRule: AtRule, index: number) => false | void
): false | undefined
/**
* Returns a `child`’s index within the `Container#nodes` array.
* Traverses the container’s descendant nodes, calling callback
* for each at-rule node.
*
* If you pass a filter, iteration will only happen over at-rules
* that have matching names.
*
* Like `Container#each`, this method is safe
* to use if you are mutating arrays during iteration.
*
* ```js
* rule.index( rule.nodes[2] ) //=> 2
* root.walkAtRules(rule => {
* if (isOld(rule.name)) rule.remove()
* })
*
* let first = false
* root.walkAtRules('charset', rule => {
* if (!first) {
* first = true
* } else {
* rule.remove()
* }
* })
* ```
*
* @param child Child of the current container.
* @return Child index.
* @param name String or regular expression to filter at-rules by name.
* @param callback Iterator receives each node and index.
* @return Returns `false` if iteration was broke.
*/
index(child: Child | number): number
walkAtRules(
nameFilter: RegExp | string,
callback: (atRule: AtRule, index: number) => false | void
): false | undefined
walkComments(
callback: (comment: Comment, indexed: number) => false | void
): false | undefined
walkComments(
callback: (comment: Comment, indexed: number) => false | void
): false | undefined
walkDecls(
callback: (decl: Declaration, index: number) => false | void
): false | undefined
/**
* Traverses the container’s descendant nodes, calling callback
* for each declaration node.
*
* If you pass a filter, iteration will only happen over declarations
* with matching properties.
*
* ```js
* root.walkDecls(decl => {
* checkPropertySupport(decl.prop)
* })
*
* root.walkDecls('border-radius', decl => {
* decl.remove()
* })
*
* root.walkDecls(/^background/, decl => {
* decl.value = takeFirstColorFromGradient(decl.value)
* })
* ```
*
* Like `Container#each`, this method is safe
* to use if you are mutating arrays during iteration.
*
* @param prop String or regular expression to filter declarations
* by property name.
* @param callback Iterator receives each node and index.
* @return Returns `false` if iteration was broke.
*/
walkDecls(
propFilter: RegExp | string,
callback: (decl: Declaration, index: number) => false | void
): false | undefined
walkRules(
callback: (rule: Rule, index: number) => false | void
): false | undefined
/**
* Traverses the container’s descendant nodes, calling callback
* for each rule node.
*
* If you pass a filter, iteration will only happen over rules
* with matching selectors.
*
* Like `Container#each`, this method is safe
* to use if you are mutating arrays during iteration.
*
* ```js
* const selectors = []
* root.walkRules(rule => {
* selectors.push(rule.selector)
* })
* console.log(`Your CSS uses ${ selectors.length } selectors`)
* ```
*
* @param selector String or regular expression to filter rules by selector.
* @param callback Iterator receives each node and index.
* @return Returns `false` if iteration was broke.
*/
walkRules(
selectorFilter: RegExp | string,
callback: (rule: Rule, index: number) => false | void
): false | undefined
}

@@ -456,0 +456,0 @@

@@ -28,8 +28,20 @@ 'use strict'

class Container extends Node {
push(child) {
child.parent = this
this.proxyOf.nodes.push(child)
append(...children) {
for (let child of children) {
let nodes = this.normalize(child, this.last)
for (let node of nodes) this.proxyOf.nodes.push(node)
}
this.markDirty()
return this
}
cleanRaws(keepBetween) {
super.cleanRaws(keepBetween)
if (this.nodes) {
for (let node of this.nodes) node.cleanRaws(keepBetween)
}
}
each(callback) {

@@ -52,149 +64,78 @@ if (!this.proxyOf.nodes) return undefined

walk(callback) {
return this.each((child, i) => {
let result
try {
result = callback(child, i)
} catch (e) {
throw child.addToError(e)
}
if (result !== false && child.walk) {
result = child.walk(callback)
}
return result
})
every(condition) {
return this.nodes.every(condition)
}
walkDecls(prop, callback) {
if (!callback) {
callback = prop
return this.walk((child, i) => {
if (child.type === 'decl') {
return callback(child, i)
}
})
}
if (prop instanceof RegExp) {
return this.walk((child, i) => {
if (child.type === 'decl' && prop.test(child.prop)) {
return callback(child, i)
}
})
}
return this.walk((child, i) => {
if (child.type === 'decl' && child.prop === prop) {
return callback(child, i)
}
})
get first() {
if (!this.proxyOf.nodes) return undefined
return this.proxyOf.nodes[0]
}
walkRules(selector, callback) {
if (!callback) {
callback = selector
getIterator() {
if (!this.lastEach) this.lastEach = 0
if (!this.indexes) this.indexes = {}
return this.walk((child, i) => {
if (child.type === 'rule') {
return callback(child, i)
}
})
}
if (selector instanceof RegExp) {
return this.walk((child, i) => {
if (child.type === 'rule' && selector.test(child.selector)) {
return callback(child, i)
}
})
}
return this.walk((child, i) => {
if (child.type === 'rule' && child.selector === selector) {
return callback(child, i)
}
})
this.lastEach += 1
let iterator = this.lastEach
this.indexes[iterator] = 0
return iterator
}
walkAtRules(name, callback) {
if (!callback) {
callback = name
return this.walk((child, i) => {
if (child.type === 'atrule') {
return callback(child, i)
getProxyProcessor() {
return {
get(node, prop) {
if (prop === 'proxyOf') {
return node
} else if (!node[prop]) {
return node[prop]
} else if (
prop === 'each' ||
(typeof prop === 'string' && prop.startsWith('walk'))
) {
return (...args) => {
return node[prop](
...args.map(i => {
if (typeof i === 'function') {
return (child, index) => i(child.toProxy(), index)
} else {
return i
}
})
)
}
} else if (prop === 'every' || prop === 'some') {
return cb => {
return node[prop]((child, ...other) =>
cb(child.toProxy(), ...other)
)
}
} else if (prop === 'root') {
return () => node.root().toProxy()
} else if (prop === 'nodes') {
return node.nodes.map(i => i.toProxy())
} else if (prop === 'first' || prop === 'last') {
return node[prop].toProxy()
} else {
return node[prop]
}
})
}
if (name instanceof RegExp) {
return this.walk((child, i) => {
if (child.type === 'atrule' && name.test(child.name)) {
return callback(child, i)
},
set(node, prop, value) {
if (node[prop] === value) return true
node[prop] = value
if (prop === 'name' || prop === 'params' || prop === 'selector') {
node.markDirty()
}
})
}
return this.walk((child, i) => {
if (child.type === 'atrule' && child.name === name) {
return callback(child, i)
return true
}
})
}
walkComments(callback) {
return this.walk((child, i) => {
if (child.type === 'comment') {
return callback(child, i)
}
})
}
append(...children) {
for (let child of children) {
let nodes = this.normalize(child, this.last)
for (let node of nodes) this.proxyOf.nodes.push(node)
}
this.markDirty()
return this
}
prepend(...children) {
children = children.reverse()
for (let child of children) {
let nodes = this.normalize(child, this.first, 'prepend').reverse()
for (let node of nodes) this.proxyOf.nodes.unshift(node)
for (let id in this.indexes) {
this.indexes[id] = this.indexes[id] + nodes.length
}
}
this.markDirty()
return this
index(child) {
if (typeof child === 'number') return child
if (child.proxyOf) child = child.proxyOf
return this.proxyOf.nodes.indexOf(child)
}
cleanRaws(keepBetween) {
super.cleanRaws(keepBetween)
if (this.nodes) {
for (let node of this.nodes) node.cleanRaws(keepBetween)
}
}
insertBefore(exist, add) {
let existIndex = this.index(exist)
let type = existIndex === 0 ? 'prepend' : false
let nodes = this.normalize(add, this.proxyOf.nodes[existIndex], type).reverse()
existIndex = this.index(exist)
for (let node of nodes) this.proxyOf.nodes.splice(existIndex, 0, node)
let index
for (let id in this.indexes) {
index = this.indexes[id]
if (existIndex <= index) {
this.indexes[id] = index + nodes.length
}
}
this.markDirty()
return this
}
insertAfter(exist, add) {

@@ -219,6 +160,8 @@ let existIndex = this.index(exist)

removeChild(child) {
child = this.index(child)
this.proxyOf.nodes[child].parent = undefined
this.proxyOf.nodes.splice(child, 1)
insertBefore(exist, add) {
let existIndex = this.index(exist)
let type = existIndex === 0 ? 'prepend' : false
let nodes = this.normalize(add, this.proxyOf.nodes[existIndex], type).reverse()
existIndex = this.index(exist)
for (let node of nodes) this.proxyOf.nodes.splice(existIndex, 0, node)

@@ -228,4 +171,4 @@ let index

index = this.indexes[id]
if (index >= child) {
this.indexes[id] = index - 1
if (existIndex <= index) {
this.indexes[id] = index + nodes.length
}

@@ -239,48 +182,2 @@ }

removeAll() {
for (let node of this.proxyOf.nodes) node.parent = undefined
this.proxyOf.nodes = []
this.markDirty()
return this
}
replaceValues(pattern, opts, callback) {
if (!callback) {
callback = opts
opts = {}
}
this.walkDecls(decl => {
if (opts.props && !opts.props.includes(decl.prop)) return
if (opts.fast && !decl.value.includes(opts.fast)) return
decl.value = decl.value.replace(pattern, callback)
})
this.markDirty()
return this
}
every(condition) {
return this.nodes.every(condition)
}
some(condition) {
return this.nodes.some(condition)
}
index(child) {
if (typeof child === 'number') return child
if (child.proxyOf) child = child.proxyOf
return this.proxyOf.nodes.indexOf(child)
}
get first() {
if (!this.proxyOf.nodes) return undefined
return this.proxyOf.nodes[0]
}
get last() {

@@ -341,62 +238,165 @@ if (!this.proxyOf.nodes) return undefined

getProxyProcessor() {
return {
set(node, prop, value) {
if (node[prop] === value) return true
node[prop] = value
if (prop === 'name' || prop === 'params' || prop === 'selector') {
node.markDirty()
}
return true
},
prepend(...children) {
children = children.reverse()
for (let child of children) {
let nodes = this.normalize(child, this.first, 'prepend').reverse()
for (let node of nodes) this.proxyOf.nodes.unshift(node)
for (let id in this.indexes) {
this.indexes[id] = this.indexes[id] + nodes.length
}
}
get(node, prop) {
if (prop === 'proxyOf') {
return node
} else if (!node[prop]) {
return node[prop]
} else if (
prop === 'each' ||
(typeof prop === 'string' && prop.startsWith('walk'))
) {
return (...args) => {
return node[prop](
...args.map(i => {
if (typeof i === 'function') {
return (child, index) => i(child.toProxy(), index)
} else {
return i
}
})
)
}
} else if (prop === 'every' || prop === 'some') {
return cb => {
return node[prop]((child, ...other) =>
cb(child.toProxy(), ...other)
)
}
} else if (prop === 'root') {
return () => node.root().toProxy()
} else if (prop === 'nodes') {
return node.nodes.map(i => i.toProxy())
} else if (prop === 'first' || prop === 'last') {
return node[prop].toProxy()
} else {
return node[prop]
}
this.markDirty()
return this
}
push(child) {
child.parent = this
this.proxyOf.nodes.push(child)
return this
}
removeAll() {
for (let node of this.proxyOf.nodes) node.parent = undefined
this.proxyOf.nodes = []
this.markDirty()
return this
}
removeChild(child) {
child = this.index(child)
this.proxyOf.nodes[child].parent = undefined
this.proxyOf.nodes.splice(child, 1)
let index
for (let id in this.indexes) {
index = this.indexes[id]
if (index >= child) {
this.indexes[id] = index - 1
}
}
this.markDirty()
return this
}
getIterator() {
if (!this.lastEach) this.lastEach = 0
if (!this.indexes) this.indexes = {}
replaceValues(pattern, opts, callback) {
if (!callback) {
callback = opts
opts = {}
}
this.lastEach += 1
let iterator = this.lastEach
this.indexes[iterator] = 0
this.walkDecls(decl => {
if (opts.props && !opts.props.includes(decl.prop)) return
if (opts.fast && !decl.value.includes(opts.fast)) return
return iterator
decl.value = decl.value.replace(pattern, callback)
})
this.markDirty()
return this
}
some(condition) {
return this.nodes.some(condition)
}
walk(callback) {
return this.each((child, i) => {
let result
try {
result = callback(child, i)
} catch (e) {
throw child.addToError(e)
}
if (result !== false && child.walk) {
result = child.walk(callback)
}
return result
})
}
walkAtRules(name, callback) {
if (!callback) {
callback = name
return this.walk((child, i) => {
if (child.type === 'atrule') {
return callback(child, i)
}
})
}
if (name instanceof RegExp) {
return this.walk((child, i) => {
if (child.type === 'atrule' && name.test(child.name)) {
return callback(child, i)
}
})
}
return this.walk((child, i) => {
if (child.type === 'atrule' && child.name === name) {
return callback(child, i)
}
})
}
walkComments(callback) {
return this.walk((child, i) => {
if (child.type === 'comment') {
return callback(child, i)
}
})
}
walkDecls(prop, callback) {
if (!callback) {
callback = prop
return this.walk((child, i) => {
if (child.type === 'decl') {
return callback(child, i)
}
})
}
if (prop instanceof RegExp) {
return this.walk((child, i) => {
if (child.type === 'decl' && prop.test(child.prop)) {
return callback(child, i)
}
})
}
return this.walk((child, i) => {
if (child.type === 'decl' && child.prop === prop) {
return callback(child, i)
}
})
}
walkRules(selector, callback) {
if (!callback) {
callback = selector
return this.walk((child, i) => {
if (child.type === 'rule') {
return callback(child, i)
}
})
}
if (selector instanceof RegExp) {
return this.walk((child, i) => {
if (child.type === 'rule' && selector.test(child.selector)) {
return callback(child, i)
}
})
}
return this.walk((child, i) => {
if (child.type === 'rule' && child.selector === selector) {
return callback(child, i)
}
})
}
}

@@ -403,0 +403,0 @@

@@ -9,10 +9,10 @@ import { FilePosition } from './input.js'

/**
* The line number in the input.
* The column number in the input.
*/
line: number
column: number
/**
* The column number in the input.
* The line number in the input.
*/
column: number
line: number
}

@@ -55,56 +55,41 @@

/**
* Instantiates a CSS syntax error. Can be instantiated for a single position
* or for a range.
* @param message Error message.
* @param lineOrStartPos If for a single position, the line number, or if for
* a range, the inclusive start position of the error.
* @param columnOrEndPos If for a single position, the column number, or if for
* a range, the exclusive end position of the error.
* @param source Source code of the broken file.
* @param file Absolute path to the broken file.
* @param plugin PostCSS plugin name, if error came from plugin.
*/
constructor(
message: string,
lineOrStartPos?: number | CssSyntaxError.RangePosition,
columnOrEndPos?: number | CssSyntaxError.RangePosition,
source?: string,
file?: string,
plugin?: string
)
stack: string
/**
* Always equal to `'CssSyntaxError'`. You should always check error type
* by `error.name === 'CssSyntaxError'`
* instead of `error instanceof CssSyntaxError`,
* because npm could have several PostCSS versions.
* Source column of the error.
*
* ```js
* if (error.name === 'CssSyntaxError') {
* error //=> CssSyntaxError
* }
* error.column //=> 1
* error.input.column //=> 4
* ```
*
* PostCSS will use the input source map to detect the original location.
* If you need the position in the PostCSS input, use `error.input.column`.
*/
name: 'CssSyntaxError'
column?: number
/**
* Error message.
* Source column of the error's end, exclusive. Provided if the error pertains
* to a range.
*
* ```js
* error.message //=> 'Unclosed block'
* error.endColumn //=> 1
* error.input.endColumn //=> 4
* ```
*
* PostCSS will use the input source map to detect the original location.
* If you need the position in the PostCSS input, use `error.input.endColumn`.
*/
reason: string
endColumn?: number
/**
* Full error text in the GNU error format
* with plugin, file, line and column.
* Source line of the error's end, exclusive. Provided if the error pertains
* to a range.
*
* ```js
* error.message //=> 'a.css:1:1: Unclosed block'
* error.endLine //=> 3
* error.input.endLine //=> 4
* ```
*
* PostCSS will use the input source map to detect the original location.
* If you need the position in the PostCSS input, use `error.input.endLine`.
*/
message: string
endLine?: number

@@ -125,66 +110,53 @@ /**

/**
* Source line of the error.
* Input object with PostCSS internal information
* about input file. If input has source map
* from previous tool, PostCSS will use origin
* (for example, Sass) source. You can use this
* object to get PostCSS input source.
*
* ```js
* error.line //=> 2
* error.input.line //=> 4
* error.input.file //=> 'a.css'
* error.file //=> 'a.sass'
* ```
*
* PostCSS will use the input source map to detect the original location.
* If you need the position in the PostCSS input, use `error.input.line`.
*/
line?: number
input?: FilePosition
/**
* Source column of the error.
* Source line of the error.
*
* ```js
* error.column //=> 1
* error.input.column //=> 4
* error.line //=> 2
* error.input.line //=> 4
* ```
*
* PostCSS will use the input source map to detect the original location.
* If you need the position in the PostCSS input, use `error.input.column`.
* If you need the position in the PostCSS input, use `error.input.line`.
*/
column?: number
line?: number
/**
* Source line of the error's end, exclusive. Provided if the error pertains
* to a range.
* Full error text in the GNU error format
* with plugin, file, line and column.
*
* ```js
* error.endLine //=> 3
* error.input.endLine //=> 4
* error.message //=> 'a.css:1:1: Unclosed block'
* ```
*
* PostCSS will use the input source map to detect the original location.
* If you need the position in the PostCSS input, use `error.input.endLine`.
*/
endLine?: number
message: string
/**
* Source column of the error's end, exclusive. Provided if the error pertains
* to a range.
* Always equal to `'CssSyntaxError'`. You should always check error type
* by `error.name === 'CssSyntaxError'`
* instead of `error instanceof CssSyntaxError`,
* because npm could have several PostCSS versions.
*
* ```js
* error.endColumn //=> 1
* error.input.endColumn //=> 4
* if (error.name === 'CssSyntaxError') {
* error //=> CssSyntaxError
* }
* ```
*
* PostCSS will use the input source map to detect the original location.
* If you need the position in the PostCSS input, use `error.input.endColumn`.
*/
endColumn?: number
name: 'CssSyntaxError'
/**
* Source code of the broken file.
*
* ```js
* error.source //=> 'a { b {} }'
* error.input.source //=> 'a b { }'
* ```
*/
source?: string
/**
* Plugin name, if error came from plugin.

@@ -199,29 +171,44 @@ *

/**
* Input object with PostCSS internal information
* about input file. If input has source map
* from previous tool, PostCSS will use origin
* (for example, Sass) source. You can use this
* object to get PostCSS input source.
* Error message.
*
* ```js
* error.input.file //=> 'a.css'
* error.file //=> 'a.sass'
* error.message //=> 'Unclosed block'
* ```
*/
input?: FilePosition
reason: string
/**
* Returns error position, message and source code of the broken part.
* Source code of the broken file.
*
* ```js
* error.toString() //=> "CssSyntaxError: app.css:1:1: Unclosed block
* // > 1 | a {
* // | ^"
* error.source //=> 'a { b {} }'
* error.input.source //=> 'a b { }'
* ```
*
* @return Error position, message and source code.
*/
toString(): string
source?: string
stack: string
/**
* Instantiates a CSS syntax error. Can be instantiated for a single position
* or for a range.
* @param message Error message.
* @param lineOrStartPos If for a single position, the line number, or if for
* a range, the inclusive start position of the error.
* @param columnOrEndPos If for a single position, the column number, or if for
* a range, the exclusive end position of the error.
* @param source Source code of the broken file.
* @param file Absolute path to the broken file.
* @param plugin PostCSS plugin name, if error came from plugin.
*/
constructor(
message: string,
lineOrStartPos?: CssSyntaxError.RangePosition | number,
columnOrEndPos?: CssSyntaxError.RangePosition | number,
source?: string,
file?: string,
plugin?: string
)
/**
* Returns a few lines of CSS source that caused the error.

@@ -248,2 +235,15 @@ *

showSourceCode(color?: boolean): string
/**
* Returns error position, message and source code of the broken part.
*
* ```js
* error.toString() //=> "CssSyntaxError: app.css:1:1: Unclosed block
* // > 1 | a {
* // | ^"
* ```
*
* @return Error position, message and source code.
*/
toString(): string
}

@@ -250,0 +250,0 @@

@@ -67,3 +67,3 @@ 'use strict'

if (color) {
let { bold, red, gray } = pico.createColors(true)
let { bold, gray, red } = pico.createColors(true)
mark = text => bold(red(text))

@@ -70,0 +70,0 @@ aside = text => gray(text)

@@ -26,4 +26,4 @@ import Container from './container.js'

value?: {
raw: string
value: string
raw: string
}

@@ -33,10 +33,10 @@ }

export interface DeclarationProps {
/** Whether the declaration has an `!important` annotation. */
important?: boolean
/** Name of the declaration. */
prop: string
/** Information used to generate byte-to-byte equal node string as it was in the origin input. */
raws?: DeclarationRaws
/** Value of the declaration. */
value: string
/** Whether the declaration has an `!important` annotation. */
important?: boolean
/** Information used to generate byte-to-byte equal node string as it was in the origin input. */
raws?: DeclarationRaws
}

@@ -49,7 +49,8 @@

/**
* Represents a CSS declaration.
* It represents a class that handles
* [CSS declarations](https://developer.mozilla.org/en-US/docs/Web/CSS/Syntax#css_declarations)
*
* ```js
* Once (root, { Declaration }) {
* let color = new Declaration({ prop: 'color', value: 'black' })
* const color = new Declaration({ prop: 'color', value: 'black' })
* root.append(color)

@@ -61,19 +62,33 @@ * }

* const root = postcss.parse('a { color: black }')
* const decl = root.first.first
* decl.type //=> 'decl'
* decl.toString() //=> ' color: black'
* const decl = root.first?.first
*
* console.log(decl.type) //=> 'decl'
* console.log(decl.toString()) //=> ' color: black'
* ```
*/
declare class Declaration_ extends Node {
type: 'decl'
/**
* It represents a specificity of the declaration.
*
* If true, the CSS declaration will have an
* [important](https://developer.mozilla.org/en-US/docs/Web/CSS/important)
* specifier.
*
* ```js
* const root = postcss.parse('a { color: black !important; color: red }')
*
* console.log(root.first?.first?.important) //=> true
* console.log(root.first?.last?.important) //=> undefined
* ```
*/
important: boolean
parent: Container | undefined
raws: Declaration.DeclarationRaws
/**
* The declaration's property name.
* The property name for a CSS declaration.
*
* ```js
* const root = postcss.parse('a { color: black }')
* const decl = root.first.first
* decl.prop //=> 'color'
* const decl = root.first?.first
*
* console.log(decl.prop) //=> 'color'
* ```

@@ -83,14 +98,21 @@ */

raws: Declaration.DeclarationRaws
type: 'decl'
/**
* The declaration’s value.
* The property value for a CSS declaration.
*
* This value will be cleaned of comments. If the source value contained
* comments, those comments will be available in the `raws` property.
* If you have not changed the value, the result of `decl.toString()`
* will include the original raws value (comments and all).
* Any CSS comments inside the value string will be filtered out.
* CSS comments present in the source value will be available in
* the `raws` property.
*
* Assigning new `value` would ignore the comments in `raws`
* property while compiling node to string.
*
* ```js
* const root = postcss.parse('a { color: black }')
* const decl = root.first.first
* decl.value //=> 'black'
* const decl = root.first?.first
*
* console.log(decl.value) //=> 'black'
* ```

@@ -101,20 +123,10 @@ */

/**
* `true` if the declaration has an `!important` annotation.
* It represents a getter that returns `true` if a declaration starts with
* `--` or `$`, which are used to declare variables in CSS and SASS/SCSS.
*
* ```js
* const root = postcss.parse('a { color: black !important; color: red }')
* root.first.first.important //=> true
* root.first.last.important //=> undefined
* ```
*/
important: boolean
/**
* `true` if declaration is declaration of CSS Custom Property
* or Sass variable.
* const root = postcss.parse(':root { --one: 1 }')
* const one = root.first?.first
*
* ```js
* const root = postcss.parse(':root { --one: 1 }')
* let one = root.first.first
* one.variable //=> true
* console.log(one?.variable) //=> true
* ```

@@ -124,4 +136,5 @@ *

* const root = postcss.parse('$one: 1')
* let one = root.first
* one.variable //=> true
* const one = root.first
*
* console.log(one?.variable) //=> true
* ```

@@ -132,6 +145,6 @@ */

constructor(defaults?: Declaration.DeclarationProps)
assign(overrides: object | Declaration.DeclarationProps): this
assign(overrides: Declaration.DeclarationProps | object): this
clone(overrides?: Partial<Declaration.DeclarationProps>): this
cloneAfter(overrides?: Partial<Declaration.DeclarationProps>): this
cloneBefore(overrides?: Partial<Declaration.DeclarationProps>): this
cloneAfter(overrides?: Partial<Declaration.DeclarationProps>): this
}

@@ -138,0 +151,0 @@

@@ -38,4 +38,4 @@ import Container, { ContainerProps } from './container.js'

declare class Document_ extends Container<Root> {
parent: undefined
type: 'document'
parent: undefined

@@ -42,0 +42,0 @@ constructor(defaults?: Document.DocumentProps)

@@ -7,35 +7,35 @@ import { CssSyntaxError, ProcessOptions } from './postcss.js'

/**
* URL for the source file.
* Column of inclusive start position in source file.
*/
url: string
column: number
/**
* Absolute path to the source file.
* Column of exclusive end position in source file.
*/
file?: string
endColumn?: number
/**
* Line of inclusive start position in source file.
* Line of exclusive end position in source file.
*/
line: number
endLine?: number
/**
* Column of inclusive start position in source file.
* Absolute path to the source file.
*/
column: number
file?: string
/**
* Line of exclusive end position in source file.
* Line of inclusive start position in source file.
*/
endLine?: number
line: number
/**
* Column of exclusive end position in source file.
* Source code.
*/
endColumn?: number
source?: string
/**
* Source code.
* URL for the source file.
*/
source?: string
url: string
}

@@ -67,12 +67,2 @@

/**
* The input source map passed from a compilation step before PostCSS
* (for example, from Sass compiler).
*
* ```js
* root.source.input.map.consumer().sources //=> ['a.sass']
* ```
*/
map: PreviousMap
/**
* The absolute path to the CSS source file defined

@@ -89,2 +79,7 @@ * with the `from` option.

/**
* The flag to indicate whether or not the source code has Unicode BOM.
*/
hasBOM: boolean
/**
* The unique ID of the CSS source. It will be created if `from` option

@@ -102,5 +97,10 @@ * is not provided (because PostCSS does not know the file path).

/**
* The flag to indicate whether or not the source code has Unicode BOM.
* The input source map passed from a compilation step before PostCSS
* (for example, from Sass compiler).
*
* ```js
* root.source.input.map.consumer().sources //=> ['a.sass']
* ```
*/
hasBOM: boolean
map: PreviousMap

@@ -113,3 +113,40 @@ /**

error(
message: string,
start:
| {
column: number
line: number
}
| {
offset: number
},
end:
| {
column: number
line: number
}
| {
offset: number
},
opts?: { plugin?: CssSyntaxError['plugin'] }
): CssSyntaxError
/**
* Returns `CssSyntaxError` with information about the error and its position.
*/
error(
message: string,
line: number,
column: number,
opts?: { plugin?: CssSyntaxError['plugin'] }
): CssSyntaxError
error(
message: string,
offset: number,
opts?: { plugin?: CssSyntaxError['plugin'] }
): CssSyntaxError
/**
* The CSS source identifier. Contains `Input#file` if the user

@@ -127,4 +164,9 @@ * set the `from` option, or `Input#id` if they did not.

get from(): string
/**
* Converts source offset to line and column.
*
* @param offset Source offset.
*/
fromOffset(offset: number): { col: number; line: number } | null
/**
* Reads the input source map and returns a symbol position

@@ -153,45 +195,3 @@ * in the input source (e.g., in a Sass file that was compiled

endColumn?: number
): Input.FilePosition | false
/**
* Converts source offset to line and column.
*
* @param offset Source offset.
*/
fromOffset(offset: number): { line: number; col: number } | null
/**
* Returns `CssSyntaxError` with information about the error and its position.
*/
error(
message: string,
line: number,
column: number,
opts?: { plugin?: CssSyntaxError['plugin'] }
): CssSyntaxError
error(
message: string,
offset: number,
opts?: { plugin?: CssSyntaxError['plugin'] }
): CssSyntaxError
error(
message: string,
start:
| {
offset: number
}
| {
line: number
column: number
},
end:
| {
offset: number
}
| {
line: number
column: number
},
opts?: { plugin?: CssSyntaxError['plugin'] }
): CssSyntaxError
): false | Input.FilePosition
}

@@ -198,0 +198,0 @@

@@ -5,3 +5,3 @@ 'use strict'

let { fileURLToPath, pathToFileURL } = require('url')
let { resolve, isAbsolute } = require('path')
let { isAbsolute, resolve } = require('path')
let { nanoid } = require('nanoid/non-secure')

@@ -64,44 +64,2 @@

fromOffset(offset) {
let lastLine, lineToIndex
if (!this[fromOffsetCache]) {
let lines = this.css.split('\n')
lineToIndex = new Array(lines.length)
let prevIndex = 0
for (let i = 0, l = lines.length; i < l; i++) {
lineToIndex[i] = prevIndex
prevIndex += lines[i].length + 1
}
this[fromOffsetCache] = lineToIndex
} else {
lineToIndex = this[fromOffsetCache]
}
lastLine = lineToIndex[lineToIndex.length - 1]
let min = 0
if (offset >= lastLine) {
min = lineToIndex.length - 1
} else {
let max = lineToIndex.length - 2
let mid
while (min < max) {
mid = min + ((max - min) >> 1)
if (offset < lineToIndex[mid]) {
max = mid - 1
} else if (offset >= lineToIndex[mid + 1]) {
min = mid + 1
} else {
min = mid
break
}
}
}
return {
line: min + 1,
col: offset - lineToIndex[min] + 1
}
}
error(message, line, column, opts = {}) {

@@ -141,6 +99,6 @@ let result, endLine, endColumn

? origin.line
: { line: origin.line, column: origin.column },
: { column: origin.column, line: origin.line },
origin.endLine === undefined
? origin.column
: { line: origin.endLine, column: origin.endColumn },
: { column: origin.endColumn, line: origin.endLine },
origin.source,

@@ -153,4 +111,4 @@ origin.file,

message,
endLine === undefined ? line : { line, column },
endLine === undefined ? column : { line: endLine, column: endColumn },
endLine === undefined ? line : { column, line },
endLine === undefined ? column : { column: endColumn, line: endLine },
this.css,

@@ -162,3 +120,3 @@ this.file,

result.input = { line, column, endLine, endColumn, source: this.css }
result.input = { column, endColumn, endLine, line, source: this.css }
if (this.file) {

@@ -174,2 +132,55 @@ if (pathToFileURL) {

get from() {
return this.file || this.id
}
fromOffset(offset) {
let lastLine, lineToIndex
if (!this[fromOffsetCache]) {
let lines = this.css.split('\n')
lineToIndex = new Array(lines.length)
let prevIndex = 0
for (let i = 0, l = lines.length; i < l; i++) {
lineToIndex[i] = prevIndex
prevIndex += lines[i].length + 1
}
this[fromOffsetCache] = lineToIndex
} else {
lineToIndex = this[fromOffsetCache]
}
lastLine = lineToIndex[lineToIndex.length - 1]
let min = 0
if (offset >= lastLine) {
min = lineToIndex.length - 1
} else {
let max = lineToIndex.length - 2
let mid
while (min < max) {
mid = min + ((max - min) >> 1)
if (offset < lineToIndex[mid]) {
max = mid - 1
} else if (offset >= lineToIndex[mid + 1]) {
min = mid + 1
} else {
min = mid
break
}
}
}
return {
col: offset - lineToIndex[min] + 1,
line: min + 1
}
}
mapResolve(file) {
if (/^\w+:\/\//.test(file)) {
return file
}
return resolve(this.map.consumer().sourceRoot || this.map.root || '.', file)
}
origin(line, column, endLine, endColumn) {

@@ -179,3 +190,3 @@ if (!this.map) return false

let from = consumer.originalPositionFor({ line, column })
let from = consumer.originalPositionFor({ column, line })
if (!from.source) return false

@@ -185,3 +196,3 @@

if (typeof endLine === 'number') {
to = consumer.originalPositionFor({ line: endLine, column: endColumn })
to = consumer.originalPositionFor({ column: endColumn, line: endLine })
}

@@ -201,7 +212,7 @@

let result = {
url: fromUrl.toString(),
line: from.line,
column: from.column,
endColumn: to && to.column,
endLine: to && to.line,
endColumn: to && to.column
line: from.line,
url: fromUrl.toString()
}

@@ -224,13 +235,2 @@

mapResolve(file) {
if (/^\w+:\/\//.test(file)) {
return file
}
return resolve(this.map.consumer().sourceRoot || this.map.root || '.', file)
}
get from() {
return this.file || this.id
}
toJSON() {

@@ -237,0 +237,0 @@ let json = {}

@@ -1,6 +0,6 @@

import Result, { Message, ResultOptions } from './result.js'
import { SourceMap } from './postcss.js'
import Processor from './processor.js'
import Result, { Message, ResultOptions } from './result.js'
import Root from './root.js'
import Warning from './warning.js'
import Root from './root.js'

@@ -24,4 +24,3 @@ declare namespace LazyResult {

* Processes input CSS through synchronous and asynchronous plugins
* and calls `onFulfilled` with a Result instance. If a plugin throws
* an error, the `onRejected` callback will be executed.
* and calls onRejected for each error thrown in any plugin.
*

@@ -31,12 +30,14 @@ * It implements standard Promise API.

* ```js
* postcss([autoprefixer]).process(css, { from: cssPath }).then(result => {
* postcss([autoprefixer]).process(css).then(result => {
* console.log(result.css)
* }).catch(error => {
* console.error(error)
* })
* ```
*/
then: Promise<Result>['then']
catch: Promise<Result>['catch']
/**
* Processes input CSS through synchronous and asynchronous plugins
* and calls onRejected for each error thrown in any plugin.
* and calls onFinally on any error or when all plugins will finish work.
*

@@ -46,14 +47,13 @@ * It implements standard Promise API.

* ```js
* postcss([autoprefixer]).process(css).then(result => {
* console.log(result.css)
* }).catch(error => {
* console.error(error)
* postcss([autoprefixer]).process(css).finally(() => {
* console.log('processing ended')
* })
* ```
*/
catch: Promise<Result>['catch']
finally: Promise<Result>['finally']
/**
* Processes input CSS through synchronous and asynchronous plugins
* and calls onFinally on any error or when all plugins will finish work.
* and calls `onFulfilled` with a Result instance. If a plugin throws
* an error, the `onRejected` callback will be executed.
*

@@ -63,8 +63,8 @@ * It implements standard Promise API.

* ```js
* postcss([autoprefixer]).process(css).finally(() => {
* console.log('processing ended')
* postcss([autoprefixer]).process(css, { from: cssPath }).then(result => {
* console.log(result.css)
* })
* ```
*/
finally: Promise<Result>['finally']
then: Promise<Result>['then']

@@ -79,21 +79,11 @@ /**

/**
* Returns the default string description of an object.
* Required to implement the Promise interface.
* Run plugin in async way and return `Result`.
*
* @return Result with output content.
*/
get [Symbol.toStringTag](): string
async(): Promise<Result>
/**
* Returns a `Processor` instance, which will be used
* for CSS transformations.
*/
get processor(): Processor
/**
* Options from the `Processor#process` call.
*/
get opts(): ResultOptions
/**
* Processes input CSS through synchronous plugins, converts `Root`
* to a CSS string and returns `Result#css`.
* An alias for the `css` property. Use it with syntaxes
* that generate non-CSS output.
*

@@ -106,7 +96,7 @@ * This property will only work with synchronous plugins.

*/
get css(): string
get content(): string
/**
* An alias for the `css` property. Use it with syntaxes
* that generate non-CSS output.
* Processes input CSS through synchronous plugins, converts `Root`
* to a CSS string and returns `Result#css`.
*

@@ -119,3 +109,3 @@ * This property will only work with synchronous plugins.

*/
get content(): string
get css(): string

@@ -136,3 +126,3 @@ /**

* Processes input CSS through synchronous plugins
* and returns `Result#root`.
* and returns `Result#messages`.
*

@@ -144,7 +134,18 @@ * This property will only work with synchronous plugins. If the processor

*/
get root(): Root
get messages(): Message[]
/**
* Options from the `Processor#process` call.
*/
get opts(): ResultOptions
/**
* Returns a `Processor` instance, which will be used
* for CSS transformations.
*/
get processor(): Processor
/**
* Processes input CSS through synchronous plugins
* and returns `Result#messages`.
* and returns `Result#root`.
*

@@ -156,11 +157,16 @@ * This property will only work with synchronous plugins. If the processor

*/
get messages(): Message[]
get root(): Root
/**
* Processes input CSS through synchronous plugins
* and calls `Result#warnings`.
* Returns the default string description of an object.
* Required to implement the Promise interface.
*/
get [Symbol.toStringTag](): string
/**
* Run plugin in sync way and return `Result`.
*
* @return Warnings from plugins.
* @return Result with output content.
*/
warnings(): Warning[]
sync(): Result

@@ -179,14 +185,8 @@ /**

/**
* Run plugin in sync way and return `Result`.
* Processes input CSS through synchronous plugins
* and calls `Result#warnings`.
*
* @return Result with output content.
* @return Warnings from plugins.
*/
sync(): Result
/**
* Run plugin in async way and return `Result`.
*
* @return Result with output content.
*/
async(): Promise<Result>
warnings(): Warning[]
}

@@ -193,0 +193,0 @@

@@ -14,33 +14,33 @@ 'use strict'

const TYPE_TO_CLASS_NAME = {
atrule: 'AtRule',
comment: 'Comment',
decl: 'Declaration',
document: 'Document',
root: 'Root',
atrule: 'AtRule',
rule: 'Rule',
decl: 'Declaration',
comment: 'Comment'
rule: 'Rule'
}
const PLUGIN_PROPS = {
AtRule: true,
AtRuleExit: true,
Comment: true,
CommentExit: true,
Declaration: true,
DeclarationExit: true,
Document: true,
DocumentExit: true,
Once: true,
OnceExit: true,
postcssPlugin: true,
prepare: true,
Once: true,
Document: true,
Root: true,
Declaration: true,
RootExit: true,
Rule: true,
AtRule: true,
Comment: true,
DeclarationExit: true,
RuleExit: true,
AtRuleExit: true,
CommentExit: true,
RootExit: true,
DocumentExit: true,
OnceExit: true
RuleExit: true
}
const NOT_VISITORS = {
Once: true,
postcssPlugin: true,
prepare: true,
Once: true
prepare: true
}

@@ -91,8 +91,8 @@

return {
eventIndex: 0,
events,
iterator: 0,
node,
events,
eventIndex: 0,
visitors: [],
visitorIndex: 0,
iterator: 0
visitors: []
}

@@ -148,3 +148,3 @@ }

this.result = new Result(processor, root, opts)
this.helpers = { ...postcss, result: this.result, postcss }
this.helpers = { ...postcss, postcss, result: this.result }
this.plugins = this.processor.plugins.map(plugin => {

@@ -159,63 +159,2 @@ if (typeof plugin === 'object' && plugin.prepare) {

get [Symbol.toStringTag]() {
return 'LazyResult'
}
get processor() {
return this.result.processor
}
get opts() {
return this.result.opts
}
get css() {
return this.stringify().css
}
get content() {
return this.stringify().content
}
get map() {
return this.stringify().map
}
get root() {
return this.sync().root
}
get messages() {
return this.sync().messages
}
warnings() {
return this.sync().warnings()
}
toString() {
return this.css
}
then(onFulfilled, onRejected) {
if (process.env.NODE_ENV !== 'production') {
if (!('from' in this.opts)) {
warnOnce(
'Without `from` option PostCSS could generate wrong source map ' +
'and will not find Browserslist config. Set it to CSS file path ' +
'or to `undefined` to prevent this warning.'
)
}
}
return this.async().then(onFulfilled, onRejected)
}
catch(onRejected) {
return this.async().catch(onRejected)
}
finally(onFinally) {
return this.async().then(onFinally, onFinally)
}
async() {

@@ -230,122 +169,18 @@ if (this.error) return Promise.reject(this.error)

sync() {
if (this.error) throw this.error
if (this.processed) return this.result
this.processed = true
if (this.processing) {
throw this.getAsyncError()
}
for (let plugin of this.plugins) {
let promise = this.runOnRoot(plugin)
if (isPromise(promise)) {
throw this.getAsyncError()
}
}
this.prepareVisitors()
if (this.hasListener) {
let root = this.result.root
while (!root[isClean]) {
root[isClean] = true
this.walkSync(root)
}
if (this.listeners.OnceExit) {
if (root.type === 'document') {
for (let subRoot of root.nodes) {
this.visitSync(this.listeners.OnceExit, subRoot)
}
} else {
this.visitSync(this.listeners.OnceExit, root)
}
}
}
return this.result
catch(onRejected) {
return this.async().catch(onRejected)
}
stringify() {
if (this.error) throw this.error
if (this.stringified) return this.result
this.stringified = true
this.sync()
let opts = this.result.opts
let str = stringify
if (opts.syntax) str = opts.syntax.stringify
if (opts.stringifier) str = opts.stringifier
if (str.stringify) str = str.stringify
let map = new MapGenerator(str, this.result.root, this.result.opts)
let data = map.generate()
this.result.css = data[0]
this.result.map = data[1]
return this.result
get content() {
return this.stringify().content
}
walkSync(node) {
node[isClean] = true
let events = getEvents(node)
for (let event of events) {
if (event === CHILDREN) {
if (node.nodes) {
node.each(child => {
if (!child[isClean]) this.walkSync(child)
})
}
} else {
let visitors = this.listeners[event]
if (visitors) {
if (this.visitSync(visitors, node.toProxy())) return
}
}
}
get css() {
return this.stringify().css
}
visitSync(visitors, node) {
for (let [plugin, visitor] of visitors) {
this.result.lastPlugin = plugin
let promise
try {
promise = visitor(node, this.helpers)
} catch (e) {
throw this.handleError(e, node.proxyOf)
}
if (node.type !== 'root' && node.type !== 'document' && !node.parent) {
return true
}
if (isPromise(promise)) {
throw this.getAsyncError()
}
}
finally(onFinally) {
return this.async().then(onFinally, onFinally)
}
runOnRoot(plugin) {
this.result.lastPlugin = plugin
try {
if (typeof plugin === 'object' && plugin.Once) {
if (this.result.root.type === 'document') {
let roots = this.result.root.nodes.map(root =>
plugin.Once(root, this.helpers)
)
if (isPromise(roots[0])) {
return Promise.all(roots)
}
return roots
}
return plugin.Once(this.result.root, this.helpers)
} else if (typeof plugin === 'function') {
return plugin(this.result.root, this.result)
}
} catch (error) {
throw this.handleError(error)
}
}
getAsyncError() {

@@ -394,2 +229,60 @@ throw new Error('Use process(css).then(cb) to work with async plugins')

get map() {
return this.stringify().map
}
get messages() {
return this.sync().messages
}
get opts() {
return this.result.opts
}
prepareVisitors() {
this.listeners = {}
let add = (plugin, type, cb) => {
if (!this.listeners[type]) this.listeners[type] = []
this.listeners[type].push([plugin, cb])
}
for (let plugin of this.plugins) {
if (typeof plugin === 'object') {
for (let event in plugin) {
if (!PLUGIN_PROPS[event] && /^[A-Z]/.test(event)) {
throw new Error(
`Unknown event ${event} in ${plugin.postcssPlugin}. ` +
`Try to update PostCSS (${this.processor.version} now).`
)
}
if (!NOT_VISITORS[event]) {
if (typeof plugin[event] === 'object') {
for (let filter in plugin[event]) {
if (filter === '*') {
add(plugin, event, plugin[event][filter])
} else {
add(
plugin,
event + '-' + filter.toLowerCase(),
plugin[event][filter]
)
}
}
} else if (typeof plugin[event] === 'function') {
add(plugin, event, plugin[event])
}
}
}
}
}
this.hasListener = Object.keys(this.listeners).length > 0
}
get processor() {
return this.result.processor
}
get root() {
return this.sync().root
}
async runAsync() {

@@ -452,40 +345,124 @@ this.plugin = 0

prepareVisitors() {
this.listeners = {}
let add = (plugin, type, cb) => {
if (!this.listeners[type]) this.listeners[type] = []
this.listeners[type].push([plugin, cb])
runOnRoot(plugin) {
this.result.lastPlugin = plugin
try {
if (typeof plugin === 'object' && plugin.Once) {
if (this.result.root.type === 'document') {
let roots = this.result.root.nodes.map(root =>
plugin.Once(root, this.helpers)
)
if (isPromise(roots[0])) {
return Promise.all(roots)
}
return roots
}
return plugin.Once(this.result.root, this.helpers)
} else if (typeof plugin === 'function') {
return plugin(this.result.root, this.result)
}
} catch (error) {
throw this.handleError(error)
}
}
stringify() {
if (this.error) throw this.error
if (this.stringified) return this.result
this.stringified = true
this.sync()
let opts = this.result.opts
let str = stringify
if (opts.syntax) str = opts.syntax.stringify
if (opts.stringifier) str = opts.stringifier
if (str.stringify) str = str.stringify
let map = new MapGenerator(str, this.result.root, this.result.opts)
let data = map.generate()
this.result.css = data[0]
this.result.map = data[1]
return this.result
}
get [Symbol.toStringTag]() {
return 'LazyResult'
}
sync() {
if (this.error) throw this.error
if (this.processed) return this.result
this.processed = true
if (this.processing) {
throw this.getAsyncError()
}
for (let plugin of this.plugins) {
if (typeof plugin === 'object') {
for (let event in plugin) {
if (!PLUGIN_PROPS[event] && /^[A-Z]/.test(event)) {
throw new Error(
`Unknown event ${event} in ${plugin.postcssPlugin}. ` +
`Try to update PostCSS (${this.processor.version} now).`
)
let promise = this.runOnRoot(plugin)
if (isPromise(promise)) {
throw this.getAsyncError()
}
}
this.prepareVisitors()
if (this.hasListener) {
let root = this.result.root
while (!root[isClean]) {
root[isClean] = true
this.walkSync(root)
}
if (this.listeners.OnceExit) {
if (root.type === 'document') {
for (let subRoot of root.nodes) {
this.visitSync(this.listeners.OnceExit, subRoot)
}
if (!NOT_VISITORS[event]) {
if (typeof plugin[event] === 'object') {
for (let filter in plugin[event]) {
if (filter === '*') {
add(plugin, event, plugin[event][filter])
} else {
add(
plugin,
event + '-' + filter.toLowerCase(),
plugin[event][filter]
)
}
}
} else if (typeof plugin[event] === 'function') {
add(plugin, event, plugin[event])
}
}
} else {
this.visitSync(this.listeners.OnceExit, root)
}
}
}
this.hasListener = Object.keys(this.listeners).length > 0
return this.result
}
then(onFulfilled, onRejected) {
if (process.env.NODE_ENV !== 'production') {
if (!('from' in this.opts)) {
warnOnce(
'Without `from` option PostCSS could generate wrong source map ' +
'and will not find Browserslist config. Set it to CSS file path ' +
'or to `undefined` to prevent this warning.'
)
}
}
return this.async().then(onFulfilled, onRejected)
}
toString() {
return this.css
}
visitSync(visitors, node) {
for (let [plugin, visitor] of visitors) {
this.result.lastPlugin = plugin
let promise
try {
promise = visitor(node, this.helpers)
} catch (e) {
throw this.handleError(e, node.proxyOf)
}
if (node.type !== 'root' && node.type !== 'document' && !node.parent) {
return true
}
if (isPromise(promise)) {
throw this.getAsyncError()
}
}
}
visitTick(stack) {

@@ -547,2 +524,25 @@ let visit = stack[stack.length - 1]

}
walkSync(node) {
node[isClean] = true
let events = getEvents(node)
for (let event of events) {
if (event === CHILDREN) {
if (node.nodes) {
node.each(child => {
if (!child[isClean]) this.walkSync(child)
})
}
} else {
let visitors = this.listeners[event]
if (visitors) {
if (this.visitSync(visitors, node.toProxy())) return
}
}
}
}
warnings() {
return this.sync().warnings()
}
}

@@ -549,0 +549,0 @@

declare namespace list {
type List = {
default: List
/**
* Safely splits values.
* Safely splits comma-separated values (such as those for `transition-*`
* and `background` properties).
*
* ```js
* Once (root, { list }) {
* list.split('1px calc(10% + 1px)', [' ', '\n', '\t']) //=> ['1px', 'calc(10% + 1px)']
* list.comma('black, linear-gradient(white, black)')
* //=> ['black', 'linear-gradient(white, black)']
* }
* ```
*
* @param string separated values.
* @param separators array of separators.
* @param last boolean indicator.
* @param str Comma-separated values.
* @return Split values.
*/
split(string: string, separators: string[], last: boolean): string[]
comma(str: string): string[]
default: List
/**

@@ -37,16 +37,16 @@ * Safely splits space-separated values (such as those for `background`,

/**
* Safely splits comma-separated values (such as those for `transition-*`
* and `background` properties).
* Safely splits values.
*
* ```js
* Once (root, { list }) {
* list.comma('black, linear-gradient(white, black)')
* //=> ['black', 'linear-gradient(white, black)']
* list.split('1px calc(10% + 1px)', [' ', '\n', '\t']) //=> ['1px', 'calc(10% + 1px)']
* }
* ```
*
* @param str Comma-separated values.
* @param string separated values.
* @param separators array of separators.
* @param last boolean indicator.
* @return Split values.
*/
comma(str: string): string[]
split(string: string, separators: string[], last: boolean): string[]
}

@@ -53,0 +53,0 @@ }

'use strict'
let list = {
comma(string) {
return list.split(string, [','], true)
},
space(string) {
let spaces = [' ', '\n', '\t']
return list.split(string, spaces)
},
split(string, separators, last) {

@@ -45,11 +54,2 @@ let array = []

return array
},
space(string) {
let spaces = [' ', '\n', '\t']
return list.split(string, spaces)
},
comma(string) {
return list.split(string, [','], true)
}

@@ -56,0 +56,0 @@ }

'use strict'
let { SourceMapConsumer, SourceMapGenerator } = require('source-map-js')
let { dirname, resolve, relative, sep } = require('path')
let { dirname, relative, resolve, sep } = require('path')
let { pathToFileURL } = require('url')

@@ -22,96 +22,21 @@

isMap() {
if (typeof this.opts.map !== 'undefined') {
return !!this.opts.map
}
return this.previous().length > 0
}
addAnnotation() {
let content
previous() {
if (!this.previousMaps) {
this.previousMaps = []
if (this.root) {
this.root.walk(node => {
if (node.source && node.source.input.map) {
let map = node.source.input.map
if (!this.previousMaps.includes(map)) {
this.previousMaps.push(map)
}
}
})
} else {
let input = new Input(this.css, this.opts)
if (input.map) this.previousMaps.push(input.map)
}
if (this.isInline()) {
content =
'data:application/json;base64,' + this.toBase64(this.map.toString())
} else if (typeof this.mapOpts.annotation === 'string') {
content = this.mapOpts.annotation
} else if (typeof this.mapOpts.annotation === 'function') {
content = this.mapOpts.annotation(this.opts.to, this.root)
} else {
content = this.outputFile() + '.map'
}
let eol = '\n'
if (this.css.includes('\r\n')) eol = '\r\n'
return this.previousMaps
this.css += eol + '/*# sourceMappingURL=' + content + ' */'
}
isInline() {
if (typeof this.mapOpts.inline !== 'undefined') {
return this.mapOpts.inline
}
let annotation = this.mapOpts.annotation
if (typeof annotation !== 'undefined' && annotation !== true) {
return false
}
if (this.previous().length) {
return this.previous().some(i => i.inline)
}
return true
}
isSourcesContent() {
if (typeof this.mapOpts.sourcesContent !== 'undefined') {
return this.mapOpts.sourcesContent
}
if (this.previous().length) {
return this.previous().some(i => i.withContent())
}
return true
}
clearAnnotation() {
if (this.mapOpts.annotation === false) return
if (this.root) {
let node
for (let i = this.root.nodes.length - 1; i >= 0; i--) {
node = this.root.nodes[i]
if (node.type !== 'comment') continue
if (node.text.indexOf('# sourceMappingURL=') === 0) {
this.root.removeChild(i)
}
}
} else if (this.css) {
this.css = this.css.replace(/(\n)?\/\*#[\S\s]*?\*\/$/gm, '')
}
}
setSourcesContent() {
let already = {}
if (this.root) {
this.root.walk(node => {
if (node.source) {
let from = node.source.input.from
if (from && !already[from]) {
already[from] = true
let fromUrl = this.usesFileUrls
? this.toFileUrl(from)
: this.toUrl(this.path(from))
this.map.setSourceContent(fromUrl, node.source.input.css)
}
}
})
} else if (this.css) {
let from = this.opts.from
? this.toUrl(this.path(this.opts.from))
: '<no source>'
this.map.setSourceContent(from, this.css)
}
}
applyPrevMaps() {

@@ -136,52 +61,32 @@ for (let prev of this.previous()) {

isAnnotation() {
if (this.isInline()) {
return true
}
if (typeof this.mapOpts.annotation !== 'undefined') {
return this.mapOpts.annotation
}
if (this.previous().length) {
return this.previous().some(i => i.annotation)
}
return true
}
clearAnnotation() {
if (this.mapOpts.annotation === false) return
toBase64(str) {
if (Buffer) {
return Buffer.from(str).toString('base64')
} else {
return window.btoa(unescape(encodeURIComponent(str)))
if (this.root) {
let node
for (let i = this.root.nodes.length - 1; i >= 0; i--) {
node = this.root.nodes[i]
if (node.type !== 'comment') continue
if (node.text.indexOf('# sourceMappingURL=') === 0) {
this.root.removeChild(i)
}
}
} else if (this.css) {
this.css = this.css.replace(/(\n)?\/\*#[\S\s]*?\*\/$/gm, '')
}
}
addAnnotation() {
let content
if (this.isInline()) {
content =
'data:application/json;base64,' + this.toBase64(this.map.toString())
} else if (typeof this.mapOpts.annotation === 'string') {
content = this.mapOpts.annotation
} else if (typeof this.mapOpts.annotation === 'function') {
content = this.mapOpts.annotation(this.opts.to, this.root)
generate() {
this.clearAnnotation()
if (pathAvailable && sourceMapAvailable && this.isMap()) {
return this.generateMap()
} else {
content = this.outputFile() + '.map'
let result = ''
this.stringify(this.root, i => {
result += i
})
return [result]
}
let eol = '\n'
if (this.css.includes('\r\n')) eol = '\r\n'
this.css += eol + '/*# sourceMappingURL=' + content + ' */'
}
outputFile() {
if (this.opts.to) {
return this.path(this.opts.to)
} else if (this.opts.from) {
return this.path(this.opts.from)
} else {
return 'to.css'
}
}
generateMap() {

@@ -197,7 +102,7 @@ if (this.root) {

this.map.addMapping({
generated: { column: 0, line: 1 },
original: { column: 0, line: 1 },
source: this.opts.from
? this.toUrl(this.path(this.opts.from))
: '<no source>',
generated: { line: 1, column: 0 },
original: { line: 1, column: 0 }
: '<no source>'
})

@@ -217,44 +122,2 @@ }

path(file) {
if (file.indexOf('<') === 0) return file
if (/^\w+:\/\//.test(file)) return file
if (this.mapOpts.absolute) return file
let from = this.opts.to ? dirname(this.opts.to) : '.'
if (typeof this.mapOpts.annotation === 'string') {
from = dirname(resolve(from, this.mapOpts.annotation))
}
file = relative(from, file)
return file
}
toUrl(path) {
if (sep === '\\') {
path = path.replace(/\\/g, '/')
}
return encodeURI(path).replace(/[#?]/g, encodeURIComponent)
}
toFileUrl(path) {
if (pathToFileURL) {
return pathToFileURL(path).toString()
} else {
throw new Error(
'`map.absolute` option is not available in this PostCSS build'
)
}
}
sourcePath(node) {
if (this.mapOpts.from) {
return this.toUrl(this.mapOpts.from)
} else if (this.usesFileUrls) {
return this.toFileUrl(node.source.input.from)
} else {
return this.toUrl(this.path(node.source.input.from))
}
}
generateString() {

@@ -269,5 +132,5 @@ this.css = ''

let mapping = {
source: '',
generated: { line: 0, column: 0 },
original: { line: 0, column: 0 }
generated: { column: 0, line: 0 },
original: { column: 0, line: 0 },
source: ''
}

@@ -329,16 +192,153 @@

generate() {
this.clearAnnotation()
if (pathAvailable && sourceMapAvailable && this.isMap()) {
return this.generateMap()
isAnnotation() {
if (this.isInline()) {
return true
}
if (typeof this.mapOpts.annotation !== 'undefined') {
return this.mapOpts.annotation
}
if (this.previous().length) {
return this.previous().some(i => i.annotation)
}
return true
}
isInline() {
if (typeof this.mapOpts.inline !== 'undefined') {
return this.mapOpts.inline
}
let annotation = this.mapOpts.annotation
if (typeof annotation !== 'undefined' && annotation !== true) {
return false
}
if (this.previous().length) {
return this.previous().some(i => i.inline)
}
return true
}
isMap() {
if (typeof this.opts.map !== 'undefined') {
return !!this.opts.map
}
return this.previous().length > 0
}
isSourcesContent() {
if (typeof this.mapOpts.sourcesContent !== 'undefined') {
return this.mapOpts.sourcesContent
}
if (this.previous().length) {
return this.previous().some(i => i.withContent())
}
return true
}
outputFile() {
if (this.opts.to) {
return this.path(this.opts.to)
} else if (this.opts.from) {
return this.path(this.opts.from)
} else {
let result = ''
this.stringify(this.root, i => {
result += i
return 'to.css'
}
}
path(file) {
if (file.indexOf('<') === 0) return file
if (/^\w+:\/\//.test(file)) return file
if (this.mapOpts.absolute) return file
let from = this.opts.to ? dirname(this.opts.to) : '.'
if (typeof this.mapOpts.annotation === 'string') {
from = dirname(resolve(from, this.mapOpts.annotation))
}
file = relative(from, file)
return file
}
previous() {
if (!this.previousMaps) {
this.previousMaps = []
if (this.root) {
this.root.walk(node => {
if (node.source && node.source.input.map) {
let map = node.source.input.map
if (!this.previousMaps.includes(map)) {
this.previousMaps.push(map)
}
}
})
} else {
let input = new Input(this.css, this.opts)
if (input.map) this.previousMaps.push(input.map)
}
}
return this.previousMaps
}
setSourcesContent() {
let already = {}
if (this.root) {
this.root.walk(node => {
if (node.source) {
let from = node.source.input.from
if (from && !already[from]) {
already[from] = true
let fromUrl = this.usesFileUrls
? this.toFileUrl(from)
: this.toUrl(this.path(from))
this.map.setSourceContent(fromUrl, node.source.input.css)
}
}
})
return [result]
} else if (this.css) {
let from = this.opts.from
? this.toUrl(this.path(this.opts.from))
: '<no source>'
this.map.setSourceContent(from, this.css)
}
}
sourcePath(node) {
if (this.mapOpts.from) {
return this.toUrl(this.mapOpts.from)
} else if (this.usesFileUrls) {
return this.toFileUrl(node.source.input.from)
} else {
return this.toUrl(this.path(node.source.input.from))
}
}
toBase64(str) {
if (Buffer) {
return Buffer.from(str).toString('base64')
} else {
return window.btoa(unescape(encodeURIComponent(str)))
}
}
toFileUrl(path) {
if (pathToFileURL) {
return pathToFileURL(path).toString()
} else {
throw new Error(
'`map.absolute` option is not available in this PostCSS build'
)
}
}
toUrl(path) {
if (sep === '\\') {
path = path.replace(/\\/g, '/')
}
return encodeURI(path).replace(/[#?]/g, encodeURIComponent)
}
}
module.exports = MapGenerator

@@ -1,7 +0,7 @@

import Result, { Message, ResultOptions } from './result.js'
import LazyResult from './lazy-result.js'
import { SourceMap } from './postcss.js'
import Processor from './processor.js'
import Result, { Message, ResultOptions } from './result.js'
import Root from './root.js'
import Warning from './warning.js'
import Root from './root.js'
import LazyResult from './lazy-result.js'

@@ -26,18 +26,18 @@ declare namespace NoWorkResult {

declare class NoWorkResult_ implements LazyResult {
then: Promise<Result>['then']
catch: Promise<Result>['catch']
finally: Promise<Result>['finally']
then: Promise<Result>['then']
constructor(processor: Processor, css: string, opts: ResultOptions)
get [Symbol.toStringTag](): string
get processor(): Processor
get opts(): ResultOptions
async(): Promise<Result>
get content(): string
get css(): string
get content(): string
get map(): SourceMap
get messages(): Message[]
get opts(): ResultOptions
get processor(): Processor
get root(): Root
get messages(): Message[]
get [Symbol.toStringTag](): string
sync(): Result
toString(): string
warnings(): Warning[]
toString(): string
sync(): Result
async(): Promise<Result>
}

@@ -44,0 +44,0 @@

@@ -43,12 +43,13 @@ 'use strict'

get [Symbol.toStringTag]() {
return 'NoWorkResult'
async() {
if (this.error) return Promise.reject(this.error)
return Promise.resolve(this.result)
}
get processor() {
return this.result.processor
catch(onRejected) {
return this.async().catch(onRejected)
}
get opts() {
return this.result.opts
get content() {
return this.result.css
}

@@ -60,4 +61,4 @@

get content() {
return this.result.css
finally(onFinally) {
return this.async().then(onFinally, onFinally)
}

@@ -69,2 +70,14 @@

get messages() {
return []
}
get opts() {
return this.result.opts
}
get processor() {
return this.result.processor
}
get root() {

@@ -92,14 +105,11 @@ if (this._root) {

get messages() {
return []
get [Symbol.toStringTag]() {
return 'NoWorkResult'
}
warnings() {
return []
sync() {
if (this.error) throw this.error
return this.result
}
toString() {
return this._css
}
then(onFulfilled, onRejected) {

@@ -119,19 +129,9 @@ if (process.env.NODE_ENV !== 'production') {

catch(onRejected) {
return this.async().catch(onRejected)
toString() {
return this._css
}
finally(onFinally) {
return this.async().then(onFinally, onFinally)
warnings() {
return []
}
async() {
if (this.error) return Promise.reject(this.error)
return Promise.resolve(this.result)
}
sync() {
if (this.error) throw this.error
return this.result
}
}

@@ -138,0 +138,0 @@

@@ -1,33 +0,35 @@

import Declaration, { DeclarationProps } from './declaration.js'
import Comment, { CommentProps } from './comment.js'
import { Stringifier, Syntax } from './postcss.js'
import AtRule = require('./at-rule.js')
import { AtRuleProps } from './at-rule.js'
import Rule, { RuleProps } from './rule.js'
import Warning, { WarningOptions } from './warning.js'
import Comment, { CommentProps } from './comment.js'
import Container from './container.js'
import CssSyntaxError from './css-syntax-error.js'
import Declaration, { DeclarationProps } from './declaration.js'
import Document from './document.js'
import Input from './input.js'
import { Stringifier, Syntax } from './postcss.js'
import Result from './result.js'
import Input from './input.js'
import Root from './root.js'
import Document from './document.js'
import Container from './container.js'
import Rule, { RuleProps } from './rule.js'
import Warning, { WarningOptions } from './warning.js'
declare namespace Node {
export type ChildNode = AtRule.default | Rule | Declaration | Comment
export type ChildNode = AtRule.default | Comment | Declaration | Rule
export type AnyNode = AtRule.default | Rule | Declaration | Comment | Root | Document
export type AnyNode =
| AtRule.default
| Comment
| Declaration
| Document
| Root
| Rule
export type ChildProps =
| AtRuleProps
| CommentProps
| DeclarationProps
| RuleProps
| DeclarationProps
| CommentProps
export interface Position {
/**
* Source offset in file. It starts from 0.
*/
offset: number
/**
* Source line in file. In contrast to `offset` it starts from 1.

@@ -41,2 +43,7 @@ */

line: number
/**
* Source offset in file. It starts from 0.
*/
offset: number
}

@@ -46,27 +53,38 @@

/**
* Start position, inclusive.
* End position, exclusive.
*/
start: Position
end: Position
/**
* End position, exclusive.
* Start position, inclusive.
*/
end: Position
start: Position
}
/**
* Source represents an interface for the {@link Node.source} property.
*/
export interface Source {
/**
* The file source of the node.
* The inclusive ending position for the source
* code of a node.
*/
end?: Position
/**
* The source file from where a node has originated.
*/
input: Input
/**
* The inclusive starting position of the node’s source.
* The inclusive starting position for the source
* code of a node.
*/
start?: Position
/**
* The inclusive ending position of the node's source.
*/
end?: Position
}
/**
* Interface represents an interface for an object received
* as parameter by Node class constructor.
*/
export interface NodeProps {

@@ -78,2 +96,12 @@ source?: Source

/**
* An ending index inside a node's string that should be highlighted as
* source of error.
*/
endIndex?: number
/**
* An index inside a node's string that should be highlighted as source
* of error.
*/
index?: number
/**
* Plugin name that created this error. PostCSS will set it automatically.

@@ -87,12 +115,2 @@ */

word?: string
/**
* An index inside a node's string that should be highlighted as source
* of error.
*/
index?: number
/**
* An ending index inside a node's string that should be highlighted as
* source of error.
*/
endIndex?: number
}

@@ -106,47 +124,75 @@

/**
* All node classes inherit the following common methods.
* It represents an abstract class that handles common
* methods for other CSS abstract syntax tree nodes.
*
* You should not extend this classes to create AST for selector or value
* parser.
* Any node that represents CSS selector or value should
* not extend the `Node` class.
*/
declare abstract class Node_ {
/**
* tring representing the node’s type. Possible values are `root`, `atrule`,
* `rule`, `decl`, or `comment`.
* It represents parent of the current node.
*
* ```js
* new Declaration({ prop: 'color', value: 'black' }).type //=> 'decl'
* console.log(root.nodes[0].parent === root) //=> true
* ```
*/
type: string
parent: Container | Document | undefined
/**
* The node’s parent node.
* It represents unnecessary whitespace and characters present
* in the css source code.
*
* Information to generate byte-to-byte equal node string as it was
* in the origin input.
*
* The properties of the raws object are decided by parser,
* the default parser uses the following properties:
*
* * `before`: the space symbols before the node. It also stores `*`
* and `_` symbols before the declaration (IE hack).
* * `after`: the space symbols after the last child of the node
* to the end of the node.
* * `between`: the symbols between the property and value
* for declarations, selector and `{` for rules, or last parameter
* and `{` for at-rules.
* * `semicolon`: contains true if the last child has
* an (optional) semicolon.
* * `afterName`: the space between the at-rule name and its parameters.
* * `left`: the space symbols between `/*` and the comment’s text.
* * `right`: the space symbols between the comment’s text
* and <code>*&#47;</code>.
* - `important`: the content of the important statement,
* if it is not just `!important`.
*
* PostCSS filters out the comments inside selectors, declaration values
* and at-rule parameters but it stores the origin content in raws.
*
* ```js
* root.nodes[0].parent === root
* const root = postcss.parse('a {\n color:black\n}')
* console.log(root.first.first.raws) //=> { before: '\n ', between: ':' }
* ```
*/
parent: Document | Container | undefined
raws: any
/**
* The input source of the node.
* It represents information related to origin of a node and is required
* for generating source maps.
*
* The property is used in source map generation.
* The nodes that are created manually using the public APIs
* provided by PostCSS will have `source` undefined and
* will be absent in the source map.
*
* If you create a node manually (e.g., with `postcss.decl()`),
* that node will not have a `source` property and will be absent
* from the source map. For this reason, the plugin developer should
* consider cloning nodes to create new ones (in which case the new node’s
* source will reference the original, cloned node) or setting
* the `source` property manually.
* For this reason, the plugin developer should consider
* duplicating nodes as the duplicate node will have the
* same source as the original node by default or assign
* source to a node created manually.
*
* ```js
* decl.source.input.from //=> '/home/ai/a.sass'
* decl.source.start //=> { line: 10, column: 2 }
* decl.source.end //=> { line: 10, column: 12 }
* console.log(decl.source.input.from) //=> '/home/ai/source.css'
* console.log(decl.source.start) //=> { line: 10, column: 2 }
* console.log(decl.source.end) //=> { line: 10, column: 12 }
* ```
*
* ```js
* // Bad
* // Incorrect method, source not specified!
* const prefixed = postcss.decl({

@@ -157,4 +203,6 @@ * prop: '-moz-' + decl.prop,

*
* // Good
* const prefixed = decl.clone({ prop: '-moz-' + decl.prop })
* // Correct method, source is inherited when duplicating.
* const prefixed = decl.clone({
* prop: '-moz-' + decl.prop
* })
* ```

@@ -164,4 +212,8 @@ *

* if (atrule.name === 'add-link') {
* const rule = postcss.rule({ selector: 'a', source: atrule.source })
* atrule.parent.insertBefore(atrule, rule)
* const rule = postcss.rule({
* selector: 'a',
* source: atrule.source
* })
*
* atrule.parent.insertBefore(atrule, rule)
* }

@@ -173,133 +225,79 @@ * ```

/**
* Information to generate byte-to-byte equal node string as it was
* in the origin input.
* It represents type of a node in
* an abstract syntax tree.
*
* Every parser saves its own properties,
* but the default CSS parser uses:
* A type of node helps in identification of a node
* and perform operation based on it's type.
*
* * `before`: the space symbols before the node. It also stores `*`
* and `_` symbols before the declaration (IE hack).
* * `after`: the space symbols after the last child of the node
* to the end of the node.
* * `between`: the symbols between the property and value
* for declarations, selector and `{` for rules, or last parameter
* and `{` for at-rules.
* * `semicolon`: contains true if the last child has
* an (optional) semicolon.
* * `afterName`: the space between the at-rule name and its parameters.
* * `left`: the space symbols between `/*` and the comment’s text.
* * `right`: the space symbols between the comment’s text
* and <code>*&#47;</code>.
* * `important`: the content of the important statement,
* if it is not just `!important`.
* ```js
* const declaration = new Declaration({
* prop: 'color',
* value: 'black'
* })
*
* PostCSS cleans selectors, declaration values and at-rule parameters
* from comments and extra spaces, but it stores origin content in raws
* properties. As such, if you don’t change a declaration’s value,
* PostCSS will use the raw value with comments.
*
* ```js
* const root = postcss.parse('a {\n color:black\n}')
* root.first.first.raws //=> { before: '\n ', between: ':' }
* console.log(declaration.type) //=> 'decl'
* ```
*/
raws: any
type: string
/**
* @param defaults Value for node properties.
*/
constructor(defaults?: object)
/**
* Returns a `CssSyntaxError` instance containing the original position
* of the node in the source, showing line and column numbers and also
* a small excerpt to facilitate debugging.
* Insert new node after current node to current node’s parent.
*
* If present, an input source map will be used to get the original position
* of the source, even from a previous compilation step
* (e.g., from Sass compilation).
* Just alias for `node.parent.insertAfter(node, add)`.
*
* This method produces very useful error messages.
*
* ```js
* if (!variables[name]) {
* throw decl.error(`Unknown variable ${name}`, { word: name })
* // CssSyntaxError: postcss-vars:a.sass:4:3: Unknown variable $black
* // color: $black
* // a
* // ^
* // background: white
* }
* decl.after('color: black')
* ```
*
* @param message Error description.
* @param opts Options.
*
* @return Error object to throw it.
* @param newNode New node.
* @return This node for methods chain.
*/
error(message: string, options?: Node.NodeErrorOptions): CssSyntaxError
after(newNode: Node | Node.ChildProps | Node[] | string): this
/**
* This method is provided as a convenience wrapper for `Result#warn`.
* It assigns properties to an existing node instance.
*
* ```js
* Declaration: {
* bad: (decl, { result }) => {
* decl.warn(result, 'Deprecated property bad')
* }
* }
* decl.assign({ prop: 'word-wrap', value: 'break-word' })
* ```
*
* @param result The `Result` instance that will receive the warning.
* @param text Warning message.
* @param opts Warning Options.
* @param overrides New properties to override the node.
*
* @return Created warning object.
* @return `this` for method chaining.
*/
warn(result: Result, text: string, opts?: WarningOptions): Warning
assign(overrides: object): this
/**
* Removes the node from its parent and cleans the parent properties
* from the node and its children.
* Insert new node before current node to current node’s parent.
*
* ```js
* if (decl.prop.match(/^-webkit-/)) {
* decl.remove()
* }
* ```
* Just alias for `node.parent.insertBefore(node, add)`.
*
* @return Node to make calls chain.
*/
remove(): this
/**
* Returns a CSS string representing the node.
*
* ```js
* new Rule({ selector: 'a' }).toString() //=> "a {}"
* decl.before('content: ""')
* ```
*
* @param stringifier A syntax to use in string generation.
* @return CSS string of this node.
* @param newNode New node.
* @return This node for methods chain.
*/
toString(stringifier?: Stringifier | Syntax): string
before(newNode: Node | Node.ChildProps | Node[] | string): this
/**
* Assigns properties to the current node.
* Clear the code style properties for the node and its children.
*
* ```js
* decl.assign({ prop: 'word-wrap', value: 'break-word' })
* node.raws.before //=> ' '
* node.cleanRaws()
* node.raws.before //=> undefined
* ```
*
* @param overrides New properties to override the node.
* @return Current node to methods chain.
* @param keepBetween Keep the `raws.between` symbols.
*/
assign(overrides: object): this
cleanRaws(keepBetween?: boolean): void
/**
* Returns an exact clone of the node.
* It creates clone of an existing node, which includes all the properties
* and their values, that includes `raws` but not `type`.
*
* The resulting cloned node and its (cloned) children will retain
* code style properties.
*
* ```js

@@ -313,8 +311,18 @@ * decl.raws.before //=> "\n "

* @param overrides New properties to override in the clone.
* @return Clone of the node.
*
* @return Duplicate of the node instance.
*/
clone(overrides?: object): this
clone(overrides?: object): Node_
/**
* Shortcut to clone the node and insert the resulting cloned node
* after the current node.
*
* @param overrides New properties to override in the clone.
* @return New node.
*/
cloneAfter(overrides?: object): this
/**
* Shortcut to clone the node and insert the resulting cloned node
* before the current node.

@@ -333,27 +341,36 @@ *

/**
* Shortcut to clone the node and insert the resulting cloned node
* after the current node.
* It creates an instance of the class `CssSyntaxError` and parameters passed
* to this method are assigned to the error instance.
*
* @param overrides New properties to override in the clone.
* @return New node.
*/
cloneAfter(overrides?: object): this
/**
* Inserts node(s) before the current node and removes the current node.
* The error instance will have description for the
* error, original position of the node in the
* source, showing line and column number.
*
* If any previous map is present, it would be used
* to get original position of the source.
*
* The Previous Map here is referred to the source map
* generated by previous compilation, example: Less,
* Stylus and Sass.
*
* This method returns the error instance instead of
* throwing it.
*
* ```js
* AtRule: {
* mixin: atrule => {
* atrule.replaceWith(mixinRules[atrule.params])
* }
* if (!variables[name]) {
* throw decl.error(`Unknown variable ${name}`, { word: name })
* // CssSyntaxError: postcss-vars:a.sass:4:3: Unknown variable $black
* // color: $black
* // a
* // ^
* // background: white
* }
* ```
*
* @param nodes Mode(s) to replace current one.
* @return Current node to methods chain.
* @param message Description for the error instance.
* @param options Options for the error instance.
*
* @return Error instance is returned.
*/
replaceWith(
...nodes: (Node.ChildNode | Node.ChildProps | Node.ChildNode[] | Node.ChildProps[])[]
): this
error(message: string, options?: Node.NodeErrorOptions): CssSyntaxError

@@ -378,2 +395,18 @@ /**

/**
* Get the position for a word or an index inside the node.
*
* @param opts Options.
* @return Position.
*/
positionBy(opts?: Pick<WarningOptions, 'index' | 'word'>): Node.Position
/**
* Convert string index to line/column.
*
* @param index The symbol number in the node’s string.
* @return Symbol position in file.
*/
positionInside(index: number): Node.Position
/**
* Returns the previous child of the node’s parent.

@@ -394,72 +427,78 @@ * Returns `undefined` if the current node is the first child.

/**
* Insert new node before current node to current node’s parent.
* Get the range for a word or start and end index inside the node.
* The start index is inclusive; the end index is exclusive.
*
* Just alias for `node.parent.insertBefore(node, add)`.
*
* ```js
* decl.before('content: ""')
* ```
*
* @param newNode New node.
* @return This node for methods chain.
* @param opts Options.
* @return Range.
*/
before(newNode: Node | Node.ChildProps | string | Node[]): this
rangeBy(
opts?: Pick<WarningOptions, 'endIndex' | 'index' | 'word'>
): Node.Range
/**
* Insert new node after current node to current node’s parent.
* Returns a `raws` value. If the node is missing
* the code style property (because the node was manually built or cloned),
* PostCSS will try to autodetect the code style property by looking
* at other nodes in the tree.
*
* Just alias for `node.parent.insertAfter(node, add)`.
*
* ```js
* decl.after('color: black')
* const root = postcss.parse('a { background: white }')
* root.nodes[0].append({ prop: 'color', value: 'black' })
* root.nodes[0].nodes[1].raws.before //=> undefined
* root.nodes[0].nodes[1].raw('before') //=> ' '
* ```
*
* @param newNode New node.
* @return This node for methods chain.
* @param prop Name of code style property.
* @param defaultType Name of default value, it can be missed
* if the value is the same as prop.
* @return {string} Code style value.
*/
after(newNode: Node | Node.ChildProps | string | Node[]): this
raw(prop: string, defaultType?: string): string
/**
* Finds the Root instance of the node’s tree.
* It removes the node from its parent and deletes its parent property.
*
* ```js
* root.nodes[0].nodes[0].root() === root
* if (decl.prop.match(/^-webkit-/)) {
* decl.remove()
* }
* ```
*
* @return Root parent.
* @return `this` for method chaining.
*/
root(): Root
remove(): this
/**
* Returns a `Node#raws` value. If the node is missing
* the code style property (because the node was manually built or cloned),
* PostCSS will try to autodetect the code style property by looking
* at other nodes in the tree.
* Inserts node(s) before the current node and removes the current node.
*
* ```js
* const root = postcss.parse('a { background: white }')
* root.nodes[0].append({ prop: 'color', value: 'black' })
* root.nodes[0].nodes[1].raws.before //=> undefined
* root.nodes[0].nodes[1].raw('before') //=> ' '
* AtRule: {
* mixin: atrule => {
* atrule.replaceWith(mixinRules[atrule.params])
* }
* }
* ```
*
* @param prop Name of code style property.
* @param defaultType Name of default value, it can be missed
* if the value is the same as prop.
* @return {string} Code style value.
* @param nodes Mode(s) to replace current one.
* @return Current node to methods chain.
*/
raw(prop: string, defaultType?: string): string
replaceWith(
...nodes: (
| Node.ChildNode
| Node.ChildNode[]
| Node.ChildProps
| Node.ChildProps[]
)[]
): this
/**
* Clear the code style properties for the node and its children.
* Finds the Root instance of the node’s tree.
*
* ```js
* node.raws.before //=> ' '
* node.cleanRaws()
* node.raws.before //=> undefined
* root.nodes[0].nodes[0].root() === root
* ```
*
* @param keepBetween Keep the `raws.between` symbols.
* @return Root parent.
*/
cleanRaws(keepBetween?: boolean): void
root(): Root

@@ -474,29 +513,37 @@ /**

/**
* Convert string index to line/column.
* It compiles the node to browser readable cascading style sheets string
* depending on it's type.
*
* @param index The symbol number in the node’s string.
* @return Symbol position in file.
*/
positionInside(index: number): Node.Position
/**
* Get the position for a word or an index inside the node.
* ```js
* console.log(new Rule({ selector: 'a' }).toString()) //=> "a {}"
* ```
*
* @param opts Options.
* @return Position.
* @param stringifier A syntax to use in string generation.
* @return CSS string of this node.
*/
positionBy(opts?: Pick<WarningOptions, 'word' | 'index'>): Node.Position
toString(stringifier?: Stringifier | Syntax): string
/**
* Get the range for a word or start and end index inside the node.
* The start index is inclusive; the end index is exclusive.
* It is a wrapper for {@link Result#warn}, providing convenient
* way of generating warnings.
*
* @param opts Options.
* @return Range.
* ```js
* Declaration: {
* bad: (decl, { result }) => {
* decl.warn(result, 'Deprecated property: bad')
* }
* }
* ```
*
* @param result The `Result` instance that will receive the warning.
* @param message Description for the warning.
* @param options Options for the warning.
*
* @return `Warning` instance is returned
*/
rangeBy(opts?: Pick<WarningOptions, 'word' | 'index' | 'endIndex'>): Node.Range
warn(result: Result, message: string, options?: WarningOptions): Warning
}
declare class Node extends Node_ {}
declare class Node extends Node_ { }
export = Node

@@ -57,38 +57,19 @@ 'use strict'

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
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 new CssSyntaxError(message)
return error
}
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
after(add) {
this.parent.insertAfter(this, add)
return this
}
toString(stringifier = stringify) {
if (stringifier.stringify) stringifier = stringifier.stringify
let result = ''
stringifier(this, i => {
result += i
})
return result
}
assign(overrides = {}) {

@@ -101,2 +82,13 @@ for (let name in overrides) {

before(add) {
this.parent.insertBefore(this, add)
return this
}
cleanRaws(keepBetween) {
delete this.raws.before
delete this.raws.after
if (!keepBetween) delete this.raws.between
}
clone(overrides = {}) {

@@ -110,35 +102,66 @@ let cloned = cloneNode(this)

cloneBefore(overrides = {}) {
cloneAfter(overrides = {}) {
let cloned = this.clone(overrides)
this.parent.insertBefore(this, cloned)
this.parent.insertAfter(this, cloned)
return cloned
}
cloneAfter(overrides = {}) {
cloneBefore(overrides = {}) {
let cloned = this.clone(overrides)
this.parent.insertAfter(this, cloned)
this.parent.insertBefore(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
error(message, opts = {}) {
if (this.source) {
let { end, start } = this.rangeBy(opts)
return this.source.input.error(
message,
{ column: start.column, line: start.line },
{ column: end.column, line: end.line },
opts
)
}
return new CssSyntaxError(message)
}
getProxyProcessor() {
return {
get(node, prop) {
if (prop === 'proxyOf') {
return node
} else if (prop === 'root') {
return () => node.root().toProxy()
} else {
this.parent.insertBefore(bookmark, node)
return node[prop]
}
},
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
}
}
}
if (!foundSelf) {
this.remove()
markDirty() {
if (this[isClean]) {
this[isClean] = false
let next = this
while ((next = next.parent)) {
next[isClean] = false
}
}
return this
}

@@ -152,2 +175,31 @@

positionBy(opts, stringRepresentation) {
let pos = this.source.start
if (opts.index) {
pos = this.positionInside(opts.index, stringRepresentation)
} else if (opts.word) {
stringRepresentation = this.toString()
let index = stringRepresentation.indexOf(opts.word)
if (index !== -1) pos = this.positionInside(index, stringRepresentation)
}
return pos
}
positionInside(index, stringRepresentation) {
let string = stringRepresentation || 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 { column, line }
}
prev() {

@@ -159,12 +211,96 @@ if (!this.parent) return undefined

before(add) {
this.parent.insertBefore(this, add)
get proxyOf() {
return this
}
after(add) {
this.parent.insertAfter(this, add)
rangeBy(opts) {
let start = {
column: this.source.start.column,
line: this.source.start.line
}
let end = this.source.end
? {
column: this.source.end.column + 1,
line: this.source.end.line
}
: {
column: start.column + 1,
line: start.line
}
if (opts.word) {
let stringRepresentation = this.toString()
let index = stringRepresentation.indexOf(opts.word)
if (index !== -1) {
start = this.positionInside(index, stringRepresentation)
end = this.positionInside(index + opts.word.length, stringRepresentation)
}
} else {
if (opts.start) {
start = {
column: opts.start.column,
line: opts.start.line
}
} else if (opts.index) {
start = this.positionInside(opts.index)
}
if (opts.end) {
end = {
column: opts.end.column,
line: opts.end.line
}
} 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 = { column: start.column + 1, line: start.line }
}
return { end, start }
}
raw(prop, defaultType) {
let str = new Stringifier()
return str.raw(this, prop, defaultType)
}
remove() {
if (this.parent) {
this.parent.removeChild(this)
}
this.parent = undefined
return this
}
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
}
root() {

@@ -178,13 +314,2 @@ let result = this

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) {

@@ -222,5 +347,5 @@ let fixed = {}

fixed[name] = {
end: value.end,
inputId,
start: value.start,
end: value.end
start: value.start
}

@@ -239,114 +364,2 @@ } else {

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() {

@@ -359,27 +372,16 @@ if (!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
toString(stringifier = stringify) {
if (stringifier.stringify) stringifier = stringifier.stringify
let result = ''
stringifier(this, i => {
result += i
})
return result
}
markDirty() {
if (this[isClean]) {
this[isClean] = false
let next = this
while ((next = next.parent)) {
next[isClean] = false
}
}
warn(result, text, opts) {
let data = { node: this }
for (let i in opts) data[i] = opts[i]
return result.warn(text, data)
}
get proxyOf() {
return this
}
}

@@ -386,0 +388,0 @@

@@ -34,47 +34,138 @@ 'use strict'

this.createTokenizer()
this.root.source = { input, start: { offset: 0, line: 1, column: 1 } }
this.root.source = { input, start: { column: 1, line: 1, offset: 0 } }
}
createTokenizer() {
this.tokenizer = tokenizer(this.input)
}
atrule(token) {
let node = new AtRule()
node.name = token[1].slice(1)
if (node.name === '') {
this.unnamedAtrule(node, token)
}
this.init(node, token[2])
parse() {
let token
let type
let prev
let shift
let last = false
let open = false
let params = []
let brackets = []
while (!this.tokenizer.endOfFile()) {
token = this.tokenizer.nextToken()
type = token[0]
switch (token[0]) {
case 'space':
this.spaces += token[1]
break
if (type === '(' || type === '[') {
brackets.push(type === '(' ? ')' : ']')
} else if (type === '{' && brackets.length > 0) {
brackets.push('}')
} else if (type === brackets[brackets.length - 1]) {
brackets.pop()
}
case ';':
this.freeSemicolon(token)
if (brackets.length === 0) {
if (type === ';') {
node.source.end = this.getPosition(token[2])
this.semicolon = true
break
case '}':
} else if (type === '{') {
open = true
break
} else if (type === '}') {
if (params.length > 0) {
shift = params.length - 1
prev = params[shift]
while (prev && prev[0] === 'space') {
prev = params[--shift]
}
if (prev) {
node.source.end = this.getPosition(prev[3] || prev[2])
}
}
this.end(token)
break
} else {
params.push(token)
}
} else {
params.push(token)
}
case 'comment':
this.comment(token)
break
if (this.tokenizer.endOfFile()) {
last = true
break
}
}
case 'at-word':
this.atrule(token)
break
node.raws.between = this.spacesAndCommentsFromEnd(params)
if (params.length) {
node.raws.afterName = this.spacesAndCommentsFromStart(params)
this.raw(node, 'params', params)
if (last) {
token = params[params.length - 1]
node.source.end = this.getPosition(token[3] || token[2])
this.spaces = node.raws.between
node.raws.between = ''
}
} else {
node.raws.afterName = ''
node.params = ''
}
case '{':
this.emptyRule(token)
break
if (open) {
node.nodes = []
this.current = node
}
}
default:
this.other(token)
break
checkMissedSemicolon(tokens) {
let colon = this.colon(tokens)
if (colon === false) return
let founded = 0
let token
for (let j = colon - 1; j >= 0; j--) {
token = tokens[j]
if (token[0] !== 'space') {
founded += 1
if (founded === 2) break
}
}
this.endFile()
// If the token is a word, e.g. `!important`, `red` or any other valid property's value.
// Then we need to return the colon after that word token. [3] is the "end" colon of that word.
// And because we need it after that one we do +1 to get the next one.
throw this.input.error(
'Missed semicolon',
token[0] === 'word' ? token[3] + 1 : token[2]
)
}
colon(tokens) {
let brackets = 0
let token, type, prev
for (let [i, element] of tokens.entries()) {
token = element
type = token[0]
if (type === '(') {
brackets += 1
}
if (type === ')') {
brackets -= 1
}
if (brackets === 0 && type === ':') {
if (!prev) {
this.doubleColon(token)
} else if (prev[0] === 'word' && prev[1] === 'progid') {
continue
} else {
return i
}
}
prev = token
}
return false
}
comment(token) {

@@ -98,84 +189,6 @@ let node = new Comment()

emptyRule(token) {
let node = new Rule()
this.init(node, token[2])
node.selector = ''
node.raws.between = ''
this.current = node
createTokenizer() {
this.tokenizer = tokenizer(this.input)
}
other(start) {
let end = false
let type = null
let colon = false
let bracket = null
let brackets = []
let customProperty = start[1].startsWith('--')
let tokens = []
let token = start
while (token) {
type = token[0]
tokens.push(token)
if (type === '(' || type === '[') {
if (!bracket) bracket = token
brackets.push(type === '(' ? ')' : ']')
} else if (customProperty && colon && type === '{') {
if (!bracket) bracket = token
brackets.push('}')
} else if (brackets.length === 0) {
if (type === ';') {
if (colon) {
this.decl(tokens, customProperty)
return
} else {
break
}
} else if (type === '{') {
this.rule(tokens)
return
} else if (type === '}') {
this.tokenizer.back(tokens.pop())
end = true
break
} else if (type === ':') {
colon = true
}
} else if (type === brackets[brackets.length - 1]) {
brackets.pop()
if (brackets.length === 0) bracket = null
}
token = this.tokenizer.nextToken()
}
if (this.tokenizer.endOfFile()) end = true
if (brackets.length > 0) this.unclosedBracket(bracket)
if (end && colon) {
if (!customProperty) {
while (tokens.length) {
token = tokens[tokens.length - 1][0]
if (token !== 'space' && token !== 'comment') break
this.tokenizer.back(tokens.pop())
}
}
this.decl(tokens, customProperty)
} else {
this.unknownWord(tokens)
}
}
rule(tokens) {
tokens.pop()
let node = new Rule()
this.init(node, tokens[0][2])
node.raws.between = this.spacesAndCommentsFromEnd(tokens)
this.raw(node, 'selector', tokens)
this.current = node
}
decl(tokens, customProperty) {

@@ -285,83 +298,16 @@ let node = new Declaration()

atrule(token) {
let node = new AtRule()
node.name = token[1].slice(1)
if (node.name === '') {
this.unnamedAtrule(node, token)
}
doubleColon(token) {
throw this.input.error(
'Double colon',
{ offset: token[2] },
{ offset: token[2] + token[1].length }
)
}
emptyRule(token) {
let node = new Rule()
this.init(node, token[2])
let type
let prev
let shift
let last = false
let open = false
let params = []
let brackets = []
while (!this.tokenizer.endOfFile()) {
token = this.tokenizer.nextToken()
type = token[0]
if (type === '(' || type === '[') {
brackets.push(type === '(' ? ')' : ']')
} else if (type === '{' && brackets.length > 0) {
brackets.push('}')
} else if (type === brackets[brackets.length - 1]) {
brackets.pop()
}
if (brackets.length === 0) {
if (type === ';') {
node.source.end = this.getPosition(token[2])
this.semicolon = true
break
} else if (type === '{') {
open = true
break
} else if (type === '}') {
if (params.length > 0) {
shift = params.length - 1
prev = params[shift]
while (prev && prev[0] === 'space') {
prev = params[--shift]
}
if (prev) {
node.source.end = this.getPosition(prev[3] || prev[2])
}
}
this.end(token)
break
} else {
params.push(token)
}
} else {
params.push(token)
}
if (this.tokenizer.endOfFile()) {
last = true
break
}
}
node.raws.between = this.spacesAndCommentsFromEnd(params)
if (params.length) {
node.raws.afterName = this.spacesAndCommentsFromStart(params)
this.raw(node, 'params', params)
if (last) {
token = params[params.length - 1]
node.source.end = this.getPosition(token[3] || token[2])
this.spaces = node.raws.between
node.raws.between = ''
}
} else {
node.raws.afterName = ''
node.params = ''
}
if (open) {
node.nodes = []
this.current = node
}
node.selector = ''
node.raws.between = ''
this.current = node
}

@@ -410,5 +356,5 @@

return {
offset,
column: pos.col,
line: pos.line,
column: pos.col
offset
}

@@ -420,4 +366,4 @@ }

node.source = {
start: this.getPosition(offset),
input: this.input
input: this.input,
start: this.getPosition(offset)
}

@@ -429,2 +375,107 @@ node.raws.before = this.spaces

other(start) {
let end = false
let type = null
let colon = false
let bracket = null
let brackets = []
let customProperty = start[1].startsWith('--')
let tokens = []
let token = start
while (token) {
type = token[0]
tokens.push(token)
if (type === '(' || type === '[') {
if (!bracket) bracket = token
brackets.push(type === '(' ? ')' : ']')
} else if (customProperty && colon && type === '{') {
if (!bracket) bracket = token
brackets.push('}')
} else if (brackets.length === 0) {
if (type === ';') {
if (colon) {
this.decl(tokens, customProperty)
return
} else {
break
}
} else if (type === '{') {
this.rule(tokens)
return
} else if (type === '}') {
this.tokenizer.back(tokens.pop())
end = true
break
} else if (type === ':') {
colon = true
}
} else if (type === brackets[brackets.length - 1]) {
brackets.pop()
if (brackets.length === 0) bracket = null
}
token = this.tokenizer.nextToken()
}
if (this.tokenizer.endOfFile()) end = true
if (brackets.length > 0) this.unclosedBracket(bracket)
if (end && colon) {
if (!customProperty) {
while (tokens.length) {
token = tokens[tokens.length - 1][0]
if (token !== 'space' && token !== 'comment') break
this.tokenizer.back(tokens.pop())
}
}
this.decl(tokens, customProperty)
} else {
this.unknownWord(tokens)
}
}
parse() {
let token
while (!this.tokenizer.endOfFile()) {
token = this.tokenizer.nextToken()
switch (token[0]) {
case 'space':
this.spaces += token[1]
break
case ';':
this.freeSemicolon(token)
break
case '}':
this.end(token)
break
case 'comment':
this.comment(token)
break
case 'at-word':
this.atrule(token)
break
case '{':
this.emptyRule(token)
break
default:
this.other(token)
break
}
}
this.endFile()
}
precheckMissedSemicolon(/* tokens */) {
// Hook for Safe Parser
}
raw(node, prop, tokens, customProperty) {

@@ -460,3 +511,3 @@ let token, type

let raw = tokens.reduce((all, i) => all + i[1], '')
node.raws[prop] = { value, raw }
node.raws[prop] = { raw, value }
}

@@ -466,2 +517,13 @@ node[prop] = value

rule(tokens) {
tokens.pop()
let node = new Rule()
this.init(node, tokens[0][2])
node.raws.between = this.spacesAndCommentsFromEnd(tokens)
this.raw(node, 'selector', tokens)
this.current = node
}
spacesAndCommentsFromEnd(tokens) {

@@ -478,2 +540,4 @@ let lastTokenType

// Errors
spacesAndCommentsFromStart(tokens) {

@@ -510,32 +574,7 @@ let next

colon(tokens) {
let brackets = 0
let token, type, prev
for (let [i, element] of tokens.entries()) {
token = element
type = token[0]
if (type === '(') {
brackets += 1
}
if (type === ')') {
brackets -= 1
}
if (brackets === 0 && type === ':') {
if (!prev) {
this.doubleColon(token)
} else if (prev[0] === 'word' && prev[1] === 'progid') {
continue
} else {
return i
}
}
prev = token
}
return false
unclosedBlock() {
let pos = this.current.source.start
throw this.input.error('Unclosed block', pos.line, pos.column)
}
// Errors
unclosedBracket(bracket) {

@@ -549,10 +588,2 @@ throw this.input.error(

unknownWord(tokens) {
throw this.input.error(
'Unknown word',
{ offset: tokens[0][2] },
{ offset: tokens[0][2] + tokens[0][1].length }
)
}
unexpectedClose(token) {

@@ -566,12 +597,7 @@ throw this.input.error(

unclosedBlock() {
let pos = this.current.source.start
throw this.input.error('Unclosed block', pos.line, pos.column)
}
doubleColon(token) {
unknownWord(tokens) {
throw this.input.error(
'Double colon',
{ offset: token[2] },
{ offset: token[2] + token[1].length }
'Unknown word',
{ offset: tokens[0][2] },
{ offset: tokens[0][2] + tokens[0][1].length }
)

@@ -587,30 +613,4 @@ }

}
precheckMissedSemicolon(/* tokens */) {
// Hook for Safe Parser
}
checkMissedSemicolon(tokens) {
let colon = this.colon(tokens)
if (colon === false) return
let founded = 0
let token
for (let j = colon - 1; j >= 0; j--) {
token = tokens[j]
if (token[0] !== 'space') {
founded += 1
if (founded === 2) break
}
}
// If the token is a word, e.g. `!important`, `red` or any other valid property's value.
// Then we need to return the colon after that word token. [3] is the "end" colon of that word.
// And because we need it after that one we do +1 to get the next one.
throw this.input.error(
'Missed semicolon',
token[0] === 'word' ? token[3] + 1 : token[2]
)
}
}
module.exports = Parser

@@ -1,26 +0,26 @@

import { SourceMapGenerator, RawSourceMap } from 'source-map-js'
import { RawSourceMap, SourceMapGenerator } from 'source-map-js'
import AtRule, { AtRuleProps } from './at-rule.js'
import Comment, { CommentProps } from './comment.js'
import Container, { ContainerProps } from './container.js'
import CssSyntaxError from './css-syntax-error.js'
import Declaration, { DeclarationProps } from './declaration.js'
import Document, { DocumentProps } from './document.js'
import Input, { FilePosition } from './input.js'
import LazyResult from './lazy-result.js'
import list from './list.js'
import Node, {
Position,
Source,
AnyNode,
ChildNode,
ChildProps,
NodeErrorOptions,
NodeProps,
ChildProps,
AnyNode
Position,
Source
} from './node.js'
import Declaration, { DeclarationProps } from './declaration.js'
import Container, { ContainerProps } from './container.js'
import Document, { DocumentProps } from './document.js'
import Warning, { WarningOptions } from './warning.js'
import Comment, { CommentProps } from './comment.js'
import AtRule, { AtRuleProps } from './at-rule.js'
import Input, { FilePosition } from './input.js'
import Processor from './processor.js'
import Result, { Message } from './result.js'
import Root, { RootProps } from './root.js'
import Rule, { RuleProps } from './rule.js'
import CssSyntaxError from './css-syntax-error.js'
import list from './list.js'
import LazyResult from './lazy-result.js'
import Processor from './processor.js'
import Warning, { WarningOptions } from './warning.js'

@@ -45,38 +45,29 @@ type DocumentProcessor = (

/**
* Will be called on `Document` node.
* Will be called on all`AtRule` nodes.
*
* Will be called again on children changes.
* Will be called again on node or children changes.
*/
Document?: DocumentProcessor
AtRule?: { [name: string]: AtRuleProcessor } | AtRuleProcessor
/**
* Will be called on `Document` node, when all children will be processed.
* Will be called on all `AtRule` nodes, when all children will be processed.
*
* Will be called again on children changes.
* Will be called again on node or children changes.
*/
DocumentExit?: DocumentProcessor
AtRuleExit?: { [name: string]: AtRuleProcessor } | AtRuleProcessor
/**
* Will be called on `Root` node once.
*/
Once?: RootProcessor
/**
* Will be called on `Root` node once, when all children will be processed.
*/
OnceExit?: RootProcessor
/**
* Will be called on `Root` node.
* Will be called on all `Comment` nodes.
*
* Will be called again on children changes.
* Will be called again on node or children changes.
*/
Root?: RootProcessor
Comment?: CommentProcessor
/**
* Will be called on `Root` node, when all children will be processed.
* Will be called on all `Comment` nodes after listeners
* for `Comment` event.
*
* Will be called again on children changes.
* Will be called again on node or children changes.
*/
RootExit?: RootProcessor
CommentExit?: CommentProcessor

@@ -89,3 +80,3 @@ /**

*/
Declaration?: DeclarationProcessor | { [prop: string]: DeclarationProcessor }
Declaration?: { [prop: string]: DeclarationProcessor } | DeclarationProcessor

@@ -98,47 +89,56 @@ /**

DeclarationExit?:
| { [prop: string]: DeclarationProcessor }
| DeclarationProcessor
| { [prop: string]: DeclarationProcessor }
/**
* Will be called on all `Rule` nodes.
* Will be called on `Document` node.
*
* Will be called again on node or children changes.
* Will be called again on children changes.
*/
Rule?: RuleProcessor
Document?: DocumentProcessor
/**
* Will be called on all `Rule` nodes, when all children will be processed.
* Will be called on `Document` node, when all children will be processed.
*
* Will be called again on node or children changes.
* Will be called again on children changes.
*/
RuleExit?: RuleProcessor
DocumentExit?: DocumentProcessor
/**
* Will be called on all`AtRule` nodes.
* Will be called on `Root` node once.
*/
Once?: RootProcessor
/**
* Will be called on `Root` node once, when all children will be processed.
*/
OnceExit?: RootProcessor
/**
* Will be called on `Root` node.
*
* Will be called again on node or children changes.
* Will be called again on children changes.
*/
AtRule?: AtRuleProcessor | { [name: string]: AtRuleProcessor }
Root?: RootProcessor
/**
* Will be called on all `AtRule` nodes, when all children will be processed.
* Will be called on `Root` node, when all children will be processed.
*
* Will be called again on node or children changes.
* Will be called again on children changes.
*/
AtRuleExit?: AtRuleProcessor | { [name: string]: AtRuleProcessor }
RootExit?: RootProcessor
/**
* Will be called on all `Comment` nodes.
* Will be called on all `Rule` nodes.
*
* Will be called again on node or children changes.
*/
Comment?: CommentProcessor
Rule?: RuleProcessor
/**
* Will be called on all `Comment` nodes after listeners
* for `Comment` event.
* Will be called on all `Rule` nodes, when all children will be processed.
*
* Will be called again on node or children changes.
*/
CommentExit?: CommentProcessor
RuleExit?: RuleProcessor
}

@@ -148,34 +148,34 @@

export {
NodeErrorOptions,
AnyNode,
AtRule,
AtRuleProps,
ChildNode,
ChildProps,
Comment,
CommentProps,
Container,
ContainerProps,
CssSyntaxError,
Declaration,
DeclarationProps,
CssSyntaxError,
ContainerProps,
WarningOptions,
Document,
DocumentProps,
FilePosition,
CommentProps,
AtRuleProps,
Declaration,
ChildProps,
Input,
LazyResult,
ChildNode,
list,
Message,
Node,
NodeErrorOptions,
NodeProps,
Position,
Processor,
Result,
Root,
RootProps,
Rule,
RuleProps,
RootProps,
Container,
Position,
Document,
AnyNode,
Source,
Warning,
Message,
Comment,
Source,
AtRule,
Result,
Input,
Node,
list,
Rule,
Root
WarningOptions
}

@@ -187,3 +187,3 @@

export type Helpers = { result: Result; postcss: Postcss } & Postcss
export type Helpers = { postcss: Postcss; result: Result } & Postcss

@@ -215,15 +215,15 @@ export interface Plugin extends Processors {

export type AcceptedPlugin =
| {
postcss: Processor | TransformCallback
}
| OldPlugin<any>
| Plugin
| PluginCreator<any>
| OldPlugin<any>
| Processor
| TransformCallback
| {
postcss: TransformCallback | Processor
}
| Processor
export interface Parser<RootNode = Root | Document> {
export interface Parser<RootNode = Document | Root> {
(
css: string | { toString(): string },
opts?: Pick<ProcessOptions, 'map' | 'from'>
css: { toString(): string } | string,
opts?: Pick<ProcessOptions, 'from' | 'map'>
): RootNode

@@ -233,3 +233,3 @@ }

export interface Builder {
(part: string, node?: AnyNode, type?: 'start' | 'end'): void
(part: string, node?: AnyNode, type?: 'end' | 'start'): void
}

@@ -242,4 +242,4 @@

export interface JSONHydrator {
(data: object): Node
(data: object[]): Node[]
(data: object): Node
}

@@ -261,2 +261,26 @@

/**
* Use absolute path in generated source map.
*/
absolute?: boolean
/**
* Indicates that PostCSS should add annotation comments to the CSS.
* By default, PostCSS will always add a comment with a path
* to the source map. PostCSS will not add annotations to CSS files
* that do not contain any comments.
*
* By default, PostCSS presumes that you want to save the source map as
* `opts.to + '.map'` and will use this path in the annotation comment.
* A different path can be set by providing a string value for annotation.
*
* If you have set `inline: true`, annotation cannot be disabled.
*/
annotation?: ((file: string, root: Root) => string) | boolean | string
/**
* Override `from` in map’s sources.
*/
from?: string
/**
* Indicates that the source map should be embedded in the output CSS

@@ -281,3 +305,3 @@ * as a Base64-encoded comment. By default, it is `true`.

*/
prev?: string | boolean | object | ((file: string) => string)
prev?: ((file: string) => string) | boolean | object | string

@@ -291,26 +315,2 @@ /**

sourcesContent?: boolean
/**
* Indicates that PostCSS should add annotation comments to the CSS.
* By default, PostCSS will always add a comment with a path
* to the source map. PostCSS will not add annotations to CSS files
* that do not contain any comments.
*
* By default, PostCSS presumes that you want to save the source map as
* `opts.to + '.map'` and will use this path in the annotation comment.
* A different path can be set by providing a string value for annotation.
*
* If you have set `inline: true`, annotation cannot be disabled.
*/
annotation?: string | boolean | ((file: string, root: Root) => string)
/**
* Override `from` in map’s sources.
*/
from?: string
/**
* Use absolute path in generated source map.
*/
absolute?: boolean
}

@@ -326,6 +326,5 @@

/**
* The path where you'll put the output CSS file. You should always set `to`
* to generate correct source maps.
* Source map options
*/
to?: string
map?: boolean | SourceMapOptions

@@ -335,3 +334,3 @@ /**

*/
parser?: Syntax | Parser
parser?: Parser | Syntax

@@ -341,3 +340,3 @@ /**

*/
stringifier?: Syntax | Stringifier
stringifier?: Stringifier | Syntax

@@ -350,5 +349,6 @@ /**

/**
* Source map options
* The path where you'll put the output CSS file. You should always set `to`
* to generate correct source maps.
*/
map?: SourceMapOptions | boolean
to?: string
}

@@ -355,0 +355,0 @@

@@ -24,31 +24,31 @@ import { SourceMapConsumer } from 'source-map-js'

/**
* Was source map inlined by data-uri to input CSS.
* `sourceMappingURL` content.
*/
inline: boolean
annotation?: string
/**
* `sourceMappingURL` content.
* The CSS source identifier. Contains `Input#file` if the user
* set the `from` option, or `Input#id` if they did not.
*/
annotation?: string
file?: string
/**
* Source map file content.
* Was source map inlined by data-uri to input CSS.
*/
text?: string
inline: boolean
/**
* The directory with source map file, if source map is in separated file.
* Path to source map file.
*/
root?: string
mapFile?: string
/**
* The CSS source identifier. Contains `Input#file` if the user
* set the `from` option, or `Input#id` if they did not.
* The directory with source map file, if source map is in separated file.
*/
file?: string
root?: string
/**
* Path to source map file.
* Source map file content.
*/
mapFile?: string
text?: string

@@ -55,0 +55,0 @@ /**

@@ -38,12 +38,18 @@ 'use strict'

withContent() {
return !!(
this.consumer().sourcesContent &&
this.consumer().sourcesContent.length > 0
)
}
decodeInline(text) {
let baseCharsetUri = /^data:application\/json;charset=utf-?8;base64,/
let baseUri = /^data:application\/json;base64,/
let charsetUri = /^data:application\/json;charset=utf-?8,/
let uri = /^data:application\/json,/
startWith(string, start) {
if (!string) return false
return string.substr(0, start.length) === start
if (charsetUri.test(text) || uri.test(text)) {
return decodeURIComponent(text.substr(RegExp.lastMatch.length))
}
if (baseCharsetUri.test(text) || baseUri.test(text)) {
return fromBase64(text.substr(RegExp.lastMatch.length))
}
let encoding = text.match(/data:application\/json;([^,]+),/)[1]
throw new Error('Unsupported source map encoding ' + encoding)
}

@@ -55,2 +61,11 @@

isMap(map) {
if (typeof map !== 'object') return false
return (
typeof map.mappings === 'string' ||
typeof map._mappings === 'string' ||
Array.isArray(map.sections)
)
}
loadAnnotation(css) {

@@ -70,20 +85,2 @@ let comments = css.match(/\/\*\s*# sourceMappingURL=/gm)

decodeInline(text) {
let baseCharsetUri = /^data:application\/json;charset=utf-?8;base64,/
let baseUri = /^data:application\/json;base64,/
let charsetUri = /^data:application\/json;charset=utf-?8,/
let uri = /^data:application\/json,/
if (charsetUri.test(text) || uri.test(text)) {
return decodeURIComponent(text.substr(RegExp.lastMatch.length))
}
if (baseCharsetUri.test(text) || baseUri.test(text)) {
return fromBase64(text.substr(RegExp.lastMatch.length))
}
let encoding = text.match(/data:application\/json;([^,]+),/)[1]
throw new Error('Unsupported source map encoding ' + encoding)
}
loadFile(path) {

@@ -134,8 +131,11 @@ this.root = dirname(path)

isMap(map) {
if (typeof map !== 'object') return false
return (
typeof map.mappings === 'string' ||
typeof map._mappings === 'string' ||
Array.isArray(map.sections)
startWith(string, start) {
if (!string) return false
return string.substr(0, start.length) === start
}
withContent() {
return !!(
this.consumer().sourcesContent &&
this.consumer().sourcesContent.length > 0
)

@@ -142,0 +142,0 @@ }

@@ -0,1 +1,3 @@

import LazyResult from './lazy-result.js'
import NoWorkResult from './no-work-result.js'
import {

@@ -5,9 +7,7 @@ AcceptedPlugin,

ProcessOptions,
Transformer,
TransformCallback
TransformCallback,
Transformer
} from './postcss.js'
import LazyResult from './lazy-result.js'
import Result from './result.js'
import Root from './root.js'
import NoWorkResult from './no-work-result.js'

@@ -31,2 +31,12 @@ declare namespace Processor {

/**
* Plugins added to this processor.
*
* ```js
* const processor = postcss([autoprefixer, postcssNested])
* processor.plugins.length //=> 2
* ```
*/
plugins: (Plugin | TransformCallback | Transformer)[]
/**
* Current PostCSS version.

@@ -43,17 +53,31 @@ *

/**
* Plugins added to this processor.
* @param plugins PostCSS plugins
*/
constructor(plugins?: AcceptedPlugin[])
/**
* Parses source CSS and returns a `LazyResult` Promise proxy.
* Because some plugins can be asynchronous it doesn’t make
* any transformations. Transformations will be applied
* in the `LazyResult` methods.
*
* ```js
* const processor = postcss([autoprefixer, postcssNested])
* processor.plugins.length //=> 2
* processor.process(css, { from: 'a.css', to: 'a.out.css' })
* .then(result => {
* console.log(result.css)
* })
* ```
*
* @param css String with input CSS or any object with a `toString()` method,
* like a Buffer. Optionally, send a `Result` instance
* and the processor will take the `Root` from it.
* @param opts Options.
* @return Promise proxy.
*/
plugins: (Plugin | Transformer | TransformCallback)[]
process(
css: { toString(): string } | LazyResult | Result | Root | string,
options?: ProcessOptions
): LazyResult | NoWorkResult
/**
* @param plugins PostCSS plugins
*/
constructor(plugins?: AcceptedPlugin[])
/**
* Adds a plugin to be used as a CSS processor.

@@ -86,26 +110,2 @@ *

use(plugin: AcceptedPlugin): this
/**
* Parses source CSS and returns a `LazyResult` Promise proxy.
* Because some plugins can be asynchronous it doesn’t make
* any transformations. Transformations will be applied
* in the `LazyResult` methods.
*
* ```js
* processor.process(css, { from: 'a.css', to: 'a.out.css' })
* .then(result => {
* console.log(result.css)
* })
* ```
*
* @param css String with input CSS or any object with a `toString()` method,
* like a Buffer. Optionally, send a `Result` instance
* and the processor will take the `Root` from it.
* @param opts Options.
* @return Promise proxy.
*/
process(
css: string | { toString(): string } | Result | LazyResult | Root,
options?: ProcessOptions
): LazyResult | NoWorkResult
}

@@ -112,0 +112,0 @@

@@ -10,24 +10,6 @@ 'use strict'

constructor(plugins = []) {
this.version = '8.4.24'
this.version = '8.4.25'
this.plugins = this.normalize(plugins)
}
use(plugin) {
this.plugins = this.plugins.concat(this.normalize([plugin]))
return this
}
process(css, opts = {}) {
if (
this.plugins.length === 0 &&
typeof opts.parser === 'undefined' &&
typeof opts.stringifier === 'undefined' &&
typeof opts.syntax === 'undefined'
) {
return new NoWorkResult(this, css, opts)
} else {
return new LazyResult(this, css, opts)
}
}
normalize(plugins) {

@@ -62,2 +44,20 @@ let normalized = []

}
process(css, opts = {}) {
if (
this.plugins.length === 0 &&
typeof opts.parser === 'undefined' &&
typeof opts.stringifier === 'undefined' &&
typeof opts.syntax === 'undefined'
) {
return new NoWorkResult(this, css, opts)
} else {
return new LazyResult(this, css, opts)
}
}
use(plugin) {
this.plugins = this.plugins.concat(this.normalize([plugin]))
return this
}
}

@@ -64,0 +64,0 @@

import {
Document,
Node,
Plugin,
ProcessOptions,
Plugin,
Root,
SourceMap,
TransformCallback,
Root,
Document,
Node,
Warning,

@@ -16,6 +16,3 @@ WarningOptions

export interface Message {
/**
* Message type.
*/
type: string
[others: string]: any

@@ -27,3 +24,6 @@ /**

[others: string]: any
/**
* Message type.
*/
type: string
}

@@ -67,15 +67,32 @@

/**
* The Processor instance used for this transformation.
* A CSS string representing of `Result#root`.
*
* ```js
* for (const plugin of result.processor.plugins) {
* if (plugin.postcssPlugin === 'postcss-bad') {
* throw 'postcss-good is incompatible with postcss-bad'
* }
* })
* postcss.parse('a{}').toResult().css //=> "a{}"
* ```
*/
processor: Processor
css: string
/**
* Last runned PostCSS plugin.
*/
lastPlugin: Plugin | TransformCallback
/**
* An instance of `SourceMapGenerator` class from the `source-map` library,
* representing changes to the `Result#root` instance.
*
* ```js
* result.map.toJSON() //=> { version: 3, file: 'a.css', … }
* ```
*
* ```js
* if (result.map) {
* fs.writeFileSync(result.opts.to + '.map', result.map.toString())
* }
* ```
*/
map: SourceMap
/**
* Contains messages from plugins (e.g., warnings or custom messages).

@@ -101,11 +118,2 @@ * Each message should have type and plugin properties.

/**
* Root node after all transformations.
*
* ```js
* root.toResult().root === root
* ```
*/
root: Root | Document
/**
* Options from the `Processor#process` or `Root#toResult` call

@@ -121,32 +129,24 @@ * that produced this Result instance.]

/**
* A CSS string representing of `Result#root`.
* The Processor instance used for this transformation.
*
* ```js
* postcss.parse('a{}').toResult().css //=> "a{}"
* for (const plugin of result.processor.plugins) {
* if (plugin.postcssPlugin === 'postcss-bad') {
* throw 'postcss-good is incompatible with postcss-bad'
* }
* })
* ```
*/
css: string
processor: Processor
/**
* An instance of `SourceMapGenerator` class from the `source-map` library,
* representing changes to the `Result#root` instance.
* Root node after all transformations.
*
* ```js
* result.map.toJSON() //=> { version: 3, file: 'a.css', … }
* root.toResult().root === root
* ```
*
* ```js
* if (result.map) {
* fs.writeFileSync(result.opts.to + '.map', result.map.toString())
* }
* ```
*/
map: SourceMap
root: Document | Root
/**
* Last runned PostCSS plugin.
*/
lastPlugin: Plugin | TransformCallback
/**
* @param processor Processor used for this transformation.

@@ -156,3 +156,3 @@ * @param root Root node after all transformations.

*/
constructor(processor: Processor, root: Root | Document, opts: Result.ResultOptions)
constructor(processor: Processor, root: Document | Root, opts: Result.ResultOptions)

@@ -159,0 +159,0 @@ /**

@@ -15,2 +15,6 @@ 'use strict'

get content() {
return this.css
}
toString() {

@@ -36,6 +40,2 @@ return this.css

}
get content() {
return this.css
}
}

@@ -42,0 +42,0 @@

@@ -14,3 +14,3 @@ import Container, { ContainerProps } from './container.js'

/**
* Non-CSS code before `Root`, when `Root` is inside `Document`.
* Non-CSS code after `Root`, when `Root` is inside `Document`.
*

@@ -20,6 +20,6 @@ * **Experimental:** some aspects of this node could change within minor

*/
codeBefore?: string
codeAfter?: string
/**
* Non-CSS code after `Root`, when `Root` is inside `Document`.
* Non-CSS code before `Root`, when `Root` is inside `Document`.
*

@@ -29,3 +29,3 @@ * **Experimental:** some aspects of this node could change within minor

*/
codeAfter?: string
codeBefore?: string

@@ -60,6 +60,9 @@ /**

declare class Root_ extends Container {
type: 'root'
parent: Document | undefined
raws: Root.RootRaws
type: 'root'
constructor(defaults?: Root.RootProps)
assign(overrides: object | Root.RootProps): this
/**

@@ -79,5 +82,2 @@ * Returns a `Result` instance representing the root’s CSS.

toResult(options?: ProcessOptions): Result
constructor(defaults?: Root.RootProps)
assign(overrides: object | Root.RootProps): this
}

@@ -84,0 +84,0 @@

@@ -14,12 +14,2 @@ 'use strict'

removeChild(child, ignore) {
let index = this.index(child)
if (!ignore && index === 0 && this.nodes.length > 1) {
this.nodes[1].raws.before = this.nodes[index].raws.before
}
return super.removeChild(child)
}
normalize(child, sample, type) {

@@ -45,2 +35,12 @@ let nodes = super.normalize(child)

removeChild(child, ignore) {
let index = this.index(child)
if (!ignore && index === 0 && this.nodes.length > 1) {
this.nodes[1].raws.before = this.nodes[index].raws.before
}
return super.removeChild(child)
}
toResult(opts = {}) {

@@ -47,0 +47,0 @@ let lazy = new LazyResult(new Processor(), this, opts)

@@ -6,2 +6,7 @@ import Container, { ContainerProps } from './container.js'

/**
* The space symbols after the last child of the node to the end of the node.
*/
after?: string
/**
* The space symbols before the node. It also stores `*`

@@ -13,7 +18,2 @@ * and `_` symbols before the declaration (IE hack).

/**
* The space symbols after the last child of the node to the end of the node.
*/
after?: string
/**
* The symbols between the selector and `{` for rules.

@@ -24,7 +24,2 @@ */

/**
* Contains `true` if the last child has an (optional) semicolon.
*/
semicolon?: boolean
/**
* Contains `true` if there is semicolon after rule.

@@ -38,8 +33,15 @@ */

selector?: {
raw: string
value: string
raw: string
}
/**
* Contains `true` if the last child has an (optional) semicolon.
*/
semicolon?: boolean
}
export interface RuleProps extends ContainerProps {
/** Information used to generate byte-to-byte equal node string as it was in the origin input. */
raws?: RuleRaws
/** Selector or selectors of the rule. */

@@ -49,4 +51,2 @@ selector?: string

selectors?: string[]
/** Information used to generate byte-to-byte equal node string as it was in the origin input. */
raws?: RuleRaws
}

@@ -77,6 +77,4 @@

declare class Rule_ extends Container {
type: 'rule'
parent: Container | undefined
raws: Rule.RuleRaws
/**

@@ -110,7 +108,9 @@ * The rule’s full selector represented as a string.

type: 'rule'
constructor(defaults?: Rule.RuleProps)
assign(overrides: object | Rule.RuleProps): this
clone(overrides?: Partial<Rule.RuleProps>): this
cloneAfter(overrides?: Partial<Rule.RuleProps>): this
cloneBefore(overrides?: Partial<Rule.RuleProps>): this
cloneAfter(overrides?: Partial<Rule.RuleProps>): this
}

@@ -117,0 +117,0 @@

import {
AnyNode,
AtRule,
Builder,
Comment,
Container,
Declaration,
Document,
Root,
Comment,
Declaration,
Builder,
AnyNode,
Rule,
AtRule,
Container
Rule
} from './postcss.js'

@@ -21,23 +21,23 @@

constructor(builder: Builder)
stringify(node: AnyNode, semicolon?: boolean): void
document(node: Document): void
root(node: Root): void
atrule(node: AtRule, semicolon?: boolean): void
beforeAfter(node: AnyNode, detect: 'after' | 'before'): string
block(node: AnyNode, start: string): void
body(node: Container): void
comment(node: Comment): void
decl(node: Declaration, semicolon?: boolean): void
rule(node: Rule): void
atrule(node: AtRule, semicolon?: boolean): void
body(node: Container): void
block(node: AnyNode, start: string): void
raw(node: AnyNode, own: string | null, detect?: string): string
rawSemicolon(root: Root): boolean | undefined
rawEmptyBody(root: Root): string | undefined
rawIndent(root: Root): string | undefined
document(node: Document): void
raw(node: AnyNode, own: null | string, detect?: string): string
rawBeforeClose(root: Root): string | undefined
rawBeforeComment(root: Root, node: Comment): string | undefined
rawBeforeDecl(root: Root, node: Declaration): string | undefined
rawBeforeOpen(root: Root): string | undefined
rawBeforeRule(root: Root): string | undefined
rawBeforeClose(root: Root): string | undefined
rawBeforeOpen(root: Root): string | undefined
rawColon(root: Root): string | undefined
beforeAfter(node: AnyNode, detect: 'before' | 'after'): string
rawEmptyBody(root: Root): string | undefined
rawIndent(root: Root): string | undefined
rawSemicolon(root: Root): boolean | undefined
rawValue(node: AnyNode, prop: string): string
root(node: Root): void
rule(node: Rule): void
stringify(node: AnyNode, semicolon?: boolean): void
}

@@ -44,0 +44,0 @@

'use strict'
const DEFAULT_RAW = {
colon: ': ',
indent: ' ',
after: '\n',
beforeClose: '\n',
beforeComment: '\n',
beforeDecl: '\n',
beforeOpen: ' ',
beforeRule: '\n',
beforeOpen: ' ',
beforeClose: '\n',
beforeComment: '\n',
after: '\n',
emptyBody: '',
colon: ': ',
commentLeft: ' ',
commentRight: ' ',
emptyBody: '',
indent: ' ',
semicolon: false

@@ -27,50 +27,2 @@ }

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)
}
document(node) {
this.body(node)
}
root(node) {
this.body(node)
if (node.raws.after) this.builder(node.raws.after)
}
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)
}
rule(node) {
this.block(node, this.rawValue(node, 'selector'))
if (node.raws.ownSemicolon) {
this.builder(node.raws.ownSemicolon, node, 'end')
}
}
atrule(node, semicolon) {

@@ -94,16 +46,29 @@ let name = '@' + node.name

body(node) {
let last = node.nodes.length - 1
while (last > 0) {
if (node.nodes[last].type !== 'comment') break
last -= 1
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 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)
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
}

@@ -127,2 +92,40 @@

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) {

@@ -182,34 +185,11 @@ let value

rawSemicolon(root) {
rawBeforeClose(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
}
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, '')
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

@@ -219,2 +199,3 @@ }

})
if (value) value = value.replace(/\S/g, '')
return value

@@ -261,2 +242,13 @@ }

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) {

@@ -279,24 +271,18 @@ let value

rawBeforeClose(root) {
rawColon(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
}
root.walkDecls(i => {
if (typeof i.raws.between !== 'undefined') {
value = i.raws.between.replace(/[^\s:]/g, '')
return false
}
})
if (value) value = value.replace(/\S/g, '')
return value
}
rawBeforeOpen(root) {
rawEmptyBody(root) {
let value
root.walk(i => {
if (i.type !== 'decl') {
value = i.raws.between
if (i.nodes && i.nodes.length === 0) {
value = i.raws.after
if (typeof value !== 'undefined') return false

@@ -308,8 +294,14 @@ }

rawColon(root) {
rawIndent(root) {
if (root.raws.indent) return root.raws.indent
let value
root.walkDecls(i => {
if (typeof i.raws.between !== 'undefined') {
value = i.raws.between.replace(/[^\s:]/g, '')
return false
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
}
}

@@ -320,28 +312,10 @@ })

beforeAfter(node, detect) {
rawSemicolon(root) {
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
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

@@ -359,2 +333,28 @@ }

}
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)
}
}

@@ -361,0 +361,0 @@

@@ -14,17 +14,17 @@ 'use strict'

const HIGHLIGHT_THEME = {
'brackets': pico.cyan,
'at-word': pico.cyan,
'comment': pico.gray,
'string': pico.green,
'class': pico.yellow,
'hash': pico.magenta,
'call': pico.cyan,
';': pico.yellow,
':': pico.yellow,
'(': pico.cyan,
')': pico.cyan,
'[': pico.yellow,
']': pico.yellow,
'{': pico.yellow,
'}': pico.yellow,
'[': pico.yellow,
']': pico.yellow,
':': pico.yellow,
';': pico.yellow
'at-word': pico.cyan,
'brackets': pico.cyan,
'call': pico.cyan,
'class': pico.yellow,
'comment': pico.gray,
'hash': pico.magenta,
'string': pico.green
}

@@ -31,0 +31,0 @@

@@ -262,6 +262,6 @@ 'use strict'

back,
endOfFile,
nextToken,
endOfFile,
position
}
}

@@ -7,10 +7,10 @@ import { RangePosition } from './css-syntax-error.js'

/**
* CSS node that caused the warning.
* End position, exclusive, in CSS node string that caused the warning.
*/
node?: Node
end?: RangePosition
/**
* Word in CSS source that caused the warning.
* End index, exclusive, in CSS node string that caused the warning.
*/
word?: string
endIndex?: number

@@ -23,21 +23,21 @@ /**

/**
* End index, exclusive, in CSS node string that caused the warning.
* CSS node that caused the warning.
*/
endIndex?: number
node?: Node
/**
* Start position, inclusive, in CSS node string that caused the warning.
* Name of the plugin that created this warning. `Result#warn` fills
* this property automatically.
*/
start?: RangePosition
plugin?: string
/**
* End position, exclusive, in CSS node string that caused the warning.
* Start position, inclusive, in CSS node string that caused the warning.
*/
end?: RangePosition
start?: RangePosition
/**
* Name of the plugin that created this warning. `Result#warn` fills
* this property automatically.
* Word in CSS source that caused the warning.
*/
plugin?: string
word?: string
}

@@ -60,34 +60,27 @@

/**
* Type to filter warnings from `Result#messages`.
* Always equal to `"warning"`.
*/
type: 'warning'
/**
* The warning message.
* Column for inclusive start position in the input file with this warning’s source.
*
* ```js
* warning.text //=> 'Try to avoid !important'
* warning.column //=> 6
* ```
*/
text: string
column: number
/**
* The name of the plugin that created this warning.
* When you call `Node#warn` it will fill this property automatically.
* Column for exclusive end position in the input file with this warning’s source.
*
* ```js
* warning.plugin //=> 'postcss-important'
* warning.endColumn //=> 4
* ```
*/
plugin: string
endColumn?: number
/**
* Contains the CSS node that caused the warning.
* Line for exclusive end position in the input file with this warning’s source.
*
* ```js
* warning.node.toString() //=> 'color: white !important'
* warning.endLine //=> 6
* ```
*/
node: Node
endLine?: number

@@ -104,29 +97,36 @@ /**

/**
* Column for inclusive start position in the input file with this warning’s source.
* Contains the CSS node that caused the warning.
*
* ```js
* warning.column //=> 6
* warning.node.toString() //=> 'color: white !important'
* ```
*/
column: number
node: Node
/**
* Line for exclusive end position in the input file with this warning’s source.
* The name of the plugin that created this warning.
* When you call `Node#warn` it will fill this property automatically.
*
* ```js
* warning.endLine //=> 6
* warning.plugin //=> 'postcss-important'
* ```
*/
endLine?: number
plugin: string
/**
* Column for exclusive end position in the input file with this warning’s source.
* The warning message.
*
* ```js
* warning.endColumn //=> 4
* warning.text //=> 'Try to avoid !important'
* ```
*/
endColumn?: number
text: string
/**
* Type to filter warnings from `Result#messages`.
* Always equal to `"warning"`.
*/
type: 'warning'
/**
* @param text Warning message.

@@ -133,0 +133,0 @@ * @param opts Warning options.

@@ -22,4 +22,4 @@ 'use strict'

return this.node.error(this.text, {
index: this.index,
plugin: this.plugin,
index: this.index,
word: this.word

@@ -26,0 +26,0 @@ }).message

{
"name": "postcss",
"version": "8.4.24",
"version": "8.4.25",
"description": "Tool for transforming styles with JS plugins",

@@ -5,0 +5,0 @@ "engines": {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc