@conarti/eslint-plugin-feature-sliced 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/CHANGELOG.md +477 -0
  2. package/README.md +142 -0
  3. package/dist/config.js +27 -0
  4. package/dist/configs/import-order/index.js +20 -0
  5. package/dist/configs/import-order/recommended.js +28 -0
  6. package/dist/configs/import-order/with-newlines-and-type-group.js +28 -0
  7. package/dist/configs/import-order/with-newlines.js +28 -0
  8. package/dist/configs/import-order/with-type-group.js +28 -0
  9. package/dist/configs/recommended.js +11 -0
  10. package/dist/configs/rules.js +11 -0
  11. package/dist/index.js +24 -0
  12. package/dist/lib/fsd-lib/extract-feature-sliced-parts.js +18 -0
  13. package/dist/lib/fsd-lib/extract-layer.js +21 -0
  14. package/dist/lib/fsd-lib/extract-paths-info.js +59 -0
  15. package/dist/lib/fsd-lib/extract-paths.js +19 -0
  16. package/dist/lib/fsd-lib/extract-segment.js +18 -0
  17. package/dist/lib/fsd-lib/extract-slice.js +10 -0
  18. package/dist/lib/fsd-lib/index.js +10 -0
  19. package/dist/lib/fsd-lib/layers.js +16 -0
  20. package/dist/lib/fsd-lib/validate-extracted-feature-sliced-parts.js +29 -0
  21. package/dist/lib/path-lib/convert-to-absolute.js +18 -0
  22. package/dist/lib/path-lib/index.js +9 -0
  23. package/dist/lib/path-lib/is-path-relative.js +7 -0
  24. package/dist/lib/path-lib/join-path.js +12 -0
  25. package/dist/lib/path-lib/normalize-path.js +19 -0
  26. package/dist/lib/rule-lib/can-validate.js +11 -0
  27. package/dist/lib/rule-lib/create-rule.js +7 -0
  28. package/dist/lib/rule-lib/extract-current-file-path.js +11 -0
  29. package/dist/lib/rule-lib/extract-cwd.js +13 -0
  30. package/dist/lib/rule-lib/extract-node-path.js +13 -0
  31. package/dist/lib/rule-lib/extract-rule-options.js +7 -0
  32. package/dist/lib/rule-lib/get-source-range-without-quotes.js +7 -0
  33. package/dist/lib/rule-lib/index.js +23 -0
  34. package/dist/lib/rule-lib/is-ignored-current-file.js +12 -0
  35. package/dist/lib/rule-lib/is-ignored.js +12 -0
  36. package/dist/lib/rule-lib/is-node-type.js +17 -0
  37. package/dist/lib/rule-lib/models.js +2 -0
  38. package/dist/lib/shared/get-by-reg-exp.js +12 -0
  39. package/dist/lib/shared/index.js +11 -0
  40. package/dist/lib/shared/is-null.js +7 -0
  41. package/dist/lib/shared/is-object.js +7 -0
  42. package/dist/lib/shared/is-undefined.js +7 -0
  43. package/dist/rules/absolute-relative/config.js +2 -0
  44. package/dist/rules/absolute-relative/index.js +52 -0
  45. package/dist/rules/absolute-relative/model/errors-lib.js +17 -0
  46. package/dist/rules/absolute-relative/model/index.js +5 -0
  47. package/dist/rules/absolute-relative/model/should-be-absolute.js +16 -0
  48. package/dist/rules/absolute-relative/model/should-be-relative.js +21 -0
  49. package/dist/rules/absolute-relative/model/validate-and-report.js +24 -0
  50. package/dist/rules/layers-slices/config.js +2 -0
  51. package/dist/rules/layers-slices/index.js +56 -0
  52. package/dist/rules/layers-slices/model/can-import-layer.js +22 -0
  53. package/dist/rules/layers-slices/model/errors-lib.js +14 -0
  54. package/dist/rules/layers-slices/model/index.js +5 -0
  55. package/dist/rules/layers-slices/model/validate-and-report.js +22 -0
  56. package/dist/rules/public-api/config.js +2 -0
  57. package/dist/rules/public-api/index.js +65 -0
  58. package/dist/rules/public-api/model/convert-to-public-api.js +24 -0
  59. package/dist/rules/public-api/model/errors-lib.js +34 -0
  60. package/dist/rules/public-api/model/index.js +5 -0
  61. package/dist/rules/public-api/model/is-index-file.js +7 -0
  62. package/dist/rules/public-api/model/is-layer-public-api.js +23 -0
  63. package/dist/rules/public-api/model/is-segments-public-api.js +11 -0
  64. package/dist/rules/public-api/model/is-slice-public-api.js +7 -0
  65. package/dist/rules/public-api/model/should-be-from-public-api.js +21 -0
  66. package/dist/rules/public-api/model/validate-and-report-program.js +15 -0
  67. package/dist/rules/public-api/model/validate-and-report.js +18 -0
  68. package/package.json +86 -0
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isObject = void 0;
4
+ function isObject(target) {
5
+ return (typeof target === 'object' || typeof target === 'function') && (target !== null);
6
+ }
7
+ exports.isObject = isObject;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isUndefined = void 0;
4
+ function isUndefined(target) {
5
+ return target === undefined;
6
+ }
7
+ exports.isUndefined = isUndefined;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const rule_lib_1 = require("../../lib/rule-lib");
4
+ const model_1 = require("./model");
5
+ exports.default = (0, rule_lib_1.createRule)({
6
+ name: 'absolute-relative',
7
+ meta: {
8
+ type: 'problem',
9
+ docs: {
10
+ description: 'Checks for absolute and relative paths',
11
+ recommended: false,
12
+ },
13
+ messages: {
14
+ ["must-be-relative-path"]: 'There must be relative paths',
15
+ ["must-be-absolute-path"]: 'There must be absolute paths',
16
+ },
17
+ schema: [
18
+ {
19
+ type: 'object',
20
+ properties: {
21
+ ignoreInFilesPatterns: {
22
+ type: 'array',
23
+ items: {
24
+ type: 'string',
25
+ },
26
+ },
27
+ },
28
+ },
29
+ ],
30
+ },
31
+ defaultOptions: [
32
+ {
33
+ ignoreInFilesPatterns: [],
34
+ },
35
+ ],
36
+ create(context, optionsWithDefault) {
37
+ return {
38
+ ImportDeclaration(node) {
39
+ (0, model_1.validateAndReport)(node, context, optionsWithDefault);
40
+ },
41
+ ImportExpression(node) {
42
+ (0, model_1.validateAndReport)(node, context, optionsWithDefault);
43
+ },
44
+ ExportAllDeclaration(node) {
45
+ (0, model_1.validateAndReport)(node, context, optionsWithDefault, { needCheckForAbsolute: false });
46
+ },
47
+ ExportNamedDeclaration(node) {
48
+ (0, model_1.validateAndReport)(node, context, optionsWithDefault, { needCheckForAbsolute: false });
49
+ },
50
+ };
51
+ },
52
+ });
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.reportShouldBeAbsolute = exports.reportShouldBeRelative = void 0;
4
+ function reportShouldBeRelative(node, context) {
5
+ context.report({
6
+ node: node.source,
7
+ messageId: "must-be-relative-path",
8
+ });
9
+ }
10
+ exports.reportShouldBeRelative = reportShouldBeRelative;
11
+ function reportShouldBeAbsolute(node, context) {
12
+ context.report({
13
+ node: node.source,
14
+ messageId: "must-be-absolute-path",
15
+ });
16
+ }
17
+ exports.reportShouldBeAbsolute = reportShouldBeAbsolute;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateAndReport = void 0;
4
+ var validate_and_report_1 = require("./validate-and-report");
5
+ Object.defineProperty(exports, "validateAndReport", { enumerable: true, get: function () { return validate_and_report_1.validateAndReport; } });
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.shouldBeAbsolute = void 0;
4
+ const path_lib_1 = require("../../../lib/path-lib");
5
+ function shouldBeAbsolute(pathsInfo) {
6
+ const { normalizedTargetPath, fsdPartsOfTarget, fsdPartsOfCurrentFile, hasUnknownLayers, } = pathsInfo;
7
+ const isAbsolute = !(0, path_lib_1.isPathRelative)(normalizedTargetPath);
8
+ if (isAbsolute) {
9
+ return false;
10
+ }
11
+ if (hasUnknownLayers) {
12
+ return false;
13
+ }
14
+ return fsdPartsOfCurrentFile.layer !== fsdPartsOfTarget.layer;
15
+ }
16
+ exports.shouldBeAbsolute = shouldBeAbsolute;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.shouldBeRelative = void 0;
4
+ const path_lib_1 = require("../../../lib/path-lib");
5
+ function shouldBeRelative(pathsInfo) {
6
+ const { validatedFeatureSlicedPartsOfCurrentFile, normalizedTargetPath, isSameLayerWithoutSlices, isSameLayer, isSameSlice, } = pathsInfo;
7
+ const isRelative = (0, path_lib_1.isPathRelative)(normalizedTargetPath);
8
+ if (isRelative) {
9
+ return false;
10
+ }
11
+ const isImportToLayerPublicApi = validatedFeatureSlicedPartsOfCurrentFile.hasNotSlice && isSameLayer;
12
+ if (isImportToLayerPublicApi) {
13
+ return true;
14
+ }
15
+ if (isSameLayerWithoutSlices) {
16
+ return true;
17
+ }
18
+ const isSameLayerAndSlice = isSameLayer && isSameSlice;
19
+ return isSameLayerAndSlice;
20
+ }
21
+ exports.shouldBeRelative = shouldBeRelative;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateAndReport = void 0;
4
+ const fsd_lib_1 = require("../../../lib/fsd-lib");
5
+ const rule_lib_1 = require("../../../lib/rule-lib");
6
+ const errors_lib_1 = require("./errors-lib");
7
+ const should_be_absolute_1 = require("./should-be-absolute");
8
+ const should_be_relative_1 = require("./should-be-relative");
9
+ function validateAndReport(node, context, optionsWithDefault, options = { needCheckForAbsolute: true }) {
10
+ if (!(0, rule_lib_1.canValidate)(node)) {
11
+ return;
12
+ }
13
+ if ((0, rule_lib_1.isIgnoredCurrentFile)(context, optionsWithDefault)) {
14
+ return;
15
+ }
16
+ const pathsInfo = (0, fsd_lib_1.extractPathsInfo)(node, context);
17
+ if ((0, should_be_relative_1.shouldBeRelative)(pathsInfo)) {
18
+ (0, errors_lib_1.reportShouldBeRelative)(node, context);
19
+ }
20
+ if (options.needCheckForAbsolute && (0, should_be_absolute_1.shouldBeAbsolute)(pathsInfo)) {
21
+ (0, errors_lib_1.reportShouldBeAbsolute)(node, context);
22
+ }
23
+ }
24
+ exports.validateAndReport = validateAndReport;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const rule_lib_1 = require("../../lib/rule-lib");
4
+ const model_1 = require("./model");
5
+ exports.default = (0, rule_lib_1.createRule)({
6
+ name: 'layers-slices',
7
+ meta: {
8
+ type: 'problem',
9
+ docs: {
10
+ description: 'Checks layer imports',
11
+ recommended: false,
12
+ },
13
+ messages: {
14
+ ["can-not-import"]: 'You cannot import layer "{{ importLayer }}" into "{{ currentFileLayer }}" (shared -> entities -> features -> widgets -> pages -> processes -> app)',
15
+ },
16
+ schema: [
17
+ {
18
+ type: 'object',
19
+ properties: {
20
+ allowTypeImports: {
21
+ type: 'boolean',
22
+ },
23
+ ignorePatterns: {
24
+ type: 'array',
25
+ items: {
26
+ type: 'string',
27
+ },
28
+ },
29
+ ignoreInFilesPatterns: {
30
+ type: 'array',
31
+ items: {
32
+ type: 'string',
33
+ },
34
+ },
35
+ },
36
+ },
37
+ ],
38
+ },
39
+ defaultOptions: [
40
+ {
41
+ allowTypeImports: true,
42
+ ignorePatterns: [],
43
+ ignoreInFilesPatterns: [],
44
+ },
45
+ ],
46
+ create(context, optionsWithDefault) {
47
+ return {
48
+ ImportDeclaration(node) {
49
+ (0, model_1.validateAndReport)(node, context, optionsWithDefault);
50
+ },
51
+ ImportExpression(node) {
52
+ (0, model_1.validateAndReport)(node, context, optionsWithDefault);
53
+ },
54
+ };
55
+ },
56
+ });
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.canImportLayer = void 0;
4
+ const fsd_lib_1 = require("../../../lib/fsd-lib");
5
+ const rule_lib_1 = require("../../../lib/rule-lib");
6
+ function canImportLayer(pathsInfo, node, ruleOptions) {
7
+ const { fsdPartsOfTarget, fsdPartsOfCurrentFile, isSameSlice, isSameLayerWithoutSlices, hasUnknownLayers, } = pathsInfo;
8
+ if (hasUnknownLayers) {
9
+ return true;
10
+ }
11
+ const { allowTypeImports } = ruleOptions;
12
+ const isType = (0, rule_lib_1.isNodeType)(node);
13
+ const isTypeAndAllowedToImport = allowTypeImports && isType;
14
+ const importLayerOrder = (0, fsd_lib_1.getLayerWeight)(fsdPartsOfTarget.layer);
15
+ const currentFileLayerOrder = (0, fsd_lib_1.getLayerWeight)(fsdPartsOfCurrentFile.layer);
16
+ const isImportLayerBelowCurrent = currentFileLayerOrder > importLayerOrder;
17
+ return isSameSlice
18
+ || isTypeAndAllowedToImport
19
+ || isSameLayerWithoutSlices
20
+ || isImportLayerBelowCurrent;
21
+ }
22
+ exports.canImportLayer = canImportLayer;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.reportCanNotImportLayer = void 0;
4
+ function reportCanNotImportLayer(context, node, pathsInfo) {
5
+ context.report({
6
+ node: node.source,
7
+ messageId: "can-not-import",
8
+ data: {
9
+ importLayer: pathsInfo.fsdPartsOfTarget.layer,
10
+ currentFileLayer: pathsInfo.fsdPartsOfCurrentFile.layer,
11
+ },
12
+ });
13
+ }
14
+ exports.reportCanNotImportLayer = reportCanNotImportLayer;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateAndReport = void 0;
4
+ var validate_and_report_1 = require("./validate-and-report");
5
+ Object.defineProperty(exports, "validateAndReport", { enumerable: true, get: function () { return validate_and_report_1.validateAndReport; } });
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateAndReport = void 0;
4
+ const fsd_lib_1 = require("../../../lib/fsd-lib");
5
+ const rule_lib_1 = require("../../../lib/rule-lib");
6
+ const can_import_layer_1 = require("./can-import-layer");
7
+ const errors_lib_1 = require("./errors-lib");
8
+ function validateAndReport(node, context, optionsWithDefault) {
9
+ if (!(0, rule_lib_1.canValidate)(node)) {
10
+ return;
11
+ }
12
+ const pathsInfo = (0, fsd_lib_1.extractPathsInfo)(node, context);
13
+ const userDefinedRuleOptions = (0, rule_lib_1.extractRuleOptions)(optionsWithDefault);
14
+ const isIgnoredTargetPath = (0, rule_lib_1.isIgnored)(pathsInfo.targetPath, userDefinedRuleOptions.ignorePatterns);
15
+ if (isIgnoredTargetPath || (0, rule_lib_1.isIgnoredCurrentFile)(context, optionsWithDefault)) {
16
+ return;
17
+ }
18
+ if (!(0, can_import_layer_1.canImportLayer)(pathsInfo, node, userDefinedRuleOptions)) {
19
+ (0, errors_lib_1.reportCanNotImportLayer)(context, node, pathsInfo);
20
+ }
21
+ }
22
+ exports.validateAndReport = validateAndReport;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const rule_lib_1 = require("../../lib/rule-lib");
4
+ const model_1 = require("./model");
5
+ const validate_and_report_program_1 = require("./model/validate-and-report-program");
6
+ exports.default = (0, rule_lib_1.createRule)({
7
+ name: 'public-api',
8
+ meta: {
9
+ type: 'problem',
10
+ docs: {
11
+ description: 'Check for module imports from public api',
12
+ recommended: false,
13
+ },
14
+ hasSuggestions: true,
15
+ messages: {
16
+ ["should-be-from-public-api"]: 'Absolute imports are only allowed from public api ("{{ fixedPath }}")',
17
+ ["remove-suggestion"]: 'Remove the "{{ valueToRemove }}"',
18
+ ["layers-public-api-not-allowed"]: 'The layer public API is not allowed. It harms both architecturally and practically (code splitting)',
19
+ },
20
+ schema: [
21
+ {
22
+ type: 'object',
23
+ properties: {
24
+ level: {
25
+ enum: [
26
+ "segments",
27
+ "slices",
28
+ ],
29
+ },
30
+ ignoreInFilesPatterns: {
31
+ type: 'array',
32
+ items: {
33
+ type: 'string',
34
+ },
35
+ },
36
+ },
37
+ },
38
+ ],
39
+ },
40
+ defaultOptions: [
41
+ {
42
+ level: "slices",
43
+ ignoreInFilesPatterns: [],
44
+ },
45
+ ],
46
+ create(context, optionsWithDefault) {
47
+ return {
48
+ ImportDeclaration(node) {
49
+ (0, model_1.validateAndReport)(node, context, optionsWithDefault);
50
+ },
51
+ ImportExpression(node) {
52
+ (0, model_1.validateAndReport)(node, context, optionsWithDefault);
53
+ },
54
+ ExportAllDeclaration(node) {
55
+ (0, model_1.validateAndReport)(node, context, optionsWithDefault);
56
+ },
57
+ ExportNamedDeclaration(node) {
58
+ (0, model_1.validateAndReport)(node, context, optionsWithDefault);
59
+ },
60
+ Program(node) {
61
+ (0, validate_and_report_program_1.validateAndReportProgram)(node, context, optionsWithDefault);
62
+ },
63
+ };
64
+ },
65
+ });
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.convertToPublicApi = void 0;
4
+ const shared_1 = require("../../../lib/shared");
5
+ function addSlashToStart(targetPath) {
6
+ if ((0, shared_1.isNull)(targetPath)) {
7
+ return '';
8
+ }
9
+ return `/${targetPath}`;
10
+ }
11
+ function extractValueToRemove(pathsInfo) {
12
+ const { isSameSlice, fsdPartsOfTarget, } = pathsInfo;
13
+ if (isSameSlice) {
14
+ return fsdPartsOfTarget.segmentFiles;
15
+ }
16
+ return `${fsdPartsOfTarget.segment}${addSlashToStart(fsdPartsOfTarget.segmentFiles)}`;
17
+ }
18
+ function convertToPublicApi(pathsInfo) {
19
+ const { normalizedTargetPath } = pathsInfo;
20
+ const valueToRemove = extractValueToRemove(pathsInfo);
21
+ const publicApiPath = normalizedTargetPath.replace(`/${valueToRemove}`, '');
22
+ return [publicApiPath, valueToRemove];
23
+ }
24
+ exports.convertToPublicApi = convertToPublicApi;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.reportLayersPublicApiNotAllowed = exports.reportShouldBeFromPublicApi = void 0;
4
+ const fsd_lib_1 = require("../../../lib/fsd-lib");
5
+ const rule_lib_1 = require("../../../lib/rule-lib");
6
+ const convert_to_public_api_1 = require("./convert-to-public-api");
7
+ function reportShouldBeFromPublicApi(node, context) {
8
+ const pathsInfo = (0, fsd_lib_1.extractPathsInfo)(node, context);
9
+ const [fixedPath, valueToRemove] = (0, convert_to_public_api_1.convertToPublicApi)(pathsInfo);
10
+ context.report({
11
+ node: node.source,
12
+ messageId: "should-be-from-public-api",
13
+ data: {
14
+ fixedPath,
15
+ },
16
+ suggest: [
17
+ {
18
+ messageId: "remove-suggestion",
19
+ data: {
20
+ valueToRemove,
21
+ },
22
+ fix: (fixer) => fixer.replaceTextRange((0, rule_lib_1.getSourceRangeWithoutQuotes)(node.source.range), fixedPath),
23
+ },
24
+ ],
25
+ });
26
+ }
27
+ exports.reportShouldBeFromPublicApi = reportShouldBeFromPublicApi;
28
+ function reportLayersPublicApiNotAllowed(node, context) {
29
+ context.report({
30
+ node,
31
+ messageId: "layers-public-api-not-allowed",
32
+ });
33
+ }
34
+ exports.reportLayersPublicApiNotAllowed = reportLayersPublicApiNotAllowed;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateAndReport = void 0;
4
+ var validate_and_report_1 = require("./validate-and-report");
5
+ Object.defineProperty(exports, "validateAndReport", { enumerable: true, get: function () { return validate_and_report_1.validateAndReport; } });
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isIndexFile = void 0;
4
+ function isIndexFile(segmentFiles) {
5
+ return /^index\.\w+/i.test(segmentFiles);
6
+ }
7
+ exports.isIndexFile = isIndexFile;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.isLayerPublicApi = void 0;
7
+ const picomatch_1 = __importDefault(require("picomatch"));
8
+ const fsd_lib_1 = require("../../../lib/fsd-lib");
9
+ const rule_lib_1 = require("../../../lib/rule-lib");
10
+ const shared_1 = require("../../../lib/shared");
11
+ function isLayerPublicApi(context) {
12
+ const normalizedCurrentFilePath = (0, rule_lib_1.extractCurrentFilePath)(context);
13
+ const cwd = (0, rule_lib_1.extractCwd)(context);
14
+ const layer = (0, fsd_lib_1.extractLayer)(normalizedCurrentFilePath, cwd);
15
+ if ((0, shared_1.isNull)(layer)) {
16
+ return false;
17
+ }
18
+ const matcher = (0, picomatch_1.default)([
19
+ `**/${layer}/index.*`,
20
+ ]);
21
+ return matcher(normalizedCurrentFilePath);
22
+ }
23
+ exports.isLayerPublicApi = isLayerPublicApi;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isSegmentsPublicApi = void 0;
4
+ const is_index_file_1 = require("./is-index-file");
5
+ function isSegmentsPublicApi(pathsInfo) {
6
+ const { fsdPartsOfTarget, validatedFeatureSlicedPartsOfTarget, isSameSegment, } = pathsInfo;
7
+ const isSegmentPublicApi = validatedFeatureSlicedPartsOfTarget.hasNotSegmentFiles
8
+ || (0, is_index_file_1.isIndexFile)(fsdPartsOfTarget.segmentFiles);
9
+ return isSameSegment || isSegmentPublicApi;
10
+ }
11
+ exports.isSegmentsPublicApi = isSegmentsPublicApi;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isSlicePublicApi = void 0;
4
+ function isSlicePublicApi(pathsInfo) {
5
+ return pathsInfo.validatedFeatureSlicedPartsOfTarget.hasNotSegment;
6
+ }
7
+ exports.isSlicePublicApi = isSlicePublicApi;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.shouldBeFromPublicApi = void 0;
4
+ const fsd_lib_1 = require("../../../lib/fsd-lib");
5
+ const rule_lib_1 = require("../../../lib/rule-lib");
6
+ const is_segments_public_api_1 = require("./is-segments-public-api");
7
+ const is_slice_public_api_1 = require("./is-slice-public-api");
8
+ function shouldBeFromSlicePublicApi(pathsInfo) {
9
+ const isFromAnotherSlice = !pathsInfo.isSameSlice;
10
+ return isFromAnotherSlice && !(0, is_slice_public_api_1.isSlicePublicApi)(pathsInfo);
11
+ }
12
+ function shouldBeFromSegmentsPublicApi(pathsInfo, validateOptions) {
13
+ const needValidateSegments = validateOptions.level === "segments";
14
+ return needValidateSegments && !(0, is_segments_public_api_1.isSegmentsPublicApi)(pathsInfo);
15
+ }
16
+ function shouldBeFromPublicApi(node, context, optionsWithDefault) {
17
+ const pathsInfo = (0, fsd_lib_1.extractPathsInfo)(node, context);
18
+ const ruleOptions = (0, rule_lib_1.extractRuleOptions)(optionsWithDefault);
19
+ return shouldBeFromSlicePublicApi(pathsInfo) || shouldBeFromSegmentsPublicApi(pathsInfo, ruleOptions);
20
+ }
21
+ exports.shouldBeFromPublicApi = shouldBeFromPublicApi;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateAndReportProgram = void 0;
4
+ const rule_lib_1 = require("../../../lib/rule-lib");
5
+ const errors_lib_1 = require("./errors-lib");
6
+ const is_layer_public_api_1 = require("./is-layer-public-api");
7
+ function validateAndReportProgram(node, context, optionsWithDefault) {
8
+ if ((0, rule_lib_1.isIgnoredCurrentFile)(context, optionsWithDefault)) {
9
+ return;
10
+ }
11
+ if ((0, is_layer_public_api_1.isLayerPublicApi)(context)) {
12
+ (0, errors_lib_1.reportLayersPublicApiNotAllowed)(node, context);
13
+ }
14
+ }
15
+ exports.validateAndReportProgram = validateAndReportProgram;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateAndReport = void 0;
4
+ const rule_lib_1 = require("../../../lib/rule-lib");
5
+ const errors_lib_1 = require("./errors-lib");
6
+ const should_be_from_public_api_1 = require("./should-be-from-public-api");
7
+ function validateAndReport(node, context, optionsWithDefault) {
8
+ if (!(0, rule_lib_1.canValidate)(node)) {
9
+ return;
10
+ }
11
+ if ((0, rule_lib_1.isIgnoredCurrentFile)(context, optionsWithDefault)) {
12
+ return;
13
+ }
14
+ if ((0, should_be_from_public_api_1.shouldBeFromPublicApi)(node, context, optionsWithDefault)) {
15
+ (0, errors_lib_1.reportShouldBeFromPublicApi)(node, context);
16
+ }
17
+ }
18
+ exports.validateAndReport = validateAndReport;
package/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "@conarti/eslint-plugin-feature-sliced",
3
+ "version": "1.0.3",
4
+ "description": "Feature-sliced design methodology plugin",
5
+ "repository": "https://github.com/conarti/eslint-plugin-fsd.git",
6
+ "keywords": [
7
+ "eslint",
8
+ "eslintplugin",
9
+ "eslint-plugin",
10
+ "feature-sliced",
11
+ "feature-slices",
12
+ "feature-driven",
13
+ "feature-based"
14
+ ],
15
+ "files": [
16
+ "dist",
17
+ "CHANGELOG.md"
18
+ ],
19
+ "author": "conarti",
20
+ "main": "./dist/index.js",
21
+ "exports": {
22
+ ".": "./dist/index.js",
23
+ "./import-order": "./dist/configs/import-order/index.js"
24
+ },
25
+ "scripts": {
26
+ "clean": "rimraf ./dist",
27
+ "build": "npm run clean && tsc -p tsconfig.build.json",
28
+ "lint": "npm-run-all \"lint:*\"",
29
+ "lint:js": "eslint .",
30
+ "test": "vitest",
31
+ "test:ui": "vitest --ui --api 9527",
32
+ "test:run": "vitest run",
33
+ "test:coverage": "vitest run --coverage",
34
+ "publish:patch": "npm version patch && npm publish",
35
+ "publish:minor": "npm version minor && npm publish",
36
+ "publish:major": "npm version major && npm publish",
37
+ "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
38
+ "local-build": "node scripts/local-build.js",
39
+ "release": "node scripts/release.js",
40
+ "docs:dev": "vitepress dev docs",
41
+ "docs:build": "vitepress build docs",
42
+ "docs:preview": "vitepress preview docs"
43
+ },
44
+ "devDependencies": {
45
+ "@total-typescript/ts-reset": "^0.4.2",
46
+ "@tsconfig/node14": "^1.0.3",
47
+ "@types/eslint": "^8.40.2",
48
+ "@types/node": "^20.2.5",
49
+ "@types/picomatch": "^2.3.0",
50
+ "@typescript-eslint/eslint-plugin": "^5.59.9",
51
+ "@typescript-eslint/parser": "^5.53.0",
52
+ "@typescript-eslint/utils": "^5.59.9",
53
+ "@vitest/coverage-v8": "^0.32.0",
54
+ "@vitest/ui": "^0.32.0",
55
+ "conventional-changelog-cli": "^2.2.2",
56
+ "eslint": "^8.42.0",
57
+ "eslint-config-airbnb-base": "^15.0.0",
58
+ "eslint-import-resolver-typescript": "^3.5.5",
59
+ "eslint-plugin-eslint-plugin": "^5.0.0",
60
+ "eslint-plugin-filenames-simple": "^0.8.0",
61
+ "eslint-plugin-import": "^2.27.5",
62
+ "eslint-plugin-node": "^11.1.0",
63
+ "eslint-plugin-unused-imports": "^2.0.0",
64
+ "eslint-plugin-vitest": "^0.2.6",
65
+ "execa": "5.1.1",
66
+ "npm-run-all": "^4.1.5",
67
+ "picocolors": "^1.0.0",
68
+ "prompts": "^2.4.2",
69
+ "rimraf": "^5.0.1",
70
+ "semver": "^7.3.8",
71
+ "typescript": "^4.9.5",
72
+ "vitepress": "^1.0.0-alpha.64",
73
+ "vitest": "^0.32.0"
74
+ },
75
+ "engines": {
76
+ "node": "^14.17.0 || ^16.0.0 || >= 18.0.0"
77
+ },
78
+ "peerDependencies": {
79
+ "eslint": ">=7",
80
+ "eslint-plugin-import": ">=2.26"
81
+ },
82
+ "license": "ISC",
83
+ "dependencies": {
84
+ "picomatch": "^2.3.1"
85
+ }
86
+ }