@conarti/eslint-plugin-feature-sliced 1.0.4 → 2.0.0-rc.1

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 (71) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +8 -5
  3. package/dist/index.cjs +1082 -0
  4. package/dist/index.d.cts +63 -0
  5. package/dist/index.d.ts +63 -0
  6. package/dist/index.js +1059 -24
  7. package/package.json +44 -44
  8. package/dist/config.js +0 -27
  9. package/dist/configs/import-order/index.js +0 -20
  10. package/dist/configs/import-order/recommended.js +0 -28
  11. package/dist/configs/import-order/with-newlines-and-type-group.js +0 -28
  12. package/dist/configs/import-order/with-newlines.js +0 -28
  13. package/dist/configs/import-order/with-type-group.js +0 -28
  14. package/dist/configs/recommended.js +0 -11
  15. package/dist/configs/rules.js +0 -11
  16. package/dist/lib/fsd-lib/extract-feature-sliced-parts.js +0 -18
  17. package/dist/lib/fsd-lib/extract-layer.js +0 -21
  18. package/dist/lib/fsd-lib/extract-paths-info.js +0 -59
  19. package/dist/lib/fsd-lib/extract-paths.js +0 -19
  20. package/dist/lib/fsd-lib/extract-segment.js +0 -18
  21. package/dist/lib/fsd-lib/extract-slice.js +0 -10
  22. package/dist/lib/fsd-lib/index.js +0 -10
  23. package/dist/lib/fsd-lib/layers.js +0 -16
  24. package/dist/lib/fsd-lib/validate-extracted-feature-sliced-parts.js +0 -29
  25. package/dist/lib/path-lib/convert-to-absolute.js +0 -18
  26. package/dist/lib/path-lib/index.js +0 -9
  27. package/dist/lib/path-lib/is-path-relative.js +0 -7
  28. package/dist/lib/path-lib/join-path.js +0 -12
  29. package/dist/lib/path-lib/normalize-path.js +0 -19
  30. package/dist/lib/rule-lib/can-validate.js +0 -11
  31. package/dist/lib/rule-lib/create-rule.js +0 -7
  32. package/dist/lib/rule-lib/extract-current-file-path.js +0 -11
  33. package/dist/lib/rule-lib/extract-cwd.js +0 -13
  34. package/dist/lib/rule-lib/extract-node-path.js +0 -13
  35. package/dist/lib/rule-lib/extract-rule-options.js +0 -7
  36. package/dist/lib/rule-lib/get-source-range-without-quotes.js +0 -7
  37. package/dist/lib/rule-lib/index.js +0 -23
  38. package/dist/lib/rule-lib/is-ignored-current-file.js +0 -12
  39. package/dist/lib/rule-lib/is-ignored.js +0 -12
  40. package/dist/lib/rule-lib/is-node-type.js +0 -17
  41. package/dist/lib/rule-lib/models.js +0 -2
  42. package/dist/lib/shared/get-by-reg-exp.js +0 -12
  43. package/dist/lib/shared/index.js +0 -11
  44. package/dist/lib/shared/is-null.js +0 -7
  45. package/dist/lib/shared/is-object.js +0 -7
  46. package/dist/lib/shared/is-undefined.js +0 -7
  47. package/dist/rules/absolute-relative/config.js +0 -2
  48. package/dist/rules/absolute-relative/index.js +0 -52
  49. package/dist/rules/absolute-relative/model/errors-lib.js +0 -17
  50. package/dist/rules/absolute-relative/model/index.js +0 -5
  51. package/dist/rules/absolute-relative/model/should-be-absolute.js +0 -16
  52. package/dist/rules/absolute-relative/model/should-be-relative.js +0 -21
  53. package/dist/rules/absolute-relative/model/validate-and-report.js +0 -24
  54. package/dist/rules/layers-slices/config.js +0 -2
  55. package/dist/rules/layers-slices/index.js +0 -56
  56. package/dist/rules/layers-slices/model/can-import-layer.js +0 -22
  57. package/dist/rules/layers-slices/model/errors-lib.js +0 -14
  58. package/dist/rules/layers-slices/model/index.js +0 -5
  59. package/dist/rules/layers-slices/model/validate-and-report.js +0 -22
  60. package/dist/rules/public-api/config.js +0 -2
  61. package/dist/rules/public-api/index.js +0 -65
  62. package/dist/rules/public-api/model/convert-to-public-api.js +0 -24
  63. package/dist/rules/public-api/model/errors-lib.js +0 -34
  64. package/dist/rules/public-api/model/index.js +0 -5
  65. package/dist/rules/public-api/model/is-index-file.js +0 -7
  66. package/dist/rules/public-api/model/is-layer-public-api.js +0 -23
  67. package/dist/rules/public-api/model/is-segments-public-api.js +0 -11
  68. package/dist/rules/public-api/model/is-slice-public-api.js +0 -7
  69. package/dist/rules/public-api/model/should-be-from-public-api.js +0 -21
  70. package/dist/rules/public-api/model/validate-and-report-program.js +0 -15
  71. package/dist/rules/public-api/model/validate-and-report.js +0 -18
