Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor to improve types for no-duplicate-* rules #5543

Merged
merged 1 commit into from
Sep 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 12 additions & 11 deletions lib/rules/no-duplicate-at-import-rules/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @ts-nocheck

'use strict';

const mediaParser = require('postcss-media-query-parser').default;
Expand All @@ -14,30 +12,33 @@ const messages = ruleMessages(ruleName, {
rejected: (atImport) => `Unexpected duplicate @import rule ${atImport}`,
});

function rule(actual) {
/** @type {import('stylelint').StylelintRule} */
const rule = (primary) => {
return (root, result) => {
const validOptions = validateOptions(result, ruleName, { actual });
const validOptions = validateOptions(result, ruleName, { actual: primary });

if (!validOptions) {
return;
}

/** @type {Record<string, string[]>} */
const imports = {};

root.walkAtRules(/^import$/i, (atRule) => {
const params = valueParser(atRule.params).nodes;
const [firstParam, ...restParams] = valueParser(atRule.params).nodes;

if (!params.length) {
if (!firstParam) {
return;
}

// extract uri from url() if exists
const uri =
params[0].type === 'function' && params[0].value === 'url'
? params[0].nodes[0].value
: params[0].value;
firstParam.type === 'function' && firstParam.value === 'url'
? firstParam.nodes[0].value
: firstParam.value;

// extract media queries if any
const media = mediaParser(valueParser.stringify(params.slice(1)))
const media = mediaParser(valueParser.stringify(restParams))
.nodes.map((n) => n.value.replace(/\s/g, ''))
.filter((n) => n.length);

Expand All @@ -61,7 +62,7 @@ function rule(actual) {
imports[uri] = imports[uri].concat(media);
});
};
}
};

rule.ruleName = ruleName;
rule.messages = messages;
Expand Down
34 changes: 18 additions & 16 deletions lib/rules/no-duplicate-selectors/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// @ts-nocheck

'use strict';

const findAtRuleContext = require('../../utils/findAtRuleContext');
Expand All @@ -20,16 +18,17 @@ const messages = ruleMessages(ruleName, {
`Unexpected duplicate selector "${selector}", first used at line ${firstDuplicateLine}`,
});

function rule(actual, options) {
/** @type {import('stylelint').StylelintRule} */
const rule = (primary, secondaryOptions) => {
return (root, result) => {
const validOptions = validateOptions(
result,
ruleName,
{ actual },
{ actual: primary },
{
actual: options,
actual: secondaryOptions,
possible: {
disallowInList: isBoolean,
disallowInList: [isBoolean],
},
optional: true,
},
Expand All @@ -39,7 +38,7 @@ function rule(actual, options) {
return;
}

const shouldDisallowDuplicateInList = options && options.disallowInList;
const shouldDisallowDuplicateInList = secondaryOptions && secondaryOptions.disallowInList;

// The top level of this map will be rule sources.
// Each source maps to another map, which maps rule parents to a set of selectors.
Expand All @@ -56,18 +55,20 @@ function rule(actual, options) {
ruleNode,
findAtRuleContext(ruleNode),
);
const resolvedSelectors = new Set();

ruleNode.selectors.forEach((selector) => {
resolvedNestedSelector(selector, ruleNode).forEach((s) => resolvedSelectors.add(s));
});

const resolvedSelectorList = [...resolvedSelectors];
const resolvedSelectorList = [
...new Set(
ruleNode.selectors.flatMap((selector) => resolvedNestedSelector(selector, ruleNode)),
),
];
const normalizedSelectorList = resolvedSelectorList.map(normalizeSelector);

// Sort the selectors list so that the order of the constituents
// doesn't matter
const sortedSelectorList = normalizedSelectorList.slice().sort().join(',');
const sortedSelectorList = [...normalizedSelectorList].sort().join(',');

if (!ruleNode.source) throw new Error('The rule node must have a source');

if (!ruleNode.source.start) throw new Error('The rule source must have a start position');

const selectorLine = ruleNode.source.start.line;

Expand All @@ -76,6 +77,7 @@ function rule(actual, options) {
let previousDuplicatePosition;
// When `disallowInList` is true, we must parse `sortedSelectorList` into
// list items.
/** @type {string[]} */
const selectorListParsed = [];

if (shouldDisallowDuplicateInList) {
Expand Down Expand Up @@ -145,7 +147,7 @@ function rule(actual, options) {
}
});
};
}
};

rule.ruleName = ruleName;
rule.messages = messages;
Expand Down
5 changes: 5 additions & 0 deletions types/normalize-selector/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
declare module 'normalize-selector' {
function normalizeSelector(selector: string): string;

export = normalizeSelector;
}