@hubspot/cli 7.11.8-experimental.0 → 8.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. package/api/__tests__/migrate.test.js +19 -1
  2. package/api/migrate.d.ts +1 -1
  3. package/api/migrate.js +2 -1
  4. package/bin/cli.js +12 -27
  5. package/commands/__tests__/customObject.test.js +0 -2
  6. package/commands/__tests__/doctor.test.js +0 -2
  7. package/commands/__tests__/getStarted.test.js +0 -4
  8. package/commands/__tests__/project.test.js +0 -4
  9. package/commands/__tests__/upgrade.test.js +309 -0
  10. package/commands/account/__tests__/auth.test.js +180 -0
  11. package/commands/account/__tests__/list.test.js +128 -3
  12. package/commands/account/__tests__/rename.test.js +0 -2
  13. package/commands/account/__tests__/use.test.js +138 -0
  14. package/commands/account/auth.js +1 -1
  15. package/commands/account/clean.js +4 -3
  16. package/commands/account/createOverride.js +3 -2
  17. package/commands/account/info.js +2 -2
  18. package/commands/account/list.js +4 -4
  19. package/commands/account/remove.js +3 -2
  20. package/commands/account/removeOverride.js +3 -2
  21. package/commands/account/use.js +4 -3
  22. package/commands/app/__tests__/migrate.test.js +8 -25
  23. package/commands/app/migrate.js +10 -16
  24. package/commands/app/secret/__tests__/add.test.js +112 -0
  25. package/commands/app/secret/add.js +13 -13
  26. package/commands/auth.js +8 -2
  27. package/commands/cms/__tests__/fetch.test.js +114 -15
  28. package/commands/cms/__tests__/upload.test.js +308 -0
  29. package/commands/cms/__tests__/watch.test.js +212 -0
  30. package/commands/cms/app/create.js +2 -3
  31. package/commands/cms/convertFields.js +1 -1
  32. package/commands/cms/fetch.js +3 -2
  33. package/commands/cms/function/deploy.js +2 -2
  34. package/commands/cms/function/list.js +2 -3
  35. package/commands/cms/lighthouseScore.js +19 -27
  36. package/commands/cms/module/marketplace-validate.js +0 -1
  37. package/commands/cms/theme/__tests__/preview.test.js +2 -8
  38. package/commands/cms/theme/create.js +1 -1
  39. package/commands/cms/theme/marketplace-validate.js +0 -1
  40. package/commands/cms/theme/preview.d.ts +0 -1
  41. package/commands/cms/theme/preview.js +12 -52
  42. package/commands/cms/upload.js +3 -3
  43. package/commands/cms/watch.js +3 -3
  44. package/commands/customObject.js +0 -2
  45. package/commands/doctor.js +10 -2
  46. package/commands/filemanager/__tests__/upload.test.js +161 -0
  47. package/commands/getStarted.js +13 -3
  48. package/commands/hubdb/__tests__/list.test.js +0 -9
  49. package/commands/hubdb/list.js +6 -8
  50. package/commands/init.js +8 -2
  51. package/commands/mcp/__tests__/start.test.js +113 -3
  52. package/commands/mcp/setup.js +0 -7
  53. package/commands/mcp/start.d.ts +1 -1
  54. package/commands/mcp/start.js +0 -7
  55. package/commands/project/__tests__/add.test.js +0 -2
  56. package/commands/project/__tests__/create.test.js +2 -2
  57. package/commands/project/__tests__/deploy.test.js +0 -4
  58. package/commands/project/__tests__/dev.test.js +273 -0
  59. package/commands/project/__tests__/devUnifiedFlow.test.js +2 -5
  60. package/commands/project/__tests__/installDeps.test.js +0 -2
  61. package/commands/project/__tests__/lint.test.js +0 -5
  62. package/commands/project/__tests__/logs.test.js +24 -31
  63. package/commands/project/__tests__/migrate.test.js +7 -12
  64. package/commands/project/__tests__/updateDeps.test.js +0 -2
  65. package/commands/project/__tests__/upload.test.js +191 -0
  66. package/commands/project/__tests__/validate.test.js +314 -31
  67. package/commands/project/cloneApp.d.ts +1 -7
  68. package/commands/project/cloneApp.js +1 -149
  69. package/commands/project/create.js +3 -4
  70. package/commands/project/deploy.js +18 -7
  71. package/commands/project/dev/deprecatedFlow.js +0 -2
  72. package/commands/project/dev/index.js +23 -11
  73. package/commands/project/dev/unifiedFlow.d.ts +1 -1
  74. package/commands/project/dev/unifiedFlow.js +1 -4
  75. package/commands/project/list.js +4 -4
  76. package/commands/project/listBuilds.js +2 -7
  77. package/commands/project/logs.js +19 -12
  78. package/commands/project/migrate.js +3 -3
  79. package/commands/project/profile/add.js +1 -1
  80. package/commands/project/profile/delete.js +1 -1
  81. package/commands/project/upload.d.ts +1 -1
  82. package/commands/project/upload.js +13 -4
  83. package/commands/project/validate.js +85 -13
  84. package/commands/project/watch.js +7 -7
  85. package/commands/project.js +0 -4
  86. package/commands/sandbox/__tests__/create.test.js +0 -2
  87. package/commands/secret/__tests__/addSecret.test.js +140 -7
  88. package/commands/secret/addSecret.js +3 -1
  89. package/commands/testAccount/__tests__/create.test.js +6 -1
  90. package/commands/testAccount/__tests__/importData.test.js +0 -1
  91. package/commands/testAccount/create.d.ts +1 -0
  92. package/commands/testAccount/create.js +13 -5
  93. package/commands/upgrade.d.ts +8 -0
  94. package/commands/upgrade.js +119 -0
  95. package/lang/en.d.ts +88 -10
  96. package/lang/en.js +105 -26
  97. package/lib/__tests__/buildAccount.test.js +0 -13
  98. package/lib/__tests__/cliUpgradeUtils.test.js +131 -0
  99. package/lib/__tests__/commonOpts.test.js +0 -1
  100. package/lib/__tests__/dependencyManagement.test.js +633 -13
  101. package/lib/__tests__/developerTestAccounts.test.js +0 -1
  102. package/lib/__tests__/hasFeature.test.js +0 -6
  103. package/lib/__tests__/importData.test.js +0 -1
  104. package/lib/__tests__/npmCli.test.js +84 -0
  105. package/lib/__tests__/oauth.test.js +1 -11
  106. package/lib/__tests__/process.test.js +0 -1
  107. package/lib/__tests__/sandboxSync.test.js +0 -1
  108. package/lib/__tests__/sandboxes.test.js +0 -1
  109. package/lib/__tests__/serverlessLogs.test.js +0 -1
  110. package/lib/__tests__/usageTracking.test.js +39 -6
  111. package/lib/__tests__/validation.test.js +0 -1
  112. package/lib/app/__tests__/migrate.test.js +137 -12
  113. package/lib/app/migrate.d.ts +5 -2
  114. package/lib/app/migrate.js +30 -11
  115. package/lib/app/urls.d.ts +1 -1
  116. package/lib/buildAccount.d.ts +1 -1
  117. package/lib/cliUpgradeUtils.d.ts +22 -0
  118. package/lib/cliUpgradeUtils.js +62 -0
  119. package/lib/cmsAssets/api-sample.js +2 -5
  120. package/lib/cmsAssets/function.js +1 -9
  121. package/lib/cmsAssets/module.js +1 -9
  122. package/lib/cmsAssets/template.js +1 -9
  123. package/lib/configOptions.d.ts +0 -1
  124. package/lib/configOptions.js +1 -5
  125. package/lib/constants.d.ts +6 -0
  126. package/lib/constants.js +10 -4
  127. package/lib/dependencyManagement.d.ts +9 -0
  128. package/lib/dependencyManagement.js +127 -26
  129. package/lib/developerTestAccounts.d.ts +1 -1
  130. package/lib/doctor/Diagnosis.d.ts +1 -0
  131. package/lib/doctor/Diagnosis.js +7 -0
  132. package/lib/doctor/DiagnosticInfoBuilder.d.ts +2 -1
  133. package/lib/doctor/DiagnosticInfoBuilder.js +8 -4
  134. package/lib/doctor/Doctor.d.ts +12 -0
  135. package/lib/doctor/Doctor.js +283 -33
  136. package/lib/doctor/__tests__/Diagnosis.test.js +1 -0
  137. package/lib/doctor/__tests__/Doctor.test.js +201 -51
  138. package/lib/errorHandlers/__tests__/index.test.d.ts +1 -0
  139. package/lib/errorHandlers/__tests__/index.test.js +278 -0
  140. package/lib/errorHandlers/index.d.ts +1 -0
  141. package/lib/errorHandlers/index.js +14 -2
  142. package/lib/http.js +3 -1
  143. package/lib/links.js +2 -3
  144. package/lib/mcp/__tests__/setup.test.js +69 -2
  145. package/lib/mcp/setup.d.ts +1 -0
  146. package/lib/mcp/setup.js +37 -4
  147. package/lib/middleware/__tests__/configMiddleware.test.js +1 -43
  148. package/lib/middleware/__tests__/usageTrackingMiddleware.test.d.ts +1 -0
  149. package/lib/middleware/__tests__/usageTrackingMiddleware.test.js +44 -0
  150. package/lib/middleware/__tests__/yargsChecksMiddleware.test.js +0 -5
  151. package/lib/middleware/autoUpdateMiddleware.js +58 -57
  152. package/lib/middleware/configMiddleware.d.ts +0 -3
  153. package/lib/middleware/configMiddleware.js +0 -11
  154. package/lib/middleware/fireAlarmMiddleware.js +1 -1
  155. package/lib/middleware/spinniesMiddleware.d.ts +1 -0
  156. package/lib/middleware/spinniesMiddleware.js +4 -0
  157. package/lib/middleware/usageTrackingMiddleware.d.ts +13 -0
  158. package/lib/middleware/usageTrackingMiddleware.js +16 -0
  159. package/lib/{npm.d.ts → npm/npmCli.d.ts} +8 -3
  160. package/lib/npm/npmCli.js +59 -0
  161. package/lib/npm/packageJson.d.ts +24 -0
  162. package/lib/npm/packageJson.js +102 -0
  163. package/lib/npm/workspaces.d.ts +12 -0
  164. package/lib/npm/workspaces.js +48 -0
  165. package/lib/oauth.js +1 -3
  166. package/lib/projects/__tests__/AppDevModeInterface.test.js +40 -18
  167. package/lib/projects/__tests__/DevServerManager.test.js +1 -0
  168. package/lib/projects/__tests__/DevSessionManager.test.d.ts +1 -0
  169. package/lib/projects/__tests__/DevSessionManager.test.js +250 -0
  170. package/lib/projects/__tests__/LocalDevProcess.test.js +19 -6
  171. package/lib/projects/__tests__/LocalDevWebsocketServer.test.js +0 -2
  172. package/lib/projects/__tests__/UIExtensionsDevModeInterface.test.js +0 -1
  173. package/lib/projects/__tests__/components.test.js +6 -22
  174. package/lib/projects/__tests__/deploy.test.js +0 -1
  175. package/lib/projects/__tests__/localDevProjectHelpers.test.js +3 -5
  176. package/lib/projects/__tests__/pollProjectBuildAndDeploy.test.d.ts +1 -0
  177. package/lib/projects/__tests__/pollProjectBuildAndDeploy.test.js +328 -0
  178. package/lib/projects/__tests__/projectProfiles.test.d.ts +1 -0
  179. package/lib/projects/__tests__/projectProfiles.test.js +441 -0
  180. package/lib/projects/__tests__/projects.test.js +0 -1
  181. package/lib/projects/__tests__/structure.test.js +0 -1
  182. package/lib/projects/__tests__/uieLinting.test.js +2 -11
  183. package/lib/projects/__tests__/upload.test.js +104 -3
  184. package/lib/projects/add/__tests__/legacyAddComponent.test.js +0 -2
  185. package/lib/projects/add/__tests__/v2AddComponent.test.js +2 -4
  186. package/lib/projects/add/v2AddComponent.js +2 -3
  187. package/lib/projects/components.d.ts +1 -1
  188. package/lib/projects/components.js +4 -4
  189. package/lib/projects/create/__tests__/legacy.test.js +0 -1
  190. package/lib/projects/create/__tests__/v2.test.js +0 -1
  191. package/lib/projects/create/v2.d.ts +1 -1
  192. package/lib/projects/create/v2.js +1 -1
  193. package/lib/projects/ensureProjectExists.js +0 -1
  194. package/lib/projects/localDev/AppDevModeInterface.js +9 -2
  195. package/lib/projects/localDev/DevSessionManager.d.ts +18 -0
  196. package/lib/projects/localDev/DevSessionManager.js +95 -0
  197. package/lib/projects/localDev/LocalDevLogger.d.ts +4 -0
  198. package/lib/projects/localDev/LocalDevLogger.js +18 -7
  199. package/lib/projects/localDev/LocalDevManager_DEPRECATED.d.ts +4 -3
  200. package/lib/projects/localDev/LocalDevManager_DEPRECATED.js +23 -12
  201. package/lib/projects/localDev/LocalDevProcess.d.ts +2 -1
  202. package/lib/projects/localDev/LocalDevProcess.js +18 -7
  203. package/lib/projects/localDev/LocalDevState.d.ts +3 -2
  204. package/lib/projects/localDev/helpers/account.d.ts +1 -1
  205. package/lib/projects/localDev/helpers/devSessionsApi.d.ts +9 -0
  206. package/lib/projects/localDev/helpers/devSessionsApi.js +19 -0
  207. package/lib/projects/localDev/helpers/project.d.ts +1 -1
  208. package/lib/projects/localDev/helpers/project.js +1 -2
  209. package/lib/projects/pollProjectBuildAndDeploy.js +4 -5
  210. package/lib/projects/projectProfiles.d.ts +17 -0
  211. package/lib/projects/projectProfiles.js +140 -0
  212. package/lib/projects/structure.d.ts +1 -1
  213. package/lib/projects/uieLinting.js +6 -8
  214. package/lib/projects/upload.d.ts +9 -1
  215. package/lib/projects/upload.js +11 -5
  216. package/lib/projects/urls.d.ts +1 -0
  217. package/lib/projects/urls.js +3 -3
  218. package/lib/prompts/__tests__/createDeveloperTestAccountConfigPrompt.test.js +8 -4
  219. package/lib/prompts/createDeveloperTestAccountConfigPrompt.d.ts +2 -0
  220. package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +19 -13
  221. package/lib/sandboxSync.d.ts +1 -1
  222. package/lib/sandboxes.d.ts +1 -1
  223. package/lib/serverlessLogs.js +0 -1
  224. package/lib/theme/__tests__/migrate.test.js +12 -4
  225. package/lib/theme/migrate.js +2 -3
  226. package/lib/ui/__tests__/SpinniesManager.test.js +0 -1
  227. package/lib/usageTracking.js +18 -0
  228. package/mcp-server/tools/cms/HsCreateFunctionTool.d.ts +2 -2
  229. package/mcp-server/tools/cms/HsCreateFunctionTool.js +2 -1
  230. package/mcp-server/tools/cms/HsCreateModuleTool.js +2 -1
  231. package/mcp-server/tools/cms/HsCreateTemplateTool.js +2 -1
  232. package/mcp-server/tools/cms/HsFunctionLogsTool.js +2 -2
  233. package/mcp-server/tools/cms/HsListFunctionsTool.js +2 -2
  234. package/mcp-server/tools/cms/HsListTool.js +2 -2
  235. package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +4 -4
  236. package/mcp-server/tools/cms/__tests__/HsCreateModuleTool.test.js +4 -4
  237. package/mcp-server/tools/cms/__tests__/HsCreateTemplateTool.test.js +4 -4
  238. package/mcp-server/tools/cms/__tests__/HsFunctionLogsTool.test.js +4 -4
  239. package/mcp-server/tools/cms/__tests__/HsListFunctionsTool.test.js +4 -4
  240. package/mcp-server/tools/cms/__tests__/HsListTool.test.js +4 -4
  241. package/mcp-server/tools/project/AddFeatureToProjectTool.js +4 -3
  242. package/mcp-server/tools/project/CreateProjectTool.js +4 -3
  243. package/mcp-server/tools/project/CreateTestAccountTool.d.ts +7 -2
  244. package/mcp-server/tools/project/CreateTestAccountTool.js +19 -9
  245. package/mcp-server/tools/project/DocFetchTool.js +2 -1
  246. package/mcp-server/tools/project/DocsSearchTool.js +2 -1
  247. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +4 -4
  248. package/mcp-server/tools/project/GetApplicationInfoTool.js +5 -5
  249. package/mcp-server/tools/project/GetConfigValuesTool.js +2 -1
  250. package/mcp-server/tools/project/UploadProjectTools.js +6 -3
  251. package/mcp-server/tools/project/ValidateProjectTool.js +2 -1
  252. package/mcp-server/tools/project/__tests__/AddFeatureToProjectTool.test.js +4 -2
  253. package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +4 -2
  254. package/mcp-server/tools/project/__tests__/CreateTestAccountTool.test.js +23 -4
  255. package/mcp-server/tools/project/__tests__/DeployProjectTool.test.js +3 -1
  256. package/mcp-server/tools/project/__tests__/DocFetchTool.test.js +0 -1
  257. package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +3 -1
  258. package/mcp-server/tools/project/__tests__/GetApiUsagePatternsByAppIdTool.test.js +4 -2
  259. package/mcp-server/tools/project/__tests__/GetApplicationInfoTool.test.js +8 -5
  260. package/mcp-server/tools/project/__tests__/GetBuildLogsTool.test.js +3 -1
  261. package/mcp-server/tools/project/__tests__/GetBuildStatusTool.test.js +3 -1
  262. package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +7 -3
  263. package/mcp-server/tools/project/__tests__/GuidedWalkthroughTool.test.js +3 -1
  264. package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +17 -3
  265. package/mcp-server/tools/project/__tests__/ValidateProjectTool.test.js +3 -1
  266. package/mcp-server/utils/__tests__/content.test.js +0 -3
  267. package/mcp-server/utils/__tests__/feedbackTracking.test.js +0 -3
  268. package/mcp-server/utils/__tests__/project.test.js +65 -4
  269. package/mcp-server/utils/project.js +6 -2
  270. package/package.json +15 -17
  271. package/types/Cms.d.ts +1 -1
  272. package/types/Cms.js +2 -0
  273. package/types/LocalDev.d.ts +3 -2
  274. package/types/PackageJson.d.ts +10 -0
  275. package/types/PackageJson.js +1 -0
  276. package/types/ProjectComponents.d.ts +1 -1
  277. package/ui/components/BoxWithTitle.js +1 -1
  278. package/ui/components/Table.d.ts +89 -0
  279. package/ui/components/Table.js +246 -0
  280. package/ui/lib/table.d.ts +2 -0
  281. package/ui/lib/table.js +11 -0
  282. package/ui/playground/Playground.d.ts +5 -0
  283. package/ui/{views/UiSandbox.js → playground/Playground.js} +4 -4
  284. package/ui/{lib/ui-testing-utils.d.ts → playground/fixtures.d.ts} +1 -1
  285. package/ui/{lib/ui-testing-utils.js → playground/fixtures.js} +33 -1
  286. package/ui/render.d.ts +19 -0
  287. package/ui/render.js +44 -0
  288. package/commands/__tests__/create.test.js +0 -53
  289. package/commands/create.d.ts +0 -4
  290. package/commands/create.js +0 -137
  291. package/commands/customObject/__tests__/schema.test.js +0 -53
  292. package/commands/customObject/schema/create.d.ts +0 -4
  293. package/commands/customObject/schema/create.js +0 -34
  294. package/commands/customObject/schema/delete.d.ts +0 -4
  295. package/commands/customObject/schema/delete.js +0 -37
  296. package/commands/customObject/schema/fetch-all.d.ts +0 -4
  297. package/commands/customObject/schema/fetch-all.js +0 -32
  298. package/commands/customObject/schema/fetch.d.ts +0 -4
  299. package/commands/customObject/schema/fetch.js +0 -36
  300. package/commands/customObject/schema/list.d.ts +0 -4
  301. package/commands/customObject/schema/list.js +0 -26
  302. package/commands/customObject/schema/update.d.ts +0 -4
  303. package/commands/customObject/schema/update.js +0 -39
  304. package/commands/customObject/schema.d.ts +0 -3
  305. package/commands/customObject/schema.js +0 -31
  306. package/commands/fetch.d.ts +0 -4
  307. package/commands/fetch.js +0 -52
  308. package/commands/function/deploy.d.ts +0 -4
  309. package/commands/function/deploy.js +0 -31
  310. package/commands/function/list.d.ts +0 -4
  311. package/commands/function/list.js +0 -33
  312. package/commands/function/server.d.ts +0 -4
  313. package/commands/function/server.js +0 -57
  314. package/commands/function.d.ts +0 -3
  315. package/commands/function.js +0 -32
  316. package/commands/lint.d.ts +0 -4
  317. package/commands/lint.js +0 -31
  318. package/commands/list.d.ts +0 -4
  319. package/commands/list.js +0 -31
  320. package/commands/logs.d.ts +0 -4
  321. package/commands/logs.js +0 -58
  322. package/commands/module/marketplace-validate.d.ts +0 -4
  323. package/commands/module/marketplace-validate.js +0 -31
  324. package/commands/module.d.ts +0 -3
  325. package/commands/module.js +0 -23
  326. package/commands/mv.d.ts +0 -4
  327. package/commands/mv.js +0 -35
  328. package/commands/project/__tests__/migrateApp.test.js +0 -78
  329. package/commands/project/migrateApp.d.ts +0 -4
  330. package/commands/project/migrateApp.js +0 -55
  331. package/commands/remove.d.ts +0 -4
  332. package/commands/remove.js +0 -31
  333. package/commands/theme/generate-selectors.d.ts +0 -4
  334. package/commands/theme/generate-selectors.js +0 -30
  335. package/commands/theme/marketplace-validate.d.ts +0 -4
  336. package/commands/theme/marketplace-validate.js +0 -33
  337. package/commands/theme/preview.d.ts +0 -4
  338. package/commands/theme/preview.js +0 -59
  339. package/commands/theme.d.ts +0 -3
  340. package/commands/theme.js +0 -29
  341. package/commands/upload.d.ts +0 -4
  342. package/commands/upload.js +0 -62
  343. package/commands/watch.d.ts +0 -4
  344. package/commands/watch.js +0 -73
  345. package/lib/__tests__/npm.test.js +0 -57
  346. package/lib/__tests__/projectProfiles.test.js +0 -129
  347. package/lib/app/__tests__/migrate_legacy.test.js +0 -143
  348. package/lib/app/migrate_legacy.d.ts +0 -4
  349. package/lib/app/migrate_legacy.js +0 -121
  350. package/lib/npm.js +0 -33
  351. package/lib/projectProfiles.d.ts +0 -7
  352. package/lib/projectProfiles.js +0 -73
  353. package/lib/ui/table.d.ts +0 -3
  354. package/lib/ui/table.js +0 -63
  355. package/ui/index.d.ts +0 -1
  356. package/ui/index.js +0 -6
  357. package/ui/views/UiSandbox.d.ts +0 -5
  358. /package/commands/__tests__/{create.test.d.ts → upgrade.test.d.ts} +0 -0
  359. /package/commands/{customObject/__tests__/schema.test.d.ts → cms/__tests__/upload.test.d.ts} +0 -0
  360. /package/commands/{project/__tests__/migrateApp.test.d.ts → cms/__tests__/watch.test.d.ts} +0 -0
  361. /package/{lib/__tests__/npm.test.d.ts → commands/project/__tests__/dev.test.d.ts} +0 -0
  362. /package/lib/__tests__/{projectProfiles.test.d.ts → cliUpgradeUtils.test.d.ts} +0 -0
  363. /package/lib/{app/__tests__/migrate_legacy.test.d.ts → __tests__/npmCli.test.d.ts} +0 -0
