no-import.ts 3.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import { Rule } from "eslint";
  2. const SEMI_PACKAGE_REG = /(?<=packages\/|@douyinfe\/|\.\.\/)(semi-[\w-]+)/;
  3. const RELATIVE_PATH_REG = /(..\/)+semi-[\w-]+/;
  4. const rule: Rule.RuleModule = {
  5. meta: {
  6. type: "problem",
  7. docs: {
  8. description: "disable import statement",
  9. recommended: true,
  10. url: "https://github.com/DouyinFE/semi-design"
  11. },
  12. fixable: "code",
  13. messages: {
  14. unexpected: "Unexpected import statement, semi ui should not be used as a dependency of semi foundation",
  15. unexpectedLodashES: "Unexpected import statement, please use lodash instead of lodash-es.",
  16. unexpectedRelativeImport: "Unexpected import statement, please use module name instead of relative path.",
  17. unexpectedImportSelf: 'Unexpected import statement, please use relative paths to import modules in the same package.'
  18. },
  19. schema: [],
  20. },
  21. create(context) {
  22. return {
  23. ImportDeclaration: (node) => {
  24. const fileName = context.getFilename();
  25. const sourceCode = context.getSourceCode();
  26. const importName = node.source.raw;
  27. const isFoundationFile = fileName.includes('semi-foundation');
  28. const isUIFile = fileName.includes('semi-ui');
  29. const importText = sourceCode.getText(node);
  30. if (isFoundationFile) {
  31. if (importName.includes('semi-ui')) {
  32. context.report({ node, messageId: "unexpected" });
  33. }
  34. }
  35. if (isFoundationFile || isUIFile) {
  36. if (importName.includes('lodash-es')) {
  37. const fixedSource = importText.replace('lodash-es', 'lodash');
  38. context.report({
  39. node,
  40. messageId: "unexpectedLodashES",
  41. fix: (fixer) => {
  42. return fixer.replaceText(node, fixedSource);
  43. }
  44. });
  45. } else if (importName.includes('semi-')) {
  46. if (isImportRelativePackage({ path: importName, fileName })) {
  47. const importPackageName = SEMI_PACKAGE_REG.exec(importName)[0];
  48. const fixedSource = importText.replace(RELATIVE_PATH_REG, `@douyinfe/${importPackageName}`);
  49. context.report({
  50. node,
  51. messageId: "unexpectedRelativeImport",
  52. fix: (fixer) => {
  53. return fixer.replaceText(node, fixedSource);
  54. }
  55. });
  56. } else if (isImportSelf({ path: importName, fileName })) {
  57. context.report({
  58. node,
  59. messageId: "unexpectedImportSelf",
  60. });
  61. }
  62. }
  63. }
  64. }
  65. };
  66. }
  67. };
  68. function isRelativePath(path: string) {
  69. return path.includes('../');
  70. }
  71. function isImportRelativePackage(options: { path: string, fileName: string }) {
  72. const { path, fileName } = options;
  73. const currentPackageName = SEMI_PACKAGE_REG.exec(fileName)[0];
  74. const importPackageName = SEMI_PACKAGE_REG.exec(path)[0];
  75. return currentPackageName !== importPackageName && isRelativePath(path);
  76. }
  77. function isImportSelf(options: { path: string, fileName: string }) {
  78. const { path, fileName } = options;
  79. const currentPackageName = SEMI_PACKAGE_REG.exec(fileName)[0];
  80. const importPackageName = SEMI_PACKAGE_REG.exec(path)[0];
  81. return currentPackageName === importPackageName;
  82. }
  83. export default rule;