stylelint
Advanced tools
Comparing version 15.4.0 to 15.5.0
307
lib/cli.js
@@ -7,85 +7,87 @@ 'use strict'; | ||
const { red, dim } = require('picocolors'); | ||
const resolveFrom = require('resolve-from'); | ||
const { isPlainObject } = require('./utils/validateTypes'); | ||
const checkInvalidCLIOptions = require('./utils/checkInvalidCLIOptions'); | ||
const getFormatterOptionsText = require('./utils/getFormatterOptionsText'); | ||
const getStdin = require('./utils/getStdin'); | ||
const printConfig = require('./printConfig'); | ||
const resolveFrom = require('resolve-from'); | ||
const standalone = require('./standalone'); | ||
const writeOutputFile = require('./writeOutputFile'); | ||
const resolveCustomFormatter = require('./resolveCustomFormatter'); | ||
const { | ||
DEFAULT_CACHE_LOCATION, | ||
DEFAULT_IGNORE_FILENAME, | ||
DEFAULT_FORMATTER, | ||
EXIT_CODE_ERROR, | ||
} = require('./constants'); | ||
const EXIT_CODE_ERROR = 2; | ||
/** | ||
* @typedef {object} CLIFlags | ||
* @property {boolean} [cache] | ||
* @property {string} [cacheLocation] | ||
* @property {string} [cacheStrategy] | ||
* @property {string | false} config | ||
* @property {string} [configBasedir] | ||
* @property {string} [customSyntax] | ||
* @property {string} [printConfig] | ||
* @property {string} [color] | ||
* @property {string} [customFormatter] | ||
* @property {boolean} [disableDefaultIgnores] | ||
* @property {boolean} [fix] | ||
* @property {string} [formatter="string"] | ||
* @property {string} [help] | ||
* @property {boolean} [ignoreDisables] | ||
* @property {string[]} [ignorePath] | ||
* @property {string[]} [ignorePattern] | ||
* @property {string} [noColor] | ||
* @property {string} [outputFile] | ||
* @property {boolean} [stdin] | ||
* @property {string} [stdinFilename] | ||
* @property {boolean} [reportNeedlessDisables] | ||
* @property {boolean} [reportInvalidScopeDisables] | ||
* @property {boolean} [reportDescriptionlessDisables] | ||
* @property {number} [maxWarnings] | ||
* @property {boolean} quiet | ||
* @property {boolean} quietDeprecationWarnings | ||
* @property {string} [version] | ||
* @property {boolean} [allowEmptyInput] | ||
* @property {string} [globbyOptions] | ||
* @typedef {{ | ||
* allowEmptyInput: boolean; | ||
* cache: boolean; | ||
* cacheLocation?: string; | ||
* cacheStrategy?: string; | ||
* color: boolean; | ||
* config?: string; | ||
* configBasedir?: string; | ||
* customFormatter?: string; | ||
* customSyntax?: string; | ||
* disableDefaultIgnores: boolean; | ||
* fix: boolean; | ||
* formatter: string; | ||
* globbyOptions?: string; | ||
* help: boolean; | ||
* ignoreDisables: boolean; | ||
* ignorePath: string[]; | ||
* ignorePattern: string[]; | ||
* maxWarnings?: number; | ||
* outputFile?: string; | ||
* printConfig: boolean; | ||
* quiet: boolean; | ||
* quietDeprecationWarnings: boolean; | ||
* reportDescriptionlessDisables: boolean; | ||
* reportInvalidScopeDisables: boolean; | ||
* reportNeedlessDisables: boolean; | ||
* stdin: boolean; | ||
* stdinFilename?: string; | ||
* version: boolean; | ||
* }} CLIFlags | ||
*/ | ||
/** | ||
* @typedef {object} CLIOptions | ||
* @property {any} input | ||
* @property {any} help | ||
* @property {any} pkg | ||
* @property {Function} showHelp | ||
* @property {Function} showVersion | ||
* @property {CLIFlags} flags | ||
* @typedef {{ | ||
* input: string[]; | ||
* showHelp: (code: number) => void; | ||
* showVersion: () => void; | ||
* flags: CLIFlags; | ||
* }} CLIOptions | ||
*/ | ||
/** | ||
* @typedef {object} OptionBaseType | ||
* @property {any} formatter | ||
* @property {boolean} [cache] | ||
* @property {string} [configFile] | ||
* @property {string} [cacheLocation] | ||
* @property {string} [cacheStrategy] | ||
* @property {string} [customSyntax] | ||
* @property {string} [codeFilename] | ||
* @property {string} [configBasedir] | ||
* @property {boolean} [quiet] | ||
* @property {boolean} [quietDeprecationWarnings] | ||
* @property {any} [printConfig] | ||
* @property {boolean} [fix] | ||
* @property {Record<string, unknown>} [globbyOptions] | ||
* @property {boolean} [ignoreDisables] | ||
* @property {any} [ignorePath] | ||
* @property {string} [outputFile] | ||
* @property {boolean} [reportNeedlessDisables] | ||
* @property {boolean} [reportInvalidScopeDisables] | ||
* @property {boolean} [reportDescriptionlessDisables] | ||
* @property {boolean} [disableDefaultIgnores] | ||
* @property {number} [maxWarnings] | ||
* @property {string[]} [ignorePattern] | ||
* @property {boolean} [allowEmptyInput] | ||
* @property {string} [files] | ||
* @property {string} [code] | ||
* @typedef {{ | ||
* allowEmptyInput?: boolean; | ||
* cache?: boolean; | ||
* cacheLocation?: string; | ||
* cacheStrategy?: string; | ||
* code?: string; | ||
* codeFilename?: string; | ||
* configFile?: string; | ||
* configBasedir?: string; | ||
* customSyntax?: string; | ||
* disableDefaultIgnores?: boolean; | ||
* files?: string[]; | ||
* fix?: boolean; | ||
* formatter: any; | ||
* globbyOptions?: Record<string, unknown>; | ||
* ignoreDisables?: boolean; | ||
* ignorePath?: string[]; | ||
* ignorePattern?: string[]; | ||
* maxWarnings?: number; | ||
* outputFile?: string; | ||
* quiet?: boolean; | ||
* quietDeprecationWarnings?: boolean; | ||
* reportDescriptionlessDisables?: boolean; | ||
* reportInvalidScopeDisables?: boolean; | ||
* reportNeedlessDisables?: boolean; | ||
* }} OptionBaseType | ||
*/ | ||
@@ -102,3 +104,3 @@ | ||
If an input argument is wrapped in quotation marks, it will be passed to | ||
globby for cross-platform glob support. node_modules are always ignored. | ||
globby for cross-platform glob support. "node_modules" are always ignored. | ||
You can also pass no input and use stdin, instead. | ||
@@ -108,16 +110,18 @@ | ||
--config, -c | ||
--config, -c <path_or_module> | ||
Path to a specific configuration file (JSON, YAML, or CommonJS), or the | ||
name of a module in node_modules that points to one. If no --config | ||
argument is provided, stylelint will search for configuration files in | ||
the following places, in this order: | ||
- a stylelint property in package.json | ||
- a .stylelintrc file (with or without filename extension: | ||
.json, .yaml, .yml, and .js are available) | ||
- a stylelint.config.js file exporting a JS object | ||
A path to a specific configuration file (JSON, YAML, or CommonJS), or a | ||
module name in "node_modules" that points to one. If no argument is | ||
provided, Stylelint will search for configuration files in the following | ||
places, in this order: | ||
- a "stylelint" property in "package.json" | ||
- a ".stylelintrc" file (with or without filename extension: | ||
".json", ".yaml", ".yml", ".js", and ".cjs" are available) | ||
- a "stylelint.config.js" file exporting a JS object | ||
The search will begin in the working directory and move up the directory | ||
tree until a configuration file is found. | ||
--config-basedir | ||
--config-basedir <path> | ||
@@ -128,16 +132,17 @@ An absolute path to the directory that relative paths defining "extends", | ||
--print-config | ||
--print-config <path> | ||
Print the configuration for the given path. | ||
--ignore-path, -i | ||
--ignore-path, -i <path> | ||
Path to a file containing patterns that describe files to ignore. The | ||
path can be absolute or relative to process.cwd(). You can repeat the | ||
A path to a file containing patterns that describe files to ignore. The | ||
path can be absolute or relative to "process.cwd()". You can repeat the | ||
option to provide multiple paths. By default, Stylelint looks for | ||
.stylelintignore in process.cwd(). | ||
"${DEFAULT_IGNORE_FILENAME}" in "process.cwd()". Multiple can be set. | ||
--ignore-pattern, --ip | ||
--ignore-pattern, --ip <pattern> | ||
Pattern of files to ignore (in addition to those in .stylelintignore) | ||
A pattern of files to ignore (in addition to those in "${DEFAULT_IGNORE_FILENAME}"). | ||
Multiple can be set. | ||
@@ -148,5 +153,5 @@ --fix | ||
--custom-syntax | ||
--custom-syntax <name_or_path> | ||
Module name or path to a JS file exporting a PostCSS-compatible syntax. | ||
A module name or path to a JS file exporting a PostCSS-compatible syntax. | ||
@@ -157,3 +162,3 @@ --stdin | ||
--stdin-filename | ||
--stdin-filename <name> | ||
@@ -164,43 +169,53 @@ A filename to assign stdin input. | ||
Ignore stylelint-disable comments. | ||
Ignore "stylelint-disable" comments. | ||
--disable-default-ignores, --di | ||
Allow linting of node_modules. | ||
Allow linting of "node_modules". | ||
--cache [default: false] | ||
--[no-]cache | ||
Store the info about processed files in order to only operate on the | ||
changed ones the next time you run stylelint. By default, the cache | ||
is stored in "./.stylelintcache". To adjust this, use --cache-location. | ||
changed ones the next time you run Stylelint. By default, the cache is | ||
stored in "${DEFAULT_CACHE_LOCATION}". To adjust this, use "--cache-location". | ||
Cache is disabled by default. | ||
--cache-location [default: '.stylelintcache'] | ||
--cache-location <path> | ||
Path to a file or directory to be used for the cache location. | ||
Default is "./.stylelintcache". If a directory is specified, a cache | ||
file will be created inside the specified folder, with a name derived | ||
from a hash of the current working directory. | ||
A path to a file or directory to be used for the cache location. If a | ||
directory is specified, a cache file will be created inside the specified | ||
folder, with a name derived from a hash of the current working directory. | ||
If the directory for the cache does not exist, make sure you add a trailing "/" | ||
on *nix systems or "\\" on Windows. Otherwise the path will be assumed to be a file. | ||
on *nix systems or "\\" on Windows. Otherwise the path will be assumed to | ||
be a file. | ||
--cache-strategy [default: "metadata"] | ||
--cache-strategy <strategy> | ||
Strategy for the cache to use for detecting changed files. Can be either | ||
"metadata" or "content". | ||
A strategy for the cache to use for detecting changed files. Either one of: | ||
The "content" strategy can be useful in cases where the modification time of | ||
your files changes even if their contents have not. For example, this can happen | ||
during git operations like "git clone" because git does not track file modification | ||
time. | ||
metadata by metadata of a file (default) | ||
content by content of a file | ||
--formatter, -f [default: "string"] | ||
The "content" strategy can be useful in cases where the modification time | ||
of your files changes even if their contents have not. For example, this can | ||
happen during git operations like "git clone" because git does not track file | ||
modification time. | ||
The output formatter: ${getFormatterOptionsText({ useOr: true })}. | ||
--formatter, -f <formatter> | ||
--custom-formatter | ||
An output formatter. The variants are as follows: | ||
Path to a JS file exporting a custom formatting function. | ||
The file can either be a filesystem path, a module name, or a file to load from a dependency. | ||
string human-readable strings (default) | ||
compact similar to ESLint's compact formatter | ||
github workflow commands for GitHub Actions | ||
json JSON format | ||
tap TAP format | ||
unix C compiler-like format | ||
verbose extend "string" to include a file list and a tally | ||
--custom-formatter <path_or_module> | ||
A path to a JS file or module name exporting a custom formatting function. | ||
--quiet, -q | ||
@@ -215,4 +230,3 @@ | ||
--color | ||
--no-color | ||
--[no-]color | ||
@@ -223,36 +237,41 @@ Force enabling/disabling of color. | ||
Also report errors for stylelint-disable comments that are not blocking a lint warning. | ||
The process will exit with code ${EXIT_CODE_ERROR} if needless disables are found. | ||
Also report errors for "stylelint-disable" comments that are not blocking | ||
a lint warning. The process will exit with code ${EXIT_CODE_ERROR} if needless disables are found. | ||
--report-invalid-scope-disables, --risd | ||
Report stylelint-disable comments that used for rules that don't exist within the configuration object. | ||
The process will exit with code ${EXIT_CODE_ERROR} if invalid scope disables are found. | ||
Report "stylelint-disable" comments that used for rules that don't exist | ||
within the configuration object. The process will exit with code ${EXIT_CODE_ERROR} if invalid | ||
scope disables are found. | ||
--report-descriptionless-disables, --rdd | ||
Report stylelint-disable comments without a description. | ||
The process will exit with code ${EXIT_CODE_ERROR} if descriptionless disables are found. | ||
Report "stylelint-disable" comments without a description. The process will | ||
exit with code ${EXIT_CODE_ERROR} if descriptionless disables are found. | ||
--max-warnings, --mw | ||
--max-warnings, --mw <number> | ||
Number of warnings above which the process will exit with code ${EXIT_CODE_ERROR}. | ||
Useful when setting "defaultSeverity" to "warning" and expecting the | ||
process to fail on warnings (e.g. CI build). | ||
The number of warnings above which the process will exit with code ${EXIT_CODE_ERROR}. | ||
Useful when setting "defaultSeverity" to "warning" and expecting the process | ||
to fail on warnings (e.g. CI build). | ||
--output-file, -o | ||
--output-file, -o <path> | ||
Path of file to write report. | ||
A file path to write a report. | ||
--version, -v | ||
--allow-empty-input, --aei | ||
Show the currently installed version of stylelint. | ||
When a glob pattern matches no files, the process will exit without throwing an error. | ||
--allow-empty-input, --aei | ||
--globby-options, --go <json> | ||
When glob pattern matches no files, the process will exit without throwing an error. | ||
Options in JSON format passed to globby. | ||
--globby-options, --go | ||
--version, -v | ||
Options in JSON format passed to globby. | ||
Show the version. | ||
--help, -h | ||
Show the help. | ||
`, | ||
@@ -298,5 +317,9 @@ flags: { | ||
alias: 'f', | ||
default: 'string', | ||
type: 'string', | ||
default: DEFAULT_FORMATTER, | ||
}, | ||
globbyOptions: { | ||
alias: 'go', | ||
type: 'string', | ||
}, | ||
help: { | ||
@@ -360,6 +383,2 @@ alias: 'h', | ||
}, | ||
globbyOptions: { | ||
alias: 'go', | ||
type: 'string', | ||
}, | ||
}, | ||
@@ -372,3 +391,3 @@ }; | ||
*/ | ||
module.exports = async (argv) => { | ||
module.exports = async function main(argv) { | ||
const cli = buildCLI(argv); | ||
@@ -524,10 +543,8 @@ | ||
...optionsBase, | ||
files: /** @type {string} */ (cli.input), | ||
files: cli.input, | ||
} | ||
: await getStdin().then((stdin) => { | ||
return { | ||
...optionsBase, | ||
code: stdin, | ||
}; | ||
}); | ||
: await getStdin().then((stdin) => ({ | ||
...optionsBase, | ||
code: stdin, | ||
})); | ||
@@ -534,0 +551,0 @@ if (cli.flags.printConfig) { |
@@ -66,2 +66,6 @@ 'use strict'; | ||
if (hasNonWhitespace(statement)) { | ||
return; | ||
} | ||
let index = beforeBlockString(statement, { noRawBefore: true }).length; | ||
@@ -98,2 +102,12 @@ | ||
} | ||
/** | ||
* @param {Statement} statement | ||
* @returns {boolean} | ||
*/ | ||
function hasNonWhitespace(statement) { | ||
const { after } = statement.raws; | ||
return typeof after === 'string' && /\S/.test(after); | ||
} | ||
}; | ||
@@ -100,0 +114,0 @@ }; |
@@ -8,3 +8,5 @@ 'use strict'; | ||
const ruleMessages = require('../../utils/ruleMessages'); | ||
const { isRegExp, isString } = require('../../utils/validateTypes'); | ||
const validateOptions = require('../../utils/validateOptions'); | ||
const optionsMatches = require('../../utils/optionsMatches'); | ||
@@ -22,5 +24,16 @@ const ruleName = 'declaration-block-no-duplicate-custom-properties'; | ||
/** @type {import('stylelint').Rule} */ | ||
const rule = (primary) => { | ||
const rule = (primary, secondaryOptions) => { | ||
return (root, result) => { | ||
const validOptions = validateOptions(result, ruleName, { actual: primary }); | ||
const validOptions = validateOptions( | ||
result, | ||
ruleName, | ||
{ actual: primary }, | ||
{ | ||
actual: secondaryOptions, | ||
possible: { | ||
ignoreProperties: [isString, isRegExp], | ||
}, | ||
optional: true, | ||
}, | ||
); | ||
@@ -45,2 +58,6 @@ if (!validOptions) { | ||
if (optionsMatches(secondaryOptions, 'ignoreProperties', prop)) { | ||
return; | ||
} | ||
const isDuplicate = decls.has(prop); | ||
@@ -47,0 +64,0 @@ |
'use strict'; | ||
const { parse, List } = require('css-tree'); | ||
const eachDeclarationBlock = require('../../utils/eachDeclarationBlock'); | ||
@@ -10,3 +11,3 @@ const isCustomProperty = require('../../utils/isCustomProperty'); | ||
const validateOptions = require('../../utils/validateOptions'); | ||
const { isString } = require('../../utils/validateTypes'); | ||
const { isRegExp, isString } = require('../../utils/validateTypes'); | ||
const vendor = require('../../utils/vendor'); | ||
@@ -25,2 +26,64 @@ | ||
/** @typedef {import('css-tree').CssNode} CssNode */ | ||
/** @type {(node: CssNode) => node is CssNode & { children: List<CssNode> }} */ | ||
const hasChildren = (node) => 'children' in node && node.children instanceof List; | ||
/** @type {(node1: CssNode[], node2: CssNode[]) => boolean} */ | ||
const isEqualValueNodes = (nodes1, nodes2) => { | ||
if (nodes1.length !== nodes2.length) { | ||
return false; | ||
} | ||
for (let i = 0; i < nodes1.length; i++) { | ||
const node1 = nodes1[i]; | ||
const node2 = nodes2[i]; | ||
if (typeof node1 === 'undefined' || typeof node2 === 'undefined' || node1.type !== node2.type) { | ||
return false; | ||
} | ||
const node1Children = hasChildren(node1) ? node1.children.toArray() : null; | ||
const node2Children = hasChildren(node2) ? node2.children.toArray() : null; | ||
if (Array.isArray(node1Children) && Array.isArray(node2Children)) { | ||
const node1Name = 'name' in node1 ? String(node1.name) : ''; | ||
const node2Name = 'name' in node2 ? String(node2.name) : ''; | ||
if (node1Name.toLowerCase() !== node2Name.toLowerCase()) { | ||
return false; | ||
} | ||
if (isEqualValueNodes(node1Children, node2Children)) { | ||
continue; | ||
} else { | ||
return false; | ||
} | ||
} | ||
const node1Unit = 'unit' in node1 ? node1.unit : ''; | ||
const node2Unit = 'unit' in node2 ? node2.unit : ''; | ||
if (node1Unit !== node2Unit) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
}; | ||
/** @type {(value1: string, value2: string) => boolean} */ | ||
const isEqualValueSyntaxes = (value1, value2) => { | ||
if (value1 === value2) { | ||
return true; | ||
} | ||
const value1Node = parse(value1, { context: 'value' }); | ||
const value2Node = parse(value2, { context: 'value' }); | ||
const node1Children = hasChildren(value1Node) ? value1Node.children.toArray() : []; | ||
const node2Children = hasChildren(value2Node) ? value2Node.children.toArray() : []; | ||
return isEqualValueNodes(node1Children, node2Children); | ||
}; | ||
/** @type {import('stylelint').Rule} */ | ||
@@ -39,5 +102,6 @@ const rule = (primary, secondaryOptions, context) => { | ||
'consecutive-duplicates-with-different-values', | ||
'consecutive-duplicates-with-different-syntaxes', | ||
'consecutive-duplicates-with-same-prefixless-values', | ||
], | ||
ignoreProperties: [isString], | ||
ignoreProperties: [isString, isRegExp], | ||
}, | ||
@@ -58,2 +122,7 @@ optional: true, | ||
); | ||
const ignoreDiffSyntaxes = optionsMatches( | ||
secondaryOptions, | ||
'ignore', | ||
'consecutive-duplicates-with-different-syntaxes', | ||
); | ||
const ignorePrefixlessSameValues = optionsMatches( | ||
@@ -131,3 +200,3 @@ secondaryOptions, | ||
if (ignoreDiffValues || ignorePrefixlessSameValues) { | ||
if (ignoreDiffValues || ignoreDiffSyntaxes || ignorePrefixlessSameValues) { | ||
if ( | ||
@@ -138,4 +207,16 @@ !duplicatesAreConsecutive || | ||
fixOrReport(); | ||
return; | ||
} | ||
if (ignoreDiffSyntaxes) { | ||
const duplicateValueSyntaxesAreEqual = isEqualValueSyntaxes(value, duplicateValue); | ||
if (duplicateValueSyntaxesAreEqual) { | ||
fixOrReport(); | ||
return; | ||
} | ||
} | ||
if (value !== duplicateValue) { | ||
@@ -142,0 +223,0 @@ return; |
@@ -88,3 +88,3 @@ 'use strict'; | ||
if (!unit || (unit && propList.includes(unit.toLowerCase()))) { | ||
if (!unit || propList.includes(unit.toLowerCase())) { | ||
return; | ||
@@ -91,0 +91,0 @@ } |
@@ -70,3 +70,3 @@ 'use strict'; | ||
if (!unit || (unit && !propList.includes(unit.toLowerCase()))) { | ||
if (!unit || !propList.includes(unit.toLowerCase())) { | ||
return; | ||
@@ -73,0 +73,0 @@ } |
@@ -8,3 +8,7 @@ 'use strict'; | ||
const { isTokenNode } = require('@csstools/css-parser-algorithms'); | ||
const { isMediaFeaturePlain, isMediaFeatureRange } = require('@csstools/media-query-list-parser'); | ||
const { | ||
isMediaFeaturePlain, | ||
isMediaFeatureRange, | ||
isMediaQueryInvalid, | ||
} = require('@csstools/media-query-list-parser'); | ||
const validateObjectWithArrayProps = require('../../utils/validateObjectWithArrayProps'); | ||
@@ -48,5 +52,7 @@ const { isString } = require('../../utils/validateTypes'); | ||
root.walkAtRules(/^media$/i, (atRule) => { | ||
const mediaQueryList = parseMediaQuery(atRule, result); | ||
const mediaQueryList = parseMediaQuery(atRule); | ||
mediaQueryList.forEach((mediaQuery) => { | ||
if (isMediaQueryInvalid(mediaQuery)) return; | ||
mediaQuery.walk((entry) => { | ||
@@ -53,0 +59,0 @@ if (!isMediaFeaturePlain(entry.node) && !isMediaFeatureRange(entry.node)) { |
@@ -9,2 +9,3 @@ 'use strict'; | ||
isMediaFeatureRange, | ||
isMediaQueryInvalid, | ||
} = require('@csstools/media-query-list-parser'); | ||
@@ -45,6 +46,8 @@ const { TokenNode } = require('@csstools/css-parser-algorithms'); | ||
root.walkAtRules(/^media$/i, (atRule) => { | ||
const mediaQueryList = parseMediaQuery(atRule, result); | ||
const mediaQueryList = parseMediaQuery(atRule); | ||
let hasFixes = false; | ||
mediaQueryList.forEach((mediaQuery) => { | ||
if (isMediaQueryInvalid(mediaQuery)) return; | ||
mediaQuery.walk((entry) => { | ||
@@ -51,0 +54,0 @@ const node = entry.node; |
@@ -77,3 +77,3 @@ 'use strict'; | ||
if (!unit || !number || (unit && primaryValues.includes(unit.toLowerCase()))) { | ||
if (!number || !unit || primaryValues.includes(unit.toLowerCase())) { | ||
return; | ||
@@ -80,0 +80,0 @@ } |
@@ -79,3 +79,3 @@ 'use strict'; | ||
// There is not unit or it is not configured as a problem | ||
if (!unit || !number || (unit && !primaryValues.includes(unit.toLowerCase()))) { | ||
if (!number || !unit || !primaryValues.includes(unit.toLowerCase())) { | ||
return; | ||
@@ -82,0 +82,0 @@ } |
@@ -278,5 +278,5 @@ 'use strict'; | ||
if (formatterFunction === undefined) { | ||
throw new Error( | ||
`You must use a valid formatter option: ${getFormatterOptionsText()} or a function`, | ||
); | ||
const formattersText = getFormatterOptionsText(', ', '"'); | ||
throw new Error(`You must use a valid formatter option: ${formattersText} or a function`); | ||
} | ||
@@ -283,0 +283,0 @@ |
@@ -5,13 +5,14 @@ 'use strict'; | ||
const fileEntryCache = require('file-entry-cache'); | ||
const path = require('path'); | ||
const pkg = require('../../package.json'); | ||
const getCacheFile = require('./getCacheFile'); | ||
const hash = require('./hash'); | ||
const pkg = require('../../package.json'); | ||
const path = require('path'); | ||
const { | ||
DEFAULT_CACHE_LOCATION, | ||
CACHE_STRATEGY_METADATA, | ||
CACHE_STRATEGY_CONTENT, | ||
DEFAULT_CACHE_STRATEGY, | ||
} = require('../constants'); | ||
const CACHE_STRATEGY_METADATA = 'metadata'; | ||
const CACHE_STRATEGY_CONTENT = 'content'; | ||
const DEFAULT_CACHE_LOCATION = './.stylelintcache'; | ||
const DEFAULT_CACHE_STRATEGY = CACHE_STRATEGY_METADATA; | ||
/** @typedef {import('file-entry-cache').FileDescriptor["meta"] & { hashOfConfig?: string }} CacheMetadata */ | ||
@@ -18,0 +19,0 @@ |
'use strict'; | ||
// Try to get file ignorer from '.stylelintignore' | ||
@@ -8,6 +7,5 @@ const fs = require('fs'); | ||
const { DEFAULT_IGNORE_FILENAME } = require('../constants'); | ||
const isPathNotFoundError = require('./isPathNotFoundError'); | ||
const DEFAULT_IGNORE_FILENAME = '.stylelintignore'; | ||
/** | ||
@@ -14,0 +12,0 @@ * @typedef {import('stylelint').LinterOptions} LinterOptions |
@@ -6,15 +6,10 @@ 'use strict'; | ||
/** | ||
* @param {{ useOr?: boolean }} [options={}] | ||
* @param {string} separator | ||
* @param {string} [quote] | ||
* @returns {string} | ||
*/ | ||
module.exports = function getFormatterOptionsText(options = {}) { | ||
let output = Object.keys(formatters) | ||
.map((name) => `"${name}"`) | ||
.join(', '); | ||
if (options.useOr) { | ||
output = output.replace(/, ([a-z"]+)$/u, ' or $1'); | ||
} | ||
return output; | ||
module.exports = function getFormatterOptionsText(separator, quote = '') { | ||
return Object.keys(formatters) | ||
.map((name) => `${quote}${name}${quote}`) | ||
.join(separator); | ||
}; |
'use strict'; | ||
const { isComment, hasSource } = require('./typeGuards'); | ||
const { isComment, isDocument, isRoot, hasSource } = require('./typeGuards'); | ||
@@ -12,6 +12,10 @@ /** | ||
if (parentNode === undefined || parentNode.type === 'root') { | ||
if (parentNode === undefined) { | ||
return false; | ||
} | ||
if (isRoot(parentNode) && !isInDocument(parentNode)) { | ||
return false; | ||
} | ||
if (statement === parentNode.first) { | ||
@@ -75,1 +79,9 @@ return true; | ||
}; | ||
/** | ||
* @param {import('postcss').Node} node | ||
* @returns {boolean} | ||
*/ | ||
function isInDocument({ parent }) { | ||
return Boolean(parent && isDocument(parent)); | ||
} |
@@ -18,3 +18,6 @@ 'use strict'; | ||
if (fnNode.type === 'word' && (fnNode.value.startsWith('#') || fnNode.value.startsWith('$'))) | ||
if ( | ||
fnNode.type === 'word' && | ||
(fnNode.value.startsWith('#') || fnNode.value.startsWith('$') || fnNode.value.includes('.$')) | ||
) | ||
return false; | ||
@@ -21,0 +24,0 @@ } |
'use strict'; | ||
const { parse, isMediaQueryInvalid } = require('@csstools/media-query-list-parser'); | ||
const { parse } = require('@csstools/media-query-list-parser'); | ||
/** | ||
* @param {import('postcss').AtRule} atRule | ||
* @param {import('stylelint').PostcssResult} result | ||
* @returns {ReturnType<typeof parse>} | ||
*/ | ||
module.exports = function parseMediaQuery(atRule, result) { | ||
module.exports = function parseMediaQuery(atRule) { | ||
const source = atRule.params; | ||
@@ -16,13 +15,3 @@ const mediaQueries = parse(source, { | ||
mediaQueries.forEach((mediaQuery) => { | ||
if (isMediaQueryInvalid(mediaQuery)) { | ||
result.warn(`Cannot parse media query`, { | ||
node: atRule, | ||
word: source, | ||
stylelintType: 'parseError', | ||
}); | ||
} | ||
}); | ||
return mediaQueries; | ||
}; |
'use strict'; | ||
/** @typedef {import('postcss').Node} Node */ | ||
/** @typedef {import('postcss').Node} NodeSource */ | ||
/** @typedef {import('postcss').Source} NodeSource */ | ||
@@ -47,2 +47,10 @@ /** | ||
/** | ||
* @param {Node} node | ||
* @returns {node is import('postcss').Document} | ||
*/ | ||
module.exports.isDocument = function isDocument(node) { | ||
return node.type === 'document'; | ||
}; | ||
/** | ||
* @param {import('postcss-value-parser').Node} node | ||
@@ -49,0 +57,0 @@ * @returns {node is import('postcss-value-parser').FunctionNode} |
@@ -114,3 +114,3 @@ 'use strict'; | ||
// If actual is NOT an object ... | ||
if (!isPlainObject(actual) || typeof actual !== 'object' || actual == null) { | ||
if (!isPlainObject(actual) || typeof actual !== 'object' || actual === null) { | ||
complain( | ||
@@ -117,0 +117,0 @@ `Invalid option value ${stringify(actual)} for rule "${ruleName}": should be an object`, |
{ | ||
"name": "stylelint", | ||
"version": "15.4.0", | ||
"version": "15.5.0", | ||
"description": "A mighty CSS linter that helps you avoid errors and enforce conventions.", | ||
@@ -117,3 +117,3 @@ "keywords": [ | ||
"@csstools/css-tokenizer": "^2.1.0", | ||
"@csstools/media-query-list-parser": "^2.0.1", | ||
"@csstools/media-query-list-parser": "^2.0.2", | ||
"@csstools/selector-specificity": "^2.2.0", | ||
@@ -132,3 +132,3 @@ "balanced-match": "^2.0.0", | ||
"globjoin": "^0.1.4", | ||
"html-tags": "^3.2.0", | ||
"html-tags": "^3.3.1", | ||
"ignore": "^5.2.4", | ||
@@ -184,3 +184,3 @@ "import-lazy": "^4.0.0", | ||
"deepmerge": "^4.3.1", | ||
"eslint": "^8.36.0", | ||
"eslint": "^8.38.0", | ||
"eslint-config-stylelint": "^18.0.0", | ||
@@ -192,5 +192,5 @@ "eslint-plugin-jest": "^27.2.1", | ||
"jest-watch-typeahead": "^2.2.2", | ||
"lint-staged": "^13.2.0", | ||
"lint-staged": "^13.2.1", | ||
"node-fetch": "^3.3.1", | ||
"np": "^7.6.4", | ||
"np": "^7.7.0", | ||
"npm-run-all": "^4.1.5", | ||
@@ -205,3 +205,3 @@ "patch-package": "^6.5.1", | ||
"sugarss": "^4.0.1", | ||
"typescript": "^5.0.2" | ||
"typescript": "^5.0.4" | ||
}, | ||
@@ -208,0 +208,0 @@ "engines": { |
# Stylelint | ||
[![npm version](https://img.shields.io/npm/v/stylelint)](https://www.npmjs.com/package/stylelint) | ||
[![Build Status](https://github.com/stylelint/stylelint/workflows/Testing/badge.svg)](https://github.com/stylelint/stylelint/actions/workflows/testing.yml?query=branch%3Amain) | ||
[![npm version](https://img.shields.io/npm/v/stylelint?logo=npm&logoColor=fff)](https://www.npmjs.com/package/stylelint) | ||
[![Build Status](https://img.shields.io/github/actions/workflow/status/stylelint/stylelint/testing.yml?branch=main&label=Tests&logo=github)](https://github.com/stylelint/stylelint/actions/workflows/testing.yml?query=branch%3Amain) | ||
[![npm downloads](https://img.shields.io/npm/dm/stylelint)](https://npmcharts.com/compare/stylelint?minimal=true) | ||
@@ -6,0 +6,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
1285584
589
29012
0
+ Addedcss-functions-list@3.2.2(transitive)
- Removedcss-functions-list@3.2.3(transitive)
Updatedhtml-tags@^3.3.1