@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.
- package/.idea/compiler.xml +6 -0
- package/.idea/git_toolbox_blame.xml +6 -0
- package/.idea/git_toolbox_prj.xml +15 -0
- package/.idea/misc.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/suitecloud-stacker.iml +9 -0
- package/.idea/vcs.xml +6 -0
- package/CONTRIBUTING.md +72 -0
- package/README.md +242 -0
- package/bin/updateModule.d.ts +6 -0
- package/bin/updateModule.js +12 -0
- package/commands/CONTRIBUTING.md +7 -0
- package/commands/accountManageauth.d.ts +93 -0
- package/commands/accountManageauth.js +228 -0
- package/commands/accountSetup.d.ts +56 -0
- package/commands/accountSetup.js +218 -0
- package/commands/customhook/compiless.d.ts +10 -0
- package/commands/customhook/compiless.js +46 -0
- package/commands/customhook/watchss.d.ts +14 -0
- package/commands/customhook/watchss.js +77 -0
- package/commands/fileImport.d.ts +31 -0
- package/commands/fileImport.js +503 -0
- package/commands/fileList.d.ts +19 -0
- package/commands/fileList.js +40 -0
- package/commands/fileUpload.d.ts +52 -0
- package/commands/fileUpload.js +355 -0
- package/commands/generic.d.ts +5 -0
- package/commands/generic.js +13 -0
- package/commands/objectImport.d.ts +32 -0
- package/commands/objectImport.js +287 -0
- package/commands/objectList.d.ts +13 -0
- package/commands/objectList.js +78 -0
- package/commands/projectCreate.d.ts +31 -0
- package/commands/projectCreate.js +506 -0
- package/commands/projectDeploy.d.ts +25 -0
- package/commands/projectDeploy.js +371 -0
- package/commands/projectPackage.d.ts +10 -0
- package/commands/projectPackage.js +32 -0
- package/commands/projectValidate.d.ts +21 -0
- package/commands/projectValidate.js +112 -0
- package/commands/sdfAcs_authmap.d.ts +15 -0
- package/commands/sdfAcs_authmap.js +26 -0
- package/commands/sdfAcs_clean.d.ts +20 -0
- package/commands/sdfAcs_clean.js +22 -0
- package/deleteManifest.cjs +11 -0
- package/demo.md +26 -0
- package/index.d.ts +284 -0
- package/lib/MakeJestTestsFromDeploy.d.ts +13 -0
- package/lib/MakeJestTestsFromDeploy.js +60 -0
- package/lib/addGitKeep.d.ts +5 -0
- package/lib/addGitKeep.js +40 -0
- package/lib/addSdfObjectDirs.d.ts +5 -0
- package/lib/addSdfObjectDirs.js +16 -0
- package/lib/callCli.d.ts +7 -0
- package/lib/callCli.js +26 -0
- package/lib/compileHelper.d.ts +44 -0
- package/lib/compileHelper.js +196 -0
- package/lib/deleteProjectJson.d.ts +6 -0
- package/lib/deleteProjectJson.js +16 -0
- package/lib/deployFileHelper.d.ts +77 -0
- package/lib/deployFileHelper.js +249 -0
- package/lib/handleRootProjectJson.d.ts +10 -0
- package/lib/handleRootProjectJson.js +30 -0
- package/lib/isProd.d.ts +9 -0
- package/lib/isProd.js +13 -0
- package/lib/logHelper.d.ts +5 -0
- package/lib/logHelper.js +13 -0
- package/lib/logger.d.ts +6 -0
- package/lib/logger.js +10 -0
- package/lib/makeDeployXml.d.ts +6 -0
- package/lib/makeDeployXml.js +30 -0
- package/lib/makeJest.d.ts +12 -0
- package/lib/makeJest.js +58 -0
- package/lib/makeManifestXml.d.ts +6 -0
- package/lib/makeManifestXml.js +21 -0
- package/lib/makeProjectJson.d.ts +6 -0
- package/lib/makeProjectJson.js +16 -0
- package/lib/onErrorHelper.d.ts +31 -0
- package/lib/onErrorHelper.js +93 -0
- package/lib/pathHelpers.d.ts +133 -0
- package/lib/pathHelpers.js +428 -0
- package/lib/pause.d.ts +6 -0
- package/lib/pause.js +10 -0
- package/lib/projectJsonHelpers.d.ts +29 -0
- package/lib/projectJsonHelpers.js +92 -0
- package/lib/promptHelpers.d.ts +77 -0
- package/lib/promptHelpers.js +195 -0
- package/lib/removeFiles.d.ts +20 -0
- package/lib/removeFiles.js +46 -0
- package/lib/sdf.d.ts +11 -0
- package/lib/sdf.js +158 -0
- package/lib/spawnSuitecloudChild.d.ts +30 -0
- package/lib/spawnSuitecloudChild.js +88 -0
- package/lib/switchAuth.d.ts +17 -0
- package/lib/switchAuth.js +23 -0
- package/lib/tempFileHelper.d.ts +29 -0
- package/lib/tempFileHelper.js +70 -0
- package/lib/updateModule.d.ts +10 -0
- package/lib/updateModule.js +79 -0
- package/lib/validators.d.ts +12 -0
- package/lib/validators.js +25 -0
- package/package.json +38 -0
- package/safeCommands.d.ts +95 -0
- package/safeCommands.js +959 -0
- package/sdf.config.js +15 -0
- package/sdf.exe.js +16 -0
- package/templates/customizations.projectroot.d.ts +74 -0
- package/templates/makeModuleTypeDef.d.ts +5 -0
- package/templates/makeModuleTypeDef.js +29 -0
- package/templates/sdfGitIgnore.txt +42 -0
- package/templates/suitecloud.config.js +17 -0
- package/templates/tsconfig.ss21.projectroot.json +64 -0
- package/types/colors.d.ts +43 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file sdf/commands/fileImport.ts
|
|
3
|
+
* @author Gerald Gillespie <gerald.gillespie@fullscript.com>
|
|
4
|
+
*/
|
|
5
|
+
import { FileImportCommand, SdfCommand } from "index";
|
|
6
|
+
/**
|
|
7
|
+
* @description - will spawn a separate `file:import` job that has a different folder reference
|
|
8
|
+
* - to put the file in a temp folder
|
|
9
|
+
* - in a way this is calling itself because it is the same task. related handlers use child detection
|
|
10
|
+
* - if the `customoptions` is used then a second authid can be used for third compare source (e.g. `altauth:123_SBX2`)
|
|
11
|
+
*/
|
|
12
|
+
export declare const downloadForDiff: () => SdfCommand;
|
|
13
|
+
/**
|
|
14
|
+
* @description - very similar tothe fixFileUploadPaths except we need to compare against netsuite
|
|
15
|
+
* Also we don't filter out any files
|
|
16
|
+
*/
|
|
17
|
+
export declare const fixFileImportPaths: () => SdfCommand;
|
|
18
|
+
/**
|
|
19
|
+
* @description -
|
|
20
|
+
* @deprecated - there are better combos now -- no need to prompt for globs as every path is technically a glob
|
|
21
|
+
* @param {{excludeproperties: boolean}} forceOptions
|
|
22
|
+
* @returns {_origin: 'importRegex';}
|
|
23
|
+
*/
|
|
24
|
+
export declare const importFileOrPattern: (forceOptions: {
|
|
25
|
+
excludeproperties: boolean;
|
|
26
|
+
}) => SdfCommand;
|
|
27
|
+
/**
|
|
28
|
+
* @description - file:import requires a manifest file when not doing the diff option
|
|
29
|
+
*/
|
|
30
|
+
export declare const detectManifest: () => SdfCommand;
|
|
31
|
+
export declare const beforeExecuting: FileImportCommand['beforeExecuting'];
|
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file sdf/commands/fileImport.ts
|
|
4
|
+
* @author Gerald Gillespie <gerald.gillespie@fullscript.com>
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.beforeExecuting = exports.detectManifest = exports.importFileOrPattern = exports.fixFileImportPaths = exports.downloadForDiff = void 0;
|
|
8
|
+
const console = require("node:console");
|
|
9
|
+
const cp = require("node:child_process");
|
|
10
|
+
const nodePath = require("node:path");
|
|
11
|
+
const promptHelpers_1 = require("../lib/promptHelpers");
|
|
12
|
+
const tempFileHelper = require("../lib/tempFileHelper");
|
|
13
|
+
const pathHelpers_1 = require("../lib/pathHelpers");
|
|
14
|
+
const onErrorHelper = require("../lib/onErrorHelper");
|
|
15
|
+
const minimatch_1 = require("minimatch");
|
|
16
|
+
const spawnSuitecloud = require("../lib/spawnSuitecloudChild");
|
|
17
|
+
const tempFileHelper_1 = require("../lib/tempFileHelper");
|
|
18
|
+
const makeManifest = require("../lib/makeManifestXml");
|
|
19
|
+
const getListRoot = (proposedFolder) => {
|
|
20
|
+
switch (true) {
|
|
21
|
+
case /\bTemplates\b/.test(proposedFolder):
|
|
22
|
+
return '/Templates';
|
|
23
|
+
case /\bWeb Site Hosting Files\b/.test(proposedFolder):
|
|
24
|
+
return 'Web Site Hosting Files';
|
|
25
|
+
case /\bSuiteScripts\b/.test(proposedFolder):
|
|
26
|
+
default:
|
|
27
|
+
return '/SuiteScripts';
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* @description - will spawn a separate `file:import` job that has a different folder reference
|
|
32
|
+
* - to put the file in a temp folder
|
|
33
|
+
* - in a way this is calling itself because it is the same task. related handlers use child detection
|
|
34
|
+
* - if the `customoptions` is used then a second authid can be used for third compare source (e.g. `altauth:123_SBX2`)
|
|
35
|
+
*/
|
|
36
|
+
const downloadForDiff = () => {
|
|
37
|
+
const origin = 'downloadForDiff';
|
|
38
|
+
const tempFile = 'downloadForDiff.json';
|
|
39
|
+
const optionsObserved = {};
|
|
40
|
+
return {
|
|
41
|
+
_origin: origin, isStackable: true,
|
|
42
|
+
beforeExecuting: async (options) => {
|
|
43
|
+
try {
|
|
44
|
+
Object.assign(optionsObserved, options);
|
|
45
|
+
if (!options.arguments.calledfromcomparefiles)
|
|
46
|
+
return options;
|
|
47
|
+
const isQuiet = options.arguments.runhooks === 'quiet';
|
|
48
|
+
const [secondAuth] = (options.arguments.customoptions || []).flatMap((cust) => {
|
|
49
|
+
if (!/^altauth:/.test(cust))
|
|
50
|
+
return [];
|
|
51
|
+
return [cust.split(':').pop()];
|
|
52
|
+
});
|
|
53
|
+
// the child import should not loop an import
|
|
54
|
+
if (spawnSuitecloud.isChildProcess())
|
|
55
|
+
return options;
|
|
56
|
+
// guard
|
|
57
|
+
if (!Array.isArray(options.arguments.paths))
|
|
58
|
+
throw onErrorHelper.makeError(origin, new Error('Diff compare needs an array.'));
|
|
59
|
+
// single length array
|
|
60
|
+
if (options.arguments.paths.length === 0)
|
|
61
|
+
throw onErrorHelper.makeError(origin, new Error('Diff compare supports exactly 1 file at a time currently.'));
|
|
62
|
+
// use the first file
|
|
63
|
+
const [file] = options.arguments.paths;
|
|
64
|
+
// normalize to file system
|
|
65
|
+
// e.g. /User/geraldgillespie/project/src/FileCabinet/SuiteScripts/blah.js
|
|
66
|
+
let fixed = (0, pathHelpers_1.getAbsolutePath)({
|
|
67
|
+
projectPath: options.projectPath,
|
|
68
|
+
executionPath: options.executionPath,
|
|
69
|
+
filePath: file,
|
|
70
|
+
});
|
|
71
|
+
// await promptUser({message: 'pause'});
|
|
72
|
+
// check if you have it locally
|
|
73
|
+
if (!await (0, pathHelpers_1.hasFile)(fixed) && !/\btemp\b.FileCabinet/.test(fixed)) {
|
|
74
|
+
throw onErrorHelper.makeError(origin, new Error('You do not have this file locally ' + fixed));
|
|
75
|
+
}
|
|
76
|
+
// finish the fix for SDF
|
|
77
|
+
// e.g. /SuiteScripts/blah.js
|
|
78
|
+
fixed = fixed.replace(/^.*(.\bSuiteScripts.*)$/, '$1');
|
|
79
|
+
{
|
|
80
|
+
// child process will save to temp
|
|
81
|
+
// mktemp for the file
|
|
82
|
+
// reset this array
|
|
83
|
+
options.arguments.paths = [];
|
|
84
|
+
// copy suitecloud there
|
|
85
|
+
const tempLocation = await (0, pathHelpers_1.makeTempDirForSdf)(options.projectPath);
|
|
86
|
+
const tempProjectFolder = (0, pathHelpers_1.getRelativeOf)(process.cwd(), tempLocation);
|
|
87
|
+
const [newFile, secondFile] = await Promise.all([
|
|
88
|
+
options.authId, secondAuth
|
|
89
|
+
]
|
|
90
|
+
.filter(Boolean)
|
|
91
|
+
.map(async (auth) => {
|
|
92
|
+
const childArgs = [
|
|
93
|
+
'--paths', fixed,
|
|
94
|
+
'--calledfromcomparefiles',
|
|
95
|
+
'--excludeproperties',
|
|
96
|
+
'--project', tempProjectFolder,
|
|
97
|
+
'--noconfig',
|
|
98
|
+
];
|
|
99
|
+
if (auth)
|
|
100
|
+
childArgs.push('--authid', auth);
|
|
101
|
+
['config'].forEach((keep) => {
|
|
102
|
+
if (Reflect.has(options.arguments, keep))
|
|
103
|
+
childArgs.push(`--${keep}`, Reflect.get(options.arguments, keep));
|
|
104
|
+
});
|
|
105
|
+
// trigger the import for it in the temp folder
|
|
106
|
+
const errorCode = await spawnSuitecloud.createAsync({
|
|
107
|
+
command: 'file:import',
|
|
108
|
+
args: childArgs,
|
|
109
|
+
interact: true,
|
|
110
|
+
// spawns in a separate location but is still a child process
|
|
111
|
+
});
|
|
112
|
+
if (errorCode !== 0)
|
|
113
|
+
process.exit(errorCode);
|
|
114
|
+
const dataJson = await (0, tempFileHelper_1.consumeTempFile)(tempFile);
|
|
115
|
+
const parsedData = JSON.parse(dataJson);
|
|
116
|
+
return parsedData.fullPath;
|
|
117
|
+
}));
|
|
118
|
+
let diffTool = process.env.SUITECLOUD_DIFF_TOOL;
|
|
119
|
+
// console.log(process.env);
|
|
120
|
+
const nag = async () => {
|
|
121
|
+
process.stdout.write((0, promptHelpers_1.goColor)('INFO', `\nSet your environment variable ${(0, promptHelpers_1.goColor)('HIGHLIGHT', 'SUITECLOUD_DIFF_TOOL')}${(0, promptHelpers_1.goColor)('INFO', ' to avoid this prompt in the future')}`));
|
|
122
|
+
diffTool = await (0, promptHelpers_1.promptUser)({ message: 'What is your difftool?' });
|
|
123
|
+
return diffTool;
|
|
124
|
+
};
|
|
125
|
+
while (!diffTool && !isQuiet) {
|
|
126
|
+
await nag();
|
|
127
|
+
}
|
|
128
|
+
const currentFile = (0, pathHelpers_1.joinPaths)(options.projectPath, 'FileCabinet', fixed);
|
|
129
|
+
// const thirdFile =
|
|
130
|
+
// launch diff tool
|
|
131
|
+
// Spawn a new process (e.g., launching another Node script)
|
|
132
|
+
console.log([diffTool, ['diff', currentFile, newFile, secondFile]]);
|
|
133
|
+
const fileArgs = [newFile, currentFile, secondFile].filter(Boolean).map((f) => `"${f}"`);
|
|
134
|
+
const diffChildProc = cp.spawn(diffTool, ['diff', ...fileArgs], {
|
|
135
|
+
detached: true, // Allows the child to run independently
|
|
136
|
+
stdio: 'inherit',
|
|
137
|
+
shell: true // Optional: ignore parent's stdio (or use 'inherit' to share)
|
|
138
|
+
});
|
|
139
|
+
console.log(diffChildProc.pid);
|
|
140
|
+
// Unreference the child so that the parent process doesn't wait for it to exit
|
|
141
|
+
const diffPromise = new Promise((ok, no) => {
|
|
142
|
+
diffChildProc.on('spawn', () => {
|
|
143
|
+
// spawn plus 2 seconds
|
|
144
|
+
setTimeout(() => {
|
|
145
|
+
ok(0);
|
|
146
|
+
}, 2000);
|
|
147
|
+
});
|
|
148
|
+
// diffChildProc
|
|
149
|
+
});
|
|
150
|
+
// Exit the current process
|
|
151
|
+
await diffPromise;
|
|
152
|
+
diffChildProc.unref();
|
|
153
|
+
// do not prompt when in quiet mode
|
|
154
|
+
const choices = { 'Y': 'Yes', 'N': 'No' };
|
|
155
|
+
let answer = choices['N'];
|
|
156
|
+
options.arguments.paths = [];
|
|
157
|
+
if (!isQuiet) {
|
|
158
|
+
answer = await (0, promptHelpers_1.promptChoices)({
|
|
159
|
+
choices,
|
|
160
|
+
displayChoices: choices,
|
|
161
|
+
// premessage:,
|
|
162
|
+
question: 'Would you like to continue with the import?',
|
|
163
|
+
default: choices['N'],
|
|
164
|
+
});
|
|
165
|
+
if (answer === choices['Y'])
|
|
166
|
+
options.arguments.paths = [fixed];
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
catch (e) {
|
|
171
|
+
console.error(e);
|
|
172
|
+
throw e;
|
|
173
|
+
}
|
|
174
|
+
return options;
|
|
175
|
+
},
|
|
176
|
+
onCompleted: async (options) => {
|
|
177
|
+
if (!spawnSuitecloud.isChildProcess()) {
|
|
178
|
+
if (options?._status !== 'SUCCESS')
|
|
179
|
+
return options;
|
|
180
|
+
// clean up any temp files
|
|
181
|
+
await (0, pathHelpers_1.removeTempDirForSdf)(options.projectPath).catch(() => {
|
|
182
|
+
});
|
|
183
|
+
return options;
|
|
184
|
+
}
|
|
185
|
+
const [firstResult] = options?._data.results || [];
|
|
186
|
+
// make a temp file
|
|
187
|
+
if (firstResult && firstResult?.path)
|
|
188
|
+
await (0, tempFileHelper_1.makeTempFile)(tempFile, JSON.stringify({
|
|
189
|
+
path: firstResult?.path,
|
|
190
|
+
project: options?.commandParameters.project,
|
|
191
|
+
fullPath: (0, pathHelpers_1.joinPaths)(options?.commandParameters.project, 'FileCabinet', firstResult?.path)
|
|
192
|
+
}));
|
|
193
|
+
return options;
|
|
194
|
+
},
|
|
195
|
+
onError: async (error) => {
|
|
196
|
+
if (!spawnSuitecloud.isChildProcess()) {
|
|
197
|
+
// clean up any temp files
|
|
198
|
+
await (0, pathHelpers_1.removeTempDirForSdf)(optionsObserved.projectPath).catch(() => {
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
return onErrorHelper.detectOriginAndReturn(origin, error, (error) => {
|
|
202
|
+
return error;
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
};
|
|
207
|
+
exports.downloadForDiff = downloadForDiff;
|
|
208
|
+
/**
|
|
209
|
+
* @description - very similar tothe fixFileUploadPaths except we need to compare against netsuite
|
|
210
|
+
* Also we don't filter out any files
|
|
211
|
+
*/
|
|
212
|
+
const fixFileImportPaths = () => {
|
|
213
|
+
const origin = 'fixFileImportPaths';
|
|
214
|
+
return {
|
|
215
|
+
_origin: origin,
|
|
216
|
+
isStackable: true,
|
|
217
|
+
beforeExecuting: async (options) => {
|
|
218
|
+
if (!Array.isArray(options?.arguments?.paths))
|
|
219
|
+
options.arguments.paths = [];
|
|
220
|
+
const isQuiet = options?.arguments?.runhooks === 'quiet';
|
|
221
|
+
// it is expected that parents will fix any paths before calling
|
|
222
|
+
if (spawnSuitecloud.isChildProcess() && options.arguments.calledfromcomparefiles)
|
|
223
|
+
return options;
|
|
224
|
+
const { projectPath } = options;
|
|
225
|
+
const executionPath = options.executionPath || process.cwd();
|
|
226
|
+
await (0, promptHelpers_1.promptUser)({
|
|
227
|
+
message: JSON.stringify({
|
|
228
|
+
executionPath, ...options, ischild: spawnSuitecloud.isChildProcess()
|
|
229
|
+
})
|
|
230
|
+
});
|
|
231
|
+
// deal with relative paths, etc 1️⃣
|
|
232
|
+
const shortenedPathOrGlobs = options.arguments.paths.map((path) => {
|
|
233
|
+
if (/^\.+[\\\/]/.test(path) && !/\bSuiteScripts\b/.test(path))
|
|
234
|
+
return nodePath.join(executionPath,
|
|
235
|
+
// could be . or a ..
|
|
236
|
+
...path.split(/[\\\/]/))
|
|
237
|
+
.replace(/^.*(\bSuiteScripts\b.*)/, '/$1');
|
|
238
|
+
// anything longer
|
|
239
|
+
const fixed = [/^.*(\bSuiteScripts\b.*)$/].reduce((p, rgx) => {
|
|
240
|
+
if (p)
|
|
241
|
+
return p;
|
|
242
|
+
if (!rgx.test(path))
|
|
243
|
+
return p;
|
|
244
|
+
// already good
|
|
245
|
+
return path.replace(rgx, '/$1');
|
|
246
|
+
}, '');
|
|
247
|
+
if (fixed)
|
|
248
|
+
return fixed;
|
|
249
|
+
// TODO: any other patterns?
|
|
250
|
+
}).filter(Boolean);
|
|
251
|
+
const childArgs = ['config'].reduce((sofar, keep) => {
|
|
252
|
+
// most vars will be taken care of by environment variables
|
|
253
|
+
if (Reflect.has(options.arguments, keep))
|
|
254
|
+
sofar.push(`--${keep}`, Reflect.get(options.arguments, keep));
|
|
255
|
+
return sofar;
|
|
256
|
+
}, ['--folder', '/SuiteScripts']);
|
|
257
|
+
if (options.authId)
|
|
258
|
+
childArgs.push('--authid', options.authId);
|
|
259
|
+
if (!isQuiet)
|
|
260
|
+
await (0, promptHelpers_1.promptUser)({ message: 'pause' });
|
|
261
|
+
// globbing has to be done here before we clean 2️⃣
|
|
262
|
+
const exitCode = await spawnSuitecloud.createAsync({
|
|
263
|
+
command: 'file:list',
|
|
264
|
+
args: childArgs,
|
|
265
|
+
interact: false,
|
|
266
|
+
});
|
|
267
|
+
if (exitCode !== 0)
|
|
268
|
+
throw onErrorHelper.makeError(origin, new Error('List failed to generate'));
|
|
269
|
+
const jsonList = await tempFileHelper.consumeTempFile(tempFileHelper.FileNames.fileList);
|
|
270
|
+
const tests = shortenedPathOrGlobs.map((p) => (entry) => (0, minimatch_1.minimatch)(entry, p));
|
|
271
|
+
const listOfFiles = JSON.parse(jsonList)['_data'];
|
|
272
|
+
const filteredList = new Set();
|
|
273
|
+
await Promise.allSettled(listOfFiles.map(async (file) => {
|
|
274
|
+
const pass = await tests
|
|
275
|
+
.reduce(async (answer, test) => {
|
|
276
|
+
const currentAnswer = await answer;
|
|
277
|
+
return currentAnswer ? answer : test(file);
|
|
278
|
+
}, Promise.resolve(false));
|
|
279
|
+
if (pass)
|
|
280
|
+
filteredList.add(file);
|
|
281
|
+
}));
|
|
282
|
+
options.arguments.paths = [...filteredList];
|
|
283
|
+
// 3️⃣ -- no filtering out here
|
|
284
|
+
return options;
|
|
285
|
+
},
|
|
286
|
+
onError: async (error) => onErrorHelper.detectOriginAndReturn(origin, error, (e) => {
|
|
287
|
+
console.log(origin, e);
|
|
288
|
+
return e;
|
|
289
|
+
}),
|
|
290
|
+
};
|
|
291
|
+
};
|
|
292
|
+
exports.fixFileImportPaths = fixFileImportPaths;
|
|
293
|
+
/**
|
|
294
|
+
* @description -
|
|
295
|
+
* @deprecated - there are better combos now -- no need to prompt for globs as every path is technically a glob
|
|
296
|
+
* @param {{excludeproperties: boolean}} forceOptions
|
|
297
|
+
* @returns {_origin: 'importRegex';}
|
|
298
|
+
*/
|
|
299
|
+
const importFileOrPattern = (forceOptions) => {
|
|
300
|
+
const origin = 'importFileOrPattern';
|
|
301
|
+
const toReturn = {
|
|
302
|
+
_origin: origin,
|
|
303
|
+
/**
|
|
304
|
+
* @param {FileImportBeforeExecutingOptions} options
|
|
305
|
+
* @returns {FileImportBeforeExecutingOptions}
|
|
306
|
+
*/
|
|
307
|
+
beforeExecuting: async (options) => {
|
|
308
|
+
if (options.arguments.calledfromcomparefiles)
|
|
309
|
+
return options;
|
|
310
|
+
if (options?.arguments?.runhooks === 'quiet')
|
|
311
|
+
return options;
|
|
312
|
+
try {
|
|
313
|
+
// force this on
|
|
314
|
+
if (typeof forceOptions === 'object' &&
|
|
315
|
+
Reflect.has(forceOptions, 'excludeproperties'))
|
|
316
|
+
options.arguments.excludeproperties = forceOptions.excludeproperties;
|
|
317
|
+
// filter the list
|
|
318
|
+
if (!Array.isArray(options?.arguments?.paths))
|
|
319
|
+
options.arguments.paths = [];
|
|
320
|
+
const promptForFiles = options.arguments.paths.length === 0;
|
|
321
|
+
if (promptForFiles) {
|
|
322
|
+
let answer;
|
|
323
|
+
let pass = false;
|
|
324
|
+
const nagForPath = async () => {
|
|
325
|
+
answer = await (0, promptHelpers_1.promptUser)({
|
|
326
|
+
message: `Enter the path. \nIt can be a local relative path or a SuiteScripts path\n. e.g. /SuiteScripts/myfolder/**/*.js`
|
|
327
|
+
});
|
|
328
|
+
};
|
|
329
|
+
while (!pass) {
|
|
330
|
+
await nagForPath();
|
|
331
|
+
if (!/^\/(SuiteScripts|Templates|Web Site Hosting Files)/.test(answer))
|
|
332
|
+
pass = Boolean(await (0, pathHelpers_1.hasFile)(nodePath.resolve(answer)));
|
|
333
|
+
else
|
|
334
|
+
pass = true;
|
|
335
|
+
}
|
|
336
|
+
options.arguments.paths.push(answer);
|
|
337
|
+
}
|
|
338
|
+
// TODO: this should be a combo with options.projectPath and json
|
|
339
|
+
const suiteScriptsOfCurrent = process.cwd().replace(/^.*(.\bSuiteScripts\b.*)$/, '$1');
|
|
340
|
+
const nature = /^\/(SuiteScripts|Templates|Web Site Hosting Files)/.test(String(options?.arguments?.paths?.[0]))
|
|
341
|
+
? 'glob'
|
|
342
|
+
: 'path';
|
|
343
|
+
// run a list
|
|
344
|
+
const uniqueAndFiltered = new Set();
|
|
345
|
+
await Promise.all(options.arguments.paths.map(async (pathOrPattern) => {
|
|
346
|
+
if (nature === 'path') {
|
|
347
|
+
// resolve path first
|
|
348
|
+
const resolvedPath = nodePath.resolve(pathOrPattern).replace(/^.*(.\b(SuiteScripts|Templates|Web Site Hosting Files).*)$/, '$1');
|
|
349
|
+
uniqueAndFiltered.add(resolvedPath);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
uniqueAndFiltered.add(pathOrPattern);
|
|
353
|
+
}));
|
|
354
|
+
options.arguments.paths = [...uniqueAndFiltered];
|
|
355
|
+
// confirm2:
|
|
356
|
+
{
|
|
357
|
+
let importAnswer = '';
|
|
358
|
+
const importChoices = [
|
|
359
|
+
'Import This list',
|
|
360
|
+
'Save Filtered List To File (',
|
|
361
|
+
'Save Original List To File',
|
|
362
|
+
'Enter A Different Path / Glob',
|
|
363
|
+
'Do Not Import'
|
|
364
|
+
];
|
|
365
|
+
const nag = async () => {
|
|
366
|
+
process.stdout.write((0, promptHelpers_1.goColor)('GOOD', '\nfilteredList:\n', JSON.stringify(options.arguments.paths, null, 2)));
|
|
367
|
+
importAnswer = await (0, promptHelpers_1.promptChoices)({
|
|
368
|
+
choices: importChoices,
|
|
369
|
+
displayChoices: importChoices,
|
|
370
|
+
question: 'Are you good to import this list?',
|
|
371
|
+
default: importChoices[0],
|
|
372
|
+
});
|
|
373
|
+
};
|
|
374
|
+
while (![importChoices[0], importChoices[4]].includes(importAnswer)) {
|
|
375
|
+
await nag();
|
|
376
|
+
if (importAnswer === importChoices[3]) {
|
|
377
|
+
options.arguments.paths = [];
|
|
378
|
+
return toReturn.beforeExecuting(options);
|
|
379
|
+
}
|
|
380
|
+
if (importAnswer === importChoices[1]) {
|
|
381
|
+
// save to file
|
|
382
|
+
// not supported yet
|
|
383
|
+
}
|
|
384
|
+
if (importAnswer === importChoices[2]) {
|
|
385
|
+
// save to file
|
|
386
|
+
// not supported yet
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
if (importAnswer === importChoices[4])
|
|
390
|
+
options.arguments.paths = [];
|
|
391
|
+
}
|
|
392
|
+
// safety net
|
|
393
|
+
if (options.arguments.paths.find((path) => !path.includes(suiteScriptsOfCurrent))) {
|
|
394
|
+
const choices = { 'Y': 'Yes', 'N': 'No' };
|
|
395
|
+
// prompt for file choice between this folder and entire project
|
|
396
|
+
const answer = await (0, promptHelpers_1.promptChoices)({
|
|
397
|
+
choices,
|
|
398
|
+
displayChoices: choices,
|
|
399
|
+
question: `Current: ${(0, promptHelpers_1.goColor)("INFO", suiteScriptsOfCurrent)}\nAre you sure you want to import files outside of this directory (Y/N)?`,
|
|
400
|
+
default: choices['Y'],
|
|
401
|
+
});
|
|
402
|
+
if (answer === 'N')
|
|
403
|
+
options.arguments.paths = [];
|
|
404
|
+
}
|
|
405
|
+
if (options.arguments.paths.length === 0 && !spawnSuitecloud.isChildProcess()) {
|
|
406
|
+
// nothing to do
|
|
407
|
+
process.exit(0);
|
|
408
|
+
}
|
|
409
|
+
return options;
|
|
410
|
+
}
|
|
411
|
+
catch (e) {
|
|
412
|
+
throw onErrorHelper.makeError(origin, e);
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
onCompleted: async (options) => {
|
|
416
|
+
return options;
|
|
417
|
+
},
|
|
418
|
+
onError: async (error) => {
|
|
419
|
+
return onErrorHelper.detectOriginAndReturn(origin, error, (error) => {
|
|
420
|
+
process.stdout.write((0, promptHelpers_1.goColor)('BAD', 'oops ❌'));
|
|
421
|
+
return error;
|
|
422
|
+
});
|
|
423
|
+
},
|
|
424
|
+
isStackable: true,
|
|
425
|
+
};
|
|
426
|
+
return toReturn;
|
|
427
|
+
};
|
|
428
|
+
exports.importFileOrPattern = importFileOrPattern;
|
|
429
|
+
/**
|
|
430
|
+
* @description - file:import requires a manifest file when not doing the diff option
|
|
431
|
+
*/
|
|
432
|
+
const detectManifest = () => {
|
|
433
|
+
const origin = 'detectManifest';
|
|
434
|
+
let deleteManifest = false;
|
|
435
|
+
let manifestPath = '';
|
|
436
|
+
return {
|
|
437
|
+
_origin: origin,
|
|
438
|
+
isStackable: true,
|
|
439
|
+
beforeExecuting: async (options) => {
|
|
440
|
+
// not needed when...
|
|
441
|
+
if (options.arguments?.paths?.length === 0)
|
|
442
|
+
return options;
|
|
443
|
+
if (options.arguments.calledfromcomparefiles)
|
|
444
|
+
return options;
|
|
445
|
+
const isQuiet = options?.arguments?.runhooks === 'quiet';
|
|
446
|
+
// check if manifest exists
|
|
447
|
+
const hasManifest = await (0, pathHelpers_1.hasFile)([options.projectPath, 'manifest.xml']);
|
|
448
|
+
const choices = { 'Y': 'Yes' };
|
|
449
|
+
let answer = choices['Y'];
|
|
450
|
+
if (!hasManifest) {
|
|
451
|
+
if (!isQuiet) {
|
|
452
|
+
// prompt to create one
|
|
453
|
+
answer = await (0, promptHelpers_1.promptChoices)({
|
|
454
|
+
choices,
|
|
455
|
+
displayChoices: choices,
|
|
456
|
+
// premessage:,
|
|
457
|
+
question: 'No Manifest detected. Should a temporary one be created?',
|
|
458
|
+
default: choices['Y'],
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
if (answer === choices['Y']) {
|
|
462
|
+
deleteManifest = true;
|
|
463
|
+
await makeManifest(options.projectPath, 'Temporary', 'manifest.xml');
|
|
464
|
+
manifestPath = await (0, pathHelpers_1.hasFile)([options.projectPath, 'manifest.xml']) || '';
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
else {
|
|
468
|
+
manifestPath = hasManifest;
|
|
469
|
+
}
|
|
470
|
+
return options;
|
|
471
|
+
},
|
|
472
|
+
onCompleted: async (options) => {
|
|
473
|
+
// console.log({ deleteManifest, manifestPath},options?._commandParameters?.project);
|
|
474
|
+
if (deleteManifest && options?._commandParameters?.project) {
|
|
475
|
+
const unquotedProject = await Promise.resolve(options?._commandParameters?.project)
|
|
476
|
+
.then((p) => JSON.parse(p))
|
|
477
|
+
.catch(() => { });
|
|
478
|
+
if (unquotedProject) {
|
|
479
|
+
process.stdout.write((0, promptHelpers_1.goColor)('INFO', '\n', 'Deleting temporary manifest in ', unquotedProject));
|
|
480
|
+
await (0, pathHelpers_1.removeFile)([unquotedProject, 'manifest.xml']);
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
process.stdout.write((0, promptHelpers_1.goColor)('BAD', '\n', 'Could not find manifest.xml in ', options?._commandParameters?.project));
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
return options;
|
|
487
|
+
},
|
|
488
|
+
onError: async (error) => {
|
|
489
|
+
if (deleteManifest && manifestPath) {
|
|
490
|
+
await (0, pathHelpers_1.removeFile)([manifestPath]);
|
|
491
|
+
}
|
|
492
|
+
return error;
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
};
|
|
496
|
+
exports.detectManifest = detectManifest;
|
|
497
|
+
const beforeExecuting = (options) => {
|
|
498
|
+
console.log(options);
|
|
499
|
+
throw new Error('wut');
|
|
500
|
+
return options;
|
|
501
|
+
};
|
|
502
|
+
exports.beforeExecuting = beforeExecuting;
|
|
503
|
+
//# sourceMappingURL=fileImport.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file /Users/geraldgillespie/code/nsaccounts/sdf/commands/fileList
|
|
3
|
+
* @author Gerald Gillespie <gerald.gillespie@fullscript.com>
|
|
4
|
+
*/
|
|
5
|
+
import { SdfCommand } from "#root/index";
|
|
6
|
+
/**
|
|
7
|
+
* @description - Get a file list
|
|
8
|
+
* @deprecated
|
|
9
|
+
* @param options
|
|
10
|
+
* @param {Array<*>} tests - in this case, if any test passes then it is good
|
|
11
|
+
* @returns {Promise<string[]>} - the filtered list
|
|
12
|
+
*/
|
|
13
|
+
export declare const runFileListFromFolder: (options: {
|
|
14
|
+
folder: string;
|
|
15
|
+
}, tests: Array<(entry: string) => boolean | Promise<boolean>>) => Promise<string[]>;
|
|
16
|
+
/**
|
|
17
|
+
* @description
|
|
18
|
+
*/
|
|
19
|
+
export declare const saveFileListToTemp: () => SdfCommand;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file /Users/geraldgillespie/code/nsaccounts/sdf/commands/fileList
|
|
4
|
+
* @author Gerald Gillespie <gerald.gillespie@fullscript.com>
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.saveFileListToTemp = exports.runFileListFromFolder = void 0;
|
|
8
|
+
const promptHelpers_1 = require("../lib/promptHelpers");
|
|
9
|
+
const tempFileHelper = require("../lib/tempFileHelper");
|
|
10
|
+
/**
|
|
11
|
+
* @description - Get a file list
|
|
12
|
+
* @deprecated
|
|
13
|
+
* @param options
|
|
14
|
+
* @param {Array<*>} tests - in this case, if any test passes then it is good
|
|
15
|
+
* @returns {Promise<string[]>} - the filtered list
|
|
16
|
+
*/
|
|
17
|
+
const runFileListFromFolder = async (options, tests) => {
|
|
18
|
+
throw new Error('obsolete');
|
|
19
|
+
};
|
|
20
|
+
exports.runFileListFromFolder = runFileListFromFolder;
|
|
21
|
+
/**
|
|
22
|
+
* @description
|
|
23
|
+
*/
|
|
24
|
+
const saveFileListToTemp = () => {
|
|
25
|
+
const origin = 'saveFileListToTemp';
|
|
26
|
+
return {
|
|
27
|
+
_origin: origin,
|
|
28
|
+
isStackable: true,
|
|
29
|
+
beforeExecuting: async (options) => {
|
|
30
|
+
return options;
|
|
31
|
+
},
|
|
32
|
+
onCompleted: async (options) => {
|
|
33
|
+
process.stdout.write((0, promptHelpers_1.goColor)('SUBTLE', '\n', origin, ': ', tempFileHelper.FileNames.fileList));
|
|
34
|
+
await tempFileHelper.makeTempFile(tempFileHelper.FileNames.fileList, JSON.stringify(options, null, 2));
|
|
35
|
+
return options;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
exports.saveFileListToTemp = saveFileListToTemp;
|
|
40
|
+
//# sourceMappingURL=fileList.js.map
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file /Users/geraldgillespie/code/nsaccounts/sdf/commands/fileUpload
|
|
3
|
+
* @author Gerald Gillespie <gerald.gillespie@fullscript.com>
|
|
4
|
+
*/
|
|
5
|
+
import { SdfCommand } from "#root/index";
|
|
6
|
+
/**
|
|
7
|
+
* @description - only prompt if not paths given
|
|
8
|
+
* @param {string} opts.message
|
|
9
|
+
*/
|
|
10
|
+
export declare const promptForPath: (opts?: {
|
|
11
|
+
message?: string;
|
|
12
|
+
}) => SdfCommand;
|
|
13
|
+
/**
|
|
14
|
+
* @description - deploy.xml files are filtered out of an upload allowed in the upload, buuut...
|
|
15
|
+
* - If you provide one as the only file to upload then it will load the files listed in it
|
|
16
|
+
*
|
|
17
|
+
* - they are allowed in an import BUT that is rare so if an import see this path then it will not import
|
|
18
|
+
* it but treat it like an import instructions
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
export declare const getFilesFromDeployXml: () => SdfCommand;
|
|
22
|
+
/**
|
|
23
|
+
* @description -
|
|
24
|
+
*/
|
|
25
|
+
export declare const confirmFileList: () => SdfCommand;
|
|
26
|
+
/**
|
|
27
|
+
* @description - fix paths in a way that file:upload needs them fixed.
|
|
28
|
+
* - 0️⃣ paths that begin with SuiteScripts or SuiteBundles or SuiteApps are left as-is.
|
|
29
|
+
* - 1️⃣ relative paths -- these SHOULD begin with `.` or `..` or they will be treated as relative to cwd.
|
|
30
|
+
* - 2️⃣ globbing -- all paths are essentially viewed as a glob. globs that are
|
|
31
|
+
* - 3️⃣ clean and prevent bad files. e.g. typescript should be swapped for js (This should occur AFTER resolving any globs).
|
|
32
|
+
* - 4️⃣ check if the file exists and remove it
|
|
33
|
+
* - 5️⃣ finally trim to valid SDK path such as /SuiteScripts
|
|
34
|
+
*
|
|
35
|
+
* #Globbing:
|
|
36
|
+
* - every path here is SuiteScripts so ...
|
|
37
|
+
*
|
|
38
|
+
* - ignore certain files
|
|
39
|
+
*/
|
|
40
|
+
export declare const fixFileUploadPaths: () => SdfCommand;
|
|
41
|
+
/**
|
|
42
|
+
* @description - Guesses at what files might be TS and then generates
|
|
43
|
+
* @deprecated - not sure the benefit of this is worth the trouble
|
|
44
|
+
* @todo -
|
|
45
|
+
* @returns {SdfCommand}
|
|
46
|
+
*/
|
|
47
|
+
export declare const compileFilesPrompt: () => SdfCommand;
|
|
48
|
+
/**
|
|
49
|
+
* @description - calls jest for the files involved
|
|
50
|
+
* ⚠️ - make sure paths are fixed first
|
|
51
|
+
*/
|
|
52
|
+
export declare const testFilesPrompt: () => SdfCommand;
|