@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,428 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file /Users/geraldgillespie/code/nsaccounts/sdf/lib/pathHelpers
|
|
4
|
+
* @author Gerald Gillespie <gerald.gillespie@fullscript.com>
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.convertFileExtensions = exports.removeIllegalObjectFiles = exports.removeIllegalFileCabinetFiles = exports.getAllFilesRecursively = exports.findMatchingDirectories = exports.getAccountFolders = exports.getAbsolutePath = exports.makeTempDirForSdf = exports.removeFile = exports.removeTempDirForSdf = exports.getAccountDir = exports.getRelativeOf = exports.getDifferenceFromProjectRootToFileCabinet = exports.getFolderHoldingFileCabinetPlus = exports.getRootOfAccount = exports.getSuiteCloudConfigPath = exports.joinPaths = exports.combineOverLappingPaths = exports.getRootOfProject = exports.hasFile = exports.CONSTANTS = void 0;
|
|
8
|
+
const nodePath = require("node:path");
|
|
9
|
+
const fs = require("node:fs/promises");
|
|
10
|
+
const validators_1 = require("./validators");
|
|
11
|
+
const minimatch_1 = require("minimatch");
|
|
12
|
+
const makeManifest = require("./makeManifestXml");
|
|
13
|
+
const packageJsonLocation = nodePath.dirname(require.resolve('#root/package.json'));
|
|
14
|
+
const AccountRoots = [
|
|
15
|
+
'SuiteScripts',
|
|
16
|
+
'FileCabinet',
|
|
17
|
+
'Objects',
|
|
18
|
+
];
|
|
19
|
+
exports.CONSTANTS = {
|
|
20
|
+
TSCONFIG_SS21: 'tsconfig.ss21.json',
|
|
21
|
+
SDF_DEFAULT_ROOT: 'src',
|
|
22
|
+
SDF_TEMP_ROOT: '.src',
|
|
23
|
+
SDF_FILE_CABINET: 'FileCabinet',
|
|
24
|
+
SDF_TEMP_ROOT_RGX: new RegExp('(?:^|\W)[.]src\b')
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* @description - have it or not
|
|
28
|
+
* @param filePath
|
|
29
|
+
* @returns {false|string}
|
|
30
|
+
*/
|
|
31
|
+
const hasFile = async (filePath) => {
|
|
32
|
+
const path = nodePath.join(...[filePath].flat());
|
|
33
|
+
return fs.access(path, fs.constants.R_OK)
|
|
34
|
+
.then(() => path)
|
|
35
|
+
.catch(() => false);
|
|
36
|
+
};
|
|
37
|
+
exports.hasFile = hasFile;
|
|
38
|
+
/**
|
|
39
|
+
* ⚠️⚠️⚠️⚠️⚠️ WARNING: this gets the root of this project and not the project using this as a dependency!
|
|
40
|
+
* @returns {string} e.g. /Users/jdoe/code/nsaccounts
|
|
41
|
+
*/
|
|
42
|
+
const getRootOfProject = () => {
|
|
43
|
+
return packageJsonLocation;
|
|
44
|
+
};
|
|
45
|
+
exports.getRootOfProject = getRootOfProject;
|
|
46
|
+
/**
|
|
47
|
+
* @description - for example:
|
|
48
|
+
* - a relative path and the current directory
|
|
49
|
+
* - the entire path and a SuiteScripts path that both have SuiteScripts in it
|
|
50
|
+
* @param path1 -- must be an absolute path
|
|
51
|
+
* @param path2 - can be a partial path, relative path or special SDK path e.g. /SuiteScripts
|
|
52
|
+
*/
|
|
53
|
+
const combineOverLappingPaths = (path1, path2) => {
|
|
54
|
+
// remove any separators or dots
|
|
55
|
+
const normalizedPath1 = nodePath.normalize(path1);
|
|
56
|
+
const normalizedPath2 = nodePath.normalize(path2);
|
|
57
|
+
// first resolve any relative paths
|
|
58
|
+
const projectPath = process.env.SUITECLOUD_PROJECT_PATH || normalizedPath1;
|
|
59
|
+
const newPath2 = (0, exports.getAbsolutePath)({
|
|
60
|
+
projectPath,
|
|
61
|
+
filePath: path2
|
|
62
|
+
});
|
|
63
|
+
// address any obvious overlap
|
|
64
|
+
if (normalizedPath1.includes(normalizedPath2))
|
|
65
|
+
return normalizedPath1;
|
|
66
|
+
if (normalizedPath2.includes(normalizedPath1))
|
|
67
|
+
return normalizedPath2;
|
|
68
|
+
// Split paths into segments (ignoring any empty segments)
|
|
69
|
+
const parts1 = normalizedPath1.split(/[\/\\]/).filter(Boolean);
|
|
70
|
+
const parts2 = normalizedPath2.split(/[\/\\]/).filter(Boolean);
|
|
71
|
+
// Determine the maximum overlap length between the end of parts1 and start of parts2.
|
|
72
|
+
let overlapLength = 0;
|
|
73
|
+
const maxOverlap = Math.min(parts1.length, parts2.length);
|
|
74
|
+
for (let i = maxOverlap; i > 0; i--) {
|
|
75
|
+
// Compare the last i segments of parts1 with the first i segments of parts2.
|
|
76
|
+
if (parts1.slice(-i).join(nodePath.sep) === parts2.slice(0, i).join(nodePath.sep)) {
|
|
77
|
+
overlapLength = i;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Create the combined segments: all of parts1 plus the non-overlapping part of parts2.
|
|
82
|
+
const combinedParts = parts1.concat(parts2.slice(overlapLength));
|
|
83
|
+
// Reconstruct the path. Preserve absolute paths from the first argument.
|
|
84
|
+
// If path1 is absolute, ensure the result starts with the path separator.
|
|
85
|
+
let combinedPath = combinedParts.join(nodePath.sep);
|
|
86
|
+
if (nodePath.isAbsolute(normalizedPath1)) {
|
|
87
|
+
combinedPath = nodePath.sep + combinedPath;
|
|
88
|
+
}
|
|
89
|
+
return combinedPath;
|
|
90
|
+
};
|
|
91
|
+
exports.combineOverLappingPaths = combineOverLappingPaths;
|
|
92
|
+
const joinPaths = (...paths) => {
|
|
93
|
+
return nodePath.join(...paths);
|
|
94
|
+
};
|
|
95
|
+
exports.joinPaths = joinPaths;
|
|
96
|
+
/**
|
|
97
|
+
*
|
|
98
|
+
* @param {string} [path]
|
|
99
|
+
* @returns {Promise<string>}
|
|
100
|
+
*/
|
|
101
|
+
const getSuiteCloudConfigPath = async (path) => {
|
|
102
|
+
const pathToUse = path || process.env['SUITECLOUD_PROJECT_ROOT'] || process.cwd();
|
|
103
|
+
await fs.access(pathToUse, fs.constants.R_OK);
|
|
104
|
+
return pathToUse;
|
|
105
|
+
};
|
|
106
|
+
exports.getSuiteCloudConfigPath = getSuiteCloudConfigPath;
|
|
107
|
+
/**
|
|
108
|
+
*
|
|
109
|
+
* @param {string} folder - the current place that you are. e.g process.cwd() or __dirname or whatever
|
|
110
|
+
* @param {boolean} [folderNameOnly] - where to strip off the folders e.g. 12345323
|
|
111
|
+
* @returns {string} e.g. /path/to/12346357
|
|
112
|
+
*/
|
|
113
|
+
const getRootOfAccount = (folder, folderNameOnly) => {
|
|
114
|
+
// get the root and subtract that
|
|
115
|
+
const projectRoot = (0, exports.getRootOfProject)();
|
|
116
|
+
const projectFolder = folder.replace(projectRoot, '')
|
|
117
|
+
// slit on dir separators
|
|
118
|
+
.split(/[\\\/]/)
|
|
119
|
+
// filter out leading slash artifacts
|
|
120
|
+
.filter(Boolean)
|
|
121
|
+
// return the first
|
|
122
|
+
.shift();
|
|
123
|
+
console.log({ projectFolder, projectRoot });
|
|
124
|
+
return folderNameOnly === true ? projectFolder : nodePath.join(projectRoot, projectFolder);
|
|
125
|
+
};
|
|
126
|
+
exports.getRootOfAccount = getRootOfAccount;
|
|
127
|
+
/**
|
|
128
|
+
* @description - aka. "projectPath" in SDF SDK - the combination of where the config resolves and the projectFolder
|
|
129
|
+
* @param {string} anyCabinetPathInAccount
|
|
130
|
+
* @returns {string} e.g. /Users/jdoe/code/nsaccounts/24365476/src
|
|
131
|
+
*/
|
|
132
|
+
const getFolderHoldingFileCabinet = (anyCabinetPathInAccount) => {
|
|
133
|
+
if (/\bFileCabinet\b/.test(anyCabinetPathInAccount))
|
|
134
|
+
// get the filecabinet and subtract that
|
|
135
|
+
return anyCabinetPathInAccount.replace(/^(.*?).\bFileCabinet\b.*$/, '$1');
|
|
136
|
+
if (process.env['SUITECLOUD_PROJECT_PATH'])
|
|
137
|
+
return process.env['SUITECLOUD_PROJECT_PATH'];
|
|
138
|
+
throw new Error('Cannot find FileCabinet. You must provide a `defaultProjectFolder` argument or be in an account');
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* @description - If the provided path does not contain the reference then this will scan the descendants for the first one
|
|
142
|
+
* @param path
|
|
143
|
+
* @returns {Promise<string>}
|
|
144
|
+
*/
|
|
145
|
+
const getFolderHoldingFileCabinetPlus = async (path) => {
|
|
146
|
+
if (/\bFileCabinet\b/.test(path))
|
|
147
|
+
return getFolderHoldingFileCabinet(path);
|
|
148
|
+
// go hunting for it.
|
|
149
|
+
const list = await fs.readdir(path, { recursive: true });
|
|
150
|
+
const candidate = list.find((c) => /\bFileCabinet\b/.test(c) && !exports.CONSTANTS.SDF_TEMP_ROOT_RGX.test(c));
|
|
151
|
+
return getFolderHoldingFileCabinet(nodePath.join(path, candidate));
|
|
152
|
+
};
|
|
153
|
+
exports.getFolderHoldingFileCabinetPlus = getFolderHoldingFileCabinetPlus;
|
|
154
|
+
/**
|
|
155
|
+
*
|
|
156
|
+
* @param {string} anyCabinetPathInAccount
|
|
157
|
+
* @param {string} [projectRoot]
|
|
158
|
+
* @returns {string} * @returns {string} e.g. 24365476/src
|
|
159
|
+
*/
|
|
160
|
+
const getDifferenceFromProjectRootToFileCabinet = (anyCabinetPathInAccount, projectRoot) => {
|
|
161
|
+
const root = projectRoot || (0, exports.getRootOfProject)();
|
|
162
|
+
let tempFolder = anyCabinetPathInAccount.replace(root, '').replace(/^[\\\/]?/, '');
|
|
163
|
+
// get the filecabinet and subtract that
|
|
164
|
+
return tempFolder.replace(/(.*?).\bFileCabinet\b.*$/, '$1');
|
|
165
|
+
};
|
|
166
|
+
exports.getDifferenceFromProjectRootToFileCabinet = getDifferenceFromProjectRootToFileCabinet;
|
|
167
|
+
/**
|
|
168
|
+
* @description - same as path.relative
|
|
169
|
+
* @param projectJsonLocation
|
|
170
|
+
* @param projectRoot
|
|
171
|
+
*/
|
|
172
|
+
const getRelativeOf = (projectJsonLocation, projectRoot) => {
|
|
173
|
+
return nodePath.relative(projectJsonLocation, projectRoot);
|
|
174
|
+
};
|
|
175
|
+
exports.getRelativeOf = getRelativeOf;
|
|
176
|
+
/**
|
|
177
|
+
* @description - for common folders
|
|
178
|
+
* @param {string} type
|
|
179
|
+
* @param {string[]} extras
|
|
180
|
+
* @param {string} [target] - defaults to cwd
|
|
181
|
+
* @returns {string} - The full path
|
|
182
|
+
*
|
|
183
|
+
*/
|
|
184
|
+
const getAccountDir = async (type, extras, target) => {
|
|
185
|
+
let dirs = [];
|
|
186
|
+
switch (type) {
|
|
187
|
+
case 'FileCabinet':
|
|
188
|
+
dirs.push('FileCabinet');
|
|
189
|
+
break;
|
|
190
|
+
case 'Objects':
|
|
191
|
+
dirs.push('Objects');
|
|
192
|
+
break;
|
|
193
|
+
case 'Translations':
|
|
194
|
+
dirs.push('Translations');
|
|
195
|
+
break;
|
|
196
|
+
case 'AccountConfiguration':
|
|
197
|
+
dirs.push('AccountConfiguration');
|
|
198
|
+
break;
|
|
199
|
+
case 'SuiteScripts':
|
|
200
|
+
dirs.push('FileCabinet', 'SuiteScripts');
|
|
201
|
+
break;
|
|
202
|
+
case 'Templates':
|
|
203
|
+
dirs.push('FileCabinet', 'Templates');
|
|
204
|
+
break;
|
|
205
|
+
case 'Web Site Hosting Files':
|
|
206
|
+
dirs.push('FileCabinet', 'Web Site Hosting Files');
|
|
207
|
+
default:
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
console.log({ target, dirs, type });
|
|
211
|
+
const fcPath = await (0, exports.getFolderHoldingFileCabinetPlus)(target || process.env['SUITECLOUD_PROJECT_PATH'] || process.cwd());
|
|
212
|
+
if (dirs.length > 0)
|
|
213
|
+
return nodePath.join(fcPath, ...dirs, ...extras.flatMap((x) => x.split(/\\\//)));
|
|
214
|
+
throw new Error('Unknown type');
|
|
215
|
+
};
|
|
216
|
+
exports.getAccountDir = getAccountDir;
|
|
217
|
+
const removeTempDirForSdf = async (projectPath) => {
|
|
218
|
+
const newPath = nodePath.join(projectPath, '..', exports.CONSTANTS.SDF_TEMP_ROOT);
|
|
219
|
+
await fs.rm(newPath, { recursive: true, force: true }).catch((e) => {
|
|
220
|
+
console.error(e);
|
|
221
|
+
});
|
|
222
|
+
return newPath;
|
|
223
|
+
};
|
|
224
|
+
exports.removeTempDirForSdf = removeTempDirForSdf;
|
|
225
|
+
/**
|
|
226
|
+
* @description
|
|
227
|
+
* @param {string[]} pathBits
|
|
228
|
+
*/
|
|
229
|
+
const removeFile = async (pathBits) => {
|
|
230
|
+
const newPath = nodePath.join(...pathBits);
|
|
231
|
+
await fs.rm(newPath, { force: true }).catch((e) => {
|
|
232
|
+
console.error(e);
|
|
233
|
+
});
|
|
234
|
+
return newPath;
|
|
235
|
+
};
|
|
236
|
+
exports.removeFile = removeFile;
|
|
237
|
+
/**
|
|
238
|
+
* @description - makes a `temp` directory in the same account root
|
|
239
|
+
* - no need to copy anything over
|
|
240
|
+
* @param {string} projectPath
|
|
241
|
+
* @returns {Promise<string>}
|
|
242
|
+
*/
|
|
243
|
+
const makeTempDirForSdf = async (projectPath) => {
|
|
244
|
+
const newPath = nodePath.join(projectPath, '..', exports.CONSTANTS.SDF_TEMP_ROOT);
|
|
245
|
+
// clean up old files first
|
|
246
|
+
await (0, exports.removeTempDirForSdf)(projectPath);
|
|
247
|
+
await fs.mkdir(newPath, { recursive: true });
|
|
248
|
+
// make manifest file
|
|
249
|
+
await makeManifest(newPath, 'temp');
|
|
250
|
+
return newPath;
|
|
251
|
+
};
|
|
252
|
+
exports.makeTempDirForSdf = makeTempDirForSdf;
|
|
253
|
+
/**
|
|
254
|
+
* @description - Figures out the path
|
|
255
|
+
* - if you have a relative path then compare it against cwd
|
|
256
|
+
* - if you have an absolute path then check if it is actually a NetSuite project path
|
|
257
|
+
* -
|
|
258
|
+
*/
|
|
259
|
+
const getAbsolutePath = (options) => {
|
|
260
|
+
if (!nodePath.isAbsolute(options.filePath))
|
|
261
|
+
return nodePath.resolve(nodePath.join(options.executionPath || process.cwd(), options.filePath));
|
|
262
|
+
if (/^[\\\/]\b(SuiteScripts|SuiteBundles|Suite\w+)\b/.test(options.filePath)) {
|
|
263
|
+
return nodePath.resolve(nodePath.join(options.projectPath, 'FileCabinet', options.filePath));
|
|
264
|
+
}
|
|
265
|
+
if (/^[\\\/]\b(Objects)\b/.test(options.filePath)) {
|
|
266
|
+
return nodePath.resolve(nodePath.join(options.projectPath, options.filePath));
|
|
267
|
+
}
|
|
268
|
+
// e.g. /Users/geraldgillespie/project/src/FileCabinet/SuiteScripts
|
|
269
|
+
return nodePath.resolve(options.filePath);
|
|
270
|
+
};
|
|
271
|
+
exports.getAbsolutePath = getAbsolutePath;
|
|
272
|
+
/**
|
|
273
|
+
* @description -
|
|
274
|
+
*/
|
|
275
|
+
const getAccountFolders = async (path) => {
|
|
276
|
+
const tier1List = await fs.readdir(path, { withFileTypes: true });
|
|
277
|
+
return tier1List.flatMap((p) => {
|
|
278
|
+
if (!p.isDirectory())
|
|
279
|
+
return [];
|
|
280
|
+
return (0, validators_1.isValidAccountFolderName)(p.name) ? [p.name] : [];
|
|
281
|
+
});
|
|
282
|
+
};
|
|
283
|
+
exports.getAccountFolders = getAccountFolders;
|
|
284
|
+
/**
|
|
285
|
+
* Recursively find directories whose names match a series of tests at each depth.
|
|
286
|
+
* @param {string} dir - The directory to start searching from.
|
|
287
|
+
* @param {*[]} tests - Current recursion depth (default is 0).
|
|
288
|
+
* @returns {Promise<string[]>} - An array of matching directory paths.
|
|
289
|
+
*/
|
|
290
|
+
const findMatchingDirectories = async (dir, tests) => {
|
|
291
|
+
// remove it and make the test list shorter
|
|
292
|
+
const [rgx, ...rest] = tests;
|
|
293
|
+
let matchingDirs = [];
|
|
294
|
+
// Stop recursion if we exceed the maximum depth
|
|
295
|
+
if (typeof rgx === 'undefined')
|
|
296
|
+
return matchingDirs;
|
|
297
|
+
let entries;
|
|
298
|
+
try {
|
|
299
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
console.error(`Error reading directory ${dir}:`, error);
|
|
303
|
+
return matchingDirs;
|
|
304
|
+
}
|
|
305
|
+
for (const entry of entries) {
|
|
306
|
+
if (entry.isDirectory()) {
|
|
307
|
+
const fullPath = nodePath.join(dir, entry.name);
|
|
308
|
+
// If the directory name passes the test, add its full path to the results
|
|
309
|
+
if (rgx.test(entry.name)) {
|
|
310
|
+
matchingDirs.push(fullPath);
|
|
311
|
+
// Recursively search within the directory
|
|
312
|
+
const subDirs = await (0, exports.findMatchingDirectories)(fullPath, rest);
|
|
313
|
+
matchingDirs = matchingDirs.concat(subDirs);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return matchingDirs;
|
|
318
|
+
};
|
|
319
|
+
exports.findMatchingDirectories = findMatchingDirectories;
|
|
320
|
+
/**
|
|
321
|
+
* @description - Get the remaining path
|
|
322
|
+
* @param {string[]} paths
|
|
323
|
+
* @param {'SuiteScripts'} type -
|
|
324
|
+
* @param {Array<function|string|RegExp>} [tests] - functions or globs or regex to apply. Only `some` has to pass.
|
|
325
|
+
* @returns {Promise<string[]>}
|
|
326
|
+
*/
|
|
327
|
+
const getAllFilesRecursively = async (paths, type, tests) => {
|
|
328
|
+
// console.log({paths, tests});
|
|
329
|
+
const unique = new Set();
|
|
330
|
+
const replacer = [new RegExp(`^.*(\\b${type}\\b.*)$`), '/$1'];
|
|
331
|
+
const testers = tests.flatMap((test) => {
|
|
332
|
+
if (typeof test === 'function')
|
|
333
|
+
return [test];
|
|
334
|
+
if (typeof test === 'string')
|
|
335
|
+
return [(x) => (0, minimatch_1.minimatch)(x, test)];
|
|
336
|
+
if (typeof test === 'object' && test instanceof RegExp)
|
|
337
|
+
return [(x) => test.test(x)];
|
|
338
|
+
return [];
|
|
339
|
+
});
|
|
340
|
+
await Promise.allSettled(paths.map(async (path) => {
|
|
341
|
+
const branch = await fs.readdir(path, { recursive: true, withFileTypes: true });
|
|
342
|
+
branch.forEach((p) => {
|
|
343
|
+
if (!p.isFile())
|
|
344
|
+
return;
|
|
345
|
+
if (!p.parentPath.includes(type))
|
|
346
|
+
return;
|
|
347
|
+
let modifiedP = nodePath.join(p.parentPath, p.name);
|
|
348
|
+
if (Array.isArray(replacer))
|
|
349
|
+
modifiedP = modifiedP.replace(...replacer);
|
|
350
|
+
if (testers.some((test) => test(modifiedP)))
|
|
351
|
+
unique.add(modifiedP);
|
|
352
|
+
});
|
|
353
|
+
}));
|
|
354
|
+
return [...unique];
|
|
355
|
+
};
|
|
356
|
+
exports.getAllFilesRecursively = getAllFilesRecursively;
|
|
357
|
+
/**
|
|
358
|
+
* @description -- you should convert first
|
|
359
|
+
* @param paths
|
|
360
|
+
*/
|
|
361
|
+
const removeIllegalFileCabinetFiles = (paths) => {
|
|
362
|
+
return paths.filter((p) => {
|
|
363
|
+
if (/\.tsx?$/.test(p))
|
|
364
|
+
return false;
|
|
365
|
+
if (/\.csv$/.test(p))
|
|
366
|
+
return false;
|
|
367
|
+
if (/\.test\.js$/.test(p))
|
|
368
|
+
return false;
|
|
369
|
+
if (/\.map$/.test(p))
|
|
370
|
+
return false;
|
|
371
|
+
// anything in these subfolders
|
|
372
|
+
if (/__(tests?|mocks?)__/.test(p))
|
|
373
|
+
return false;
|
|
374
|
+
if (/\.attributes\b/.test(p))
|
|
375
|
+
return false;
|
|
376
|
+
if (/\.attr\.xml\b/.test(p))
|
|
377
|
+
return false;
|
|
378
|
+
if (/\.[mc]js$/.test(p))
|
|
379
|
+
return false;
|
|
380
|
+
// suitecloud
|
|
381
|
+
if (/\bsuitecloud\.config\b/.test(p))
|
|
382
|
+
return false;
|
|
383
|
+
if (/\bproject\b.*\bjson\b/.test(p))
|
|
384
|
+
return false;
|
|
385
|
+
// any deploy files
|
|
386
|
+
if (/\bdeploy\b.*\bxml\b/.test(p))
|
|
387
|
+
return false;
|
|
388
|
+
// jest config
|
|
389
|
+
if (/\bjest\b/.test(p))
|
|
390
|
+
return false;
|
|
391
|
+
// tscnofig
|
|
392
|
+
if (/\btsconfig\b/.test(p))
|
|
393
|
+
return false;
|
|
394
|
+
// hidden files e.g. .gitKeep
|
|
395
|
+
if (/[\\\/]\./.test(p))
|
|
396
|
+
return false;
|
|
397
|
+
if (/\beslint\b/.test(p))
|
|
398
|
+
return false;
|
|
399
|
+
return true;
|
|
400
|
+
});
|
|
401
|
+
};
|
|
402
|
+
exports.removeIllegalFileCabinetFiles = removeIllegalFileCabinetFiles;
|
|
403
|
+
/**
|
|
404
|
+
* @description - A legal object file has only one extension '.xml'
|
|
405
|
+
* And the scriptid inside matches its file name. We cannot open files here
|
|
406
|
+
* @param paths
|
|
407
|
+
*/
|
|
408
|
+
const removeIllegalObjectFiles = (paths) => {
|
|
409
|
+
return paths.filter((p) => {
|
|
410
|
+
if (!/^(.*\/)?[a-z_\d\*]+\.xml$/.test(p))
|
|
411
|
+
return false;
|
|
412
|
+
});
|
|
413
|
+
// open the file
|
|
414
|
+
};
|
|
415
|
+
exports.removeIllegalObjectFiles = removeIllegalObjectFiles;
|
|
416
|
+
/**
|
|
417
|
+
* @description - e.g. ts to js
|
|
418
|
+
* @param paths
|
|
419
|
+
*/
|
|
420
|
+
const convertFileExtensions = (paths) => {
|
|
421
|
+
return paths.map((p) => {
|
|
422
|
+
if (/\.ts$/.test(p))
|
|
423
|
+
return p.replace(/(\.d)?\.ts$/, '.js');
|
|
424
|
+
return p;
|
|
425
|
+
});
|
|
426
|
+
};
|
|
427
|
+
exports.convertFileExtensions = convertFileExtensions;
|
|
428
|
+
//# sourceMappingURL=pathHelpers.js.map
|
package/lib/pause.d.ts
ADDED
package/lib/pause.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file sdf/lib/pause.ts
|
|
4
|
+
* @author Gerald Gillespie <gerald.gillespie@fullscript.com>
|
|
5
|
+
*/
|
|
6
|
+
const pause = () => {
|
|
7
|
+
throw new Error('this should be a pause detection');
|
|
8
|
+
};
|
|
9
|
+
module.exports = pause;
|
|
10
|
+
//# sourceMappingURL=pause.js.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file /Users/geraldgillespie/code/nsaccounts/sdf/lib/projectJsonHelpers
|
|
3
|
+
* @author Gerald Gillespie <gerald.gillespie@fullscript.com>
|
|
4
|
+
*/
|
|
5
|
+
import { ProjectJsonContents } from '../index';
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @param location
|
|
9
|
+
* @param altName
|
|
10
|
+
*/
|
|
11
|
+
export declare const readProjectJson: (location: string[], altName?: string) => Promise<any>;
|
|
12
|
+
/**
|
|
13
|
+
* @description - re-usable ProjectJson updated
|
|
14
|
+
* @param {ProjectJsonContents} options
|
|
15
|
+
* @param {string[]} location
|
|
16
|
+
* @param {string} [altName] e.g. project.x.json
|
|
17
|
+
* @returns {ProjectJsonContents}
|
|
18
|
+
*/
|
|
19
|
+
export declare const updateProjectJson: <T extends ProjectJsonContents>(options: T, location: string[], altName?: "project.json" | string) => Promise<T>;
|
|
20
|
+
export declare const readProjectJsonSync: (location: string[], altName?: string) => any;
|
|
21
|
+
/**
|
|
22
|
+
* @description - re-usable ProjectJson updated
|
|
23
|
+
* @param {ProjectJsonContents} options
|
|
24
|
+
* @param {string[]} location
|
|
25
|
+
* @param {string} [altName] e.g. project.x.json
|
|
26
|
+
* @param {boolean} [keepExisting]
|
|
27
|
+
* @returns {ProjectJsonContents}
|
|
28
|
+
*/
|
|
29
|
+
export declare const updateProjectJsonSync: <T extends ProjectJsonContents>(options: T, location: string[], altName?: "project.json" | string, keepExisting?: boolean) => T;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file /Users/geraldgillespie/code/nsaccounts/sdf/lib/projectJsonHelpers
|
|
4
|
+
* @author Gerald Gillespie <gerald.gillespie@fullscript.com>
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.updateProjectJsonSync = exports.readProjectJsonSync = exports.updateProjectJson = exports.readProjectJson = void 0;
|
|
8
|
+
const fs = require("node:fs/promises");
|
|
9
|
+
const fsSync = require("node:fs");
|
|
10
|
+
const nodePath = require("node:path");
|
|
11
|
+
const promptHelpers_1 = require("./promptHelpers");
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* @param location
|
|
15
|
+
* @param altName
|
|
16
|
+
*/
|
|
17
|
+
const readProjectJson = async (location, altName) => {
|
|
18
|
+
if (location.length === 0)
|
|
19
|
+
location.push(process.cwd());
|
|
20
|
+
const filePath = nodePath.join(...location, altName || 'project.json');
|
|
21
|
+
const serializedContents = await fs.readFile(filePath, { encoding: 'utf8' }).catch(() => ('{}'));
|
|
22
|
+
return JSON.parse(serializedContents);
|
|
23
|
+
};
|
|
24
|
+
exports.readProjectJson = readProjectJson;
|
|
25
|
+
/**
|
|
26
|
+
* @description - re-usable ProjectJson updated
|
|
27
|
+
* @param {ProjectJsonContents} options
|
|
28
|
+
* @param {string[]} location
|
|
29
|
+
* @param {string} [altName] e.g. project.x.json
|
|
30
|
+
* @returns {ProjectJsonContents}
|
|
31
|
+
*/
|
|
32
|
+
const updateProjectJson = async (options, location, altName) => {
|
|
33
|
+
if (location.length === 0)
|
|
34
|
+
location.push(process.cwd());
|
|
35
|
+
const filePath = nodePath.join(...location, altName || 'project.json');
|
|
36
|
+
const data = await (0, exports.readProjectJson)(location, altName || 'project.json');
|
|
37
|
+
if (Object.keys(options).length > 0) {
|
|
38
|
+
process.stdout.write((0, promptHelpers_1.goColor)('SUBTLE', '\nUpdating project json', JSON.stringify(data, null, 2)));
|
|
39
|
+
Object.entries(options).forEach(([key, value]) => {
|
|
40
|
+
data[key] = value;
|
|
41
|
+
});
|
|
42
|
+
await fs.writeFile(filePath, JSON.stringify(data, null, 2), { encoding: 'utf8' });
|
|
43
|
+
}
|
|
44
|
+
// if( !data.defaultAuthId )
|
|
45
|
+
return data;
|
|
46
|
+
};
|
|
47
|
+
exports.updateProjectJson = updateProjectJson;
|
|
48
|
+
const readProjectJsonSync = (location, altName) => {
|
|
49
|
+
if (location.length === 0)
|
|
50
|
+
location.push(process.cwd());
|
|
51
|
+
const filePath = nodePath.join(...location, altName || 'project.json');
|
|
52
|
+
try {
|
|
53
|
+
const serializedContents = fsSync.readFileSync(filePath, { encoding: 'utf8' });
|
|
54
|
+
return JSON.parse(serializedContents);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
exports.readProjectJsonSync = readProjectJsonSync;
|
|
61
|
+
/**
|
|
62
|
+
* @description - re-usable ProjectJson updated
|
|
63
|
+
* @param {ProjectJsonContents} options
|
|
64
|
+
* @param {string[]} location
|
|
65
|
+
* @param {string} [altName] e.g. project.x.json
|
|
66
|
+
* @param {boolean} [keepExisting]
|
|
67
|
+
* @returns {ProjectJsonContents}
|
|
68
|
+
*/
|
|
69
|
+
const updateProjectJsonSync = (options, location, altName, keepExisting) => {
|
|
70
|
+
if (location.length === 0)
|
|
71
|
+
location.push(process.cwd());
|
|
72
|
+
const filePath = nodePath.join(...location, altName || 'project.json');
|
|
73
|
+
let serializedContents = '{}';
|
|
74
|
+
try {
|
|
75
|
+
serializedContents = fsSync.readFileSync(filePath, { encoding: 'utf8' });
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
serializedContents = '{}';
|
|
79
|
+
}
|
|
80
|
+
const data = JSON.parse(serializedContents);
|
|
81
|
+
if (Object.keys(options).length > 0) {
|
|
82
|
+
Object.entries(options).forEach(([key, value]) => {
|
|
83
|
+
if (keepExisting && Reflect.has(data, key))
|
|
84
|
+
return;
|
|
85
|
+
data[key] = value;
|
|
86
|
+
});
|
|
87
|
+
fsSync.writeFileSync(filePath, JSON.stringify(data, null, 2), { encoding: 'utf8' });
|
|
88
|
+
}
|
|
89
|
+
return data;
|
|
90
|
+
};
|
|
91
|
+
exports.updateProjectJsonSync = updateProjectJsonSync;
|
|
92
|
+
//# sourceMappingURL=projectJsonHelpers.js.map
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file sdf/lib/promptHelpers.ts
|
|
3
|
+
* @author Gerald Gillespie <gerald.gillespie@fullscript.com>
|
|
4
|
+
*/
|
|
5
|
+
import { COLORS } from '../types/colors';
|
|
6
|
+
declare const Colors: {
|
|
7
|
+
readonly WARN: COLORS.ORANGE;
|
|
8
|
+
readonly BAD: COLORS.RED;
|
|
9
|
+
readonly INFO: COLORS.CYAN;
|
|
10
|
+
readonly HIGHLIGHT: COLORS.YELLOW;
|
|
11
|
+
readonly GOOD: COLORS.GREEN;
|
|
12
|
+
readonly NONE: COLORS.RESET_ALL;
|
|
13
|
+
readonly BOLD: COLORS.BOLD;
|
|
14
|
+
readonly SUBTLE: COLORS.BRIGHT_BLACK;
|
|
15
|
+
};
|
|
16
|
+
interface GoColor {
|
|
17
|
+
/**
|
|
18
|
+
* @des
|
|
19
|
+
* @param {colors: string|(keyof typeof Colors)| Array<string|keyof typeof Colors>} colors
|
|
20
|
+
* @param {string[]} messages
|
|
21
|
+
* @param {boolean} [skipReset=false]
|
|
22
|
+
* @returns {string}
|
|
23
|
+
*/
|
|
24
|
+
(colors: string | (keyof typeof Colors) | Array<string | keyof typeof Colors>, messages: any[], skipReset?: boolean): string;
|
|
25
|
+
(colors: string | (keyof typeof Colors) | Array<string | keyof typeof Colors>, ...messages: Array<any | boolean>): string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* @description
|
|
29
|
+
* @param {Array<string|keyof typeof Colors>} colors
|
|
30
|
+
* @param {string[]} messages
|
|
31
|
+
* @param {boolean} skipReset
|
|
32
|
+
* @returns {string}
|
|
33
|
+
*/
|
|
34
|
+
export declare const goColor: GoColor;
|
|
35
|
+
/**
|
|
36
|
+
* @description
|
|
37
|
+
* @param {string} previousMessage
|
|
38
|
+
* @param {string} toAppend
|
|
39
|
+
* @returns {string}
|
|
40
|
+
*/
|
|
41
|
+
export declare const appendToPrevious: (previousMessage: string, toAppend: string) => void;
|
|
42
|
+
/**
|
|
43
|
+
* @description -
|
|
44
|
+
* @param line
|
|
45
|
+
* @returns {boolean}
|
|
46
|
+
*/
|
|
47
|
+
export declare const detectPrompt: (line: string) => boolean;
|
|
48
|
+
/**
|
|
49
|
+
* @param {{message: string; timeout?: number;}} options
|
|
50
|
+
* @param {(string)=>any} [callback]
|
|
51
|
+
* @returns {Promise<string|null>}
|
|
52
|
+
*/
|
|
53
|
+
export declare const promptUser: ({ message, timeout }: {
|
|
54
|
+
message: string;
|
|
55
|
+
timeout?: number | null;
|
|
56
|
+
}, callback?: (answer: any) => any) => Promise<any>;
|
|
57
|
+
export declare const promptUserSync: ({ message, timeout }: {
|
|
58
|
+
message: string;
|
|
59
|
+
timeout?: number | null;
|
|
60
|
+
}, callback?: (answer: any) => any) => void;
|
|
61
|
+
/**
|
|
62
|
+
* @description - pass in a array of strings to be presented with a numbered choice list
|
|
63
|
+
* 0 is always "QUIT" (even if not presented) and the program will exit with code 0 (coincidence on the number)
|
|
64
|
+
* "-1" is always the default -- this helps with automation
|
|
65
|
+
*
|
|
66
|
+
* @param {{choices: string[]}} options
|
|
67
|
+
* @returns {Promise<string>}
|
|
68
|
+
*/
|
|
69
|
+
export declare const promptChoices: <C>(options: {
|
|
70
|
+
choices: Record<string, C> | C[];
|
|
71
|
+
displayChoices: string[] | Record<string, string>;
|
|
72
|
+
default: C | null;
|
|
73
|
+
premessage?: string;
|
|
74
|
+
question: string;
|
|
75
|
+
childDefault?: C;
|
|
76
|
+
}) => Promise<C & string>;
|
|
77
|
+
export {};
|