@cloud-ru/ft-deps-validator 1.1.1 → 1.1.2-preview-9ce1a08.0

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 (115) hide show
  1. package/README.md +34 -15
  2. package/dist/cjs/Checker/MonorepoChecker.d.ts +10 -0
  3. package/dist/cjs/Checker/MonorepoChecker.js +57 -0
  4. package/dist/cjs/Checker/RepoChecker.d.ts +8 -0
  5. package/dist/cjs/Checker/RepoChecker.js +36 -0
  6. package/dist/cjs/Checker/__tests__/MonorepoChecker.spec.js +305 -0
  7. package/dist/cjs/Checker/__tests__/RepoChecker.spec.js +116 -0
  8. package/dist/cjs/Checker/index.d.ts +2 -0
  9. package/dist/cjs/Checker/index.js +7 -0
  10. package/dist/cjs/Config/MonorepoConfig.d.ts +12 -0
  11. package/dist/cjs/Config/MonorepoConfig.js +42 -0
  12. package/dist/cjs/Config/RepoConfig.d.ts +10 -0
  13. package/dist/cjs/Config/RepoConfig.js +27 -0
  14. package/dist/cjs/Config/__tests__/MonorepoConfig.spec.js +296 -0
  15. package/dist/cjs/Config/__tests__/RepoConfig.spec.d.ts +1 -0
  16. package/dist/cjs/Config/__tests__/RepoConfig.spec.js +99 -0
  17. package/dist/cjs/Config/index.d.ts +2 -0
  18. package/dist/cjs/Config/index.js +7 -0
  19. package/dist/cjs/Report/__tests__/Report.spec.d.ts +1 -0
  20. package/dist/cjs/Report/__tests__/Report.spec.js +176 -0
  21. package/dist/cjs/Report/index.d.ts +11 -0
  22. package/dist/cjs/Report/index.js +55 -0
  23. package/dist/cjs/index.d.ts +0 -1
  24. package/dist/cjs/index.js +13 -57
  25. package/dist/{esm/types/config.d.ts → cjs/types.d.ts} +14 -3
  26. package/dist/cjs/utils/__tests__/getCliArguments.spec.d.ts +1 -0
  27. package/dist/cjs/utils/__tests__/getCliArguments.spec.js +70 -0
  28. package/dist/cjs/utils/getCliArguments.d.ts +6 -6
  29. package/dist/cjs/utils/getCliArguments.js +1 -27
  30. package/dist/cjs/utils/getConfigFile.d.ts +4 -3
  31. package/dist/cjs/utils/getConfigFile.js +3 -9
  32. package/dist/cjs/utils/getEnvironment.d.ts +3 -0
  33. package/dist/cjs/utils/getEnvironment.js +50 -0
  34. package/dist/cjs/utils/readPackageJsonFile.d.ts +9 -0
  35. package/dist/cjs/utils/readPackageJsonFile.js +28 -0
  36. package/dist/esm/Checker/MonorepoChecker.d.ts +10 -0
  37. package/dist/esm/Checker/MonorepoChecker.js +53 -0
  38. package/dist/esm/Checker/RepoChecker.d.ts +8 -0
  39. package/dist/esm/Checker/RepoChecker.js +29 -0
  40. package/dist/esm/Checker/__tests__/MonorepoChecker.spec.d.ts +1 -0
  41. package/dist/esm/Checker/__tests__/MonorepoChecker.spec.js +300 -0
  42. package/dist/esm/Checker/__tests__/RepoChecker.spec.d.ts +1 -0
  43. package/dist/esm/Checker/__tests__/RepoChecker.spec.js +111 -0
  44. package/dist/esm/Checker/index.d.ts +2 -0
  45. package/dist/esm/Checker/index.js +2 -0
  46. package/dist/esm/Config/MonorepoConfig.d.ts +12 -0
  47. package/dist/esm/Config/MonorepoConfig.js +35 -0
  48. package/dist/esm/Config/RepoConfig.d.ts +10 -0
  49. package/dist/esm/Config/RepoConfig.js +20 -0
  50. package/dist/esm/Config/__tests__/MonorepoConfig.spec.d.ts +1 -0
  51. package/dist/esm/Config/__tests__/MonorepoConfig.spec.js +291 -0
  52. package/dist/esm/Config/__tests__/RepoConfig.spec.d.ts +1 -0
  53. package/dist/esm/Config/__tests__/RepoConfig.spec.js +94 -0
  54. package/dist/esm/Config/index.d.ts +2 -0
  55. package/dist/esm/Config/index.js +2 -0
  56. package/dist/esm/Report/__tests__/Report.spec.d.ts +1 -0
  57. package/dist/esm/Report/__tests__/Report.spec.js +174 -0
  58. package/dist/esm/Report/index.d.ts +11 -0
  59. package/dist/esm/Report/index.js +51 -0
  60. package/dist/esm/index.d.ts +0 -1
  61. package/dist/esm/index.js +14 -55
  62. package/dist/{cjs/types/config.d.ts → esm/types.d.ts} +14 -3
  63. package/dist/esm/types.js +1 -0
  64. package/dist/esm/utils/__tests__/getCliArguments.spec.d.ts +1 -0
  65. package/dist/esm/utils/__tests__/getCliArguments.spec.js +68 -0
  66. package/dist/esm/utils/getCliArguments.d.ts +6 -6
  67. package/dist/esm/utils/getCliArguments.js +1 -27
  68. package/dist/esm/utils/getConfigFile.d.ts +4 -3
  69. package/dist/esm/utils/getConfigFile.js +3 -9
  70. package/dist/esm/utils/getEnvironment.d.ts +3 -0
  71. package/dist/esm/utils/getEnvironment.js +42 -0
  72. package/dist/esm/utils/readPackageJsonFile.d.ts +9 -0
  73. package/dist/esm/utils/readPackageJsonFile.js +20 -0
  74. package/package.json +2 -2
  75. package/src/Checker/MonorepoChecker.ts +45 -0
  76. package/src/Checker/RepoChecker.ts +23 -0
  77. package/src/Checker/__tests__/MonorepoChecker.spec.ts +330 -0
  78. package/src/Checker/__tests__/RepoChecker.spec.ts +132 -0
  79. package/src/Checker/index.ts +2 -0
  80. package/src/Config/MonorepoConfig.ts +51 -0
  81. package/src/Config/RepoConfig.ts +30 -0
  82. package/src/Config/__tests__/MonorepoConfig.spec.ts +348 -0
  83. package/src/Config/__tests__/RepoConfig.spec.ts +131 -0
  84. package/src/Config/index.ts +2 -0
  85. package/src/Report/__tests__/Report.spec.ts +221 -0
  86. package/src/Report/index.ts +75 -0
  87. package/src/index.ts +14 -67
  88. package/src/{types/config.ts → types.ts} +15 -3
  89. package/src/utils/__tests__/getCliArguments.spec.ts +89 -0
  90. package/src/utils/getCliArguments.ts +1 -35
  91. package/src/utils/getConfigFile.ts +7 -11
  92. package/src/utils/getEnvironment.ts +53 -0
  93. package/src/utils/readPackageJsonFile.ts +20 -0
  94. package/dist/cjs/types/cliArguments.d.ts +0 -4
  95. package/dist/cjs/types/config.js +0 -2
  96. package/dist/cjs/types/state.d.ts +0 -6
  97. package/dist/cjs/types/state.js +0 -2
  98. package/dist/cjs/utils/getMonorepoPrefix.d.ts +0 -6
  99. package/dist/cjs/utils/getMonorepoPrefix.js +0 -33
  100. package/dist/cjs/utils/initializeState.d.ts +0 -8
  101. package/dist/cjs/utils/initializeState.js +0 -40
  102. package/dist/esm/types/cliArguments.d.ts +0 -4
  103. package/dist/esm/types/state.d.ts +0 -6
  104. package/dist/esm/utils/getMonorepoPrefix.d.ts +0 -6
  105. package/dist/esm/utils/getMonorepoPrefix.js +0 -27
  106. package/dist/esm/utils/initializeState.d.ts +0 -8
  107. package/dist/esm/utils/initializeState.js +0 -34
  108. package/src/types/cliArguments.ts +0 -5
  109. package/src/types/state.ts +0 -6
  110. package/src/utils/getMonorepoPrefix.ts +0 -32
  111. package/src/utils/initializeState.ts +0 -51
  112. /package/dist/{esm/types/cliArguments.js → cjs/Checker/__tests__/MonorepoChecker.spec.d.ts} +0 -0
  113. /package/dist/{esm/types/config.js → cjs/Checker/__tests__/RepoChecker.spec.d.ts} +0 -0
  114. /package/dist/{esm/types/state.js → cjs/Config/__tests__/MonorepoConfig.spec.d.ts} +0 -0
  115. /package/dist/cjs/{types/cliArguments.js → types.js} +0 -0
