| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550 | 'use strict'let { isClean, my } = require('./symbols')let MapGenerator = require('./map-generator')let stringify = require('./stringify')let Container = require('./container')let Document = require('./document')let warnOnce = require('./warn-once')let Result = require('./result')let parse = require('./parse')let Root = require('./root')const TYPE_TO_CLASS_NAME = {  document: 'Document',  root: 'Root',  atrule: 'AtRule',  rule: 'Rule',  decl: 'Declaration',  comment: 'Comment'}const PLUGIN_PROPS = {  postcssPlugin: true,  prepare: true,  Once: true,  Document: true,  Root: true,  Declaration: true,  Rule: true,  AtRule: true,  Comment: true,  DeclarationExit: true,  RuleExit: true,  AtRuleExit: true,  CommentExit: true,  RootExit: true,  DocumentExit: true,  OnceExit: true}const NOT_VISITORS = {  postcssPlugin: true,  prepare: true,  Once: true}const CHILDREN = 0function isPromise(obj) {  return typeof obj === 'object' && typeof obj.then === 'function'}function getEvents(node) {  let key = false  let type = TYPE_TO_CLASS_NAME[node.type]  if (node.type === 'decl') {    key = node.prop.toLowerCase()  } else if (node.type === 'atrule') {    key = node.name.toLowerCase()  }  if (key && node.append) {    return [      type,      type + '-' + key,      CHILDREN,      type + 'Exit',      type + 'Exit-' + key    ]  } else if (key) {    return [type, type + '-' + key, type + 'Exit', type + 'Exit-' + key]  } else if (node.append) {    return [type, CHILDREN, type + 'Exit']  } else {    return [type, type + 'Exit']  }}function toStack(node) {  let events  if (node.type === 'document') {    events = ['Document', CHILDREN, 'DocumentExit']  } else if (node.type === 'root') {    events = ['Root', CHILDREN, 'RootExit']  } else {    events = getEvents(node)  }  return {    node,    events,    eventIndex: 0,    visitors: [],    visitorIndex: 0,    iterator: 0  }}function cleanMarks(node) {  node[isClean] = false  if (node.nodes) node.nodes.forEach(i => cleanMarks(i))  return node}let postcss = {}class LazyResult {  constructor(processor, css, opts) {    this.stringified = false    this.processed = false    let root    if (      typeof css === 'object' &&      css !== null &&      (css.type === 'root' || css.type === 'document')    ) {      root = cleanMarks(css)    } else if (css instanceof LazyResult || css instanceof Result) {      root = cleanMarks(css.root)      if (css.map) {        if (typeof opts.map === 'undefined') opts.map = {}        if (!opts.map.inline) opts.map.inline = false        opts.map.prev = css.map      }    } else {      let parser = parse      if (opts.syntax) parser = opts.syntax.parse      if (opts.parser) parser = opts.parser      if (parser.parse) parser = parser.parse      try {        root = parser(css, opts)      } catch (error) {        this.processed = true        this.error = error      }      if (root && !root[my]) {        /* c8 ignore next 2 */        Container.rebuild(root)      }    }    this.result = new Result(processor, root, opts)    this.helpers = { ...postcss, result: this.result, postcss }    this.plugins = this.processor.plugins.map(plugin => {      if (typeof plugin === 'object' && plugin.prepare) {        return { ...plugin, ...plugin.prepare(this.result) }      } else {        return plugin      }    })  }  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() {    if (this.error) return Promise.reject(this.error)    if (this.processed) return Promise.resolve(this.result)    if (!this.processing) {      this.processing = this.runAsync()    }    return this.processing  }  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  }  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  }  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        }      }    }  }  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()      }    }  }  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() {    throw new Error('Use process(css).then(cb) to work with async plugins')  }  handleError(error, node) {    let plugin = this.result.lastPlugin    try {      if (node) node.addToError(error)      this.error = error      if (error.name === 'CssSyntaxError' && !error.plugin) {        error.plugin = plugin.postcssPlugin        error.setMessage()      } else if (plugin.postcssVersion) {        if (process.env.NODE_ENV !== 'production') {          let pluginName = plugin.postcssPlugin          let pluginVer = plugin.postcssVersion          let runtimeVer = this.result.processor.version          let a = pluginVer.split('.')          let b = runtimeVer.split('.')          if (a[0] !== b[0] || parseInt(a[1]) > parseInt(b[1])) {            // eslint-disable-next-line no-console            console.error(              'Unknown error from PostCSS plugin. Your current PostCSS ' +                'version is ' +                runtimeVer +                ', but ' +                pluginName +                ' uses ' +                pluginVer +                '. Perhaps this is the source of the error below.'            )          }        }      }    } catch (err) {      /* c8 ignore next 3 */      // eslint-disable-next-line no-console      if (console && console.error) console.error(err)    }    return error  }  async runAsync() {    this.plugin = 0    for (let i = 0; i < this.plugins.length; i++) {      let plugin = this.plugins[i]      let promise = this.runOnRoot(plugin)      if (isPromise(promise)) {        try {          await promise        } catch (error) {          throw this.handleError(error)        }      }    }    this.prepareVisitors()    if (this.hasListener) {      let root = this.result.root      while (!root[isClean]) {        root[isClean] = true        let stack = [toStack(root)]        while (stack.length > 0) {          let promise = this.visitTick(stack)          if (isPromise(promise)) {            try {              await promise            } catch (e) {              let node = stack[stack.length - 1].node              throw this.handleError(e, node)            }          }        }      }      if (this.listeners.OnceExit) {        for (let [plugin, visitor] of this.listeners.OnceExit) {          this.result.lastPlugin = plugin          try {            if (root.type === 'document') {              let roots = root.nodes.map(subRoot =>                visitor(subRoot, this.helpers)              )              await Promise.all(roots)            } else {              await visitor(root, this.helpers)            }          } catch (e) {            throw this.handleError(e)          }        }      }    }    this.processed = true    return this.stringify()  }  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  }  visitTick(stack) {    let visit = stack[stack.length - 1]    let { node, visitors } = visit    if (node.type !== 'root' && node.type !== 'document' && !node.parent) {      stack.pop()      return    }    if (visitors.length > 0 && visit.visitorIndex < visitors.length) {      let [plugin, visitor] = visitors[visit.visitorIndex]      visit.visitorIndex += 1      if (visit.visitorIndex === visitors.length) {        visit.visitors = []        visit.visitorIndex = 0      }      this.result.lastPlugin = plugin      try {        return visitor(node.toProxy(), this.helpers)      } catch (e) {        throw this.handleError(e, node)      }    }    if (visit.iterator !== 0) {      let iterator = visit.iterator      let child      while ((child = node.nodes[node.indexes[iterator]])) {        node.indexes[iterator] += 1        if (!child[isClean]) {          child[isClean] = true          stack.push(toStack(child))          return        }      }      visit.iterator = 0      delete node.indexes[iterator]    }    let events = visit.events    while (visit.eventIndex < events.length) {      let event = events[visit.eventIndex]      visit.eventIndex += 1      if (event === CHILDREN) {        if (node.nodes && node.nodes.length) {          node[isClean] = true          visit.iterator = node.getIterator()        }        return      } else if (this.listeners[event]) {        visit.visitors = this.listeners[event]        return      }    }    stack.pop()  }}LazyResult.registerPostcss = dependant => {  postcss = dependant}module.exports = LazyResultLazyResult.default = LazyResultRoot.registerLazyResult(LazyResult)Document.registerLazyResult(LazyResult)
 |