@@ -0,0 +1,441 @@
1
+ import path from 'path';
2
+ import { loadHsProfileFile, getHsProfileFilename, getAllHsProfiles, validateProfileVariables, } from '@hubspot/project-parsing-lib/profiles';
3
+ import { lib } from '../../../lang/en.js';
4
+ import { uiBetaTag, uiLine } from '../../ui/index.js';
5
+ import { uiLogger } from '../../ui/logger.js';
6
+ import { getConfigAccountById } from '@hubspot/local-dev-lib/config';
7
+ import { logProfileHeader, logProfileFooter, loadProfile, enforceProfileUsage, loadAndValidateProfile, validateProjectForProfile, } from '../projectProfiles.js';
8
+ import { handleTranslate } from '../upload.js';
9
+ import SpinniesManager from '../../ui/SpinniesManager.js';
10
+ import { commands } from '../../../lang/en.js';
11
+ // Mock dependencies
12
+ vi.mock('@hubspot/project-parsing-lib/profiles');
13
+ vi.mock('@hubspot/local-dev-lib/config');
14
+ vi.mock('../../ui', async (importOriginal) => {
15
+ const actual = (await importOriginal());
16
+ return {
17
+ ...actual,
18
+ uiBetaTag: vi.fn(),
19
+ uiLine: vi.fn(),
20
+ indent: vi.fn((level) => ' '.repeat(level)),
21
+ };
22
+ });
23
+ vi.mock('../../../lang/en');
24
+ vi.mock('../upload');
25
+ vi.mock('../../ui/SpinniesManager');
26
+ const mockedLoadHsProfileFile = loadHsProfileFile;
27
+ const mockedGetHsProfileFilename = getHsProfileFilename;
28
+ const mockedGetAllHsProfiles = getAllHsProfiles;
29
+ const mockedValidateProfileVariables = validateProfileVariables;
30
+ const mockedGetConfigAccountById = getConfigAccountById;
31
+ const mockedUiBetaTag = uiBetaTag;
32
+ const mockedUiLine = uiLine;
33
+ const mockedUiLogger = uiLogger;
34
+ describe('lib/projectProfiles', () => {
35
+ describe('logProfileHeader()', () => {
36
+ it('should log profile header with correct format', () => {
37
+ const profileName = 'test-profile';
38
+ const filename = 'test-profile.hsprofile';
39
+ mockedGetHsProfileFilename.mockReturnValue(filename);
40
+ logProfileHeader(profileName);
41
+ expect(mockedUiLine).toHaveBeenCalled();
42
+ expect(mockedUiBetaTag).toHaveBeenCalledWith(lib.projectProfiles.logs.usingProfile(filename));
43
+ expect(mockedUiLogger.log).toHaveBeenCalledWith('');
44
+ });
45
+ });
46
+ describe('logProfileFooter()', () => {
47
+ const mockProfile = {
48
+ accountId: 123,
49
+ variables: {
50
+ key1: 'value1',
51
+ key2: 'value2',
52
+ },
53
+ };
54
+ it('should log profile footer with account ID', () => {
55
+ logProfileFooter(mockProfile);
56
+ expect(mockedUiLogger.log).toHaveBeenCalledWith(lib.projectProfiles.logs.profileTargetAccount(mockProfile.accountId));
57
+ expect(mockedUiLine).toHaveBeenCalled();
58
+ expect(mockedUiLogger.log).toHaveBeenCalledWith('');
59
+ });
60
+ it('should log variables when includeVariables is true', () => {
61
+ logProfileFooter(mockProfile, true);
62
+ expect(mockedUiLogger.log).toHaveBeenCalledWith(lib.projectProfiles.logs.profileTargetAccount(mockProfile.accountId));
63
+ expect(mockedUiLogger.log).toHaveBeenCalledWith('');
64
+ expect(mockedUiLogger.log).toHaveBeenCalledWith(lib.projectProfiles.logs.profileVariables);
65
+ expect(mockedUiLogger.log).toHaveBeenCalledWith(' key1: value1');
66
+ expect(mockedUiLogger.log).toHaveBeenCalledWith(' key2: value2');
67
+ expect(mockedUiLine).toHaveBeenCalled();
68
+ expect(mockedUiLogger.log).toHaveBeenCalledWith('');
69
+ });
70
+ });
71
+ describe('loadProfile()', () => {
72
+ const mockProjectConfig = {
73
+ srcDir: 'src',
74
+ name: 'test-project',
75
+ platformVersion: '1.0.0',
76
+ };
77
+ const mockProjectDir = '/test/project';
78
+ const mockProfileName = 'test-profile';
79
+ const mockProfile = {
80
+ accountId: 123,
81
+ };
82
+ it('should throw error when project config is missing', () => {
83
+ expect(() => loadProfile(null, mockProjectDir, mockProfileName)).toThrow(lib.projectProfiles.loadProfile.errors.noProjectConfig);
84
+ });
85
+ it('should throw error when project dir is missing', () => {
86
+ expect(() => loadProfile(mockProjectConfig, null, mockProfileName)).toThrow(lib.projectProfiles.loadProfile.errors.noProjectConfig);
87
+ });
88
+ it('should throw error when profile is not found', () => {
89
+ mockedLoadHsProfileFile.mockReturnValue(null);
90
+ const filename = 'test-profile.hsprofile';
91
+ mockedGetHsProfileFilename.mockReturnValue(filename);
92
+ expect(() => loadProfile(mockProjectConfig, mockProjectDir, mockProfileName)).toThrow(lib.projectProfiles.loadProfile.errors.profileNotFound(filename));
93
+ });
94
+ it('should throw error when profile has no account ID', () => {
95
+ mockedLoadHsProfileFile.mockReturnValue({});
96
+ const filename = 'test-profile.hsprofile';
97
+ mockedGetHsProfileFilename.mockReturnValue(filename);
98
+ expect(() => loadProfile(mockProjectConfig, mockProjectDir, mockProfileName)).toThrow(lib.projectProfiles.loadProfile.errors.missingAccountId(filename));
99
+ });
100
+ it('should throw error when profile loading fails', () => {
101
+ mockedLoadHsProfileFile.mockImplementation(() => {
102
+ throw new Error('Load failed');
103
+ });
104
+ const filename = 'test-profile.hsprofile';
105
+ mockedGetHsProfileFilename.mockReturnValue(filename);
106
+ expect(() => loadProfile(mockProjectConfig, mockProjectDir, mockProfileName)).toThrow(lib.projectProfiles.loadProfile.errors.failedToLoadProfile(filename));
107
+ });
108
+ it('should throw error when account is not found in config', () => {
109
+ mockedLoadHsProfileFile.mockReturnValue(mockProfile);
110
+ mockedGetConfigAccountById.mockImplementation(() => {
111
+ throw new Error('Account not found');
112
+ });
113
+ const filename = 'test-profile.hsprofile';
114
+ mockedGetHsProfileFilename.mockReturnValue(filename);
115
+ expect(() => loadProfile(mockProjectConfig, mockProjectDir, mockProfileName)).toThrow(lib.projectProfiles.loadProfile.errors.listedAccountNotFound(mockProfile.accountId, filename));
116
+ });
117
+ it('should return profile when loading succeeds', () => {
118
+ mockedLoadHsProfileFile.mockReturnValue(mockProfile);
119
+ mockedGetConfigAccountById.mockReturnValue({
120
+ accountId: mockProfile.accountId,
121
+ });
122
+ const result = loadProfile(mockProjectConfig, mockProjectDir, mockProfileName);
123
+ expect(result).toEqual(mockProfile);
124
+ expect(mockedLoadHsProfileFile).toHaveBeenCalledWith(path.join(mockProjectDir, mockProjectConfig.srcDir), mockProfileName);
125
+ expect(mockedGetConfigAccountById).toHaveBeenCalledWith(mockProfile.accountId);
126
+ });
127
+ });
128
+ describe('enforceProfileUsage()', () => {
129
+ const mockProjectConfig = {
130
+ srcDir: 'src',
131
+ name: 'test-project',
132
+ platformVersion: '1.0.0',
133
+ };
134
+ const mockProjectDir = '/test/project';
135
+ it('should not throw when no profiles exist', async () => {
136
+ mockedGetAllHsProfiles.mockResolvedValue([]);
137
+ await expect(enforceProfileUsage(mockProjectConfig, mockProjectDir)).resolves.toBeUndefined();
138
+ });
139
+ it('should throw error when profiles exist', async () => {
140
+ mockedGetAllHsProfiles.mockResolvedValue(['profile1', 'profile2']);
141
+ await expect(enforceProfileUsage(mockProjectConfig, mockProjectDir)).rejects.toThrow(lib.projectProfiles.exitIfUsingProfiles.errors.noProfileSpecified);
142
+ });
143
+ it('should not throw when project config is null', async () => {
144
+ await expect(enforceProfileUsage(null, mockProjectDir)).resolves.toBeUndefined();
145
+ });
146
+ it('should not throw when project dir is null', async () => {
147
+ await expect(enforceProfileUsage(mockProjectConfig, null)).resolves.toBeUndefined();
148
+ });
149
+ });
150
+ describe('loadAndValidateProfile()', () => {
151
+ const mockProjectConfig = {
152
+ srcDir: 'src',
153
+ name: 'test-project',
154
+ platformVersion: '1.0.0',
155
+ };
156
+ const mockProjectDir = '/test/project';
157
+ const mockProfileName = 'test-profile';
158
+ const mockProfile = {
159
+ accountId: 123,
160
+ variables: {
161
+ key1: 'value1',
162
+ key2: 'value2',
163
+ },
164
+ };
165
+ it('should enforce profile usage when no profile name provided', async () => {
166
+ mockedGetAllHsProfiles.mockResolvedValue([]);
167
+ const result = await loadAndValidateProfile(mockProjectConfig, mockProjectDir, undefined);
168
+ expect(result).toBeUndefined();
169
+ expect(mockedGetAllHsProfiles).toHaveBeenCalledWith(path.join(mockProjectDir, mockProjectConfig.srcDir));
170
+ });
171
+ it('should throw when profiles exist but no profile name provided', async () => {
172
+ mockedGetAllHsProfiles.mockResolvedValue(['profile1']);
173
+ await expect(loadAndValidateProfile(mockProjectConfig, mockProjectDir, undefined)).rejects.toThrow(lib.projectProfiles.exitIfUsingProfiles.errors.noProfileSpecified);
174
+ });
175
+ it('should load and return account ID when profile is valid', async () => {
176
+ mockedLoadHsProfileFile.mockReturnValue(mockProfile);
177
+ mockedGetConfigAccountById.mockReturnValue({
178
+ accountId: mockProfile.accountId,
179
+ });
180
+ mockedGetHsProfileFilename.mockReturnValue('test-profile.hsprofile');
181
+ mockedValidateProfileVariables.mockReturnValue({ success: true });
182
+ const result = await loadAndValidateProfile(mockProjectConfig, mockProjectDir, mockProfileName);
183
+ expect(result).toBe(mockProfile.accountId);
184
+ expect(mockedLoadHsProfileFile).toHaveBeenCalledWith(path.join(mockProjectDir, mockProjectConfig.srcDir), mockProfileName);
185
+ expect(mockedValidateProfileVariables).toHaveBeenCalledWith(mockProfile.variables, mockProfileName);
186
+ });
187
+ it('should log profile header and footer when not silent', async () => {
188
+ mockedLoadHsProfileFile.mockReturnValue(mockProfile);
189
+ mockedGetConfigAccountById.mockReturnValue({
190
+ accountId: mockProfile.accountId,
191
+ });
192
+ mockedGetHsProfileFilename.mockReturnValue('test-profile.hsprofile');
193
+ mockedValidateProfileVariables.mockReturnValue({ success: true });
194
+ await loadAndValidateProfile(mockProjectConfig, mockProjectDir, mockProfileName, false);
195
+ expect(mockedUiBetaTag).toHaveBeenCalled();
196
+ expect(mockedUiLine).toHaveBeenCalled();
197
+ expect(mockedUiLogger.log).toHaveBeenCalled();
198
+ });
199
+ it('should not log when silent is true', async () => {
200
+ mockedLoadHsProfileFile.mockReturnValue(mockProfile);
201
+ mockedGetConfigAccountById.mockReturnValue({
202
+ accountId: mockProfile.accountId,
203
+ });
204
+ mockedValidateProfileVariables.mockReturnValue({ success: true });
205
+ await loadAndValidateProfile(mockProjectConfig, mockProjectDir, mockProfileName, true);
206
+ expect(mockedUiBetaTag).not.toHaveBeenCalled();
207
+ expect(mockedUiLine).not.toHaveBeenCalled();
208
+ });
209
+ it('should throw error when profile variables are invalid', async () => {
210
+ const invalidProfile = {
211
+ accountId: 123,
212
+ variables: {
213
+ invalid: 'value',
214
+ },
215
+ };
216
+ const validationErrors = ['Variable "invalid" is not allowed'];
217
+ mockedLoadHsProfileFile.mockReturnValue(invalidProfile);
218
+ mockedGetConfigAccountById.mockReturnValue({
219
+ accountId: invalidProfile.accountId,
220
+ });
221
+ mockedGetHsProfileFilename.mockReturnValue('test-profile.hsprofile');
222
+ mockedValidateProfileVariables.mockReturnValue({
223
+ success: false,
224
+ errors: validationErrors,
225
+ });
226
+ await expect(loadAndValidateProfile(mockProjectConfig, mockProjectDir, mockProfileName)).rejects.toThrow(lib.projectProfiles.loadProfile.errors.profileNotValid('test-profile.hsprofile', validationErrors));
227
+ });
228
+ it('should not validate when profile has no variables', async () => {
229
+ const profileWithoutVars = {
230
+ accountId: 123,
231
+ };
232
+ mockedLoadHsProfileFile.mockReturnValue(profileWithoutVars);
233
+ mockedGetConfigAccountById.mockReturnValue({
234
+ accountId: profileWithoutVars.accountId,
235
+ });
236
+ mockedGetHsProfileFilename.mockReturnValue('test-profile.hsprofile');
237
+ const result = await loadAndValidateProfile(mockProjectConfig, mockProjectDir, mockProfileName);
238
+ expect(result).toBe(profileWithoutVars.accountId);
239
+ expect(mockedValidateProfileVariables).not.toHaveBeenCalled();
240
+ });
241
+ });
242
+ describe('validateProjectForProfile()', () => {
243
+ const mockProjectConfig = {
244
+ srcDir: 'src',
245
+ name: 'test-project',
246
+ platformVersion: '2025.2',
247
+ };
248
+ const mockProjectDir = '/test/project';
249
+ const mockProfileName = 'test-profile';
250
+ const mockDerivedAccountId = 123;
251
+ const mockProfileFilename = 'test-profile.hsprofile';
252
+ const mockProfile = {
253
+ accountId: mockDerivedAccountId,
254
+ };
255
+ beforeEach(() => {
256
+ mockedGetHsProfileFilename.mockReturnValue(mockProfileFilename);
257
+ vi.mocked(SpinniesManager.init);
258
+ vi.mocked(SpinniesManager.add);
259
+ vi.mocked(SpinniesManager.succeed);
260
+ vi.mocked(SpinniesManager.fail);
261
+ // Mock dependencies for loadAndValidateProfile
262
+ mockedGetAllHsProfiles.mockResolvedValue([]);
263
+ mockedLoadHsProfileFile.mockReturnValue(mockProfile);
264
+ mockedGetConfigAccountById.mockReturnValue({
265
+ accountId: mockDerivedAccountId,
266
+ });
267
+ mockedValidateProfileVariables.mockReturnValue({ success: true });
268
+ vi.mocked(handleTranslate).mockResolvedValue(undefined);
269
+ });
270
+ it('should return empty array when validation succeeds', async () => {
271
+ const result = await validateProjectForProfile({
272
+ projectConfig: mockProjectConfig,
273
+ projectDir: mockProjectDir,
274
+ profileName: mockProfileName,
275
+ derivedAccountId: mockDerivedAccountId,
276
+ });
277
+ expect(result).toEqual([]);
278
+ expect(SpinniesManager.add).toHaveBeenCalledWith(`validatingProfile-${mockProfileName}`, {
279
+ text: commands.project.validate.spinners.validatingProfile(mockProfileFilename),
280
+ indent: 0,
281
+ });
282
+ expect(SpinniesManager.succeed).toHaveBeenCalledWith(`validatingProfile-${mockProfileName}`, {
283
+ text: commands.project.validate.spinners.profileValidationSucceeded(mockProfileFilename),
284
+ succeedColor: 'white',
285
+ });
286
+ });
287
+ it('should call handleTranslate with profile account ID from profile', async () => {
288
+ await validateProjectForProfile({
289
+ projectConfig: mockProjectConfig,
290
+ projectDir: mockProjectDir,
291
+ profileName: mockProfileName,
292
+ derivedAccountId: mockDerivedAccountId,
293
+ });
294
+ expect(handleTranslate).toHaveBeenCalledWith({
295
+ projectDir: mockProjectDir,
296
+ projectConfig: mockProjectConfig,
297
+ accountId: mockDerivedAccountId,
298
+ skipValidation: false,
299
+ profile: mockProfileName,
300
+ includeTranslationErrorMessage: false,
301
+ });
302
+ });
303
+ it('should call handleTranslate with different profile account ID when profile has different ID', async () => {
304
+ const profileAccountId = 456;
305
+ const profileWithDifferentId = {
306
+ accountId: profileAccountId,
307
+ };
308
+ mockedLoadHsProfileFile.mockReturnValue(profileWithDifferentId);
309
+ mockedGetConfigAccountById.mockReturnValue({
310
+ accountId: profileAccountId,
311
+ });
312
+ await validateProjectForProfile({
313
+ projectConfig: mockProjectConfig,
314
+ projectDir: mockProjectDir,
315
+ profileName: mockProfileName,
316
+ derivedAccountId: mockDerivedAccountId,
317
+ });
318
+ expect(handleTranslate).toHaveBeenCalledWith({
319
+ projectDir: mockProjectDir,
320
+ projectConfig: mockProjectConfig,
321
+ accountId: profileAccountId,
322
+ skipValidation: false,
323
+ profile: mockProfileName,
324
+ includeTranslationErrorMessage: false,
325
+ });
326
+ });
327
+ it('should return error when profile has no accountId', async () => {
328
+ // @ts-expect-error causing an error on purpose
329
+ const profileWithoutId = {};
330
+ mockedLoadHsProfileFile.mockReturnValue(profileWithoutId);
331
+ const result = await validateProjectForProfile({
332
+ projectConfig: mockProjectConfig,
333
+ projectDir: mockProjectDir,
334
+ profileName: mockProfileName,
335
+ derivedAccountId: mockDerivedAccountId,
336
+ });
337
+ expect(result.length).toBeGreaterThan(0);
338
+ expect(SpinniesManager.fail).toHaveBeenCalled();
339
+ expect(handleTranslate).not.toHaveBeenCalled();
340
+ });
341
+ it('should indent spinners when indentSpinners is true', async () => {
342
+ await validateProjectForProfile({
343
+ projectConfig: mockProjectConfig,
344
+ projectDir: mockProjectDir,
345
+ profileName: mockProfileName,
346
+ derivedAccountId: mockDerivedAccountId,
347
+ indentSpinners: true,
348
+ });
349
+ expect(SpinniesManager.add).toHaveBeenCalledWith(`validatingProfile-${mockProfileName}`, {
350
+ text: commands.project.validate.spinners.validatingProfile(mockProfileFilename),
351
+ indent: 2,
352
+ });
353
+ });
354
+ it('should not indent spinners when indentSpinners is false', async () => {
355
+ await validateProjectForProfile({
356
+ projectConfig: mockProjectConfig,
357
+ projectDir: mockProjectDir,
358
+ profileName: mockProfileName,
359
+ derivedAccountId: mockDerivedAccountId,
360
+ indentSpinners: false,
361
+ });
362
+ expect(SpinniesManager.add).toHaveBeenCalledWith(`validatingProfile-${mockProfileName}`, {
363
+ text: commands.project.validate.spinners.validatingProfile(mockProfileFilename),
364
+ indent: 0,
365
+ });
366
+ });
367
+ it('should return error array when profile loading fails', async () => {
368
+ mockedLoadHsProfileFile.mockReturnValue(null);
369
+ const result = await validateProjectForProfile({
370
+ projectConfig: mockProjectConfig,
371
+ projectDir: mockProjectDir,
372
+ profileName: mockProfileName,
373
+ derivedAccountId: mockDerivedAccountId,
374
+ });
375
+ expect(result.length).toBeGreaterThan(0);
376
+ expect(SpinniesManager.fail).toHaveBeenCalledWith(`validatingProfile-${mockProfileName}`, {
377
+ text: commands.project.validate.spinners.profileValidationFailed(mockProfileFilename),
378
+ failColor: 'white',
379
+ });
380
+ expect(handleTranslate).not.toHaveBeenCalled();
381
+ });
382
+ it('should return error when profile file loading throws', async () => {
383
+ mockedLoadHsProfileFile.mockImplementation(() => {
384
+ throw new Error('Failed to load profile file');
385
+ });
386
+ const result = await validateProjectForProfile({
387
+ projectConfig: mockProjectConfig,
388
+ projectDir: mockProjectDir,
389
+ profileName: mockProfileName,
390
+ derivedAccountId: mockDerivedAccountId,
391
+ });
392
+ expect(result.length).toBeGreaterThan(0);
393
+ expect(SpinniesManager.fail).toHaveBeenCalledWith(`validatingProfile-${mockProfileName}`, {
394
+ text: commands.project.validate.spinners.profileValidationFailed(mockProfileFilename),
395
+ failColor: 'white',
396
+ });
397
+ expect(handleTranslate).not.toHaveBeenCalled();
398
+ });
399
+ it('should return error array when translation fails', async () => {
400
+ const error = new Error('Translation failed');
401
+ vi.mocked(handleTranslate).mockRejectedValue(error);
402
+ const result = await validateProjectForProfile({
403
+ projectConfig: mockProjectConfig,
404
+ projectDir: mockProjectDir,
405
+ profileName: mockProfileName,
406
+ derivedAccountId: mockDerivedAccountId,
407
+ });
408
+ expect(result).toHaveLength(2);
409
+ expect(result[0]).toBe(commands.project.validate.failureWithProfile(mockProfileName));
410
+ expect(result[1]).toBe(` ${error.message}\n`);
411
+ expect(SpinniesManager.fail).toHaveBeenCalledWith(`validatingProfile-${mockProfileName}`, {
412
+ text: commands.project.validate.spinners.invalidWithProfile(mockProfileName),
413
+ failColor: 'white',
414
+ });
415
+ });
416
+ it('should return string error when translation fails with non-Error', async () => {
417
+ const error = 'Translation error';
418
+ vi.mocked(handleTranslate).mockRejectedValue(error);
419
+ const result = await validateProjectForProfile({
420
+ projectConfig: mockProjectConfig,
421
+ projectDir: mockProjectDir,
422
+ profileName: mockProfileName,
423
+ derivedAccountId: mockDerivedAccountId,
424
+ });
425
+ expect(result).toHaveLength(2);
426
+ expect(result[0]).toBe(commands.project.validate.failureWithProfile(mockProfileName));
427
+ expect(result[1]).toBe(` ${error}\n`);
428
+ });
429
+ it('should use correct spinner name based on profile name', async () => {
430
+ const customProfileName = 'custom-profile';
431
+ await validateProjectForProfile({
432
+ projectConfig: mockProjectConfig,
433
+ projectDir: mockProjectDir,
434
+ profileName: customProfileName,
435
+ derivedAccountId: mockDerivedAccountId,
436
+ });
437
+ expect(SpinniesManager.add).toHaveBeenCalledWith(`validatingProfile-${customProfileName}`, expect.any(Object));
438
+ expect(SpinniesManager.succeed).toHaveBeenCalledWith(`validatingProfile-${customProfileName}`, expect.any(Object));
439
+ });
440
+ });
441
+ });
@@ -3,7 +3,6 @@ import os from 'os';
3
3
  import path from 'path';
