feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
77
common/autoinstallers/rush-lint-staged/.lintstagedrc.js
Normal file
77
common/autoinstallers/rush-lint-staged/.lintstagedrc.js
Normal file
@@ -0,0 +1,77 @@
|
||||
const {
|
||||
excludeIgnoredFiles,
|
||||
groupChangedFilesByProject,
|
||||
getRushConfiguration,
|
||||
} = require('./utils');
|
||||
const micromatch = require('micromatch');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
module.exports = {
|
||||
'**/*.{ts,tsx,js,jsx,mjs}': async files => {
|
||||
const match = micromatch.not(files, [
|
||||
'**/common/_templates/!(_*)/**/(.)?*',
|
||||
]);
|
||||
const changedFileGroup = await groupChangedFilesByProject(match);
|
||||
const eslintCmds = Object.entries(changedFileGroup)
|
||||
.filter(([packageName]) =>
|
||||
packageName !== '@coze-arch/arco-icon' && packageName !== '@coze-arch/arco-illustration')
|
||||
.map(
|
||||
([packageName, changedFiles]) => {
|
||||
const rushConfiguration = getRushConfiguration();
|
||||
const { projectFolder, packageName: name } =
|
||||
rushConfiguration.getProjectByName(packageName);
|
||||
const filesToCheck = changedFiles
|
||||
.map(f => path.relative(projectFolder, f))
|
||||
.join(' ');
|
||||
// TSESTREE_SINGLE_RUN doc https://typescript-eslint.io/packages/parser/#allowautomaticsingleruninference
|
||||
// 切换到项目文件夹,并运行 ESLint 命令
|
||||
const cmd = [
|
||||
`cd ${projectFolder}`,
|
||||
`TSESTREE_SINGLE_RUN=true eslint --fix --cache ${filesToCheck} --no-error-on-unmatched-pattern`,
|
||||
].join(' && ');
|
||||
return {
|
||||
name,
|
||||
cmd,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
if (!eslintCmds.length) return [];
|
||||
|
||||
if (eslintCmds.length > 16) {
|
||||
console.log(
|
||||
`For performance reason, skip ESlint detection due to ${eslintCmds.length} eslint commands.`,
|
||||
);
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
// 这里不能直接返回 eslintCmds 数组,因为 lint-staged 会依次串行执行每个命令
|
||||
// 而 concurrently 会并行执行多个命令
|
||||
`concurrently --max-process 8 --names ${eslintCmds
|
||||
.map(r => `${r.name}`)
|
||||
.join(',')} --kill-others-on-fail ${eslintCmds
|
||||
.map(r => `"${r.cmd}"`)
|
||||
.join(' ')}`,
|
||||
];
|
||||
},
|
||||
'**/*.{less,scss,css}': files => {
|
||||
// 暂时只修复,不报错卡点
|
||||
return [`stylelint ${files.join(' ')} --fix || exit 0`];
|
||||
},
|
||||
'**/package.json': async files => {
|
||||
const match = micromatch.not(files, [
|
||||
'**/common/_templates/!(_*)/**/(.)?*',
|
||||
]);
|
||||
const filesToLint = await excludeIgnoredFiles(match);
|
||||
if (!filesToLint) return [];
|
||||
return [
|
||||
// https://eslint.org/docs/latest/flags/#enable-feature-flags-with-the-cli
|
||||
// eslint v9默认从cwd找配置,这里需要使用 unstable_config_lookup_from_file 配置,否则会报错
|
||||
`eslint --cache ${filesToLint} --flag unstable_config_lookup_from_file`,
|
||||
`prettier ${filesToLint} --write`,
|
||||
];
|
||||
},
|
||||
'**/!(package).json': 'prettier --write',
|
||||
};
|
||||
18
common/autoinstallers/rush-lint-staged/package.json
Normal file
18
common/autoinstallers/rush-lint-staged/package.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "rush-lint-staged",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"author": "fanwenjie.fe@bytedance.com",
|
||||
"resolutions": {},
|
||||
"dependencies": {
|
||||
"@microsoft/rush-lib": "5.147.1",
|
||||
"concurrently": "^7.6.0",
|
||||
"eslint": "~9.12.0",
|
||||
"lint-staged": "^13.0.3",
|
||||
"micromatch": "^4.0.5",
|
||||
"prettier": "^2.7.1",
|
||||
"pretty-quick": "^3.1.3",
|
||||
"stylelint": "^16.7.0",
|
||||
"typescript": "~5.8.2"
|
||||
}
|
||||
}
|
||||
4652
common/autoinstallers/rush-lint-staged/pnpm-lock.yaml
generated
Normal file
4652
common/autoinstallers/rush-lint-staged/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
106
common/autoinstallers/rush-lint-staged/utils.js
Normal file
106
common/autoinstallers/rush-lint-staged/utils.js
Normal file
@@ -0,0 +1,106 @@
|
||||
const path = require('path');
|
||||
|
||||
const { ESLint } = require('eslint');
|
||||
const { RushConfiguration } = require('@microsoft/rush-lib');
|
||||
|
||||
const getRushConfiguration = (function () {
|
||||
let rushConfiguration = null;
|
||||
return function () {
|
||||
// eslint-disable-next-line
|
||||
return (rushConfiguration ||= RushConfiguration.loadFromDefaultLocation({
|
||||
startingFolder: process.cwd(),
|
||||
}));
|
||||
};
|
||||
})();
|
||||
|
||||
// 获取变更文件所在的项目路径
|
||||
function withProjectFolder(changedFiles) {
|
||||
const projectFolders = [];
|
||||
|
||||
try {
|
||||
const rushConfiguration = getRushConfiguration();
|
||||
const { rushJsonFolder } = rushConfiguration;
|
||||
const lookup = rushConfiguration.getProjectLookupForRoot(rushJsonFolder);
|
||||
|
||||
for (const file of changedFiles) {
|
||||
const project = lookup.findChildPath(path.relative(rushJsonFolder, file));
|
||||
// 忽略不在 rush.json 内定义的项目
|
||||
if (project) {
|
||||
const projectFolder = project?.projectFolder ?? rushJsonFolder;
|
||||
const packageName = project?.packageName;
|
||||
projectFolders.push({
|
||||
file,
|
||||
projectFolder,
|
||||
packageName,
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
return projectFolders;
|
||||
}
|
||||
|
||||
async function excludeIgnoredFiles(changedFiles) {
|
||||
try {
|
||||
const eslintInstances = new Map();
|
||||
|
||||
const changedFilesWithIgnored = await Promise.all(
|
||||
withProjectFolder(changedFiles).map(async ({ file, projectFolder }) => {
|
||||
let eslint = eslintInstances.get(projectFolder);
|
||||
if (!eslint) {
|
||||
eslint = new ESLint({ cwd: projectFolder });
|
||||
eslintInstances.set(projectFolder, eslint);
|
||||
}
|
||||
|
||||
return {
|
||||
file,
|
||||
isIgnored: await eslint.isPathIgnored(file),
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
return changedFilesWithIgnored
|
||||
.filter(change => !change.isIgnored)
|
||||
.map(change => change.file)
|
||||
.join(' ');
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取发生变更的项目路径
|
||||
function getChangedProjects(changedFiles) {
|
||||
const changedProjectFolders = new Set();
|
||||
const changedProjects = new Set();
|
||||
|
||||
withProjectFolder(changedFiles).forEach(({ projectFolder, packageName }) => {
|
||||
if (!changedProjectFolders.has(projectFolder)) {
|
||||
changedProjectFolders.add(projectFolder);
|
||||
changedProjects.add({
|
||||
packageName,
|
||||
projectFolder,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return [...changedProjects];
|
||||
}
|
||||
|
||||
const groupChangedFilesByProject = changedFiles => {
|
||||
const changedFilesMap = withProjectFolder(changedFiles);
|
||||
const result = changedFilesMap.reduce((pre, cur) => {
|
||||
pre[cur.packageName] ||= [];
|
||||
pre[cur.packageName].push(cur.file);
|
||||
return pre;
|
||||
}, {});
|
||||
return result;
|
||||
};
|
||||
|
||||
exports.excludeIgnoredFiles = excludeIgnoredFiles;
|
||||
exports.getRushConfiguration = getRushConfiguration;
|
||||
exports.getChangedProjects = getChangedProjects;
|
||||
exports.groupChangedFilesByProject = groupChangedFilesByProject;
|
||||
Reference in New Issue
Block a user