chore: implement use-using rule (#10798)

This commit is contained in:
jrandolf 2023-08-29 21:41:29 +02:00 committed by GitHub
parent 085936bd7e
commit dca327f99f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 214 additions and 22 deletions

View File

@ -1,3 +1,6 @@
const rulesDirPlugin = require('eslint-plugin-rulesdir');
rulesDirPlugin.RULES_DIR = 'tools/eslint/lib';
module.exports = {
root: true,
env: {
@ -136,10 +139,12 @@ module.exports = {
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/stylistic',
],
plugins: ['eslint-plugin-tsdoc', 'local'],
plugins: ['eslint-plugin-tsdoc', 'rulesdir'],
rules: {
// Keeps comments formatted.
'local/prettier-comments': 'error',
'rulesdir/prettier-comments': 'error',
// Enforces clean up of used resources.
'rulesdir/use-using': 'off',
// Brackets keep code readable.
curly: ['error', 'all'],
// Brackets keep code readable and `return` intentions clear.

53
package-lock.json generated
View File

@ -9,7 +9,8 @@
"workspaces": [
"packages/*",
"test",
"test/installation"
"test/installation",
"tools/eslint"
],
"devDependencies": {
"@actions/core": "1.10.0",
@ -45,9 +46,9 @@
"eslint-config-prettier": "9.0.0",
"eslint-formatter-codeframe": "7.32.1",
"eslint-plugin-import": "2.28.1",
"eslint-plugin-local": "1.0.0",
"eslint-plugin-mocha": "10.1.0",
"eslint-plugin-prettier": "5.0.0",
"eslint-plugin-rulesdir": "0.2.2",
"eslint-plugin-tsdoc": "0.2.17",
"eslint-plugin-unused-imports": "3.0.0",
"esprima": "4.0.1",
@ -80,6 +81,12 @@
"zod": "3.22.2"
}
},
"eslint": {
"name": "@puppeteer/eslint",
"version": "0.1.0",
"extraneous": true,
"license": "Apache-2.0"
},
"node_modules/@aashutoshrathi/word-wrap": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
@ -1873,6 +1880,10 @@
"resolved": "packages/browsers",
"link": true
},
"node_modules/@puppeteer/eslint": {
"resolved": "tools/eslint",
"link": true
},
"node_modules/@puppeteer/ng-schematics": {
"resolved": "packages/ng-schematics",
"link": true
@ -4523,11 +4534,6 @@
"semver": "bin/semver.js"
}
},
"node_modules/eslint-plugin-local": {
"version": "1.0.0",
"dev": true,
"license": "MIT"
},
"node_modules/eslint-plugin-mocha": {
"version": "10.1.0",
"dev": true,
@ -4622,6 +4628,15 @@
}
}
},
"node_modules/eslint-plugin-rulesdir": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-rulesdir/-/eslint-plugin-rulesdir-0.2.2.tgz",
"integrity": "sha512-qhBtmrWgehAIQeMDJ+Q+PnOz1DWUZMPeVrI0wE9NZtnpIMFUfh3aPKFYt2saeMSemZRrvUtjWfYwepsC8X+mjQ==",
"dev": true,
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/eslint-plugin-tsdoc": {
"version": "0.2.17",
"dev": true,
@ -11191,6 +11206,12 @@
"ws": "8.13.0"
}
},
"packages/ts-plugin": {
"name": "@puppeteer/ts-plugin",
"version": "0.1.0",
"extraneous": true,
"license": "Apache-2.0"
},
"test": {
"name": "@puppeteer-test/test",
"version": "latest",
@ -11205,6 +11226,11 @@
"glob": "10.3.3",
"mocha": "10.2.0"
}
},
"tools/eslint": {
"name": "@puppeteer/eslint",
"version": "0.1.0",
"license": "Apache-2.0"
}
},
"dependencies": {
@ -12367,6 +12393,9 @@
}
}
},
"@puppeteer/eslint": {
"version": "file:tools/eslint"
},
"@puppeteer/ng-schematics": {
"version": "file:packages/ng-schematics",
"requires": {
@ -14304,10 +14333,6 @@
}
}
},
"eslint-plugin-local": {
"version": "1.0.0",
"dev": true
},
"eslint-plugin-mocha": {
"version": "10.1.0",
"dev": true,
@ -14357,6 +14382,12 @@
"synckit": "^0.8.5"
}
},
"eslint-plugin-rulesdir": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-rulesdir/-/eslint-plugin-rulesdir-0.2.2.tgz",
"integrity": "sha512-qhBtmrWgehAIQeMDJ+Q+PnOz1DWUZMPeVrI0wE9NZtnpIMFUfh3aPKFYt2saeMSemZRrvUtjWfYwepsC8X+mjQ==",
"dev": true
},
"eslint-plugin-tsdoc": {
"version": "0.2.17",
"dev": true,

View File

@ -22,6 +22,7 @@
"lint:prettier": "prettier --check .",
"lint": "run-s lint:prettier lint:eslint",
"postinstall": "npm run postinstall --workspaces --if-present",
"prepare": "npm run prepare --workspaces --if-present",
"test-install": "npm run test --workspace @puppeteer-test/installation",
"test-types": "tsd -t packages/puppeteer",
"test:chrome:headful": "wireit",
@ -137,7 +138,7 @@
"eslint-config-prettier": "9.0.0",
"eslint-formatter-codeframe": "7.32.1",
"eslint-plugin-import": "2.28.1",
"eslint-plugin-local": "1.0.0",
"eslint-plugin-rulesdir": "0.2.2",
"eslint-plugin-mocha": "10.1.0",
"eslint-plugin-prettier": "5.0.0",
"eslint-plugin-tsdoc": "0.2.17",
@ -174,6 +175,7 @@
"workspaces": [
"packages/*",
"test",
"test/installation"
"test/installation",
"tools/eslint"
]
}