4
4
  import { validateProjectConfig } from '../../projects/config.js';
5
5
  import ProjectValidationError from '../../errors/ProjectValidationError.js';
6
- vi.mock('../../ui/logger.js');
7
6
  describe('lib/projects', () => {
8
7
  describe('validateProjectConfig()', () => {
9
8
  let projectDir;
@@ -5,7 +5,6 @@ import { getComponentTypeFromConfigFile, loadConfigFile, getAppCardConfigs, getI
5
5
  import { ComponentTypes } from '../../../types/Projects.js';
6
6
  vi.mock('fs');
7
7
  vi.mock('@hubspot/local-dev-lib/fs');
8
- vi.mock('../../ui/logger.js');
9
8
  const mockedReadFileSync = fs.readFileSync;
10
9
  const mockedWalk = HSfs.walk;
11
10
  const getMockPrivateAppConfig = (cards = []) => ({
@@ -4,7 +4,7 @@ import util from 'util';
4
4
  import { uiLogger } from '../../ui/logger.js';
5
5
  import * as dependencyManagement from '../../dependencyManagement.js';
6
6
  import { isEslintInstalled, areAllLintPackagesInstalled, getMissingLintPackages, lintPackages, lintPackagesInDirectory, displayLintResults, hasEslintConfig, hasDeprecatedEslintConfig, getDeprecatedEslintConfigFiles, createEslintConfig, } from '../uieLinting.js';
7
- vi.mock('../../ui/logger.js');
7
+ import { clearPackageJsonCache } from '../../npm/packageJson.js';
8
8
  vi.mock('fs');
9
9
  vi.mock('../../dependencyManagement.js', async () => {
10
10
  const actual = await vi.importActual('../../dependencyManagement.js');
@@ -23,7 +23,7 @@ const mockExec = vi.fn();
23
23
  vi.mocked(util.promisify).mockReturnValue(mockExec);
24
24
  describe('lib/linting', () => {
25
25
  afterEach(() => {
26
- vi.clearAllMocks();
26
+ clearPackageJsonCache();
27
27
  });
28
28
  describe('isEslintInstalled', () => {
29
29
  it('should return true if eslint is in package.json and node_modules', () => {
@@ -84,9 +84,6 @@ describe('lib/linting', () => {
84
84
  });
85
85
  });
86
86
  describe('areAllLintPackagesInstalled', () => {
87
- beforeEach(() => {
88
- vi.clearAllMocks();
89
- });
90
87
  it('should return true if all packages are installed', () => {
91
88
  const directory = '/test/project/component1';
92
89
  const packageJson = JSON.stringify({
@@ -183,9 +180,6 @@ describe('lib/linting', () => {
183
180
  });
184
181
  });
185
182
  describe('getMissingLintPackages', () => {
186
- beforeEach(() => {
187
- vi.clearAllMocks();
188
- });
189
183
  it('should return empty array if all packages are installed with correct versions', () => {
190
184
  const directory = '/test/project/component1';
191
185
  const packageJson = JSON.stringify({
@@ -442,9 +436,6 @@ describe('lib/linting', () => {
442
436
  });
443
437
  describe('createEslintConfig', () => {
444
438
  const writeFileSyncSpy = vi.spyOn(fs, 'writeFileSync');
445
- afterEach(() => {
446
- vi.clearAllMocks();
447
- });
448
439
  it('should create eslint.config.mts with template content', () => {
449
440
  const directory = '/test/project/component1';
450
441
  const result = createEslintConfig(directory);
@@ -1,17 +1,38 @@
1
1
  import fs from 'fs-extra';
2
2
  import os from 'os';
3
3
  import path from 'path';
4
+ import archiver from 'archiver';
5
+ import tmp from 'tmp';
4
6
  import { vi } from 'vitest';
5
- import { validateSourceDirectory } from '../upload.js';
7
+ import { validateSourceDirectory, handleProjectUpload } from '../upload.js';
6
8
  import { uiLogger } from '../../ui/logger.js';
7
9
  import { lib } from '../../../lang/en.js';
8
10
  import { isV2Project } from '../platformVersion.js';
9
11
  import ProjectValidationError from '../../errors/ProjectValidationError.js';
10
12
  import { walk } from '@hubspot/local-dev-lib/fs';
13
+ import { uploadProject } from '@hubspot/local-dev-lib/api/projects';
14
+ import { ensureProjectExists } from '../ensureProjectExists.js';
15
+ import { projectContainsHsMetaFiles } from '@hubspot/project-parsing-lib/projects';
16
+ import { shouldIgnoreFile } from '@hubspot/local-dev-lib/ignoreRules';
17
+ import { getConfigAccountIfExists } from '@hubspot/local-dev-lib/config';
11
18
  // Mock dependencies
12
- vi.mock('../../ui/logger.js');
19
+ vi.mock('../../ui/SpinniesManager');
13
20
  vi.mock('../platformVersion.js');
14
21
  vi.mock('@hubspot/local-dev-lib/fs');
22
+ vi.mock('@hubspot/local-dev-lib/api/projects');
23
+ vi.mock('../ensureProjectExists.js');
24
+ vi.mock('@hubspot/project-parsing-lib/projects');
25
+ vi.mock('@hubspot/local-dev-lib/ignoreRules');
26
+ vi.mock('@hubspot/local-dev-lib/config');
27
+ vi.mock('archiver');
28
+ vi.mock('tmp');
29
+ vi.mock('fs-extra', async () => {
30
+ const actual = await vi.importActual('fs-extra');
31
+ return {
32
+ ...actual,
33
+ createWriteStream: vi.fn(),
34
+ };
35
+ });
15
36
  describe('lib/projects/upload', () => {
16
37
  describe('validateSourceDirectory', () => {
17
38
  let tempDir;
@@ -26,7 +47,8 @@ describe('lib/projects/upload', () => {
26
47
  srcDir: 'src',
27
48
  platformVersion: '2025.2',
28
49
  };
29
- vi.clearAllMocks();
50
+ // Mock config to prevent reading actual config file
51
+ vi.mocked(getConfigAccountIfExists).mockReturnValue(undefined);
30
52
  });
31
53
  afterEach(() => {
32
54
  fs.removeSync(tempDir);
@@ -79,4 +101,83 @@ describe('lib/projects/upload', () => {
79
101
  expect(uiLogger.warn).not.toHaveBeenCalled();
80
102
  });
81
103
  });
104
+ describe('handleProjectUpload', () => {
105
+ let tempDir;
106
+ let projectConfig;
107
+ let mockWriteStream;
108
+ let mockArchive;
109
+ beforeEach(() => {
110
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'upload-test-'));
111
+ const srcDir = path.join(tempDir, 'src');
112
+ fs.mkdirSync(srcDir, { recursive: true });
113
+ fs.writeFileSync(path.join(srcDir, 'test.js'), 'test content');
114
+ projectConfig = {
115
+ name: 'test-project',
116
+ srcDir: 'src',
117
+ platformVersion: '2025.2',
118
+ };
119
+ // Mock config to prevent reading actual config file
120
+ vi.mocked(getConfigAccountIfExists).mockReturnValue(undefined);
121
+ vi.mocked(walk).mockResolvedValue([path.join(srcDir, 'test.js')]);
122
+ vi.mocked(shouldIgnoreFile).mockReturnValue(false);
123
+ vi.mocked(projectContainsHsMetaFiles).mockResolvedValue(false);
124
+ vi.mocked(isV2Project).mockReturnValue(false);
125
+ vi.mocked(tmp.fileSync).mockReturnValue({
126
+ name: path.join(tempDir, 'test.zip'),
127
+ fd: 1,
128
+ removeCallback: vi.fn(),
129
+ });
130
+ // Store close callback so archive.finalize() can trigger it
131
+ let closeCallback;
132
+ mockWriteStream = {
133
+ on: vi.fn((event, callback) => {
134
+ if (event === 'close') {
135
+ closeCallback = callback;
136
+ }
137
+ }),
138
+ };
139
+ vi.spyOn(fs, 'createWriteStream').mockReturnValue(mockWriteStream);
140
+ mockArchive = {
141
+ pipe: vi.fn(),
142
+ directory: vi.fn(),
143
+ finalize: vi.fn(() => {
144
+ // Trigger the close event when finalize is called
145
+ if (closeCallback) {
146
+ process.nextTick(closeCallback);
147
+ }
148
+ }),
149
+ pointer: vi.fn().mockReturnValue(100),
150
+ on: vi.fn(),
151
+ };
152
+ vi.mocked(archiver).mockReturnValue(mockArchive);
153
+ });
154
+ afterEach(() => {
155
+ fs.removeSync(tempDir);
156
+ });
157
+ it('should upload project files and call callback when project exists', async () => {
158
+ const accountId = 123;
159
+ const buildId = 456;
160
+ const callbackResult = { success: true };
161
+ const callbackFunc = vi.fn().mockResolvedValue(callbackResult);
162
+ vi.mocked(ensureProjectExists).mockResolvedValue({
163
+ projectExists: true,
164
+ });
165
+ vi.mocked(uploadProject).mockResolvedValue({
166
+ data: { buildId },
167
+ });
168
+ const uploadPromise = handleProjectUpload({
169
+ accountId,
170
+ projectConfig,
171
+ projectDir: tempDir,
172
+ callbackFunc,
173
+ isUploadCommand: true,
174
+ });
175
+ // Trigger the close event by calling finalize
176
+ mockArchive.finalize();
177
+ const result = await uploadPromise;
178
+ expect(uploadProject).toHaveBeenCalled();
179
+ expect(callbackFunc).toHaveBeenCalled();
180
+ expect(result.result).toEqual(callbackResult);
181
+ });
182
+ });
82
183
  });
@@ -10,9 +10,7 @@ import { commands } from '../../../../lang/en.js';
10
10
  vi.mock('../../structure');
11
11
  vi.mock('../../create/legacy');
12
12
  vi.mock('../../../prompts/projectAddPrompt');
13
- vi.mock('../../../ui/logger.js');
14
13
  vi.mock('@hubspot/local-dev-lib/github');
15
- vi.mock('../../../usageTracking.js');
16
14
  const mockedFindProjectComponents = vi.mocked(findProjectComponents);
17
15
  const mockedGetProjectComponentListFromRepo = vi.mocked(getProjectComponentListFromRepo);
18
16
  const mockedProjectAddPrompt = vi.mocked(projectAddPrompt);
@@ -5,7 +5,7 @@ import { createV2App } from '../../create/v2.js';
5
5
  import { confirmPrompt } from '../../../prompts/promptUtils.js';
6
6
  import { projectAddPromptV2 } from '../../../prompts/projectAddPrompt.js';
7
7
  import { cloneGithubRepo } from '@hubspot/local-dev-lib/github';
8
- import { getProjectMetadata } from '@hubspot/project-parsing-lib/src/lib/project.js';
8
+ import { getProjectMetadata } from '@hubspot/project-parsing-lib/projects';
9
9
  import { trackCommandUsage } from '../../../usageTracking.js';
10
10
  import { updateHsMetaFilesWithAutoGeneratedFields } from '../../components.js';
11
11
  import { commands } from '../../../../lang/en.js';
@@ -15,10 +15,8 @@ vi.mock('../../create/legacy');
15
15
  vi.mock('../../create/v2');
16
16
  vi.mock('../../../prompts/projectAddPrompt');
17
17
  vi.mock('@hubspot/local-dev-lib/github');
18
- vi.mock('../../../ui/logger.js');
19
18
  vi.mock('../../../ui/SpinniesManager.js');
20
- vi.mock('@hubspot/project-parsing-lib/src/lib/project');
21
- vi.mock('../../../usageTracking');
19
+ vi.mock('@hubspot/project-parsing-lib/projects');
22
20
  vi.mock('../../components.js');
23
21
  const mockedFs = vi.mocked(fs);
24
22
  const mockedGetConfigForPlatformVersion = vi.mocked(getConfigForPlatformVersion);