@hubspot/cli 7.7.27-experimental.2 → 7.7.28-experimental.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/README.md +0 -4
- package/api/__tests__/migrate.test.js +5 -5
- package/api/migrate.d.ts +10 -4
- package/api/migrate.js +2 -2
- package/commands/__tests__/create.test.js +20 -0
- package/commands/__tests__/testAccount.test.js +2 -0
- package/commands/app/__tests__/migrate.test.js +1 -0
- package/commands/create/function.js +2 -2
- package/commands/create/module.js +2 -2
- package/commands/create/template.js +2 -2
- package/commands/create.js +47 -0
- package/commands/getStarted.js +66 -4
- package/commands/mcp/setup.d.ts +0 -1
- package/commands/mcp/setup.js +3 -11
- package/commands/project/__tests__/create.test.js +57 -0
- package/commands/project/__tests__/devUnifiedFlow.test.js +18 -30
- package/commands/project/create.js +6 -1
- package/commands/project/deploy.js +31 -1
- package/commands/project/dev/deprecatedFlow.js +2 -1
- package/commands/project/dev/index.js +32 -12
- package/commands/project/dev/unifiedFlow.d.ts +1 -1
- package/commands/project/dev/unifiedFlow.js +10 -16
- package/commands/project/profile/delete.js +26 -14
- package/commands/project/upload.d.ts +2 -2
- package/commands/project/upload.js +1 -1
- package/commands/testAccount/__tests__/importData.test.d.ts +1 -0
- package/commands/testAccount/__tests__/importData.test.js +93 -0
- package/commands/testAccount/create.js +23 -13
- package/commands/testAccount/importData.d.ts +9 -0
- package/commands/testAccount/importData.js +61 -0
- package/commands/testAccount.js +2 -0
- package/lang/en.d.ts +160 -46
- package/lang/en.js +175 -59
- package/lang/en.lyaml +35 -14
- package/lib/__tests__/importData.test.d.ts +1 -0
- package/lib/__tests__/importData.test.js +89 -0
- package/lib/accountTypes.js +2 -3
- package/lib/app/__tests__/migrate.test.js +81 -36
- package/lib/app/migrate.d.ts +17 -4
- package/lib/app/migrate.js +97 -19
- package/lib/constants.d.ts +1 -0
- package/lib/constants.js +1 -0
- package/lib/hasFeature.d.ts +1 -0
- package/lib/hasFeature.js +7 -0
- package/lib/importData.d.ts +3 -0
- package/lib/importData.js +50 -0
- package/lib/mcp/setup.d.ts +0 -2
- package/lib/mcp/setup.js +0 -24
- package/lib/process.js +15 -4
- package/lib/projectProfiles.d.ts +1 -1
- package/lib/projectProfiles.js +10 -2
- package/lib/projects/__tests__/AppDevModeInterface.test.js +3 -3
- package/lib/projects/__tests__/LocalDevProcess.test.js +5 -95
- package/lib/projects/__tests__/LocalDevWebsocketServer.test.js +6 -6
- package/lib/projects/__tests__/components.test.js +164 -7
- package/lib/projects/__tests__/localDevProjectHelpers.test.d.ts +1 -0
- package/lib/projects/__tests__/localDevProjectHelpers.test.js +118 -0
- package/lib/projects/add/v3AddComponent.js +16 -4
- package/lib/projects/components.d.ts +1 -0
- package/lib/projects/components.js +27 -1
- package/lib/projects/localDev/AppDevModeInterface.js +35 -3
- package/lib/projects/localDev/LocalDevLogger.d.ts +0 -4
- package/lib/projects/localDev/LocalDevLogger.js +2 -19
- package/lib/projects/localDev/LocalDevManager.js +1 -1
- package/lib/projects/localDev/LocalDevProcess.d.ts +1 -2
- package/lib/projects/localDev/LocalDevProcess.js +3 -26
- package/lib/projects/localDev/LocalDevState.d.ts +6 -7
- package/lib/projects/localDev/LocalDevState.js +16 -15
- package/lib/projects/localDev/LocalDevWebsocketServer.d.ts +1 -0
- package/lib/projects/localDev/LocalDevWebsocketServer.js +17 -2
- package/lib/projects/localDev/{helpers.d.ts → helpers/account.d.ts} +1 -7
- package/lib/projects/localDev/{helpers.js → helpers/account.js} +44 -144
- package/lib/projects/localDev/helpers/project.d.ts +12 -0
- package/lib/projects/localDev/helpers/project.js +173 -0
- package/lib/projects/urls.d.ts +1 -0
- package/lib/projects/urls.js +4 -0
- package/lib/prompts/__tests__/createFunctionPrompt.test.d.ts +1 -0
- package/lib/prompts/__tests__/createFunctionPrompt.test.js +129 -0
- package/lib/prompts/__tests__/createModulePrompt.test.d.ts +1 -0
- package/lib/prompts/__tests__/createModulePrompt.test.js +187 -0
- package/lib/prompts/__tests__/createTemplatePrompt.test.d.ts +1 -0
- package/lib/prompts/__tests__/createTemplatePrompt.test.js +102 -0
- package/lib/prompts/confirmImportDataPrompt.d.ts +1 -0
- package/lib/prompts/confirmImportDataPrompt.js +12 -0
- package/lib/prompts/createFunctionPrompt.d.ts +2 -1
- package/lib/prompts/createFunctionPrompt.js +36 -7
- package/lib/prompts/createModulePrompt.d.ts +2 -1
- package/lib/prompts/createModulePrompt.js +48 -1
- package/lib/prompts/createTemplatePrompt.d.ts +3 -24
- package/lib/prompts/createTemplatePrompt.js +9 -1
- package/lib/prompts/importDataFilePathPrompt.d.ts +1 -0
- package/lib/prompts/importDataFilePathPrompt.js +24 -0
- package/lib/prompts/importDataTestAccountSelectPrompt.d.ts +3 -0
- package/lib/prompts/importDataTestAccountSelectPrompt.js +29 -0
- package/lib/prompts/projectDevTargetAccountPrompt.js +1 -0
- package/lib/prompts/promptUtils.d.ts +7 -1
- package/lib/prompts/promptUtils.js +14 -1
- package/lib/ui/__tests__/removeAnsiCodes.test.d.ts +1 -0
- package/lib/ui/__tests__/removeAnsiCodes.test.js +84 -0
- package/lib/ui/index.js +3 -6
- package/lib/ui/removeAnsiCodes.d.ts +1 -0
- package/lib/ui/removeAnsiCodes.js +4 -0
- package/mcp-server/server.js +2 -1
- package/mcp-server/tools/cms/HsListTool.d.ts +23 -0
- package/mcp-server/tools/cms/HsListTool.js +58 -0
- package/mcp-server/tools/cms/__tests__/HsListTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsListTool.test.js +120 -0
- package/mcp-server/tools/index.d.ts +1 -0
- package/mcp-server/tools/index.js +8 -0
- package/mcp-server/tools/project/DocFetchTool.d.ts +17 -0
- package/mcp-server/tools/project/DocFetchTool.js +49 -0
- package/mcp-server/tools/project/DocsSearchTool.d.ts +26 -0
- package/mcp-server/tools/project/DocsSearchTool.js +62 -0
- package/mcp-server/tools/project/GetConfigValuesTool.js +3 -2
- package/mcp-server/tools/project/__tests__/DocFetchTool.test.d.ts +1 -0
- package/mcp-server/tools/project/__tests__/DocFetchTool.test.js +117 -0
- package/mcp-server/tools/project/__tests__/DocsSearchTool.test.d.ts +1 -0
- package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +190 -0
- package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +1 -1
- package/mcp-server/tools/project/constants.d.ts +2 -0
- package/mcp-server/tools/project/constants.js +6 -0
- package/mcp-server/utils/toolUsageTracking.d.ts +3 -1
- package/mcp-server/utils/toolUsageTracking.js +2 -1
- package/package.json +9 -6
- package/types/Cms.d.ts +16 -0
- package/types/Cms.js +25 -1
- package/types/LocalDev.d.ts +0 -3
- package/types/Prompts.d.ts +1 -0
- package/types/Yargs.d.ts +1 -1
- package/ui/index.d.ts +1 -0
- package/ui/index.js +6 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { createModulePrompt } from '../createModulePrompt.js';
|
|
3
|
+
import { promptUser } from '../promptUtils.js';
|
|
4
|
+
vi.mock('../promptUtils.js');
|
|
5
|
+
const mockPromptUser = vi.mocked(promptUser);
|
|
6
|
+
describe('createModulePrompt', () => {
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
vi.resetAllMocks();
|
|
9
|
+
});
|
|
10
|
+
describe('when all parameters are provided', () => {
|
|
11
|
+
it('should return provided values without prompting', async () => {
|
|
12
|
+
const commandArgs = {
|
|
13
|
+
moduleLabel: 'My Module',
|
|
14
|
+
reactType: true,
|
|
15
|
+
contentTypes: 'LANDING_PAGE,SITE_PAGE',
|
|
16
|
+
global: false,
|
|
17
|
+
availableForNewContent: true,
|
|
18
|
+
};
|
|
19
|
+
const result = await createModulePrompt(commandArgs);
|
|
20
|
+
expect(mockPromptUser).not.toHaveBeenCalled();
|
|
21
|
+
expect(result).toEqual({
|
|
22
|
+
moduleLabel: 'My Module',
|
|
23
|
+
reactType: true,
|
|
24
|
+
contentTypes: ['LANDING_PAGE', 'SITE_PAGE'],
|
|
25
|
+
global: false,
|
|
26
|
+
availableForNewContent: true,
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
it('should use default values when optional parameters not provided', async () => {
|
|
30
|
+
const commandArgs = {
|
|
31
|
+
moduleLabel: 'My Module',
|
|
32
|
+
};
|
|
33
|
+
mockPromptUser.mockResolvedValue({
|
|
34
|
+
reactType: false,
|
|
35
|
+
contentTypes: ['ANY'],
|
|
36
|
+
global: false,
|
|
37
|
+
availableForNewContent: true,
|
|
38
|
+
});
|
|
39
|
+
const result = await createModulePrompt(commandArgs);
|
|
40
|
+
expect(mockPromptUser).toHaveBeenCalledWith([
|
|
41
|
+
expect.objectContaining({ name: 'reactType' }),
|
|
42
|
+
expect.objectContaining({ name: 'contentTypes' }),
|
|
43
|
+
expect.objectContaining({ name: 'global' }),
|
|
44
|
+
expect.objectContaining({ name: 'availableForNewContent' }),
|
|
45
|
+
]);
|
|
46
|
+
expect(result).toEqual({
|
|
47
|
+
moduleLabel: 'My Module',
|
|
48
|
+
reactType: false,
|
|
49
|
+
contentTypes: ['ANY'],
|
|
50
|
+
global: false,
|
|
51
|
+
availableForNewContent: true,
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
it('should parse contentTypes string correctly', async () => {
|
|
55
|
+
const commandArgs = {
|
|
56
|
+
moduleLabel: 'Test Module',
|
|
57
|
+
contentTypes: 'BLOG_POST, EMAIL, LANDING_PAGE',
|
|
58
|
+
};
|
|
59
|
+
mockPromptUser.mockResolvedValue({
|
|
60
|
+
reactType: false,
|
|
61
|
+
global: false,
|
|
62
|
+
availableForNewContent: true,
|
|
63
|
+
});
|
|
64
|
+
const result = await createModulePrompt(commandArgs);
|
|
65
|
+
expect(result.contentTypes).toEqual([
|
|
66
|
+
'BLOG_POST',
|
|
67
|
+
'EMAIL',
|
|
68
|
+
'LANDING_PAGE',
|
|
69
|
+
]);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
describe('when some parameters are missing', () => {
|
|
73
|
+
it('should only prompt for missing parameters', async () => {
|
|
74
|
+
const commandArgs = {
|
|
75
|
+
moduleLabel: 'My Module',
|
|
76
|
+
reactType: true,
|
|
77
|
+
};
|
|
78
|
+
mockPromptUser.mockResolvedValue({
|
|
79
|
+
contentTypes: ['SITE_PAGE'],
|
|
80
|
+
global: true,
|
|
81
|
+
availableForNewContent: false,
|
|
82
|
+
});
|
|
83
|
+
const result = await createModulePrompt(commandArgs);
|
|
84
|
+
expect(mockPromptUser).toHaveBeenCalledWith([
|
|
85
|
+
expect.objectContaining({ name: 'contentTypes' }),
|
|
86
|
+
expect.objectContaining({ name: 'global' }),
|
|
87
|
+
expect.objectContaining({ name: 'availableForNewContent' }),
|
|
88
|
+
]);
|
|
89
|
+
expect(result).toEqual({
|
|
90
|
+
moduleLabel: 'My Module',
|
|
91
|
+
reactType: true,
|
|
92
|
+
contentTypes: ['SITE_PAGE'],
|
|
93
|
+
global: true,
|
|
94
|
+
availableForNewContent: false,
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe('when no parameters are provided', () => {
|
|
99
|
+
it('should prompt for all parameters', async () => {
|
|
100
|
+
mockPromptUser.mockResolvedValue({
|
|
101
|
+
moduleLabel: 'Prompted Module',
|
|
102
|
+
reactType: false,
|
|
103
|
+
contentTypes: ['ANY'],
|
|
104
|
+
global: false,
|
|
105
|
+
availableForNewContent: true,
|
|
106
|
+
});
|
|
107
|
+
const result = await createModulePrompt();
|
|
108
|
+
expect(mockPromptUser).toHaveBeenCalledWith([
|
|
109
|
+
expect.objectContaining({ name: 'moduleLabel' }),
|
|
110
|
+
expect.objectContaining({ name: 'reactType' }),
|
|
111
|
+
expect.objectContaining({ name: 'contentTypes' }),
|
|
112
|
+
expect.objectContaining({ name: 'global' }),
|
|
113
|
+
expect.objectContaining({ name: 'availableForNewContent' }),
|
|
114
|
+
]);
|
|
115
|
+
expect(result).toEqual({
|
|
116
|
+
moduleLabel: 'Prompted Module',
|
|
117
|
+
reactType: false,
|
|
118
|
+
contentTypes: ['ANY'],
|
|
119
|
+
global: false,
|
|
120
|
+
availableForNewContent: true,
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
describe('parameter precedence', () => {
|
|
125
|
+
it('should prioritize command args over prompted values', async () => {
|
|
126
|
+
const commandArgs = {
|
|
127
|
+
moduleLabel: 'Args Module',
|
|
128
|
+
global: true,
|
|
129
|
+
};
|
|
130
|
+
mockPromptUser.mockResolvedValue({
|
|
131
|
+
reactType: false,
|
|
132
|
+
contentTypes: ['EMAIL'],
|
|
133
|
+
availableForNewContent: false,
|
|
134
|
+
});
|
|
135
|
+
const result = await createModulePrompt(commandArgs);
|
|
136
|
+
expect(result).toEqual({
|
|
137
|
+
moduleLabel: 'Args Module', // from commandArgs
|
|
138
|
+
reactType: false, // from prompt
|
|
139
|
+
contentTypes: ['EMAIL'], // from prompt
|
|
140
|
+
global: true, // from commandArgs
|
|
141
|
+
availableForNewContent: false, // from prompt
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
it('should handle boolean false values correctly', async () => {
|
|
145
|
+
const commandArgs = {
|
|
146
|
+
moduleLabel: 'Test Module',
|
|
147
|
+
reactType: false,
|
|
148
|
+
contentTypes: 'ANY',
|
|
149
|
+
global: false,
|
|
150
|
+
availableForNewContent: false,
|
|
151
|
+
};
|
|
152
|
+
const result = await createModulePrompt(commandArgs);
|
|
153
|
+
expect(mockPromptUser).not.toHaveBeenCalled();
|
|
154
|
+
expect(result).toEqual({
|
|
155
|
+
moduleLabel: 'Test Module',
|
|
156
|
+
reactType: false,
|
|
157
|
+
contentTypes: ['ANY'],
|
|
158
|
+
global: false,
|
|
159
|
+
availableForNewContent: false,
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
it('should handle mixed scenario with partial command args and prompting', async () => {
|
|
163
|
+
const commandArgs = {
|
|
164
|
+
moduleLabel: 'Partial Module',
|
|
165
|
+
contentTypes: 'BLOG_POST,BLOG_LISTING',
|
|
166
|
+
};
|
|
167
|
+
mockPromptUser.mockResolvedValue({
|
|
168
|
+
reactType: true,
|
|
169
|
+
global: false,
|
|
170
|
+
availableForNewContent: true,
|
|
171
|
+
});
|
|
172
|
+
const result = await createModulePrompt(commandArgs);
|
|
173
|
+
expect(mockPromptUser).toHaveBeenCalledWith([
|
|
174
|
+
expect.objectContaining({ name: 'reactType' }),
|
|
175
|
+
expect.objectContaining({ name: 'global' }),
|
|
176
|
+
expect.objectContaining({ name: 'availableForNewContent' }),
|
|
177
|
+
]);
|
|
178
|
+
expect(result).toEqual({
|
|
179
|
+
moduleLabel: 'Partial Module', // from commandArgs
|
|
180
|
+
reactType: true, // from prompt
|
|
181
|
+
contentTypes: ['BLOG_POST', 'BLOG_LISTING'], // from commandArgs (parsed)
|
|
182
|
+
global: false, // from prompt
|
|
183
|
+
availableForNewContent: true, // from prompt
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { createTemplatePrompt } from '../createTemplatePrompt.js';
|
|
3
|
+
import { promptUser } from '../promptUtils.js';
|
|
4
|
+
vi.mock('../promptUtils.js');
|
|
5
|
+
const mockPromptUser = vi.mocked(promptUser);
|
|
6
|
+
describe('createTemplatePrompt', () => {
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
vi.resetAllMocks();
|
|
9
|
+
});
|
|
10
|
+
describe('when templateType is provided', () => {
|
|
11
|
+
it('should return provided templateType without prompting', async () => {
|
|
12
|
+
const commandArgs = {
|
|
13
|
+
templateType: 'page-template',
|
|
14
|
+
};
|
|
15
|
+
const result = await createTemplatePrompt(commandArgs);
|
|
16
|
+
expect(mockPromptUser).not.toHaveBeenCalled();
|
|
17
|
+
expect(result).toEqual({
|
|
18
|
+
templateType: 'page-template',
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
it('should work with different template types', async () => {
|
|
22
|
+
const testCases = [
|
|
23
|
+
'email-template',
|
|
24
|
+
'partial',
|
|
25
|
+
'global-partial',
|
|
26
|
+
'blog-listing-template',
|
|
27
|
+
'blog-post-template',
|
|
28
|
+
'search-template',
|
|
29
|
+
'section',
|
|
30
|
+
];
|
|
31
|
+
for (const templateType of testCases) {
|
|
32
|
+
const commandArgs = { templateType };
|
|
33
|
+
const result = await createTemplatePrompt(commandArgs);
|
|
34
|
+
expect(mockPromptUser).not.toHaveBeenCalled();
|
|
35
|
+
expect(result).toEqual({ templateType });
|
|
36
|
+
vi.resetAllMocks();
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe('when templateType is not provided', () => {
|
|
41
|
+
it('should prompt for templateType', async () => {
|
|
42
|
+
mockPromptUser.mockResolvedValue({
|
|
43
|
+
templateType: 'page-template',
|
|
44
|
+
});
|
|
45
|
+
const result = await createTemplatePrompt();
|
|
46
|
+
expect(mockPromptUser).toHaveBeenCalledWith([
|
|
47
|
+
expect.objectContaining({
|
|
48
|
+
name: 'templateType',
|
|
49
|
+
type: 'list',
|
|
50
|
+
choices: expect.any(Array),
|
|
51
|
+
}),
|
|
52
|
+
]);
|
|
53
|
+
expect(result).toEqual({
|
|
54
|
+
templateType: 'page-template',
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
it('should prompt when commandArgs is empty', async () => {
|
|
58
|
+
mockPromptUser.mockResolvedValue({
|
|
59
|
+
templateType: 'email-template',
|
|
60
|
+
});
|
|
61
|
+
const result = await createTemplatePrompt({});
|
|
62
|
+
expect(mockPromptUser).toHaveBeenCalledWith([
|
|
63
|
+
expect.objectContaining({ name: 'templateType' }),
|
|
64
|
+
]);
|
|
65
|
+
expect(result).toEqual({
|
|
66
|
+
templateType: 'email-template',
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
it('should prompt when templateType is undefined', async () => {
|
|
70
|
+
const commandArgs = {
|
|
71
|
+
templateType: undefined,
|
|
72
|
+
};
|
|
73
|
+
mockPromptUser.mockResolvedValue({
|
|
74
|
+
templateType: 'partial',
|
|
75
|
+
});
|
|
76
|
+
const result = await createTemplatePrompt(commandArgs);
|
|
77
|
+
expect(mockPromptUser).toHaveBeenCalledWith([
|
|
78
|
+
expect.objectContaining({ name: 'templateType' }),
|
|
79
|
+
]);
|
|
80
|
+
expect(result).toEqual({
|
|
81
|
+
templateType: 'partial',
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
describe('integration scenarios', () => {
|
|
86
|
+
it('should handle mixed usage patterns', async () => {
|
|
87
|
+
// First call with templateType provided
|
|
88
|
+
let result = await createTemplatePrompt({
|
|
89
|
+
templateType: 'blog-post-template',
|
|
90
|
+
});
|
|
91
|
+
expect(result.templateType).toBe('blog-post-template');
|
|
92
|
+
expect(mockPromptUser).not.toHaveBeenCalled();
|
|
93
|
+
// Second call without templateType
|
|
94
|
+
mockPromptUser.mockResolvedValue({
|
|
95
|
+
templateType: 'section',
|
|
96
|
+
});
|
|
97
|
+
result = await createTemplatePrompt();
|
|
98
|
+
expect(result.templateType).toBe('section');
|
|
99
|
+
expect(mockPromptUser).toHaveBeenCalledTimes(1);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function confirmImportDataPrompt(targetAccountId: number, dataFileNames: string[]): Promise<boolean>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { getAccountConfig } from '@hubspot/local-dev-lib/config';
|
|
2
|
+
import { promptUser } from './promptUtils.js';
|
|
3
|
+
import { lib } from '../../lang/en.js';
|
|
4
|
+
export async function confirmImportDataPrompt(targetAccountId, dataFileNames) {
|
|
5
|
+
const account = getAccountConfig(targetAccountId);
|
|
6
|
+
const { confirmImportData } = await promptUser({
|
|
7
|
+
type: 'confirm',
|
|
8
|
+
name: 'confirmImportData',
|
|
9
|
+
message: lib.prompts.confirmImportDataPrompt.message(dataFileNames, account),
|
|
10
|
+
});
|
|
11
|
+
return confirmImportData;
|
|
12
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { CreateArgs } from '../../types/Cms.js';
|
|
1
2
|
type CreateFunctionPromptResponse = {
|
|
2
3
|
functionsFolder: string;
|
|
3
4
|
filename: string;
|
|
4
5
|
endpointMethod: string;
|
|
5
6
|
endpointPath: string;
|
|
6
7
|
};
|
|
7
|
-
export declare function createFunctionPrompt(): Promise<CreateFunctionPromptResponse>;
|
|
8
|
+
export declare function createFunctionPrompt(commandArgs?: Partial<CreateArgs>): Promise<CreateFunctionPromptResponse>;
|
|
8
9
|
export {};
|
|
@@ -55,11 +55,40 @@ const ENDPOINT_PATH_PROMPT = {
|
|
|
55
55
|
return true;
|
|
56
56
|
},
|
|
57
57
|
};
|
|
58
|
-
export function createFunctionPrompt() {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
export function createFunctionPrompt(commandArgs = {}) {
|
|
59
|
+
// Check if all required parameters are provided (endpointMethod has default)
|
|
60
|
+
const hasAllRequired = commandArgs.functionsFolder &&
|
|
61
|
+
commandArgs.filename &&
|
|
62
|
+
commandArgs.endpointPath;
|
|
63
|
+
if (hasAllRequired) {
|
|
64
|
+
return Promise.resolve({
|
|
65
|
+
functionsFolder: commandArgs.functionsFolder,
|
|
66
|
+
filename: commandArgs.filename,
|
|
67
|
+
endpointMethod: commandArgs.endpointMethod || 'GET',
|
|
68
|
+
endpointPath: commandArgs.endpointPath,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
const prompts = [];
|
|
72
|
+
// Only prompt for missing parameters
|
|
73
|
+
if (!commandArgs.functionsFolder) {
|
|
74
|
+
prompts.push(FUNCTIONS_FOLDER_PROMPT);
|
|
75
|
+
}
|
|
76
|
+
if (!commandArgs.filename) {
|
|
77
|
+
prompts.push(FUNCTION_FILENAME_PROMPT);
|
|
78
|
+
}
|
|
79
|
+
if (!commandArgs.endpointMethod) {
|
|
80
|
+
prompts.push(ENDPOINT_METHOD_PROMPT);
|
|
81
|
+
}
|
|
82
|
+
if (!commandArgs.endpointPath) {
|
|
83
|
+
prompts.push(ENDPOINT_PATH_PROMPT);
|
|
84
|
+
}
|
|
85
|
+
return promptUser(prompts).then(promptResponse => {
|
|
86
|
+
// Merge prompted values with provided commandArgs
|
|
87
|
+
return {
|
|
88
|
+
functionsFolder: commandArgs.functionsFolder || promptResponse.functionsFolder,
|
|
89
|
+
filename: commandArgs.filename || promptResponse.filename,
|
|
90
|
+
endpointMethod: commandArgs.endpointMethod || promptResponse.endpointMethod || 'GET',
|
|
91
|
+
endpointPath: commandArgs.endpointPath || promptResponse.endpointPath,
|
|
92
|
+
};
|
|
93
|
+
});
|
|
65
94
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CreateArgs } from '../../types/Cms.js';
|
|
1
2
|
type CreateModulePromptResponse = {
|
|
2
3
|
moduleLabel: string;
|
|
3
4
|
reactType: boolean;
|
|
@@ -5,5 +6,5 @@ type CreateModulePromptResponse = {
|
|
|
5
6
|
global: boolean;
|
|
6
7
|
availableForNewContent: boolean;
|
|
7
8
|
};
|
|
8
|
-
export declare function createModulePrompt(): Promise<CreateModulePromptResponse>;
|
|
9
|
+
export declare function createModulePrompt(commandArgs?: Partial<CreateArgs>): Promise<CreateModulePromptResponse>;
|
|
9
10
|
export {};
|
|
@@ -58,7 +58,54 @@ const AVAILABLE_FOR_NEW_CONTENT = {
|
|
|
58
58
|
message: i18n(`lib.prompts.createModulePrompt.availableForNewContent`),
|
|
59
59
|
default: true,
|
|
60
60
|
};
|
|
61
|
-
export function createModulePrompt() {
|
|
61
|
+
export function createModulePrompt(commandArgs = {}) {
|
|
62
|
+
// Check if moduleLabel is provided (main requirement to skip full prompting)
|
|
63
|
+
// but still allow individual parameter prompting for enhanced UX
|
|
64
|
+
if (commandArgs.moduleLabel) {
|
|
65
|
+
const prompts = [];
|
|
66
|
+
// Only prompt for parameters not explicitly provided
|
|
67
|
+
if (commandArgs.reactType === undefined) {
|
|
68
|
+
prompts.push(REACT_TYPE_PROMPT);
|
|
69
|
+
}
|
|
70
|
+
if (!commandArgs.contentTypes) {
|
|
71
|
+
prompts.push(CONTENT_TYPES_PROMPT);
|
|
72
|
+
}
|
|
73
|
+
if (commandArgs.global === undefined) {
|
|
74
|
+
prompts.push(GLOBAL_PROMPT);
|
|
75
|
+
}
|
|
76
|
+
if (commandArgs.availableForNewContent === undefined) {
|
|
77
|
+
prompts.push(AVAILABLE_FOR_NEW_CONTENT);
|
|
78
|
+
}
|
|
79
|
+
// If no additional prompts needed, return with defaults
|
|
80
|
+
if (prompts.length === 0) {
|
|
81
|
+
const contentTypesArray = commandArgs.contentTypes
|
|
82
|
+
? commandArgs.contentTypes.split(',').map((t) => t.trim())
|
|
83
|
+
: ['ANY'];
|
|
84
|
+
return Promise.resolve({
|
|
85
|
+
moduleLabel: commandArgs.moduleLabel,
|
|
86
|
+
reactType: commandArgs.reactType ?? false,
|
|
87
|
+
contentTypes: contentTypesArray,
|
|
88
|
+
global: commandArgs.global ?? false,
|
|
89
|
+
availableForNewContent: commandArgs.availableForNewContent ?? true,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
// Prompt only for missing optional parameters
|
|
93
|
+
return promptUser(prompts).then(promptResponse => {
|
|
94
|
+
const contentTypesArray = commandArgs.contentTypes
|
|
95
|
+
? commandArgs.contentTypes.split(',').map((t) => t.trim())
|
|
96
|
+
: promptResponse.contentTypes || ['ANY'];
|
|
97
|
+
return {
|
|
98
|
+
moduleLabel: commandArgs.moduleLabel,
|
|
99
|
+
reactType: commandArgs.reactType ?? promptResponse.reactType ?? false,
|
|
100
|
+
contentTypes: contentTypesArray,
|
|
101
|
+
global: commandArgs.global ?? promptResponse.global ?? false,
|
|
102
|
+
availableForNewContent: commandArgs.availableForNewContent ??
|
|
103
|
+
promptResponse.availableForNewContent ??
|
|
104
|
+
true,
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
// No moduleLabel provided, prompt for everything (original behavior)
|
|
62
109
|
return promptUser([
|
|
63
110
|
MODULE_LABEL_PROMPT,
|
|
64
111
|
REACT_TYPE_PROMPT,
|
|
@@ -1,27 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
readonly name: "page";
|
|
3
|
-
readonly value: "page-template";
|
|
4
|
-
}, {
|
|
5
|
-
readonly name: "email";
|
|
6
|
-
readonly value: "email-template";
|
|
7
|
-
}, {
|
|
8
|
-
readonly name: "partial";
|
|
9
|
-
readonly value: "partial";
|
|
10
|
-
}, {
|
|
11
|
-
readonly name: "global partial";
|
|
12
|
-
readonly value: "global-partial";
|
|
13
|
-
}, {
|
|
14
|
-
readonly name: "blog listing";
|
|
15
|
-
readonly value: "blog-listing-template";
|
|
16
|
-
}, {
|
|
17
|
-
readonly name: "blog post";
|
|
18
|
-
readonly value: "blog-post-template";
|
|
19
|
-
}, {
|
|
20
|
-
readonly name: "search results";
|
|
21
|
-
readonly value: "search-template";
|
|
22
|
-
}];
|
|
1
|
+
import { CreateArgs, TemplateType } from '../../types/Cms.js';
|
|
23
2
|
interface CreateTemplatePromptResponse {
|
|
24
|
-
templateType:
|
|
3
|
+
templateType: TemplateType;
|
|
25
4
|
}
|
|
26
|
-
export declare function createTemplatePrompt(): Promise<CreateTemplatePromptResponse>;
|
|
5
|
+
export declare function createTemplatePrompt(commandArgs?: Partial<CreateArgs>): Promise<CreateTemplatePromptResponse>;
|
|
27
6
|
export {};
|
|
@@ -8,6 +8,7 @@ const templateTypeChoices = [
|
|
|
8
8
|
{ name: 'blog listing', value: 'blog-listing-template' },
|
|
9
9
|
{ name: 'blog post', value: 'blog-post-template' },
|
|
10
10
|
{ name: 'search results', value: 'search-template' },
|
|
11
|
+
{ name: 'section', value: 'section' },
|
|
11
12
|
];
|
|
12
13
|
const TEMPLATE_TYPE_PROMPT = {
|
|
13
14
|
type: 'list',
|
|
@@ -16,6 +17,13 @@ const TEMPLATE_TYPE_PROMPT = {
|
|
|
16
17
|
default: 'page',
|
|
17
18
|
choices: templateTypeChoices,
|
|
18
19
|
};
|
|
19
|
-
export function createTemplatePrompt() {
|
|
20
|
+
export function createTemplatePrompt(commandArgs = {}) {
|
|
21
|
+
// If templateType is provided, return it directly
|
|
22
|
+
if (commandArgs.templateType) {
|
|
23
|
+
return Promise.resolve({
|
|
24
|
+
templateType: commandArgs.templateType,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
// No templateType provided, prompt for it (original behavior)
|
|
20
28
|
return promptUser([TEMPLATE_TYPE_PROMPT]);
|
|
21
29
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function importDataFilePathPrompt(): Promise<string>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { validateImportRequestFile } from '@hubspot/local-dev-lib/crm';
|
|
2
|
+
import { promptUser } from './promptUtils.js';
|
|
3
|
+
import { lib } from '../../lang/en.js';
|
|
4
|
+
import { logError } from '../errorHandlers/index.js';
|
|
5
|
+
import { uiLogger } from '../ui/logger.js';
|
|
6
|
+
export async function importDataFilePathPrompt() {
|
|
7
|
+
uiLogger.log(lib.prompts.importDataFilePathPrompt.promptContext);
|
|
8
|
+
const { filePath } = await promptUser({
|
|
9
|
+
type: 'input',
|
|
10
|
+
name: 'filePath',
|
|
11
|
+
message: lib.prompts.importDataFilePathPrompt.promptMessage,
|
|
12
|
+
validate: (filePath) => {
|
|
13
|
+
try {
|
|
14
|
+
validateImportRequestFile(filePath);
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
logError(error);
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
return filePath;
|
|
24
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { getAccountIdentifier } from '@hubspot/local-dev-lib/config/getAccountIdentifier';
|
|
2
|
+
import { promptUser } from './promptUtils.js';
|
|
3
|
+
import { getConfigAccounts } from '@hubspot/local-dev-lib/config';
|
|
4
|
+
import { uiAccountDescription } from '../ui/index.js';
|
|
5
|
+
import { lib } from '../../lang/en.js';
|
|
6
|
+
export async function importDataTestAccountSelectPrompt(parentAccountId) {
|
|
7
|
+
const accounts = getConfigAccounts();
|
|
8
|
+
if (!accounts) {
|
|
9
|
+
throw new Error(lib.prompts.importDataTestAccountSelectPrompt.errors.noAccountsFound);
|
|
10
|
+
}
|
|
11
|
+
const childAccounts = accounts
|
|
12
|
+
.filter(account => account.parentAccountId === parentAccountId)
|
|
13
|
+
.map(account => {
|
|
14
|
+
return {
|
|
15
|
+
name: uiAccountDescription(getAccountIdentifier(account)),
|
|
16
|
+
value: getAccountIdentifier(account),
|
|
17
|
+
};
|
|
18
|
+
})
|
|
19
|
+
.filter(account => account.value !== undefined && account.name !== undefined);
|
|
20
|
+
if (childAccounts.length === 0) {
|
|
21
|
+
throw new Error(lib.prompts.importDataTestAccountSelectPrompt.errors.noChildTestAccountsFound(parentAccountId));
|
|
22
|
+
}
|
|
23
|
+
return promptUser({
|
|
24
|
+
type: 'list',
|
|
25
|
+
name: 'selectedAccountId',
|
|
26
|
+
message: '[--account] Select a developer test account:',
|
|
27
|
+
choices: childAccounts,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { Separator as _Separator } from '@inquirer/prompts';
|
|
2
2
|
import { PromptConfig, GenericPromptResponse, PromptWhen, PromptChoices } from '../../types/Prompts.js';
|
|
3
3
|
export declare const Separator: _Separator;
|
|
4
|
+
export declare const PROMPT_THEME: {
|
|
5
|
+
prefix: {
|
|
6
|
+
idle: string;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
4
9
|
export declare function promptUser<T extends GenericPromptResponse>(config: PromptConfig<T> | PromptConfig<T>[]): Promise<T>;
|
|
5
10
|
export declare function confirmPrompt(message: string, options?: {
|
|
6
11
|
defaultAnswer?: boolean;
|
|
7
12
|
}): Promise<boolean>;
|
|
8
|
-
export declare function listPrompt<T = string>(message: string, { choices, when, defaultAnswer, validate, }: {
|
|
13
|
+
export declare function listPrompt<T = string>(message: string, { choices, when, defaultAnswer, validate, loop, }: {
|
|
9
14
|
choices: PromptChoices<T>;
|
|
10
15
|
when?: PromptWhen;
|
|
11
16
|
defaultAnswer?: string | number | boolean;
|
|
12
17
|
validate?: (input: T[]) => (boolean | string) | Promise<boolean | string>;
|
|
18
|
+
loop?: boolean;
|
|
13
19
|
}): Promise<T>;
|
|
14
20
|
export declare function inputPrompt(message: string, { when, validate, defaultAnswer, }?: {
|
|
15
21
|
when?: boolean | (() => boolean);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { confirm, Separator as _Separator, select, input, checkbox, password, number, } from '@inquirer/prompts';
|
|
2
2
|
import { EXIT_CODES } from '../enums/exitCodes.js';
|
|
3
|
+
import chalk from 'chalk';
|
|
3
4
|
export const Separator = new _Separator();
|
|
5
|
+
export const PROMPT_THEME = { prefix: { idle: chalk.green('?') } };
|
|
4
6
|
function isUserCancellationError(error) {
|
|
5
7
|
return error instanceof Error && error.name === 'ExitPromptError';
|
|
6
8
|
}
|
|
@@ -102,6 +104,8 @@ function handleRawListPrompt(config) {
|
|
|
102
104
|
choices: choices,
|
|
103
105
|
pageSize: config.pageSize,
|
|
104
106
|
default: config.default,
|
|
107
|
+
loop: config.loop,
|
|
108
|
+
theme: PROMPT_THEME,
|
|
105
109
|
}).then(resp => ({ [config.name]: resp }));
|
|
106
110
|
}
|
|
107
111
|
function handleNumberPrompt(config) {
|
|
@@ -109,6 +113,7 @@ function handleNumberPrompt(config) {
|
|
|
109
113
|
message: config.message,
|
|
110
114
|
default: config.default,
|
|
111
115
|
validate: config.validate,
|
|
116
|
+
theme: PROMPT_THEME,
|
|
112
117
|
}).then(resp => ({ [config.name]: resp }));
|
|
113
118
|
}
|
|
114
119
|
function handlePasswordPrompt(config) {
|
|
@@ -116,6 +121,7 @@ function handlePasswordPrompt(config) {
|
|
|
116
121
|
message: config.message,
|
|
117
122
|
mask: '*',
|
|
118
123
|
validate: config.validate,
|
|
124
|
+
theme: PROMPT_THEME,
|
|
119
125
|
}).then(resp => ({ [config.name]: resp }));
|
|
120
126
|
}
|
|
121
127
|
function handleCheckboxPrompt(config) {
|
|
@@ -125,6 +131,8 @@ function handleCheckboxPrompt(config) {
|
|
|
125
131
|
choices: choices,
|
|
126
132
|
pageSize: config.pageSize,
|
|
127
133
|
validate: config.validate,
|
|
134
|
+
loop: config.loop,
|
|
135
|
+
theme: PROMPT_THEME,
|
|
128
136
|
}).then(resp => ({ [config.name]: resp }));
|
|
129
137
|
}
|
|
130
138
|
function handleConfirmPrompt(config) {
|
|
@@ -138,6 +146,7 @@ function handleInputPrompt(config) {
|
|
|
138
146
|
default: config.default,
|
|
139
147
|
validate: config.validate,
|
|
140
148
|
transformer: config.transformer,
|
|
149
|
+
theme: PROMPT_THEME,
|
|
141
150
|
}).then(resp => ({ [config.name]: resp }));
|
|
142
151
|
}
|
|
143
152
|
function handleSelectPrompt(config) {
|
|
@@ -147,6 +156,8 @@ function handleSelectPrompt(config) {
|
|
|
147
156
|
choices: choices,
|
|
148
157
|
default: config.default,
|
|
149
158
|
pageSize: config.pageSize,
|
|
159
|
+
loop: config.loop,
|
|
160
|
+
theme: PROMPT_THEME,
|
|
150
161
|
}).then(resp => ({ [config.name]: resp }));
|
|
151
162
|
}
|
|
152
163
|
export async function confirmPrompt(message, options = {}) {
|
|
@@ -154,10 +165,11 @@ export async function confirmPrompt(message, options = {}) {
|
|
|
154
165
|
const choice = await confirm({
|
|
155
166
|
message,
|
|
156
167
|
default: defaultAnswer,
|
|
168
|
+
theme: PROMPT_THEME,
|
|
157
169
|
});
|
|
158
170
|
return choice;
|
|
159
171
|
}
|
|
160
|
-
export async function listPrompt(message, { choices, when, defaultAnswer, validate, }) {
|
|
172
|
+
export async function listPrompt(message, { choices, when, defaultAnswer, validate, loop, }) {
|
|
161
173
|
const { choice } = await promptUser({
|
|
162
174
|
name: 'choice',
|
|
163
175
|
type: 'list',
|
|
@@ -166,6 +178,7 @@ export async function listPrompt(message, { choices, when, defaultAnswer, valida
|
|
|
166
178
|
when,
|
|
167
179
|
default: defaultAnswer,
|
|
168
180
|
validate,
|
|
181
|
+
loop,
|
|
169
182
|
});
|
|
170
183
|
return choice;
|
|
171
184
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|