@conarti/eslint-plugin-feature-sliced 1.0.5 → 2.0.0-rc.2

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