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