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