chenjiawei.inizio e5d73966b4
fix: license header autoinstall (#455)
* fix: autoinstall license dep

* chore: add filter
2025-07-03 10:16:49 +00:00

136 lines
4.1 KiB
JavaScript

/**
* 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
}
);