Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
view-container / src / vendor / postcss / css-syntax-error.ts
Size: Mime:
// import supportsColor from 'supports-color'

import terminalHighlight from './terminal-highlight'
import warnOnce from './warn-once'

const supportsColor = true

/**
 * The CSS parser throws this error for broken CSS.
 *
 * Custom parsers can throw this error for broken custom syntax using
 * the {@link Node#error} method.
 *
 * PostCSS will use the input source map to detect the original error location.
 * If you wrote a Sass file, compiled it to CSS and then parsed it with PostCSS,
 * PostCSS will show the original position in the Sass file.
 *
 * If you need the position in the PostCSS input
 * (e.g., to debug the previous compiler), use `error.input.file`.
 *
 * @example
 * // Catching and checking syntax error
 * try {
 *   postcss.parse('a{')
 * } catch (error) {
 *   if ( error.name === 'CssSyntaxError' ) {
 *     error //=> CssSyntaxError
 *   }
 * }
 *
 * @example
 * // Raising error from plugin
 * throw node.error('Unknown variable', { plugin: 'postcss-vars' });
 */
class CssSyntaxError {
  /**
   * @member {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.
   *
   * @example
   * if ( error.name === 'CssSyntaxError' ) {
   *   error //=> CssSyntaxError
   * }
   */
  name = 'CssSyntaxError'
  /**
   * @member {string} - Error message.
   *
   * @example
   * error.message //=> 'Unclosed block'
   */
  reason?: string
  /**
   * @member {string} - Absolute path to the broken file.
   *
   * @example
   * error.file       //=> 'a.sass'
   * error.input.file //=> 'a.css'
   */
  file?: string
  /**
   * @member {string} - Source code of the broken file.
   *
   * @example
   * error.source       //=> 'a { b {} }'
   * error.input.column //=> 'a b { }'
   */
  source?: string
  /**
   * @member {string} - Plugin name, if error came from plugin.
   *
   * @example
   * error.plugin //=> 'postcss-vars'
   */
  plugin?: string
  /**
   * @member {number} - Source line of the error.
   *
   * @example
   * error.line       //=> 2
   * error.input.line //=> 4
   */
  line?: number | string
  /**
   * @member {number} - Source column of the error.
   *
   * @example
   * error.column       //=> 1
   * error.input.column //=> 4
   */
  column?: number | string
  message?: string
  /**
   * @memberof CssSyntaxError#
   * @member {Input} input - 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.
   *
   * @example
   * error.input.file //=> 'a.css'
   * error.file       //=> 'a.sass'
   */
  input: any

  /**
   * @param {string} message  - error message
   * @param {number} [line]   - source line of the error
   * @param {number} [column] - source column of the error
   * @param {string} [source] - source code of the broken file
   * @param {string} [file]   - absolute path to the broken file
   * @param {string} [plugin] - PostCSS plugin name, if error came from plugin
   */
  constructor(
    message?: string,
    line?: number,
    column?: number,
    source?: string,
    file?: string,
    plugin?: string
  ) {
    this.reason = message

    if (file) {
      this.file = file
    }
    if (source) {
      this.source = source
    }
    if (plugin) {
      this.plugin = plugin
    }
    if (typeof line !== 'undefined' && typeof column !== 'undefined') {
      this.line = line
      this.column = column
    }

    this.setMessage()

    if (Error.captureStackTrace) {
      Error.captureStackTrace(this, CssSyntaxError)
    }
  }

  setMessage() {
    /**
     * @member {string} - Full error text in the GNU error format
     *                    with plugin, file, line and column.
     *
     * @example
     * error.message //=> 'a.css:1:1: Unclosed block'
     */
    this.message = this.plugin ? this.plugin + ': ' : ''
    this.message += this.file ? this.file : '<css input>'
    if (typeof this.line !== 'undefined') {
      this.message += ':' + this.line + ':' + this.column
    }
    this.message += ': ' + this.reason
  }

  /**
   * Returns a few lines of CSS source that caused the error.
   *
   * If the CSS has an input source map without `sourceContent`,
   * this method will return an empty string.
   *
   * @param {boolean} [color] whether arrow will be colored red by terminal
   *                          color codes. By default, PostCSS will detect
   *                          color support by `process.stdout.isTTY`
   *                          and `process.env.NODE_DISABLE_COLORS`.
   *
   * @example
   * error.showSourceCode() //=> "  4 | }
   *                        //      5 | a {
   *                        //    > 6 |   bad
   *                        //        |   ^
   *                        //      7 | }
   *                        //      8 | b {"
   *
   * @return {string} few lines of CSS source that caused the error
   */
  showSourceCode(color?: boolean): string {
    if (!this.source) return ''

    let css = this.source
    if (typeof color === 'undefined') color = supportsColor
    if (color) css = terminalHighlight(css)

    const lines = css.split(/\r?\n/)
    const start = Math.max(this.line - 3, 0)
    const end = Math.min(this.line + 2, lines.length)
    const maxWidth = String(end).length

    return lines
      .slice(start, end)
      .map((line, index) => {
        const number = start + 1 + index
        const padded = (' ' + number).slice(-maxWidth)
        const gutter = ' ' + padded + ' | '
        if ((number as any) === this.line) {
          const spacing =
            gutter.replace(/\d/g, ' ') +
            line.slice(0, this.column - 1).replace(/[^\t]/g, ' ')
          return '>' + gutter + line + '\n ' + spacing + '^'
        } else {
          return ' ' + gutter + line
        }
      })
      .join('\n')
  }

  /**
   * Returns error position, message and source code of the broken part.
   *
   * @example
   * error.toString() //=> "CssSyntaxError: app.css:1:1: Unclosed block
   *                  //    > 1 | a {
   *                  //        | ^"
   *
   * @return {string} error position, message and source code
   */
  toString() {
    let code = this.showSourceCode()
    if (code) {
      code = '\n\n' + code + '\n'
    }
    return this.name + ': ' + this.message + code
  }

  get generated() {
    warnOnce('CssSyntaxError#generated is depreacted. Use input instead.')
    return this.input
  }
}

export default CssSyntaxError