@suitegeezus/suitecloud-stacker 25.2.127

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 (113) hide show
  1. package/.idea/compiler.xml +6 -0
  2. package/.idea/git_toolbox_blame.xml +6 -0
  3. package/.idea/git_toolbox_prj.xml +15 -0
  4. package/.idea/misc.xml +6 -0
  5. package/.idea/modules.xml +8 -0
  6. package/.idea/suitecloud-stacker.iml +9 -0
  7. package/.idea/vcs.xml +6 -0
  8. package/CONTRIBUTING.md +72 -0
  9. package/README.md +242 -0
  10. package/bin/updateModule.d.ts +6 -0
  11. package/bin/updateModule.js +12 -0
  12. package/commands/CONTRIBUTING.md +7 -0
  13. package/commands/accountManageauth.d.ts +93 -0
  14. package/commands/accountManageauth.js +228 -0
  15. package/commands/accountSetup.d.ts +56 -0
  16. package/commands/accountSetup.js +218 -0
  17. package/commands/customhook/compiless.d.ts +10 -0
  18. package/commands/customhook/compiless.js +46 -0
  19. package/commands/customhook/watchss.d.ts +14 -0
  20. package/commands/customhook/watchss.js +77 -0
  21. package/commands/fileImport.d.ts +31 -0
  22. package/commands/fileImport.js +503 -0
  23. package/commands/fileList.d.ts +19 -0
  24. package/commands/fileList.js +40 -0
  25. package/commands/fileUpload.d.ts +52 -0
  26. package/commands/fileUpload.js +355 -0
  27. package/commands/generic.d.ts +5 -0
  28. package/commands/generic.js +13 -0
  29. package/commands/objectImport.d.ts +32 -0
  30. package/commands/objectImport.js +287 -0
  31. package/commands/objectList.d.ts +13 -0
  32. package/commands/objectList.js +78 -0
  33. package/commands/projectCreate.d.ts +31 -0
  34. package/commands/projectCreate.js +506 -0
  35. package/commands/projectDeploy.d.ts +25 -0
  36. package/commands/projectDeploy.js +371 -0
  37. package/commands/projectPackage.d.ts +10 -0
  38. package/commands/projectPackage.js +32 -0
  39. package/commands/projectValidate.d.ts +21 -0
  40. package/commands/projectValidate.js +112 -0
  41. package/commands/sdfAcs_authmap.d.ts +15 -0
  42. package/commands/sdfAcs_authmap.js +26 -0
  43. package/commands/sdfAcs_clean.d.ts +20 -0
  44. package/commands/sdfAcs_clean.js +22 -0
  45. package/deleteManifest.cjs +11 -0
  46. package/demo.md +26 -0
  47. package/index.d.ts +284 -0
  48. package/lib/MakeJestTestsFromDeploy.d.ts +13 -0
  49. package/lib/MakeJestTestsFromDeploy.js +60 -0
  50. package/lib/addGitKeep.d.ts +5 -0
  51. package/lib/addGitKeep.js +40 -0
  52. package/lib/addSdfObjectDirs.d.ts +5 -0
  53. package/lib/addSdfObjectDirs.js +16 -0
  54. package/lib/callCli.d.ts +7 -0
  55. package/lib/callCli.js +26 -0
  56. package/lib/compileHelper.d.ts +44 -0
  57. package/lib/compileHelper.js +196 -0
  58. package/lib/deleteProjectJson.d.ts +6 -0
  59. package/lib/deleteProjectJson.js +16 -0
  60. package/lib/deployFileHelper.d.ts +77 -0
  61. package/lib/deployFileHelper.js +249 -0
  62. package/lib/handleRootProjectJson.d.ts +10 -0
  63. package/lib/handleRootProjectJson.js +30 -0
  64. package/lib/isProd.d.ts +9 -0
  65. package/lib/isProd.js +13 -0
  66. package/lib/logHelper.d.ts +5 -0
  67. package/lib/logHelper.js +13 -0
  68. package/lib/logger.d.ts +6 -0
  69. package/lib/logger.js +10 -0
  70. package/lib/makeDeployXml.d.ts +6 -0
  71. package/lib/makeDeployXml.js +30 -0
  72. package/lib/makeJest.d.ts +12 -0
  73. package/lib/makeJest.js +58 -0
  74. package/lib/makeManifestXml.d.ts +6 -0
  75. package/lib/makeManifestXml.js +21 -0
  76. package/lib/makeProjectJson.d.ts +6 -0
  77. package/lib/makeProjectJson.js +16 -0
  78. package/lib/onErrorHelper.d.ts +31 -0
  79. package/lib/onErrorHelper.js +93 -0
  80. package/lib/pathHelpers.d.ts +133 -0
  81. package/lib/pathHelpers.js +428 -0
  82. package/lib/pause.d.ts +6 -0
  83. package/lib/pause.js +10 -0
  84. package/lib/projectJsonHelpers.d.ts +29 -0
  85. package/lib/projectJsonHelpers.js +92 -0
  86. package/lib/promptHelpers.d.ts +77 -0
  87. package/lib/promptHelpers.js +195 -0
  88. package/lib/removeFiles.d.ts +20 -0
  89. package/lib/removeFiles.js +46 -0
  90. package/lib/sdf.d.ts +11 -0
  91. package/lib/sdf.js +158 -0
  92. package/lib/spawnSuitecloudChild.d.ts +30 -0
  93. package/lib/spawnSuitecloudChild.js +88 -0
  94. package/lib/switchAuth.d.ts +17 -0
  95. package/lib/switchAuth.js +23 -0
  96. package/lib/tempFileHelper.d.ts +29 -0
  97. package/lib/tempFileHelper.js +70 -0
  98. package/lib/updateModule.d.ts +10 -0
  99. package/lib/updateModule.js +79 -0
  100. package/lib/validators.d.ts +12 -0
  101. package/lib/validators.js +25 -0
  102. package/package.json +38 -0
  103. package/safeCommands.d.ts +95 -0
  104. package/safeCommands.js +959 -0
  105. package/sdf.config.js +15 -0
  106. package/sdf.exe.js +16 -0
  107. package/templates/customizations.projectroot.d.ts +74 -0
  108. package/templates/makeModuleTypeDef.d.ts +5 -0
  109. package/templates/makeModuleTypeDef.js +29 -0
  110. package/templates/sdfGitIgnore.txt +42 -0
  111. package/templates/suitecloud.config.js +17 -0
  112. package/templates/tsconfig.ss21.projectroot.json +64 -0
  113. package/types/colors.d.ts +43 -0
