From 909063d307b22b35d28faf48a965cdbf08150bb6 Mon Sep 17 00:00:00 2001 From: Masafumi Koba <473530+ybiquitous@users.noreply.github.com> Date: Sun, 12 Jul 2020 23:47:33 +0900 Subject: [PATCH 1/6] Replace 3rd-party type definitions (#4857) * Replace 3rd-party type definitions This change replaces 3rd-party type definitions under the `types/` directory with the following `@types/*` npm packages. - [@types/balanced-match](https://www.npmjs.com/package/@types/balanced-match) - [@types/imurmurhash](https://www.npmjs.com/package/@types/imurmurhash) - [@types/postcss-safe-parser](https://www.npmjs.com/package/@types/postcss-safe-parser) - [@types/style-search](https://www.npmjs.com/package/@types/style-search) - [@types/svg-tags](https://www.npmjs.com/package/@types/svg-tags) - [@types/write-file-atomic](https://www.npmjs.com/package/@types/write-file-atomic) Note that this change does **not** replace all type definitions under `types/`. We should address the remaining types via other pull requests. Related to #4399 * Replace with `@types/file-entry-cache` --- .../index.js | 8 ++- lib/utils/FileCache.js | 3 ++ lib/utils/blurFunctionArguments.js | 9 +++- lib/utils/functionArgumentsSearch.js | 4 ++ lib/writeOutputFile.js | 2 +- package-lock.json | 51 +++++++++++++++++++ package.json | 7 +++ types/balanced-match/index.d.ts | 5 -- types/file-entry-cache/index.d.ts | 5 -- types/imurmurhash/index.d.ts | 5 -- types/postcss/extensions.d.ts | 10 ---- types/style-search/index.d.ts | 17 ------- types/svg-tags/index.d.ts | 6 --- types/svg-tags/postcss-safe-parser.ts | 1 - types/write-file-atomic/index.d.ts | 21 -------- 15 files changed, 80 insertions(+), 74 deletions(-) delete mode 100644 types/balanced-match/index.d.ts delete mode 100644 types/file-entry-cache/index.d.ts delete mode 100644 types/imurmurhash/index.d.ts delete mode 100644 types/postcss/extensions.d.ts delete mode 100644 types/style-search/index.d.ts delete mode 100644 types/svg-tags/index.d.ts delete mode 100644 types/svg-tags/postcss-safe-parser.ts delete mode 100644 types/write-file-atomic/index.d.ts diff --git a/lib/rules/function-calc-no-unspaced-operator/index.js b/lib/rules/function-calc-no-unspaced-operator/index.js index 27a4368ffd..abcc9e8f70 100644 --- a/lib/rules/function-calc-no-unspaced-operator/index.js +++ b/lib/rules/function-calc-no-unspaced-operator/index.js @@ -36,7 +36,13 @@ function rule(actual) { return; } - const parensMatch = balancedMatch('(', ')', valueParser.stringify(node)); + const nodeText = valueParser.stringify(node); + const parensMatch = balancedMatch('(', ')', nodeText); + + if (!parensMatch) { + throw new Error(`No parens match: "${nodeText}"`); + } + const rawExpression = parensMatch.body; const expressionIndex = decl.source.start.column + diff --git a/lib/utils/FileCache.js b/lib/utils/FileCache.js index d16060bb90..0474a6ce81 100644 --- a/lib/utils/FileCache.js +++ b/lib/utils/FileCache.js @@ -8,6 +8,8 @@ const path = require('path'); const DEFAULT_CACHE_LOCATION = './.stylelintcache'; const DEFAULT_HASH = ''; +/** @typedef {import('file-entry-cache').FileDescriptor["meta"] & { hashOfConfig?: string }} CacheMetadata */ + /** * @param {string} [cacheLocation] * @param {string} [hashOfConfig] @@ -30,6 +32,7 @@ class FileCache { // 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; diff --git a/lib/utils/blurFunctionArguments.js b/lib/utils/blurFunctionArguments.js index f4d9f72497..0f64378e0b 100644 --- a/lib/utils/blurFunctionArguments.js +++ b/lib/utils/blurFunctionArguments.js @@ -33,8 +33,13 @@ module.exports = function (source, functionName, blurChar = '`') { while (lowerCaseSource.includes(nameWithParen, searchStartIndex)) { const openingParenIndex = lowerCaseSource.indexOf(nameWithParen, searchStartIndex) + functionNameLength; - const closingParenIndex = - balancedMatch('(', ')', lowerCaseSource.slice(openingParenIndex)).end + openingParenIndex; + 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 = diff --git a/lib/utils/functionArgumentsSearch.js b/lib/utils/functionArgumentsSearch.js index 88088b126f..fac9aa647a 100644 --- a/lib/utils/functionArgumentsSearch.js +++ b/lib/utils/functionArgumentsSearch.js @@ -31,6 +31,10 @@ module.exports = function (source, functionName, callback) { const parensMatch = balancedMatch('(', ')', source.substr(match.startIndex)); + if (!parensMatch) { + throw new Error(`No parens match: "${source}"`); + } + callback(parensMatch.body, match.endIndex + 1); }, ); diff --git a/lib/writeOutputFile.js b/lib/writeOutputFile.js index 3ab4a4342e..a495f45a1e 100644 --- a/lib/writeOutputFile.js +++ b/lib/writeOutputFile.js @@ -7,7 +7,7 @@ const writeFileAtomic = require('write-file-atomic'); /** * @param {string} content * @param {string} filePath - * @returns {Promise} + * @returns {Promise} */ module.exports = (content, filePath) => writeFileAtomic(path.normalize(filePath), stripAnsi(content)); diff --git a/package-lock.json b/package-lock.json index b746cc9239..e2213632b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -779,6 +779,12 @@ "@babel/types": "^7.3.0" } }, + "@types/balanced-match": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/balanced-match/-/balanced-match-1.0.1.tgz", + "integrity": "sha512-flYjxKu45rRRd//gE2Y3zfVb1rCa4aNHW8fZ68c4Yt++iCBjij7YmraB9DGjsue1RC5pj4+yU50sI5cADCKZRA==", + "dev": true + }, "@types/braces": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/braces/-/braces-3.0.0.tgz", @@ -814,6 +820,15 @@ "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==", "dev": true }, + "@types/file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-WeUjhy7AbHrD8GlhFSMDXlJkZ0aKrwdDg4cEsFDaFeSphMvsCU3eM9LH6pfCRAz1ZPa64WOYLN0Bv8gNBKRB6A==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.2.tgz", @@ -851,6 +866,12 @@ "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==", "dev": true }, + "@types/imurmurhash": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@types/imurmurhash/-/imurmurhash-0.1.1.tgz", + "integrity": "sha512-ThbETc7uxx6rIpNP0fE3bqrSSIeBWPrFY4TzY4WFsvdQYWinub+PLZV/9nT3zicRJJPWbmHqJIsHZHeh5Ad+Ug==", + "dev": true + }, "@types/istanbul-lib-coverage": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", @@ -933,6 +954,15 @@ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, + "@types/postcss-safe-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/postcss-safe-parser/-/postcss-safe-parser-4.0.0.tgz", + "integrity": "sha512-ugodq0ycpehQTRKoVybk7dmaoLDwK5M7nzTdCqlKErfEWIrp0R0UHRL4YEwS/4FIP1lM0rJ68ZCRAQpRc13vWA==", + "dev": true, + "requires": { + "postcss": "^7.0.30" + } + }, "@types/prettier": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.0.1.tgz", @@ -954,11 +984,32 @@ "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", "dev": true }, + "@types/style-search": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@types/style-search/-/style-search-0.1.1.tgz", + "integrity": "sha512-pJOod5SN0d6rTl9d9YMqiFqLY1tMlqaQtpB/2E/SceXCf+Lwn0VVkthe7Ts4Ln3m0USPoY1lqXoyF5c7N2redg==", + "dev": true + }, + "@types/svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha512-PlLI3u2hocS4nbzd9WUzQn/EyFl+NifbssU9QV40XzWOpwf5R7cDod2dmTUKYN7awE9jMrhy9FCO904ZYwaBDw==", + "dev": true + }, "@types/unist": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==" }, + "@types/write-file-atomic": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/write-file-atomic/-/write-file-atomic-3.0.1.tgz", + "integrity": "sha512-o5Pl/qux8JEuFpof5fUg/Fl6R3N26ExJlsmWpB67ayrEJDMIxWdM9NDJacisXeNB7YW+vij8onctH8Pr1Zhi5g==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/yargs": { "version": "15.0.5", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.5.tgz", diff --git a/package.json b/package.json index 2d68c22ee6..9bd6f74bbe 100644 --- a/package.json +++ b/package.json @@ -162,12 +162,19 @@ "devDependencies": { "@stylelint/prettier-config": "^2.0.0", "@stylelint/remark-preset": "^1.0.0", + "@types/balanced-match": "^1.0.1", "@types/browserslist": "^4.8.0", "@types/debug": "^4.1.5", + "@types/file-entry-cache": "^5.0.1", "@types/global-modules": "^2.0.0", "@types/globjoin": "^0.1.0", + "@types/imurmurhash": "^0.1.1", "@types/lodash": "^4.14.155", "@types/micromatch": "^4.0.1", + "@types/postcss-safe-parser": "^4.0.0", + "@types/style-search": "^0.1.1", + "@types/svg-tags": "^1.0.0", + "@types/write-file-atomic": "^3.0.1", "benchmark": "^2.1.4", "common-tags": "^1.8.0", "del": "^5.1.0", diff --git a/types/balanced-match/index.d.ts b/types/balanced-match/index.d.ts deleted file mode 100644 index daf5e78b31..0000000000 --- a/types/balanced-match/index.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -declare module 'balanced-match' { - var def: any; // TODO TYPES - - export = def; -} diff --git a/types/file-entry-cache/index.d.ts b/types/file-entry-cache/index.d.ts deleted file mode 100644 index 99d37a6b15..0000000000 --- a/types/file-entry-cache/index.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -declare module 'file-entry-cache' { - type CacheEntry = any; // TODO TYPES - - export function create(file: string): CacheEntry; -} diff --git a/types/imurmurhash/index.d.ts b/types/imurmurhash/index.d.ts deleted file mode 100644 index 3277fc8589..0000000000 --- a/types/imurmurhash/index.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -declare module 'imurmurhash' { - var result: any; // TODO TYPES - - export = result; -} diff --git a/types/postcss/extensions.d.ts b/types/postcss/extensions.d.ts deleted file mode 100644 index 3e612db517..0000000000 --- a/types/postcss/extensions.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import * as postcss from 'postcss'; -declare module 'postcss' { - interface NodeSource { - lang?: string; - } - - interface Input { - css?: string; - } -} diff --git a/types/style-search/index.d.ts b/types/style-search/index.d.ts deleted file mode 100644 index 77ba994646..0000000000 --- a/types/style-search/index.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -declare function searchFn( - param: { - source: string; - target: string | string[]; - once?: boolean; - comments?: 'skip' | 'check' | 'only'; - strings?: 'skip' | 'check' | 'only'; - functionNames?: 'skip' | 'check' | 'only'; - functionArguments?: 'skip' | 'check' | 'only'; - parentheticals?: 'skip' | 'check' | 'only'; - }, - callback: (param: { startIndex: number; endIndex: number }) => void, -): void; - -declare module 'style-search' { - export = searchFn; -} diff --git a/types/svg-tags/index.d.ts b/types/svg-tags/index.d.ts deleted file mode 100644 index 165bca0cef..0000000000 --- a/types/svg-tags/index.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'svg-tags' { - var def: any; // TODO TYPES - // Export is string[] - - export = def; -} diff --git a/types/svg-tags/postcss-safe-parser.ts b/types/svg-tags/postcss-safe-parser.ts deleted file mode 100644 index 0037a904e1..0000000000 --- a/types/svg-tags/postcss-safe-parser.ts +++ /dev/null @@ -1 +0,0 @@ -declare module 'postcss-safe-parser'; diff --git a/types/write-file-atomic/index.d.ts b/types/write-file-atomic/index.d.ts deleted file mode 100644 index 90c55572c5..0000000000 --- a/types/write-file-atomic/index.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -declare namespace writeFile { - interface Options { - chown?: { - uid: number; - gid: number; - }; - encoding?: string; - fsync?: boolean; - mode?: number; - } -} - -declare function writeFileAsync( - filename: string, - data: string | Buffer, - options?: writeFile.Options, -): Promise; - -declare module 'write-file-atomic' { - export = writeFileAsync; -} From 5a942941920b3aa99a81f5ac6385bf5b0bd492ca Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2020 15:03:14 +0200 Subject: [PATCH 2/6] Bump lodash from 4.17.15 to 4.17.19 (#4864) Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index e2213632b8..ebdb4bd76b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5777,9 +5777,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" }, "lodash.sortby": { "version": "4.7.0", diff --git a/package.json b/package.json index 9bd6f74bbe..286eee4dd0 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "imurmurhash": "^0.1.4", "known-css-properties": "^0.19.0", "leven": "^3.1.0", - "lodash": "^4.17.15", + "lodash": "^4.17.19", "log-symbols": "^4.0.0", "mathml-tag-names": "^2.1.3", "meow": "^7.0.1", From cecacb9d4fe3b5bae5f264efa6e60c414a0f4946 Mon Sep 17 00:00:00 2001 From: Masafumi Koba <473530+ybiquitous@users.noreply.github.com> Date: Fri, 17 Jul 2020 21:36:54 +0900 Subject: [PATCH 3/6] Remove `postcss-reporter` package (#4858) * Remove `postcss-reporter` package This change removes the `postcss-reporter` package and reduces the dependencies. As you see the changed `package-lock.json`, this package depends on: - `chalk` - `lodash` - `log-symbols` - `postcss` See also https://github.com/stylelint/stylelint/issues/2454#issuecomment-622604821 We've used only the tiny utility function `getLocation()` in the package. This function just returns an object with the `line` and `column` property in our project, so I think we can replace it with a simple code. https://github.com/postcss/postcss-reporter/blob/f01a601ea2cd41d626e561969d66a765b3afcb2d/lib/util.js#L4-L13 * Fix test name: `stringFormatter` -> `verboseFormatter` --- .../__tests__/verboseFormatter.test.js | 2 +- lib/formatters/stringFormatter.js | 7 ++--- package-lock.json | 31 ------------------- package.json | 1 - types/postcss/index.d.ts | 4 --- 5 files changed, 4 insertions(+), 41 deletions(-) diff --git a/lib/formatters/__tests__/verboseFormatter.test.js b/lib/formatters/__tests__/verboseFormatter.test.js index af58772952..6a98b8c4b8 100644 --- a/lib/formatters/__tests__/verboseFormatter.test.js +++ b/lib/formatters/__tests__/verboseFormatter.test.js @@ -4,7 +4,7 @@ const prepareFormatterOutput = require('./prepareFormatterOutput'); const stripIndent = require('common-tags').stripIndent; const verboseFormatter = require('../verboseFormatter'); -describe('stringFormatter', () => { +describe('verboseFormatter', () => { it('outputs no warnings', () => { const results = [ { diff --git a/lib/formatters/stringFormatter.js b/lib/formatters/stringFormatter.js index 7047f2b595..5896827be8 100644 --- a/lib/formatters/stringFormatter.js +++ b/lib/formatters/stringFormatter.js @@ -6,7 +6,6 @@ const path = require('path'); const stringWidth = require('string-width'); const symbols = require('log-symbols'); const table = require('table'); -const utils = require('postcss-reporter/lib/util'); const MARGIN_WIDTHS = 9; @@ -134,14 +133,14 @@ function formatter(messages, source) { } const cleanedMessages = orderedMessages.map((message) => { - const location = utils.getLocation(message); + const { line, column } = message; const severity = /** @type {keyof import('log-symbols')} */ (message.severity); /** * @type {[string, string, string, string, string]} */ const row = [ - location.line ? location.line.toString() : '', - location.column ? location.column.toString() : '', + line ? line.toString() : '', + column ? column.toString() : '', symbols[severity] ? chalk[/** @type {'blue' | 'red' | 'yellow'} */ (levelColors[severity])](symbols[severity]) : severity, diff --git a/package-lock.json b/package-lock.json index ebdb4bd76b..68e48e97fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7520,37 +7520,6 @@ "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", "integrity": "sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ=" }, - "postcss-reporter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-6.0.1.tgz", - "integrity": "sha512-LpmQjfRWyabc+fRygxZjpRxfhRf9u/fdlKf4VHG4TSPbV2XNsuISzYW1KL+1aQzx53CAppa1bKG4APIB/DOXXw==", - "requires": { - "chalk": "^2.4.1", - "lodash": "^4.17.11", - "log-symbols": "^2.2.0", - "postcss": "^7.0.7" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "requires": { - "chalk": "^2.0.1" - } - } - } - }, "postcss-resolve-nested-selector": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz", diff --git a/package.json b/package.json index 286eee4dd0..40bb041b32 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,6 @@ "postcss-html": "^0.36.0", "postcss-less": "^3.1.4", "postcss-media-query-parser": "^0.2.3", - "postcss-reporter": "^6.0.1", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^4.0.2", "postcss-sass": "^0.4.4", diff --git a/types/postcss/index.d.ts b/types/postcss/index.d.ts index a8084ba565..5173bd4af7 100644 --- a/types/postcss/index.d.ts +++ b/types/postcss/index.d.ts @@ -33,10 +33,6 @@ declare module 'postcss-syntax' { export = result; } -declare module 'postcss-reporter/lib/util' { - export function getLocation(message: Object): { line: number; column: number; file?: string }; -} - declare module 'postcss/lib/result' { import { Result } from 'postcss'; From c935d0ac6538e7e4999b17b68a18ef0fe71851f5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 22 Jul 2020 10:07:25 +0100 Subject: [PATCH 4/6] Bump @types/lodash from 4.14.155 to 4.14.157 (#4869) Bumps [@types/lodash](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/lodash) from 4.14.155 to 4.14.157. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/lodash) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 68e48e97fe..cc6d50e2fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -913,9 +913,9 @@ } }, "@types/lodash": { - "version": "4.14.155", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.155.tgz", - "integrity": "sha512-vEcX7S7aPhsBCivxMwAANQburHBtfN9RdyXFk84IJmu2Z4Hkg1tOFgaslRiEqqvoLtbCBi6ika1EMspE+NZ9Lg==", + "version": "4.14.157", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.157.tgz", + "integrity": "sha512-Ft5BNFmv2pHDgxV5JDsndOWTRJ+56zte0ZpYLowp03tW+K+t8u8YMOzAnpuqPgzX6WO1XpDIUm7u04M8vdDiVQ==", "dev": true }, "@types/micromatch": { diff --git a/package.json b/package.json index 40bb041b32..3f5498a278 100644 --- a/package.json +++ b/package.json @@ -168,7 +168,7 @@ "@types/global-modules": "^2.0.0", "@types/globjoin": "^0.1.0", "@types/imurmurhash": "^0.1.1", - "@types/lodash": "^4.14.155", + "@types/lodash": "^4.14.157", "@types/micromatch": "^4.0.1", "@types/postcss-safe-parser": "^4.0.0", "@types/style-search": "^0.1.1", From cba8dcfa4ff3a5733016c34007cb64a19d863662 Mon Sep 17 00:00:00 2001 From: Matt Wang Date: Thu, 23 Jul 2020 02:28:39 -0700 Subject: [PATCH 5/6] Fix false negatives for where, is, nth-child and nth-last-child in selector-max-* (except selector-max-type) (#4842) * updates keywordSets * replaces functionality of isLogicalCombination with isContextFunctionalPseudoClass note: possible logic error in selector-max-type, will investigate further * adds a check for nonstandard syntax type selectors to selector-max-type * Apply suggestions from code review minor documentation fixes! Co-authored-by: Richard Hallows Co-authored-by: Richard Hallows --- lib/reference/keywordSets.js | 12 ++--- lib/rules/selector-max-attribute/index.js | 6 +-- lib/rules/selector-max-class/index.js | 6 +-- .../selector-max-compound-selectors/index.js | 6 +-- lib/rules/selector-max-id/index.js | 6 +-- lib/rules/selector-max-pseudo-class/index.js | 6 +-- lib/rules/selector-max-type/index.js | 11 +++-- .../isContextFunctionalPseudoClass.test.js | 48 +++++++++++++++++++ .../__tests__/isLogicalCombination.test.js | 39 --------------- lib/utils/isContextFunctionalPseudoClass.js | 23 +++++++++ lib/utils/isLogicalCombination.js | 22 --------- lib/utils/isStandardSyntaxTypeSelector.js | 1 + 12 files changed, 101 insertions(+), 85 deletions(-) create mode 100644 lib/utils/__tests__/isContextFunctionalPseudoClass.test.js delete mode 100644 lib/utils/__tests__/isLogicalCombination.test.js create mode 100644 lib/utils/isContextFunctionalPseudoClass.js delete mode 100644 lib/utils/isLogicalCombination.js diff --git a/lib/reference/keywordSets.js b/lib/reference/keywordSets.js index 0fdf90ffc2..52f4a718d5 100644 --- a/lib/reference/keywordSets.js +++ b/lib/reference/keywordSets.js @@ -208,9 +208,7 @@ keywordSets.pseudoElements = uniteSets( ); keywordSets.aNPlusBNotationPseudoClasses = new Set([ - 'nth-child', 'nth-column', - 'nth-last-child', 'nth-last-column', 'nth-last-of-type', 'nth-of-type', @@ -220,6 +218,10 @@ keywordSets.linguisticPseudoClasses = new Set(['dir', 'lang']); keywordSets.atRulePagePseudoClasses = new Set(['first', 'right', 'left', 'blank']); +keywordSets.logicalCombinationsPseudoClasses = new Set(['has', 'is', 'matches', 'not', 'where']); + +keywordSets.aNPlusBOfSNotationPseudoClasses = new Set(['nth-child', 'nth-last-child']); + keywordSets.otherPseudoClasses = new Set([ 'active', 'any-link', @@ -241,19 +243,15 @@ keywordSets.otherPseudoClasses = new Set([ 'focus-visible', 'fullscreen', 'future', - 'has', 'host', 'host-context', 'hover', 'indeterminate', 'in-range', 'invalid', - 'is', 'last-child', 'last-of-type', 'link', - 'matches', - 'not', 'only-child', 'only-of-type', 'optional', @@ -302,6 +300,8 @@ keywordSets.webkitProprietaryPseudoClasses = new Set([ keywordSets.pseudoClasses = uniteSets( keywordSets.aNPlusBNotationPseudoClasses, keywordSets.linguisticPseudoClasses, + keywordSets.logicalCombinationsPseudoClasses, + keywordSets.aNPlusBOfSNotationPseudoClasses, keywordSets.otherPseudoClasses, ); diff --git a/lib/rules/selector-max-attribute/index.js b/lib/rules/selector-max-attribute/index.js index c344139628..f0a4f9c3c6 100644 --- a/lib/rules/selector-max-attribute/index.js +++ b/lib/rules/selector-max-attribute/index.js @@ -3,7 +3,7 @@ 'use strict'; const _ = require('lodash'); -const isLogicalCombination = require('../../utils/isLogicalCombination'); +const isContextFunctionalPseudoClass = require('../../utils/isContextFunctionalPseudoClass'); const isStandardSyntaxRule = require('../../utils/isStandardSyntaxRule'); const optionsMatches = require('../../utils/optionsMatches'); const parseSelector = require('../../utils/parseSelector'); @@ -49,8 +49,8 @@ function rule(max, options) { function checkSelector(selectorNode, ruleNode) { const count = selectorNode.reduce((total, childNode) => { - // Only traverse inside actual selectors and logical combinations - if (childNode.type === 'selector' || isLogicalCombination(childNode)) { + // Only traverse inside actual selectors and context functional pseudo-classes + if (childNode.type === 'selector' || isContextFunctionalPseudoClass(childNode)) { checkSelector(childNode, ruleNode); } diff --git a/lib/rules/selector-max-class/index.js b/lib/rules/selector-max-class/index.js index b48a9a5b8a..8e08e1a4ed 100644 --- a/lib/rules/selector-max-class/index.js +++ b/lib/rules/selector-max-class/index.js @@ -2,7 +2,7 @@ 'use strict'; -const isLogicalCombination = require('../../utils/isLogicalCombination'); +const isContextFunctionalPseudoClass = require('../../utils/isContextFunctionalPseudoClass'); const isStandardSyntaxRule = require('../../utils/isStandardSyntaxRule'); const parseSelector = require('../../utils/parseSelector'); const report = require('../../utils/report'); @@ -34,8 +34,8 @@ function rule(max) { function checkSelector(selectorNode, ruleNode) { const count = selectorNode.reduce((total, childNode) => { - // Only traverse inside actual selectors and logical combinations - if (childNode.type === 'selector' || isLogicalCombination(childNode)) { + // Only traverse inside actual selectors and context functional pseudo-classes + if (childNode.type === 'selector' || isContextFunctionalPseudoClass(childNode)) { checkSelector(childNode, ruleNode); } diff --git a/lib/rules/selector-max-compound-selectors/index.js b/lib/rules/selector-max-compound-selectors/index.js index febfddf17a..92ed6145ec 100644 --- a/lib/rules/selector-max-compound-selectors/index.js +++ b/lib/rules/selector-max-compound-selectors/index.js @@ -2,7 +2,7 @@ 'use strict'; -const isLogicalCombination = require('../../utils/isLogicalCombination'); +const isContextFunctionalPseudoClass = require('../../utils/isContextFunctionalPseudoClass'); const isStandardSyntaxRule = require('../../utils/isStandardSyntaxRule'); const parseSelector = require('../../utils/parseSelector'); const report = require('../../utils/report'); @@ -39,8 +39,8 @@ function rule(max) { let compoundCount = 1; selectorNode.each((childNode) => { - // Only traverse inside actual selectors and logical combinations - if (childNode.type === 'selector' || isLogicalCombination(childNode)) { + // Only traverse inside actual selectors and context functional pseudo-classes + if (childNode.type === 'selector' || isContextFunctionalPseudoClass(childNode)) { checkSelector(childNode, rule); } diff --git a/lib/rules/selector-max-id/index.js b/lib/rules/selector-max-id/index.js index bf608bb3dc..91555fe03d 100644 --- a/lib/rules/selector-max-id/index.js +++ b/lib/rules/selector-max-id/index.js @@ -3,7 +3,7 @@ 'use strict'; const _ = require('lodash'); -const isLogicalCombination = require('../../utils/isLogicalCombination'); +const isContextFunctionalPseudoClass = require('../../utils/isContextFunctionalPseudoClass'); const isStandardSyntaxRule = require('../../utils/isStandardSyntaxRule'); const optionsMatches = require('../../utils/optionsMatches'); const parseSelector = require('../../utils/parseSelector'); @@ -47,10 +47,10 @@ function rule(max, options) { function checkSelector(selectorNode, ruleNode) { const count = selectorNode.reduce((total, childNode) => { - // Only traverse inside actual selectors and logical combinations that are not part of ignored functional pseudo-classes + // Only traverse inside actual selectors and context functional pseudo-classes that are not part of ignored functional pseudo-classes if ( childNode.type === 'selector' || - (isLogicalCombination(childNode) && + (isContextFunctionalPseudoClass(childNode) && !isIgnoredContextFunctionalPseudoClass(childNode, options)) ) { checkSelector(childNode, ruleNode); diff --git a/lib/rules/selector-max-pseudo-class/index.js b/lib/rules/selector-max-pseudo-class/index.js index 0d73785815..fc8d581a98 100644 --- a/lib/rules/selector-max-pseudo-class/index.js +++ b/lib/rules/selector-max-pseudo-class/index.js @@ -2,7 +2,7 @@ 'use strict'; -const isLogicalCombination = require('../../utils/isLogicalCombination'); +const isContextFunctionalPseudoClass = require('../../utils/isContextFunctionalPseudoClass'); const isStandardSyntaxRule = require('../../utils/isStandardSyntaxRule'); const keywordSets = require('../../reference/keywordSets'); const parseSelector = require('../../utils/parseSelector'); @@ -35,8 +35,8 @@ function rule(max) { function checkSelector(selectorNode, ruleNode) { const count = selectorNode.reduce((total, childNode) => { - // Only traverse inside actual selectors and logical combinations - if (childNode.type === 'selector' || isLogicalCombination(childNode)) { + // Only traverse inside actual selectors and context functional pseudo-classes + if (childNode.type === 'selector' || isContextFunctionalPseudoClass(childNode)) { checkSelector(childNode, ruleNode); } diff --git a/lib/rules/selector-max-type/index.js b/lib/rules/selector-max-type/index.js index 05bc10ab5a..0b4502c660 100644 --- a/lib/rules/selector-max-type/index.js +++ b/lib/rules/selector-max-type/index.js @@ -3,11 +3,12 @@ 'use strict'; const _ = require('lodash'); +const isContextFunctionalPseudoClass = require('../../utils/isContextFunctionalPseudoClass'); const isKeyframeSelector = require('../../utils/isKeyframeSelector'); -const isLogicalCombination = require('../../utils/isLogicalCombination'); const isOnlyWhitespace = require('../../utils/isOnlyWhitespace'); const isStandardSyntaxRule = require('../../utils/isStandardSyntaxRule'); const isStandardSyntaxSelector = require('../../utils/isStandardSyntaxSelector'); +const isStandardSyntaxTypeSelector = require('../../utils/isStandardSyntaxTypeSelector'); const optionsMatches = require('../../utils/optionsMatches'); const parseSelector = require('../../utils/parseSelector'); const report = require('../../utils/report'); @@ -56,8 +57,8 @@ function rule(max, options) { function checkSelector(selectorNode, ruleNode) { const count = selectorNode.reduce((total, childNode) => { - // Only traverse inside actual selectors and logical combinations - if (childNode.type === 'selector' || isLogicalCombination(childNode)) { + // Only traverse inside actual selectors and context functional pseudo-classes + if (childNode.type === 'selector' || isContextFunctionalPseudoClass(childNode)) { checkSelector(childNode, ruleNode); } @@ -81,6 +82,10 @@ function rule(max, options) { return total; } + if (childNode.type === 'tag' && !isStandardSyntaxTypeSelector(childNode)) { + return total; + } + return total + (childNode.type === 'tag'); }, 0); diff --git a/lib/utils/__tests__/isContextFunctionalPseudoClass.test.js b/lib/utils/__tests__/isContextFunctionalPseudoClass.test.js new file mode 100644 index 0000000000..f3f506128b --- /dev/null +++ b/lib/utils/__tests__/isContextFunctionalPseudoClass.test.js @@ -0,0 +1,48 @@ +'use strict'; + +const isContextFunctionalPseudoClass = require('../isContextFunctionalPseudoClass'); +const parseSelector = require('postcss-selector-parser'); +const postcss = require('postcss'); + +function selector(css, cb) { + postcss.parse(css).walkRules((rule) => { + parseSelector((selectorAST) => { + selectorAST.walkPseudos(cb); + }).processSync(rule.selector); + }); +} + +describe('isContextFunctionalPseudoClass', () => { + it('handles non-context-functional pseudo-classes, like hover', () => { + selector('a:hover {}', (selector) => { + expect(isContextFunctionalPseudoClass(selector)).toBe(false); + }); + }); + + it('handles logical combinations, ', () => { + selector('a:has(.foo) {}', (selector) => { + expect(isContextFunctionalPseudoClass(selector)).toBe(true); + }); + selector('a:is(.foo) {}', (selector) => { + expect(isContextFunctionalPseudoClass(selector)).toBe(true); + }); + selector('a:matches(.foo) {}', (selector) => { + expect(isContextFunctionalPseudoClass(selector)).toBe(true); + }); + selector('a:not(.foo) {}', (selector) => { + expect(isContextFunctionalPseudoClass(selector)).toBe(true); + }); + selector('a:where(.foo) {}', (selector) => { + expect(isContextFunctionalPseudoClass(selector)).toBe(true); + }); + }); + + it('handles tree structural/NPlusBOfSNotationPseudoClasses classes', () => { + selector('a:nth-child(n+7) {}', (selector) => { + expect(isContextFunctionalPseudoClass(selector)).toBe(true); + }); + selector('a:nth-last-child(n+7) {}', (selector) => { + expect(isContextFunctionalPseudoClass(selector)).toBe(true); + }); + }); +}); diff --git a/lib/utils/__tests__/isLogicalCombination.test.js b/lib/utils/__tests__/isLogicalCombination.test.js deleted file mode 100644 index 33e64ef749..0000000000 --- a/lib/utils/__tests__/isLogicalCombination.test.js +++ /dev/null @@ -1,39 +0,0 @@ -'use strict'; - -const isLogicalCombination = require('../isLogicalCombination'); -const parseSelector = require('postcss-selector-parser'); -const postcss = require('postcss'); - -function selector(css, cb) { - postcss.parse(css).walkRules((rule) => { - parseSelector((selectorAST) => { - selectorAST.walkPseudos(cb); - }).processSync(rule.selector); - }); -} - -describe('isLogicalCombination', () => { - it('hover pseudo class is NOT logical combination', () => { - selector('a:hover {}', (selector) => { - expect(isLogicalCombination(selector)).toBe(false); - }); - }); - - it('not pseudo class is logical combination', () => { - selector('a:not(.foo) {}', (selector) => { - expect(isLogicalCombination(selector)).toBe(true); - }); - }); - - it('has pseudo class is logical combination', () => { - selector('a:has(.foo) {}', (selector) => { - expect(isLogicalCombination(selector)).toBe(true); - }); - }); - - it('matches pseudo class is logical combination', () => { - selector('a:matches(.foo) {}', (selector) => { - expect(isLogicalCombination(selector)).toBe(true); - }); - }); -}); diff --git a/lib/utils/isContextFunctionalPseudoClass.js b/lib/utils/isContextFunctionalPseudoClass.js new file mode 100644 index 0000000000..4fcca055bb --- /dev/null +++ b/lib/utils/isContextFunctionalPseudoClass.js @@ -0,0 +1,23 @@ +'use strict'; + +const keywordSets = require('../reference/keywordSets'); + +/** + * 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').Pseudo} node postcss-selector-parser node (of type pseudo) + * @return {boolean} 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 ( + keywordSets.logicalCombinationsPseudoClasses.has(normalisedParentName) || + keywordSets.aNPlusBOfSNotationPseudoClasses.has(normalisedParentName) + ); + } + + return false; +}; diff --git a/lib/utils/isLogicalCombination.js b/lib/utils/isLogicalCombination.js deleted file mode 100644 index cd92885eec..0000000000 --- a/lib/utils/isLogicalCombination.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; - -/** - * Check whether a node is logical combination (`:not`, `:has`, `:matches`) - * - * @param {import('postcss-selector-parser').Pseudo} node postcss-selector-parser node (of type pseudo) - * @return {boolean} If `true`, the combination is logical - */ -module.exports = function isLogicalCombination(node) { - if (node.type === 'pseudo') { - switch (node.value) { - case ':not': - case ':has': - case ':matches': - return true; - default: - return false; - } - } - - return false; -}; diff --git a/lib/utils/isStandardSyntaxTypeSelector.js b/lib/utils/isStandardSyntaxTypeSelector.js index 1275676272..3bf35e4bf5 100644 --- a/lib/utils/isStandardSyntaxTypeSelector.js +++ b/lib/utils/isStandardSyntaxTypeSelector.js @@ -27,6 +27,7 @@ module.exports = function (node) { if ( parentType === 'pseudo' && (keywordSets.aNPlusBNotationPseudoClasses.has(normalisedParentName) || + keywordSets.aNPlusBOfSNotationPseudoClasses.has(normalisedParentName) || keywordSets.linguisticPseudoClasses.has(normalisedParentName) || keywordSets.shadowTreePseudoElements.has(normalisedParentName)) ) { From ac0519d65847c719dc04f53c584ec7f82f3720d2 Mon Sep 17 00:00:00 2001 From: Mike Allanson Date: Thu, 23 Jul 2020 10:30:50 +0100 Subject: [PATCH 6/6] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6494cb85b8..f31248903d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to this project are documented in this file. - Added: `*-allowed-list`, `*-disallowed-list` and `*-required-list` new names for `*-whitelist`, `*-blacklist` and `*-requirelist` rules, respectively; the rules are aliased as their old names ([#4845](https://github.com/stylelint/stylelint/pull/4845)). - Added: `ignoreContextFunctionalPseudoClasses` to `selector-max-id` ([#4835](https://github.com/stylelint/stylelint/pull/4835)). - Added: `ignoreComments[]` to `comment-empty-line-before` ([#4841](https://github.com/stylelint/stylelint/pull/4841)). +- Fixed: false negatives for `where`, `is`, `nth-child` and `nth-last-child` in `selector-max-*` rules (except selector-max-type) ([#4842](https://github.com/stylelint/stylelint/pull/4842)). ## 13.6.1