diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /remote/test/puppeteer/tools/eslint/src | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'remote/test/puppeteer/tools/eslint/src')
4 files changed, 315 insertions, 0 deletions
diff --git a/remote/test/puppeteer/tools/eslint/src/check-license.ts b/remote/test/puppeteer/tools/eslint/src/check-license.ts new file mode 100644 index 0000000000..7ae1a54384 --- /dev/null +++ b/remote/test/puppeteer/tools/eslint/src/check-license.ts @@ -0,0 +1,83 @@ +/** + * @license + * Copyright 2024 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import type {TSESTree} from '@typescript-eslint/utils'; +import {ESLintUtils} from '@typescript-eslint/utils'; + +const createRule = ESLintUtils.RuleCreator(name => { + return `https://github.com/puppeteer/puppeteer/tree/main/tools/eslint/${name}.ts`; +}); + +const copyrightPattern = /Copyright ([0-9]{4}) Google Inc\./; + +// const currentYear = new Date().getFullYear; + +// const licenseHeader = `/** +// * @license +// * Copyright ${currentYear} Google Inc. +// * SPDX-License-Identifier: Apache-2.0 +// */`; + +const enforceLicenseRule = createRule<[], 'licenseRule'>({ + name: 'check-license', + meta: { + type: 'layout', + docs: { + description: 'Validate existence of license header', + requiresTypeChecking: false, + }, + fixable: undefined, // TODO: change to 'code' once fixer works. + schema: [], + messages: { + licenseRule: 'Add license header.', + }, + }, + defaultOptions: [], + create(context) { + const sourceCode = context.sourceCode; + const comments = sourceCode.getAllComments(); + const header = + comments[0]?.type === 'Block' && isHeaderComment(comments[0]) + ? comments[0] + : null; + + function isHeaderComment(comment: TSESTree.Comment) { + if (comment && comment.range[0] >= 0 && comment.range[1] <= 88) { + return true; + } else { + return false; + } + } + + return { + Program(node) { + if ( + header && + header.value.includes('@license') && + header.value.includes('SPDX-License-Identifier: Apache-2.0') && + copyrightPattern.test(header.value) + ) { + return; + } + + // Add header license + if (!header || !header.value.includes('@license')) { + // const startLoc: [number, number] = [0, 88]; + context.report({ + node: node, + messageId: 'licenseRule', + // TODO: fix the fixer. + // fix(fixer) { + // return fixer.insertTextBeforeRange(startLoc, licenseHeader); + // }, + }); + } + }, + }; + }, +}); + +export = enforceLicenseRule; diff --git a/remote/test/puppeteer/tools/eslint/src/extensions.ts b/remote/test/puppeteer/tools/eslint/src/extensions.ts new file mode 100644 index 0000000000..89b9279625 --- /dev/null +++ b/remote/test/puppeteer/tools/eslint/src/extensions.ts @@ -0,0 +1,48 @@ +/** + * @license + * Copyright 2023 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import {ESLintUtils} from '@typescript-eslint/utils'; + +const createRule = ESLintUtils.RuleCreator(name => { + return `https://github.com/puppeteer/puppeteer/tree/main/tools/eslint/${name}.js`; +}); + +const enforceExtensionRule = createRule<[], 'extensionsRule'>({ + name: 'extensions', + meta: { + docs: { + description: 'Requires `.js` for imports', + requiresTypeChecking: false, + }, + messages: { + extensionsRule: 'Add `.js` to import.', + }, + schema: [], + fixable: 'code', + type: 'problem', + }, + defaultOptions: [], + create(context) { + return { + ImportDeclaration(node): void { + const file = node.source.value.split('/').pop(); + + if (!node.source.value.startsWith('.') || file?.includes('.')) { + return; + } + context.report({ + node: node.source, + messageId: 'extensionsRule', + fix(fixer) { + return fixer.replaceText(node.source, `'${node.source.value}.js'`); + }, + }); + }, + }; + }, +}); + +export = enforceExtensionRule; diff --git a/remote/test/puppeteer/tools/eslint/src/prettier-comments.js b/remote/test/puppeteer/tools/eslint/src/prettier-comments.js new file mode 100644 index 0000000000..3cbaad2909 --- /dev/null +++ b/remote/test/puppeteer/tools/eslint/src/prettier-comments.js @@ -0,0 +1,99 @@ +/** + * @license + * Copyright 2023 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +// @ts-nocheck +// TODO: We should convert this to types. + +const prettier = require('@prettier/sync'); + +const prettierConfigPath = '../../../.prettierrc.cjs'; +const prettierConfig = require(prettierConfigPath); + +const cleanupBlockComment = value => { + return value + .trim() + .split('\n') + .map(value => { + value = value.trim(); + if (value.startsWith('*')) { + value = value.slice(1); + if (value.startsWith(' ')) { + value = value.slice(1); + } + } + return value.trimEnd(); + }) + .join('\n') + .trim(); +}; + +const format = (value, offset) => { + return prettier + .format(value, { + ...prettierConfig, + parser: 'markdown', + // This is the print width minus 3 (the length of ` * `) and the offset. + printWidth: 80 - (offset + 3), + }) + .trim(); +}; + +const buildBlockComment = (value, offset) => { + const spaces = ' '.repeat(offset); + const lines = value.split('\n').map(line => { + return ` * ${line}`; + }); + lines.unshift('/**'); + lines.push(' */'); + lines.forEach((line, i) => { + lines[i] = `${spaces}${line}`; + }); + return lines.join('\n'); +}; + +/** + * @type import("eslint").Rule.RuleModule + */ +const prettierCommentsRule = { + meta: { + type: 'suggestion', + docs: { + description: 'Enforce Prettier formatting on comments', + recommended: false, + }, + fixable: 'code', + schema: [], + messages: {}, + }, + + create(context) { + for (const comment of context.sourceCode.getAllComments()) { + switch (comment.type) { + case 'Block': { + const offset = comment.loc.start.column; + const value = cleanupBlockComment(comment.value); + const formattedValue = format(value, offset); + if (formattedValue !== value) { + context.report({ + node: comment, + message: `Comment is not formatted correctly.`, + fix(fixer) { + return fixer.replaceText( + comment, + buildBlockComment(formattedValue, offset).trimStart() + ); + }, + }); + } + break; + } + } + } + return {}; + }, +}; + +module.exports = prettierCommentsRule; diff --git a/remote/test/puppeteer/tools/eslint/src/use-using.ts b/remote/test/puppeteer/tools/eslint/src/use-using.ts new file mode 100644 index 0000000000..0c727a4334 --- /dev/null +++ b/remote/test/puppeteer/tools/eslint/src/use-using.ts @@ -0,0 +1,85 @@ +/** + * @license + * Copyright 2023 Google Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +import {ESLintUtils, TSESTree} from '@typescript-eslint/utils'; + +const usingSymbols = ['ElementHandle', 'JSHandle']; + +const createRule = ESLintUtils.RuleCreator(name => { + return `https://github.com/puppeteer/puppeteer/tree/main/tools/eslint/${name}.js`; +}); + +const useUsingRule = createRule<[], 'useUsing' | 'useUsingFix'>({ + name: 'use-using', + meta: { + docs: { + description: "Requires 'using' for element/JS handles.", + requiresTypeChecking: true, + }, + hasSuggestions: true, + messages: { + useUsing: "Use 'using'.", + useUsingFix: "Replace with 'using' to ignore.", + }, + 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) || node.declare) { + 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', + suggest: [ + { + messageId: 'useUsingFix', + fix(fixer) { + return fixer.replaceTextRange( + [node.range[0], node.range[0] + node.kind.length], + 'using' + ); + }, + }, + ], + }); + } + } + } + }, + }; + }, +}); + +export = useUsingRule; |