@@ -0,0 +1,506 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rootProjectChoices = exports.newAccount = exports.projectJsonPromptAndEscape = void 0;
4
+ const onErrorHelper = require("../lib/onErrorHelper");
5
+ const pathHelper = require("../lib/pathHelpers");
6
+ const safeCommands_1 = require("../safeCommands");
7
+ const validators_1 = require("../lib/validators");
8
+ const pathHelpers_1 = require("../lib/pathHelpers");
9
+ const path = require('node:path');
10
+ const fs = require('node:fs/promises');
11
+ const cp = require('node:child_process');
12
+ const addGitKeep = require('../lib/addGitKeep');
13
+ const addSdfObjectDirs = require('../lib/addSdfObjectDirs');
14
+ const makeModuleTypeDef = require('../templates/makeModuleTypeDef');
15
+ const { promptUser, goColor, promptChoices } = require('../lib/promptHelpers');
16
+ const messagesThatAreNotErrors = {
17
+ CREATE_PROJECT_JSON: 'Created project.json. Now exiting project:create',
18
+ };
19
+ const makeDefaultCallbacks = () => ({
20
+ _origin: 'makeDefaultCallbacks',
21
+ beforeExecuting: async (options) => {
22
+ return options;
23
+ },
24
+ onCompleted: async (options) => {
25
+ return options;
26
+ },
27
+ onError: async (error) => onErrorHelper.detectOriginAndReturn('makeDefaultCallback', error),
28
+ isStackable: true,
29
+ });
30
+ async function moveContentsUp(dir) {
31
+ try {
32
+ // Get all entries (files and folders) in the directory.
33
+ const entries = await fs.readdir(dir, { withFileTypes: true });
34
+ // Determine the parent directory.
35
+ const parentDir = path.dirname(dir);
36
+ for (const entry of entries) {
37
+ const oldPath = path.join(dir, entry.name);
38
+ const newPath = path.join(parentDir, entry.name);
39
+ // Move the entry using fs.rename.
40
+ await fs.rename(oldPath, newPath);
41
+ console.log(goColor('INFO', `Moved: `), goColor('SUBTLE', `${oldPath} -> ${newPath}`));
42
+ }
43
+ console.log(goColor('GOOD', 'All entries have been moved up one level.'));
44
+ }
45
+ catch (error) {
46
+ console.error(goColor('BAD', 'Error moving contents:'), error);
47
+ }
48
+ }
49
+ /**
50
+ * @description - For an existing mini-project. Use the 'project:create' command as a way to switch accounts
51
+ * Assumes the following:
52
+ * - you have a subdirectory called "deploy"
53
+ * - uses local project.json permuations as a configuration file from that
54
+ * @param {root: string} [opts]
55
+ */
56
+ const projectJsonPromptAndEscape = (opts) => {
57
+ return {
58
+ _origin: 'projectJsonPromptAndEscape',
59
+ beforeExecuting: async ( /* options */) => {
60
+ let message = '';
61
+ try {
62
+ // TODO should be a combo of options.projectPath and project.json
63
+ const { root: projectFolder } = { root: path.join(process.cwd(), 'project.json'), ...opts };
64
+ // enforce having a deploy directory with project.*.json files
65
+ const projectJsonList = await fs.readdir(path.join(projectFolder, 'deploy'))
66
+ .then((files) => files.filter((pJson) => /^project(\.\w+)?\.json$/.test(pJson)))
67
+ // failover to empty list
68
+ .catch(() => {
69
+ console.error(goColor('WARN', `${path.join(projectFolder, 'deploy')} does not exist! Suggest to create one manually.`));
70
+ return [];
71
+ });
72
+ if (!projectJsonList || projectJsonList?.length === 0)
73
+ throw new Error('projectJsonPromptAndEscape:NO deploy/project.*.json files found');
74
+ // cycle through project.json files
75
+ // ask user to confirm to use this one
76
+ const projectJsonToUse = await projectJsonList
77
+ .reduce(async (acc, pJson) => {
78
+ const answer = await acc;
79
+ const candidatePath = path.join(projectFolder, 'deploy', pJson);
80
+ console.log(answer);
81
+ if (typeof answer === 'string' && /^Y(es|eah|up)?$/i.test(answer))
82
+ return acc;
83
+ const contents = await fs.readFile(candidatePath, 'utf8');
84
+ // make sure it serializes
85
+ JSON.stringify(JSON.parse(contents));
86
+ return promptUser({
87
+ message: [
88
+ `Would you like to use ${pJson} with content:`,
89
+ contents,
90
+ ].join('\n'),
91
+ timeout: 10000,
92
+ }).then(() => candidatePath);
93
+ }, Promise.resolve(''));
94
+ // make chosen project.json the active one
95
+ if (projectJsonToUse) {
96
+ console.log({ projectJsonToUse });
97
+ await fs.cp(projectJsonToUse, path.join(projectFolder, 'project.json'));
98
+ message = messagesThatAreNotErrors.CREATE_PROJECT_JSON;
99
+ }
100
+ }
101
+ catch (e) {
102
+ console.error(e);
103
+ }
104
+ if (message)
105
+ throw new Error(message);
106
+ throw new Error('projectJsonPromptAndEscape:Exiting Project JSON choice');
107
+ },
108
+ onError: async (error) => {
109
+ return onErrorHelper.detectOriginAndReturn('projectJsonPromptAndEscape', error, (error) => {
110
+ // console.error('options', options, typeof options, options.split(/\s/));
111
+ const goodMessage = Object.values(messagesThatAreNotErrors).find((msg) => error.endsWith(msg));
112
+ // console.log(goodMessage);
113
+ if (typeof goodMessage === 'string') {
114
+ console.log(goColor('GOOD', 'Everything is fine. That error is a necessary evil', false));
115
+ process.exit(0);
116
+ }
117
+ else {
118
+ process.exit(1);
119
+ }
120
+ });
121
+ },
122
+ onCompleted: async (e) => {
123
+ console.log('project complete');
124
+ },
125
+ isStackable: true,
126
+ };
127
+ };
128
+ exports.projectJsonPromptAndEscape = projectJsonPromptAndEscape;
129
+ /**
130
+ * @description - For setting up a new account on your machine
131
+ * # Restrictions
132
+ * - Account must have a name that matches a certain name format
133
+ *
134
+ * @param opts
135
+ * @returns {any}
136
+ */
137
+ const newAccount = (opts) => {
138
+ const shared = { foo: () => console.log('not updated') };
139
+ return {
140
+ _origin: 'newAccount',
141
+ /**
142
+ * @description - asdf
143
+ * @param {BeforeExecutingOptions} options
144
+ */
145
+ beforeExecuting: async (options) => {
146
+ console.log(goColor('SUBTLE', { options }));
147
+ shared.foo = () => console.log(goColor('GOOD', 'updated!*****************************'));
148
+ return options;
149
+ },
150
+ /**
151
+ *
152
+ * @param {any} options
153
+ */
154
+ onCompleted: async (options) => {
155
+ console.log(goColor('INFO', 'onCompleted'), goColor('SUBTLE', options));
156
+ shared.foo();
157
+ if (options?._status === 'SUCCESS') {
158
+ let rootOrSrc = '';
159
+ const nag = async () => {
160
+ rootOrSrc = await safeCommands_1.promptHelpers.promptUser({
161
+ message: 'What root would you like? e.g. `src`'
162
+ });
163
+ };
164
+ while (!/^\w{3,}$/.test(rootOrSrc)) {
165
+ await nag();
166
+ }
167
+ const fileCabRoot = path.join(options._projectDirectory, rootOrSrc);
168
+ //(async ()=> {
169
+ // await moveContentsUp(path.join(options._projectDirectory, 'src'));
170
+ // // remove the empty src dir
171
+ // await fs.rmdir(
172
+ // path.join(options._projectDirectory, 'src'),
173
+ // {force: true}
174
+ // );
175
+ //})
176
+ // object subsfolders
177
+ await addSdfObjectDirs.add(path.join(fileCabRoot, 'Objects'));
178
+ // move the structure up one
179
+ // add gitKeep
180
+ await addGitKeep.add(fileCabRoot);
181
+ // backup deploy as it changes a lot
182
+ await fs.rename(path.join(fileCabRoot, 'deploy.xml'), path.join(fileCabRoot, 'deploy.generic.xml'));
183
+ // custom gitignore default
184
+ process.stdout.write('\n' + goColor('SUBTLE', path.join(__dirname, '../templates/sdfGitIgnore.txt', ' --> .gitignore')));
185
+ await fs.cp(path.join(__dirname, '../templates/sdfGitIgnore.txt'), path.join(pathHelper.getRootOfAccount(fileCabRoot), '.gitignore'))
186
+ .then(() => process.stdout.write('✅'))
187
+ .catch(() => process.stdout.write('❌'));
188
+ // default tsconfig
189
+ process.stdout.write('\n' + goColor('INFO', 'create tsconfig for ss2.1 '));
190
+ await fs.cp(path.join(__dirname, '../templates/tsconfig.ss21.projectroot.json'), path.join(pathHelper.getRootOfAccount(fileCabRoot), 'tsconfig.ss21.json'))
191
+ .then(() => process.stdout.write('✅'))
192
+ .catch(() => process.stdout.write('❌'));
193
+ // suitecloud config
194
+ process.stdout.write('\n' + goColor('INFO', 'create suitecloud.config.js for ss2.1 '));
195
+ await fs.cp(path.join(__dirname, '../templates/suitecloud.config.js'), path.join(options._projectDirectory, 'suitecloud.config.js'))
196
+ .then(() => process.stdout.write('✅'))
197
+ .catch(() => process.stdout.write('❌'));
198
+ // make types dir (such as customizations.d.ts)
199
+ process.stdout.write('\n' + goColor('INFO', 'create customizations.d.ts for Type resolution'));
200
+ await Promise.allSettled([
201
+ await fs.mkdir(path.join(options._projectDirectory, 'types')),
202
+ await fs.cp(path.join(__dirname, '../templates/customizations.projectroot.d.ts'), path.join(pathHelper.getRootOfAccount(fileCabRoot), 'types', 'customizations.d.ts'))
203
+ ])
204
+ .then(() => process.stdout.write('✅'))
205
+ .catch(() => process.stdout.write('❌'));
206
+ // create account-specific N
207
+ // copy mocks
208
+ // run git init
209
+ process.stdout.write('\n' + goColor('INFO', 'git commands:'));
210
+ await [
211
+ ['git', 'init'],
212
+ ['git', 'add', '-A'],
213
+ ['git', 'commit', '-m', 'firstcommit'],
214
+ ].reduce(async (promiseChain, command) => {
215
+ await promiseChain;
216
+ return new Promise((ok, no) => {
217
+ const [first, second, ...args] = command;
218
+ process.stdout.write(goColor('HIGHLIGHT', `\n ${second} `));
219
+ const initGit = cp.spawn(first, [second, ...args], { cwd: options._projectDirectory });
220
+ initGit.on('close', (code) => {
221
+ if (code)
222
+ no(code);
223
+ ok(true);
224
+ process.stdout.write(`✅`);
225
+ });
226
+ });
227
+ }, Promise.resolve(true)).catch(() => process.stdout.write('❌'));
228
+ }
229
+ },
230
+ isStackable: true,
231
+ defaultProjectFolder: opts.root,
232
+ };
233
+ };
234
+ exports.newAccount = newAccount;
235
+ /**
236
+ * @description
237
+ * - to be called from a beforeExecuting callback of 'project:create' in order to help create a ts project
238
+ * - the project name becomes the root folder so it is not an argument of this function
239
+ * - creates all the folders needed e.g. deploy, docs, entry
240
+ * - create a jest config for the project
241
+ * - creates a suitecloud.config file for the project
242
+ *
243
+ * @example
244
+ * ```bash
245
+ * suitecloud project:create --type ACCOUNTCUSTOMIZATION --projectname doesStuff
246
+ * ```
247
+ * @param {BeforeExecutingOptions} options
248
+ * @param {{authid: string; acctid: string}} extras
249
+ */
250
+ const makeTsProject = (options, extras) => {
251
+ const Shared = {
252
+ casenumber: '',
253
+ casepath: '',
254
+ authid: extras.authid
255
+ };
256
+ return {
257
+ _origin: 'makeTsProject',
258
+ onError: async (error) => {
259
+ return onErrorHelper.detectOriginAndReturn('makeTsProject', error);
260
+ },
261
+ /**
262
+ * @description - for this function the project path given must be
263
+ * @param options
264
+ */
265
+ beforeExecuting: async (options) => {
266
+ try {
267
+ // check to make sure we are not going to overwrite anything
268
+ // TODO
269
+ // prompt for a caseNumber;
270
+ options.arguments.overwrite = false;
271
+ options.arguments.type = 'ACCOUNTCUSTOMIZATION';
272
+ /**
273
+ * @description - recursive function until OP gets it correct
274
+ * @param message
275
+ */
276
+ const getCaseNumberCorrect = async (message) => {
277
+ // list first level contents of SuiteScripts
278
+ const ssFolders = await fs.readdir(path.join(process.cwd(), extras.folder, 'SuiteScripts', 'Apps'), { withFileTypes: true })
279
+ .then((folders) => folders.filter((f) => f.isDirectory()))
280
+ .catch(() => []);
281
+ process.stdout.write(goColor('INFO', '\nExisting Folders: ', ssFolders.map(({ name }) => goColor('WARN', '\n /SuiteScripts/Apps/', name)).join('\n')));
282
+ // console.log({options, extras})
283
+ Shared.casepath = await promptUser({
284
+ message: `${message || ''}\nWhat is the new folder name? (e.g. Apps/glplugins)`,
285
+ timeout: null
286
+ });
287
+ if (Shared?.casepath?.length === 0)
288
+ return getCaseNumberCorrect('You must provide a folder');
289
+ if (/^!(\w[\\\w]*\w|\w+)$/.test(Shared.casepath))
290
+ return getCaseNumberCorrect('Bad folder name');
291
+ Shared.casepath = Shared.casepath.replace(/.*\bSuiteScripts\b\/?/, '');
292
+ return;
293
+ };
294
+ // trigger
295
+ await getCaseNumberCorrect();
296
+ Shared.casenumber = path.basename(Shared.casepath);
297
+ // this property gets used by SDF to create the folder and it will respect the slashes
298
+ options.arguments.projectname = path.join(extras.folder, 'SuiteScripts', Shared.casepath);
299
+ const newOptions = {
300
+ ...options,
301
+ projectPath: path.join(options.projectPath,
302
+ // os-agnostic safe
303
+ extras.folder, 'SuiteScripts', Shared.casepath),
304
+ overwrite: false,
305
+ };
306
+ // console.log({newOptions}, extras);
307
+ // check path and create pre-folder if needed so that SDF can create the last folder
308
+ await fs.mkdir(path.dirname(newOptions.projectPath), { recursive: true }).catch((error) => {
309
+ console.error(error);
310
+ });
311
+ return newOptions;
312
+ }
313
+ catch (err) {
314
+ console.error(err);
315
+ throw err;
316
+ }
317
+ },
318
+ onCompleted: async (options) => {
319
+ // destroy all the stuff that SDF created in the folder that we don't want
320
+ // TODO
321
+ // this will be something like /Users/geraldgillespie/code/nsaccounts/65432/src/FileCabinet/SuiteScripts/Apps/foo
322
+ const folderToUse = options._projectDirectory; // path.join(await pathHelper.getFolderHoldingFileCabinetPlus(options._projectDirectory), 'FileCabinet');
323
+ {
324
+ // copy some demo templates
325
+ // console.log(path.join(process.cwd(), 'demo', 'FileCabinet', 'SuiteScripts', 'Apps', 'case123'));
326
+ const casePath = path.join(process.cwd(), 'demo', 'FileCabinet', 'SuiteScripts', 'Apps', 'case123');
327
+ await fs.access(casePath)
328
+ .catch((e) => fs.mkdir(casePath, { recursive: true }))
329
+ .then(() => fs.cp(casePath, folderToUse, { recursive: true }));
330
+ // neuter a file that can trip you up - note: it is gitignore but
331
+ await fs.writeFile(path.join(folderToUse, 'project.json'), JSON.stringify({
332
+ defaultAuthId: null,
333
+ caseNumber: Shared.casenumber,
334
+ deployXml: null
335
+ }, null, 2), { encoding: 'utf-8' }).catch(console.error);
336
+ }
337
+ const fileCabinetPath = folderToUse.replace(/^.*(\bFileCabinet.*)$/, '$1');
338
+ // do not need this anymore?
339
+ {
340
+ // modify TS extends path
341
+ const currentTsJSon = await fs.readFile(path.join(folderToUse, 'tsconfig.json'), { encoding: 'utf8' });
342
+ const parsedTsConfig = JSON.parse(currentTsJSon);
343
+ {
344
+ // e.g. "extends": ["../../../../tsconfig.ss21.json"],
345
+ console.log(goColor('SUBTLE', { folderToUse, fileCabinetPath }));
346
+ // console.log(goColor('HIGHLIGHT', 'this one?'), goColor('SUBTLE', path.relative(folderToUse, fileCabinetPath)));
347
+ // console.log(goColor('HIGHLIGHT', 'or this one?'), goColor('SUBTLE', path.relative(fileCabinetPath, folderToUse)));
348
+ parsedTsConfig.extends = [
349
+ path.join(path.relative(folderToUse, pathHelper.getRootOfAccount(folderToUse)), 'tsconfig.ss21.json')
350
+ ];
351
+ // TODO: includes this? "../../../../../types/*.d.ts",
352
+ // map the relative path to the project's root types
353
+ await fs.writeFile(path.join(folderToUse, 'tsconfig.json'), JSON.stringify(parsedTsConfig, null, 2), { encoding: 'utf8' });
354
+ }
355
+ }
356
+ // create some templates;
357
+ // create folder specific things;
358
+ // create module.d.ts that is specific;
359
+ const moduleContent = makeModuleTypeDef.fromRoot(folderToUse);
360
+ await fs.writeFile(path.join(folderToUse, 'module.d.ts'), moduleContent, { encoding: 'utf8' });
361
+ const deployXmlContent = `
362
+ <!-- for case number ${Shared.casenumber} for client ${Shared.authid} -->
363
+ <deploy>
364
+ <files>
365
+ <path>~/${fileCabinetPath}/utils/utils.js</path>
366
+ <!--<path>~/${fileCabinetPath}/entry/example.js</path> -->
367
+ <path>~/${fileCabinetPath}/docs/*</path>
368
+ </files>
369
+ <!--
370
+ <objects>
371
+ <path>~/Objects/</path>
372
+ </objects>
373
+ -->
374
+ </deploy>
375
+ `;
376
+ // write the xml
377
+ await fs.writeFile(path.join(folderToUse, 'deploy', `deploy.${path.basename(Shared.casenumber)}.xml`), deployXmlContent, { encoding: 'utf8' });
378
+ const projectJsonContent = JSON.stringify({
379
+ defaultAuthId: Shared.authid,
380
+ caseNumber: Shared.casenumber,
381
+ deployXml: `deploy.${Shared.casenumber}.xml`
382
+ }, null, 2);
383
+ await fs.writeFile(path.join(folderToUse, 'deploy', `project.${Shared.casenumber}.${Shared.authid}.json`), projectJsonContent, { encoding: 'utf8' });
384
+ // remove what SDF created by default
385
+ await fs.rm(path.join(folderToUse, pathHelpers_1.CONSTANTS.SDF_DEFAULT_ROOT), { recursive: true, force: true });
386
+ const created = await fs.readdir(folderToUse, { recursive: true });
387
+ console.log({ created });
388
+ try {
389
+ await [
390
+ ['git', 'add', '-A'],
391
+ ['git', 'commit', '-m', 'created project ' + options._projectName],
392
+ ].reduce(async (promiseChain, command) => {
393
+ await promiseChain;
394
+ return new Promise((ok, no) => {
395
+ const [first, ...args] = command;
396
+ const initGit = cp.spawn(first, args, { cwd: options._projectDirectory });
397
+ initGit.on('close', (code) => {
398
+ if (code)
399
+ no(code);
400
+ ok(true);
401
+ });
402
+ });
403
+ }, Promise.resolve(true));
404
+ process.stdout.write(goColor('SUCCESS', '\nGit initalized in ', options._projectDirectory));
405
+ }
406
+ catch (err) {
407
+ console.error('Git Commands failed', err);
408
+ }
409
+ process.stdout.write(goColor('SUCCESS', '\nNavigate to \n', goColor('HIGHLIGHT', options._projectDirectory), goColor('GOOD', '\n to continue')));
410
+ },
411
+ isStackable: true,
412
+ };
413
+ };
414
+ /**
415
+ * @description - hi
416
+ *
417
+ */
418
+ const rootProjectChoices = () => {
419
+ const sdfCommand = makeDefaultCallbacks();
420
+ const origin = 'rootProjectChoices';
421
+ return {
422
+ _origin: origin,
423
+ beforeExecuting: async (options) => {
424
+ // force ACCOUNTCUSTOMIZATION
425
+ options.arguments.type = 'ACCOUNTCUSTOMIZATION';
426
+ options.arguments.overwrite = false;
427
+ // prompt for acct
428
+ const potentials = await pathHelper.findMatchingDirectories(process.cwd(),
429
+ // length/depth of 3. first test must be to match account number (folder)
430
+ [/^(td)?\d+/, /^\w+$/, /^\w+$/, /^\w+$/]);
431
+ const filtered = potentials.filter((p) => /\bFileCabinet$/.test(p));
432
+ const choices = filtered.map((f) => f.replace(/^.*nsaccounts\b.((td)?\d+.*)$/, '$1'));
433
+ let folderChoice = await promptChoices({
434
+ choices: [...choices, 'NEW'],
435
+ displayChoices: [...choices, 'NEW'],
436
+ question: 'Which account? (or NEW?)',
437
+ default: 'NEW'
438
+ });
439
+ if (folderChoice === 'NEW') {
440
+ const nag = async () => {
441
+ folderChoice = await promptUser({
442
+ message: 'Type in the account id (e.g. 654321)'
443
+ });
444
+ };
445
+ while (!filtered.includes(folderChoice) && !(0, validators_1.isValidAccountFolderName)(folderChoice)) {
446
+ await nag();
447
+ }
448
+ }
449
+ // it will either be an existing choice OR a choice is a brand new value
450
+ const requestedAccount = folderChoice.replace(/^((td)?\d+).*$/, '$1');
451
+ // validate account
452
+ if (!/^(td)?\d+/.test(requestedAccount))
453
+ throw onErrorHelper.makeError(origin, new Error('Malformed account number ' + requestedAccount));
454
+ options.arguments.projectname = requestedAccount;
455
+ // check if it already exists
456
+ const matchedAccount = await fs.readdir(process.cwd(), { encoding: 'utf8' })
457
+ .then((candidates) => candidates.find(candidate => candidate === requestedAccount));
458
+ // give choices related to existing account
459
+ if (matchedAccount) {
460
+ const choices = ['Create TS Project for a case'];
461
+ const choiceMap = {
462
+ [choices[0]]: () => makeTsProject(options, {
463
+ /** @todo lookup the authid in the existing account project.json */
464
+ authid: requestedAccount || 'TBD',
465
+ acctid: matchedAccount,
466
+ folder: folderChoice
467
+ })
468
+ };
469
+ // list first level contents of SuiteScripts
470
+ const ssFolders = await fs.readdir(path.join(process.cwd(), folderChoice, 'SuiteScripts', 'Apps'), { withFileTypes: true })
471
+ .then((folders) => folders.filter((f) => f.isDirectory()))
472
+ .catch(() => []);
473
+ process.stdout.write(goColor('INFO', '\nExisting Folders: ', ssFolders.map(({ name }) => goColor('WARN', '\n /SuiteScripts/Apps/', name)).join('\n')));
474
+ const answer = await safeCommands_1.promptHelpers.promptChoices({
475
+ choices: Object.keys(choiceMap),
476
+ displayChoices: Object.keys(choiceMap),
477
+ question: 'Which type?',
478
+ default: choices[0],
479
+ });
480
+ const choiceFunction = Reflect.get(choiceMap, answer);
481
+ if (typeof choiceFunction === 'function') {
482
+ Object.assign(sdfCommand, choiceFunction());
483
+ }
484
+ }
485
+ else {
486
+ Object.assign(sdfCommand, (0, exports.newAccount)({ root: '.' }));
487
+ }
488
+ /*const confirm = await promptUser({
489
+ message: ['Proceed with these options?', JSON.stringify(options, null, 2),].join('\n'),
490
+ timeout: null
491
+ });
492
+ if (!/^y(es|up|eah)?$/i.test(confirm)) throw new Error("rootProjectChoices:Cancelled");*/
493
+ return sdfCommand.beforeExecuting(options);
494
+ },
495
+ onCompleted: async (options) => {
496
+ await sdfCommand.onCompleted(options);
497
+ return options;
498
+ },
499
+ onError: async (error) => {
500
+ return onErrorHelper.detectOriginAndReturn('rootProjectChoices', error);
501
+ },
502
+ isStackable: true,
503
+ };
504
+ };
505
+ exports.rootProjectChoices = rootProjectChoices;
506
+ //# sourceMappingURL=projectCreate.js.map
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @file sdf/commands/projectDeploy.ts
3
+ * @author Gerald Gillespie <gerald.gillespie@fullscript.com>
4
+ */
5
+ import { SdfCommand } from "index";
6
+ export declare const doDryRunAsChild: (authid: string | undefined) => Promise<number>;
7
+ export declare const offerValidate: () => SdfCommand;
8
+ export declare const forceValidate: () => SdfCommand;
9
+ export declare const compileBeforeDeploy: () => SdfCommand;
10
+ /**
11
+ * @deprecated
12
+ */
13
+ export declare const runTestBeforeDeploy: () => SdfCommand;
14
+ export declare const forceLog: () => SdfCommand;
15
+ /**
16
+ * @description - prompt deployXml choices and confirm
17
+ * @see {SdfCommand}
18
+ */
19
+ export declare const promptForDeployFile: () => SdfCommand;
20
+ export declare const logErrors: () => SdfCommand;
21
+ /**
22
+ * @description -
23
+ * @
24
+ */
25
+ export declare const askForDryrun: () => SdfCommand;