@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,959 @@
1
+ "use strict";
2
+ /**
3
+ * @file sdf/safeCommands.ts
4
+ * @author Gerald Gillespie <gerald.gillespie@fullscript.com>
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.makeSafeExports = exports.caseCommands = exports.defaultCommands = exports.stack = exports.makeSuiteCloudConfig = exports.genericCommandProxy = exports.makeFunctionProxy = exports.accountManageAuthCommand = exports.accountSetupCommand = exports.fileUploadCommand = exports.objectImportCommand = exports.objectListCommand = exports.projectValidateCommand = exports.projectDeployCommand = exports.projectCreateCommand = exports.fileImportCommand = exports.promptHelpers = void 0;
8
+ const makeManifest = require("./lib/makeManifestXml");
9
+ const makeDeploy = require("./lib/makeDeployXml");
10
+ const removeFiles = require("./lib/removeFiles");
11
+ const process = require("node:process");
12
+ const fs = require("node:fs");
13
+ const nodePath = require("node:path");
14
+ const promptHelper = require("./lib/promptHelpers");
15
+ const pathHelpers = require("./lib/pathHelpers");
16
+ const projectJsonHelpers = require("./lib/projectJsonHelpers");
17
+ const accountManageAuth = require("./commands/accountManageauth");
18
+ const accountSetup = require("./commands/accountSetup");
19
+ const onErrorHelper = require("./lib/onErrorHelper");
20
+ const spawnSuitecloudChild = require("./lib/spawnSuitecloudChild");
21
+ const tempFileHelper = require("./lib/tempFileHelper");
22
+ const fileList = require("./commands/fileList");
23
+ const fileImports = require("./commands/fileImport");
24
+ const projectCreates = require("./commands/projectCreate");
25
+ const projectDeploys = require("./commands/projectDeploy");
26
+ const fileUpload = require("./commands/fileUpload");
27
+ const projectValidates = require("./commands/projectValidate");
28
+ const objectLists = require("./commands/objectList");
29
+ const objectImports = require("./commands/objectImport");
30
+ const projectPackages = require("./commands/projectPackage");
31
+ const onErrorHelper_1 = require("./lib/onErrorHelper");
32
+ const watchss_1 = require("./commands/customhook/watchss");
33
+ const compiless_1 = require("./commands/customhook/compiless");
34
+ const promptHelpers_1 = require("./lib/promptHelpers");
35
+ exports.promptHelpers = promptHelper;
36
+ exports.fileImportCommand = fileImports;
37
+ exports.projectCreateCommand = projectCreates;
38
+ exports.projectDeployCommand = projectDeploys;
39
+ exports.projectValidateCommand = projectValidates;
40
+ exports.objectListCommand = objectLists;
41
+ exports.objectImportCommand = objectImports;
42
+ exports.fileUploadCommand = fileUpload;
43
+ exports.accountSetupCommand = accountSetup;
44
+ exports.accountManageAuthCommand = accountManageAuth;
45
+ const SHARED = {
46
+ DEBUG: false,
47
+ };
48
+ /**
49
+ * @internal
50
+ * @description - clean up some files
51
+ * @param fileNames
52
+ * @param root
53
+ */
54
+ const cleanup = (fileNames, root) => {
55
+ removeFiles({
56
+ fileNames,
57
+ doBackup: false,
58
+ root
59
+ });
60
+ };
61
+ /**
62
+ * @description - if blocked then an error is thrown (useful for temporarily neutering a capability)
63
+ * - the original candidate can satisfy the handler then it will
64
+ * - otherwise the replacement will
65
+ * @param {function} candidate - the root object
66
+ * @param {boolean} doBlock - whether to block access to the true candidate or not -- useful in debugging
67
+ * @param {boolean} debug - Whether to print useful values such as the property, value, arguments
68
+ */
69
+ const makeFunctionProxy = (candidate, doBlock, debug) => {
70
+ if (candidate === null || (!['function', 'object'].includes(typeof candidate))) {
71
+ if (debug)
72
+ console.log(exports.promptHelpers.goColor('SUBTLE', 'skipping proxy for', typeof candidate, JSON.stringify({
73
+ doBlock,
74
+ debug
75
+ }, null, 2), false));
76
+ if (doBlock)
77
+ throw Error('blocked');
78
+ return candidate;
79
+ }
80
+ // console.log(promptHelpers.goColor('SUBTLE', 'making proxy', false));
81
+ if (debug)
82
+ console.log(exports.promptHelpers.goColor('SUBTLE', 'for', typeof candidate, JSON.stringify({
83
+ doBlock,
84
+ debug
85
+ }, null, 2), false));
86
+ return new Proxy(candidate, {
87
+ get(target, key, receiver) {
88
+ if (debug)
89
+ console.log(exports.promptHelpers.goColor('SUBTLE', 'accessing proxied object', JSON.stringify({
90
+ key,
91
+ doBlock,
92
+ debug
93
+ }, null, 2), false));
94
+ if (doBlock === true)
95
+ throw Error('blocked');
96
+ if (Array.isArray(doBlock) && doBlock.includes(key))
97
+ throw Error('blocked');
98
+ const toReturn = Reflect.get(target, key, receiver);
99
+ return (0, exports.makeFunctionProxy)(toReturn, doBlock, debug);
100
+ },
101
+ set(target, key, value, receiver) {
102
+ if (debug)
103
+ console.log(exports.promptHelpers.goColor('SUBTLE', 'accessing proxied object', JSON.stringify({
104
+ key,
105
+ value,
106
+ doBlock,
107
+ debug
108
+ }, null, 2), false));
109
+ if (doBlock === true)
110
+ throw Error('blocked');
111
+ if (Array.isArray(doBlock) && doBlock.includes(key))
112
+ throw Error('blocked');
113
+ return Reflect.set(target, key, value, receiver);
114
+ },
115
+ apply(target, thisArg, argArray) {
116
+ if (debug)
117
+ console.log(exports.promptHelpers.goColor('SUBTLE', 'running function', JSON.stringify({ argArray }, null, 2), false));
118
+ if (doBlock === true)
119
+ throw Error('blocked');
120
+ if (typeof target === 'function')
121
+ return Reflect.apply(target, thisArg, argArray);
122
+ throw new Error('not a function');
123
+ },
124
+ has(target, key) {
125
+ if (debug)
126
+ console.log(exports.promptHelpers.goColor('SUBTLE', 'accessing proxied function', JSON.stringify({ key }), false));
127
+ if (doBlock === true)
128
+ throw Error('blocked');
129
+ return Reflect.has(target, key);
130
+ },
131
+ isExtensible( /* target */) {
132
+ return false;
133
+ }
134
+ });
135
+ };
136
+ exports.makeFunctionProxy = makeFunctionProxy;
137
+ /**
138
+ * @description - converts an "existing" command object into a proxy for both the existing and missing pieces so you can track the inputs and outputs
139
+ * @param {object} existing
140
+ * @param {boolean} doBlock
141
+ * @param {boolean} debug
142
+ */
143
+ const genericCommandProxy = (existing, doBlock, debug) => {
144
+ try {
145
+ const noop = (options) => options;
146
+ return new Proxy(existing, {
147
+ get(target, key, receiver) {
148
+ try {
149
+ if (Reflect.has(target, key)) {
150
+ return (0, exports.makeFunctionProxy)(Reflect.get(target, key, receiver), doBlock, debug);
151
+ }
152
+ if (typeof key === 'string' && /:/.test(key)) {
153
+ return (0, exports.makeFunctionProxy)({
154
+ projectFolder: null,
155
+ beforeExecuting: noop,
156
+ onCompleted: noop,
157
+ onError: noop,
158
+ }, doBlock, debug);
159
+ }
160
+ }
161
+ catch (err) {
162
+ console.error(err);
163
+ }
164
+ }
165
+ });
166
+ }
167
+ catch (err) {
168
+ console.error(err);
169
+ throw err;
170
+ }
171
+ };
172
+ exports.genericCommandProxy = genericCommandProxy;
173
+ /**
174
+ * @deprecated
175
+ * @description - Take commands and export safe commands.
176
+ * - Proxies the function of each command
177
+ * - Anytime the `authid` option is seen it will strip it out as this is coming from native.
178
+ * - Will replace the `authid` option with a value that is taken from a transient .project.json file. Note that the
179
+ * transient file will only exist if it was called properly.
180
+ * @param options
181
+ */
182
+ const makeSuiteCloudConfig = (options, authFolderMap, extras) => {
183
+ cleanup(['manifest.xml', 'deploy.xml'], process.cwd());
184
+ let authid = null;
185
+ let projectFolder = null;
186
+ let debugInJson = null;
187
+ let { debug } = { debug: false, ...extras };
188
+ try {
189
+ // make manifest
190
+ // temp
191
+ const projectJson = fs.readFileSync(nodePath.join(process.cwd(), '.project.json'), { encoding: 'utf8' });
192
+ ({ defaultAuthId: authid, defaultProjectFolder: projectFolder, debug: debugInJson } = {
193
+ defaultAuthId: null,
194
+ defaultProjectFolder: null,
195
+ debug: null,
196
+ ...JSON.parse(projectJson || "null")
197
+ });
198
+ if (projectFolder === null && authid !== null)
199
+ projectFolder = authid;
200
+ // debug in .project.json means it was requested on the command line so it is an override
201
+ if (debugInJson === true)
202
+ debug = true;
203
+ if (debugInJson === false)
204
+ debug = false;
205
+ if (authFolderMap && typeof authFolderMap === 'object') {
206
+ for (const [authMapKey, folders] of Object.entries(authFolderMap)) {
207
+ if (authMapKey !== authid)
208
+ continue;
209
+ if (!folders.includes(projectFolder))
210
+ throw new Error(`${authMapKey} is not allowed to work with folder ${projectFolder}. Check your suitecloud.config.js`);
211
+ }
212
+ }
213
+ const deferredJobs = [];
214
+ // delete the project.json files
215
+ if (projectFolder !== null) {
216
+ deferredJobs.push(() => cleanup(['manifest.xml', 'deploy.xml'], nodePath.join(process.cwd(), projectFolder)), () => makeManifest(nodePath.join(process.cwd(), projectFolder, 'manifest.xml'), projectFolder), () => makeDeploy(nodePath.join(process.cwd(), projectFolder, 'deploy.xml')));
217
+ }
218
+ else {
219
+ deferredJobs.push(() => makeManifest(nodePath.join(process.cwd(), 'manifest.xml'), 'unknown'), () => makeDeploy(nodePath.join(process.cwd(), 'deploy.xml')));
220
+ console.log('No project folder found ***************');
221
+ }
222
+ // for now execute them here as everything is synchronous so far
223
+ deferredJobs.forEach((job) => job());
224
+ if (debug)
225
+ console.log({ cwd: process.cwd() });
226
+ return new Proxy(options, {
227
+ get(outer, key, receiver) {
228
+ if (debug)
229
+ console.log('accessing outer', { key });
230
+ // in case this file is imported by another in order to read the commands
231
+ if (['then', 'catch', 'finally'].includes(key))
232
+ return Reflect.get(outer, key, receiver);
233
+ if (key === 'default')
234
+ return { ...options, authFolderMap, };
235
+ if (['projectFolder', 'defaultProjectFolder'].includes(key)) {
236
+ // temporary
237
+ return projectFolder;
238
+ }
239
+ if (key === 'commands')
240
+ return new Proxy(options?.commands || {}, {
241
+ get(target, command, receiver) {
242
+ if (debug)
243
+ console.log('accessing inner', { command });
244
+ let commandSpecificObject = Reflect.has(target, command)
245
+ ? Reflect.get(target, command, receiver)
246
+ : {};
247
+ return new Proxy(commandSpecificObject, {
248
+ get(target, property, receiver) {
249
+ if (debug)
250
+ console.log('accessing command', { property });
251
+ if (['projectFolder', 'defaultProjectFolder'].includes(command)) {
252
+ // temporary
253
+ return projectFolder + '2';
254
+ }
255
+ const value = Reflect.get(target, property, receiver);
256
+ if (typeof value === 'function')
257
+ return (0, exports.makeFunctionProxy)(value, false, debug);
258
+ // assume any other property is a function until we know more
259
+ return (0, exports.makeFunctionProxy)((options) => options, false, debug);
260
+ }
261
+ });
262
+ }
263
+ });
264
+ const value = Reflect.get(outer, key, receiver);
265
+ if (debug)
266
+ console.log({ key, value });
267
+ return value;
268
+ }
269
+ });
270
+ }
271
+ catch (error) {
272
+ if (debug)
273
+ console.error(error);
274
+ cleanup(['manifest.xml', 'deploy.xml', 'project.json', '.project.json'], nodePath.join(process.cwd()));
275
+ if (projectFolder !== null)
276
+ cleanup(['manifest.xml', 'deploy.xml', 'project.json', '.project.json'], nodePath.join(process.cwd(), projectFolder));
277
+ throw error;
278
+ }
279
+ cleanup(['manifest.xml', 'deploy.xml', 'project.json', '.project.json'], nodePath.join(process.cwd()));
280
+ if (projectFolder !== null)
281
+ cleanup(['manifest.xml', 'deploy.xml', 'project.json', '.project.json'], nodePath.join(process.cwd(), projectFolder));
282
+ };
283
+ exports.makeSuiteCloudConfig = makeSuiteCloudConfig;
284
+ /** @internal
285
+ * @example
286
+ * stacks['file:import'].beforeExecuting = []
287
+ * */
288
+ const stacks = {};
289
+ /**
290
+ * @description - curried
291
+ * @param {string} command - e.g. 'file:import'
292
+ * @param {string} [origin] - e.g. a property of the handling library that was used
293
+ * @param {string} [projectFolder]
294
+ */
295
+ const done = (command, origin, projectFolder) => {
296
+ /** @ internal
297
+ * @description - async because any one of the internal stacks might contain async methods
298
+ */
299
+ return (options) => {
300
+ if (stacks[command].onError.length === 0)
301
+ stacks[command].onError.push(
302
+ // add a default error handler that will help error forensics
303
+ (error) => onErrorHelper.detectOriginAndReturn(command, error));
304
+ if (stacks[command].onCompleted.length === 0)
305
+ stacks[command].onCompleted.push(
306
+ // add a default error handler that will help error forensics
307
+ (options) => options);
308
+ const starter = { stacked: true };
309
+ if (projectFolder)
310
+ starter[projectFolder] = projectFolder;
311
+ //
312
+ return Object.entries(stacks[command]).reduce((accumulator, [methodName, methods], i) => {
313
+ // iterate over them calling each method
314
+ accumulator[methodName] = async (originalOptions) => {
315
+ if (SHARED.DEBUG)
316
+ await exports.promptHelpers.promptUser({
317
+ message: `pause from \`done\` prior to calling ${methodName}[${i}]`,
318
+ });
319
+ // validation
320
+ if (['beforeExecuting'].includes(methodName) && !originalOptions?.command) {
321
+ process.stdout.write(exports.promptHelpers.goColor('SUBTLE', '\n', 'options passed in ', originalOptions));
322
+ throw new Error(`This must be called from a valid command`);
323
+ }
324
+ const { command } = originalOptions;
325
+ // validation
326
+ if (methods.length === 0)
327
+ throw new Error(`The stack for ${origin}:${command}:${methodName} cannot be empty`);
328
+ // DRY validation
329
+ const optionsTest = (opts, index, method) => {
330
+ if (typeof opts === null || !['object', 'string'].includes(typeof opts))
331
+ throw new Error(`handler[${index}] for ${origin}:${command}:${methodName} must return the options to be stackable`);
332
+ process.stdout.write(exports.promptHelpers.goColor('SUBTLE', '\n', 'pop off ', [method?.origin ?? origin, methodName].join(':')));
333
+ // call with', JSON.stringify(opts, null, 2), '\n'));
334
+ };
335
+ // console.log({methods}, methods.map((m) => [Reflect.get(m, 'origin'), Reflect.get(m, 'command')]));
336
+ const newOptions = await methods.reduce(async (toPass, method, i) => {
337
+ // // @ts-expect-error is optional
338
+ // process.stdout.write(promptHelpers.goColor('SUBTLE', '\n', method?.origin, '[',i,']'));
339
+ const awaitedOptions = await toPass;
340
+ // validate
341
+ optionsTest(awaitedOptions, i, method);
342
+ // only some methods technically need to return the options but we return them always
343
+ return method(awaitedOptions);
344
+ }, Promise.resolve(originalOptions))
345
+ .catch((err) => {
346
+ process.stdout.write(exports.promptHelpers.goColor('INFO', '\n', 'error from ', origin, ': '));
347
+ // // @ts-expect-error yes it does
348
+ process.stdout.write(exports.promptHelpers.goColor('WARN', err?.message, '\n'));
349
+ // console.error(err);
350
+ throw err;
351
+ });
352
+ // validate
353
+ optionsTest(newOptions, methods.length - 1);
354
+ // always force this cleaning of projectJson
355
+ if (['onCompleted', 'onError'].includes(methodName)) {
356
+ // projectJsonHelpers.updateProjectJson(process.cwd(), Boolean(options?.allowLoops), 0);
357
+ }
358
+ return newOptions;
359
+ };
360
+ return accumulator;
361
+ }, starter);
362
+ };
363
+ };
364
+ /**
365
+ * @description -
366
+ * - Be careful about what you return. Each function in the stack should return options BUT some of the properties in a function are effectively `readonly` --
367
+ * i.e. they are not frozen and do not behave readonly until the very last handler.
368
+ * e.g. if you modify the property `options.arguments.authid` in `beforeExecuting` then you will be able to
369
+ * but the final SDF internal handler will not read the updated value.
370
+ * - Further some functions do not need to export options, BUT this process will pass them on to the next. This is an
371
+ * opportunity to modify those options, but it is a rare cases so be careful
372
+ * @param {string} command - e.g. 'file:import'
373
+ * @returns {Function}
374
+ */
375
+ const stack = (command) => {
376
+ // if (!Reflect.has(stacks, command))
377
+ // process.stdout.write(promptHelpers.goColor('SUBTLE', 'overwriting stack for ', command, '|'));
378
+ // else
379
+ // process.stdout.write(promptHelpers.goColor('SUBTLE', 'creating stack for ', command, '|'));
380
+ // // process.stdout.write(goColor('SUBTLE', '\n', 'creating stack for ', methodName));
381
+ //
382
+ let origin = '';
383
+ // always re-initiate for a command
384
+ Reflect.set(stacks, command, {
385
+ beforeExecuting: [],
386
+ onCompleted: [],
387
+ onError: [],
388
+ });
389
+ /**
390
+ * @description
391
+ * @param {*} firstToStack
392
+ * @param {*[]} restToStack
393
+ * @returns {{stack: typeof stack; done: typeof done}}
394
+ */
395
+ const innerStack = (firstToStack, ...restToStack) => {
396
+ // for easier troubleshooting
397
+ const noop = () => {
398
+ throw new Error(`You forgot to call \`done\` for ${command} stack`);
399
+ };
400
+ noop.stack = innerStack;
401
+ noop.add = innerStack;
402
+ try {
403
+ if (Array.isArray(restToStack) && restToStack.length > 0) {
404
+ console.log(restToStack);
405
+ [firstToStack, ...restToStack].map((to) => innerStack(to));
406
+ }
407
+ else if (typeof firstToStack === 'function')
408
+ return innerStack(firstToStack());
409
+ //
410
+ else if (typeof firstToStack !== 'object')
411
+ throw new Error('You must provide a stackable object');
412
+ //
413
+ else {
414
+ origin = firstToStack._origin || origin;
415
+ if (!Reflect.has(firstToStack, 'onError')) {
416
+ // a default error handler that stamps the command
417
+ Reflect.set(firstToStack, 'onError', (error) => onErrorHelper.detectOriginAndReturn(command, error));
418
+ }
419
+ if (!Reflect.get(firstToStack, 'isStackable'))
420
+ throw new Error(`The handler ${Reflect.get(firstToStack, 'name') || 'unnamed'} must have property \`isStackable\``);
421
+ Object.entries(firstToStack).forEach(
422
+ /**
423
+ *
424
+ * @param methodName e.g. 'beforeExecuting'
425
+ * @param method
426
+ * @param i
427
+ */
428
+ ([methodName, method], i) => {
429
+ if (typeof method !== 'function')
430
+ return;
431
+ // safety for unknown methods
432
+ if (!Reflect.get(stacks[command], methodName))
433
+ Reflect.set(stacks[command], methodName, []);
434
+ // if (i === 0) process.stdout.write(goColor('SUBTLE', '\n', 'adding to stack for ', methodName));
435
+ // else process.stdout.write(goColor('SUBTLE', '.'));
436
+ if (Reflect.get(stacks, command)[methodName].includes(method)) {
437
+ console.log({ methodName, command });
438
+ throw new Error('thi sis already int he stack');
439
+ }
440
+ method.origin = origin;
441
+ method.command = command;
442
+ // process.stdout.write(promptHelpers.goColor('SUBTLE', '\nadding ', i, ':', command, ':', origin, '|', typeof method));
443
+ Reflect.get(stacks, command)[methodName].push(method);
444
+ });
445
+ }
446
+ // finish
447
+ noop.done = done(command, origin);
448
+ return noop;
449
+ }
450
+ catch (e) {
451
+ console.error(e);
452
+ throw e;
453
+ }
454
+ };
455
+ const noop = () => {
456
+ throw new Error(`You forgot to "add" to the \`stack\` for the ${command} stack`);
457
+ };
458
+ noop.stack = innerStack;
459
+ noop.add = innerStack;
460
+ noop.done = () => {
461
+ throw new Error(`You must add a handler to the ${command} stack before calling done`);
462
+ };
463
+ return noop;
464
+ };
465
+ exports.stack = stack;
466
+ const defaultStackable = () => ({
467
+ _origin: 'defaultStackable',
468
+ beforeExecuting: (options) => options,
469
+ onCompleted: (options) => options,
470
+ onError: (error) => onErrorHelper.detectOriginAndReturn('defaultStackable', error),
471
+ isStackable: true,
472
+ });
473
+ /** @internal */
474
+ const printOptions = (opts) => {
475
+ const origin = 'printOptions';
476
+ return {
477
+ _origin: origin,
478
+ isStackable: true,
479
+ beforeExecuting: async (options) => {
480
+ try {
481
+ process.stdout.write(exports.promptHelpers.goColor(opts.messageType, '\nargs:', process.argv));
482
+ process.stdout.write(exports.promptHelpers.goColor(opts.messageType, '\noptions:', JSON.stringify(options, null, 2)));
483
+ const SDFENV = Object.fromEntries(Object.entries(process.env).filter(([key]) => key.startsWith('SUITECLOUD')));
484
+ process.stdout.write(exports.promptHelpers.goColor(opts.messageType, '\nsdf:', JSON.stringify(SDFENV, null, 2)));
485
+ if (options.arguments.runhooks !== 'quiet' && opts.confirm === true && !spawnSuitecloudChild.isChildProcess()) {
486
+ const choices = { 'Y': 'Yes' };
487
+ await promptHelper.promptChoices({
488
+ choices,
489
+ displayChoices: choices,
490
+ question: 'Continue? (Y)',
491
+ default: choices['Y'],
492
+ });
493
+ }
494
+ }
495
+ catch (e) {
496
+ console.error(e);
497
+ throw e;
498
+ }
499
+ return options;
500
+ },
501
+ onCompleted: async (options) => {
502
+ process.stdout.write(exports.promptHelpers.goColor(opts.messageType, '\n', JSON.stringify(options, null, 2)));
503
+ return options;
504
+ },
505
+ onError: async (error) => {
506
+ process.stdout.write(exports.promptHelpers.goColor(opts.messageType, '\n', error));
507
+ return error;
508
+ }
509
+ };
510
+ };
511
+ /** @internal */
512
+ const fakeManifest = (features) => {
513
+ const origin = 'fakeManifest';
514
+ return {
515
+ _origin: origin,
516
+ isStackable: true,
517
+ /**
518
+ * @description - the only reliable way to get the manifest location is to know the project folder
519
+ * which does not come through options. You must get it from the project.JSON
520
+ * @param options
521
+ */
522
+ beforeExecuting: async (options) => {
523
+ const { defaultProjectFolder } = {
524
+ defaultProjectFolder: '',
525
+ ...await projectJsonHelpers.updateProjectJson({}, [options.projectPath])
526
+ };
527
+ if (!defaultProjectFolder)
528
+ throw (0, onErrorHelper_1.makeError)(origin, new Error('Failed to read project json at ' + options.projectPath));
529
+ const manifestPath = nodePath.join(options.projectPath, defaultProjectFolder, 'manifest.xml');
530
+ console.log({ manifestPath });
531
+ if (!fs.existsSync(manifestPath))
532
+ fs.writeFileSync(manifestPath, '');
533
+ return options;
534
+ }
535
+ };
536
+ };
537
+ /**
538
+ * @description - forces interactive mode
539
+ * @param options
540
+ */
541
+ const onlyInteractive = () => {
542
+ const origin = 'onlyInteractive';
543
+ return {
544
+ _origin: origin,
545
+ isStackable: true,
546
+ beforeExecuting: async (options) => {
547
+ if (options.interactive)
548
+ return options;
549
+ // only allow interactive mode
550
+ if (process.argv.includes('-i'))
551
+ return options;
552
+ throw onErrorHelper.makeError(origin, new Error(`${options?.command} is currently only allowing interactive mode (-i))`));
553
+ }
554
+ };
555
+ };
556
+ /**
557
+ * @internal
558
+ */
559
+ const notSupported = () => {
560
+ const origin = 'notSupported';
561
+ return {
562
+ _origin: origin,
563
+ isStackable: true,
564
+ beforeExecuting: async (options) => {
565
+ if (!/\bFileCabinet\b/.test(process.cwd()))
566
+ throw onErrorHelper.makeError(origin, new Error(`\n ${options.command} not supported from ${process.cwd()} yet`));
567
+ return options;
568
+ },
569
+ };
570
+ };
571
+ /**
572
+ * @internal
573
+ * @description - Prompt for which folder to use -- only useful at the root level
574
+ */
575
+ const verifyFolderFromRoot = () => {
576
+ const origin = 'verifyFolderFromRoot';
577
+ return {
578
+ _origin: origin,
579
+ isStackable: true,
580
+ beforeExecuting: async (options) => {
581
+ // verify the current root from the project JSON
582
+ const { defaultProjectFolder } = await projectJsonHelpers.readProjectJson([]);
583
+ console.log(options);
584
+ if (process.cwd() === pathHelpers.getRootOfProject()) {
585
+ const potentials = await pathHelpers.findMatchingDirectories(process.cwd(),
586
+ // length/depth of 3. first test must be to match account number (folder)
587
+ [/^(td)?\d+/, /^\w+$/, /^\w+$/, /^\w+$/]);
588
+ const filtered = potentials.filter((p) => /\bFileCabinet$/.test(p));
589
+ const displayChoices = filtered
590
+ .map((f) => f.replace(/^.*nsaccounts\b.((td)?\d+.*)$/, '$1'))
591
+ .map((x) => {
592
+ const [...rest] = x.split(/[\\\/]/);
593
+ const last = rest.pop();
594
+ if (last === 'FileCabinet')
595
+ return `${rest.join('/')}${(0, promptHelpers_1.goColor)('SUBTLE', '/', last)}`;
596
+ return x;
597
+ });
598
+ const choices = filtered
599
+ .map((f) => f.replace(/^.*nsaccounts\b.((td)?\d+.*?)(\W?\bFileCabinet.*)?$/, '$1'));
600
+ console.log({ choices });
601
+ const folderChoice = await promptHelper.promptChoices({
602
+ choices,
603
+ displayChoices,
604
+ question: `Which folder to use? ${(0, promptHelpers_1.goColor)('SUBTLE', 'current: ', [options.projectPath, defaultProjectFolder].join('/'))}`,
605
+ default: null
606
+ });
607
+ console.log({ folderChoice }, folderChoice !== defaultProjectFolder);
608
+ if (folderChoice !== defaultProjectFolder) {
609
+ // force a restart
610
+ await projectJsonHelpers.updateProjectJson({ defaultProjectFolder: folderChoice }, []);
611
+ throw onErrorHelper.makeError(origin, new Error('Must restart due to folder change'));
612
+ }
613
+ return options;
614
+ }
615
+ }
616
+ };
617
+ };
618
+ // default
619
+ /**
620
+ * @description - getters so that stack is not invoked until called and they are readonly
621
+ */
622
+ exports.defaultCommands = {
623
+ get 'account:manageauth'() {
624
+ return (0, exports.stack)('account:manageauth')
625
+ .stack(defaultStackable)
626
+ // .stack(printOptions({messageType: 'SUBTLE'}))
627
+ .stack(accountManageAuth.saveList())
628
+ .stack(accountManageAuth.betterList())
629
+ .done();
630
+ },
631
+ get 'account:setup:ci'() {
632
+ return (0, exports.stack)('account:setup:ci')
633
+ .stack(defaultStackable)
634
+ .stack(printOptions({ messageType: 'SUBTLE' }))
635
+ .stack(fakeManifest({}))
636
+ .stack(accountSetup.chooseExistingCertificate())
637
+ .stack(accountSetup.promptForAccount())
638
+ .stack(accountSetup.promptForAuthId())
639
+ .stack(accountSetup.askToReplace())
640
+ .stack(printOptions({ messageType: 'INFO', confirm: true }))
641
+ // .stack(forceAccountInName()) // does not make sense for default
642
+ .done();
643
+ },
644
+ get 'account:setup'() {
645
+ return (0, exports.stack)('account:setup')
646
+ .stack(defaultStackable).done();
647
+ },
648
+ get 'object:import'() {
649
+ return (0, exports.stack)('object:import')
650
+ .stack(notSupported())
651
+ .stack(accountManageAuth.promptForAccountChoice())
652
+ .done();
653
+ },
654
+ get 'object:list'() {
655
+ return (0, exports.stack)('object:list')
656
+ .stack(notSupported())
657
+ .stack(accountManageAuth.promptForAccountChoice())
658
+ .done();
659
+ },
660
+ get 'file:create'() {
661
+ return (0, exports.stack)('file:create')
662
+ .stack(notSupported())
663
+ .stack(accountManageAuth.promptForAccountChoice())
664
+ .done();
665
+ },
666
+ get 'file:import'() {
667
+ return (0, exports.stack)('file:import')
668
+ .stack(notSupported())
669
+ /*.stack(
670
+ accountManageAuth.promptForAccountChoice()
671
+ )*/ .done();
672
+ },
673
+ get 'file:list'() {
674
+ return (0, exports.stack)('file:list')
675
+ .stack(notSupported())
676
+ .stack(accountManageAuth.promptForAccountChoice())
677
+ .done();
678
+ },
679
+ get 'file:upload'() {
680
+ return (0, exports.stack)('file:upload')
681
+ .stack(notSupported())
682
+ .stack(accountManageAuth.promptForAccountChoice()).done();
683
+ },
684
+ get 'object:update'() {
685
+ return (0, exports.stack)('object:update')
686
+ .stack(notSupported())
687
+ .stack(accountManageAuth.promptForAccountChoice()).done();
688
+ },
689
+ get 'project:adddependencies'() {
690
+ return (0, exports.stack)('project:adddependencies')
691
+ .stack(notSupported())
692
+ .done();
693
+ },
694
+ get 'project:create'() {
695
+ return (0, exports.stack)('project:create')
696
+ .stack(projectCreates.rootProjectChoices())
697
+ .done();
698
+ },
699
+ get 'project:deploy'() {
700
+ return (0, exports.stack)('project:deploy')
701
+ .stack(notSupported())
702
+ .stack(accountManageAuth.promptForAccountChoice())
703
+ .done();
704
+ },
705
+ get 'project:package'() {
706
+ return (0, exports.stack)('project:package')
707
+ .stack(notSupported())
708
+ .stack(accountManageAuth.promptForAccountChoice())
709
+ .done();
710
+ },
711
+ get 'project:validate'() {
712
+ return (0, exports.stack)('project:validate')
713
+ .stack(notSupported())
714
+ .stack(accountManageAuth.promptForAccountChoice())
715
+ .done();
716
+ },
717
+ get help() {
718
+ return (0, exports.stack)('help')
719
+ .stack(defaultStackable).done();
720
+ },
721
+ };
722
+ /**
723
+ * @description - getters
724
+ */
725
+ exports.caseCommands = {
726
+ get 'custom:hook'() {
727
+ return (0, exports.stack)('custom:hook')
728
+ .stack((0, compiless_1.compileSuiteScript)([]))
729
+ .stack((0, watchss_1.watchSuiteScript)('sdf.config.js', ['module.d.ts']))
730
+ .done();
731
+ },
732
+ get 'account:manageauth'() {
733
+ return (0, exports.stack)('account:manageauth')
734
+ .stack(defaultStackable)
735
+ //.stack(printOptions({messageType: 'SUBTLE'})) // this is very noisy here on success
736
+ .stack(accountManageAuth.saveList())
737
+ .stack(accountManageAuth.betterList())
738
+ .done();
739
+ },
740
+ get 'account:setup:ci'() {
741
+ return (0, exports.stack)('account:setup:ci')
742
+ .stack(defaultStackable)
743
+ .stack(printOptions({ messageType: 'SUBTLE' }))
744
+ .stack(accountSetup.chooseExistingCertificate())
745
+ .stack(accountSetup.promptForAccount())
746
+ .stack(accountSetup.promptForAuthId())
747
+ .stack(accountSetup.forceAccountInName())
748
+ .stack(fileImports.detectManifest())
749
+ .stack(printOptions({ messageType: 'INFO' }))
750
+ .done();
751
+ },
752
+ get 'account:setup'() {
753
+ return (0, exports.stack)('account:setup')
754
+ .stack(defaultStackable)
755
+ .done();
756
+ },
757
+ get 'file:create'() {
758
+ return (0, exports.stack)('file:create')
759
+ .stack(notSupported())
760
+ .stack(accountManageAuth.promptForAccountChoice())
761
+ .done();
762
+ },
763
+ get 'file:import'() {
764
+ return (0, exports.stack)('file:import')
765
+ .stack(accountManageAuth.promptForAccountChoice())
766
+ // prompt if they didn't give us one
767
+ .stack(fileUpload.promptForPath({
768
+ message: 'Enter a file or Glob to import (e.g. ./**/*.js)'
769
+ }))
770
+ .stack(printOptions({ messageType: 'INFO', confirm: true }))
771
+ .stack(fileImports.downloadForDiff())
772
+ // could be an xml
773
+ .stack(fileUpload.getFilesFromDeployXml())
774
+ // or could be a glob or partial
775
+ .stack(fileImports.fixFileImportPaths())
776
+ .stack(fileUpload.confirmFileList())
777
+ .stack(fileImports.detectManifest())
778
+ // .stack(printOptions({messageType: 'SUBTLE'}))
779
+ .done();
780
+ },
781
+ get 'file:list'() {
782
+ return (0, exports.stack)('file:list')
783
+ .stack(printOptions({ messageType: 'INFO', confirm: true }))
784
+ .stack(accountManageAuth.promptForAccountChoice())
785
+ .stack(printOptions({ messageType: 'INFO', confirm: true }))
786
+ .stack(fileList.saveFileListToTemp())
787
+ .done();
788
+ },
789
+ get 'file:upload'() {
790
+ return (0, exports.stack)('file:upload')
791
+ .stack(printOptions({ messageType: 'INFO', confirm: true }))
792
+ .stack(accountManageAuth.promptForAccountChoice())
793
+ // prompt if they didn't give us one
794
+ .stack(fileUpload.promptForPath({
795
+ message: 'Enter a file or Glob to upload (e.g. ./**/*.js)'
796
+ }))
797
+ // could be an xml
798
+ .stack(fileUpload.getFilesFromDeployXml())
799
+ // or could be a glob or partial
800
+ .stack(fileUpload.fixFileUploadPaths())
801
+ .stack(fileUpload.confirmFileList())
802
+ // .stack(fileUpload.compileFilesPrompt()) // use nodemon instead
803
+ .stack(fileUpload.testFilesPrompt())
804
+ .done();
805
+ },
806
+ get 'object:import'() {
807
+ return (0, exports.stack)('object:import')
808
+ // .stack(notSupported())
809
+ .stack(printOptions({ messageType: 'INFO', confirm: true }))
810
+ .stack(accountManageAuth.promptForAccountChoice())
811
+ .stack(objectImports.forceDestination())
812
+ .stack(printOptions({ messageType: 'INFO', confirm: true }))
813
+ .stack(objectImports.forceTypeAll())
814
+ .stack(fileUpload.promptForPath({
815
+ message: `Enter an object to upload. ${exports.promptHelpers.goColor('SUBTLE', '\n Wildcard is * \n \`type\` prefix is required but can be a wildcard (e.g. customrecord:custrecord_acs*)')}`
816
+ }))
817
+ .stack(fileUpload.getFilesFromDeployXml())
818
+ // .stack(printOptions({messageType: 'INFO', confirm: true}))
819
+ // or could be a glob or partial
820
+ .stack(objectImports.fixObjectImportPaths())
821
+ .stack(fileUpload.confirmFileList())
822
+ // .stack(objectImports.importGlobOrXml())
823
+ // organize into folders
824
+ .stack(objectImports.createObjectsDir())
825
+ .done();
826
+ },
827
+ get 'object:list'() {
828
+ return (0, exports.stack)('object:list')
829
+ .stack(printOptions({ messageType: 'INFO', confirm: true }))
830
+ .stack(accountManageAuth.promptForAccountChoice())
831
+ .stack(objectLists.saveObjectListToTemp())
832
+ .stack(objectLists.createFoldersForAllTypes())
833
+ .done();
834
+ },
835
+ get 'object:update'() {
836
+ return (0, exports.stack)('object:update')
837
+ .stack(notSupported())
838
+ .stack(accountManageAuth.promptForAccountChoice()).done();
839
+ },
840
+ get 'project:adddependencies'() {
841
+ return (0, exports.stack)('project:adddependencies')
842
+ .stack(notSupported())
843
+ .done();
844
+ },
845
+ get 'project:create'() {
846
+ return (0, exports.stack)('project:create')
847
+ .stack(notSupported())
848
+ .stack(accountManageAuth.promptForAccountChoice()).stack(projectCreates.projectJsonPromptAndEscape()).done();
849
+ },
850
+ get 'project:deploy'() {
851
+ return (0, exports.stack)('project:deploy')
852
+ .stack(projectDeploys.logErrors())
853
+ .stack(accountManageAuth.promptForAccountChoice()).stack(projectDeploys.forceLog())
854
+ .stack(projectDeploys.offerValidate())
855
+ .stack(projectDeploys.promptForDeployFile())
856
+ .stack(projectDeploys.askForDryrun())
857
+ .stack(projectDeploys.compileBeforeDeploy())
858
+ .stack(projectDeploys.runTestBeforeDeploy()
859
+ // projectDeploy.makeProjectDeployV1()
860
+ )
861
+ .done();
862
+ },
863
+ get 'project:package'() {
864
+ return (0, exports.stack)('project:package')
865
+ .stack(notSupported())
866
+ .stack(projectPackages.watchAndCompile())
867
+ .stack(printOptions({ messageType: "SUBTLE" }))
868
+ .stack(onlyInteractive())
869
+ .done();
870
+ },
871
+ get 'project:validate'() {
872
+ return (0, exports.stack)('project:validate')
873
+ .stack(notSupported())
874
+ .stack(projectValidates.forceLog())
875
+ .stack(projectValidates.promptServer())
876
+ // .stack(printOptions({messageType: 'SUBTLE'}))
877
+ .stack(projectValidates.runTests())
878
+ .stack(projectValidates.validateJest())
879
+ .stack(accountManageAuth.promptForAccountChoice()).done();
880
+ },
881
+ get help() {
882
+ return (0, exports.stack)('help')
883
+ .stack(defaultStackable).done();
884
+ }
885
+ };
886
+ /**
887
+ * @description - THIS MUST BE SYNCHRONOUS - you will get errors if the account is not setup.
888
+ * The way around that is to prompt the user and then they can try again
889
+ * @param options
890
+ * @param {object} extra
891
+ * @param {string[]} [extra.clean] - Files to remove after running. Default is `deploy.xml` and `.project.json`. `sdftemp.*` files are always removed
892
+ * @param {function} [extra.onExit] - callback that run on Exit of the process. Whatever string[] are returned will be printed as lines to the console
893
+ * @param {module} module
894
+ */
895
+ const makeSafeExports = (options, extra, module) => {
896
+ try {
897
+ // if launched by something like:
898
+ // nodemon ./suitecloud.config.js watch -e ts --ignore module.d.ts
899
+ if (process.pid !== process.ppid && /^\d+$/.test(`${process.ppid}`) && process.argv.includes('watch')) {
900
+ // compile
901
+ return;
902
+ }
903
+ //Todo: if no local jest.config file exists then create one
904
+ // jobs when the process was spawned "normally from command line"
905
+ if (!spawnSuitecloudChild.isChildProcess()) {
906
+ // clean these up on start-up
907
+ tempFileHelper.removeTempFiles('sdftemp.');
908
+ // parent processes subscribe to clean-up
909
+ process.once('exit', async (e) => {
910
+ // console.log('close');
911
+ // do not delete 'tsconfig.json'
912
+ const toClean = Array.isArray(extra.clean) ? extra.clean : ['deploy.xml', '.project.json'];
913
+ process.stdout.write(exports.promptHelpers.goColor('SUBTLE', '\ncleaning up '));
914
+ cleanup(toClean, process.cwd());
915
+ if (!e)
916
+ process.stdout.write('\n✅');
917
+ process.stdout.write('\n');
918
+ if (e > 0)
919
+ tempFileHelper.removeTempFiles('sdftemp.');
920
+ if (typeof extra.onExit === 'function') {
921
+ const result = await extra.onExit(process);
922
+ if (Array.isArray(result))
923
+ result
924
+ .filter((r) => (typeof r === 'string'))
925
+ .forEach((msg) => process.stdout.write(` ${msg}\n`));
926
+ }
927
+ });
928
+ }
929
+ Object.assign(options, projectJsonHelpers.readProjectJsonSync([]));
930
+ // projectJson defaults
931
+ if (extra.autoCreateProjectJson && !spawnSuitecloudChild.isChildProcess()) {
932
+ // note: do not need project json anymore
933
+ projectJsonHelpers.updateProjectJsonSync({
934
+ defaultAuthId: options.defaultAuthId || 'root',
935
+ defaultProjectFolder: options.defaultProjectFolder || 'demo'
936
+ }, [], 'project.json', false);
937
+ }
938
+ // look for loops
939
+ // SHARED.DEBUG = true; // Boolean(extra?.debug);
940
+ //if (doConfig) {
941
+ Object.keys(exports.defaultCommands).forEach((command) => {
942
+ if (!Reflect.get(options.commands, command)) {
943
+ // use default
944
+ Reflect.set(options.commands, command, exports.defaultCommands[command]);
945
+ }
946
+ const fromOptions = options.commands[command];
947
+ });
948
+ // @ts-expect-error yes it does
949
+ options.commands = (0, exports.genericCommandProxy)(options.commands, Boolean(extra.block), Boolean(extra.debug));
950
+ module.exports = options;
951
+ return module.exports;
952
+ }
953
+ catch (e) {
954
+ console.error(e);
955
+ throw e;
956
+ }
957
+ };
958
+ exports.makeSafeExports = makeSafeExports;
959
+ //# sourceMappingURL=safeCommands.js.map