fix: prevent asset conflicts between React and Grid.js versions

Add coexistence checks to all enqueue methods to prevent loading
both React and Grid.js assets simultaneously.

Changes:
- ReactAdmin.php: Only enqueue React assets when ?react=1
- Init.php: Skip Grid.js when React active on admin pages
- Form.php, Coupon.php, Access.php: Restore classic assets when ?react=0
- Customer.php, Product.php, License.php: Add coexistence checks

Now the toggle between Classic and React versions works correctly.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
dwindown
2026-04-18 17:02:14 +07:00
parent bd9cdac02e
commit e8fbfb14c1
74973 changed files with 6658406 additions and 71 deletions

91
node_modules/stylelint/lib/utils/FileCache.js generated vendored Normal file
View File

@@ -0,0 +1,91 @@
'use strict';
const debug = require('debug')('stylelint:file-cache');
const fileEntryCache = require('file-entry-cache');
const getCacheFile = require('./getCacheFile');
const hash = require('./hash');
const pkg = require('../../package.json');
const path = require('path');
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 */
class FileCache {
constructor(
cacheLocation = DEFAULT_CACHE_LOCATION,
cacheStrategy = DEFAULT_CACHE_STRATEGY,
cwd = process.cwd(),
) {
if (![CACHE_STRATEGY_METADATA, CACHE_STRATEGY_CONTENT].includes(cacheStrategy)) {
throw new Error(
`"${cacheStrategy}" cache strategy is unsupported. Specify either "${CACHE_STRATEGY_METADATA}" or "${CACHE_STRATEGY_CONTENT}"`,
);
}
const cacheFile = path.resolve(getCacheFile(cacheLocation, cwd));
const useCheckSum = cacheStrategy === CACHE_STRATEGY_CONTENT;
debug(`Cache file is created at ${cacheFile}`);
this._fileCache = fileEntryCache.create(cacheFile, undefined, useCheckSum);
this._hashOfConfig = '';
}
/**
* @param {import('stylelint').Config} config
*/
calcHashOfConfig(config) {
if (this._hashOfConfig) return;
const stylelintVersion = pkg.version;
const configString = JSON.stringify(config || {});
this._hashOfConfig = hash(`${stylelintVersion}_${configString}`);
}
/**
* @param {string} absoluteFilepath
* @return {boolean}
*/
hasFileChanged(absoluteFilepath) {
// Get file descriptor compares current metadata against cached
// one and stores the result to "changed" prop.w
const descriptor = this._fileCache.getFileDescriptor(absoluteFilepath);
/** @type {CacheMetadata} */
const meta = descriptor.meta || {};
const changed = descriptor.changed || meta.hashOfConfig !== this._hashOfConfig;
if (!changed) {
debug(`Skip linting ${absoluteFilepath}. File hasn't changed.`);
}
// Mutate file descriptor object and store config hash to each file.
// Running lint with different config should invalidate the cache.
if (meta.hashOfConfig !== this._hashOfConfig) {
meta.hashOfConfig = this._hashOfConfig;
}
return changed;
}
reconcile() {
this._fileCache.reconcile();
}
destroy() {
this._fileCache.destroy();
}
/**
* @param {string} absoluteFilepath
*/
removeEntry(absoluteFilepath) {
this._fileCache.removeEntry(absoluteFilepath);
}
}
module.exports = FileCache;

28
node_modules/stylelint/lib/utils/addEmptyLineAfter.js generated vendored Normal file
View File

@@ -0,0 +1,28 @@
'use strict';
/**
* Add an empty line after a node. Mutates the node.
*
* @template {import('postcss').Rule | import('postcss').AtRule} T
* @param {T} node
* @param {string} newline
* @returns {T}
*/
module.exports = function addEmptyLineAfter(node, newline) {
const { raws } = node;
if (typeof raws.after !== 'string') {
return node;
}
const spaces = raws.after.split(';');
const after = spaces[spaces.length - 1] || '';
if (!/\r?\n/.test(after)) {
raws.after += newline.repeat(2);
} else {
raws.after = raws.after.replace(/(\r?\n)/, `${newline}$1`);
}
return node;
};

23
node_modules/stylelint/lib/utils/addEmptyLineBefore.js generated vendored Normal file
View File

@@ -0,0 +1,23 @@
'use strict';
/**
* Add an empty line before a node. Mutates the node.
*
* @template {import('postcss').ChildNode} T
* @param {T} node
* @param {string} newline
* @returns {T}
*/
module.exports = function addEmptyLineBefore(node, newline) {
const { raws } = node;
if (typeof raws.before !== 'string') {
return node;
}
raws.before = !/\r?\n/.test(raws.before)
? newline.repeat(2) + raws.before
: raws.before.replace(/(\r?\n)/, `${newline}$1`);
return node;
};

View File

@@ -0,0 +1,11 @@
'use strict';
class AllFilesIgnoredError extends Error {
constructor() {
super();
this.message = `All input files were ignored because of the ignore pattern. Either change your input, ignore pattern or use "--allow-empty-input" to allow no inputs`;
}
}
module.exports = AllFilesIgnoredError;

16
node_modules/stylelint/lib/utils/arrayEqual.js generated vendored Normal file
View File

@@ -0,0 +1,16 @@
'use strict';
/**
* Tests if two arrays are equal.
*
* @param {unknown} a
* @param {unknown} b
* @returns {boolean}
*/
module.exports = function arrayEqual(a, b) {
if (!Array.isArray(a) || !Array.isArray(b)) return false;
if (a.length !== b.length) return false;
return a.every((elem, index) => elem === b[index]);
};

16
node_modules/stylelint/lib/utils/atRuleParamIndex.js generated vendored Normal file
View File

@@ -0,0 +1,16 @@
'use strict';
/**
* @param {import('postcss').AtRule} atRule
* @returns {number}
*/
module.exports = function atRuleParamIndex(atRule) {
// Initial 1 is for the `@`
let index = 1 + atRule.name.length;
if (atRule.raws.afterName) {
index += atRule.raws.afterName.length;
}
return index;
};

29
node_modules/stylelint/lib/utils/beforeBlockString.js generated vendored Normal file
View File

@@ -0,0 +1,29 @@
'use strict';
const { isAtRule, isRule } = require('./typeGuards');
/**
* @param {import('postcss').Container} statement
* @returns {string}
*/
module.exports = function beforeBlockString(statement, { noRawBefore } = { noRawBefore: false }) {
let result = '';
const before = statement.raws.before || '';
if (!noRawBefore) {
result += before;
}
if (isRule(statement)) {
result += statement.selector;
} else if (isAtRule(statement)) {
result += `@${statement.name}${statement.raws.afterName || ''}${statement.params}`;
} else {
return '';
}
result += statement.raws.between || '';
return result;
};

21
node_modules/stylelint/lib/utils/blockString.js generated vendored Normal file
View File

@@ -0,0 +1,21 @@
'use strict';
const beforeBlockString = require('./beforeBlockString');
const hasBlock = require('./hasBlock');
const rawNodeString = require('./rawNodeString');
/**
* Return a CSS statement's block -- the string that starts and `{` and ends with `}`.
*
* If the statement has no block (e.g. `@import url(foo.css);`), returns an empty string.
*
* @param {import('postcss').Container} statement
* @returns {string}
*/
module.exports = function blockString(statement) {
if (!hasBlock(statement)) {
return '';
}
return rawNodeString(statement).slice(beforeBlockString(statement).length);
};

10
node_modules/stylelint/lib/utils/blurComments.js generated vendored Normal file
View File

