check-license.ts (2434B)
1 /** 2 * @license 3 * Copyright 2024 Google Inc. 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 import type {TSESTree} from '@typescript-eslint/utils'; 8 import {ESLintUtils} from '@typescript-eslint/utils'; 9 10 const createRule = ESLintUtils.RuleCreator<{ 11 requiresTypeChecking: boolean; 12 }>(name => { 13 return `https://github.com/puppeteer/puppeteer/tree/main/tools/eslint/${name}.ts`; 14 }); 15 16 const currentYear = new Date().getFullYear(); 17 18 // Needs to start and end with new line 19 const licenseHeader = ` 20 /** 21 * @license 22 * Copyright ${currentYear} Google Inc. 23 * SPDX-License-Identifier: Apache-2.0 24 */ 25 `; 26 27 const enforceLicenseRule = createRule<[], 'licenseRule'>({ 28 name: 'check-license', 29 meta: { 30 type: 'layout', 31 docs: { 32 description: 'Validate existence of license header', 33 requiresTypeChecking: false, 34 }, 35 fixable: 'code', 36 schema: [], 37 messages: { 38 licenseRule: 'Add license header.', 39 }, 40 }, 41 defaultOptions: [], 42 create(context) { 43 const sourceCode = context.sourceCode; 44 const comments = sourceCode.getAllComments(); 45 let insertAfter = [0, 0] as TSESTree.Range; 46 let header: TSESTree.Comment | null = null; 47 // Check only the first 2 comments 48 for (let index = 0; index < 2; index++) { 49 const comment = comments[index]; 50 if (!comment) { 51 break; 52 } 53 // Shebang comments should be at the top 54 if ( 55 // Types don't have it debugger showed it... 56 (comment.type as string) === 'Shebang' || 57 (comment.type === 'Line' && comment.value.startsWith('#!')) 58 ) { 59 insertAfter = comment.range; 60 continue; 61 } 62 if (comment.type === 'Block') { 63 header = comment; 64 break; 65 } 66 } 67 68 return { 69 Program(node) { 70 if (context.filename.endsWith('.json')) { 71 return; 72 } 73 74 if ( 75 header && 76 (header.value.includes('@license') || 77 header.value.includes('License') || 78 header.value.includes('Copyright')) 79 ) { 80 return; 81 } 82 83 // Add header license 84 if (!header || !header.value.includes('@license')) { 85 context.report({ 86 node: node, 87 messageId: 'licenseRule', 88 fix(fixer) { 89 return fixer.insertTextAfterRange(insertAfter, licenseHeader); 90 }, 91 }); 92 } 93 }, 94 }; 95 }, 96 }); 97 98 export = enforceLicenseRule;