| // NOTICE: This file is generated by Rollup. To modify it, |
| // please instead edit the ESM counterpart and rebuild with Rollup (npm run build). |
| 'use strict'; |
| |
| const path = require('node:path'); |
| const fs = require('node:fs'); |
| const process = require('node:process'); |
| const createDebug = require('debug'); |
| const fastGlob = require('fast-glob'); |
| const globby = require('globby'); |
| const normalizePath = require('normalize-path'); |
| const writeFileAtomic = require('write-file-atomic'); |
| const errors = require('./utils/errors.cjs'); |
| const validateTypes = require('./utils/validateTypes.cjs'); |
| const emitWarning = require('./utils/emitWarning.cjs'); |
| const constants = require('./constants.cjs'); |
| const suppressionsService = require('./utils/suppressionsService.cjs'); |
| const createPartialStylelintResult = require('./createPartialStylelintResult.cjs'); |
| const createStylelint = require('./createStylelint.cjs'); |
| const filterFilePaths = require('./utils/filterFilePaths.cjs'); |
| const getConfigForFile = require('./getConfigForFile.cjs'); |
| const getFileIgnorer = require('./utils/getFileIgnorer.cjs'); |
| const getFormatter = require('./utils/getFormatter.cjs'); |
| const lintSource = require('./lintSource.cjs'); |
| const normalizeFixMode = require('./utils/normalizeFixMode.cjs'); |
| const prepareReturnValue = require('./prepareReturnValue.cjs'); |
| const resolveFilePath = require('./utils/resolveFilePath.cjs'); |
| const resolveOptionValue = require('./utils/resolveOptionValue.cjs'); |
| |
| const debug = createDebug('stylelint:standalone'); |
| |
| const ALWAYS_IGNORED_GLOBS = ['**/node_modules/**']; |
| |
| /** @import {InternalApi, LintResult} from 'stylelint' */ |
| |
| /** |
| * @type {import('stylelint').PublicApi['lint']} |
| */ |
| async function standalone({ |
| allowEmptyInput, |
| cache, |
| cacheLocation, |
| cacheStrategy, |
| code, |
| codeFilename, |
| config, |
| configBasedir, |
| configFile, |
| customSyntax, |
| cwd = process.cwd(), |
| disableDefaultIgnores, |
| files, |
| fix, |
| computeEditInfo, |
| formatter, |
| _defaultFormatter, |
| globbyOptions, |
| ignoreDisables, |
| ignorePath, |
| ignorePattern, |
| maxWarnings, |
| quiet, |
| quietDeprecationWarnings = false, |
| reportDescriptionlessDisables, |
| reportInvalidScopeDisables, |
| reportNeedlessDisables, |
| reportUnscopedDisables, |
| suppressAll, |
| suppressRule, |
| suppressLocation, |
| validate = true, |
| }) { |
| const startTime = Date.now(); |
| |
| const useInputCode = !files && validateTypes.isString(code); |
| const hasOneValidInput = (files && !validateTypes.isString(code)) || useInputCode; |
| |
| if (!hasOneValidInput) { |
| return Promise.reject( |
| new Error('You must pass stylelint a `files` glob or a `code` string, though not both'), |
| ); |
| } |
| |
| // The ignorer will be used to filter file paths after the glob is checked, |
| // before any files are actually read |
| /** @type {import('ignore').Ignore} */ |
| let ignorer; |
| |
| try { |
| ignorer = getFileIgnorer({ cwd, ignorePath, ignorePattern }); |
| } catch (error) { |
| return Promise.reject(error); |
| } |
| |
| const stylelint = createStylelint({ |
| allowEmptyInput, |
| cache, |
| cacheLocation, |
| cacheStrategy, |
| config, |
| configFile, |
| configBasedir, |
| cwd, |
| formatter, |
| _defaultFormatter, |
| ignoreDisables, |
| ignorePath, |
| reportNeedlessDisables, |
| reportInvalidScopeDisables, |
| reportDescriptionlessDisables, |
| reportUnscopedDisables, |
| customSyntax, |
| fix, |
| computeEditInfo, |
| quiet, |
| quietDeprecationWarnings, |
| validate, |
| }); |
| |
| /** @see https://github.com/stylelint/stylelint/issues/7447 */ |
| if (!quietDeprecationWarnings && formatter === 'github') { |
| emitWarning.emitDeprecationWarning( |
| '"github" formatter is deprecated.', |
| 'GITHUB_FORMATTER', |
| 'See https://stylelint.io/awesome-stylelint#formatters for alternative formatters.', |
| ); |
| } |
| |
| const formatterFunction = await getFormatter(stylelint); |
| |
| if (!files) { |
| validateTypes.assertString(code); |
| |
| const absoluteCodeFilename = |
| codeFilename !== undefined && !path.isAbsolute(codeFilename) |
| ? path.join(cwd, codeFilename) |
| : codeFilename; |
| |
| // if file is ignored, return nothing |
| if ( |
| absoluteCodeFilename && |
| !filterFilePaths(ignorer, [path.relative(cwd, absoluteCodeFilename)]).length |
| ) { |
| return prepareReturnValue({ |
| results: [], |
| maxWarnings, |
| quietDeprecationWarnings, |
| formatter: formatterFunction, |
| cwd, |
| }); |
| } |
| |
| let stylelintResult; |
| |
| try { |
| const postcssResult = await lintSource(stylelint, { |
| code, |
| codeFilename: absoluteCodeFilename, |
| }); |
| |
| stylelintResult = createPartialStylelintResult(postcssResult); |
| } catch (error) { |
| stylelintResult = handleError(error); |
| } |
| |
| await postProcessStylelintResult(stylelint, stylelintResult, absoluteCodeFilename); |
| |
| const postcssResult = stylelintResult._postcssResult; |
| const returnValue = prepareReturnValue({ |
| results: [stylelintResult], |
| maxWarnings, |
| quietDeprecationWarnings, |
| formatter: formatterFunction, |
| cwd, |
| }); |
| |
| const autofix = normalizeFixMode(stylelint._options.fix) ?? config?.fix ?? false; |
| |
| if (autofix && postcssResult && !postcssResult.stylelint.ignored) { |
| returnValue.code = postcssResult.opts |
| ? // If we're fixing, the output should be the fixed code |
| postcssResult.root.toString(postcssResult.opts.syntax) |
| : // If the writing of the fix is disabled, the input code is returned as-is |
| code; |
| |
| returnValue._output = returnValue.code; // TODO: Deprecated. Remove in the next major version. |
| } |
| |
| return returnValue; |
| } |
| |
| let fileList = [files].flat().map((entry) => { |
| const globCWD = (globbyOptions && globbyOptions.cwd) || cwd; |
| const absolutePath = !path.isAbsolute(entry) ? path.join(globCWD, entry) : path.normalize(entry); |
| |
| if (fs.existsSync(absolutePath)) { |
| // This path points to a file. Return an escaped path to avoid globbing |
| return fastGlob.escapePath(normalizePath(entry)); |
| } |
| |
| return entry; |
| }); |
| |
| if (!disableDefaultIgnores) { |
| fileList = fileList.concat(ALWAYS_IGNORED_GLOBS.map((glob) => `!${glob}`)); |
| } |
| |
| const useCache = await resolveOptionValue({ stylelint, name: 'cache', default: false }); |
| |
| if (!useCache) { |
| stylelint._fileCache.destroy(); |
| } |
| |
| const effectiveGlobbyOptions = { |
| cwd, |
| ...(globbyOptions || {}), |
| absolute: true, |
| }; |
| |
| const globCWD = effectiveGlobbyOptions.cwd; |
| |
| let filePaths = await globby(fileList, effectiveGlobbyOptions); |
| // Record the length of filePaths before ignore operation |
| // Prevent prompting "No files matching the pattern 'xx' were found." when .stylelintignore ignore all input files |
| const filePathsLengthBeforeIgnore = filePaths.length; |
| |
| // The ignorer filter needs to check paths relative to cwd |
| filePaths = filterFilePaths( |
| ignorer, |
| filePaths.map((p) => path.relative(globCWD, p)), |
| ); |
| |
| let stylelintResults; |
| |
| if (filePaths.length) { |
| let absoluteFilePaths = filePaths.map((filePath) => { |
| const absoluteFilepath = !path.isAbsolute(filePath) |
| ? path.join(globCWD, filePath) |
| : path.normalize(filePath); |
| |
| return absoluteFilepath; |
| }); |
| |
| const getStylelintResults = absoluteFilePaths.map(async (absoluteFilepath) => { |
| debug(`Processing ${absoluteFilepath}`); |
| |
| try { |
| const postcssResult = await lintSource(stylelint, { |
| filePath: absoluteFilepath, |
| cache: useCache, |
| }); |
| |
| if ( |
| (postcssResult.stylelint.stylelintError || postcssResult.stylelint.stylelintWarning) && |
| useCache |
| ) { |
| debug(`${absoluteFilepath} contains linting errors and will not be cached.`); |
| stylelint._fileCache.removeEntry(absoluteFilepath); |
| } |
| |
| /** |
| * If we're fixing, save the file with changed code |
| */ |
| if (postcssResult.root && postcssResult.opts && !postcssResult.stylelint.ignored && fix) { |
| const fixedCss = postcssResult.root.toString(postcssResult.opts.syntax); |
| |
| if ( |
| postcssResult.root && |
| postcssResult.root.source && |
| postcssResult.root.source.input.css !== fixedCss |
| ) { |
| await writeFileAtomic(absoluteFilepath, fixedCss); |
| } |
| } |
| |
| const stylelintResult = createPartialStylelintResult(postcssResult); |
| |
| await postProcessStylelintResult(stylelint, stylelintResult, absoluteFilepath); |
| |
| return stylelintResult; |
| } catch (error) { |
| // On any error, we should not cache the lint result |
| stylelint._fileCache.removeEntry(absoluteFilepath); |
| |
| const stylelintResult = handleError(error); |
| |
| await postProcessStylelintResult(stylelint, stylelintResult, absoluteFilepath); |
| |
| return stylelintResult; |
| } |
| }); |
| |
| stylelintResults = await Promise.all(getStylelintResults); |
| } else if (await resolveOptionValue({ stylelint, name: 'allowEmptyInput', default: false })) { |
| stylelintResults = await Promise.all([]); |
| } else if (filePathsLengthBeforeIgnore) { |
| // All input files ignored |
| stylelintResults = await Promise.reject(new errors.AllFilesIgnoredError()); |
| } else { |
| stylelintResults = await Promise.reject(new errors.NoFilesFoundError(fileList)); |
| } |
| |
| if (!useInputCode) { |
| const resolvedSuppressLocation = resolveFilePath( |
| suppressLocation || constants.DEFAULT_SUPPRESSION_FILENAME, |
| cwd, |
| constants.DEFAULT_SUPPRESSION_FILENAME, |
| ); |
| |
| const existsSuppressionsFile = fs.existsSync(resolvedSuppressLocation); |
| |
| if (suppressLocation && !existsSuppressionsFile && !suppressAll && !suppressRule) { |
| throw new errors.SuppressionFileNotFoundError(); |
| } |
| |
| if (suppressAll || suppressRule || existsSuppressionsFile) { |
| emitWarning.emitExperimentalWarning( |
| 'The suppressions feature is experimental.', |
| 'SUPPRESSIONS', |
| 'See https://stylelint.io/user-guide/suppressions for more information.', |
| ); |
| |
| const suppressions = new suppressionsService.SuppressionsService({ |
| filePath: resolvedSuppressLocation, |
| cwd: process.cwd(), |
| }); |
| |
| if (suppressAll || suppressRule) { |
| await suppressions.suppress(stylelintResults, suppressRule); |
| } |
| |
| const suppressionResults = suppressions.applySuppressions( |
| stylelintResults, |
| await suppressions.load(), |
| ); |
| |
| stylelintResults = suppressionResults.results; |
| } |
| } |
| |
| if (useCache) { |
| stylelint._fileCache.reconcile(); |
| } |
| |
| const result = prepareReturnValue({ |
| results: stylelintResults, |
| maxWarnings, |
| quietDeprecationWarnings, |
| formatter: formatterFunction, |
| cwd, |
| }); |
| |
| debug(`Linting complete in ${Date.now() - startTime}ms`); |
| |
| return result; |
| } |
| |
| /** |
| * @import {CssSyntaxError} from 'stylelint' |
| * |
| * @param {unknown} error |
| * @returns {LintResult} |
| */ |
| function handleError(error) { |
| if (error instanceof Error && error.name === 'CssSyntaxError') { |
| return createPartialStylelintResult(undefined, /** @type {CssSyntaxError} */ (error)); |
| } |
| |
| throw error; |
| } |
| |
| /** |
| * @param {InternalApi} stylelint |
| * @param {LintResult} stylelintResult |
| * @param {string} [filePath] |
| * @returns {Promise<void>} |
| */ |
| async function postProcessStylelintResult(stylelint, stylelintResult, filePath) { |
| const configForFile = await getConfigForFile({ stylelint, searchPath: filePath, filePath }); |
| |
| const config = configForFile === null ? {} : configForFile.config; |
| |
| if (!config._processorFunctions) { |
| return; |
| } |
| |
| for (let postprocess of config._processorFunctions.values()) { |
| postprocess?.(stylelintResult, stylelintResult._postcssResult?.root); |
| } |
| } |
| |
| module.exports = standalone; |