package/dist/index.cjs ADDED
@@ -0,0 +1,1082 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ default: () => src_default
34
+ });
35
+ module.exports = __toCommonJS(src_exports);
36
+
37
+ // src/create-plugin.ts
38
+ var import_eslint_flat_config_utils = require("eslint-flat-config-utils");
39
+
40
+ // src/config.ts
41
+ var PLUGIN_NAME = "@conarti/feature-sliced";
42
+ var layers = [
43
+ "shared",
44
+ "entities",
45
+ "features",
46
+ "widgets",
47
+ "pages",
48
+ "processes",
49
+ "app"
50
+ ];
51
+ var layersWithoutSlices = [
52
+ "shared",
53
+ "app"
54
+ ];
55
+ var layersWithSlices = layers.filter((layer) => !layersWithoutSlices.includes(layer));
56
+ var segments = [
57
+ "ui",
58
+ "model",
59
+ "lib",
60
+ "api",
61
+ "config",
62
+ "assets"
63
+ ];
64
+ var pathSeparator = "/";
65
+
66
+ // src/configs/import-order/shared.ts
67
+ var import_eslint_plugin_import_x = __toESM(require("eslint-plugin-import-x"), 1);
68
+ var plugins = {
69
+ import: import_eslint_plugin_import_x.default
70
+ };
71
+ var LAYERS_REVERSED = [...layers].reverse();
72
+
73
+ // src/configs/import-order/recommended.ts
74
+ var recommended = {
75
+ name: "@conarti/sort-imports/recommended",
76
+ plugins,
77
+ rules: {
78
+ "import/order": [
79
+ 2,
80
+ {
81
+ "alphabetize": {
82
+ order: "asc",
83
+ caseInsensitive: true
84
+ },
85
+ "newlines-between": "never",
86
+ "pathGroups": LAYERS_REVERSED.map(
87
+ (layer) => ({
88
+ pattern: `**/?(*)${layer}{,/**}`,
89
+ group: "internal",
90
+ position: "after"
91
+ })
92
+ ),
93
+ "distinctGroup": false,
94
+ "pathGroupsExcludedImportTypes": ["builtin"],
95
+ "groups": ["builtin", "external", "internal", "parent", "sibling", "index"]
96
+ }
97
+ ]
98
+ }
99
+ };
100
+
101
+ // src/configs/import-order/with-newlines.ts
102
+ var withNewlines = {
103
+ name: "@conarti/sort-imports/with-newlines",
104
+ plugins,
105
+ rules: {
106
+ "import/order": [
107
+ 2,
108
+ {
109
+ "alphabetize": {
110
+ order: "asc",
111
+ caseInsensitive: true
112
+ },
113
+ "newlines-between": "always",
114
+ "pathGroups": LAYERS_REVERSED.map(
115
+ (layer) => ({
116
+ pattern: `**/?(*)${layer}{,/**}`,
117
+ group: "internal",
118
+ position: "after"
119
+ })
120
+ ),
121
+ "distinctGroup": false,
122
+ "pathGroupsExcludedImportTypes": ["builtin"],
123
+ "groups": ["builtin", "external", "internal", "parent", "sibling", "index"]
124
+ }
125
+ ]
126
+ }
127
+ };
128
+
129
+ // src/configs/import-order/with-newlines-and-type-group.ts
130
+ var withNewlinesAndTypeGroup = {
131
+ name: "@conarti/sort-imports/with-newlines-and-type-group",
132
+ plugins,
133
+ rules: {
134
+ "import/order": [
135
+ 2,
136
+ {
137
+ "alphabetize": {
138
+ order: "asc",
139
+ caseInsensitive: true
140
+ },
141
+ "newlines-between": "always",
142
+ "pathGroups": LAYERS_REVERSED.map(
143
+ (layer) => ({
144
+ pattern: `**/?(*)${layer}{,/**}`,
145
+ group: "internal",
146
+ position: "after"
147
+ })
148
+ ),
149
+ "distinctGroup": false,
150
+ "pathGroupsExcludedImportTypes": ["builtin", "type"],
151
+ "groups": ["builtin", "external", "internal", "type", "parent", "sibling", "index"]
152
+ }
153
+ ]
154
+ }
155
+ };
156
+
157
+ // src/configs/import-order/with-type-group.ts
158
+ var withTypeGroup = {
159
+ name: "@conarti/sort-imports/with-type-group",
160
+ plugins,
161
+ rules: {
162
+ "import/order": [
163
+ 2,
164
+ {
165
+ "alphabetize": {
166
+ order: "asc",
167
+ caseInsensitive: true
168
+ },
169
+ "newlines-between": "never",
170
+ "pathGroups": LAYERS_REVERSED.map(
171
+ (layer) => ({
172
+ pattern: `**/?(*)${layer}{,/**}`,
173
+ group: "internal",
174
+ position: "after"
175
+ })
176
+ ),
177
+ "distinctGroup": false,
178
+ "pathGroupsExcludedImportTypes": ["builtin", "type"],
179
+ "groups": ["builtin", "external", "internal", "type", "parent", "sibling", "index"]
180
+ }
181
+ ]
182
+ }
183
+ };
184
+
185
+ // src/configs/import-order/index.ts
186
+ var importOrder = {
187
+ recommended,
188
+ "with-newlines": withNewlines,
189
+ "with-type-group": withTypeGroup,
190
+ "with-newlines-and-type-group": withNewlinesAndTypeGroup
191
+ };
192
+
193
+ // package.json
194
+ var version = "2.0.0-rc.1";
195
+
196
+ // src/lib/rule/create-rule.ts
197
+ var import_eslint_utils = require("@typescript-eslint/utils/eslint-utils");
198
+ var blobUrl = "https://github.com/conarti/eslint-plugin-feature-sliced/blob/master/src/rules";
199
+ var createEslintRule = (0, import_eslint_utils.RuleCreator)(
200
+ (ruleName) => `${blobUrl}/${ruleName}/index.test.ts`
201
+ );
202
+
203
+ // src/lib/path/is-path-relative.ts
204
+ function isPathRelative(path3) {
205
+ return path3.startsWith(".");
206
+ }
207
+
208
+ // src/lib/path/join-path.ts
209
+ var import_node_path2 = __toESM(require("path"), 1);
210
+
211
+ // src/lib/path/normalize-path.ts
212
+ var import_node_path = __toESM(require("path"), 1);
213
+ function normalizePath(targetPath) {
214
+ const winSepRegExp = /\\/g;
215
+ const withNormalizedSeparators = import_node_path.default.normalize(targetPath).replace(winSepRegExp, pathSeparator);
216
+ if (targetPath.startsWith("./")) {
217
+ return `./${withNormalizedSeparators}`;
218
+ }
219
+ return withNormalizedSeparators;
220
+ }
221
+
222
+ // src/lib/path/join-path.ts
223
+ function joinPath(from, to) {
224
+ return normalizePath(import_node_path2.default.join(normalizePath(from), normalizePath(to)));
225
+ }
226
+
227
+ // src/lib/path/convert-to-absolute.ts
228
+ function convertToAbsolute(base, target) {
229
+ if (target === "") {
230
+ return base;
231
+ }
232
+ if (base === "") {
233
+ return target;
234
+ }
235
+ if (!isPathRelative(target)) {
236
+ return target;
237
+ }
238
+ return joinPath(base, `../${target}`);
239
+ }
240
+
241
+ // src/lib/rule/extract-current-file-path.ts
242
+ function extractCurrentFilePath(context) {
243
+ const currentFilePath = context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename();
244
+ return normalizePath(currentFilePath);
245
+ }
246
+
247
+ // src/lib/shared/get-by-reg-exp.ts
248
+ function getByRegExp(target, regExp, fromEnd = false) {
249
+ const results = target.match(regExp) || [];
250
+ if (fromEnd) {
251
+ const lastResult = results[results.length - 1];
252
+ return lastResult || null;
253
+ }
254
+ return results[0] || null;
255
+ }
256
+
257
+ // src/lib/shared/is-null.ts
258
+ function isNull(target) {
259
+ return target === null;
260
+ }
261
+
262
+ // src/lib/shared/is-object.ts
263
+ function isObject(target) {
264
+ return (typeof target === "object" || typeof target === "function") && target !== null;
265
+ }
266
+
267
+ // src/lib/shared/is-undefined.ts
268
+ function isUndefined(target) {
269
+ return target === void 0;
270
+ }
271
+
272
+ // src/lib/rule/extract-cwd.ts
273
+ function extractCwd(context) {
274
+ const cwd = context.getCwd?.();
275
+ if (isUndefined(cwd)) {
276
+ return void 0;
277
+ }
278
+ return normalizePath(cwd);
279
+ }
280
+
281
+ // src/lib/rule/extract-node-path.ts
282
+ function extractNodePath(node) {
283
+ const targetPath = node.source.value;
284
+ const normalizedTargetPath = normalizePath(targetPath);
285
+ return {
286
+ targetPath,
287
+ normalizedTargetPath
288
+ };
289
+ }
290
+
291
+ // src/lib/rule/extract-paths.ts
292
+ function extractPaths(node, context) {
293
+ const normalizedCurrentFilePath = extractCurrentFilePath(context);
294
+ const {
295
+ targetPath,
296
+ normalizedTargetPath
297
+ } = extractNodePath(node);
298
+ const absoluteTargetPath = convertToAbsolute(normalizedCurrentFilePath, normalizedTargetPath);
299
+ const cwd = extractCwd(context);
300
+ return {
301
+ targetPath,
302
+ normalizedTargetPath,
303
+ normalizedCurrentFilePath,
304
+ absoluteTargetPath,
305
+ normalizedCwd: cwd
306
+ };
307
+ }
308
+
309
+ // src/lib/rule/extract-rule-options.ts
310
+ function extractRuleOptions(optionsWithDefault) {
311
+ return optionsWithDefault[0];
312
+ }
313
+
314
+ // src/lib/rule/get-source-range-without-quotes.ts
315
+ function getSourceRangeWithoutQuotes([rangeStart, rangeEnd]) {
316
+ return [rangeStart + 1, rangeEnd - 1];
317
+ }
318
+
319
+ // src/lib/rule/has-path.ts
320
+ function hasPath(node) {
321
+ if (isObject(node) && "source" in node) {
322
+ return node.source !== null;
323
+ }
324
+ return false;
325
+ }
326
+
327
+ // src/lib/rule/is-ignored.ts
328
+ var import_picomatch = __toESM(require("picomatch"), 1);
329
+ function isIgnored(path3, patterns) {
330
+ const match = (0, import_picomatch.default)(patterns);
331
+ return match(path3);
332
+ }
333
+
334
+ // src/lib/rule/is-ignored-current-file.ts
335
+ function isIgnoredCurrentFile(context, optionsWithDefault) {
336
+ const ruleOptions = extractRuleOptions(optionsWithDefault);
337
+ const normalizedCurrentFilePath = extractCurrentFilePath(context);
338
+ return isIgnored(normalizedCurrentFilePath, ruleOptions.ignoreInFilesPatterns);
339
+ }
340
+
341
+ // src/lib/rule/is-ignored-target.ts
342
+ function isIgnoredTarget(node, optionsWithDefault) {
343
+ const { targetPath } = extractNodePath(node);
344
+ const userDefinedRuleOptions = extractRuleOptions(optionsWithDefault);
345
+ return isIgnored(targetPath, userDefinedRuleOptions.ignorePatterns);
346
+ }
347
+
348
+ // src/lib/rule/is-node-type.ts
349
+ var import_utils = require("@typescript-eslint/utils");
350
+ function isNodeType(node) {
351
+ const isImport = import_utils.ASTUtils.isNodeOfTypes([import_utils.AST_NODE_TYPES.ImportSpecifier, import_utils.AST_NODE_TYPES.ImportDeclaration])(node);
352
+ const isExport = import_utils.ASTUtils.isNodeOfTypes([import_utils.AST_NODE_TYPES.ExportAllDeclaration, import_utils.AST_NODE_TYPES.ExportNamedDeclaration])(node);
353
+ if (isImport) {
354
+ return node.importKind === "type";
355
+ }
356
+ if (isExport) {
357
+ return node.exportKind === "type";
358
+ }
359
+ return false;
360
+ }
361
+
362
+ // src/lib/feature-sliced/extract-layer.ts
363
+ function prepareToExtract(targetPath, cwd) {
364
+ const lowerCasedTargetPath = targetPath.toLowerCase();
365
+ if (cwd === void 0) {
366
+ return lowerCasedTargetPath;
367
+ }
368
+ const lowerCasedCwd = cwd.toLowerCase();
369
+ const pathWithoutCwd = lowerCasedTargetPath.replace(lowerCasedCwd, "");
370
+ return pathWithoutCwd;
371
+ }
372
+ function extractLayer(targetPath, cwd) {
373
+ const layersRegExpPattern = `(${layers.join("|")})(?![\\w\\.-])`;
374
+ const layersRegExp = new RegExp(layersRegExpPattern, "gi");
375
+ const pathForExtract = prepareToExtract(targetPath, cwd);
376
+ return getByRegExp(pathForExtract, layersRegExp);
377
+ }
378
+
379
+ // src/lib/feature-sliced/extract-segment.ts
380
+ var layersUnion = layersWithSlices.join("|");
381
+ var segmentsUnion = segments.join("|");
382
+ var fsdPartsRegExp = new RegExp(
383
+ `(?<=(?<layer>${layersUnion}))\\/(?<slice>([\\w-]*\\/)+?)(?<segment>(${segmentsUnion})(\\.\\w+)?)(\\/(?<segmentFiles>.*))?`
384
+ );
385
+ function extractSegment(targetPath) {
386
+ const fsdParts = targetPath.match(fsdPartsRegExp);
387
+ if (fsdParts === null) {
388
+ return [null, null];
389
+ }
390
+ const {
391
+ segment = null,
392
+ segmentFiles = null
393
+ } = fsdParts.groups || {};
394
+ const fileExtensionRegExp = /\.[^/.]+$/;
395
+ const segmentWithoutFileExtension = segment?.replace(fileExtensionRegExp, "") || null;
396
+ return [segmentWithoutFileExtension, segmentFiles];
397
+ }
398
+
399
+ // src/lib/feature-sliced/extract-slice.ts
400
+ function extractSlice(targetPath) {
401
+ const targetPathWithoutCurrentFileName = targetPath.replace(/\/\w+\.\w+$/, "");
402
+ return getByRegExp(targetPathWithoutCurrentFileName, new RegExp(`(?<=(${layersWithSlices.join("|")})\\/)(\\w|-)+`, "gi"));
403
+ }
404
+
405
+ // src/lib/feature-sliced/extract-feature-sliced-parts.ts
406
+ function extractFeatureSlicedParts(targetPath, cwd) {
407
+ const layer = extractLayer(targetPath, cwd);
408
+ const slice = extractSlice(targetPath);
409
+ const [segment, segmentFiles] = extractSegment(targetPath);
410
+ return {
411
+ layer,
412
+ slice,
413
+ segment,
414
+ segmentFiles
415
+ };
416
+ }
417
+
418
+ // src/lib/feature-sliced/layers.ts
419
+ function isLayer(layer) {
420
+ return typeof layer === "string" && layers.includes(layer);
421
+ }
422
+ function getLayerWeight(layer) {
423
+ return layers.indexOf(layer);
424
+ }
425
+ function canLayerContainSlices(layer) {
426
+ return !layersWithoutSlices.includes(layer);
427
+ }
428
+
429
+ // src/lib/feature-sliced/validate-extracted-feature-sliced-parts.ts
430
+ function validateExtractedFeatureSlicedParts(extractedFeatureSlicedParts) {
431
+ const {
432
+ layer,
433
+ slice,
434
+ segment,
435
+ segmentFiles
436
+ } = extractedFeatureSlicedParts;
437
+ const hasLayer = isLayer(layer);
438
+ const hasNotLayer = !hasLayer;
439
+ const hasSlice = !isNull(slice);
440
+ const hasNotSlice = !hasSlice;
441
+ const hasSegment = !isNull(segment);
442
+ const hasNotSegment = !hasSegment;
443
+ const hasSegmentFiles = !isNull(segmentFiles);
444
+ const hasNotSegmentFiles = !hasSegmentFiles;
445
+ const canContainSlices = hasLayer && canLayerContainSlices(layer);
446
+ return {
447
+ hasLayer,
448
+ hasNotLayer,
449
+ hasSlice,
450
+ hasNotSlice,
451
+ hasSegment,
452
+ hasNotSegment,
453
+ hasSegmentFiles,
454
+ hasNotSegmentFiles,
455
+ canLayerContainSlices: canContainSlices
456
+ };
457
+ }
458
+
459
+ // src/lib/feature-sliced/extract-paths-info.ts
460
+ function compareFeatureSlicedParts(fsPartsToCompare) {
461
+ const {
462
+ target,
463
+ currentFile
464
+ } = fsPartsToCompare;
465
+ const hasUnknownLayers = target.validatedFeatureSlicedParts.hasNotLayer || currentFile.validatedFeatureSlicedParts.hasNotLayer;
466
+ const isSameLayer = target.validatedFeatureSlicedParts.hasLayer && currentFile.validatedFeatureSlicedParts.hasLayer && target.fsdParts.layer === currentFile.fsdParts.layer;
467
+ const isSameSlice = target.validatedFeatureSlicedParts.hasSlice && currentFile.validatedFeatureSlicedParts.hasSlice && target.fsdParts.slice === currentFile.fsdParts.slice;
468
+ const isSameSegment = target.fsdParts.segment === currentFile.fsdParts.segment;
469
+ const isSameLayerWithoutSlices = isSameLayer && !target.validatedFeatureSlicedParts.canLayerContainSlices && !currentFile.validatedFeatureSlicedParts.canLayerContainSlices;
470
+ return {
471
+ hasUnknownLayers,
472
+ isSameLayer,
473
+ isSameSlice,
474
+ isSameSegment,
475
+ isSameLayerWithoutSlices
476
+ };
477
+ }
478
+ function extractPathsInfo(node, context) {
479
+ const {
480
+ targetPath,
481
+ normalizedTargetPath,
482
+ normalizedCurrentFilePath,
483
+ absoluteTargetPath,
484
+ normalizedCwd
485
+ } = extractPaths(node, context);
486
+ const fsdPartsOfTarget = extractFeatureSlicedParts(absoluteTargetPath, normalizedCwd);
487
+ const fsdPartsOfCurrentFile = extractFeatureSlicedParts(normalizedCurrentFilePath, normalizedCwd);
488
+ const validatedFeatureSlicedPartsOfTarget = validateExtractedFeatureSlicedParts(fsdPartsOfTarget);
489
+ const validatedFeatureSlicedPartsOfCurrentFile = validateExtractedFeatureSlicedParts(fsdPartsOfCurrentFile);
490
+ const {
491
+ hasUnknownLayers,
492
+ isSameLayer,
493
+ isSameSlice,
494
+ isSameSegment,
495
+ isSameLayerWithoutSlices
496
+ } = compareFeatureSlicedParts({
497
+ target: {
498
+ validatedFeatureSlicedParts: validatedFeatureSlicedPartsOfTarget,
499
+ fsdParts: fsdPartsOfTarget
500
+ },
501
+ currentFile: {
502
+ validatedFeatureSlicedParts: validatedFeatureSlicedPartsOfCurrentFile,
503
+ fsdParts: fsdPartsOfCurrentFile
504
+ }
505
+ });
506
+ return {
507
+ targetPath,
508
+ normalizedTargetPath,
509
+ normalizedCurrentFilePath,
510
+ absoluteTargetPath,
511
+ fsdPartsOfTarget,
512
+ fsdPartsOfCurrentFile,
513
+ isSameLayer,
514
+ isSameSlice,
515
+ isSameSegment,
516
+ isSameLayerWithoutSlices,
517
+ hasUnknownLayers,
518
+ validatedFeatureSlicedPartsOfTarget,
519
+ validatedFeatureSlicedPartsOfCurrentFile
520
+ };
521
+ }
522
+
523
+ // src/rules/absolute-relative/model/errors.ts
524
+ function reportShouldBeRelative(node, context) {
525
+ context.report({
526
+ node: node.source,
527
+ messageId: "must-be-relative-path" /* MUST_BE_RELATIVE_PATH */
528
+ });
529
+ }
530
+ function reportShouldBeAbsolute(node, context) {
531
+ context.report({
532
+ node: node.source,
533
+ messageId: "must-be-absolute-path" /* MUST_BE_ABSOLUTE_PATH */
534
+ });
535
+ }
536
+
537
+ // src/rules/absolute-relative/model/should-be-absolute.ts
538
+ function shouldBeAbsolute(pathsInfo) {
539
+ const {
540
+ normalizedTargetPath,
541
+ fsdPartsOfTarget,
542
+ fsdPartsOfCurrentFile,
543
+ hasUnknownLayers
544
+ } = pathsInfo;
545
+ const isAbsolute = !isPathRelative(normalizedTargetPath);
546
+ if (isAbsolute) {
547
+ return false;
548
+ }
549
+ if (hasUnknownLayers) {
550
+ return false;
551
+ }
552
+ return fsdPartsOfCurrentFile.layer !== fsdPartsOfTarget.layer;
553
+ }
554
+
555
+ // src/rules/absolute-relative/model/should-be-relative.ts
556
+ function shouldBeRelative(pathsInfo) {
557
+ const {
558
+ validatedFeatureSlicedPartsOfCurrentFile,
559
+ normalizedTargetPath,
560
+ isSameLayerWithoutSlices,
561
+ isSameLayer,
562
+ isSameSlice
563
+ } = pathsInfo;
564
+ const isRelative = isPathRelative(normalizedTargetPath);
565
+ if (isRelative) {
566
+ return false;
567
+ }
568
+ const isImportToLayerPublicApi = validatedFeatureSlicedPartsOfCurrentFile.hasNotSlice && isSameLayer;
569
+ if (isImportToLayerPublicApi) {
570
+ return true;
571
+ }
572
+ if (isSameLayerWithoutSlices) {
573
+ return true;
574
+ }
575
+ const isSameLayerAndSlice = isSameLayer && isSameSlice;
576
+ return isSameLayerAndSlice;
577
+ }
578
+
579
+ // src/rules/absolute-relative/model/validate-and-report.ts
580
+ function validateAndReport(node, context, optionsWithDefault, options = { needCheckForAbsolute: true }) {
581
+ if (!hasPath(node)) {
582
+ return;
583
+ }
584
+ if (isIgnoredCurrentFile(context, optionsWithDefault)) {
585
+ return;
586
+ }
587
+ const pathsInfo = extractPathsInfo(node, context);
588
+ if (shouldBeRelative(pathsInfo)) {
589
+ reportShouldBeRelative(node, context);
590
+ }
591
+ if (options.needCheckForAbsolute && shouldBeAbsolute(pathsInfo)) {
592
+ reportShouldBeAbsolute(node, context);
593
+ }
594
+ }
595
+
596
+ // src/rules/absolute-relative/index.ts
597
+ var absolute_relative_default = createEslintRule({
598
+ name: "absolute-relative",
599
+ meta: {
600
+ type: "problem",
601
+ docs: {
602
+ description: "Checks for absolute and relative paths"
603
+ },
604
+ messages: {
605
+ ["must-be-relative-path" /* MUST_BE_RELATIVE_PATH */]: "There must be relative paths",
606
+ ["must-be-absolute-path" /* MUST_BE_ABSOLUTE_PATH */]: "There must be absolute paths"
607
+ },
608
+ schema: [
609
+ {
610
+ type: "object",
611
+ properties: {
612
+ ignoreInFilesPatterns: {
613
+ type: "array",
614
+ items: {
615
+ type: "string"
616
+ }
617
+ }
618
+ }
619
+ }
620
+ ]
621
+ },
622
+ defaultOptions: [
623
+ {
624
+ ignoreInFilesPatterns: []
625
+ }
626
+ ],
627
+ create(context, optionsWithDefault) {
628
+ return {
629
+ ImportDeclaration(node) {
630
+ validateAndReport(node, context, optionsWithDefault);
631
+ },
632
+ ImportExpression(node) {
633
+ validateAndReport(node, context, optionsWithDefault);
634
+ },
635
+ ExportAllDeclaration(node) {
636
+ validateAndReport(node, context, optionsWithDefault, { needCheckForAbsolute: false });
637
+ },
638
+ ExportNamedDeclaration(node) {
639
+ validateAndReport(node, context, optionsWithDefault, { needCheckForAbsolute: false });
640
+ }
641
+ };
642
+ }
643
+ });
644
+
645
+ // src/rules/layers-slices/model/validate-and-report.ts
646
+ var import_utils4 = require("@typescript-eslint/utils");
647
+
648
+ // src/rules/layers-slices/model/errors.ts
649
+ var import_utils2 = require("@typescript-eslint/utils");
650
+ function reportCanNotImportLayer(context, node, pathsInfo) {
651
+ function getReportPosition(validatedNode) {
652
+ const isSpecifier = validatedNode.type === import_utils2.AST_NODE_TYPES.ImportSpecifier;
653
+ if (isSpecifier) {
654
+ return validatedNode;
655
+ }
656
+ return validatedNode.source;
657
+ }
658
+ context.report({
659
+ node: getReportPosition(node),
660
+ messageId: "can-not-import" /* CAN_NOT_IMPORT */,
661
+ data: {
662
+ importLayer: pathsInfo.fsdPartsOfTarget.layer,
663
+ currentFileLayer: pathsInfo.fsdPartsOfCurrentFile.layer
664
+ }
665
+ });
666
+ }
667
+
668
+ // src/rules/layers-slices/model/is-not-suitable-for-validation.ts
669
+ function isNotSuitableForValidation(pathsInfo) {
670
+ const {
671
+ isSameSlice,
672
+ isSameLayerWithoutSlices,
673
+ hasUnknownLayers
674
+ } = pathsInfo;
675
+ if (hasUnknownLayers) {
676
+ return true;
677
+ }
678
+ if (isSameSlice) {
679
+ return true;
680
+ }
681
+ if (isSameLayerWithoutSlices) {
682
+ return true;
683
+ }
684
+ return false;
685
+ }
686
+
687
+ // src/rules/layers-slices/model/specifiers/has-errors-at-all-specifiers.ts
688
+ function hasErrorsAtAllSpecifiers(specifiers, invalidSpecifiers) {
689
+ const allSpecifiersCount = specifiers.length;
690
+ const invalidSpecifiersCount = invalidSpecifiers.length;
691
+ return invalidSpecifiersCount === allSpecifiersCount;
692
+ }
693
+
694
+ // src/rules/layers-slices/model/validate-node/valid-by-type-import.ts
695
+ function validByTypeImport(node, allowTypeImports) {
696
+ const isType = isNodeType(node);
697
+ return allowTypeImports && isType;
698
+ }
699
+
700
+ // src/rules/layers-slices/model/specifiers/validate-specifiers.ts
701
+ function validateSpecifiers(specifiers, allowTypeImports) {
702
+ return specifiers.filter((specifier) => !validByTypeImport(specifier, allowTypeImports));
703
+ }
704
+
705
+ // src/rules/layers-slices/model/specifiers/extract-import-specifiers.ts
706
+ var import_utils3 = require("@typescript-eslint/utils");
707
+ function extractImportSpecifiers(node) {
708
+ return node.specifiers.filter((specifier) => specifier.type === import_utils3.AST_NODE_TYPES.ImportSpecifier);
709
+ }
710
+
711
+ // src/rules/layers-slices/model/validate-node/valid-by-layer-order.ts
712
+ function validByLayerOrder(fsdPartsOfTarget, fsdPartsOfCurrentFile) {
713
+ const importLayerOrder = getLayerWeight(
714
+ fsdPartsOfTarget.layer
715
+ /* ts doesn't understand that the check was done on hasUnknownLayers */
716
+ );
717
+ const currentFileLayerOrder = getLayerWeight(
718
+ fsdPartsOfCurrentFile.layer
719
+ /* ts doesn't understand that the check was done on hasUnknownLayers */
720
+ );
721
+ return currentFileLayerOrder > importLayerOrder;
722
+ }
723
+
724
+ // src/rules/layers-slices/model/validate-node/index.ts
725
+ function validateNode(node, pathsInfo, allowTypeImports) {
726
+ const {
727
+ fsdPartsOfTarget,
728
+ fsdPartsOfCurrentFile
729
+ } = pathsInfo;
730
+ if (validByTypeImport(node, allowTypeImports)) {
731
+ return true;
732
+ }
733
+ if (validByLayerOrder(fsdPartsOfTarget, fsdPartsOfCurrentFile)) {
734
+ return true;
735
+ }
736
+ return false;
737
+ }
738
+
739
+ // src/rules/layers-slices/model/validate-and-report.ts
740
+ function validate(node, pathsInfo, allowTypeImports) {
741
+ if (validateNode(node, pathsInfo, allowTypeImports)) {
742
+ return [];
743
+ }
744
+ const isImportExpression = import_utils4.ASTUtils.isNodeOfType(import_utils4.AST_NODE_TYPES.ImportExpression)(node);
745
+ if (isImportExpression) {
746
+ return [node];
747
+ }
748
+ const specifiers = extractImportSpecifiers(node);
749
+ const invalidSpecifiers = validateSpecifiers(specifiers, allowTypeImports);
750
+ if (hasErrorsAtAllSpecifiers(specifiers, invalidSpecifiers)) {
751
+ return [node];
752
+ }
753
+ return invalidSpecifiers;
754
+ }
755
+ function reportValidationErrors(nodes, context, pathsInfo) {
756
+ nodes.forEach((node) => reportCanNotImportLayer(context, node, pathsInfo));
757
+ }
758
+ function validateAndReport2(node, context, optionsWithDefault) {
759
+ if (!hasPath(node)) {
760
+ return;
761
+ }
762
+ const isIgnoredForValidation = isIgnoredTarget(node, optionsWithDefault) || isIgnoredCurrentFile(context, optionsWithDefault);
763
+ if (isIgnoredForValidation) {
764
+ return;
765
+ }
766
+ const pathsInfo = extractPathsInfo(node, context);
767
+ if (isNotSuitableForValidation(pathsInfo)) {
768
+ return;
769
+ }
770
+ const { allowTypeImports } = extractRuleOptions(optionsWithDefault);
771
+ const nodesToReport = validate(node, pathsInfo, allowTypeImports);
772
+ reportValidationErrors(nodesToReport, context, pathsInfo);
773
+ }
774
+
775
+ // src/rules/layers-slices/index.ts
776
+ var layers_slices_default = createEslintRule({
777
+ name: "layers-slices",
778
+ meta: {
779
+ type: "problem",
780
+ docs: {
781
+ description: "Checks layer imports"
782
+ },
783
+ messages: {
784
+ ["can-not-import" /* CAN_NOT_IMPORT */]: 'You cannot import layer "{{ importLayer }}" into "{{ currentFileLayer }}" (shared -> entities -> features -> widgets -> pages -> processes -> app)'
785
+ },
786
+ schema: [
787
+ {
788
+ type: "object",
789
+ properties: {
790
+ allowTypeImports: {
791
+ type: "boolean"
792
+ },
793
+ ignorePatterns: {
794
+ type: "array",
795
+ items: {
796
+ type: "string"
797
+ }
798
+ },
799
+ ignoreInFilesPatterns: {
800
+ type: "array",
801
+ items: {
802
+ type: "string"
803
+ }
804
+ }
805
+ }
806
+ }
807
+ ]
808
+ },
809
+ defaultOptions: [
810
+ {
811
+ allowTypeImports: true,
812
+ ignorePatterns: [],
813
+ ignoreInFilesPatterns: []
814
+ }
815
+ ],
816
+ create(context, optionsWithDefault) {
817
+ return {
818
+ ImportDeclaration(node) {
819
+ validateAndReport2(node, context, optionsWithDefault);
820
+ },
821
+ ImportExpression(node) {
822
+ validateAndReport2(node, context, optionsWithDefault);
823
+ }
824
+ };
825
+ }
826
+ });
827
+
828
+ // src/rules/public-api/model/convert-to-public-api.ts
829
+ function addSlashToStart(targetPath) {
830
+ if (isNull(targetPath)) {
831
+ return "";
832
+ }
833
+ return `/${targetPath}`;
834
+ }
835
+ function extractValueToRemove(pathsInfo) {
836
+ const {
837
+ isSameSlice,
838
+ fsdPartsOfTarget
839
+ } = pathsInfo;
840
+ if (isSameSlice) {
841
+ return fsdPartsOfTarget.segmentFiles;
842
+ }
843
+ return `${fsdPartsOfTarget.segment}${addSlashToStart(fsdPartsOfTarget.segmentFiles)}`;
844
+ }
845
+ function convertToPublicApi(pathsInfo) {
846
+ const { normalizedTargetPath } = pathsInfo;
847
+ const valueToRemove = extractValueToRemove(pathsInfo);
848
+ const publicApiPath = normalizedTargetPath.replace(`/${valueToRemove}`, "");
849
+ return [publicApiPath, valueToRemove];
850
+ }
851
+
852
+ // src/rules/public-api/model/errors.ts
853
+ function reportShouldBeFromPublicApi(node, context) {
854
+ const pathsInfo = extractPathsInfo(node, context);
855
+ const [fixedPath, valueToRemove] = convertToPublicApi(pathsInfo);
856
+ context.report({
857
+ node: node.source,
858
+ messageId: "should-be-from-public-api" /* SHOULD_BE_FROM_PUBLIC_API */,
859
+ data: {
860
+ fixedPath
861
+ },
862
+ suggest: [
863
+ {
864
+ messageId: "remove-suggestion" /* REMOVE_SUGGESTION */,
865
+ data: {
866
+ valueToRemove
867
+ },
868
+ fix: (fixer) => fixer.replaceTextRange(getSourceRangeWithoutQuotes(node.source.range), fixedPath)
869
+ }
870
+ ]
871
+ });
872
+ }
873
+ function reportLayersPublicApiNotAllowed(node, context) {
874
+ context.report({
875
+ node,
876
+ messageId: "layers-public-api-not-allowed" /* LAYERS_PUBLIC_API_NOT_ALLOWED */
877
+ });
878
+ }
879
+
880
+ // src/rules/public-api/model/is-index-file.ts
881
+ function isIndexFile(segmentFiles) {
882
+ return /^index\.\w+/i.test(segmentFiles);
883
+ }
884
+
885
+ // src/rules/public-api/model/is-segments-public-api.ts
886
+ function isSegmentsPublicApi(pathsInfo) {
887
+ const {
888
+ fsdPartsOfTarget,
889
+ validatedFeatureSlicedPartsOfTarget,
890
+ isSameSegment
891
+ } = pathsInfo;
892
+ const isSegmentPublicApi = validatedFeatureSlicedPartsOfTarget.hasNotSegmentFiles || isIndexFile(
893
+ fsdPartsOfTarget.segmentFiles
894
+ /* 'hasNotSegmentFiles' is already validate it, ts doesn't understand */
895
+ );
896
+ return isSameSegment || isSegmentPublicApi;
897
+ }
898
+
899
+ // src/rules/public-api/model/is-slice-public-api.ts
900
+ function isSlicePublicApi(pathsInfo) {
901
+ return pathsInfo.validatedFeatureSlicedPartsOfTarget.hasNotSegment;
902
+ }
903
+
904
+ // src/rules/public-api/model/should-be-from-public-api.ts
905
+ function shouldBeFromSlicePublicApi(pathsInfo) {
906
+ const isFromAnotherSlice = !pathsInfo.isSameSlice;
907
+ return isFromAnotherSlice && !isSlicePublicApi(pathsInfo);
908
+ }
909
+ function shouldBeFromSegmentsPublicApi(pathsInfo, validateOptions) {
910
+ const needValidateSegments = validateOptions.level === "segments" /* SEGMENTS */;
911
+ return needValidateSegments && !isSegmentsPublicApi(pathsInfo);
912
+ }
913
+ function shouldBeFromPublicApi(node, context, optionsWithDefault) {
914
+ const pathsInfo = extractPathsInfo(node, context);
915
+ const ruleOptions = extractRuleOptions(optionsWithDefault);
916
+ return shouldBeFromSlicePublicApi(pathsInfo) || shouldBeFromSegmentsPublicApi(pathsInfo, ruleOptions);
917
+ }
918
+
919
+ // src/rules/public-api/model/validate-and-report.ts
920
+ function validateAndReport3(node, context, optionsWithDefault) {
921
+ if (!hasPath(node)) {
922
+ return;
923
+ }
924
+ if (isIgnoredCurrentFile(context, optionsWithDefault)) {
925
+ return;
926
+ }
927
+ if (shouldBeFromPublicApi(node, context, optionsWithDefault)) {
928
+ reportShouldBeFromPublicApi(node, context);
929
+ }
930
+ }
931
+
932
+ // src/rules/public-api/model/is-layer-public-api.ts
933
+ var import_picomatch2 = __toESM(require("picomatch"), 1);
934
+ function isLayerPublicApi(context) {
935
+ const normalizedCurrentFilePath = extractCurrentFilePath(context);
936
+ const cwd = extractCwd(context);
937
+ const layer = extractLayer(normalizedCurrentFilePath, cwd);
938
+ if (isNull(layer)) {
939
+ return false;
940
+ }
941
+ const matcher = (0, import_picomatch2.default)([
942
+ `**/${layer}/index.*`
943
+ ]);
944
+ return matcher(normalizedCurrentFilePath);
945
+ }
946
+
947
+ // src/rules/public-api/model/validate-and-report-program.ts
948
+ function validateAndReportProgram(node, context, optionsWithDefault) {
949
+ if (isIgnoredCurrentFile(context, optionsWithDefault)) {
950
+ return;
951
+ }
952
+ if (isLayerPublicApi(context)) {
953
+ reportLayersPublicApiNotAllowed(node, context);
954
+ }
955
+ }
956
+
957
+ // src/rules/public-api/index.ts
958
+ var public_api_default = createEslintRule({
959
+ name: "public-api",
960
+ meta: {
961
+ type: "problem",
962
+ docs: {
963
+ description: "Check for module imports from public api"
964
+ },
965
+ hasSuggestions: true,
966
+ messages: {
967
+ ["should-be-from-public-api" /* SHOULD_BE_FROM_PUBLIC_API */]: 'Absolute imports are only allowed from public api ("{{ fixedPath }}")',
968
+ ["remove-suggestion" /* REMOVE_SUGGESTION */]: 'Remove the "{{ valueToRemove }}"',
969
+ ["layers-public-api-not-allowed" /* LAYERS_PUBLIC_API_NOT_ALLOWED */]: "The layer public API is not allowed. It harms both architecturally and practically (code splitting)"
970
+ },
971
+ schema: [
972
+ {
973
+ type: "object",
974
+ properties: {
975
+ level: {
976
+ type: "string",
977
+ enum: [
978
+ "segments" /* SEGMENTS */,
979
+ "slices" /* SLICES */
980
+ ]
981
+ },
982
+ ignoreInFilesPatterns: {
983
+ type: "array",
984
+ items: {
985
+ type: "string"
986
+ }
987
+ }
988
+ }
989
+ }
990
+ ]
991
+ },
992
+ defaultOptions: [
993
+ {
994
+ level: "slices" /* SLICES */,
995
+ ignoreInFilesPatterns: []
996
+ }
997
+ ],
998
+ create(context, optionsWithDefault) {
999
+ return {
1000
+ ImportDeclaration(node) {
1001
+ validateAndReport3(node, context, optionsWithDefault);
1002
+ },
1003
+ ImportExpression(node) {
1004
+ validateAndReport3(node, context, optionsWithDefault);
1005
+ },
1006
+ ExportAllDeclaration(node) {
1007
+ validateAndReport3(node, context, optionsWithDefault);
1008
+ },
1009
+ ExportNamedDeclaration(node) {
1010
+ validateAndReport3(node, context, optionsWithDefault);
1011
+ },
1012
+ Program(node) {
1013
+ validateAndReportProgram(node, context, optionsWithDefault);
1014
+ }
1015
+ };
1016
+ }
1017
+ });
1018
+
1019
+ // src/rules/index.ts
1020
+ var rules = {
1021
+ "absolute-relative": absolute_relative_default,
1022
+ "layers-slices": layers_slices_default,
1023
+ "public-api": public_api_default
1024
+ };
1025
+ var rules_default = rules;
1026
+
1027
+ // src/plugin.ts
1028
+ var plugin = {
1029
+ meta: {
1030
+ name: PLUGIN_NAME,
1031
+ version
1032
+ },
1033
+ rules: rules_default
1034
+ };
1035
+
1036
+ // src/create-plugin.ts
1037
+ function createPlugin(options = {}) {
1038
+ const {
1039
+ sortImports = "recommended",
1040
+ absoluteRelative,
1041
+ layersSlices,
1042
+ publicApi
1043
+ } = options;
1044
+ const rules2 = defineRules({ absoluteRelative, layersSlices, publicApi });
1045
+ const config = {
1046
+ name: PLUGIN_NAME,
1047
+ plugins: {
1048
+ [PLUGIN_NAME]: plugin
1049
+ },
1050
+ rules: rules2
1051
+ };
1052
+ return enhanceWithImportOrder(config, sortImports);
1053
+ }
1054
+ function defineRules(options) {
1055
+ const {
1056
+ absoluteRelative = {},
1057
+ layersSlices = {},
1058
+ publicApi = {}
1059
+ } = options;
1060
+ const createRuleName = (rule) => `${PLUGIN_NAME}/${rule}`;
1061
+ const createRuleEntry = (ruleOptions) => ruleOptions ? ["error", ruleOptions] : ["off"];
1062
+ const rules2 = {
1063
+ [createRuleName("layers-slices")]: createRuleEntry(layersSlices),
1064
+ [createRuleName("absolute-relative")]: createRuleEntry(absoluteRelative),
1065
+ [createRuleName("public-api")]: createRuleEntry(publicApi)
1066
+ };
1067
+ return rules2;
1068
+ }
1069
+ function enhanceWithImportOrder(config, importOrderConfigName) {
1070
+ if (!importOrderConfigName) {
1071
+ return config;
1072
+ }
1073
+ const importOrderConfig = importOrder[importOrderConfigName];
1074
+ return (0, import_eslint_flat_config_utils.mergeConfigs)(
1075
+ importOrderConfig,
1076
+ config
1077
+ // the last one is to set the configuration name as 'PLUGIN_NAME'
1078
+ );
1079
+ }
1080
+
1081
+ // src/index.ts
1082
+ var src_default = createPlugin;