@@ -0,0 +1,330 @@
1
+ import depcheck from 'depcheck';
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
3
+
4
+ import { MonorepoConfig } from '../../Config/MonorepoConfig';
5
+ import { CheckState } from '../../Report';
6
+ import { readPackageJsonFile, readPackageJsonFileSync } from '../../utils/readPackageJsonFile';
7
+ import { MonorepoChecker } from '../MonorepoChecker';
8
+
9
+ vi.mock('depcheck', () => ({
10
+ default: vi.fn(),
11
+ }));
12
+
13
+ vi.mock('../../utils/readPackageJsonFile', () => ({
14
+ readPackageJsonFile: vi.fn(),
15
+ readPackageJsonFileSync: vi.fn(),
16
+ }));
17
+
18
+ describe('MonorepoChecker', () => {
19
+ let mockConfig: MonorepoConfig;
20
+ const mockDepcheck = vi.mocked(depcheck);
21
+ const mockReadPackageJsonFile = vi.mocked(readPackageJsonFile);
22
+ const mockReadPackageJsonFileSync = vi.mocked(readPackageJsonFileSync);
23
+
24
+ beforeEach(() => {
25
+ vi.clearAllMocks();
26
+
27
+ mockConfig = {
28
+ getFolders: vi.fn(),
29
+ getFolderOptions: vi.fn(),
30
+ } as unknown as MonorepoConfig;
31
+ });
32
+
33
+ describe('check', () => {
34
+ beforeEach(() => {
35
+ vi.mocked(mockConfig.getFolders).mockReturnValue([]);
36
+ });
37
+
38
+ it('should add wrongVersions when dependency version does not match', async () => {
39
+ const folders = ['/test/folder1', '/test/folder2'];
40
+ vi.mocked(mockConfig.getFolders).mockReturnValue(folders);
41
+ mockReadPackageJsonFileSync
42
+ .mockReturnValueOnce({
43
+ name: '@test/package1',
44
+ version: '1.0.0',
45
+ dependencies: {},
46
+ devDependencies: {},
47
+ })
48
+ .mockReturnValueOnce({
49
+ name: '@test/package2',
50
+ version: '2.0.0',
51
+ dependencies: {},
52
+ devDependencies: {},
53
+ });
54
+ const checkState: CheckState = { dependencies: [] };
55
+ mockDepcheck.mockResolvedValue(checkState);
56
+ mockReadPackageJsonFile.mockResolvedValue({
57
+ name: 'test-package',
58
+ version: '1.0.0',
59
+ dependencies: { '@test/package1': '1.1.0' },
60
+ devDependencies: {},
61
+ });
62
+ vi.mocked(mockConfig.getFolderOptions).mockReturnValue({} as never);
63
+
64
+ const checker = new MonorepoChecker(mockConfig);
65
+ const report = await checker.check();
66
+
67
+ const exitCode = report.printResultAndGetExitCode();
68
+ expect(exitCode).toBe(1);
69
+ });
70
+
71
+ it('should not add wrongVersions when dependency version matches', async () => {
72
+ const folders = ['/test/folder1'];
73
+ vi.mocked(mockConfig.getFolders).mockReturnValue(folders);
74
+ mockReadPackageJsonFileSync.mockReturnValue({
75
+ name: '@test/package1',
76
+ version: '1.0.0',
77
+ dependencies: {},
78
+ devDependencies: {},
79
+ });
80
+ const checkState: CheckState = { dependencies: [] };
81
+ mockDepcheck.mockResolvedValue(checkState);
82
+ mockReadPackageJsonFile.mockResolvedValue({
83
+ name: 'test-package',
84
+ version: '1.0.0',
85
+ dependencies: { '@test/package1': '1.0.0' },
86
+ devDependencies: {},
87
+ });
88
+ vi.mocked(mockConfig.getFolderOptions).mockReturnValue({} as never);
89
+
90
+ const checker = new MonorepoChecker(mockConfig);
91
+ const report = await checker.check();
92
+
93
+ const exitCode = report.printResultAndGetExitCode();
94
+ expect(exitCode).toBe(0);
95
+ });
96
+
97
+ it('should add to existing wrongVersions array', async () => {
98
+ const folders = ['/test/folder1'];
99
+ vi.mocked(mockConfig.getFolders).mockReturnValue(folders);
100
+ mockReadPackageJsonFileSync.mockReturnValue({
101
+ name: '@test/package1',
102
+ version: '1.0.0',
103
+ dependencies: {},
104
+ devDependencies: {},
105
+ });
106
+ const checkState: CheckState = {
107
+ dependencies: [],
108
+ wrongVersions: ['existing error'],
109
+ };
110
+ mockDepcheck.mockResolvedValue(checkState);
111
+ mockReadPackageJsonFile.mockResolvedValue({
112
+ name: 'test-package',
113
+ version: '1.0.0',
114
+ dependencies: { '@test/package1': '1.1.0' },
115
+ devDependencies: {},
116
+ });
117
+ vi.mocked(mockConfig.getFolderOptions).mockReturnValue({} as never);
118
+
119
+ const checker = new MonorepoChecker(mockConfig);
120
+ const report = await checker.check();
121
+
122
+ const exitCode = report.printResultAndGetExitCode();
123
+ expect(exitCode).toBe(1);
124
+ });
125
+
126
+ it('should add internalAsDev when internal package is in devDependencies', async () => {
127
+ const folders = ['/test/folder1'];
128
+ vi.mocked(mockConfig.getFolders).mockReturnValue(folders);
129
+ mockReadPackageJsonFileSync.mockReturnValue({
130
+ name: '@test/package1',
131
+ version: '1.0.0',
132
+ dependencies: {},
133
+ devDependencies: {},
134
+ });
135
+ const checkState: CheckState = { dependencies: [] };
136
+ mockDepcheck.mockResolvedValue(checkState);
137
+ mockReadPackageJsonFile.mockResolvedValue({
138
+ name: 'test-package',
139
+ version: '1.0.0',
140
+ dependencies: {},
141
+ devDependencies: { '@test/package1': '1.0.0' },
142
+ });
143
+ vi.mocked(mockConfig.getFolderOptions).mockReturnValue({} as never);
144
+
145
+ const checker = new MonorepoChecker(mockConfig);
146
+ const report = await checker.check();
147
+
148
+ const exitCode = report.printResultAndGetExitCode();
149
+ expect(exitCode).toBe(1);
150
+ });
151
+
152
+ it('should not add internalAsDev when package is not internal', async () => {
153
+ const folders = ['/test/folder1'];
154
+ vi.mocked(mockConfig.getFolders).mockReturnValue(folders);
155
+ mockReadPackageJsonFileSync.mockReturnValue({
156
+ name: '@test/package1',
157
+ version: '1.0.0',
158
+ dependencies: {},
159
+ devDependencies: {},
160
+ });
161
+ const checkState: CheckState = { dependencies: [] };
162
+ mockDepcheck.mockResolvedValue(checkState);
163
+ mockReadPackageJsonFile.mockResolvedValue({
164
+ name: 'test-package',
165
+ version: '1.0.0',
166
+ dependencies: {},
167
+ devDependencies: { 'external-package': '1.0.0' },
168
+ });
169
+ vi.mocked(mockConfig.getFolderOptions).mockReturnValue({} as never);
170
+
171
+ const checker = new MonorepoChecker(mockConfig);
172
+ const report = await checker.check();
173
+
174
+ const exitCode = report.printResultAndGetExitCode();
175
+ expect(exitCode).toBe(0);
176
+ });
177
+
178
+ it('should add to existing internalAsDev array', async () => {
179
+ const folders = ['/test/folder1'];
180
+ vi.mocked(mockConfig.getFolders).mockReturnValue(folders);
181
+ mockReadPackageJsonFileSync.mockReturnValue({
182
+ name: '@test/package1',
183
+ version: '1.0.0',
184
+ dependencies: {},
185
+ devDependencies: {},
186
+ });
187
+ const checkState: CheckState = {
188
+ dependencies: [],
189
+ internalAsDev: ['existing-package'],
190
+ };
191
+ mockDepcheck.mockResolvedValue(checkState);
192
+ mockReadPackageJsonFile.mockResolvedValue({
193
+ name: 'test-package',
194
+ version: '1.0.0',
195
+ dependencies: {},
196
+ devDependencies: { '@test/package1': '1.0.0' },
197
+ });
198
+ vi.mocked(mockConfig.getFolderOptions).mockReturnValue({} as never);
199
+
200
+ const checker = new MonorepoChecker(mockConfig);
201
+ const report = await checker.check();
202
+
203
+ const exitCode = report.printResultAndGetExitCode();
204
+ expect(exitCode).toBe(1);
205
+ });
206
+
207
+ it('should handle multiple wrong versions', async () => {
208
+ const folders = ['/test/folder1', '/test/folder2'];
209
+ vi.mocked(mockConfig.getFolders).mockReturnValue(folders);
210
+ mockReadPackageJsonFileSync
211
+ .mockReturnValueOnce({
212
+ name: '@test/package1',
213
+ version: '1.0.0',
214
+ dependencies: {},
215
+ devDependencies: {},
216
+ })
217
+ .mockReturnValueOnce({
218
+ name: '@test/package2',
219
+ version: '2.0.0',
220
+ dependencies: {},
221
+ devDependencies: {},
222
+ });
223
+ const checkState: CheckState = { dependencies: [] };
224
+ mockDepcheck.mockResolvedValue(checkState);
225
+ mockReadPackageJsonFile.mockResolvedValue({
226
+ name: 'test-package',
227
+ version: '1.0.0',
228
+ dependencies: {
229
+ '@test/package1': '1.1.0',
230
+ '@test/package2': '2.1.0',
231
+ },
232
+ devDependencies: {},
233
+ });
234
+ vi.mocked(mockConfig.getFolderOptions).mockReturnValue({} as never);
235
+
236
+ const checker = new MonorepoChecker(mockConfig);
237
+ const report = await checker.check();
238
+
239
+ const exitCode = report.printResultAndGetExitCode();
240
+ expect(exitCode).toBe(1);
241
+ });
242
+
243
+ it('should handle both wrongVersions and internalAsDev', async () => {
244
+ const folders = ['/test/folder1', '/test/folder2'];
245
+ vi.mocked(mockConfig.getFolders).mockReturnValue(folders);
246
+ mockReadPackageJsonFileSync
247
+ .mockReturnValueOnce({
248
+ name: '@test/package1',
249
+ version: '1.0.0',
250
+ dependencies: {},
251
+ devDependencies: {},
252
+ })
253
+ .mockReturnValueOnce({
254
+ name: '@test/package2',
255
+ version: '2.0.0',
256
+ dependencies: {},
257
+ devDependencies: {},
258
+ });
259
+ const checkState: CheckState = { dependencies: [] };
260
+ mockDepcheck.mockResolvedValue(checkState);
261
+ mockReadPackageJsonFile.mockResolvedValue({
262
+ name: 'test-package',
263
+ version: '1.0.0',
264
+ dependencies: { '@test/package1': '1.1.0' },
265
+ devDependencies: { '@test/package2': '2.0.0' },
266
+ });
267
+ vi.mocked(mockConfig.getFolderOptions).mockReturnValue({} as never);
268
+
269
+ const checker = new MonorepoChecker(mockConfig);
270
+ const report = await checker.check();
271
+
272
+ const exitCode = report.printResultAndGetExitCode();
273
+ expect(exitCode).toBe(1);
274
+ });
275
+
276
+ it('should add wrongVersions for external packages (when actualVersion is undefined)', async () => {
277
+ const folders = ['/test/folder1'];
278
+ vi.mocked(mockConfig.getFolders).mockReturnValue(folders);
279
+ mockReadPackageJsonFileSync.mockReturnValue({
280
+ name: '@test/package1',
281
+ version: '1.0.0',
282
+ dependencies: {},
283
+ devDependencies: {},
284
+ });
285
+ const checkState: CheckState = { dependencies: [] };
286
+ mockDepcheck.mockResolvedValue(checkState);
287
+ mockReadPackageJsonFile.mockResolvedValue({
288
+ name: 'test-package',
289
+ version: '1.0.0',
290
+ dependencies: { 'external-package': '1.0.0' },
291
+ devDependencies: {},
292
+ });
293
+ vi.mocked(mockConfig.getFolderOptions).mockReturnValue({} as never);
294
+
295
+ const checker = new MonorepoChecker(mockConfig);
296
+ const report = await checker.check();
297
+
298
+ // Текущая реализация добавляет ошибку для внешних пакетов,
299
+ // так как actualVersion === undefined, и условие undefined !== "1.0.0" будет true
300
+ const exitCode = report.printResultAndGetExitCode();
301
+ expect(exitCode).toBe(1);
302
+ });
303
+
304
+ it('should handle empty dependencies and devDependencies', async () => {
305
+ const folders = ['/test/folder1'];
306
+ vi.mocked(mockConfig.getFolders).mockReturnValue(folders);
307
+ mockReadPackageJsonFileSync.mockReturnValue({
308
+ name: '@test/package1',
309
+ version: '1.0.0',
310
+ dependencies: {},
311
+ devDependencies: {},
312
+ });
313
+ const checkState: CheckState = { dependencies: [] };
314
+ mockDepcheck.mockResolvedValue(checkState);
315
+ mockReadPackageJsonFile.mockResolvedValue({
316
+ name: 'test-package',
317
+ version: '1.0.0',
318
+ dependencies: {},
319
+ devDependencies: {},
320
+ });
321
+ vi.mocked(mockConfig.getFolderOptions).mockReturnValue({} as never);
322
+
323
+ const checker = new MonorepoChecker(mockConfig);
324
+ const report = await checker.check();
325
+
326
+ const exitCode = report.printResultAndGetExitCode();
327
+ expect(exitCode).toBe(0);
328
+ });
329
+ });
330
+ });
@@ -0,0 +1,132 @@
1
+ import depcheck from 'depcheck';
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
3
+
4
+ import { RepoConfig } from '../../Config/RepoConfig';
5
+ import { CheckState } from '../../Report';
6
+ import { RepoChecker } from '../RepoChecker';
7
+
8
+ vi.mock('depcheck', () => ({
9
+ default: vi.fn(),
10
+ }));
11
+
12
+ describe('RepoChecker', () => {
13
+ let mockConfig: RepoConfig;
14
+ const mockDepcheck = vi.mocked(depcheck);
15
+
16
+ beforeEach(() => {
17
+ vi.clearAllMocks();
18
+
19
+ mockConfig = {
20
+ getFolders: vi.fn(),
21
+ getFolderOptions: vi.fn(),
22
+ } as unknown as RepoConfig;
23
+ });
24
+
25
+ describe('constructor', () => {
26
+ it('should initialize with config', () => {
27
+ const checker = new RepoChecker(mockConfig);
28
+
29
+ expect(checker).toBeInstanceOf(RepoChecker);
30
+ });
31
+ });
32
+
33
+ describe('check', () => {
34
+ it('should call getFolders on config', async () => {
35
+ const folders = ['/test/folder1'];
36
+ vi.mocked(mockConfig.getFolders).mockReturnValue(folders);
37
+ const checkState: CheckState = { dependencies: [] };
38
+ mockDepcheck.mockResolvedValue(checkState);
39
+
40
+ const checker = new RepoChecker(mockConfig);
41
+ await checker.check();
42
+
43
+ expect(mockConfig.getFolders).toHaveBeenCalledTimes(1);
44
+ });
45
+
46
+ it('should call checkFolder for each folder', async () => {
47
+ const folders = ['/test/folder1', '/test/folder2'];
48
+ vi.mocked(mockConfig.getFolders).mockReturnValue(folders);
49
+ const checkState1: CheckState = { dependencies: ['dep1'] };
50
+ const checkState2: CheckState = { dependencies: ['dep2'] };
51
+ mockDepcheck.mockResolvedValueOnce(checkState1).mockResolvedValueOnce(checkState2);
52
+ vi.mocked(mockConfig.getFolderOptions).mockReturnValue({} as never);
53
+
54
+ const checker = new RepoChecker(mockConfig);
55
+ await checker.check();
56
+
57
+ expect(mockDepcheck).toHaveBeenCalledTimes(2);
58
+ });
59
+
60
+ it('should call getFolderOptions for each folder with correct path', async () => {
61
+ const folders = ['/test/folder1', '/test/folder2'];
62
+ vi.mocked(mockConfig.getFolders).mockReturnValue(folders);
63
+ const options1 = { ignoreBinPackage: false };
64
+ const options2 = { ignoreBinPackage: false };
65
+ vi.mocked(mockConfig.getFolderOptions)
66
+ .mockReturnValueOnce(options1 as never)
67
+ .mockReturnValueOnce(options2 as never);
68
+ const checkState: CheckState = { dependencies: [] };
69
+ mockDepcheck.mockResolvedValue(checkState);
70
+
71
+ const checker = new RepoChecker(mockConfig);
72
+ await checker.check();
73
+
74
+ expect(mockConfig.getFolderOptions).toHaveBeenCalledWith('/test/folder1');
75
+ expect(mockConfig.getFolderOptions).toHaveBeenCalledWith('/test/folder2');
76
+ });
77
+
78
+ it('should call depcheck with correct path and options', async () => {
79
+ const folders = ['/test/folder1'];
80
+ vi.mocked(mockConfig.getFolders).mockReturnValue(folders);
81
+ const options = { ignoreBinPackage: false, skipMissing: false };
82
+ vi.mocked(mockConfig.getFolderOptions).mockReturnValue(options as never);
83
+ const checkState: CheckState = { dependencies: [] };
84
+ mockDepcheck.mockResolvedValue(checkState);
85
+
86
+ const checker = new RepoChecker(mockConfig);
87
+ await checker.check();
88
+
89
+ expect(mockDepcheck).toHaveBeenCalledWith('/test/folder1', options);
90
+ });
91
+
92
+ it('should add results to report for each folder', async () => {
93
+ const folders = ['/test/folder1', '/test/folder2'];
94
+ vi.mocked(mockConfig.getFolders).mockReturnValue(folders);
95
+ const checkState1: CheckState = { dependencies: ['dep1'] };
96
+ const checkState2: CheckState = { dependencies: ['dep2'] };
97
+ mockDepcheck.mockResolvedValueOnce(checkState1).mockResolvedValueOnce(checkState2);
98
+ vi.mocked(mockConfig.getFolderOptions).mockReturnValue({} as never);
99
+
100
+ const checker = new RepoChecker(mockConfig);
101
+ const report = await checker.check();
102
+
103
+ const exitCode = report.printResultAndGetExitCode();
104
+ expect(exitCode).toBe(1);
105
+ });
106
+
107
+ it('should return Report instance', async () => {
108
+ const folders = ['/test/folder1'];
109
+ vi.mocked(mockConfig.getFolders).mockReturnValue(folders);
110
+ const checkState: CheckState = { dependencies: [] };
111
+ mockDepcheck.mockResolvedValue(checkState);
112
+ vi.mocked(mockConfig.getFolderOptions).mockReturnValue({} as never);
113
+
114
+ const checker = new RepoChecker(mockConfig);
115
+ const report = await checker.check();
116
+
117
+ expect(report).toBeDefined();
118
+ expect(report.printResultAndGetExitCode).toBeDefined();
119
+ });
120
+
121
+ it('should handle empty folders array', async () => {
122
+ vi.mocked(mockConfig.getFolders).mockReturnValue([]);
123
+
124
+ const checker = new RepoChecker(mockConfig);
125
+ const report = await checker.check();
126
+
127
+ expect(mockDepcheck).not.toHaveBeenCalled();
128
+ const exitCode = report.printResultAndGetExitCode();
129
+ expect(exitCode).toBe(0);
130
+ });
131
+ });
132
+ });
@@ -0,0 +1,2 @@
1
+ export { RepoChecker } from './RepoChecker';
2
+ export { MonorepoChecker } from './MonorepoChecker';
@@ -0,0 +1,51 @@
1
+ import { Options } from 'depcheck';
2
+ import { globSync } from 'glob';
3
+ import path from 'node:path';
4
+
5
+ import { MonorepoEnvType } from '../types';
6
+ import { RepoConfig } from './RepoConfig';
7
+
8
+ export class MonorepoConfig extends RepoConfig {
9
+ private rootPackagesFolderPattern: string;
10
+ private ignoredPackagesFolderFiles: string[];
11
+ private packages: Exclude<MonorepoEnvType['packages'], undefined>;
12
+ private folders?: string[];
13
+
14
+ constructor(env: MonorepoEnvType) {
15
+ super(env);
16
+ this.rootPackagesFolderPattern = env.rootPackagesFolderPattern;
17
+ this.ignoredPackagesFolderFiles = env.ignoredPackagesFolderFiles || [];
18
+ this.packages = env.packages || {};
19
+ }
20
+
21
+ public getFolderOptions(folderPath: string): Options {
22
+ const options = super.getFolderOptions(folderPath);
23
+
24
+ const folder = path.basename(folderPath);
25
+
26
+ const folderIgnores = this.packages[folder];
27
+
28
+ if (!folderIgnores) {
29
+ return options;
30
+ }
31
+
32
+ if (folderIgnores.ignorePatterns?.length) {
33
+ options.ignorePatterns = [...(options.ignorePatterns || []), ...folderIgnores.ignorePatterns];
34
+ }
35
+ if (folderIgnores.ignoreMatches?.length) {
36
+ options.ignoreMatches = [...(options.ignoreMatches || []), ...folderIgnores.ignoreMatches];
37
+ }
38
+
39
+ return options;
40
+ }
41
+
42
+ public getFolders(): string[] {
43
+ if (!this.folders) {
44
+ this.folders = globSync(this.rootPackagesFolderPattern, {
45
+ ignore: this.ignoredPackagesFolderFiles,
46
+ });
47
+ }
48
+
49
+ return this.folders.map(folder => path.resolve(this.pwd, folder));
50
+ }
51
+ }
@@ -0,0 +1,30 @@
1
+ import { Options } from 'depcheck';
2
+ import path from 'node:path';
3
+
4
+ import { RepoEnvType } from '../types';
5
+
6
+ export class RepoConfig {
7
+ protected pwd: string;
8
+ private ignorePatterns?: string[];
9
+ private ignoreMatches?: string[];
10
+
11
+ constructor(env: RepoEnvType) {
12
+ this.pwd = path.resolve(env.cwd);
13
+ this.ignoreMatches = env.ignoreMatches || [];
14
+ this.ignorePatterns = env.ignorePatterns || [];
15
+ }
16
+
17
+ public getFolders() {
18
+ return [this.pwd];
19
+ }
20
+
21
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
22
+ public getFolderOptions(_folder: string): Options {
23
+ return {
24
+ ignoreBinPackage: false,
25
+ skipMissing: false,
26
+ ignorePatterns: this.ignorePatterns,
27
+ ignoreMatches: this.ignoreMatches,
28
+ };
29
+ }
30
+ }