@@ -0,0 +1,10 @@
'use strict';
/**
* @param {string} source
*
* @returns {string}
*/
module.exports = function blurComments(source, blurChar = '`') {
return source.replace(/\/\*.*\*\//g, blurChar);
};

View File

@@ -0,0 +1,53 @@
'use strict';
const balancedMatch = require('balanced-match');
/**
* Replace all of the characters that are arguments to a certain
* CSS function with some innocuous character.
*
* This is useful if you need to use a RegExp to find a string
* but want to ignore matches in certain functions (e.g. `url()`,
* which might contain all kinds of false positives).
*
* For example:
* blurFunctionArguments("abc url(abc) abc", "url") === "abc url(```) abc"
*
* @param {string} source
* @param {string} functionName
* @return {string} - The result string, with the function arguments "blurred"
*/
module.exports = function blurFunctionArguments(source, functionName, blurChar = '`') {
const nameWithParen = `${functionName.toLowerCase()}(`;
const lowerCaseSource = source.toLowerCase();
if (!lowerCaseSource.includes(nameWithParen)) {
return source;
}
const functionNameLength = functionName.length;
let result = source;
let searchStartIndex = 0;
while (lowerCaseSource.includes(nameWithParen, searchStartIndex)) {
const openingParenIndex =
lowerCaseSource.indexOf(nameWithParen, searchStartIndex) + functionNameLength;
const parensMatch = balancedMatch('(', ')', lowerCaseSource.slice(openingParenIndex));
if (!parensMatch) {
throw new Error(`No parens match: "${source}"`);
}
const closingParenIndex = parensMatch.end + openingParenIndex;
const argumentsLength = closingParenIndex - openingParenIndex - 1;
result =
result.slice(0, openingParenIndex + 1) +
blurChar.repeat(argumentsLength) +
result.slice(closingParenIndex);
searchStartIndex = closingParenIndex;
}
return result;
};

10
node_modules/stylelint/lib/utils/blurInterpolation.js generated vendored Normal file
View File

@@ -0,0 +1,10 @@
'use strict';
/**
* @param {string} source
*
* @returns {string}
*/
module.exports = function blurInterpolation(source, blurChar = ' ') {
return source.replace(/[#@{}]+/g, blurChar);
};

45
node_modules/stylelint/lib/utils/checkAgainstRule.js generated vendored Normal file
View File

@@ -0,0 +1,45 @@
'use strict';
const normalizeRuleSettings = require('../normalizeRuleSettings');
const Result = require('postcss/lib/result');
const { isPlainObject } = require('./validateTypes');
const getStylelintRule = require('./getStylelintRule');
/**
* Useful for third-party code (e.g. plugins) to run a PostCSS Root
* against a specific rule and do something with the warnings
*
* @type {typeof import('stylelint').utils.checkAgainstRule}
*/
function checkAgainstRule(options, callback) {
if (!isPlainObject(options)) throw new Error('Expected an options object');
if (!callback) throw new Error('Expected a callback function');
const { ruleName, ruleSettings, root, result, context = {} } = options;
if (!ruleName) throw new Error('Expected a "ruleName" option');
const rule = getStylelintRule(ruleName, result && result.stylelint.config);
if (!rule) throw new Error(`Rule "${ruleName}" does not exist`);
if (!ruleSettings) throw new Error('Expected a "ruleSettings" option');
if (!root) throw new Error('Expected a "root" option');
const settings = normalizeRuleSettings(ruleSettings, rule);
if (!settings) {
return;
}
// @ts-expect-error - this error should not occur with PostCSS 8
const tmpPostcssResult = new Result();
rule(settings[0], /** @type {Object} */ (settings[1]), context)(root, tmpPostcssResult);
for (const warning of tmpPostcssResult.warnings()) callback(warning);
}
module.exports = checkAgainstRule;

View File

@@ -0,0 +1,104 @@
'use strict';
const EOL = require('os').EOL;
const levenshtein = require('fastest-levenshtein');
const { red, cyan } = require('picocolors');
/**
* @param {{ [key: string]: { alias?: string } }} allowedOptions
* @return {string[]}
*/
const buildAllowedOptions = (allowedOptions) => {
const options = Object.keys(allowedOptions);
for (const { alias } of Object.values(allowedOptions)) {
if (alias) {
options.push(alias);
}
}
options.sort();
return options;
};
/**
* @param {string[]} all
* @param {string} invalid
* @return {null|string}
*/
const suggest = (all, invalid) => {
const maxThreshold = 10;
for (let threshold = 1; threshold <= maxThreshold; threshold++) {
const suggestion = all.find((option) => levenshtein.distance(option, invalid) <= threshold);
if (suggestion) {
return suggestion;
}
}
return null;
};
/**
* Converts a string to kebab case.
* For example, `kebabCase('oneTwoThree') === 'one-two-three'`.
* @param {string} opt
* @returns {string}
*/
const kebabCase = (opt) => {
const matches = opt.match(/[A-Z]?[a-z]+|[A-Z]|[0-9]+/g);
if (matches) {
return matches.map((s) => s.toLowerCase()).join('-');
}
return '';
};
/**
* @param {string} opt
* @return {string}
*/
const cliOption = (opt) => {
if (opt.length === 1) {
return `"-${opt}"`;
}
return `"--${kebabCase(opt)}"`;
};
/**
* @param {string} invalid
* @param {string|null} suggestion
* @return {string}
*/
const buildMessageLine = (invalid, suggestion) => {
let line = `Invalid option ${red(cliOption(invalid))}.`;
if (suggestion) {
line += ` Did you mean ${cyan(cliOption(suggestion))}?`;
}
return line + EOL;
};
/**
* @param {{ [key: string]: any }} allowedOptions
* @param {{ [key: string]: any }} inputOptions
* @return {string}
*/
module.exports = function checkInvalidCLIOptions(allowedOptions, inputOptions) {
const allOptions = buildAllowedOptions(allowedOptions);
return Object.keys(inputOptions)
.filter((opt) => !allOptions.includes(opt))
.map((opt) => kebabCase(opt))
.reduce((msg, invalid) => {
// NOTE: No suggestion for shortcut options because it's too difficult
const suggestion = invalid.length >= 2 ? suggest(allOptions, invalid) : null;
return msg + buildMessageLine(invalid, suggestion);
}, '');
};

16
node_modules/stylelint/lib/utils/configurationError.js generated vendored Normal file
View File

@@ -0,0 +1,16 @@
'use strict';
/** @typedef {import('stylelint').ConfigurationError} ConfigurationError */
/**
* Create configurationError from text and set CLI exit code
* @param {string} text
* @returns {ConfigurationError}
*/
module.exports = function configurationError(text) {
const err = /** @type {ConfigurationError} */ (new Error(text));
err.code = 78;
return err;
};

54
node_modules/stylelint/lib/utils/containsString.js generated vendored Normal file
View File

@@ -0,0 +1,54 @@
'use strict';
const { isString } = require('./validateTypes');
/** @typedef {false | { match: string, pattern: string, substring: string }} ReturnValue */
/**
* Checks if a string contains a value. The comparison value can be a string or
* an array of strings.
*
* Any strings starting and ending with `/` are ignored. Use the
* matchesStringOrRegExp() util to match regexes.
*
* @template {unknown} T
* @param {string} input
* @param {T | T[]} comparison
* @returns {ReturnValue}
*/
module.exports = function containsString(input, comparison) {
if (!Array.isArray(comparison)) {
return testAgainstString(input, comparison);
}
for (const comparisonItem of comparison) {
const testResult = testAgainstString(input, comparisonItem);
if (testResult) {
return testResult;
}
}
return false;
};
/**
* @param {string} value
* @param {unknown} comparison
* @returns {ReturnValue}
*/
function testAgainstString(value, comparison) {
if (!comparison) return false;
if (!isString(comparison)) return false;
if (comparison.startsWith('/') && comparison.endsWith('/')) {
return false;
}
if (value.includes(comparison)) {
return { match: value, pattern: comparison, substring: comparison };
}
return false;
}

View File

@@ -0,0 +1,29 @@
'use strict';
/**
* Get the index of a declaration's value
*
* @param {import('postcss').Declaration} decl
* @returns {number}
*/
module.exports = function declarationValueIndex(decl) {
const raws = decl.raws;
return [
// @ts-expect-error -- TS2571: Object is of type 'unknown'.
raws.prop && raws.prop.prefix,
// @ts-expect-error -- TS2571: Object is of type 'unknown'.
(raws.prop && raws.prop.raw) || decl.prop,
// @ts-expect-error -- TS2571: Object is of type 'unknown'.
raws.prop && raws.prop.suffix,
raws.between || ':',
// @ts-expect-error -- TS2339: Property 'prefix' does not exist on type '{ value: string; raw: string; }'.
raws.value && raws.value.prefix,
].reduce((count, str) => {
if (str) {
return count + str.length;
}
return count;
}, 0);
};

View File

@@ -0,0 +1,61 @@
'use strict';
const { isRoot, isAtRule, isRule } = require('./typeGuards');
/** @typedef {import('postcss').Root} Root */
/** @typedef {import('postcss').Root} Document */
/** @typedef {import('postcss').Node} PostcssNode */
/** @typedef {import('postcss').Container} PostcssContainerNode */
/** @typedef {import('postcss').Declaration} Declaration */
/** @typedef {(callbackFn: (decl: Declaration, index: number, decls: Declaration[]) => void) => void} EachDeclaration */
/**
* @param {PostcssNode} node
* @returns {node is PostcssContainerNode}
*/
function isContainerNode(node) {
return isRule(node) || isAtRule(node) || isRoot(node);
}
/**
* In order to accommodate nested blocks (postcss-nested),
* we need to run a shallow loop (instead of eachDecl() or eachRule(),
* which loop recursively) and allow each nested block to accumulate
* its own list of properties -- so that a property in a nested rule
* does not conflict with the same property in the parent rule
* executes a provided function once for each declaration block.
*
* @param {Root | Document} root - root element of file.
* @param {(eachDecl: EachDeclaration) => void} callback - Function to execute for each declaration block
*
* @returns {void}
*/
module.exports = function eachDeclarationBlock(root, callback) {
/**
* @param {PostcssNode} statement
*
* @returns {void}
*/
function each(statement) {
if (!isContainerNode(statement)) return;
if (statement.nodes && statement.nodes.length) {
/** @type {Declaration[]} */
const decls = [];
for (const node of statement.nodes) {
if (node.type === 'decl') {
decls.push(node);
}
each(node);
}
if (decls.length) {
callback(decls.forEach.bind(decls));
}
}
}
each(root);
};

19
node_modules/stylelint/lib/utils/filterFilePaths.js generated vendored Normal file
View File

@@ -0,0 +1,19 @@
'use strict';
const { isPathValid } = require('ignore').default;
/**
* @param {import('ignore').Ignore} ignorer
* @param {string[]} filePaths
* @returns {string[]}
*/
module.exports = function filterFilePaths(ignorer, filePaths) {
const validForIgnore = filePaths.filter(isPathValid);
// Paths which starts with `..` are not valid for `ignore`, e. g. `../style.css`
const notValidForIgnore = new Set(filePaths.filter((p) => !validForIgnore.includes(p)));
const filteredByIgnore = new Set(ignorer.filter(validForIgnore));
// Preserving files order, while removing paths which were filtered by `ignore`
return filePaths.filter((p) => notValidForIgnore.has(p) || filteredByIgnore.has(p));
};

75
node_modules/stylelint/lib/utils/findAnimationName.js generated vendored Normal file
View File

@@ -0,0 +1,75 @@
'use strict';
const getDimension = require('./getDimension');
const isStandardSyntaxValue = require('./isStandardSyntaxValue');
const isVariable = require('./isVariable');
const { animationShorthandKeywords, basicKeywords } = require('../reference/keywords');
const postcssValueParser = require('postcss-value-parser');
/** @typedef {import('postcss-value-parser').Node} Node */
/**
* Get the animation name within an `animation` shorthand property value.
*
* @param {string} value
*
* @returns {Node[]}
*/
module.exports = function findAnimationName(value) {
/** @type {Node[]} */
const animationNames = [];
const valueNodes = postcssValueParser(value);
const { nodes } = valueNodes;
// Handle `inherit`, `initial` and etc
if (nodes.length === 1 && nodes[0] && basicKeywords.has(nodes[0].value.toLowerCase())) {
return [nodes[0]];
}
let shouldBeIgnored = false;
valueNodes.walk((valueNode) => {
if (shouldBeIgnored) return;
if (valueNode.type === 'function') {
return false;
}
if (valueNode.type !== 'word') {
return;
}
const valueLowerCase = valueNode.value.toLowerCase();
// Ignore non-standard syntax
if (!isStandardSyntaxValue(valueLowerCase)) {
// Cannot find animation name if shorthand has non-standard syntax value (#5532)
shouldBeIgnored = true;
animationNames.length = 0; // clears animationNames
return;
}
// Ignore variables
if (isVariable(valueLowerCase)) {
return;
}
// Ignore keywords for other animation parts
if (animationShorthandKeywords.has(valueLowerCase)) {
return;
}
// Ignore numbers with units
const { unit } = getDimension(valueNode);
if (unit || unit === '') {
return;
}
animationNames.push(valueNode);
});
return animationNames;
};

29
node_modules/stylelint/lib/utils/findAtRuleContext.js generated vendored Normal file
View File

@@ -0,0 +1,29 @@
'use strict';
const { isAtRule, isRule } = require('./typeGuards');
/**
* Find the at-rule in which a rule is nested.
*
* Returns `null` if the rule is not nested within an at-rule.
*
* @param {import('postcss').Rule} rule
* @returns {null | import('postcss').AtRule}
*/
module.exports = function findAtRuleContext(rule) {
const parent = rule.parent;
if (!parent) {
return null;
}
if (isAtRule(parent)) {
return parent;
}
if (isRule(parent)) {
return findAtRuleContext(parent);
}
return null;
};

130
node_modules/stylelint/lib/utils/findFontFamily.js generated vendored Normal file
View File

@@ -0,0 +1,130 @@
'use strict';
const postcssValueParser = require('postcss-value-parser');
const isNumbery = require('./isNumbery');
const isStandardSyntaxValue = require('./isStandardSyntaxValue');
const isValidFontSize = require('./isValidFontSize');
const isVariable = require('./isVariable');
const { assert } = require('./validateTypes');
const {
basicKeywords,
fontFamilyKeywords,
fontShorthandKeywords,
} = require('../reference/keywords');
const nodeTypesToCheck = new Set(['word', 'string', 'space', 'div']);
/** @typedef {import('postcss-value-parser').Node} Node */
/**
*
* @param {Node} firstNode
* @param {Node} secondNode
* @param {string | null} charactersBetween
*
* @returns {Node}
*/
function joinValueNodes(firstNode, secondNode, charactersBetween) {
firstNode.value = firstNode.value + charactersBetween + secondNode.value;
return firstNode;
}
/**
* Get the font-families within a `font` shorthand property value.
*
* @param {string} value
* @returns {Node[]} Collection font-family nodes
*/
module.exports = function findFontFamily(value) {
/** @type {Node[]} */
const fontFamilies = [];
const valueNodes = postcssValueParser(value);
const { nodes: children } = valueNodes;
// Handle `inherit`, `initial` and etc
if (children.length === 1 && children[0] && basicKeywords.has(children[0].value.toLowerCase())) {
return [children[0]];
}
let needMergeNodesByValue = false;
/** @type {string | null} */
let mergeCharacters = null;
valueNodes.walk((valueNode, index, nodes) => {
if (valueNode.type === 'function') {
return false;
}
if (!nodeTypesToCheck.has(valueNode.type)) {
return;
}
const valueLowerCase = valueNode.value.toLowerCase();
// Ignore non standard syntax
if (!isStandardSyntaxValue(valueLowerCase)) {
return;
}
// Ignore variables
if (isVariable(valueLowerCase)) {
return;
}
// Ignore keywords for other font parts
if (fontShorthandKeywords.has(valueLowerCase) && !fontFamilyKeywords.has(valueLowerCase)) {
return;
}
// Ignore font-sizes
if (isValidFontSize(valueNode.value)) {
return;
}
const prevNode = nodes[index - 1];
const prevPrevNode = nodes[index - 2];
// Ignore anything come after a <font-size>/, because it's a line-height
if (prevNode && prevNode.value === '/' && prevPrevNode && isValidFontSize(prevPrevNode.value)) {
return;
}
// Ignore number values
if (isNumbery(valueLowerCase)) {
return;
}
// Detect when a space or comma is dividing a list of font-families, and save the joining character.
if (
(valueNode.type === 'space' || (valueNode.type === 'div' && valueNode.value !== ',')) &&
fontFamilies.length !== 0
) {
needMergeNodesByValue = true;
mergeCharacters = valueNode.value;
return;
}
if (valueNode.type === 'space' || valueNode.type === 'div') {
return;
}
const fontFamily = valueNode;
if (needMergeNodesByValue) {
const lastFontFamily = fontFamilies[fontFamilies.length - 1];
assert(lastFontFamily);
joinValueNodes(lastFontFamily, fontFamily, mergeCharacters);
needMergeNodesByValue = false;
mergeCharacters = null;
} else {
fontFamilies.push(fontFamily);
}
});
return fontFamilies;
};

62
node_modules/stylelint/lib/utils/findListStyleType.js generated vendored Normal file
View File

@@ -0,0 +1,62 @@
'use strict';
const isStandardSyntaxValue = require('./isStandardSyntaxValue');
const isVariable = require('./isVariable');
const {
listStyleImageKeywords,
listStylePositionKeywords,
listStyleTypeKeywords,
} = require('../reference/keywords');
const postcssValueParser = require('postcss-value-parser');
/**
* Get the list-style-type within a `list-style` shorthand property value.
*
* @param {string} value
*/
module.exports = function findListStyleType(value) {
/** @type {Array<import('postcss-value-parser').WordNode>} */
const listStyleTypes = [];
const valueNodes = postcssValueParser(value);
const { nodes } = valueNodes;
// Handle `inherit`, `initial` and etc
if (nodes.length === 1 && nodes[0] && listStyleTypeKeywords.has(nodes[0].value.toLowerCase())) {
return [nodes[0]];
}
valueNodes.walk((valueNode) => {
if (valueNode.type === 'function') {
return false;
}
if (valueNode.type !== 'word') {
return;
}
const valueLowerCase = valueNode.value.toLowerCase();
// Ignore non standard syntax
if (!isStandardSyntaxValue(valueLowerCase)) {
return;
}
// Ignore variables
if (isVariable(valueLowerCase)) {
return;
}
// Ignore keywords for other font parts
if (
listStylePositionKeywords.has(valueLowerCase) ||
listStyleImageKeywords.has(valueLowerCase)
) {
return;
}
listStyleTypes.push(valueNode);
});
return listStyleTypes;
};

16
node_modules/stylelint/lib/utils/flattenArray.js generated vendored Normal file
View File

@@ -0,0 +1,16 @@
'use strict';
/**
* Convert the specified value to an array. If an array is specified, the array is returned as-is.
*
* @template T
* @param {T | T[] | undefined | null} value
* @returns {T[] | undefined}
*/
module.exports = function flattenArray(value) {
if (value == null) {
return;
}
return Array.isArray(value) ? value : [value];
};

View File

@@ -0,0 +1,43 @@
'use strict';
const balancedMatch = require('balanced-match');
const valueParser = require('postcss-value-parser');
const { assert, isString, isRegExp } = require('./validateTypes');
/**
* Search a CSS string for functions by name.
* For every match, invoke the callback, passing the function's
* "argument(s) string" (whatever is inside the parentheses)
* as an argument.
*
* Callback will be called once for every matching function found,
* with the function's "argument(s) string" and its starting index
* as the arguments.
*
* @param {string} source
* @param {string | RegExp} functionName
* @param {(expression: string, expressionIndex: number) => void} callback
* @returns {void}
*/
module.exports = function functionArgumentsSearch(source, functionName, callback) {
valueParser(source).walk((node) => {
if (node.type !== 'function') return;
const { value } = node;
if (isString(functionName) && value !== functionName) return;
if (isRegExp(functionName) && !functionName.test(node.value)) return;
const parensMatch = balancedMatch('(', ')', source.slice(node.sourceIndex));
assert(parensMatch);
const expression = parensMatch.body;
const parenLength = 1; // == '('
const expressionIndex = node.sourceIndex + value.length + parenLength;
callback(expression, expressionIndex);
});
};

11
node_modules/stylelint/lib/utils/getAtRuleParams.js generated vendored Normal file
View File

@@ -0,0 +1,11 @@
'use strict';
/**
* @param {import('postcss').AtRule} atRule
* @returns {string}
*/
module.exports = function getAtRuleParams(atRule) {
const raws = atRule.raws;
return (raws.params && raws.params.raw) || atRule.params;
};

52
node_modules/stylelint/lib/utils/getCacheFile.js generated vendored Normal file
View File

@@ -0,0 +1,52 @@
'use strict';
const fs = require('fs');
const hash = require('./hash');
const path = require('path');
/**
* Return the cacheFile to be used by stylelint, based on whether the provided parameter is
* a directory or looks like a directory (ends in `path.sep`), in which case the file
* name will be `cacheFile/.cache_hashOfCWD`.
*
* If cacheFile points to a file or looks like a file, then it will just use that file.
*
* @param {string} cacheFile - The name of file to be used to store the cache
* @param {string} cwd - Current working directory. Used for tests
* @returns {string} Resolved path to the cache file
*/
module.exports = function getCacheFile(cacheFile, cwd) {
/*
* Make sure path separators are normalized for environment/os.
* Also, keep trailing path separator if present.
*/
cacheFile = path.normalize(cacheFile);
const resolvedCacheFile = path.resolve(cwd, cacheFile);
// If the last character passed is a path separator, we assume is a directory.
const looksLikeADirectory = cacheFile[cacheFile.length - 1] === path.sep;
/**
* Return the default cache file name when provided parameter is a directory.
* @returns {string} - Resolved path to the cacheFile
*/
function getCacheFileForDirectory() {
return path.join(resolvedCacheFile, `.stylelintcache_${hash(cwd)}`);
}
let fileStats;
try {
fileStats = fs.lstatSync(resolvedCacheFile);
} catch {
fileStats = null;
}
if (looksLikeADirectory || (fileStats && fileStats.isDirectory())) {
// Return path to provided directory with generated file name.
return getCacheFileForDirectory();
}
// Return normalized path to cache file.
return resolvedCacheFile;
};

View File

@@ -0,0 +1,11 @@
'use strict';
/**
* @param {import('postcss').Declaration} decl
* @returns {string}
*/
module.exports = function getDeclarationValue(decl) {
const raws = decl.raws;
return (raws.value && raws.value.raw) || decl.value;
};

63
node_modules/stylelint/lib/utils/getDimension.js generated vendored Normal file
View File

@@ -0,0 +1,63 @@
'use strict';
const blurInterpolation = require('./blurInterpolation');
const isStandardSyntaxValue = require('./isStandardSyntaxValue');
const valueParser = require('postcss-value-parser');
/**
* Get Dimension from value node;
* `unit` and `number` return null if neither is found
*
* @param {import('postcss-value-parser').Node} node
*
* @returns {{unit: null, number: null} | valueParser.Dimension}
*/
module.exports = function getDimension(node) {
if (!node || !node.value) {
return {
unit: null,
number: null,
};
}
// Ignore non-word nodes
if (node.type !== 'word') {
return {
unit: null,
number: null,
};
}
// Ignore non standard syntax
if (!isStandardSyntaxValue(node.value)) {
return {
unit: null,
number: null,
};
}
// Ignore HEX
if (node.value.startsWith('#')) {
return {
unit: null,
number: null,
};
}
// Remove non standard stuff
const value = blurInterpolation(node.value, '')
// ignore hack unit
.replace('\\0', '')
.replace('\\9', '');
const parsedUnit = valueParser.unit(value);
if (!parsedUnit) {
return {
unit: null,
number: null,
};
}
return parsedUnit;
};

43
node_modules/stylelint/lib/utils/getFileIgnorer.js generated vendored Normal file
View File

@@ -0,0 +1,43 @@
'use strict';
// Try to get file ignorer from '.stylelintignore'
const fs = require('fs');
const path = require('path');
const { default: ignore } = require('ignore');
const isPathNotFoundError = require('./isPathNotFoundError');
const DEFAULT_IGNORE_FILENAME = '.stylelintignore';
/**
* @param {{ cwd: string, ignorePath?: string | string[], ignorePattern?: string[] }} options
* @return {import('ignore').Ignore}
*/
module.exports = function getFileIgnorer(options) {
const ignorer = ignore();
const ignorePaths = [options.ignorePath || []].flat();
if (ignorePaths.length === 0) {
ignorePaths.push(DEFAULT_IGNORE_FILENAME);
}
for (const ignoreFilePath of ignorePaths) {
const absoluteIgnoreFilePath = path.isAbsolute(ignoreFilePath)
? ignoreFilePath
: path.resolve(options.cwd, ignoreFilePath);
try {
const ignoreText = fs.readFileSync(absoluteIgnoreFilePath, 'utf8');
ignorer.add(ignoreText);
} catch (readError) {
if (!isPathNotFoundError(readError)) {
throw readError;
}
}
}
ignorer.add(options.ignorePattern || []);
return ignorer;
};

View File

@@ -0,0 +1,19 @@
'use strict';
const formatters = require('../formatters');
/**
* @param {{ useOr?: boolean }} [options={}]
* @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;
};

View File

@@ -0,0 +1,17 @@
'use strict';
/**
* Returns a position of `!important` (or `! important` including whitespaces)
* from the specified CSS source code. If not found, returns `undefined`.
*
* @param {string} source
* @returns {{ index: number, endIndex: number } | undefined}
*/
module.exports = function getImportantPosition(source) {
const pattern = /!\s*important\b/gi;
const match = pattern.exec(source);
if (!match) return;
return { index: match.index, endIndex: pattern.lastIndex };
};

34
node_modules/stylelint/lib/utils/getModulePath.js generated vendored Normal file
View File

@@ -0,0 +1,34 @@
'use strict';
const configurationError = require('./configurationError');
const globalModules = require('global-modules');
const resolveFrom = require('resolve-from');
/**
* @param {string} basedir
* @param {string} lookup
* @param {string} [cwd]
* @return {string}
*/
module.exports = function getModulePath(basedir, lookup, cwd = process.cwd()) {
// 1. Try to resolve from the provided directory
// 2. Try to resolve from `cwd` or `process.cwd()`
// 3. Try to resolve from global `node_modules` directory
let path = resolveFrom.silent(basedir, lookup);
if (!path) {
path = resolveFrom.silent(cwd, lookup);
}
if (!path) {
path = resolveFrom.silent(globalModules, lookup);
}
if (!path) {
throw configurationError(
`Could not find "${lookup}". Do you need the "configBasedir" or "--config-basedir" option?`,
);
}
return path;
};

View File

@@ -0,0 +1,36 @@
'use strict';
/** @typedef {import('postcss').Node} Node */
/**
* @param {Node | void} node
*/
function getNodeLine(node) {
return node && node.source && node.source.start && node.source.start.line;
}
/**
* @param {Node | void} node
* @returns {Node | void}
*/
module.exports = function getNextNonSharedLineCommentNode(node) {
if (node === undefined) {
return undefined;
}
/** @type {Node | void} */
const nextNode = node.next();
if (!nextNode || nextNode.type !== 'comment') {
return nextNode;
}
if (
getNodeLine(node) === getNodeLine(nextNode) ||
getNodeLine(nextNode) === getNodeLine(nextNode.next())
) {
return getNextNonSharedLineCommentNode(nextNode);
}
return nextNode;
};

11
node_modules/stylelint/lib/utils/getOsEol.js generated vendored Normal file
View File

@@ -0,0 +1,11 @@
'use strict';
const os = require('os');
// This function simply provides roundabout way of getting os.EOL
// so we can mock this for Jest tests
function getOsEl() {
return os.EOL;
}
module.exports = getOsEl;

View File

@@ -0,0 +1,38 @@
'use strict';
/** @typedef {import('postcss').Node} Node */
/**
* @param {Node} node
*/
function getNodeLine(node) {
return node.source && node.source.start && node.source.start.line;
}
/**
* @param {Node | undefined} node
* @returns {Node | undefined}
*/
module.exports = function getPreviousNonSharedLineCommentNode(node) {
if (node === undefined) {
return undefined;
}
const previousNode = node.prev();
if (!previousNode || previousNode.type !== 'comment') {
return previousNode;
}
if (getNodeLine(node) === getNodeLine(previousNode)) {
return getPreviousNonSharedLineCommentNode(previousNode);
}
const previousNode2 = previousNode.prev();
if (previousNode2 && getNodeLine(previousNode) === getNodeLine(previousNode2)) {
return getPreviousNonSharedLineCommentNode(previousNode);
}
return previousNode;
};

11
node_modules/stylelint/lib/utils/getRuleSelector.js generated vendored Normal file
View File

@@ -0,0 +1,11 @@
'use strict';
/**
* @param {import('postcss').Rule} ruleNode
* @returns {string}
*/
module.exports = function getRuleSelector(ruleNode) {
const raws = ruleNode.raws;
return (raws.selector && raws.selector.raw) || ruleNode.selector;
};

39
node_modules/stylelint/lib/utils/getSchemeFromUrl.js generated vendored Normal file
View File

@@ -0,0 +1,39 @@
'use strict';
const { URL } = require('url');
/**
* Get unit from value node
*
* Returns `null` if the unit is not found.
*
* @param {string} urlString
*/
module.exports = function getSchemeFromUrl(urlString) {
let protocol = null;
try {
protocol = new URL(urlString).protocol;
} catch {
return null;
}
if (protocol === null || typeof protocol === 'undefined') {
return null;
}
const scheme = protocol.slice(0, -1); // strip trailing `:`
// The URL spec does not require a scheme to be followed by `//`, but checking
// for it allows this rule to differentiate <scheme>:<hostname> urls from
// <hostname>:<port> urls. `data:` scheme urls are an exception to this rule.
const slashIndex = protocol.length;
const expectedSlashes = urlString.slice(slashIndex, slashIndex + 2);
const isSchemeLessUrl = expectedSlashes !== '//' && scheme !== 'data';
if (isSchemeLessUrl) {
return null;
}
return scheme;
};

15
node_modules/stylelint/lib/utils/getStdin.js generated vendored Normal file
View File

@@ -0,0 +1,15 @@
'use strict';
/**
* @param {NodeJS.ReadStream} [stdin]
* @returns {Promise<string>}
*/
module.exports = async function getStdin(stdin = process.stdin) {
const chunks = [];
for await (const chunk of stdin) {
chunks.push(chunk);
}
return Buffer.concat(chunks).toString();
};

10
node_modules/stylelint/lib/utils/getStylelintRule.js generated vendored Normal file
View File

@@ -0,0 +1,10 @@
const rules = require('../rules');
/**
* @param {string} ruleName
* @param {import('stylelint').Config | undefined} [config]
* @returns {import('stylelint').Rule | undefined}
*/
module.exports = function getStylelintRule(ruleName, config) {
return rules[ruleName] || (config && config.pluginFunctions && config.pluginFunctions[ruleName]);
};

11
node_modules/stylelint/lib/utils/hasBlock.js generated vendored Normal file
View File

@@ -0,0 +1,11 @@
'use strict';
/**
* Check if a statement has an block (empty or otherwise).
*
* @param {import('postcss').Container} statement
* @return {boolean} True if `statement` has a block (empty or otherwise)
*/
module.exports = function hasBlock(statement) {
return statement.nodes !== undefined;
};

13
node_modules/stylelint/lib/utils/hasEmptyBlock.js generated vendored Normal file
View File

@@ -0,0 +1,13 @@
'use strict';
const hasBlock = require('./hasBlock');
/**
* Check if a statement has an empty block.
*
* @param {import('postcss').Rule | import('postcss').AtRule} statement - postcss rule or at-rule node
* @return {boolean} True if the statement has a block and it is empty
*/
module.exports = function hasEmptyBlock(statement) {
return hasBlock(statement) && statement.nodes.length === 0;
};

13
node_modules/stylelint/lib/utils/hasEmptyLine.js generated vendored Normal file
View File

@@ -0,0 +1,13 @@
'use strict';
/**
* Check if a string contains at least one empty line
*
* @param {string | undefined} string
* @returns {boolean}
*/
module.exports = function hasEmptyLine(string) {
if (string === '' || string === undefined) return false;
return /\n[\r\t ]*\n/.test(string);
};

26
node_modules/stylelint/lib/utils/hasInterpolation.js generated vendored Normal file
View File

@@ -0,0 +1,26 @@
'use strict';
const hasLessInterpolation = require('../utils/hasLessInterpolation');
const hasPsvInterpolation = require('../utils/hasPsvInterpolation');
const hasScssInterpolation = require('../utils/hasScssInterpolation');
const hasTplInterpolation = require('../utils/hasTplInterpolation');
/**
* Check whether a string has interpolation
*
* @param {string} string
* @return {boolean} If `true`, a string has interpolation
*/
module.exports = function hasInterpolation(string) {
// SCSS or Less interpolation
if (
hasLessInterpolation(string) ||
hasScssInterpolation(string) ||
hasTplInterpolation(string) ||
hasPsvInterpolation(string)
) {
return true;
}
return false;
};

View File

@@ -0,0 +1,11 @@
'use strict';
/**
* Check whether a string has less interpolation
*
* @param {string} string
* @return {boolean} If `true`, a string has less interpolation
*/
module.exports = function hasLessInterpolation(string) {
return /@\{.+?\}/.test(string);
};

View File

@@ -0,0 +1,10 @@
'use strict';
/**
* Check whether a string has postcss-simple-vars interpolation
*
* @param {string} string
*/
module.exports = function hasPsvInterpolation(string) {
return /\$\(.+?\)/.test(string);
};

View File

@@ -0,0 +1,10 @@
'use strict';
/**
* Check whether a string has scss interpolation
*
* @param {string} string
*/
module.exports = function hasScssInterpolation(string) {
return /#\{.+?\}/.test(string);
};

View File

@@ -0,0 +1,11 @@
'use strict';
/**
* Check whether a string has JS template literal interpolation or HTML-like template
*
* @param {string} string
* @return {boolean} If `true`, a string has template literal interpolation
*/
module.exports = function hasTplInterpolation(string) {
return /\{.+?\}/.test(string);
};

12
node_modules/stylelint/lib/utils/hash.js generated vendored Normal file
View File

@@ -0,0 +1,12 @@
'use strict';
const murmur = require('imurmurhash');
/**
* hash the given string
* @param {string} str the string to hash
* @returns {string} the hash
*/
module.exports = function hash(str) {
return murmur(str).result().toString(36);
};

16
node_modules/stylelint/lib/utils/isAfterComment.js generated vendored Normal file
View File

@@ -0,0 +1,16 @@
'use strict';
const isSharedLineComment = require('./isSharedLineComment');
/**
* @param {import('postcss').Node} node
*/
module.exports = function isAfterComment(node) {
const previousNode = node.prev();
if (!previousNode || previousNode.type !== 'comment') {
return false;
}
return !isSharedLineComment(previousNode);
};

View File

@@ -0,0 +1,22 @@
'use strict';
const isSharedLineComment = require('./isSharedLineComment');
/**
* @param {import('postcss').Node} node
*/
function isAfterSingleLineComment(node) {
const prevNode = node.prev();
return (
prevNode !== undefined &&
prevNode.type === 'comment' &&
!isSharedLineComment(prevNode) &&
prevNode.source &&
prevNode.source.start &&
prevNode.source.end &&
prevNode.source.start.line === prevNode.source.end.line
);
}
module.exports = isAfterSingleLineComment;

View File

@@ -0,0 +1,20 @@
'use strict';
const getPreviousNonSharedLineCommentNode = require('./getPreviousNonSharedLineCommentNode');
const isCustomProperty = require('./isCustomProperty');
const isStandardSyntaxDeclaration = require('./isStandardSyntaxDeclaration');
const { isDeclaration } = require('./typeGuards');
/**
* @param {import('postcss').Node} node
*/
module.exports = function isAfterStandardPropertyDeclaration(node) {
const prevNode = getPreviousNonSharedLineCommentNode(node);
return (
prevNode !== undefined &&
isDeclaration(prevNode) &&
isStandardSyntaxDeclaration(prevNode) &&
!isCustomProperty(prevNode.prop || '')
);
};

339
node_modules/stylelint/lib/utils/isAutoprefixable.js generated vendored Normal file
View File

@@ -0,0 +1,339 @@
'use strict';
const vendor = require('./vendor');
/**
* Extract each list using the internal API of Autoprefixer 10.2.5.
*
* @see https://github.com/postcss/autoprefixer/tree/10.2.5
*
* @example
* const autoprefixer = require('autoprefixer');
* const Browsers = require('autoprefixer/lib/browsers');
* const Prefixes = require('autoprefixer/lib/prefixes');
* const utils = require('autoprefixer/lib/utils');
*
* const prefixes = new Prefixes(autoprefixer.data.prefixes, new Browsers(autoprefixer.data.browsers, []));
*/
/**
* @example
* Object.keys(prefixes.remove).filter((s) => s.startsWith('@'));
*/
const AT_RULES = new Set([
'@-khtml-keyframes',
'@-moz-keyframes',
'@-ms-keyframes',
'@-ms-viewport',
'@-o-keyframes',
'@-o-viewport',
'@-webkit-keyframes',
'@resolution',
]);
/**
* @example
* prefixes.remove.selectors.map((s) => s.prefixed);
*/
const SELECTORS = new Set([
':-moz-any-link',
':-moz-full-screen',
':-moz-placeholder',
':-moz-placeholder-shown',
':-moz-read-only',
':-moz-read-write',
':-ms-fullscreen',
':-ms-input-placeholder',
':-webkit-any-link',
':-webkit-full-screen',
'::-moz-placeholder',
'::-moz-selection',
'::-ms-input-placeholder',
'::-webkit-backdrop',
'::-webkit-input-placeholder',
]);
/**
* @example
* Object.entries(autoprefixer.data.prefixes)
* .filter(([key, value]) => !value.selector && !value.props && !key.startsWith('@'))
* .map(([key, value]) => key);
*/
const PROPERTIES = new Set([
'align-content',
'align-items',
'align-self',
'animation',
'animation-delay',
'animation-direction',
'animation-duration',
'animation-fill-mode',
'animation-iteration-count',
'animation-name',
'animation-play-state',
'animation-timing-function',
'appearance',
'backdrop-filter',
'backface-visibility',
'background-clip',
'background-origin',
'background-size',
'border-block-end',
'border-block-start',
'border-bottom-left-radius',
'border-bottom-right-radius',
'border-image',
'border-inline-end',
'border-inline-start',
'border-radius',
'border-top-left-radius',
'border-top-right-radius',
'box-decoration-break',
'box-shadow',
'box-sizing',
'break-after',
'break-before',
'break-inside',
'clip-path',
'color-adjust',
'column-count',
'column-fill',
'column-gap',
'column-rule',
'column-rule-color',
'column-rule-style',
'column-rule-width',
'column-span',
'column-width',
'columns',
'filter',
'flex',
'flex-basis',
'flex-direction',
'flex-flow',
'flex-grow',
'flex-shrink',
'flex-wrap',
'flow-from',
'flow-into',
'font-feature-settings',
'font-kerning',
'font-language-override',
'font-variant-ligatures',
'grid-area',
'grid-column',
'grid-column-align',
'grid-column-end',
'grid-column-start',
'grid-row',
'grid-row-align',
'grid-row-end',
'grid-row-start',
'grid-template',
'grid-template-areas',
'grid-template-columns',
'grid-template-rows',
'hyphens',
'image-rendering',
'justify-content',
'margin-block-end',
'margin-block-start',
'margin-inline-end',
'margin-inline-start',
'mask',
'mask-border',
'mask-border-outset',
'mask-border-repeat',
'mask-border-slice',
'mask-border-source',
'mask-border-width',
'mask-clip',
'mask-composite',
'mask-image',
'mask-origin',
'mask-position',
'mask-repeat',
'mask-size',
'object-fit',
'object-position',
'order',
'overscroll-behavior',
'padding-block-end',
'padding-block-start',
'padding-inline-end',
'padding-inline-start',
'perspective',
'perspective-origin',
'place-self',
'region-fragment',
'scroll-snap-coordinate',
'scroll-snap-destination',
'scroll-snap-points-x',
'scroll-snap-points-y',
'scroll-snap-type',
'shape-image-threshold',
'shape-margin',
'shape-outside',
'tab-size',
'text-align-last',
'text-decoration',
'text-decoration-color',
'text-decoration-line',
'text-decoration-skip',
'text-decoration-skip-ink',
'text-decoration-style',
'text-emphasis',
'text-emphasis-color',
'text-emphasis-position',
'text-emphasis-style',
'text-orientation',
'text-overflow',
'text-size-adjust',
'text-spacing',
'touch-action',
'transform',
'transform-origin',
'transform-style',
'transition',
'transition-delay',
'transition-duration',
'transition-property',
'transition-timing-function',
'user-select',
'writing-mode',
]);
/**
* @example
* Object.values(prefixes.remove)
* .filter((p) => Array.isArray(p.values))
* .flatMap((p) => p.values)
* .map((p) => utils.removeNote(p.prefixed)) // normalize '-webkit- old'
* .filter((p) => !p.endsWith('-')); // remove '-webkit-' only
*
* @see https://github.com/stylelint/stylelint/pull/5312/files#r636018013
*/
const PROPERTY_VALUES = new Set([
'-moz-available',
'-moz-box',
'-moz-calc',
'-moz-crisp-edges',
'-moz-element',
'-moz-fit-content',
'-moz-grab',
'-moz-grabbing',
'-moz-inline-box',
'-moz-isolate',
'-moz-isolate-override',
'-moz-linear-gradient',
'-moz-max-content',
'-moz-min-content',
'-moz-plaintext',
'-moz-radial-gradient',
'-moz-repeating-linear-gradient',
'-moz-repeating-radial-gradient',
'-moz-zoom-in',
'-moz-zoom-out',
'-ms-flexbox',
'-ms-grid',
'-ms-inline-flexbox',
'-ms-inline-grid',
'-ms-linear-gradient',
'-ms-radial-gradient',
'-ms-repeating-linear-gradient',
'-ms-repeating-radial-gradient',
'-o-linear-gradient',
'-o-pixelated',
'-o-radial-gradient',
'-o-repeating-linear-gradient',
'-o-repeating-radial-gradient',
'-webkit-box',
'-webkit-calc',
'-webkit-cross-fade',
'-webkit-fill-available',
'-webkit-filter',
'-webkit-fit-content',
'-webkit-flex',
'-webkit-grab',
'-webkit-grabbing',
'-webkit-image-set',
'-webkit-inline-box',
'-webkit-inline-flex',
'-webkit-isolate',
'-webkit-linear-gradient',
'-webkit-max-content',
'-webkit-min-content',
'-webkit-optimize-contrast',
'-webkit-radial-gradient',
'-webkit-repeating-linear-gradient',
'-webkit-repeating-radial-gradient',
'-webkit-sticky',
'-webkit-zoom-in',
'-webkit-zoom-out',
]);
/**
* Most identifier types have to be looked up in a unique way,
* so we're exposing special functions for each.
*/
module.exports = {
/**
* @param {string} identifier
* @returns {boolean}
*/
atRuleName(identifier) {
return AT_RULES.has(`@${identifier.toLowerCase()}`);
},
/**
* @param {string} identifier
* @returns {boolean}
*/
selector(identifier) {
return SELECTORS.has(identifier.toLowerCase());
},
/**
* @param {string} identifier
* @returns {boolean}
*/
mediaFeatureName(identifier) {
return identifier.toLowerCase().includes('device-pixel-ratio');
},
/**
* @param {string} identifier
* @returns {boolean}
*/
property(identifier) {
const ident = identifier.toLowerCase();
// HACK: `interpolation-mode` does not exist. This is an IE extension for `image-rendering`.
// See <https://developer.mozilla.org/en-US/docs/Web/CSS/image-rendering#examples>
if (ident === '-ms-interpolation-mode') {
return true;
}
if (vendor.prefix(ident).length === 0) {
return false;
}
return PROPERTIES.has(vendor.unprefixed(ident));
},
/**
* @param {string} value
* @returns {boolean}
*/
propertyValue(value) {
return PROPERTY_VALUES.has(value.toLowerCase());
},
/**
* @param {string} value
* @returns {string}
*/
unprefix(value) {
return value.replace(/-\w+-/, '');
},
};

View File

@@ -0,0 +1,23 @@
'use strict';
const getPreviousNonSharedLineCommentNode = require('./getPreviousNonSharedLineCommentNode');
const hasBlock = require('./hasBlock');
const { isAtRule } = require('./typeGuards');
/**
* @param {import('postcss').AtRule} atRule
* @returns {boolean}
*/
module.exports = function isBlocklessAtRuleAfterBlocklessAtRule(atRule) {
if (atRule.type !== 'atrule') {
return false;
}
const previousNode = getPreviousNonSharedLineCommentNode(atRule);
if (previousNode === undefined) {
return false;
}
return isAtRule(previousNode) && !hasBlock(previousNode) && !hasBlock(atRule);
};

View File

@@ -0,0 +1,23 @@
'use strict';
const getPreviousNonSharedLineCommentNode = require('./getPreviousNonSharedLineCommentNode');
const isBlocklessAtRuleAfterBlocklessAtRule = require('./isBlocklessAtRuleAfterBlocklessAtRule');
const { isAtRule } = require('./typeGuards');
/**
* @param {import('postcss').AtRule} atRule
* @returns {boolean}
*/
module.exports = function isBlocklessAtRuleAfterSameNameBlocklessAtRule(atRule) {
if (!isBlocklessAtRuleAfterBlocklessAtRule(atRule)) {
return false;
}
const previousNode = getPreviousNonSharedLineCommentNode(atRule);
if (previousNode && isAtRule(previousNode)) {
return previousNode.name === atRule.name;
}
return false;
};

View File

@@ -0,0 +1,26 @@
'use strict';
const {
aNPlusBOfSNotationPseudoClasses,
logicalCombinationsPseudoClasses,
} = require('../reference/selectors');
/**
* Check whether a node is a context-functional pseudo-class (i.e. either a logical combination
* or a 'aNPlusBOfSNotationPseudoClasses' / tree-structural pseudo-class)
*
* @param {import('postcss-selector-parser').Node} node - postcss-selector-parser node (of type pseudo)
* @return {node is import('postcss-selector-parser').Pseudo} If `true`, the node is a context-functional pseudo-class
*/
module.exports = function isContextFunctionalPseudoClass(node) {
if (node.type === 'pseudo') {
const normalisedParentName = node.value.toLowerCase().replace(/:+/, '');
return (
logicalCombinationsPseudoClasses.has(normalisedParentName) ||
aNPlusBOfSNotationPseudoClasses.has(normalisedParentName)
);
}
return false;
};

View File

@@ -0,0 +1,21 @@
'use strict';
const { counterIncrementKeywords } = require('../reference/keywords');
/**
* Check value is a custom ident
*
* @param {string} value
*/
module.exports = function isCounterIncrementCustomIdentValue(value) {
const valueLowerCase = value.toLowerCase();
if (
counterIncrementKeywords.has(valueLowerCase) ||
Number.isFinite(Number.parseInt(valueLowerCase, 10))
) {
return false;
}
return true;
};

View File

@@ -0,0 +1,21 @@
'use strict';
const { counterResetKeywords } = require('../reference/keywords');
/**
* Check value is a custom ident
*
* @param {string} value
*/
module.exports = function isCounterResetCustomIdentValue(value) {
const valueLowerCase = value.toLowerCase();
if (
counterResetKeywords.has(valueLowerCase) ||
Number.isFinite(Number.parseInt(valueLowerCase, 10))
) {
return false;
}
return true;
};

41
node_modules/stylelint/lib/utils/isCustomElement.js generated vendored Normal file
View File

@@ -0,0 +1,41 @@
'use strict';
const { htmlTypeSelectors } = require('../reference/selectors');
const mathMLTags = require('mathml-tag-names');
const svgTags = require('svg-tags');
/**
* Check whether a type selector is a custom element
*
* @param {string} selector
* @returns {boolean}
*/
module.exports = function isCustomElement(selector) {
if (!/^[a-z]/.test(selector)) {
return false;
}
if (!selector.includes('-')) {
return false;
}
const selectorLowerCase = selector.toLowerCase();
if (selectorLowerCase !== selector) {
return false;
}
if (svgTags.includes(selectorLowerCase)) {
return false;
}
if (htmlTypeSelectors.has(selectorLowerCase)) {
return false;
}
if (mathMLTags.includes(selectorLowerCase)) {
return false;
}
return true;
};

11
node_modules/stylelint/lib/utils/isCustomFunction.js generated vendored Normal file
View File

@@ -0,0 +1,11 @@
'use strict';
/**
* Check whether a function is custom / user-defined
* https://github.com/w3c/css-houdini-drafts/issues/1007
* @param {string} func
* @returns {boolean}
*/
module.exports = function isCustomFunction(func) {
return func.startsWith('--');
};

10
node_modules/stylelint/lib/utils/isCustomMediaQuery.js generated vendored Normal file
View File

@@ -0,0 +1,10 @@
'use strict';
/**
* Check whether a media query is a custom
* @param {string} mediaQuery
* @returns {boolean}
*/
module.exports = function isCustomMediaQuery(mediaQuery) {
return mediaQuery.startsWith('--');
};

10
node_modules/stylelint/lib/utils/isCustomProperty.js generated vendored Normal file
View File

@@ -0,0 +1,10 @@
'use strict';
/**
* Check whether a property is a custom one
* @param {string} property
* @returns {boolean}
*/
module.exports = function isCustomProperty(property) {
return property.startsWith('--');
};

11
node_modules/stylelint/lib/utils/isCustomSelector.js generated vendored Normal file
View File

@@ -0,0 +1,11 @@
'use strict';
/**
* Check whether a selector is a custom one
*
* @param {string} selector
* @returns {boolean}
*/
module.exports = function isCustomSelector(selector) {
return selector.startsWith(':--');
};

73
node_modules/stylelint/lib/utils/isFirstNested.js generated vendored Normal file
View File

@@ -0,0 +1,73 @@
'use strict';
const { isComment, hasSource } = require('./typeGuards');
/**
* @param {import('postcss').Node} statement
* @returns {boolean}
*/
module.exports = function isFirstNested(statement) {
const parentNode = statement.parent;
if (parentNode === undefined || parentNode.type === 'root') {
return false;
}
if (statement === parentNode.first) {
return true;
}
/*
* Search for the statement in the parent's nodes, ignoring comment
* nodes on the same line as the parent's opening brace.
*/
const parentNodes = parentNode.nodes;
if (!parentNodes) {
return false;
}
const firstNode = parentNodes[0];
if (!firstNode) {
return false;
}
if (
!isComment(firstNode) ||
(typeof firstNode.raws.before === 'string' && firstNode.raws.before.includes('\n'))
) {
return false;
}
if (!hasSource(firstNode) || !firstNode.source.start) {
return false;
}
const openingBraceLine = firstNode.source.start.line;
if (!firstNode.source.end || openingBraceLine !== firstNode.source.end.line) {
return false;
}
for (const [index, node] of parentNodes.entries()) {
if (index === 0) {
continue;
}
if (node === statement) {
return true;
}
if (
!isComment(node) ||
(hasSource(node) && node.source.end && node.source.end.line !== openingBraceLine)
) {
return false;
}
}
/* istanbul ignore next: Should always return in the loop */
return false;
};

19
node_modules/stylelint/lib/utils/isFirstNodeOfRoot.js generated vendored Normal file
View File

@@ -0,0 +1,19 @@
'use strict';
const { isRoot } = require('./typeGuards');
/**
* @param {import('postcss').Node} node
* @returns {boolean}
*/
module.exports = function isFirstNodeOfRoot(node) {
if (isRoot(node)) return false;
const parentNode = node.parent;
if (!parentNode) {
return false;
}
return isRoot(parentNode) && node === parentNode.first;
};

19
node_modules/stylelint/lib/utils/isKeyframeRule.js generated vendored Normal file
View File

@@ -0,0 +1,19 @@
'use strict';
const { isAtRule } = require('./typeGuards');
/**
* Check if a rule is a keyframe one
*
* @param {import('postcss').Rule} rule
* @returns {boolean}
*/
module.exports = function isKeyframeRule(rule) {
const parent = rule.parent;
if (!parent) {
return false;
}
return isAtRule(parent) && parent.name.toLowerCase() === 'keyframes';
};

22
node_modules/stylelint/lib/utils/isKeyframeSelector.js generated vendored Normal file
View File

@@ -0,0 +1,22 @@
'use strict';
const { keyframeSelectorKeywords } = require('../reference/keywords');
/**
* Check whether a string is a keyframe selector.
*
* @param {string} selector
* @returns {boolean}
*/
module.exports = function isKeyframeSelector(selector) {
if (keyframeSelectorKeywords.has(selector)) {
return true;
}
// Percentages
if (/^(?:\d+|\d*\.\d+)%$/.test(selector)) {
return true;
}
return false;
};

14
node_modules/stylelint/lib/utils/isLessVariable.js generated vendored Normal file
View File

@@ -0,0 +1,14 @@
'use strict';
const hasBlock = require('./hasBlock');
/**
* @param {import('postcss').AtRule | import('postcss-less').AtRule} atRule
* @returns {boolean}
*/
module.exports = function isLessVariable(atRule) {
return (
(atRule.type === 'atrule' && 'variable' in atRule && atRule.variable && !hasBlock(atRule)) ||
false
);
};

13
node_modules/stylelint/lib/utils/isMathFunction.js generated vendored Normal file
View File

@@ -0,0 +1,13 @@
'use strict';
const { mathFunctions } = require('../reference/functions');
/**
* Check whether a node is math function
*
* @param {import('postcss-value-parser').Node} node postcss-value-parser node
* @return {boolean} If `true`, the node is math function
*/
module.exports = function isMathFunction(node) {
return node.type === 'function' && mathFunctions.has(node.value.toLowerCase());
};

View File

@@ -0,0 +1,8 @@
'use strict';
/**
* @param {unknown} value
*/
module.exports = function isNonNegativeInteger(value) {
return Number.isInteger(value) && typeof value === 'number' && value >= 0;
};

11
node_modules/stylelint/lib/utils/isNumbery.js generated vendored Normal file
View File

@@ -0,0 +1,11 @@
'use strict';
/**
* Check whether it's a number or a number-like string:
* i.e. when coerced to a number it == itself.
*
* @param {string | number} value
*/
module.exports = function isNumbery(value) {
return value.toString().trim().length !== 0 && Number(value) == value; // eslint-disable-line eqeqeq
};

19
node_modules/stylelint/lib/utils/isOnlyWhitespace.js generated vendored Normal file
View File

@@ -0,0 +1,19 @@
'use strict';
const isWhitespace = require('./isWhitespace');
/**
* Returns a Boolean indicating whether the input string is only whitespace.
*
* @param {string} input
* @returns {boolean}
*/
module.exports = function isOnlyWhitespace(input) {
for (const element of input) {
if (!isWhitespace(element)) {
return false;
}
}
return true;
};

View File

@@ -0,0 +1,12 @@
'use strict';
const util = require('util');
/**
* @param {unknown} error
* @returns {error is NodeJS.ErrnoException}
*/
module.exports = function isPathNotFoundError(error) {
// @ts-expect-error -- TS2339: Property 'code' does not exist on type 'Error'.
return util.types.isNativeError(error) && error.code === 'ENOENT';
};

View File

@@ -0,0 +1,11 @@
'use strict';
/**
* Check whether a media feature is a range context one
*
* @param {string} mediaFeature feature
* @return {boolean} If `true`, media feature is a range context one
*/
module.exports = function isRangeContextMediaFeature(mediaFeature) {
return mediaFeature.includes('=') || mediaFeature.includes('<') || mediaFeature.includes('>');
};

21
node_modules/stylelint/lib/utils/isScssVariable.js generated vendored Normal file
View File

@@ -0,0 +1,21 @@
'use strict';
/**
* Check whether a property is SCSS variable
*
* @param {string} property
* @returns {boolean}
*/
module.exports = function isScssVariable(property) {
// SCSS var (e.g. $var: x), list (e.g. $list: (x)) or map (e.g. $map: (key:value))
if (property.startsWith('$')) {
return true;
}
// SCSS var within a namespace (e.g. namespace.$var: x)
if (property.includes('.$')) {
return true;
}
return false;
};

View File

@@ -0,0 +1,56 @@
'use strict';
const getNextNonSharedLineCommentNode = require('./getNextNonSharedLineCommentNode');
const getPreviousNonSharedLineCommentNode = require('./getPreviousNonSharedLineCommentNode');
const { isRoot, isComment } = require('./typeGuards');
/** @typedef {import('postcss').Node} PostcssNode */
/**
*
* @param {PostcssNode | void} a
* @param {PostcssNode | void} b
*/
function nodesShareLines(a, b) {
const aLine = a && a.source && a.source.end && a.source.end.line;
const bLine = b && b.source && b.source.start && b.source.start.line;
return aLine === bLine;
}
/**
* @param {PostcssNode} node
* @returns {boolean}
*/
module.exports = function isSharedLineComment(node) {
if (!isComment(node)) {
return false;
}
const previousNonSharedLineCommentNode = getPreviousNonSharedLineCommentNode(node);
if (nodesShareLines(previousNonSharedLineCommentNode, node)) {
return true;
}
const nextNonSharedLineCommentNode = getNextNonSharedLineCommentNode(node);
if (nextNonSharedLineCommentNode && nodesShareLines(node, nextNonSharedLineCommentNode)) {
return true;
}
const parentNode = node.parent;
// It's a first child and located on the same line as block start
if (
parentNode !== undefined &&
!isRoot(parentNode) &&
parentNode.index(node) === 0 &&
node.raws.before !== undefined &&
!node.raws.before.includes('\n')
) {
return true;
}
return false;
};

12
node_modules/stylelint/lib/utils/isSingleLineString.js generated vendored Normal file
View File

@@ -0,0 +1,12 @@
'use strict';
/**
* Check if a string is a single line (i.e. does not contain
* any newline characters).
*
* @param {string} input
* @return {boolean}
*/
module.exports = function isSingleLineString(input) {
return !/[\n\r]/.test(input);
};

View File

@@ -0,0 +1,29 @@
'use strict';
/**
* Check whether a at-rule is standard
*
* @param {import('postcss').AtRule | import('postcss-less').AtRule} atRule postcss at-rule node
* @return {boolean} If `true`, the declaration is standard
*/
module.exports = function isStandardSyntaxAtRule(atRule) {
// Ignore scss `@content` inside mixins
if (!atRule.nodes && atRule.params === '') {
return false;
}
// Ignore Less mixins
if ('mixin' in atRule && atRule.mixin) {
return false;
}
// Ignore Less detached ruleset `@detached-ruleset: { background: red; }; .top { @detached-ruleset(); }`
if (
('variable' in atRule && atRule.variable) ||
(!atRule.nodes && atRule.raws.afterName === '' && atRule.params[0] === '(')
) {
return false;
}
return true;
};

View File

@@ -0,0 +1,23 @@
'use strict';
const isStandardSyntaxFunction = require('./isStandardSyntaxFunction');
/**
* Check whether a function is standard syntax color function
*
* @param {import('postcss-value-parser').FunctionNode} node
* @returns {boolean}
*/
module.exports = function isStandardSyntaxColorFunction(node) {
if (!isStandardSyntaxFunction(node)) return false;
// scss can accept a #hex, or $var variables and we need to check all nested fn nodes
for (const fnNode of node.nodes) {
if (fnNode.type === 'function') return isStandardSyntaxColorFunction(fnNode);
if (fnNode.type === 'word' && (fnNode.value.startsWith('#') || fnNode.value.startsWith('$')))
return false;
}
return true;
};

View File

@@ -0,0 +1,34 @@
'use strict';
/**
* Check whether a combinator is standard
*
* @param {import('postcss-selector-parser').Combinator} node postcss-selector-parser node (of type combinator)
* @return {boolean} If `true`, the combinator is standard
*/
module.exports = function isStandardSyntaxCombinator(node) {
// if it's not a combinator, then it's not a standard combinator
if (node.type !== 'combinator') {
return false;
}
// Ignore reference combinators like `/deep/`
if (node.value.startsWith('/') || node.value.endsWith('/')) {
return false;
}
// ignore the combinators that are the first or last node in their container
if (node.parent !== undefined && node.parent !== null) {
const parent = node.parent;
if (node === parent.first) {
return false;
}
if (node === parent.last) {
return false;
}
}
return true;
};

View File

@@ -0,0 +1,15 @@
'use strict';
/**
* @param {import('postcss').Comment} comment
* @returns {boolean}
*/
module.exports = function isStandardSyntaxComment(comment) {
// We check both here because the Sass parser uses `raws.inline` to indicate
// inline comments, while the Less parser uses `inline`.
if ('inline' in comment) return false;
if ('inline' in comment.raws) return false;
return true;
};

View File

@@ -0,0 +1,77 @@
'use strict';
const isScssVariable = require('./isScssVariable');
const { isRoot, isRule } = require('./typeGuards');
/**
* @param {string} [lang]
*/
function isStandardSyntaxLang(lang) {
return lang && (lang === 'css' || lang === 'custom-template' || lang === 'template-literal');
}
/**
* Check whether a declaration is standard
*
* @param {import('postcss').Declaration | import('postcss-less').Declaration} decl
*/
module.exports = function isStandardSyntaxDeclaration(decl) {
const prop = decl.prop;
const parent = decl.parent;
// Declarations belong in a declaration block or standard CSS source
if (
parent &&
isRoot(parent) &&
parent.source &&
!isStandardSyntaxLang(
/** @type {import('postcss').Source & {lang?: string}} */ (parent.source).lang,
)
) {
return false;
}
// SCSS var; covers map and list declarations
if (isScssVariable(prop)) {
return false;
}
// Less var (e.g. @var: x), but exclude variable interpolation (e.g. @{var})
if (prop[0] === '@' && prop[1] !== '{') {
return false;
}
// Less map declaration
if (parent && parent.type === 'atrule' && parent.raws.afterName === ':') {
return false;
}
// Less map (e.g. #my-map() { myprop: red; })
if (
parent &&
isRule(parent) &&
parent.selector &&
parent.selector.startsWith('#') &&
parent.selector.endsWith('()')
) {
return false;
}
// Sass nested properties (e.g. border: { style: solid; color: red; })
if (
parent &&
isRule(parent) &&
parent.selector &&
parent.selector[parent.selector.length - 1] === ':' &&
parent.selector.substring(0, 2) !== '--'
) {
return false;
}
// Less &:extend
if ('extend' in decl && decl.extend) {
return false;
}
return true;
};

View File

@@ -0,0 +1,20 @@
'use strict';
/**
* Check whether a function is standard
*
* @param {import('postcss-value-parser').Node} node
* @returns {boolean}
*/
module.exports = function isStandardSyntaxFunction(node) {
// Function nodes without names are things in parentheses like Sass lists
if (!node.value) {
return false;
}
if (node.value.startsWith('#{')) {
return false;
}
return true;
};

View File

@@ -0,0 +1,16 @@
'use strict';
/**
* Check whether a hex color is standard
*
* @param {string} hex
* @returns {boolean}
*/
module.exports = function isStandardSyntaxHexColor(hex) {
// Less map usage (e.g. .myclass { color: #colors[somecolor]; })
if (hex.includes('[')) {
return false;
}
return true;
};

View File

@@ -0,0 +1,17 @@
'use strict';
const hasInterpolation = require('./hasInterpolation');
/**
* Check whether a keyframes name is standard
*
* @param {string} keyframesName
* @returns {boolean}
*/
module.exports = function isStandardSyntaxKeyframesName(keyframesName) {
if (hasInterpolation(keyframesName)) {
return false;
}
return true;
};

View File

@@ -0,0 +1,21 @@
'use strict';
/**
* Check whether a math function is standard
*
* @param {string} mathFunction
* @returns {boolean}
*/
module.exports = function isStandardSyntaxMathFunction(mathFunction) {
// SCSS variable
if (mathFunction.includes('$')) {
return false;
}
// Less variable
if (mathFunction.includes('@')) {
return false;
}
return true;
};

View File

@@ -0,0 +1,26 @@
'use strict';
const hasInterpolation = require('../utils/hasInterpolation');
/**
* Check whether a media feature is standard
*
* @param {string} mediaFeature
* @returns {boolean}
*/
module.exports = function isStandardSyntaxMediaFeature(mediaFeature) {
// Remove outside parens
mediaFeature = mediaFeature.slice(1, -1);
// Parentheticals used for non-standard operations e.g. ($var - 10)
if (mediaFeature.includes('(')) {
return false;
}
// SCSS or Less interpolation
if (hasInterpolation(mediaFeature)) {
return false;
}
return true;
};

View File

@@ -0,0 +1,16 @@
'use strict';
/**
* Check whether a media feature name is standard
*
* @param {string} mediaFeatureName
* @returns {boolean}
*/
module.exports = function isStandardSyntaxMediaFeatureName(mediaFeatureName) {
// SCSS interpolation
if (/#\{.+?\}|\$.+/.test(mediaFeatureName)) {
return false;
}
return true;
};

View File

@@ -0,0 +1,34 @@
'use strict';
const hasInterpolation = require('../utils/hasInterpolation');
const isScssVariable = require('./isScssVariable');
/**
* Check whether a property is standard
*
* @param {string} property
* @returns {boolean}
*/
module.exports = function isStandardSyntaxProperty(property) {
// SCSS var
if (isScssVariable(property)) {
return false;
}
// Less var (e.g. @var: x)
if (property.startsWith('@')) {
return false;
}
// Less append property value with space (e.g. transform+_: scale(2))
if (property.endsWith('+') || property.endsWith('+_')) {
return false;
}
// SCSS or Less interpolation
if (hasInterpolation(property)) {
return false;
}
return true;
};

View File

@@ -0,0 +1,26 @@
'use strict';
const isStandardSyntaxSelector = require('../utils/isStandardSyntaxSelector');
/**
* Check whether a Node is a standard rule
*
* @param {import('postcss').Rule | import('postcss-less').Rule} rule
* @returns {boolean}
*/
module.exports = function isStandardSyntaxRule(rule) {
if (rule.type !== 'rule') {
return false;
}
// Ignore Less &:extend rule
if ('extend' in rule && rule.extend) {
return false;
}
if (!isStandardSyntaxSelector(rule.selector)) {
return false;
}
return true;
};

View File

@@ -0,0 +1,58 @@
'use strict';
const hasInterpolation = require('../utils/hasInterpolation');
/**
* Check whether a selector is standard
*
* @param {string} selector
* @returns {boolean}
*/
module.exports = function isStandardSyntaxSelector(selector) {
// SCSS or Less interpolation
if (hasInterpolation(selector)) {
return false;
}
// SCSS placeholder selectors
if (selector.startsWith('%')) {
return false;
}
// SCSS nested properties
if (selector.endsWith(':')) {
return false;
}
// Less :extend()
if (/:extend(?:\(.*?\))?/.test(selector)) {
return false;
}
// Less mixin with resolved nested selectors (e.g. .foo().bar or .foo(@a, @b)[bar])
if (/\.[\w-]+\(.*\).+/.test(selector)) {
return false;
}
// Less non-outputting mixin definition (e.g. .mixin() {})
if (selector.endsWith(')') && !selector.includes(':')) {
return false;
}
// Less Parametric mixins (e.g. .mixin(@variable: x) {})
if (/\(@.*\)$/.test(selector)) {
return false;
}
// ERB template tags
if (selector.includes('<%') || selector.includes('%>')) {
return false;
}
// SCSS and Less comments
if (selector.includes('//')) {
return false;
}
return true;
};

View File

@@ -0,0 +1,58 @@
'use strict';
const {
aNPlusBNotationPseudoClasses,
aNPlusBOfSNotationPseudoClasses,
linguisticPseudoClasses,
shadowTreePseudoElements,
} = require('../reference/selectors');
/**
* Check whether a type selector is standard
*
* @param {import('postcss-selector-parser').Tag} node postcss-selector-parser node (of type tag)
* @return {boolean} If `true`, the type selector is standard
*/
module.exports = function isStandardSyntaxTypeSelector(node) {
// postcss-selector-parser includes the arguments to nth-child() functions
// as "tags", so we need to ignore them ourselves.
// The fake-tag's "parent" is actually a selector node, whose parent
// should be the :nth-child pseudo node.
if (!node.parent || !node.parent.parent) {
return false;
}
const _node$parent$parent = node.parent.parent;
const parentType = _node$parent$parent.type;
const parentValue = _node$parent$parent.value;
if (parentValue) {
const normalisedParentName = parentValue.toLowerCase().replace(/:+/, '');
if (
parentType === 'pseudo' &&
(aNPlusBNotationPseudoClasses.has(normalisedParentName) ||
aNPlusBOfSNotationPseudoClasses.has(normalisedParentName) ||
linguisticPseudoClasses.has(normalisedParentName) ||
shadowTreePseudoElements.has(normalisedParentName))
) {
return false;
}
}
// &-bar is a nesting selector combined with a suffix
if (node.prev() && node.prev().type === 'nesting') {
return false;
}
if (node.value.startsWith('%')) {
return false;
}
// Reference combinators like `/deep/`
if (node.value.startsWith('/') && node.value.endsWith('/')) {
return false;
}
return true;
};

View File

@@ -0,0 +1,48 @@
'use strict';
const hasLessInterpolation = require('../utils/hasLessInterpolation');
const hasPsvInterpolation = require('../utils/hasPsvInterpolation');
const hasScssInterpolation = require('../utils/hasScssInterpolation');
const hasTplInterpolation = require('../utils/hasTplInterpolation');
/**
* Check whether a URL is standard
*
* @param {string} url
* @returns {boolean}
*/
module.exports = function isStandardSyntaxUrl(url) {
if (url.length === 0) {
return true;
}
// Sass interpolation works anywhere
if (hasScssInterpolation(url) || hasTplInterpolation(url) || hasPsvInterpolation(url)) {
return false;
}
// Inside `'` and `"` work only LESS interpolation
if ((url.startsWith(`'`) && url.endsWith(`'`)) || (url.startsWith(`"`) && url.endsWith(`"`))) {
if (hasLessInterpolation(url)) {
return false;
}
return true;
}
// Less variable works only at the beginning
// Check is less variable, allow use '@url/some/path'
// https://github.com/less/less.js/blob/3.x/lib/less/parser/parser.js#L547
if (url.startsWith('@') && /^@@?[\w-]+$/.test(url)) {
return false;
}
// In url without quotes scss variable can be everywhere
// But in this case it is allowed to use only specific characters
// Also forbidden "/" at the end of url
if (url.includes('$') && /^[$\s\w+\-,./*'"]+$/.test(url) && !url.endsWith('/')) {
return false;
}
return true;
};

View File

@@ -0,0 +1,47 @@
'use strict';
const hasInterpolation = require('../utils/hasInterpolation');
/**
* Check whether a value is standard
*
* @param {string} value
* @returns {boolean}
*/
module.exports = function isStandardSyntaxValue(value) {
let normalizedValue = value;
// Ignore operators before variables (example -$variable)
if (/^[-+*/]/.test(value.charAt(0))) {
normalizedValue = normalizedValue.slice(1);
}
// SCSS variable (example $variable)
if (normalizedValue.startsWith('$')) {
return false;
}
// SCSS namespace (example namespace.$variable)
if (/^.+\.\$/.test(value)) {
return false;
}
// Less variable
if (normalizedValue.startsWith('@')) {
return false;
}
// SCSS or Less interpolation
if (hasInterpolation(normalizedValue)) {
return false;
}
// WebExtension replacement keyword used by Chrome/Firefox
// more information: https://developer.chrome.com/extensions/i18n
// and https://github.com/stylelint/stylelint/issues/4707
if (/__MSG_\S+__/.test(value)) {
return false;
}
return true;
};

39
node_modules/stylelint/lib/utils/isValidFontSize.js generated vendored Normal file
View File

@@ -0,0 +1,39 @@
'use strict';
const { fontSizeKeywords } = require('../reference/keywords');
const { lengthUnits } = require('../reference/units');
const valueParser = require('postcss-value-parser');
/**
* Check if a word is a font-size value.
*
* @param {string} word
* @returns {boolean}
*/
module.exports = function isValidFontSize(word) {
if (!word) {
return false;
}
if (fontSizeKeywords.has(word)) {
return true;
}
const numberUnit = valueParser.unit(word);
if (!numberUnit) {
return false;
}
const unit = numberUnit.unit;
if (unit === '%') {
return true;
}
if (lengthUnits.has(unit.toLowerCase())) {
return true;
}
return false;
};

11
node_modules/stylelint/lib/utils/isValidHex.js generated vendored Normal file
View File

@@ -0,0 +1,11 @@
'use strict';
/**
* Check if a value is a valid 3, 4, 6 or 8 digit hex
*
* @param {string} value
* @returns {boolean}
*/
module.exports = function isValidHex(value) {
return /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(value);
};

11
node_modules/stylelint/lib/utils/isVariable.js generated vendored Normal file
View File

@@ -0,0 +1,11 @@
'use strict';
/**
* Check whether a word is a variable i.e var(--custom-property).
*
* @param {string} word
* @returns {boolean}
*/
module.exports = function isVariable(word) {
return word.toLowerCase().startsWith('var(');
};

11
node_modules/stylelint/lib/utils/isWhitespace.js generated vendored Normal file
View File

@@ -0,0 +1,11 @@
'use strict';
/**
* Check if a character is whitespace.
*
* @param {string} char
* @returns {boolean}
*/
module.exports = function isWhitespace(char) {
return [' ', '\n', '\t', '\r', '\f'].includes(char);
};

View File

@@ -0,0 +1,89 @@
'use strict';
/**
* Compares a string to a second value that, if it fits a certain convention,
* is converted to a regular expression before the comparison.
* If it doesn't fit the convention, then two strings are compared.
*
* Any strings starting and ending with `/` are interpreted
* as regular expressions.
*
* @param {string | Array<string>} input
* @param {string | RegExp | Array<string | RegExp>} comparison
*
* @returns {false | {match: string, pattern: (string | RegExp), substring: string}}
*/
module.exports = function matchesStringOrRegExp(input, comparison) {
if (!Array.isArray(input)) {
return testAgainstStringOrRegExpOrArray(input, comparison);
}
for (const inputItem of input) {
const testResult = testAgainstStringOrRegExpOrArray(inputItem, comparison);
if (testResult) {
return testResult;
}
}
return false;
};
/**
* @param {string} value
* @param {string | RegExp | Array<string | RegExp>} comparison
*/
function testAgainstStringOrRegExpOrArray(value, comparison) {
if (!Array.isArray(comparison)) {
return testAgainstStringOrRegExp(value, comparison);
}
for (const comparisonItem of comparison) {
const testResult = testAgainstStringOrRegExp(value, comparisonItem);
if (testResult) {
return testResult;
}
}
return false;
}
/**
* @param {string} value
* @param {string | RegExp} comparison
*/
function testAgainstStringOrRegExp(value, comparison) {
// If it's a RegExp, test directly
if (comparison instanceof RegExp) {
const match = value.match(comparison);
return match ? { match: value, pattern: comparison, substring: match[0] || '' } : false;
}
// Check if it's RegExp in a string
const firstComparisonChar = comparison[0];
const lastComparisonChar = comparison[comparison.length - 1];
const secondToLastComparisonChar = comparison[comparison.length - 2];
const comparisonIsRegex =
firstComparisonChar === '/' &&
(lastComparisonChar === '/' ||
(secondToLastComparisonChar === '/' && lastComparisonChar === 'i'));
const hasCaseInsensitiveFlag = comparisonIsRegex && lastComparisonChar === 'i';
// If so, create a new RegExp from it
if (comparisonIsRegex) {
const valueMatch = hasCaseInsensitiveFlag
? value.match(new RegExp(comparison.slice(1, -2), 'i'))
: value.match(new RegExp(comparison.slice(1, -1)));
return valueMatch
? { match: value, pattern: comparison, substring: valueMatch[0] || '' }
: false;
}
// Otherwise, it's a string. Do a strict comparison
return value === comparison ? { match: value, pattern: comparison, substring: value } : false;
}

20
node_modules/stylelint/lib/utils/nextNonCommentNode.js generated vendored Normal file
View File

@@ -0,0 +1,20 @@
'use strict';
/** @typedef {import('postcss').Node} PostcssNode */
/**
* Get the next non-comment node in a PostCSS AST
* at or after a given node.
*
* @param {PostcssNode | void} startNode
* @returns {PostcssNode | null}
*/
module.exports = function nextNonCommentNode(startNode) {
if (!startNode || !startNode.next) return null;
if (startNode.type === 'comment') {
return nextNonCommentNode(startNode.next());
}
return startNode;
};

20
node_modules/stylelint/lib/utils/noFilesFoundError.js generated vendored Normal file
View File

@@ -0,0 +1,20 @@
'use strict';
class NoFilesFoundError extends Error {
/**
* @param {string|string[]} fileList
*/
constructor(fileList) {
super();
if (typeof fileList === 'string') {
fileList = [fileList];
}
const pattern = fileList.filter((i) => !i.startsWith('!')).join(', ');
this.message = `No files matching the pattern "${pattern}" were found.`;
}
}
module.exports = NoFilesFoundError;

Some files were not shown because too many files have changed in this diff Show More