@hubspot/cli 7.10.0 → 7.11.0-beta.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.
- package/bin/cli.js +5 -4
- package/commands/__tests__/getStarted.test.js +10 -0
- package/commands/__tests__/project.test.js +3 -0
- package/commands/account/__tests__/rename.test.js +10 -3
- package/commands/account/auth.js +10 -14
- package/commands/account/clean.js +11 -19
- package/commands/account/createOverride.js +15 -11
- package/commands/account/info.js +8 -5
- package/commands/account/list.js +15 -19
- package/commands/account/remove.js +23 -22
- package/commands/account/removeOverride.js +6 -6
- package/commands/account/rename.js +2 -2
- package/commands/account/use.js +19 -8
- package/commands/app/__tests__/migrate.test.js +8 -4
- package/commands/app/migrate.js +2 -2
- package/commands/auth.js +18 -14
- package/commands/config/migrate.js +5 -5
- package/commands/customObject/createSchema.js +2 -3
- package/commands/customObject/updateSchema.js +2 -3
- package/commands/getStarted.js +2 -3
- package/commands/hubdb/__tests__/list.test.js +1 -0
- package/commands/hubdb/list.js +2 -2
- package/commands/init.js +36 -32
- package/commands/project/__tests__/deploy.test.js +16 -11
- package/commands/project/__tests__/devUnifiedFlow.test.js +6 -4
- package/commands/project/__tests__/lint.test.js +709 -0
- package/commands/project/__tests__/logs.test.js +4 -0
- package/commands/project/__tests__/validate.test.js +2 -2
- package/commands/project/cloneApp.js +2 -2
- package/commands/project/create.js +20 -14
- package/commands/project/deploy.js +2 -2
- package/commands/project/dev/deprecatedFlow.js +4 -5
- package/commands/project/dev/index.js +6 -3
- package/commands/project/dev/unifiedFlow.js +11 -6
- package/commands/project/lint.d.ts +6 -0
- package/commands/project/lint.js +178 -0
- package/commands/project/logs.js +2 -3
- package/commands/project/migrate.js +4 -13
- package/commands/project/profile/add.js +6 -7
- package/commands/project/profile/delete.js +2 -2
- package/commands/project/upload.js +2 -2
- package/commands/project/validate.js +2 -2
- package/commands/project.js +2 -0
- package/commands/sandbox/__tests__/create.test.js +14 -5
- package/commands/sandbox/create.js +4 -5
- package/commands/sandbox/delete.js +23 -20
- package/commands/testAccount/create.js +2 -2
- package/commands/testAccount/delete.js +9 -8
- package/lang/en.d.ts +54 -12
- package/lang/en.js +64 -16
- package/lib/__tests__/buildAccount.test.js +22 -30
- package/lib/__tests__/commonOpts.test.js +9 -13
- package/lib/__tests__/developerTestAccounts.test.js +29 -17
- package/lib/__tests__/importData.test.js +20 -10
- package/lib/__tests__/oauth.test.js +19 -8
- package/lib/__tests__/sandboxSync.test.js +33 -11
- package/lib/__tests__/sandboxes.test.js +30 -19
- package/lib/__tests__/usageTracking.test.js +10 -10
- package/lib/__tests__/validation.test.js +32 -32
- package/lib/accountTypes.d.ts +9 -9
- package/lib/accountTypes.js +2 -4
- package/lib/app/__tests__/migrate.test.js +15 -0
- package/lib/app/__tests__/migrate_legacy.test.js +9 -0
- package/lib/app/migrate_legacy.d.ts +2 -2
- package/lib/buildAccount.d.ts +4 -4
- package/lib/buildAccount.js +7 -14
- package/lib/commonOpts.js +3 -3
- package/lib/configMigrate.d.ts +2 -2
- package/lib/configMigrate.js +42 -18
- package/lib/configOptions.js +3 -2
- package/lib/developerTestAccounts.d.ts +3 -3
- package/lib/developerTestAccounts.js +4 -7
- package/lib/doctor/DiagnosticInfoBuilder.d.ts +1 -1
- package/lib/doctor/DiagnosticInfoBuilder.js +9 -6
- package/lib/doctor/Doctor.js +4 -3
- package/lib/doctor/__tests__/Diagnosis.test.js +4 -3
- package/lib/doctor/__tests__/DiagnosticInfoBuilder.test.js +17 -9
- package/lib/doctor/__tests__/Doctor.test.js +14 -0
- package/lib/errorHandlers/index.js +10 -7
- package/lib/importData.js +8 -7
- package/lib/links.js +5 -5
- package/lib/middleware/{__test__ → __tests__}/commandTargetingUtils.test.js +3 -3
- package/lib/middleware/{__test__ → __tests__}/configMiddleware.test.js +23 -22
- package/lib/middleware/{__test__ → __tests__}/gitMiddleware.test.js +9 -7
- package/lib/middleware/autoUpdateMiddleware.js +34 -23
- package/lib/middleware/commandTargetingUtils.js +3 -2
- package/lib/middleware/configMiddleware.d.ts +6 -1
- package/lib/middleware/configMiddleware.js +36 -15
- package/lib/middleware/fireAlarmMiddleware.js +4 -15
- package/lib/middleware/gitMiddleware.js +8 -4
- package/lib/oauth.d.ts +2 -2
- package/lib/oauth.js +8 -10
- package/lib/projects/__tests__/AppDevModeInterface.test.js +17 -6
- package/lib/projects/__tests__/DevServerManager.test.js +1 -0
- package/lib/projects/__tests__/LocalDevProcess.test.js +1 -0
- package/lib/projects/__tests__/components.test.js +2 -22
- package/lib/projects/__tests__/deploy.test.js +16 -13
- package/lib/projects/__tests__/uieLinting.test.js +640 -0
- package/lib/projects/add/__tests__/legacyAddComponent.test.js +1 -1
- package/lib/projects/add/__tests__/v2AddComponent.test.js +30 -4
- package/lib/projects/add/legacyAddComponent.js +1 -1
- package/lib/projects/add/v2AddComponent.js +16 -5
- package/lib/projects/components.d.ts +8 -1
- package/lib/projects/components.js +91 -8
- package/lib/projects/create/__tests__/v2.test.js +11 -0
- package/lib/projects/deploy.js +21 -8
- package/lib/projects/localDev/AppDevModeInterface.js +2 -2
- package/lib/projects/localDev/DevServerManager_DEPRECATED.js +11 -3
- package/lib/projects/localDev/LocalDevLogger.js +4 -4
- package/lib/projects/localDev/LocalDevManager_DEPRECATED.js +3 -3
- package/lib/projects/localDev/helpers/account.d.ts +10 -10
- package/lib/projects/localDev/helpers/account.js +6 -11
- package/lib/projects/localDev/helpers/process.js +5 -3
- package/lib/projects/uieLinting.d.ts +33 -0
- package/lib/projects/uieLinting.js +222 -0
- package/lib/projects/urls.js +5 -6
- package/lib/prompts/__tests__/downloadProjectPrompt.test.js +7 -5
- package/lib/prompts/accountNamePrompt.js +3 -3
- package/lib/prompts/accountsPrompt.d.ts +1 -1
- package/lib/prompts/accountsPrompt.js +6 -7
- package/lib/prompts/confirmImportDataPrompt.js +2 -2
- package/lib/prompts/downloadProjectPrompt.d.ts +1 -0
- package/lib/prompts/downloadProjectPrompt.js +5 -2
- package/lib/prompts/importDataTestAccountSelectPrompt.js +4 -5
- package/lib/prompts/personalAccessKeyPrompt.js +2 -2
- package/lib/prompts/projectDevTargetAccountPrompt.d.ts +3 -3
- package/lib/prompts/projectDevTargetAccountPrompt.js +5 -7
- package/lib/prompts/sandboxesPrompt.js +7 -8
- package/lib/prompts/setAsDefaultAccountPrompt.js +7 -6
- package/lib/sandboxSync.d.ts +2 -2
- package/lib/sandboxSync.js +3 -9
- package/lib/sandboxes.d.ts +4 -4
- package/lib/sandboxes.js +6 -11
- package/lib/serverlessLogs.js +2 -2
- package/lib/theme/__tests__/migrate.test.js +15 -0
- package/lib/ui/SpinniesManager.d.ts +5 -7
- package/lib/ui/SpinniesManager.js +9 -12
- package/lib/ui/__tests__/SpinniesManager.test.d.ts +1 -0
- package/lib/ui/__tests__/SpinniesManager.test.js +489 -0
- package/lib/ui/index.js +6 -3
- package/lib/usageTracking.js +15 -8
- package/lib/validation.js +13 -11
- package/mcp-server/tools/cms/HsCreateFunctionTool.js +4 -2
- package/mcp-server/tools/cms/HsCreateModuleTool.js +4 -2
- package/mcp-server/tools/cms/HsCreateTemplateTool.js +4 -2
- package/mcp-server/tools/cms/HsFunctionLogsTool.js +4 -2
- package/mcp-server/tools/cms/HsListFunctionsTool.js +3 -1
- package/mcp-server/tools/cms/HsListTool.js +3 -1
- package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +1 -0
- package/mcp-server/tools/index.js +4 -0
- package/mcp-server/tools/project/AddFeatureToProjectTool.js +4 -2
- package/mcp-server/tools/project/CreateProjectTool.js +4 -2
- package/mcp-server/tools/project/CreateTestAccountTool.js +17 -7
- package/mcp-server/tools/project/DeployProjectTool.js +3 -1
- package/mcp-server/tools/project/DocFetchTool.js +6 -4
- package/mcp-server/tools/project/DocsSearchTool.d.ts +1 -1
- package/mcp-server/tools/project/DocsSearchTool.js +10 -8
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.d.ts +1 -1
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +9 -7
- package/mcp-server/tools/project/GetApplicationInfoTool.js +8 -6
- package/mcp-server/tools/project/GetBuildLogsTool.d.ts +26 -0
- package/mcp-server/tools/project/GetBuildLogsTool.js +125 -0
- package/mcp-server/tools/project/GetBuildStatusTool.d.ts +26 -0
- package/mcp-server/tools/project/GetBuildStatusTool.js +166 -0
- package/mcp-server/tools/project/GetConfigValuesTool.d.ts +1 -1
- package/mcp-server/tools/project/GetConfigValuesTool.js +9 -7
- package/mcp-server/tools/project/GuidedWalkthroughTool.d.ts +1 -1
- package/mcp-server/tools/project/GuidedWalkthroughTool.js +5 -3
- package/mcp-server/tools/project/UploadProjectTools.js +3 -1
- package/mcp-server/tools/project/ValidateProjectTool.js +4 -2
- package/mcp-server/tools/project/__tests__/CreateTestAccountTool.test.js +12 -2
- package/mcp-server/tools/project/__tests__/DocFetchTool.test.js +5 -1
- package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +23 -11
- package/mcp-server/tools/project/__tests__/GetApiUsagePatternsByAppIdTool.test.js +7 -5
- package/mcp-server/tools/project/__tests__/GetApplicationInfoTool.test.js +7 -5
- package/mcp-server/tools/project/__tests__/GetBuildLogsTool.test.d.ts +1 -0
- package/mcp-server/tools/project/__tests__/GetBuildLogsTool.test.js +305 -0
- package/mcp-server/tools/project/__tests__/GetBuildStatusTool.test.d.ts +1 -0
- package/mcp-server/tools/project/__tests__/GetBuildStatusTool.test.js +240 -0
- package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +8 -6
- package/mcp-server/utils/__tests__/content.test.js +21 -20
- package/mcp-server/utils/__tests__/feedbackTracking.test.js +34 -28
- package/mcp-server/utils/config.d.ts +1 -0
- package/mcp-server/utils/config.js +10 -0
- package/mcp-server/utils/content.d.ts +1 -1
- package/mcp-server/utils/content.js +2 -2
- package/mcp-server/utils/feedbackTracking.d.ts +1 -1
- package/mcp-server/utils/feedbackTracking.js +3 -3
- package/mcp-server/utils/toolUsageTracking.js +4 -3
- package/package.json +9 -9
- package/ui/components/BoxWithTitle.d.ts +2 -1
- package/ui/components/BoxWithTitle.js +2 -2
- package/ui/components/StatusMessageBoxes.d.ts +5 -4
- package/ui/components/StatusMessageBoxes.js +8 -8
- package/lib/middleware/__test__/notificationsMiddleware.test.js +0 -8
- package/lib/middleware/notificationsMiddleware.d.ts +0 -1
- package/lib/middleware/notificationsMiddleware.js +0 -28
- package/lib/ui/boxen.d.ts +0 -5
- package/lib/ui/boxen.js +0 -26
- package/mcp-server/utils/__tests__/cliConfig.test.js +0 -110
- package/mcp-server/utils/cliConfig.d.ts +0 -1
- package/mcp-server/utils/cliConfig.js +0 -12
- /package/{lib/middleware/__test__/commandTargetingUtils.test.d.ts → commands/project/__tests__/lint.test.d.ts} +0 -0
- /package/lib/middleware/{__test__/configMiddleware.test.d.ts → __tests__/commandTargetingUtils.test.d.ts} +0 -0
- /package/lib/middleware/{__test__/gitMiddleware.test.d.ts → __tests__/configMiddleware.test.d.ts} +0 -0
- /package/lib/middleware/{__test__/notificationsMiddleware.test.d.ts → __tests__/gitMiddleware.test.d.ts} +0 -0
- /package/lib/middleware/{__test__ → __tests__}/requestMiddleware.test.d.ts +0 -0
- /package/lib/middleware/{__test__ → __tests__}/requestMiddleware.test.js +0 -0
- /package/lib/middleware/{__test__ → __tests__}/yargsChecksMiddleware.test.d.ts +0 -0
- /package/lib/middleware/{__test__ → __tests__}/yargsChecksMiddleware.test.js +0 -0
- /package/{mcp-server/utils/__tests__/cliConfig.test.d.ts → lib/projects/__tests__/uieLinting.test.d.ts} +0 -0
|
@@ -0,0 +1,640 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import util from 'util';
|
|
4
|
+
import { uiLogger } from '../../ui/logger.js';
|
|
5
|
+
import * as dependencyManagement from '../../dependencyManagement.js';
|
|
6
|
+
import { isEslintInstalled, areAllLintPackagesInstalled, getMissingLintPackages, lintPackages, lintPackagesInDirectory, displayLintResults, hasEslintConfig, hasDeprecatedEslintConfig, getDeprecatedEslintConfigFiles, createEslintConfig, } from '../uieLinting.js';
|
|
7
|
+
vi.mock('../../ui/logger.js');
|
|
8
|
+
vi.mock('fs');
|
|
9
|
+
vi.mock('../../dependencyManagement.js', async () => {
|
|
10
|
+
const actual = await vi.importActual('../../dependencyManagement.js');
|
|
11
|
+
return {
|
|
12
|
+
...actual,
|
|
13
|
+
getProjectPackageJsonLocations: vi.fn(),
|
|
14
|
+
};
|
|
15
|
+
});
|
|
16
|
+
vi.mock('node:child_process');
|
|
17
|
+
vi.mock('util');
|
|
18
|
+
const readFileSyncSpy = vi.spyOn(fs, 'readFileSync');
|
|
19
|
+
const existsSyncSpy = vi.spyOn(fs, 'existsSync');
|
|
20
|
+
const getProjectPackageJsonLocationsSpy = vi.spyOn(dependencyManagement, 'getProjectPackageJsonLocations');
|
|
21
|
+
// Mock exec function
|
|
22
|
+
const mockExec = vi.fn();
|
|
23
|
+
vi.mocked(util.promisify).mockReturnValue(mockExec);
|
|
24
|
+
describe('lib/linting', () => {
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
vi.clearAllMocks();
|
|
27
|
+
});
|
|
28
|
+
describe('isEslintInstalled', () => {
|
|
29
|
+
it('should return true if eslint is in package.json and node_modules', () => {
|
|
30
|
+
const directory = '/test/project/component1';
|
|
31
|
+
readFileSyncSpy.mockReturnValueOnce(JSON.stringify({
|
|
32
|
+
dependencies: {
|
|
33
|
+
eslint: '^8.0.0',
|
|
34
|
+
},
|
|
35
|
+
}));
|
|
36
|
+
existsSyncSpy.mockReturnValueOnce(true);
|
|
37
|
+
const result = isEslintInstalled(directory);
|
|
38
|
+
expect(result).toBe(true);
|
|
39
|
+
expect(existsSyncSpy).toHaveBeenCalledWith(path.join(directory, 'node_modules', 'eslint'));
|
|
40
|
+
});
|
|
41
|
+
it('should return false if eslint is in package.json but not in node_modules', () => {
|
|
42
|
+
const directory = '/test/project/component1';
|
|
43
|
+
readFileSyncSpy.mockReturnValueOnce(JSON.stringify({
|
|
44
|
+
dependencies: {
|
|
45
|
+
eslint: '^8.0.0',
|
|
46
|
+
},
|
|
47
|
+
}));
|
|
48
|
+
existsSyncSpy.mockReturnValueOnce(false);
|
|
49
|
+
const result = isEslintInstalled(directory);
|
|
50
|
+
expect(result).toBe(false);
|
|
51
|
+
});
|
|
52
|
+
it('should return false if eslint is not in package.json', () => {
|
|
53
|
+
const directory = '/test/project/component1';
|
|
54
|
+
readFileSyncSpy.mockReturnValueOnce(JSON.stringify({
|
|
55
|
+
dependencies: {
|
|
56
|
+
typescript: '^5.0.0',
|
|
57
|
+
},
|
|
58
|
+
}));
|
|
59
|
+
existsSyncSpy.mockReturnValueOnce(false);
|
|
60
|
+
const result = isEslintInstalled(directory);
|
|
61
|
+
expect(result).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
it('should return false if eslint is only in node_modules (no package.json entry)', () => {
|
|
64
|
+
const directory = '/test/project/component1';
|
|
65
|
+
readFileSyncSpy.mockReturnValueOnce(JSON.stringify({
|
|
66
|
+
dependencies: {
|
|
67
|
+
typescript: '^5.0.0',
|
|
68
|
+
},
|
|
69
|
+
}));
|
|
70
|
+
existsSyncSpy.mockReturnValueOnce(true);
|
|
71
|
+
const result = isEslintInstalled(directory);
|
|
72
|
+
expect(result).toBe(false);
|
|
73
|
+
});
|
|
74
|
+
it('should return true if eslint is in both node_modules and package.json', () => {
|
|
75
|
+
const directory = '/test/project/component1';
|
|
76
|
+
readFileSyncSpy.mockReturnValueOnce(JSON.stringify({
|
|
77
|
+
devDependencies: {
|
|
78
|
+
eslint: '^9.0.0',
|
|
79
|
+
},
|
|
80
|
+
}));
|
|
81
|
+
existsSyncSpy.mockReturnValueOnce(true);
|
|
82
|
+
const result = isEslintInstalled(directory);
|
|
83
|
+
expect(result).toBe(true);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
describe('areAllLintPackagesInstalled', () => {
|
|
87
|
+
beforeEach(() => {
|
|
88
|
+
vi.clearAllMocks();
|
|
89
|
+
});
|
|
90
|
+
it('should return true if all packages are installed', () => {
|
|
91
|
+
const directory = '/test/project/component1';
|
|
92
|
+
const packageJson = JSON.stringify({
|
|
93
|
+
devDependencies: {
|
|
94
|
+
eslint: '^9.0.0',
|
|
95
|
+
'@typescript-eslint/eslint-plugin': '^8.46.4',
|
|
96
|
+
'@typescript-eslint/parser': '^8.46.4',
|
|
97
|
+
'typescript-eslint': '^8.46.4',
|
|
98
|
+
jiti: '^2.6.1',
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
readFileSyncSpy.mockImplementation(() => packageJson);
|
|
102
|
+
existsSyncSpy.mockImplementation(() => true);
|
|
103
|
+
const result = areAllLintPackagesInstalled(directory);
|
|
104
|
+
expect(result).toBe(true);
|
|
105
|
+
});
|
|
106
|
+
it('should return false if eslint is missing', () => {
|
|
107
|
+
const directory = '/test/project/component1';
|
|
108
|
+
readFileSyncSpy.mockImplementation(() => JSON.stringify({ dependencies: {} }));
|
|
109
|
+
existsSyncSpy.mockImplementation(() => false);
|
|
110
|
+
const result = areAllLintPackagesInstalled(directory);
|
|
111
|
+
expect(result).toBe(false);
|
|
112
|
+
});
|
|
113
|
+
it('should return false if @typescript-eslint/eslint-plugin is missing', () => {
|
|
114
|
+
const directory = '/test/project/component1';
|
|
115
|
+
const packageJson = JSON.stringify({
|
|
116
|
+
devDependencies: {
|
|
117
|
+
eslint: '^9.0.0',
|
|
118
|
+
'@typescript-eslint/parser': '^8.46.4',
|
|
119
|
+
// @typescript-eslint/eslint-plugin is missing
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
readFileSyncSpy.mockImplementation(() => packageJson);
|
|
123
|
+
existsSyncSpy.mockImplementation(path => {
|
|
124
|
+
// Only @typescript-eslint/eslint-plugin is missing from node_modules
|
|
125
|
+
return !String(path).includes('@typescript-eslint/eslint-plugin');
|
|
126
|
+
});
|
|
127
|
+
const result = areAllLintPackagesInstalled(directory);
|
|
128
|
+
expect(result).toBe(false);
|
|
129
|
+
});
|
|
130
|
+
it('should return false if @typescript-eslint/parser is missing', () => {
|
|
131
|
+
const directory = '/test/project/component1';
|
|
132
|
+
const packageJson = JSON.stringify({
|
|
133
|
+
devDependencies: {
|
|
134
|
+
eslint: '^9.0.0',
|
|
135
|
+
'@typescript-eslint/eslint-plugin': '^8.46.4',
|
|
136
|
+
// @typescript-eslint/parser is missing
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
readFileSyncSpy.mockImplementation(() => packageJson);
|
|
140
|
+
existsSyncSpy.mockImplementation(path => {
|
|
141
|
+
// Only @typescript-eslint/parser is missing from node_modules
|
|
142
|
+
return !String(path).includes('@typescript-eslint/parser');
|
|
143
|
+
});
|
|
144
|
+
const result = areAllLintPackagesInstalled(directory);
|
|
145
|
+
expect(result).toBe(false);
|
|
146
|
+
});
|
|
147
|
+
it('should return false if typescript-eslint is missing', () => {
|
|
148
|
+
const directory = '/test/project/component1';
|
|
149
|
+
const packageJson = JSON.stringify({
|
|
150
|
+
devDependencies: {
|
|
151
|
+
eslint: '^9.0.0',
|
|
152
|
+
'@typescript-eslint/eslint-plugin': '^8.46.4',
|
|
153
|
+
'@typescript-eslint/parser': '^8.46.4',
|
|
154
|
+
// typescript-eslint is missing
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
readFileSyncSpy.mockImplementation(() => packageJson);
|
|
158
|
+
existsSyncSpy.mockImplementation(path => {
|
|
159
|
+
// Only typescript-eslint is missing from node_modules
|
|
160
|
+
return !String(path).includes('typescript-eslint');
|
|
161
|
+
});
|
|
162
|
+
const result = areAllLintPackagesInstalled(directory);
|
|
163
|
+
expect(result).toBe(false);
|
|
164
|
+
});
|
|
165
|
+
it('should return false if jiti is missing', () => {
|
|
166
|
+
const directory = '/test/project/component1';
|
|
167
|
+
const packageJson = JSON.stringify({
|
|
168
|
+
devDependencies: {
|
|
169
|
+
eslint: '^9.0.0',
|
|
170
|
+
'@typescript-eslint/eslint-plugin': '^8.46.4',
|
|
171
|
+
'@typescript-eslint/parser': '^8.46.4',
|
|
172
|
+
'typescript-eslint': '^8.46.4',
|
|
173
|
+
// jiti is missing
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
readFileSyncSpy.mockImplementation(() => packageJson);
|
|
177
|
+
existsSyncSpy.mockImplementation(path => {
|
|
178
|
+
// Only jiti is missing from node_modules
|
|
179
|
+
return !String(path).includes('jiti');
|
|
180
|
+
});
|
|
181
|
+
const result = areAllLintPackagesInstalled(directory);
|
|
182
|
+
expect(result).toBe(false);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
describe('getMissingLintPackages', () => {
|
|
186
|
+
beforeEach(() => {
|
|
187
|
+
vi.clearAllMocks();
|
|
188
|
+
});
|
|
189
|
+
it('should return empty array if all packages are installed with correct versions', () => {
|
|
190
|
+
const directory = '/test/project/component1';
|
|
191
|
+
const packageJson = JSON.stringify({
|
|
192
|
+
devDependencies: {
|
|
193
|
+
eslint: '^9.0.0',
|
|
194
|
+
'@typescript-eslint/eslint-plugin': '^8.46.4',
|
|
195
|
+
'@typescript-eslint/parser': '^8.46.4',
|
|
196
|
+
'typescript-eslint': '^8.46.4',
|
|
197
|
+
jiti: '^2.6.1',
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
readFileSyncSpy.mockImplementation(() => packageJson);
|
|
201
|
+
existsSyncSpy.mockImplementation(() => true);
|
|
202
|
+
const result = getMissingLintPackages(directory);
|
|
203
|
+
expect(result).toEqual({
|
|
204
|
+
missingPackages: [],
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
it('should return packages that are in package.json but not installed', () => {
|
|
208
|
+
const directory = '/test/project/component1';
|
|
209
|
+
const packageJson = JSON.stringify({
|
|
210
|
+
devDependencies: {
|
|
211
|
+
eslint: '^9.0.0',
|
|
212
|
+
'@typescript-eslint/eslint-plugin': '^8.46.4',
|
|
213
|
+
'@typescript-eslint/parser': '^8.46.4',
|
|
214
|
+
'typescript-eslint': '^8.46.4',
|
|
215
|
+
jiti: '^2.6.1',
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
readFileSyncSpy.mockImplementation(() => packageJson);
|
|
219
|
+
existsSyncSpy.mockImplementation(() => false);
|
|
220
|
+
const result = getMissingLintPackages(directory);
|
|
221
|
+
expect(result).toEqual({
|
|
222
|
+
missingPackages: [
|
|
223
|
+
'eslint',
|
|
224
|
+
'@typescript-eslint/eslint-plugin',
|
|
225
|
+
'@typescript-eslint/parser',
|
|
226
|
+
'typescript-eslint',
|
|
227
|
+
'jiti',
|
|
228
|
+
],
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
it('should return packages that are not in package.json', () => {
|
|
232
|
+
const directory = '/test/project/component1';
|
|
233
|
+
readFileSyncSpy.mockReturnValue(JSON.stringify({ dependencies: {} }));
|
|
234
|
+
existsSyncSpy.mockReturnValue(false);
|
|
235
|
+
const result = getMissingLintPackages(directory);
|
|
236
|
+
expect(result).toEqual({
|
|
237
|
+
missingPackages: [
|
|
238
|
+
'eslint',
|
|
239
|
+
'@typescript-eslint/eslint-plugin',
|
|
240
|
+
'@typescript-eslint/parser',
|
|
241
|
+
'typescript-eslint',
|
|
242
|
+
'jiti',
|
|
243
|
+
],
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
it('should return packages that are missing in mixed scenarios', () => {
|
|
247
|
+
const directory = '/test/project/component1';
|
|
248
|
+
let readCount = 0;
|
|
249
|
+
readFileSyncSpy.mockImplementation(() => {
|
|
250
|
+
readCount++;
|
|
251
|
+
if (readCount === 1) {
|
|
252
|
+
// eslint in package.json
|
|
253
|
+
return JSON.stringify({ devDependencies: { eslint: '^9.0.0' } });
|
|
254
|
+
}
|
|
255
|
+
// Others not in package.json
|
|
256
|
+
return JSON.stringify({ dependencies: {} });
|
|
257
|
+
});
|
|
258
|
+
existsSyncSpy.mockReturnValue(false);
|
|
259
|
+
const result = getMissingLintPackages(directory);
|
|
260
|
+
expect(result).toEqual({
|
|
261
|
+
missingPackages: [
|
|
262
|
+
'eslint',
|
|
263
|
+
'@typescript-eslint/eslint-plugin',
|
|
264
|
+
'@typescript-eslint/parser',
|
|
265
|
+
'typescript-eslint',
|
|
266
|
+
'jiti',
|
|
267
|
+
],
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
it('should return packages that are in node_modules but not in package.json', () => {
|
|
271
|
+
const directory = '/test/project/component1';
|
|
272
|
+
readFileSyncSpy.mockReturnValue(JSON.stringify({ dependencies: {} }));
|
|
273
|
+
existsSyncSpy.mockReturnValue(true);
|
|
274
|
+
const result = getMissingLintPackages(directory);
|
|
275
|
+
expect(result).toEqual({
|
|
276
|
+
missingPackages: [
|
|
277
|
+
'eslint',
|
|
278
|
+
'@typescript-eslint/eslint-plugin',
|
|
279
|
+
'@typescript-eslint/parser',
|
|
280
|
+
'typescript-eslint',
|
|
281
|
+
'jiti',
|
|
282
|
+
],
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
it('should return packages that have versions below minimum', () => {
|
|
286
|
+
const directory = '/test/project/component1';
|
|
287
|
+
const packageJson = JSON.stringify({
|
|
288
|
+
devDependencies: {
|
|
289
|
+
eslint: '^8.0.0',
|
|
290
|
+
'@typescript-eslint/eslint-plugin': '^7.0.0',
|
|
291
|
+
'@typescript-eslint/parser': '^8.0.0',
|
|
292
|
+
'typescript-eslint': '^8.0.0',
|
|
293
|
+
jiti: '^2.0.0',
|
|
294
|
+
},
|
|
295
|
+
});
|
|
296
|
+
readFileSyncSpy.mockImplementation(() => packageJson);
|
|
297
|
+
existsSyncSpy.mockImplementation(() => true);
|
|
298
|
+
const result = getMissingLintPackages(directory);
|
|
299
|
+
expect(result).toEqual({
|
|
300
|
+
missingPackages: [
|
|
301
|
+
'eslint',
|
|
302
|
+
'@typescript-eslint/eslint-plugin',
|
|
303
|
+
'@typescript-eslint/parser',
|
|
304
|
+
'typescript-eslint',
|
|
305
|
+
'jiti',
|
|
306
|
+
],
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
it('should return only packages with wrong versions when others are correct', () => {
|
|
310
|
+
const directory = '/test/project/component1';
|
|
311
|
+
const packageJson = JSON.stringify({
|
|
312
|
+
devDependencies: {
|
|
313
|
+
eslint: '^8.0.0',
|
|
314
|
+
'@typescript-eslint/eslint-plugin': '^8.46.4',
|
|
315
|
+
'@typescript-eslint/parser': '^8.46.4',
|
|
316
|
+
'typescript-eslint': '^8.46.4',
|
|
317
|
+
jiti: '^2.6.1',
|
|
318
|
+
},
|
|
319
|
+
});
|
|
320
|
+
readFileSyncSpy.mockImplementation(() => packageJson);
|
|
321
|
+
existsSyncSpy.mockImplementation(() => true);
|
|
322
|
+
const result = getMissingLintPackages(directory);
|
|
323
|
+
expect(result).toEqual({
|
|
324
|
+
missingPackages: ['eslint'],
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
describe('hasEslintConfig', () => {
|
|
329
|
+
it('should return true if eslint.config.mts exists', () => {
|
|
330
|
+
const directory = '/test/project/component1';
|
|
331
|
+
existsSyncSpy.mockReturnValueOnce(true);
|
|
332
|
+
const result = hasEslintConfig(directory);
|
|
333
|
+
expect(result).toBe(true);
|
|
334
|
+
});
|
|
335
|
+
it('should return true if eslint.config.ts exists', () => {
|
|
336
|
+
const directory = '/test/project/component1';
|
|
337
|
+
existsSyncSpy
|
|
338
|
+
.mockReturnValueOnce(false) // eslint.config.mts
|
|
339
|
+
.mockReturnValueOnce(true); // eslint.config.ts
|
|
340
|
+
const result = hasEslintConfig(directory);
|
|
341
|
+
expect(result).toBe(true);
|
|
342
|
+
});
|
|
343
|
+
it('should return true if eslint.config.cts exists', () => {
|
|
344
|
+
const directory = '/test/project/component1';
|
|
345
|
+
existsSyncSpy
|
|
346
|
+
.mockReturnValueOnce(false) // eslint.config.mts
|
|
347
|
+
.mockReturnValueOnce(false) // eslint.config.ts
|
|
348
|
+
.mockReturnValueOnce(true); // eslint.config.cts
|
|
349
|
+
const result = hasEslintConfig(directory);
|
|
350
|
+
expect(result).toBe(true);
|
|
351
|
+
});
|
|
352
|
+
it('should return true if eslint.config.js exists', () => {
|
|
353
|
+
const directory = '/test/project/component1';
|
|
354
|
+
existsSyncSpy
|
|
355
|
+
.mockReturnValueOnce(false) // eslint.config.mts
|
|
356
|
+
.mockReturnValueOnce(false) // eslint.config.ts
|
|
357
|
+
.mockReturnValueOnce(false) // eslint.config.cts
|
|
358
|
+
.mockReturnValueOnce(true); // eslint.config.js
|
|
359
|
+
const result = hasEslintConfig(directory);
|
|
360
|
+
expect(result).toBe(true);
|
|
361
|
+
});
|
|
362
|
+
it('should return true if eslint.config.mjs exists', () => {
|
|
363
|
+
const directory = '/test/project/component1';
|
|
364
|
+
existsSyncSpy
|
|
365
|
+
.mockReturnValueOnce(false) // eslint.config.mts
|
|
366
|
+
.mockReturnValueOnce(false) // eslint.config.ts
|
|
367
|
+
.mockReturnValueOnce(false) // eslint.config.cts
|
|
368
|
+
.mockReturnValueOnce(false) // eslint.config.js
|
|
369
|
+
.mockReturnValueOnce(true); // eslint.config.mjs
|
|
370
|
+
const result = hasEslintConfig(directory);
|
|
371
|
+
expect(result).toBe(true);
|
|
372
|
+
});
|
|
373
|
+
it('should return true if eslint.config.cjs exists', () => {
|
|
374
|
+
const directory = '/test/project/component1';
|
|
375
|
+
existsSyncSpy
|
|
376
|
+
.mockReturnValueOnce(false) // eslint.config.mts
|
|
377
|
+
.mockReturnValueOnce(false) // eslint.config.ts
|
|
378
|
+
.mockReturnValueOnce(false) // eslint.config.cts
|
|
379
|
+
.mockReturnValueOnce(false) // eslint.config.js
|
|
380
|
+
.mockReturnValueOnce(false) // eslint.config.mjs
|
|
381
|
+
.mockReturnValueOnce(true); // eslint.config.cjs
|
|
382
|
+
const result = hasEslintConfig(directory);
|
|
383
|
+
expect(result).toBe(true);
|
|
384
|
+
});
|
|
385
|
+
it('should return false if no modern config file exists', () => {
|
|
386
|
+
const directory = '/test/project/component1';
|
|
387
|
+
existsSyncSpy.mockReturnValue(false);
|
|
388
|
+
const result = hasEslintConfig(directory);
|
|
389
|
+
expect(result).toBe(false);
|
|
390
|
+
});
|
|
391
|
+
it('should return false if only deprecated config files exist', () => {
|
|
392
|
+
const directory = '/test/project/component1';
|
|
393
|
+
existsSyncSpy.mockReturnValue(false); // No modern config files
|
|
394
|
+
const result = hasEslintConfig(directory);
|
|
395
|
+
expect(result).toBe(false);
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
describe('hasDeprecatedEslintConfig', () => {
|
|
399
|
+
it('should return true if .eslintrc.js exists', () => {
|
|
400
|
+
const directory = '/test/project/component1';
|
|
401
|
+
existsSyncSpy.mockReturnValueOnce(true);
|
|
402
|
+
const result = hasDeprecatedEslintConfig(directory);
|
|
403
|
+
expect(result).toBe(true);
|
|
404
|
+
});
|
|
405
|
+
it('should return true if .eslintrc.json exists', () => {
|
|
406
|
+
const directory = '/test/project/component1';
|
|
407
|
+
existsSyncSpy
|
|
408
|
+
.mockReturnValueOnce(false) // .eslintrc.js
|
|
409
|
+
.mockReturnValueOnce(false) // .eslintrc.cjs
|
|
410
|
+
.mockReturnValueOnce(false) // .eslintrc.yaml
|
|
411
|
+
.mockReturnValueOnce(false) // .eslintrc.yml
|
|
412
|
+
.mockReturnValueOnce(true); // .eslintrc.json
|
|
413
|
+
const result = hasDeprecatedEslintConfig(directory);
|
|
414
|
+
expect(result).toBe(true);
|
|
415
|
+
});
|
|
416
|
+
it('should return false if no deprecated config file exists', () => {
|
|
417
|
+
const directory = '/test/project/component1';
|
|
418
|
+
existsSyncSpy.mockReturnValue(false);
|
|
419
|
+
const result = hasDeprecatedEslintConfig(directory);
|
|
420
|
+
expect(result).toBe(false);
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
describe('getDeprecatedEslintConfigFiles', () => {
|
|
424
|
+
it('should return array of deprecated config files that exist', () => {
|
|
425
|
+
const directory = '/test/project/component1';
|
|
426
|
+
existsSyncSpy
|
|
427
|
+
.mockReturnValueOnce(true) // .eslintrc.js
|
|
428
|
+
.mockReturnValueOnce(false) // .eslintrc.cjs
|
|
429
|
+
.mockReturnValueOnce(false) // .eslintrc.yaml
|
|
430
|
+
.mockReturnValueOnce(false) // .eslintrc.yml
|
|
431
|
+
.mockReturnValueOnce(true) // .eslintrc.json
|
|
432
|
+
.mockReturnValueOnce(false); // .eslintrc
|
|
433
|
+
const result = getDeprecatedEslintConfigFiles(directory);
|
|
434
|
+
expect(result).toEqual(['.eslintrc.js', '.eslintrc.json']);
|
|
435
|
+
});
|
|
436
|
+
it('should return empty array if no deprecated config files exist', () => {
|
|
437
|
+
const directory = '/test/project/component1';
|
|
438
|
+
existsSyncSpy.mockReturnValue(false);
|
|
439
|
+
const result = getDeprecatedEslintConfigFiles(directory);
|
|
440
|
+
expect(result).toEqual([]);
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
describe('createEslintConfig', () => {
|
|
444
|
+
const writeFileSyncSpy = vi.spyOn(fs, 'writeFileSync');
|
|
445
|
+
afterEach(() => {
|
|
446
|
+
vi.clearAllMocks();
|
|
447
|
+
});
|
|
448
|
+
it('should create eslint.config.mts with template content', () => {
|
|
449
|
+
const directory = '/test/project/component1';
|
|
450
|
+
const result = createEslintConfig(directory);
|
|
451
|
+
expect(writeFileSyncSpy).toHaveBeenCalledWith(path.join(directory, 'eslint.config.mts'), expect.stringContaining('@typescript-eslint/parser'), 'utf-8');
|
|
452
|
+
expect(writeFileSyncSpy).toHaveBeenCalledWith(path.join(directory, 'eslint.config.mts'), expect.stringContaining('"no-console": ["warn"'), 'utf-8');
|
|
453
|
+
// Result is a relative path from process.cwd() to the config file
|
|
454
|
+
expect(result).toContain('eslint.config.mts');
|
|
455
|
+
});
|
|
456
|
+
it('should log error if write fails', () => {
|
|
457
|
+
const directory = '/test/project/component1';
|
|
458
|
+
writeFileSyncSpy.mockImplementationOnce(() => {
|
|
459
|
+
throw new Error('Write failed');
|
|
460
|
+
});
|
|
461
|
+
expect(() => createEslintConfig(directory)).toThrow();
|
|
462
|
+
expect(uiLogger.error).toHaveBeenCalledWith(expect.stringContaining('Failed to create ESLint configuration'));
|
|
463
|
+
});
|
|
464
|
+
});
|
|
465
|
+
describe('lintPackagesInDirectory', () => {
|
|
466
|
+
it('should execute eslint and return success with output', async () => {
|
|
467
|
+
const directory = '/test/project/component1';
|
|
468
|
+
mockExec.mockResolvedValueOnce({
|
|
469
|
+
stdout: 'All files passed!',
|
|
470
|
+
stderr: '',
|
|
471
|
+
});
|
|
472
|
+
const result = await lintPackagesInDirectory(directory);
|
|
473
|
+
expect(mockExec).toHaveBeenCalledWith('npx eslint . --color', {
|
|
474
|
+
cwd: directory,
|
|
475
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
476
|
+
});
|
|
477
|
+
expect(result.success).toBe(true);
|
|
478
|
+
expect(result.output).toContain('/test/project/component1');
|
|
479
|
+
expect(result.output).toContain('All files passed!');
|
|
480
|
+
});
|
|
481
|
+
it('should use relative path when projectDir is provided', async () => {
|
|
482
|
+
const directory = '/test/project/component1';
|
|
483
|
+
const projectDir = '/test/project';
|
|
484
|
+
mockExec.mockResolvedValueOnce({ stdout: '', stderr: '' });
|
|
485
|
+
const result = await lintPackagesInDirectory(directory, projectDir);
|
|
486
|
+
expect(result.output).toContain('component1:');
|
|
487
|
+
expect(result.output).toContain('No linting issues found.');
|
|
488
|
+
});
|
|
489
|
+
it('should return false and include errors in output when eslint fails', async () => {
|
|
490
|
+
const directory = '/test/project/component1';
|
|
491
|
+
const error = {
|
|
492
|
+
stdout: 'Error: Linting failed\n /test/file.ts\n 1:1 error Missing semicolon',
|
|
493
|
+
stderr: '',
|
|
494
|
+
code: 1,
|
|
495
|
+
};
|
|
496
|
+
mockExec.mockRejectedValueOnce(error);
|
|
497
|
+
const result = await lintPackagesInDirectory(directory);
|
|
498
|
+
expect(result.success).toBe(false);
|
|
499
|
+
expect(result.output).toContain(error.stdout);
|
|
500
|
+
});
|
|
501
|
+
it('should handle errors with stderr', async () => {
|
|
502
|
+
const directory = '/test/project/component1';
|
|
503
|
+
const error = {
|
|
504
|
+
stdout: '',
|
|
505
|
+
stderr: 'ESLint configuration error',
|
|
506
|
+
code: 2,
|
|
507
|
+
};
|
|
508
|
+
mockExec.mockRejectedValueOnce(error);
|
|
509
|
+
const result = await lintPackagesInDirectory(directory);
|
|
510
|
+
expect(result.success).toBe(false);
|
|
511
|
+
expect(result.output).toContain(error.stderr);
|
|
512
|
+
});
|
|
513
|
+
});
|
|
514
|
+
describe('lintPackages', () => {
|
|
515
|
+
it('should return success true when all directories pass linting', async () => {
|
|
516
|
+
const locations = [
|
|
517
|
+
'/test/project/component1',
|
|
518
|
+
'/test/project/component2',
|
|
519
|
+
];
|
|
520
|
+
mockExec.mockResolvedValue({ stdout: '', stderr: '' });
|
|
521
|
+
const result = await lintPackages(locations);
|
|
522
|
+
expect(mockExec).toHaveBeenCalledTimes(2);
|
|
523
|
+
expect(result.success).toBe(true);
|
|
524
|
+
expect(result.results).toHaveLength(2);
|
|
525
|
+
expect(result.results[0].success).toBe(true);
|
|
526
|
+
expect(result.results[1].success).toBe(true);
|
|
527
|
+
});
|
|
528
|
+
it('should return success false when some directories fail', async () => {
|
|
529
|
+
const locations = [
|
|
530
|
+
'/test/project/component1',
|
|
531
|
+
'/test/project/component2',
|
|
532
|
+
];
|
|
533
|
+
const projectDir = '/test/project';
|
|
534
|
+
mockExec
|
|
535
|
+
.mockResolvedValueOnce({ stdout: '', stderr: '' }) // component1 passes
|
|
536
|
+
.mockRejectedValueOnce({ stdout: 'errors', stderr: '', code: 1 }); // component2 fails
|
|
537
|
+
const result = await lintPackages(locations, projectDir);
|
|
538
|
+
expect(result.success).toBe(false);
|
|
539
|
+
expect(result.results).toHaveLength(2);
|
|
540
|
+
expect(result.results[0].location).toBe('component1');
|
|
541
|
+
expect(result.results[0].success).toBe(true);
|
|
542
|
+
expect(result.results[1].location).toBe('component2');
|
|
543
|
+
expect(result.results[1].success).toBe(false);
|
|
544
|
+
});
|
|
545
|
+
it('should handle multiple failures', async () => {
|
|
546
|
+
const locations = [
|
|
547
|
+
'/test/project/component1',
|
|
548
|
+
'/test/project/component2',
|
|
549
|
+
'/test/project/component3',
|
|
550
|
+
];
|
|
551
|
+
const projectDir = '/test/project';
|
|
552
|
+
mockExec
|
|
553
|
+
.mockRejectedValueOnce({ stdout: 'errors', stderr: '', code: 1 })
|
|
554
|
+
.mockResolvedValueOnce({ stdout: '', stderr: '' })
|
|
555
|
+
.mockRejectedValueOnce({ stdout: 'errors', stderr: '', code: 1 });
|
|
556
|
+
const result = await lintPackages(locations, projectDir);
|
|
557
|
+
expect(result.success).toBe(false);
|
|
558
|
+
expect(result.results).toHaveLength(3);
|
|
559
|
+
expect(result.results[0].success).toBe(false);
|
|
560
|
+
expect(result.results[1].success).toBe(true);
|
|
561
|
+
expect(result.results[2].success).toBe(false);
|
|
562
|
+
});
|
|
563
|
+
it('should get package.json locations if none provided', async () => {
|
|
564
|
+
const locations = ['/test/project/component1'];
|
|
565
|
+
getProjectPackageJsonLocationsSpy.mockResolvedValueOnce(locations);
|
|
566
|
+
mockExec.mockResolvedValueOnce({ stdout: '', stderr: '' });
|
|
567
|
+
await lintPackages();
|
|
568
|
+
expect(getProjectPackageJsonLocationsSpy).toHaveBeenCalledTimes(1);
|
|
569
|
+
expect(mockExec).toHaveBeenCalledWith('npx eslint . --color', {
|
|
570
|
+
cwd: locations[0],
|
|
571
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
572
|
+
});
|
|
573
|
+
});
|
|
574
|
+
it('should handle empty locations array', async () => {
|
|
575
|
+
const result = await lintPackages([]);
|
|
576
|
+
expect(mockExec).not.toHaveBeenCalled();
|
|
577
|
+
expect(result.success).toBe(true);
|
|
578
|
+
expect(result.results).toEqual([]);
|
|
579
|
+
});
|
|
580
|
+
});
|
|
581
|
+
describe('displayLintResults', () => {
|
|
582
|
+
it('should display output and summary for all passing results', () => {
|
|
583
|
+
const results = [
|
|
584
|
+
{
|
|
585
|
+
location: 'component1',
|
|
586
|
+
success: true,
|
|
587
|
+
output: '\ncomponent1:\n No linting issues found.\n',
|
|
588
|
+
},
|
|
589
|
+
{
|
|
590
|
+
location: 'component2',
|
|
591
|
+
success: true,
|
|
592
|
+
output: '\ncomponent2:\n No linting issues found.\n',
|
|
593
|
+
},
|
|
594
|
+
];
|
|
595
|
+
displayLintResults(results);
|
|
596
|
+
expect(uiLogger.log).toHaveBeenCalledWith(results[0].output);
|
|
597
|
+
expect(uiLogger.log).toHaveBeenCalledWith(results[1].output);
|
|
598
|
+
expect(uiLogger.success).toHaveBeenCalledWith('Linting passed in 2 directories:');
|
|
599
|
+
expect(uiLogger.log).toHaveBeenCalledWith(' ✓ component1');
|
|
600
|
+
expect(uiLogger.log).toHaveBeenCalledWith(' ✓ component2');
|
|
601
|
+
});
|
|
602
|
+
it('should display output and summary with mixed results', () => {
|
|
603
|
+
const results = [
|
|
604
|
+
{
|
|
605
|
+
location: 'component1',
|
|
606
|
+
success: true,
|
|
607
|
+
output: '\ncomponent1:\n No linting issues found.\n',
|
|
608
|
+
},
|
|
609
|
+
{
|
|
610
|
+
location: 'component2',
|
|
611
|
+
success: false,
|
|
612
|
+
output: '\ncomponent2:\n Linting errors found.\n',
|
|
613
|
+
},
|
|
614
|
+
];
|
|
615
|
+
displayLintResults(results);
|
|
616
|
+
expect(uiLogger.success).toHaveBeenCalledWith('Linting passed in 1 directory:');
|
|
617
|
+
expect(uiLogger.log).toHaveBeenCalledWith(' ✓ component1');
|
|
618
|
+
expect(uiLogger.error).toHaveBeenCalledWith('Linting failed in 1 directory:');
|
|
619
|
+
expect(uiLogger.log).toHaveBeenCalledWith(' ✗ component2');
|
|
620
|
+
});
|
|
621
|
+
it('should display only failures when all fail', () => {
|
|
622
|
+
const results = [
|
|
623
|
+
{
|
|
624
|
+
location: 'component1',
|
|
625
|
+
success: false,
|
|
626
|
+
output: '\ncomponent1:\n Errors.\n',
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
location: 'component2',
|
|
630
|
+
success: false,
|
|
631
|
+
output: '\ncomponent2:\n Errors.\n',
|
|
632
|
+
},
|
|
633
|
+
];
|
|
634
|
+
displayLintResults(results);
|
|
635
|
+
expect(uiLogger.error).toHaveBeenCalledWith('Linting failed in 2 directories:');
|
|
636
|
+
expect(uiLogger.log).toHaveBeenCalledWith(' ✗ component1');
|
|
637
|
+
expect(uiLogger.log).toHaveBeenCalledWith(' ✗ component2');
|
|
638
|
+
});
|
|
639
|
+
});
|
|
640
|
+
});
|
|
@@ -76,7 +76,7 @@ describe('lib/projects/add/legacyAddComponent', () => {
|
|
|
76
76
|
type: 'module',
|
|
77
77
|
}, accountId);
|
|
78
78
|
expect(mockedUiLogger.log).toHaveBeenCalledWith(commands.project.add.creatingComponent('test-project'));
|
|
79
|
-
expect(mockedUiLogger.success).toHaveBeenCalledWith(commands.project.add.success('
|
|
79
|
+
expect(mockedUiLogger.success).toHaveBeenCalledWith(commands.project.add.success('test-project'));
|
|
80
80
|
});
|
|
81
81
|
it('throws an error when project contains a public app', async () => {
|
|
82
82
|
const mockComponents = [
|