hackmud-script-manager 0.19.0-7c69a3b → 0.19.0-b5e2c0b
Sign up to get free protection for your applications and to get access to all the features.
- package/bin/hsm.js +1 -682
- package/constants.js +1 -4
- package/generateTypeDeclaration.js +1 -94
- package/index.js +1 -50
- package/package.json +1 -1
- package/processScript/index.js +1 -313
- package/processScript/minify.js +1 -376
- package/processScript/postprocess.js +1 -5
- package/processScript/preprocess.js +1 -83
- package/processScript/shared.js +1 -18
- package/processScript/transform.js +1 -393
- package/pull.js +1 -17
- package/push.js +1 -254
- package/syncMacros.js +1 -53
- package/tsconfig.tsbuildinfo +1 -1
- package/watch.js +1 -231
package/bin/hsm.js
CHANGED
@@ -1,683 +1,2 @@
|
|
1
1
|
#!/usr/bin/env node
|
2
|
-
import { DynamicMap } from '@samual/lib/DynamicMap';
|
3
|
-
import { assert } from '@samual/lib/assert';
|
4
|
-
import { countHackmudCharacters } from '@samual/lib/countHackmudCharacters';
|
5
|
-
import { writeFilePersistent } from '@samual/lib/writeFilePersistent';
|
6
|
-
import { readFile, writeFile, mkdir, rmdir } from 'fs/promises';
|
7
|
-
import { homedir } from 'os';
|
8
|
-
import { supportedExtensions } from '../constants.js';
|
9
|
-
import { generateTypeDeclaration } from '../generateTypeDeclaration.js';
|
10
|
-
import { pull } from '../pull.js';
|
11
|
-
import { syncMacros } from '../syncMacros.js';
|
12
|
-
import { resolve, extname, basename, dirname, relative } from 'path';
|
13
|
-
import '@samual/lib/copyFilePersistent';
|
14
|
-
|
15
|
-
const version = "0.19.0-7c69a3b";
|
16
|
-
|
17
|
-
/* | ArgValue[]*/
|
18
|
-
|
19
|
-
const configDirectoryPath = resolve(homedir(), `.config`);
|
20
|
-
const configFilePath = resolve(configDirectoryPath, `hsm.json`);
|
21
|
-
const options = new Map();
|
22
|
-
const commands = [];
|
23
|
-
const userColours = new DynamicMap(user => {
|
24
|
-
let hash = 0;
|
25
|
-
for (const char of user) hash += (hash >> 1) + hash + `xi1_8ratvsw9hlbgm02y5zpdcn7uekof463qj`.indexOf(char) + 1;
|
26
|
-
return [colourJ, colourK, colourM, colourW, colourL, colourB][hash % 6](user);
|
27
|
-
});
|
28
|
-
const logNeedHackmudPathMessage = () => console.error(colourS(`\
|
29
|
-
${colourD(`You need to set hackmudPath in config before you can use this command`)}
|
30
|
-
|
31
|
-
${colourA(`To fix this:`)}
|
32
|
-
Open hackmud and run "${colourC(`#dir`)}"
|
33
|
-
This will open a file browser and print your hackmud user's script directory
|
34
|
-
Go up 2 directories and then copy the path
|
35
|
-
Then in a terminal run "${colourC(`hsm`)} ${colourL(`config set`)} ${colourV(`hackmudPath`)} ${colourB(`<the path you copied>`)}"`));
|
36
|
-
const logHelp = () => {
|
37
|
-
const pushCommandDescription = `Push scripts from a directory to hackmud user's scripts directories`;
|
38
|
-
const watchCommandDescription = `Watch a directory and push a script when modified`;
|
39
|
-
const minifyCommandDescription = `Minify a script file on the spot`;
|
40
|
-
const generateTypeDeclarationCommandDescription = `Generate a type declaration file for a directory of scripts`;
|
41
|
-
const syncMacrosCommandDescription = `Sync macros across all hackmud users`;
|
42
|
-
const configCommandDescription = `Modify and view the config file`;
|
43
|
-
const configGetCommandDescription = `Retrieve a value from the config file`;
|
44
|
-
const configSetCommandDescription = `Assign a value to the config file`;
|
45
|
-
const configDeleteCommandDescription = `Remove a key and value from the config file`;
|
46
|
-
const pullCommandDescription = `Pull a script a from a hackmud user's script directory`;
|
47
|
-
const skipMinifyOptionDescription = `Skip minification to produce a readable script`;
|
48
|
-
const mangleNamesOptionDescription = `Reduce character count further but lose function names in error call stacks`;
|
49
|
-
const forceQuineCheatsOptionDescription = `Force quine cheats even if the character count is higher`;
|
50
|
-
console.log(colourN(`Version`) + colourS(`: `) + colourV(version));
|
51
|
-
switch (commands[0]) {
|
52
|
-
case `config`:
|
53
|
-
{
|
54
|
-
switch (commands[1]) {
|
55
|
-
case `get`:
|
56
|
-
{
|
57
|
-
console.log(`
|
58
|
-
${colourJ(configGetCommandDescription)}
|
59
|
-
|
60
|
-
${colourA(`Usage:`)}
|
61
|
-
${colourC(`hsm`)} ${colourL(`${commands[0]} ${commands[1]}`)} ${colourB(`<key>`)}`);
|
62
|
-
}
|
63
|
-
break;
|
64
|
-
case `set`:
|
65
|
-
{
|
66
|
-
console.log(`
|
67
|
-
${colourJ(configSetCommandDescription)}
|
68
|
-
|
69
|
-
${colourA(`Usage:`)}
|
70
|
-
${colourC(`hsm`)} ${colourL(`${commands[0]} ${commands[1]}`)} ${colourB(`<key> <value>`)}`);
|
71
|
-
}
|
72
|
-
break;
|
73
|
-
case `delete`:
|
74
|
-
{
|
75
|
-
console.log(`
|
76
|
-
${colourJ(configDeleteCommandDescription)}
|
77
|
-
|
78
|
-
${colourA(`Usage:`)}
|
79
|
-
${colourC(`hsm`)} ${colourL(`${commands[0]} ${commands[1]}`)} ${colourB(`<key>`)}`);
|
80
|
-
}
|
81
|
-
break;
|
82
|
-
default:
|
83
|
-
{
|
84
|
-
console.log(colourS(`\
|
85
|
-
${colourN(`Config path`)}: ${colourV(configFilePath)}
|
86
|
-
|
87
|
-
${colourJ(`Modify the config file`)}
|
88
|
-
|
89
|
-
${colourA(`Usage:`)}
|
90
|
-
${colourC(`hsm`)} ${colourL(`${commands[0]} get`)} ${colourB(`<key>`)}
|
91
|
-
${configGetCommandDescription}
|
92
|
-
${colourC(`hsm`)} ${colourL(`${commands[0]} set`)} ${colourB(`<key> <value>`)}
|
93
|
-
${configSetCommandDescription}
|
94
|
-
${colourC(`hsm`)} ${colourL(`${commands[0]} delete`)} ${colourB(`<key>`)}
|
95
|
-
${configDeleteCommandDescription}`));
|
96
|
-
}
|
97
|
-
}
|
98
|
-
}
|
99
|
-
break;
|
100
|
-
case `push`:
|
101
|
-
{
|
102
|
-
console.log(colourS(`
|
103
|
-
${colourJ(pushCommandDescription)}
|
104
|
-
|
105
|
-
${colourA(`Usage:`)}
|
106
|
-
${colourC(`hsm`)} ${colourL(commands[0])} ${colourB(`<directory> [<script user>.<script name>...]`)}
|
107
|
-
|
108
|
-
${colourA(`Options:`)}
|
109
|
-
${colourN(`--skip-minify`)}
|
110
|
-
${skipMinifyOptionDescription}
|
111
|
-
${colourN(`--mangle-names`)}
|
112
|
-
${mangleNamesOptionDescription}
|
113
|
-
${colourN(`--force-quine-cheats`)}
|
114
|
-
${forceQuineCheatsOptionDescription}`));
|
115
|
-
}
|
116
|
-
break;
|
117
|
-
case `dev`:
|
118
|
-
case `watch`:
|
119
|
-
{
|
120
|
-
console.log(colourS(`\
|
121
|
-
${colourN(`Aliases`)}: ${colourV(`watch, dev`)}
|
122
|
-
|
123
|
-
${colourJ(watchCommandDescription)}
|
124
|
-
|
125
|
-
${colourA(`Usage:`)}
|
126
|
-
${colourC(`hsm`)} ${colourL(commands[0])} ${colourB(`<directory> [<script user>.<script name>...]`)}
|
127
|
-
|
128
|
-
${colourA(`Options:`)}
|
129
|
-
${colourN(`--skip-minify`)}
|
130
|
-
${skipMinifyOptionDescription}
|
131
|
-
${colourN(`--mangle-names`)}
|
132
|
-
${mangleNamesOptionDescription}
|
133
|
-
${colourN(`--type-declaration-path`)}=${colourB(`<path>`)}
|
134
|
-
Path to generate a type declaration file for the scripts
|
135
|
-
${colourN(`--force-quine-cheats`)}
|
136
|
-
${forceQuineCheatsOptionDescription}`));
|
137
|
-
}
|
138
|
-
break;
|
139
|
-
case `pull`:
|
140
|
-
{
|
141
|
-
console.log(colourS(`
|
142
|
-
${colourJ(pullCommandDescription)}
|
143
|
-
|
144
|
-
${colourA(`Usage:`)}
|
145
|
-
${colourC(`hsm`)} ${colourL(commands[0])} ${colourB(`<script user>`)}${colourV(`.`)}${colourB(`<script name>`)}`));
|
146
|
-
}
|
147
|
-
break;
|
148
|
-
case `minify`:
|
149
|
-
case `golf`:
|
150
|
-
{
|
151
|
-
console.log(colourS(`\
|
152
|
-
${colourN(`Aliases`)}: ${colourV(`minify, golf`)}
|
153
|
-
|
154
|
-
${colourJ(minifyCommandDescription)}
|
155
|
-
|
156
|
-
${colourA(`Usage:`)}
|
157
|
-
${colourC(`hsm`)} ${colourL(commands[0])} ${colourB(`<target> [output path]`)}
|
158
|
-
|
159
|
-
${colourA(`Options:`)}
|
160
|
-
${colourN(`--skip-minify`)}
|
161
|
-
${skipMinifyOptionDescription}
|
162
|
-
${colourN(`--mangle-names`)}
|
163
|
-
${mangleNamesOptionDescription}
|
164
|
-
${colourN(`--force-quine-cheats`)}
|
165
|
-
${forceQuineCheatsOptionDescription}
|
166
|
-
${colourN(`--watch`)}
|
167
|
-
Watch for changes`));
|
168
|
-
}
|
169
|
-
break;
|
170
|
-
case `generate-type-declaration`:
|
171
|
-
case `gen-type-declaration`:
|
172
|
-
case `gen-dts`:
|
173
|
-
case `gen-types`:
|
174
|
-
{
|
175
|
-
console.log(colourS(`\
|
176
|
-
${colourN(`Aliases`)}: ${colourV(`generate-type-declaration, gen-type-declaration, gen-types, gen-dts`)}
|
177
|
-
|
178
|
-
${colourJ(generateTypeDeclarationCommandDescription)}
|
179
|
-
|
180
|
-
${colourA(`Usage:`)}
|
181
|
-
${colourC(`hsm`)} ${colourL(commands[0])} ${colourB(`<directory> [output path]`)}`));
|
182
|
-
}
|
183
|
-
break;
|
184
|
-
case `sync-macros`:
|
185
|
-
{
|
186
|
-
console.log(`\n${colourJ(syncMacrosCommandDescription)}`);
|
187
|
-
}
|
188
|
-
break;
|
189
|
-
default:
|
190
|
-
{
|
191
|
-
console.log(colourS(`
|
192
|
-
${colourJ(`Hackmud Script Manager`)}
|
193
|
-
|
194
|
-
${colourA(`Commands:`)}
|
195
|
-
${colourL(`push`)}
|
196
|
-
${pushCommandDescription}
|
197
|
-
${colourL(`watch`)}, ${colourL(`dev`)}
|
198
|
-
${watchCommandDescription}
|
199
|
-
${colourL(`minify`)}, ${colourL(`golf`)}
|
200
|
-
${minifyCommandDescription}
|
201
|
-
${colourL(`generate-type-declaration`)}, ${colourL(`gen-type-declaration`)}, ${colourL(`gen-types`)}, ${colourL(`gen-dts`)}
|
202
|
-
${generateTypeDeclarationCommandDescription}
|
203
|
-
${colourL(`sync-macros`)}
|
204
|
-
${syncMacrosCommandDescription}
|
205
|
-
${colourL(`config`)}
|
206
|
-
${configCommandDescription}
|
207
|
-
${colourL(`pull`)}
|
208
|
-
${pullCommandDescription}`));
|
209
|
-
}
|
210
|
-
}
|
211
|
-
};
|
212
|
-
const exploreObject = (object, keys, createPath = false) => {
|
213
|
-
for (const key of keys) {
|
214
|
-
if (createPath) object = typeof object[key] == `object` ? object[key] : object[key] = {};else object = object?.[key];
|
215
|
-
}
|
216
|
-
return object;
|
217
|
-
};
|
218
|
-
const updateConfig = async config => {
|
219
|
-
const json = JSON.stringify(config, undefined, `\t`);
|
220
|
-
if (configDidNotExist) log(`Creating config file at ${configFilePath}`);
|
221
|
-
await writeFile(configFilePath, json).catch(async error => {
|
222
|
-
switch (error.code) {
|
223
|
-
case `EISDIR`:
|
224
|
-
{
|
225
|
-
await rmdir(configFilePath);
|
226
|
-
}
|
227
|
-
break;
|
228
|
-
case `ENOENT`:
|
229
|
-
{
|
230
|
-
await mkdir(configDirectoryPath);
|
231
|
-
}
|
232
|
-
break;
|
233
|
-
default:
|
234
|
-
throw error;
|
235
|
-
}
|
236
|
-
await writeFile(configFilePath, json);
|
237
|
-
});
|
238
|
-
};
|
239
|
-
const logInfo = ({
|
240
|
-
file,
|
241
|
-
users,
|
242
|
-
minLength,
|
243
|
-
error
|
244
|
-
}, hackmudPath) => {
|
245
|
-
if (error) {
|
246
|
-
logError(`error "${chalk.bold(error.message)}" in ${chalk.bold(file)}`);
|
247
|
-
return;
|
248
|
-
}
|
249
|
-
console.log(`pushed ${chalk.bold(file)} to ${users.map(user => chalk.bold(userColours.get(user))).join(`, `)} | ${chalk.bold(String(minLength))} chars | ${chalk.bold(`${resolve(hackmudPath, users[0], `scripts`, basename(file, extname(file)))}.js`)}`);
|
250
|
-
};
|
251
|
-
const log = message => {
|
252
|
-
console.log(colourS(message));
|
253
|
-
};
|
254
|
-
const logError = message => {
|
255
|
-
console.error(colourD(message));
|
256
|
-
process.exitCode = 1;
|
257
|
-
};
|
258
|
-
for (const argument of process.argv.slice(2)) {
|
259
|
-
if (argument[0] == `-`) {
|
260
|
-
const [key, valueRaw] = argument.split(`=`);
|
261
|
-
let value = valueRaw;
|
262
|
-
if (value) {
|
263
|
-
if (value == `true`) value = true;else if (value == `false`) value = false;else {
|
264
|
-
const number = Number(value);
|
265
|
-
if (isFinite(number)) value = number;
|
266
|
-
}
|
267
|
-
} else value = true;
|
268
|
-
if (argument[1] == `-`) options.set(key.slice(2), value);else {
|
269
|
-
for (const option of key.slice(1)) options.set(option, value);
|
270
|
-
}
|
271
|
-
} else commands.push(argument);
|
272
|
-
}
|
273
|
-
if (commands[0] == `v` || commands[0] == `version` || options.get(`version`) || options.get(`v`)) {
|
274
|
-
console.log(version);
|
275
|
-
process.exit();
|
276
|
-
}
|
277
|
-
let configDidNotExist = false;
|
278
|
-
const configPromise = readFile(configFilePath, {
|
279
|
-
encoding: `utf-8`
|
280
|
-
}).then(configFile => {
|
281
|
-
let temporaryConfig;
|
282
|
-
try {
|
283
|
-
temporaryConfig = JSON.parse(configFile);
|
284
|
-
} catch {
|
285
|
-
// TODO log to error log file
|
286
|
-
log(`Config file was corrupted, resetting`);
|
287
|
-
return {};
|
288
|
-
}
|
289
|
-
if (!temporaryConfig || typeof temporaryConfig != `object`) {
|
290
|
-
log(`Config file was corrupted, resetting`);
|
291
|
-
return {};
|
292
|
-
}
|
293
|
-
if (`hackmudPath` in temporaryConfig && typeof temporaryConfig.hackmudPath != `string`) {
|
294
|
-
log(`Property "hackmudPath" of config file was corrupted, removing`);
|
295
|
-
delete temporaryConfig.hackmudPath;
|
296
|
-
}
|
297
|
-
return temporaryConfig;
|
298
|
-
}, () => {
|
299
|
-
configDidNotExist = true;
|
300
|
-
return {};
|
301
|
-
});
|
302
|
-
const pushModule = import('../push.js');
|
303
|
-
const processScriptModule = import('../processScript/index.js');
|
304
|
-
const watchModule = import('../watch.js');
|
305
|
-
const chokidarModule = import('chokidar');
|
306
|
-
const {
|
307
|
-
default: chalk
|
308
|
-
} = await import('chalk');
|
309
|
-
const colourA = chalk.rgb(0xFF, 0xFF, 0xFF);
|
310
|
-
const colourB = chalk.rgb(0xCA, 0xCA, 0xCA);
|
311
|
-
const colourC = chalk.rgb(0x9B, 0x9B, 0x9B);
|
312
|
-
const colourD = chalk.rgb(0xFF, 0x00, 0x00);
|
313
|
-
const colourJ = chalk.rgb(0xFF, 0xF4, 0x04);
|
314
|
-
const colourK = chalk.rgb(0xF3, 0xF9, 0x98);
|
315
|
-
const colourL = chalk.rgb(0x1E, 0xFF, 0x00);
|
316
|
-
const colourM = chalk.rgb(0xB3, 0xFF, 0x9B);
|
317
|
-
const colourN = chalk.rgb(0x00, 0xFF, 0xFF);
|
318
|
-
const colourS = chalk.rgb(0x7A, 0xB2, 0xF4);
|
319
|
-
const colourV = chalk.rgb(0xFF, 0x00, 0xEC);
|
320
|
-
const colourW = chalk.rgb(0xFF, 0x96, 0xE0);
|
321
|
-
if (options.get(`help`) || options.get(`h`)) {
|
322
|
-
logHelp();
|
323
|
-
process.exit();
|
324
|
-
}
|
325
|
-
let autoExit = true;
|
326
|
-
switch (commands[0]) {
|
327
|
-
case `push`:
|
328
|
-
{
|
329
|
-
const {
|
330
|
-
hackmudPath
|
331
|
-
} = await configPromise;
|
332
|
-
if (!hackmudPath) {
|
333
|
-
logNeedHackmudPathMessage();
|
334
|
-
break;
|
335
|
-
}
|
336
|
-
const sourcePath = commands[1];
|
337
|
-
if (!sourcePath) {
|
338
|
-
logError(`Must provide the directory to push from\n`);
|
339
|
-
logHelp();
|
340
|
-
break;
|
341
|
-
}
|
342
|
-
const scripts = commands.slice(2);
|
343
|
-
if (scripts.length) {
|
344
|
-
const invalidScript = scripts.find(script => !/^(?:[a-z_][a-z\d_]{0,24}|\*)\.(?:[a-z_][a-z\d_]{0,24}|\*)$/.test(script));
|
345
|
-
if (invalidScript) {
|
346
|
-
logError(`Invalid script name: ${JSON.stringify(invalidScript)}\n`);
|
347
|
-
logHelp();
|
348
|
-
break;
|
349
|
-
}
|
350
|
-
} else scripts.push(`*.*`);
|
351
|
-
if (options.has(`skip-minify`) && options.has(`mangle-names`)) {
|
352
|
-
logError(`Option ${colourN(`--mangle-names`)} is not compatible with ${colourN(`--skip-minify`)}\n`);
|
353
|
-
logHelp();
|
354
|
-
break;
|
355
|
-
}
|
356
|
-
const shouldSkipMinify = options.get(`skip-minify`);
|
357
|
-
let shouldMinify;
|
358
|
-
if (shouldSkipMinify != undefined) {
|
359
|
-
if (typeof shouldSkipMinify != `boolean`) {
|
360
|
-
logError(`The value for ${colourN(`--skip-minify`)} must be ${colourV(`true`)} or ${colourV(`false`)}\n`);
|
361
|
-
logHelp();
|
362
|
-
break;
|
363
|
-
}
|
364
|
-
shouldMinify = !shouldSkipMinify;
|
365
|
-
}
|
366
|
-
const shouldMangleNames = options.get(`mangle-names`);
|
367
|
-
if (shouldMangleNames != undefined && typeof shouldMangleNames != `boolean`) {
|
368
|
-
logError(`The value for ${colourN(`--mangle-names`)} must be ${colourV(`true`)} or ${colourV(`false`)}\n`);
|
369
|
-
logHelp();
|
370
|
-
break;
|
371
|
-
}
|
372
|
-
const shouldforceQuineCheats = options.get(`force-quine-cheats`);
|
373
|
-
if (shouldforceQuineCheats != undefined && typeof shouldforceQuineCheats != `boolean`) {
|
374
|
-
logError(`The value for ${colourN(`--force-quine-cheats`)} must be ${colourV(`true`)} or ${colourV(`false`)}\n`);
|
375
|
-
logHelp();
|
376
|
-
break;
|
377
|
-
}
|
378
|
-
const {
|
379
|
-
push
|
380
|
-
} = await pushModule;
|
381
|
-
const infos = await push(sourcePath, hackmudPath, {
|
382
|
-
scripts,
|
383
|
-
onPush: info => logInfo(info, hackmudPath),
|
384
|
-
minify: shouldMinify,
|
385
|
-
mangleNames: shouldMangleNames,
|
386
|
-
forceQuineCheats: shouldforceQuineCheats
|
387
|
-
});
|
388
|
-
if (!infos.length) logError(`Could not find any scripts to push`);
|
389
|
-
}
|
390
|
-
break;
|
391
|
-
case `dev`:
|
392
|
-
case `watch`:
|
393
|
-
{
|
394
|
-
const {
|
395
|
-
hackmudPath
|
396
|
-
} = await configPromise;
|
397
|
-
if (!hackmudPath) {
|
398
|
-
logNeedHackmudPathMessage();
|
399
|
-
break;
|
400
|
-
}
|
401
|
-
const sourcePath = commands[1];
|
402
|
-
if (!sourcePath) {
|
403
|
-
logError(`Must provide the directory to watch\n`);
|
404
|
-
logHelp();
|
405
|
-
break;
|
406
|
-
}
|
407
|
-
const scripts = commands.slice(2);
|
408
|
-
if (scripts.length) {
|
409
|
-
const invalidScript = scripts.find(script => !/^(?:[a-z_][a-z\d_]{0,24}|\*)\.(?:[a-z_][a-z\d_]{0,24}|\*)$/.test(script));
|
410
|
-
if (invalidScript) {
|
411
|
-
logError(`Invalid script name: ${JSON.stringify(invalidScript)}\n`);
|
412
|
-
logHelp();
|
413
|
-
break;
|
414
|
-
}
|
415
|
-
} else scripts.push(`*.*`);
|
416
|
-
if (options.has(`skip-minify`) && options.has(`mangle-names`)) {
|
417
|
-
logError(`Option ${colourN(`--mangle-names`)} is not compatible with ${colourN(`--skip-minify`)}\n`);
|
418
|
-
logHelp();
|
419
|
-
break;
|
420
|
-
}
|
421
|
-
const shouldSkipMinify = options.get(`skip-minify`);
|
422
|
-
let shouldMinify;
|
423
|
-
if (shouldSkipMinify != undefined) {
|
424
|
-
if (typeof shouldSkipMinify != `boolean`) {
|
425
|
-
logError(`The value for ${colourN(`--skip-minify`)} must be ${colourV(`true`)} or ${colourV(`false`)}\n`);
|
426
|
-
logHelp();
|
427
|
-
break;
|
428
|
-
}
|
429
|
-
shouldMinify = !shouldSkipMinify;
|
430
|
-
}
|
431
|
-
const shouldMangleNames = options.get(`mangle-names`);
|
432
|
-
if (shouldMangleNames != undefined && typeof shouldMangleNames != `boolean`) {
|
433
|
-
logError(`The value for ${colourN(`--mangle-names`)} must be ${colourV(`true`)} or ${colourV(`false`)}\n`);
|
434
|
-
logHelp();
|
435
|
-
break;
|
436
|
-
}
|
437
|
-
const shouldforceQuineCheats = options.get(`force-quine-cheats`);
|
438
|
-
if (shouldforceQuineCheats != undefined && typeof shouldforceQuineCheats != `boolean`) {
|
439
|
-
logError(`The value for ${colourN(`--force-quine-cheats`)} must be ${colourV(`true`)} or ${colourV(`false`)}\n`);
|
440
|
-
logHelp();
|
441
|
-
break;
|
442
|
-
}
|
443
|
-
const {
|
444
|
-
watch
|
445
|
-
} = await watchModule;
|
446
|
-
watch(sourcePath, hackmudPath, {
|
447
|
-
scripts,
|
448
|
-
onPush: info => logInfo(info, hackmudPath),
|
449
|
-
typeDeclarationPath: (options.get(`type-declaration-path`) || options.get(`type-declaration`) || options.get(`dts`) || options.get(`gen-types`))?.toString(),
|
450
|
-
minify: shouldMinify,
|
451
|
-
mangleNames: shouldMangleNames,
|
452
|
-
onReady: () => log(`Watching`),
|
453
|
-
forceQuineCheats: shouldforceQuineCheats
|
454
|
-
});
|
455
|
-
autoExit = false;
|
456
|
-
}
|
457
|
-
break;
|
458
|
-
case `pull`:
|
459
|
-
{
|
460
|
-
const {
|
461
|
-
hackmudPath
|
462
|
-
} = await configPromise;
|
463
|
-
if (!hackmudPath) {
|
464
|
-
logNeedHackmudPathMessage();
|
465
|
-
break;
|
466
|
-
}
|
467
|
-
const script = commands[1];
|
468
|
-
if (!script) {
|
469
|
-
logError(`Must provide the script to pull\n`);
|
470
|
-
logHelp();
|
471
|
-
break;
|
472
|
-
}
|
473
|
-
const sourcePath = commands[2] || `.`;
|
474
|
-
try {
|
475
|
-
await pull(sourcePath, hackmudPath, script);
|
476
|
-
} catch (error) {
|
477
|
-
console.error(error);
|
478
|
-
logError(`Something went wrong, did you forget to ${colourC(`#down`)} the script?`);
|
479
|
-
}
|
480
|
-
}
|
481
|
-
break;
|
482
|
-
case `sync-macros`:
|
483
|
-
{
|
484
|
-
const {
|
485
|
-
hackmudPath
|
486
|
-
} = await configPromise;
|
487
|
-
if (!hackmudPath) {
|
488
|
-
logNeedHackmudPathMessage();
|
489
|
-
break;
|
490
|
-
}
|
491
|
-
const {
|
492
|
-
macrosSynced,
|
493
|
-
usersSynced
|
494
|
-
} = await syncMacros(hackmudPath);
|
495
|
-
log(`Synced ${macrosSynced} macros to ${usersSynced} users`);
|
496
|
-
}
|
497
|
-
break;
|
498
|
-
case `generate-type-declaration`:
|
499
|
-
case `gen-type-declaration`:
|
500
|
-
case `gen-dts`:
|
501
|
-
case `gen-types`:
|
502
|
-
{
|
503
|
-
const target = commands[1];
|
504
|
-
if (!target) {
|
505
|
-
logError(`Must provide target directory\n`);
|
506
|
-
logHelp();
|
507
|
-
break;
|
508
|
-
}
|
509
|
-
const sourcePath = resolve(target);
|
510
|
-
const outputPath = commands[2] || `./player.d.ts`;
|
511
|
-
const typeDeclaration = await generateTypeDeclaration(sourcePath, (await configPromise).hackmudPath);
|
512
|
-
let typeDeclarationPath = resolve(outputPath);
|
513
|
-
try {
|
514
|
-
await writeFile(typeDeclarationPath, typeDeclaration);
|
515
|
-
} catch (error) {
|
516
|
-
assert(error instanceof Error);
|
517
|
-
if (!(error.code == `EISDIR`)) throw error;
|
518
|
-
typeDeclarationPath = resolve(typeDeclarationPath, `player.d.ts`);
|
519
|
-
await writeFile(typeDeclarationPath, typeDeclaration);
|
520
|
-
}
|
521
|
-
log(`Wrote type declaration to ${chalk.bold(typeDeclarationPath)}`);
|
522
|
-
}
|
523
|
-
break;
|
524
|
-
case `config`:
|
525
|
-
{
|
526
|
-
switch (commands[1]) {
|
527
|
-
case `get`:
|
528
|
-
{
|
529
|
-
const key = commands[2];
|
530
|
-
if (key) log(exploreObject(await configPromise, key.split(`.`)));else console.log(await configPromise);
|
531
|
-
}
|
532
|
-
break;
|
533
|
-
case `delete`:
|
534
|
-
{
|
535
|
-
const key = commands[2];
|
536
|
-
if (!key) {
|
537
|
-
logError(`Must provide a key to delete\n`);
|
538
|
-
logHelp();
|
539
|
-
break;
|
540
|
-
}
|
541
|
-
const keyParts = key.split(`.`);
|
542
|
-
const pathName = keyParts.map(name => /^[A-Za-z_$][\w$]*$/.test(name) ? name : JSON.stringify(name)).join(`.`);
|
543
|
-
const lastKey = keyParts.pop();
|
544
|
-
const config = await configPromise;
|
545
|
-
delete exploreObject(config, keyParts)?.[lastKey];
|
546
|
-
log(`Removed ${colourV(pathName)} from config file`);
|
547
|
-
}
|
548
|
-
break;
|
549
|
-
case `set`:
|
550
|
-
{
|
551
|
-
const key = commands[2];
|
552
|
-
const value = commands[3];
|
553
|
-
if (!key) {
|
554
|
-
logError(`Must provide a key and value\n`);
|
555
|
-
logHelp();
|
556
|
-
break;
|
557
|
-
}
|
558
|
-
const keys = key.split(`.`);
|
559
|
-
const pathName = keys.map(name => /^[A-Za-z_$][\w$]*$/.test(name) ? name : JSON.stringify(name)).join(`.`);
|
560
|
-
if (!value) {
|
561
|
-
logError(`Must provide a value for the key ${pathName}\n`);
|
562
|
-
logHelp();
|
563
|
-
break;
|
564
|
-
}
|
565
|
-
const lastKey = keys.pop();
|
566
|
-
const config = await configPromise;
|
567
|
-
if (!keys.length && lastKey == `hackmudPath`) config.hackmudPath = resolve(value.startsWith(`~/`) ? homedir() + value.slice(1) : value);else {
|
568
|
-
let object = config;
|
569
|
-
for (const key of keys) {
|
570
|
-
if (typeof object[key] == `object`) object = object[key];else {
|
571
|
-
object[key] = {};
|
572
|
-
object = object[key];
|
573
|
-
}
|
574
|
-
}
|
575
|
-
object[lastKey] = value;
|
576
|
-
}
|
577
|
-
console.log(config);
|
578
|
-
await updateConfig(config);
|
579
|
-
}
|
580
|
-
break;
|
581
|
-
default:
|
582
|
-
{
|
583
|
-
if (commands[1]) logError(`Unknown command: ${JSON.stringify(commands[1])}\n`);
|
584
|
-
logHelp();
|
585
|
-
}
|
586
|
-
}
|
587
|
-
}
|
588
|
-
break;
|
589
|
-
case `help`:
|
590
|
-
case `h`:
|
591
|
-
{
|
592
|
-
logHelp();
|
593
|
-
}
|
594
|
-
break;
|
595
|
-
case `golf`:
|
596
|
-
case `minify`:
|
597
|
-
{
|
598
|
-
const target = commands[1];
|
599
|
-
if (!target) {
|
600
|
-
logError(`Must provide target\n`);
|
601
|
-
logHelp();
|
602
|
-
break;
|
603
|
-
}
|
604
|
-
const fileExtension = extname(target);
|
605
|
-
if (!supportedExtensions.includes(fileExtension)) {
|
606
|
-
logError(`Unsupported file extension "${chalk.bold(fileExtension)}"\nSupported extensions are "${supportedExtensions.map(extension => chalk.bold(extension)).join(`", "`)}"`);
|
607
|
-
break;
|
608
|
-
}
|
609
|
-
const {
|
610
|
-
processScript
|
611
|
-
} = await processScriptModule;
|
612
|
-
const fileBaseName = basename(target, fileExtension);
|
613
|
-
// eslint-disable-next-line unicorn/prevent-abbreviations -- the file extension is `src` not `source`
|
614
|
-
const fileBaseNameEndsWithDotSrc = fileBaseName.endsWith(`.src`);
|
615
|
-
const scriptName = fileBaseNameEndsWithDotSrc ? fileBaseName.slice(0, -4) : fileBaseName;
|
616
|
-
const scriptUser = basename(resolve(target, `..`)) == `scripts` && basename(resolve(target, `../../..`)) == `hackmud` ? basename(resolve(target, `../..`)) : `UNKNOWN`;
|
617
|
-
const minify = !options.get(`skip-minify`);
|
618
|
-
if (options.has(`skip-minify`) && options.has(`mangle-names`)) {
|
619
|
-
logError(`Option ${colourN(`--mangle-names`)} would have no effect if minification is skipped\n`);
|
620
|
-
logHelp();
|
621
|
-
break;
|
622
|
-
}
|
623
|
-
const mangleNames_ = options.get(`mangle-names`);
|
624
|
-
if (mangleNames_ != undefined && typeof mangleNames_ != `boolean`) {
|
625
|
-
logError(`The value for ${colourN(`--mangle-names`)} must be ${colourV(`true`)} or ${colourV(`false`)}\n`);
|
626
|
-
logHelp();
|
627
|
-
break;
|
628
|
-
}
|
629
|
-
const mangleNames = mangleNames_;
|
630
|
-
const forceQuineCheats_ = options.get(`force-quine-cheats`);
|
631
|
-
if (forceQuineCheats_ != undefined && typeof forceQuineCheats_ != `boolean`) {
|
632
|
-
logError(`the value for ${colourN(`--force-quine-cheats`)} must be ${colourV(`true`)} or ${colourV(`false`)}\n`);
|
633
|
-
logHelp();
|
634
|
-
break;
|
635
|
-
}
|
636
|
-
const forceQuineCheats = forceQuineCheats_;
|
637
|
-
let outputPath = commands[2] || resolve(dirname(target), fileBaseNameEndsWithDotSrc ? `${scriptName}.js` : fileExtension == `.js` ? `${fileBaseName}.min.js` : `${fileBaseName}.js`);
|
638
|
-
const golfFile = () => readFile(target, {
|
639
|
-
encoding: `utf-8`
|
640
|
-
}).then(async source => {
|
641
|
-
const timeStart = performance.now();
|
642
|
-
const {
|
643
|
-
script,
|
644
|
-
warnings
|
645
|
-
} = await processScript(source, {
|
646
|
-
minify,
|
647
|
-
scriptUser,
|
648
|
-
scriptName,
|
649
|
-
filePath: target,
|
650
|
-
mangleNames,
|
651
|
-
forceQuineCheats
|
652
|
-
});
|
653
|
-
const timeTook = performance.now() - timeStart;
|
654
|
-
for (const {
|
655
|
-
message,
|
656
|
-
line
|
657
|
-
} of warnings) log(`Warning "${chalk.bold(message)}" on line ${chalk.bold(String(line))}`);
|
658
|
-
await writeFilePersistent(outputPath, script).catch(async error => {
|
659
|
-
if (!commands[2] || error.code != `EISDIR`) throw error;
|
660
|
-
outputPath = resolve(outputPath, `${basename(target, fileExtension)}.js`);
|
661
|
-
await writeFilePersistent(outputPath, script);
|
662
|
-
}).then(() => log(`Wrote ${chalk.bold(countHackmudCharacters(script))} chars to ${chalk.bold(relative(`.`, outputPath))} | took ${Math.round(timeTook * 100) / 100}ms`), error => logError(error.message));
|
663
|
-
}, error => logError(error.message));
|
664
|
-
if (options.get(`watch`)) {
|
665
|
-
const {
|
666
|
-
watch: watchFile
|
667
|
-
} = await chokidarModule;
|
668
|
-
watchFile(target, {
|
669
|
-
awaitWriteFinish: {
|
670
|
-
stabilityThreshold: 100
|
671
|
-
}
|
672
|
-
}).on(`ready`, () => log(`Watching ${target}`)).on(`change`, golfFile);
|
673
|
-
autoExit = false;
|
674
|
-
} else await golfFile();
|
675
|
-
}
|
676
|
-
break;
|
677
|
-
default:
|
678
|
-
{
|
679
|
-
if (commands[0]) logError(`Unknown command: ${JSON.stringify(commands[0])}\n`);
|
680
|
-
logHelp();
|
681
|
-
}
|
682
|
-
}
|
683
|
-
if (autoExit) process.exit();
|
2
|
+
import{DynamicMap as e}from"@samual/lib/DynamicMap";import{assert as t}from"@samual/lib/assert";import{countHackmudCharacters as n}from"@samual/lib/countHackmudCharacters";import{writeFilePersistent as a}from"@samual/lib/writeFilePersistent";import{readFile as s,writeFile as o,mkdir as i,rmdir as r}from"fs/promises";import{homedir as c}from"os";import{supportedExtensions as l}from"../constants.js";import{generateTypeDeclaration as f}from"../generateTypeDeclaration.js";import{pull as $}from"../pull.js";import{syncMacros as p}from"../syncMacros.js";import{resolve as m,extname as h,basename as u,dirname as g,relative as d}from"path";import"@samual/lib/copyFilePersistent";const y="0.19.0-b5e2c0b",b=m(c(),".config"),k=m(b,"hsm.json"),w=new Map,v=[],S=new e((e=>{let t=0;for(const n of e)t+=(t>>1)+t+"xi1_8ratvsw9hlbgm02y5zpdcn7uekof463qj".indexOf(n)+1;return[_,x,J,F,I,z][t%6](e)})),logNeedHackmudPathMessage=()=>console.error(D(`${W("You need to set hackmudPath in config before you can use this command")}\n\n${q("To fix this:")}\nOpen hackmud and run "${C("#dir")}"\nThis will open a file browser and print your hackmud user's script directory\nGo up 2 directories and then copy the path\nThen in a terminal run "${C("hsm")} ${I("config set")} ${E("hackmudPath")} ${z("<the path you copied>")}"`)),logHelp=()=>{const e="Push scripts from a directory to hackmud user's scripts directories",t="Watch a directory and push a script when modified",n="Minify a script file on the spot",a="Generate a type declaration file for a directory of scripts",s="Sync macros across all hackmud users",o="Retrieve a value from the config file",i="Assign a value to the config file",r="Remove a key and value from the config file",c="Pull a script a from a hackmud user's script directory",l="Skip minification to produce a readable script",f="Reduce character count further but lose function names in error call stacks",$="Force quine cheats even if the character count is higher";switch(console.log(R("Version")+D(": ")+E(y)),v[0]){case"config":switch(v[1]){case"get":console.log(`\n${_(o)}\n\n${q("Usage:")}\n${C("hsm")} ${I(`${v[0]} ${v[1]}`)} ${z("<key>")}`);break;case"set":console.log(`\n${_(i)}\n\n${q("Usage:")}\n${C("hsm")} ${I(`${v[0]} ${v[1]}`)} ${z("<key> <value>")}`);break;case"delete":console.log(`\n${_(r)}\n\n${q("Usage:")}\n${C("hsm")} ${I(`${v[0]} ${v[1]}`)} ${z("<key>")}`);break;default:console.log(D(`${R("Config path")}: ${E(k)}\n\n${_("Modify the config file")}\n\n${q("Usage:")}\n${C("hsm")} ${I(`${v[0]} get`)} ${z("<key>")}\n ${o}\n${C("hsm")} ${I(`${v[0]} set`)} ${z("<key> <value>")}\n ${i}\n${C("hsm")} ${I(`${v[0]} delete`)} ${z("<key>")}\n ${r}`))}break;case"push":console.log(D(`\n${_(e)}\n\n${q("Usage:")}\n${C("hsm")} ${I(v[0])} ${z("<directory> [<script user>.<script name>...]")}\n\n${q("Options:")}\n${R("--skip-minify")}\n ${l}\n${R("--mangle-names")}\n ${f}\n${R("--force-quine-cheats")}\n ${$}`));break;case"dev":case"watch":console.log(D(`${R("Aliases")}: ${E("watch, dev")}\n\n${_(t)}\n\n${q("Usage:")}\n${C("hsm")} ${I(v[0])} ${z("<directory> [<script user>.<script name>...]")}\n\n${q("Options:")}\n${R("--skip-minify")}\n ${l}\n${R("--mangle-names")}\n ${f}\n${R("--type-declaration-path")}=${z("<path>")}\n Path to generate a type declaration file for the scripts\n${R("--force-quine-cheats")}\n ${$}`));break;case"pull":console.log(D(`\n${_(c)}\n\n${q("Usage:")}\n${C("hsm")} ${I(v[0])} ${z("<script user>")}${E(".")}${z("<script name>")}`));break;case"minify":case"golf":console.log(D(`${R("Aliases")}: ${E("minify, golf")}\n\n${_(n)}\n\n${q("Usage:")}\n${C("hsm")} ${I(v[0])} ${z("<target> [output path]")}\n\n${q("Options:")}\n${R("--skip-minify")}\n ${l}\n${R("--mangle-names")}\n ${f}\n${R("--force-quine-cheats")}\n ${$}\n${R("--watch")}\n Watch for changes`));break;case"generate-type-declaration":case"gen-type-declaration":case"gen-dts":case"gen-types":console.log(D(`${R("Aliases")}: ${E("generate-type-declaration, gen-type-declaration, gen-types, gen-dts")}\n\n${_(a)}\n\n${q("Usage:")}\n${C("hsm")} ${I(v[0])} ${z("<directory> [output path]")}`));break;case"sync-macros":console.log(`\n${_(s)}`);break;default:console.log(D(`\n${_("Hackmud Script Manager")}\n\n${q("Commands:")}\n${I("push")}\n ${e}\n${I("watch")}, ${I("dev")}\n ${t}\n${I("minify")}, ${I("golf")}\n ${n}\n${I("generate-type-declaration")}, ${I("gen-type-declaration")}, ${I("gen-types")}, ${I("gen-dts")}\n ${a}\n${I("sync-macros")}\n ${s}\n${I("config")}\n Modify and view the config file\n${I("pull")}\n ${c}`))}},exploreObject=(e,t,n=!1)=>{for(const a of t)e=n?"object"==typeof e[a]?e[a]:e[a]={}:e?.[a];return e},logInfo=({file:e,users:t,minLength:n,error:a},s)=>{a?logError(`error "${T.bold(a.message)}" in ${T.bold(e)}`):console.log(`pushed ${T.bold(e)} to ${t.map((e=>T.bold(S.get(e)))).join(", ")} | ${T.bold(String(n))} chars | ${T.bold(`${m(s,t[0],"scripts",u(e,h(e)))}.js`)}`)},log=e=>{console.log(D(e))},logError=e=>{console.error(W(e)),process.exitCode=1};for(const e of process.argv.slice(2))if("-"==e[0]){const[t,n]=e.split("=");let a=n;if(a)if("true"==a)a=!0;else if("false"==a)a=!1;else{const e=Number(a);isFinite(e)&&(a=e)}else a=!0;if("-"==e[1])w.set(t.slice(2),a);else for(const e of t.slice(1))w.set(e,a)}else v.push(e);("v"==v[0]||"version"==v[0]||w.get("version")||w.get("v"))&&(console.log(y),process.exit());let P=!1;const j=s(k,{encoding:"utf-8"}).then((e=>{let t;try{t=JSON.parse(e)}catch{return log("Config file was corrupted, resetting"),{}}return t&&"object"==typeof t?("hackmudPath"in t&&"string"!=typeof t.hackmudPath&&(log('Property "hackmudPath" of config file was corrupted, removing'),delete t.hackmudPath),t):(log("Config file was corrupted, resetting"),{})}),(()=>(P=!0,{}))),N=import("../push.js"),O=import("../processScript/index.js"),M=import("../watch.js"),U=import("chokidar"),{default:T}=await import("chalk"),q=T.rgb(255,255,255),z=T.rgb(202,202,202),C=T.rgb(155,155,155),W=T.rgb(255,0,0),_=T.rgb(255,244,4),x=T.rgb(243,249,152),I=T.rgb(30,255,0),J=T.rgb(179,255,155),R=T.rgb(0,255,255),D=T.rgb(122,178,244),E=T.rgb(255,0,236),F=T.rgb(255,150,224);(w.get("help")||w.get("h"))&&(logHelp(),process.exit());let A=!0;switch(v[0]){case"push":{const{hackmudPath:e}=await j;if(!e){logNeedHackmudPathMessage();break}const t=v[1];if(!t){logError("Must provide the directory to push from\n"),logHelp();break}const n=v.slice(2);if(n.length){const e=n.find((e=>!/^(?:[a-z_][a-z\d_]{0,24}|\*)\.(?:[a-z_][a-z\d_]{0,24}|\*)$/.test(e)));if(e){logError(`Invalid script name: ${JSON.stringify(e)}\n`),logHelp();break}}else n.push("*.*");if(w.has("skip-minify")&&w.has("mangle-names")){logError(`Option ${R("--mangle-names")} is not compatible with ${R("--skip-minify")}\n`),logHelp();break}const a=w.get("skip-minify");let s;if(null!=a){if("boolean"!=typeof a){logError(`The value for ${R("--skip-minify")} must be ${E("true")} or ${E("false")}\n`),logHelp();break}s=!a}const o=w.get("mangle-names");if(null!=o&&"boolean"!=typeof o){logError(`The value for ${R("--mangle-names")} must be ${E("true")} or ${E("false")}\n`),logHelp();break}const i=w.get("force-quine-cheats");if(null!=i&&"boolean"!=typeof i){logError(`The value for ${R("--force-quine-cheats")} must be ${E("true")} or ${E("false")}\n`),logHelp();break}const{push:r}=await N;(await r(t,e,{scripts:n,onPush:t=>logInfo(t,e),minify:s,mangleNames:o,forceQuineCheats:i})).length||logError("Could not find any scripts to push")}break;case"dev":case"watch":{const{hackmudPath:e}=await j;if(!e){logNeedHackmudPathMessage();break}const t=v[1];if(!t){logError("Must provide the directory to watch\n"),logHelp();break}const n=v.slice(2);if(n.length){const e=n.find((e=>!/^(?:[a-z_][a-z\d_]{0,24}|\*)\.(?:[a-z_][a-z\d_]{0,24}|\*)$/.test(e)));if(e){logError(`Invalid script name: ${JSON.stringify(e)}\n`),logHelp();break}}else n.push("*.*");if(w.has("skip-minify")&&w.has("mangle-names")){logError(`Option ${R("--mangle-names")} is not compatible with ${R("--skip-minify")}\n`),logHelp();break}const a=w.get("skip-minify");let s;if(null!=a){if("boolean"!=typeof a){logError(`The value for ${R("--skip-minify")} must be ${E("true")} or ${E("false")}\n`),logHelp();break}s=!a}const o=w.get("mangle-names");if(null!=o&&"boolean"!=typeof o){logError(`The value for ${R("--mangle-names")} must be ${E("true")} or ${E("false")}\n`),logHelp();break}const i=w.get("force-quine-cheats");if(null!=i&&"boolean"!=typeof i){logError(`The value for ${R("--force-quine-cheats")} must be ${E("true")} or ${E("false")}\n`),logHelp();break}const{watch:r}=await M;r(t,e,{scripts:n,onPush:t=>logInfo(t,e),typeDeclarationPath:(w.get("type-declaration-path")||w.get("type-declaration")||w.get("dts")||w.get("gen-types"))?.toString(),minify:s,mangleNames:o,onReady:()=>log("Watching"),forceQuineCheats:i}),A=!1}break;case"pull":{const{hackmudPath:e}=await j;if(!e){logNeedHackmudPathMessage();break}const t=v[1];if(!t){logError("Must provide the script to pull\n"),logHelp();break}const n=v[2]||".";try{await $(n,e,t)}catch(e){console.error(e),logError(`Something went wrong, did you forget to ${C("#down")} the script?`)}}break;case"sync-macros":{const{hackmudPath:e}=await j;if(!e){logNeedHackmudPathMessage();break}const{macrosSynced:t,usersSynced:n}=await p(e);log(`Synced ${t} macros to ${n} users`)}break;case"generate-type-declaration":case"gen-type-declaration":case"gen-dts":case"gen-types":{const e=v[1];if(!e){logError("Must provide target directory\n"),logHelp();break}const n=m(e),a=v[2]||"./player.d.ts",s=await f(n,(await j).hackmudPath);let i=m(a);try{await o(i,s)}catch(e){if(t(e instanceof Error),"EISDIR"!=e.code)throw e;i=m(i,"player.d.ts"),await o(i,s)}log(`Wrote type declaration to ${T.bold(i)}`)}break;case"config":switch(v[1]){case"get":{const e=v[2];e?log(exploreObject(await j,e.split("."))):console.log(await j)}break;case"delete":{const e=v[2];if(!e){logError("Must provide a key to delete\n"),logHelp();break}const t=e.split("."),n=t.map((e=>/^[a-z_$][\w$]*$/i.test(e)?e:JSON.stringify(e))).join("."),a=t.pop(),s=await j;delete exploreObject(s,t)?.[a],log(`Removed ${E(n)} from config file`)}break;case"set":{const e=v[2],t=v[3];if(!e){logError("Must provide a key and value\n"),logHelp();break}const n=e.split("."),a=n.map((e=>/^[a-z_$][\w$]*$/i.test(e)?e:JSON.stringify(e))).join(".");if(!t){logError(`Must provide a value for the key ${a}\n`),logHelp();break}const s=n.pop(),l=await j;if(n.length||"hackmudPath"!=s){let e=l;for(const t of n)"object"==typeof e[t]||(e[t]={}),e=e[t];e[s]=t}else l.hackmudPath=m(t.startsWith("~/")?c()+t.slice(1):t);console.log(l),await(async e=>{const t=JSON.stringify(e,void 0,"\t");P&&log(`Creating config file at ${k}`),await o(k,t).catch((async e=>{switch(e.code){case"EISDIR":await r(k);break;case"ENOENT":await i(b);break;default:throw e}await o(k,t)}))})(l)}break;default:v[1]&&logError(`Unknown command: ${JSON.stringify(v[1])}\n`),logHelp()}break;case"help":case"h":logHelp();break;case"golf":case"minify":{const e=v[1];if(!e){logError("Must provide target\n"),logHelp();break}const t=h(e);if(!l.includes(t)){logError(`Unsupported file extension "${T.bold(t)}"\nSupported extensions are "${l.map((e=>T.bold(e))).join('", "')}"`);break}const{processScript:o}=await O,i=u(e,t),r=i.endsWith(".src"),c=r?i.slice(0,-4):i,f="scripts"==u(m(e,".."))&&"hackmud"==u(m(e,"../../.."))?u(m(e,"../..")):"UNKNOWN",$=!w.get("skip-minify");if(w.has("skip-minify")&&w.has("mangle-names")){logError(`Option ${R("--mangle-names")} would have no effect if minification is skipped\n`),logHelp();break}const p=w.get("mangle-names");if(null!=p&&"boolean"!=typeof p){logError(`The value for ${R("--mangle-names")} must be ${E("true")} or ${E("false")}\n`),logHelp();break}const y=p,b=w.get("force-quine-cheats");if(null!=b&&"boolean"!=typeof b){logError(`the value for ${R("--force-quine-cheats")} must be ${E("true")} or ${E("false")}\n`),logHelp();break}const k=b;let S=v[2]||m(g(e),r?`${c}.js`:".js"==t?`${i}.min.js`:`${i}.js`);const golfFile=()=>s(e,{encoding:"utf-8"}).then((async s=>{const i=performance.now(),{script:r,warnings:l}=await o(s,{minify:$,scriptUser:f,scriptName:c,filePath:e,mangleNames:y,forceQuineCheats:k}),p=performance.now()-i;for(const{message:e,line:t}of l)log(`Warning "${T.bold(e)}" on line ${T.bold(String(t))}`);await a(S,r).catch((async n=>{if(!v[2]||"EISDIR"!=n.code)throw n;S=m(S,`${u(e,t)}.js`),await a(S,r)})).then((()=>log(`Wrote ${T.bold(n(r))} chars to ${T.bold(d(".",S))} | took ${Math.round(100*p)/100}ms`)),(e=>logError(e.message)))}),(e=>logError(e.message)));if(w.get("watch")){const{watch:t}=await U;t(e,{awaitWriteFinish:{stabilityThreshold:100}}).on("ready",(()=>log(`Watching ${e}`))).on("change",golfFile),A=!1}else await golfFile()}break;default:v[0]&&logError(`Unknown command: ${JSON.stringify(v[0])}\n`),logHelp()}A&&process.exit();
|