prettier-comments.ts (2679B)
1 /** 2 * @license 3 * Copyright 2023 Google Inc. 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 import prettier from '@prettier/sync'; 8 import {ESLintUtils} from '@typescript-eslint/utils'; 9 10 const prettierConfigFile = prettier.resolveConfigFile( 11 '../../../.prettierrc.cjs', 12 ); 13 const prettierConfig = prettier.resolveConfig(prettierConfigFile ?? ''); 14 15 const createRule = ESLintUtils.RuleCreator<{ 16 requiresTypeChecking: boolean; 17 }>(name => { 18 return `https://github.com/puppeteer/puppeteer/tree/main/tools/eslint/${name}.js`; 19 }); 20 21 const cleanupBlockComment = (value: string) => { 22 return value 23 .trim() 24 .split('\n') 25 .map(value => { 26 value = value.trim(); 27 if (value.startsWith('*')) { 28 value = value.slice(1); 29 if (value.startsWith(' ')) { 30 value = value.slice(1); 31 } 32 } 33 return value.trimEnd(); 34 }) 35 .join('\n') 36 .trim(); 37 }; 38 39 const format = (value: string, offset: number) => { 40 return prettier 41 .format(value, { 42 ...prettierConfig, 43 parser: 'markdown', 44 // This is the print width minus 3 (the length of ` * `) and the offset. 45 printWidth: 80 - (offset + 3), 46 }) 47 .trim(); 48 }; 49 50 const buildBlockComment = (value: string, offset: number) => { 51 const spaces = ' '.repeat(offset); 52 const lines = value.split('\n').map(line => { 53 return ` * ${line}`; 54 }); 55 lines.unshift('/**'); 56 lines.push(' */'); 57 lines.forEach((line, i) => { 58 lines[i] = `${spaces}${line}`; 59 }); 60 return lines.join('\n'); 61 }; 62 63 const prettierCommentsRule = createRule<[], 'prettierComments'>({ 64 name: 'prettier-comments', 65 meta: { 66 type: 'suggestion', 67 docs: { 68 description: 'Enforce Prettier formatting on comments', 69 requiresTypeChecking: false, 70 }, 71 fixable: 'code', 72 schema: [], 73 messages: { 74 prettierComments: 'Comment is not formatted correctly.', 75 }, 76 }, 77 defaultOptions: [], 78 create(context) { 79 for (const comment of context.sourceCode.getAllComments()) { 80 switch (comment.type) { 81 case 'Block': { 82 const offset = comment.loc.start.column; 83 const value = cleanupBlockComment(comment.value); 84 const formattedValue = format(value, offset); 85 if (formattedValue !== value) { 86 context.report({ 87 node: comment, 88 messageId: 'prettierComments', 89 fix(fixer) { 90 return fixer.replaceText( 91 comment, 92 buildBlockComment(formattedValue, offset).trimStart(), 93 ); 94 }, 95 }); 96 } 97 break; 98 } 99 } 100 } 101 return {}; 102 }, 103 }); 104 105 export = prettierCommentsRule;