-
Notifications
You must be signed in to change notification settings - Fork 6
chore: forbid rc deep imports in build #18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,6 +5,33 @@ import path from 'path'; | |||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const cwd = process.cwd(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const restrictedPackageDirectoryImports = [ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| '@rc-component/*/es', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| '@rc-component/*/es/**', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| '@rc-component/*/lib', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| '@rc-component/*/lib/**', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'rc-*/es', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'rc-*/es/**', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'rc-*/lib', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'rc-*/lib/**', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const eslintRulesString = JSON.stringify({ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| '@typescript-eslint/consistent-type-exports': 'error', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'no-restricted-imports': [ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'error', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| patterns: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| group: restrictedPackageDirectoryImports, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| message: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'Do not import package internals from es/lib. Import from the package root.', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }).replace(/"/g, '\\"'); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // 检查 package.json 中是否有指定的 npm 包依赖 | ||||||||||||||||||||||||||||||||||||||||||||||||||
| function checkNpmPackageDependency(packageJson: any, packageName: string) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return !!( | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -20,7 +47,7 @@ export default (api: IApi) => { | |||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log('Check Typescript exports...'); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log('Check Typescript exports and rc package directory imports...'); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // Break if current project not install `@rc-component/np` | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const packageJson = await fs.readJson(path.join(cwd, 'package.json')); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -40,7 +67,7 @@ export default (api: IApi) => { | |||||||||||||||||||||||||||||||||||||||||||||||||
| if (isEslintInstalled) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| execSync( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // Requires compatibility with Windows environment | ||||||||||||||||||||||||||||||||||||||||||||||||||
| `npx eslint ${inputFolder} --ext .tsx,.ts --rule "@typescript-eslint/consistent-type-exports: error"`, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| `npx eslint ${inputFolder} --ext .tsx,.ts --rule "${eslintRulesString}"`, | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
68
to
+70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cd src && head -n 80 index.ts | tail -n 20Repository: react-component/father-plugin Length of output: 679 🏁 Script executed: cat -n src/index.ts | head -n 100Repository: react-component/father-plugin Length of output: 3578 避免通过 shell 字符串拼接传递 第 33 行代码对 JSON 使用了 建议改为 建议修改示例-import { execSync } from 'child_process';
+import { spawnSync } from 'child_process';
const cwd = process.cwd();
const restrictedPackageDirectoryImports = [
'`@rc-component/`*/es',
'`@rc-component/`*/es/**',
'`@rc-component/`*/lib',
'`@rc-component/`*/lib/**',
'rc-*/es',
'rc-*/es/**',
'rc-*/lib',
'rc-*/lib/**',
];
const eslintRulesString = JSON.stringify({
'`@typescript-eslint/consistent-type-exports`': 'error',
'no-restricted-imports': [
'error',
{
patterns: [
{
group: restrictedPackageDirectoryImports,
message:
'Do not import package internals from es/lib. Import from the package root.',
},
],
},
],
-}).replace(/"/g, '\\"');
...
const isEslintInstalled = checkNpmPackageDependency(packageJson, 'eslint');
if (isEslintInstalled) {
- execSync(
- // Requires compatibility with Windows environment
- `npx eslint ${inputFolder} --ext .tsx,.ts --rule "${eslintRulesString}"`,
+ const eslintBin = process.platform === 'win32' ? 'npx.cmd' : 'npx';
+ const result = spawnSync(
+ eslintBin,
+ [
+ 'eslint',
+ inputFolder,
+ '--ext',
+ '.tsx,.ts',
+ '--rule',
+ eslintRulesString,
+ ],
{
cwd,
env: process.env,
- stdio: [process.stdin, process.stdout, process.stderr],
- encoding: 'utf-8',
+ stdio: 'inherit',
},
);
+ if (result.status !== 0) {
+ process.exit(result.status ?? 1);
+ }
} else {
console.log('ESLint is not installed, skip.');
}📝 Committable suggestion
Suggested change
🧰 Tools🪛 OpenGrep (1.20.0)[ERROR] 68-77: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead. (coderabbit.command-injection.exec-js) 🤖 Prompt for AI Agents
Comment on lines
68
to
+70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the const rulesArgs = Object.entries(eslintRules)
.map(([rule, config]) => `--rule "${rule}: ${JSON.stringify(config).replace(/"/g, '\\"')}"`)
.join(' ');
execSync(
// Requires compatibility with Windows environment
`npx eslint ${inputFolder} --ext .tsx,.ts ${rulesArgs}`, |
||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| cwd, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| env: process.env, | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ESLint CLI
--ruleoption expects a single rule definition in the formatrule-id: config. It does not support passing a JSON object containing multiple rules. Passing the entire object as a single string will cause ESLint to fail or ignore the rules. It is better to keep the rules as a plain object and format them individually when constructing the command.