34
tools/eslint/package.json Normal file
View File

@ -0,0 +1,34 @@
{
"name": "@puppeteer/eslint",
"version": "0.1.0",
"private": true,
"type": "commonjs",
"repository": {
"type": "git",
"url": "https://github.com/puppeteer/puppeteer/tree/main/tools/eslint"
},
"scripts": {
"build": "wireit",
"prepare": "wireit"
},
"wireit": {
"build": {
"command": "tsc -b",
"clean": "if-file-deleted",
"files": [
"src/**"
],
"output": [
"lib/**",
"tsconfig.tsbuildinfo"
]
},
"prepare": {
"dependencies": [
"build"
]
}
},
"author": "The Chromium Authors",
"license": "Apache-2.0"
}

View File

@ -1,5 +1,26 @@
/**
* Copyright 2023 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-nocheck
// TODO: We should convert this to types.
const prettier = require('@prettier/sync');
const prettierConfig = require('./.prettierrc.cjs');
const prettierConfigPath = '../../../.prettierrc.cjs';
const prettierConfig = require(prettierConfigPath);
const cleanupBlockComment = value => {
return value
@ -46,7 +67,7 @@ const buildBlockComment = (value, offset) => {
/**
* @type import("eslint").Rule.RuleModule
*/
const rule = {
const prettierCommentsRule = {
meta: {
type: 'suggestion',
docs: {
@ -85,8 +106,4 @@ const rule = {
},
};
module.exports = {
rules: {
'prettier-comments': rule,
},
};
module.exports = prettierCommentsRule;

View File

@ -0,0 +1,89 @@
/**
* Copyright 2023 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {ESLintUtils, TSESTree} from '@typescript-eslint/utils';
import type {
RuleListener,
RuleModule,
} from '@typescript-eslint/utils/ts-eslint';
const usingSymbols = ['ElementHandle', 'JSHandle'];
const createRule = ESLintUtils.RuleCreator(name => {
return `https://github.com/puppeteer/puppeteer/tree/main/tools/eslint/${name}.js`;
});
const useUsingRule: RuleModule<'useUsing', [], RuleListener> = createRule<
[],
'useUsing'
>({
name: 'use-using',
meta: {
docs: {
description: "Requires 'using' for element/JS handles.",
requiresTypeChecking: true,
},
messages: {
useUsing: "Use 'using'.",
},
schema: [],
type: 'problem',
},
defaultOptions: [],
create(context) {
const services = ESLintUtils.getParserServices(context);
const checker = services.program.getTypeChecker();
return {
VariableDeclaration(node): void {
if (['using', 'await using'].includes(node.kind)) {
return;
}
for (const declaration of node.declarations) {
if (declaration.id.type === TSESTree.AST_NODE_TYPES.Identifier) {
const tsNode = services.esTreeNodeToTSNodeMap.get(declaration.id);
const type = checker.getTypeAtLocation(tsNode);
let isElementHandleReference = false;
if (type.isUnionOrIntersection()) {
for (const member of type.types) {
if (
member.symbol !== undefined &&
usingSymbols.includes(member.symbol.escapedName as string)
) {
isElementHandleReference = true;
break;
}
}
} else {
isElementHandleReference =
type.symbol !== undefined
? usingSymbols.includes(type.symbol.escapedName as string)
: false;
}
if (isElementHandleReference) {
context.report({
node: declaration.id,
messageId: 'useUsing',
});
}
}
}
},
};
},
});
export = useUsingRule;

View File

@ -0,0 +1,14 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "NodeNext",
"rootDir": "./src",
"outDir": "./lib",
"declaration": false,
"declarationMap": false,
"sourceMap": false,
"composite": false,
"removeComments": true
}
}