123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 |
- import Node, { ChildNode, NodeProps, ChildProps } from './node.js'
- import Declaration from './declaration.js'
- import Comment from './comment.js'
- import AtRule from './at-rule.js'
- import Rule from './rule.js'
- interface ValueOptions {
- /**
- * An array of property names.
- */
- props?: string[]
- /**
- * String that’s used to narrow down values and speed up the regexp search.
- */
- fast?: string
- }
- export interface ContainerProps extends NodeProps {
- nodes?: (ChildNode | ChildProps)[]
- }
- /**
- * The `Root`, `AtRule`, and `Rule` container nodes
- * inherit some common methods to help work with their children.
- *
- * Note that all containers can store any content. If you write a rule inside
- * a rule, PostCSS will parse it.
- */
- export default abstract class Container<
- Child extends Node = ChildNode
- > extends Node {
- /**
- * An array containing the container’s children.
- *
- * ```js
- * const root = postcss.parse('a { color: black }')
- * root.nodes.length //=> 1
- * root.nodes[0].selector //=> 'a'
- * root.nodes[0].nodes[0].prop //=> 'color'
- * ```
- */
- nodes: Child[]
- /**
- * The container’s first child.
- *
- * ```js
- * rule.first === rules.nodes[0]
- * ```
- */
- get first(): Child | undefined
- /**
- * The container’s last child.
- *
- * ```js
- * rule.last === rule.nodes[rule.nodes.length - 1]
- * ```
- */
- get last(): Child | undefined
- /**
- * Iterates through the container’s immediate children,
- * calling `callback` for each child.
- *
- * Returning `false` in the callback will break iteration.
- *
- * This method only iterates through the container’s immediate children.
- * If you need to recursively iterate through all the container’s descendant
- * nodes, use `Container#walk`.
- *
- * Unlike the for `{}`-cycle or `Array#forEach` this iterator is safe
- * if you are mutating the array of child nodes during iteration.
- * PostCSS will adjust the current index to match the mutations.
- *
- * ```js
- * const root = postcss.parse('a { color: black; z-index: 1 }')
- * const rule = root.first
- *
- * for (const decl of rule.nodes) {
- * decl.cloneBefore({ prop: '-webkit-' + decl.prop })
- * // Cycle will be infinite, because cloneBefore moves the current node
- * // to the next index
- * }
- *
- * rule.each(decl => {
- * decl.cloneBefore({ prop: '-webkit-' + decl.prop })
- * // Will be executed only for color and z-index
- * })
- * ```
- *
- * @param callback Iterator receives each node and index.
- * @return Returns `false` if iteration was broke.
- */
- each(
- callback: (node: Child, index: number) => false | void
- ): false | undefined
- /**
- * 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
- * root.walk(node => {
- * // Traverses all descendant nodes.
- * })
- * ```
- *
- * @param callback Iterator receives each node and index.
- * @return Returns `false` if iteration was broke.
- */
- walk(
- callback: (node: ChildNode, 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: string | RegExp,
- callback: (decl: Declaration, index: 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 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: string | RegExp,
- callback: (rule: Rule, 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 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
- * 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.
- */
- walkAtRules(
- nameFilter: string | RegExp,
- callback: (atRule: AtRule, index: number) => false | void
- ): false | undefined
- walkAtRules(
- callback: (atRule: AtRule, index: number) => false | void
- ): false | undefined
- /**
- * 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
- * root.walkComments(comment => {
- * comment.remove()
- * })
- * ```
- *
- * @param callback Iterator receives each node and index.
- * @return Returns `false` if iteration was broke.
- */
- walkComments(
- callback: (comment: Comment, indexed: number) => false | void
- ): false | undefined
- walkComments(
- callback: (comment: Comment, indexed: number) => false | void
- ): false | undefined
- /**
- * Inserts new nodes to the end of the container.
- *
- * ```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')
- * ```
- *
- * @param nodes New nodes.
- * @return This node for methods chain.
- */
- append(
- ...nodes: (Node | Node[] | ChildProps | ChildProps[] | string | string[])[]
- ): this
- /**
- * Inserts new nodes to the start of the container.
- *
- * ```js
- * const decl1 = new Declaration({ prop: 'color', value: 'black' })
- * const decl2 = new Declaration({ prop: 'background-color', value: 'white' })
- * rule.prepend(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')
- * ```
- *
- * @param nodes New nodes.
- * @return This node for methods chain.
- */
- prepend(
- ...nodes: (Node | Node[] | ChildProps | ChildProps[] | string | string[])[]
- ): this
- /**
- * Add child to the end of the node.
- *
- * ```js
- * rule.push(new Declaration({ prop: 'color', value: 'black' }))
- * ```
- *
- * @param child New node.
- * @return This node for methods chain.
- */
- push(child: Child): this
- /**
- * Insert new node before old node within the container.
- *
- * ```js
- * rule.insertBefore(decl, decl.clone({ prop: '-webkit-' + decl.prop }))
- * ```
- *
- * @param oldNode Child or child’s index.
- * @param newNode New node.
- * @return This node for methods chain.
- */
- insertBefore(
- oldNode: Child | number,
- newNode: Child | ChildProps | string | Child[] | ChildProps[] | string[]
- ): this
- /**
- * Insert new node after old node within the container.
- *
- * @param oldNode Child or child’s index.
- * @param newNode New node.
- * @return This node for methods chain.
- */
- insertAfter(
- oldNode: Child | number,
- newNode: Child | ChildProps | string | Child[] | ChildProps[] | string[]
- ): this
- /**
- * Removes node from the container and cleans the parent properties
- * from the node and its children.
- *
- * ```js
- * rule.nodes.length //=> 5
- * rule.removeChild(decl)
- * rule.nodes.length //=> 4
- * decl.parent //=> undefined
- * ```
- *
- * @param child Child or child’s index.
- * @return This node for methods chain.
- */
- removeChild(child: Child | number): this
- /**
- * 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
- * through callback, replacing those values with the returned result
- * of callback.
- *
- * This method is useful if you are using a custom unit or function
- * and need to iterate through all values.
- *
- * ```js
- * root.replaceValues(/\d+rem/, { fast: 'rem' }, string => {
- * return 15 * parseInt(string) + 'px'
- * })
- * ```
- *
- * @param pattern Replace pattern.
- * @param {object} opts Options to speed up the search.
- * @param callback String to replace pattern or callback
- * that returns a new value. The callback
- * will receive the same arguments
- * as those passed to a function parameter
- * of `String#replace`.
- * @return This node for methods chain.
- */
- replaceValues(
- pattern: string | RegExp,
- options: ValueOptions,
- replaced: string | { (substring: string, ...args: any[]): string }
- ): this
- replaceValues(
- pattern: string | RegExp,
- replaced: string | { (substring: string, ...args: any[]): string }
- ): this
- /**
- * Returns `true` if callback returns `true`
- * for all of the container’s children.
- *
- * ```js
- * const noPrefixes = rule.every(i => i.prop[0] !== '-')
- * ```
- *
- * @param condition Iterator returns true or false.
- * @return Is every child pass condition.
- */
- every(
- condition: (node: Child, index: number, nodes: Child[]) => boolean
- ): boolean
- /**
- * Returns `true` if callback returns `true` for (at least) one
- * of the container’s children.
- *
- * ```js
- * const hasPrefix = rule.some(i => i.prop[0] === '-')
- * ```
- *
- * @param condition Iterator returns true or false.
- * @return Is some child pass condition.
- */
- some(
- condition: (node: Child, index: number, nodes: Child[]) => boolean
- ): boolean
- /**
- * Returns a `child`’s index within the `Container#nodes` array.
- *
- * ```js
- * rule.index( rule.nodes[2] ) //=> 2
- * ```
- *
- * @param child Child of the current container.
- * @return Child index.
- */
- index(child: Child | number): number
- }
|