/** * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates * SPDX-License-Identifier: MIT */ const fs = require("fs"); const path = require("path"); const ig = require("ignore")(); const ignoreFile = fs.readFileSync(path.join(__dirname, "../../../.gitignore"), { encoding: "utf-8", }); ig.add(ignoreFile); // ignore cli install demos ig.add(['.next', 'doc_build']); const src = path.resolve(__dirname, '../../../'); const header = ` Copyright (c) 2025 Bytedance Ltd. and/or its affiliates SPDX-License-Identifier: MIT`; const bashHeader = `#!/usr/bin/env`; const rushPreHeader = `// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED.`; /** * Add License Header to all files in the folder * @param {string} targetDir - target folder path (absolute path) * @param {string} licenseContent - License content to be added (plain text) * @param {object} options - configuration items * @param {string[]} [options.includeExts] - file extensions to be processed (such as ['.js', '.ts']), all text files are processed by default * @param {string[]} [options.excludeDirs] - directories to be excluded (such as ['node_modules', 'dist']) * @param {string} [options.commentLinePrefix] - comment prefix (such as '// ' or '/* '), comment format is not added by default * @param {boolean} [options.force] - whether to force overwrite (re-add even if there is already a license), default false */ function addLicenseHeader(targetDir, licenseContent, options = {}) { const { includeExts = [".js", ".ts", ".mjs", ".cjs", ".html", ".css", ".scss"], commentLinePrefix = "// ", // default by js commentPrefix, commentSuffix, force = false, } = options; const licensedText = (commentPrefix ? commentPrefix + "\n" : "") + licenseContent .split("\n") .map((line) => commentLinePrefix + line) .join("\n") + (commentSuffix ? "\n" + commentSuffix : "") + "\n\n"; function traverseDir(currentDir) { const entries = fs.readdirSync(currentDir, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(currentDir, entry.name); if ( entry.isDirectory() && ig.ignores(path.relative(targetDir, fullPath)) ) { continue; } if (entry.isDirectory()) { traverseDir(fullPath); } else { processFile(fullPath); } } } function processFile(filePath) { const ext = path.extname(filePath).toLowerCase(); if (includeExts.length > 0 && !includeExts.includes(ext)) { return; } try { const originalContent = fs.readFileSync(filePath, "utf8"); // Check if the license already exists (simple match at the beginning) if (!force && (originalContent.startsWith(licensedText.trim()) || originalContent.startsWith(bashHeader.trim()) || originalContent.startsWith(rushPreHeader.trim()))) { return; } let newContent = originalContent; const shebangMatch = originalContent.match(/^#!.*\n/); if (shebangMatch) { newContent = shebangMatch[0] + licensedText + originalContent.replace(shebangMatch[0], ""); } else { newContent = licensedText + originalContent; } fs.writeFileSync(filePath, newContent, "utf8"); console.log(`[Success] License added: ${filePath}, please manually upload the locally modified file`); } catch (err) { console.error(`[ERROR] Failed to process file ${filePath}:`, err.message); } } if (fs.existsSync(targetDir) && fs.statSync(targetDir).isDirectory()) { traverseDir(targetDir); console.log("License Header add successfully"); } else { console.error("Error: The destination path is not a valid folder"); } } addLicenseHeader( src, header, { includeExts: ['.js', '.ts', '.tsx', '.jsx', '.mjs', '.cjs', '.scss', '.less', '.prisma', '.styl', '.css'], commentPrefix: '/**', commentLinePrefix: ' *', commentSuffix: ' */', force: false } ); addLicenseHeader( src, header, { includeExts: ['.sh'], commentLinePrefix: '# ', force: false } );