UNPKG

stylelint-processor-styled-components

Version:
125 lines (113 loc) 4.08 kB
const path = require('path') const micromatch = require('micromatch') const parse = require('./parsers/index') const { isCausedBySubstitution, getCorrectColumn } = require('./utils/result') let inputId = 1 // Make sure that state for particular path will be cleaned before each run // module may be kept in memory when used with vscode-stylelint const taggedTemplateLocsMap = {} const interpolationLinesMap = {} const sourceMapsCorrections = {} const errorWasThrown = {} const DEFAULT_OPTIONS = { moduleName: 'styled-components', importName: 'default', strict: false, ignoreFiles: [] } const realProcessor = options => ({ // Get string for stylelint to lint code(input, filepath) { let absolutePath if (filepath) { absolutePath = path.resolve(process.cwd(), filepath) } else { absolutePath = `<input css ${inputId}>` inputId += 1 } const fileIsIgnored = micromatch(filepath, options.ignoreFiles).length if (fileIsIgnored) return input try { const { extractedCSS, interpolationLines, taggedTemplateLocs, sourceMap } = parse( input, absolutePath, options ) // Save `loc` of template literals taggedTemplateLocsMap[absolutePath] = taggedTemplateLocs // Save dummy interpolation lines interpolationLinesMap[absolutePath] = interpolationLines // Save source location sourceMapsCorrections[absolutePath] = sourceMap // Clean saved errors delete errorWasThrown[absolutePath] return extractedCSS } catch (e) { // Always save the error errorWasThrown[absolutePath] = e // Incorrect interpolations will throw CssSyntaxError and they'll be handled by stylelint // so we can throw it out but not for others if (e.name === 'CssSyntaxError') { throw e } return '' } }, // Fix sourcemaps result(stylelintResult, filepath) { const err = errorWasThrown[filepath] const fileIsIgnored = micromatch(filepath, options.ignoreFiles).length if (fileIsIgnored) return stylelintResult if (err) { if (err.name === 'CssSyntaxError') { // We threw an error ourselves, in this case we have already put correct // line/column numbers so no source maps are needed // (and would actually break the line numbers) return stylelintResult } else { // For other errors, wrap them into the result return { ...stylelintResult, errored: true, parseErrors: [ { line: err.loc && err.loc.line, column: err.loc && err.loc.column, rule: 'parseError', severity: 'error', text: `${err.message}` } ] } } } const taggedTemplateLocs = taggedTemplateLocsMap[filepath] || [] const interpolationLines = interpolationLinesMap[filepath] || [] const lineCorrection = sourceMapsCorrections[filepath] const warnings = stylelintResult.warnings .filter( warning => // Filter false-positive warnings generated by interpolations substitution !isCausedBySubstitution(warning, lineCorrection[warning.line], interpolationLines) ) .map(warning => ({ ...warning, // Replace "brace" with "backtick" in warnings, e.g. // "Unexpected empty line before closing backtick" (instead of "brace") text: warning.text.replace(/brace/, 'backtick'), line: lineCorrection[warning.line] || warning.line, column: getCorrectColumn( taggedTemplateLocs, lineCorrection[warning.line] || warning.line, warning.column ) })) const result = { ...stylelintResult, warnings } // Undo `errored` if no warnings with error severity any more if (result.errored && !warnings.some(warning => warning.severity === 'error')) { delete result.errored } return result } }) module.exports = options => realProcessor({ ...DEFAULT_OPTIONS, ...options })