hackmud-script-manager 0.13.0-a60a7a2 → 0.13.0-c461329
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/.gitattributes +1 -0
- package/.github/workflows/codeql-analysis.yml +39 -0
- package/.github/workflows/publish.yml +42 -0
- package/.vscode/settings.json +6 -0
- package/babel.config.json +6 -0
- package/package.json +12 -21
- package/rollup.config.js +110 -0
- package/scripts/build-package-json.js +36 -0
- package/scripts/jsconfig.json +5 -0
- package/scripts/version-dev.js +25 -0
- package/src/bin/hsm.ts +505 -0
- package/src/constants.json +3 -0
- package/src/generateTypings.ts +116 -0
- package/src/index.ts +19 -0
- package/src/modules.d.ts +5 -0
- package/src/processScript/index.ts +198 -0
- package/src/processScript/minify.ts +529 -0
- package/src/processScript/postprocess.ts +38 -0
- package/src/processScript/preprocess.ts +146 -0
- package/src/processScript/transform.ts +760 -0
- package/src/pull.ts +16 -0
- package/src/push.ts +314 -0
- package/src/syncMacros.ts +52 -0
- package/src/test.ts +59 -0
- package/src/tsconfig.json +20 -0
- package/src/watch.ts +156 -0
- package/tsconfig.json +12 -0
- package/assert-1b7dada8.js +0 -1
- package/bin/hsm.d.ts +0 -2
- package/bin/hsm.js +0 -2
- package/generateTypings.d.ts +0 -2
- package/generateTypings.js +0 -1
- package/index.d.ts +0 -15
- package/index.js +0 -1
- package/processScript/compile.d.ts +0 -17
- package/processScript/compile.js +0 -1
- package/processScript/index.d.ts +0 -30
- package/processScript/index.js +0 -1
- package/processScript/minify.d.ts +0 -7
- package/processScript/minify.js +0 -1
- package/processScript/postProcess.d.ts +0 -2
- package/processScript/postProcess.js +0 -1
- package/processScript/preProcess.d.ts +0 -15
- package/processScript/preProcess.js +0 -1
- package/pull.d.ts +0 -9
- package/pull.js +0 -1
- package/push.d.ts +0 -26
- package/push.js +0 -1
- package/spliceString-2c6f214f.js +0 -1
- package/syncMacros.d.ts +0 -5
- package/syncMacros.js +0 -1
- package/test.d.ts +0 -6
- package/test.js +0 -1
- package/watch.d.ts +0 -14
- package/watch.js +0 -1
package/src/bin/hsm.ts
ADDED
@@ -0,0 +1,505 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
import { countHackmudCharacters, DynamicMap, writeFilePersistent } from "@samual/lib"
|
3
|
+
import chalk from "chalk"
|
4
|
+
import fs from "fs"
|
5
|
+
import { homedir as getHomeDirectory } from "os"
|
6
|
+
import { basename as getBaseName, dirname as getPathDirectory, extname as getFileExtension, relative as relativePath, resolve as resolvePath } from "path"
|
7
|
+
import { generateTypings, Info, processScript, pull, push, syncMacros, test, watch } from ".."
|
8
|
+
import { version as moduleVersion } from "../../package.json"
|
9
|
+
import { supportedExtensions } from "../constants.json"
|
10
|
+
|
11
|
+
const { readFile, rmdir: removeDirectory, writeFile, mkdir: makeDirectory } = fs.promises
|
12
|
+
|
13
|
+
type ArgValue = boolean | number | string/* | ArgValue[]*/
|
14
|
+
|
15
|
+
const configDirPath = resolvePath(getHomeDirectory(), ".config")
|
16
|
+
const configFilePath = resolvePath(configDirPath, "hsm.json")
|
17
|
+
|
18
|
+
const options = new Map<string, ArgValue>()
|
19
|
+
const commands: string[] = []
|
20
|
+
|
21
|
+
let config: Record<string, any> & Partial<{
|
22
|
+
hackmudPath: string
|
23
|
+
defaultUser: string
|
24
|
+
users: Record<string, {
|
25
|
+
colour: string
|
26
|
+
}>
|
27
|
+
}> | undefined
|
28
|
+
|
29
|
+
const colourJ = chalk.rgb(0xFF, 0xF4, 0x04)
|
30
|
+
const colourK = chalk.rgb(0xF3, 0xF9, 0x98)
|
31
|
+
const colourM = chalk.rgb(0xB3, 0xFF, 0x9B)
|
32
|
+
const colourW = chalk.rgb(0xFF, 0x96, 0xE0)
|
33
|
+
const colourL = chalk.rgb(0x1E, 0xFF, 0x00)
|
34
|
+
const colourB = chalk.rgb(0xCA, 0xCA, 0xCA)
|
35
|
+
|
36
|
+
const userColours = new DynamicMap<string, string>(user => {
|
37
|
+
let hash = 0
|
38
|
+
|
39
|
+
for (const char of user)
|
40
|
+
hash += (hash >> 1) + hash + "xi1_8ratvsw9hlbgm02y5zpdcn7uekof463qj".indexOf(char) + 1
|
41
|
+
|
42
|
+
return [ colourJ, colourK, colourM, colourW, colourL, colourB ][hash % 6](user)
|
43
|
+
})
|
44
|
+
|
45
|
+
for (const arg of process.argv.slice(2)) {
|
46
|
+
if (arg[0] == "-") {
|
47
|
+
const [ key, valueRaw ] = arg.split("=")
|
48
|
+
let value: ArgValue = valueRaw
|
49
|
+
|
50
|
+
if (value) {
|
51
|
+
if (value == "true")
|
52
|
+
value = true
|
53
|
+
else if (value == "false")
|
54
|
+
value = false
|
55
|
+
else {
|
56
|
+
const number = Number(value)
|
57
|
+
|
58
|
+
if (isFinite(number))
|
59
|
+
value = number
|
60
|
+
}
|
61
|
+
} else
|
62
|
+
value = true
|
63
|
+
|
64
|
+
if (arg[1] == "-")
|
65
|
+
options.set(key.slice(2), value)
|
66
|
+
else {
|
67
|
+
for (const option of key.slice(1))
|
68
|
+
options.set(option, value)
|
69
|
+
}
|
70
|
+
} else
|
71
|
+
commands.push(arg)
|
72
|
+
}
|
73
|
+
|
74
|
+
(async () => {
|
75
|
+
if (options.get("version") || options.get("v")) {
|
76
|
+
version()
|
77
|
+
return
|
78
|
+
}
|
79
|
+
|
80
|
+
if (options.get("help") || options.get("h")) {
|
81
|
+
help()
|
82
|
+
return
|
83
|
+
}
|
84
|
+
|
85
|
+
switch (commands[0]) {
|
86
|
+
case "push": {
|
87
|
+
const config = await getConfig()
|
88
|
+
|
89
|
+
if (!config.hackmudPath) {
|
90
|
+
console.log("you need to set hackmudPath in config before you can use this command")
|
91
|
+
break
|
92
|
+
}
|
93
|
+
|
94
|
+
const srcPath = commands[1] || "."
|
95
|
+
const hackmudPath = config.hackmudPath
|
96
|
+
const scripts = commands.slice(2)
|
97
|
+
|
98
|
+
if (!scripts.length)
|
99
|
+
scripts.push("*.*")
|
100
|
+
|
101
|
+
const infos = await push(
|
102
|
+
srcPath,
|
103
|
+
hackmudPath,
|
104
|
+
{
|
105
|
+
scripts,
|
106
|
+
onPush: onPushLogger,
|
107
|
+
minify: !options.get("skip-minify")
|
108
|
+
}
|
109
|
+
)
|
110
|
+
|
111
|
+
if (!infos.length)
|
112
|
+
console.warn("couldn't find any scripts to push")
|
113
|
+
|
114
|
+
updateConfig()
|
115
|
+
} break
|
116
|
+
|
117
|
+
case "dev":
|
118
|
+
case "watch": {
|
119
|
+
const config = await getConfig()
|
120
|
+
|
121
|
+
if (!config.hackmudPath) {
|
122
|
+
console.log("you need to set hackmudPath in config before you can use this command")
|
123
|
+
break
|
124
|
+
}
|
125
|
+
|
126
|
+
const srcPath = commands[1] || "."
|
127
|
+
const hackmudPath = config.hackmudPath
|
128
|
+
const users = options.get("users")?.toString().split(",") || []
|
129
|
+
const scripts = options.get("scripts")?.toString().split(",") || []
|
130
|
+
const genTypes = options.get("gen-types")?.toString()
|
131
|
+
|
132
|
+
watch(srcPath, hackmudPath, users, scripts, onPushLogger, { genTypes })
|
133
|
+
} break
|
134
|
+
|
135
|
+
case "pull": {
|
136
|
+
const config = await getConfig()
|
137
|
+
|
138
|
+
if (!config.hackmudPath) {
|
139
|
+
console.log("you need to set hackmudPath in config before you can use this command")
|
140
|
+
break
|
141
|
+
}
|
142
|
+
|
143
|
+
const script = commands[1]
|
144
|
+
|
145
|
+
if (!script) {
|
146
|
+
help()
|
147
|
+
break
|
148
|
+
}
|
149
|
+
|
150
|
+
const srcPath = commands[2] || "."
|
151
|
+
const hackmudPath = config.hackmudPath
|
152
|
+
|
153
|
+
try {
|
154
|
+
await pull(srcPath, hackmudPath, script)
|
155
|
+
} catch (error) {
|
156
|
+
console.log("something went wrong, did you forget to #down the script?")
|
157
|
+
}
|
158
|
+
} break
|
159
|
+
|
160
|
+
case "sync-macros": {
|
161
|
+
const { hackmudPath } = await getConfig()
|
162
|
+
|
163
|
+
if (!hackmudPath) {
|
164
|
+
console.log("you need to set hackmudPath in config before you can use this command")
|
165
|
+
break
|
166
|
+
}
|
167
|
+
|
168
|
+
const { macrosSynced, usersSynced } = await syncMacros(hackmudPath)
|
169
|
+
console.log(`synced ${macrosSynced} macros to ${usersSynced} users`)
|
170
|
+
} break
|
171
|
+
|
172
|
+
case "test": {
|
173
|
+
const srcPath = resolvePath(commands[1] || ".")
|
174
|
+
let errors = 0
|
175
|
+
|
176
|
+
console.log(`testing scripts in ${chalk.bold(srcPath)}\n`)
|
177
|
+
|
178
|
+
for (const { file, line, message } of await test(srcPath)) {
|
179
|
+
console.log(`error "${chalk.bold(message)}" in ${chalk.bold(file)} on line ${chalk.bold(String(line))}`)
|
180
|
+
errors++
|
181
|
+
}
|
182
|
+
|
183
|
+
if (!errors) {
|
184
|
+
console.log("no errors found")
|
185
|
+
break
|
186
|
+
}
|
187
|
+
|
188
|
+
if (errors) {
|
189
|
+
process.exitCode = 1
|
190
|
+
console.log(`\nencountered ${chalk.bold(String(errors))} errors`)
|
191
|
+
break
|
192
|
+
}
|
193
|
+
|
194
|
+
console.log("no errors found")
|
195
|
+
} break
|
196
|
+
|
197
|
+
case "gen-types": {
|
198
|
+
const srcPath = resolvePath(commands[1] || ".")
|
199
|
+
let targetPath: string
|
200
|
+
|
201
|
+
if (commands[2])
|
202
|
+
targetPath = resolvePath(commands[2])
|
203
|
+
else
|
204
|
+
targetPath = resolvePath(srcPath, "../player.d.ts")
|
205
|
+
|
206
|
+
generateTypings(srcPath, targetPath, (await getConfig()).hackmudPath)
|
207
|
+
} break
|
208
|
+
|
209
|
+
case "config":
|
210
|
+
switch (commands[1]) {
|
211
|
+
case "get": {
|
212
|
+
console.log(exploreObject(await getConfig(), commands[2].split(".")))
|
213
|
+
} break
|
214
|
+
|
215
|
+
case "delete": {
|
216
|
+
const keys = commands[2].split(".")
|
217
|
+
|
218
|
+
if (!keys.length) {
|
219
|
+
help()
|
220
|
+
break
|
221
|
+
}
|
222
|
+
|
223
|
+
const config = await getConfig()
|
224
|
+
|
225
|
+
delete exploreObject(config, keys)?.[commands[3]]
|
226
|
+
|
227
|
+
console.log(config)
|
228
|
+
} break
|
229
|
+
|
230
|
+
case "set": {
|
231
|
+
const keys = commands[2].split(".")
|
232
|
+
|
233
|
+
if (!keys.length) {
|
234
|
+
help()
|
235
|
+
break
|
236
|
+
}
|
237
|
+
|
238
|
+
const config = await getConfig()
|
239
|
+
let object = config
|
240
|
+
|
241
|
+
for (let key of keys.slice(0, -1))
|
242
|
+
object = typeof object[key] == "object" ? object[key] : object[key] = {}
|
243
|
+
|
244
|
+
object[keys.slice(-1)[0]] = commands[3]
|
245
|
+
|
246
|
+
if (config.hackmudPath)
|
247
|
+
config.hackmudPath = resolvePath(config.hackmudPath)
|
248
|
+
|
249
|
+
console.log(config)
|
250
|
+
} break
|
251
|
+
|
252
|
+
default: {
|
253
|
+
if (commands[1])
|
254
|
+
console.log("unknown command")
|
255
|
+
|
256
|
+
help()
|
257
|
+
}
|
258
|
+
} break
|
259
|
+
|
260
|
+
case "help":
|
261
|
+
case "h": {
|
262
|
+
help()
|
263
|
+
} break
|
264
|
+
|
265
|
+
case "version":
|
266
|
+
case "v": {
|
267
|
+
version()
|
268
|
+
} break
|
269
|
+
|
270
|
+
case "golf":
|
271
|
+
case "minify": {
|
272
|
+
// TODO `--watch` option
|
273
|
+
|
274
|
+
if (!commands[1]) {
|
275
|
+
console.log(`Target required\nUsage: ${getBaseName(process.argv[1])} ${commands[0]} <target> [output]`)
|
276
|
+
break
|
277
|
+
}
|
278
|
+
|
279
|
+
const fileExtension = getFileExtension(commands[1])
|
280
|
+
|
281
|
+
if (!supportedExtensions.includes(fileExtension)) {
|
282
|
+
console.log(`Unsupported file extension "${chalk.bold(fileExtension)}"\nSupported extensions are "${supportedExtensions.map(extension => chalk.bold(extension)).join('", "')}"`)
|
283
|
+
break
|
284
|
+
}
|
285
|
+
|
286
|
+
await readFile(commands[1], { encoding: "utf-8" }).then(
|
287
|
+
async source => {
|
288
|
+
const fileBaseName = getBaseName(commands[1], fileExtension)
|
289
|
+
const fileBaseNameEndsWithDotSrc = fileBaseName.endsWith(".src")
|
290
|
+
|
291
|
+
const scriptName = fileBaseNameEndsWithDotSrc
|
292
|
+
? fileBaseName.slice(0, -4)
|
293
|
+
: fileBaseName
|
294
|
+
|
295
|
+
let scriptUser = "UNKNOWN"
|
296
|
+
|
297
|
+
if (getBaseName(resolvePath(commands[1], "..")) == "scripts" && getBaseName(resolvePath(commands[1], "../../..")) == "hackmud")
|
298
|
+
scriptUser = getBaseName(resolvePath(commands[1], "../.."))
|
299
|
+
|
300
|
+
const minify = !options.get("skip-minify")
|
301
|
+
const mangleNames = Boolean(options.get("mangle-names"))
|
302
|
+
|
303
|
+
if (!minify && mangleNames)
|
304
|
+
console.warn("warning: `--mangle-names` has no effect while `--skip-minify` is active")
|
305
|
+
|
306
|
+
const { script, srcLength, warnings, timeTook } = await processScript(
|
307
|
+
source,
|
308
|
+
{
|
309
|
+
minify,
|
310
|
+
scriptUser,
|
311
|
+
scriptName,
|
312
|
+
filePath: commands[1],
|
313
|
+
mangleNames
|
314
|
+
}
|
315
|
+
)
|
316
|
+
|
317
|
+
for (const { message, line } of warnings)
|
318
|
+
console.log(`warning "${chalk.bold(message)}" on line ${chalk.bold(String(line))}`)
|
319
|
+
|
320
|
+
let outputPath: string
|
321
|
+
|
322
|
+
if (commands[2])
|
323
|
+
outputPath = commands[2]
|
324
|
+
else {
|
325
|
+
outputPath = resolvePath(
|
326
|
+
getPathDirectory(commands[1]),
|
327
|
+
|
328
|
+
fileBaseNameEndsWithDotSrc
|
329
|
+
? `${scriptName}.js` :
|
330
|
+
fileExtension == ".js"
|
331
|
+
? `${fileBaseName}.min.js`
|
332
|
+
: `${fileBaseName}.js`
|
333
|
+
)
|
334
|
+
}
|
335
|
+
|
336
|
+
const scriptLength = countHackmudCharacters(script)
|
337
|
+
|
338
|
+
await writeFilePersistent(outputPath, script)
|
339
|
+
.catch(async (error: NodeJS.ErrnoException) => {
|
340
|
+
if (!commands[2] || error.code != "EISDIR")
|
341
|
+
throw error
|
342
|
+
|
343
|
+
outputPath = resolvePath(outputPath, `${getBaseName(commands[1], fileExtension)}.js`)
|
344
|
+
|
345
|
+
await writeFilePersistent(outputPath, script)
|
346
|
+
})
|
347
|
+
.then(
|
348
|
+
() => console.log(`wrote ${chalk.bold(scriptLength)} chars to ${chalk.bold(relativePath(".", outputPath))} | saved ${chalk.bold(srcLength - scriptLength)} chars | took ${Math.round(timeTook * 100) / 100}ms`),
|
349
|
+
(error: NodeJS.ErrnoException) => console.log(error.message)
|
350
|
+
)
|
351
|
+
},
|
352
|
+
(error: NodeJS.ErrnoException) => console.log(error.message)
|
353
|
+
)
|
354
|
+
} break
|
355
|
+
|
356
|
+
default: {
|
357
|
+
if (commands[0])
|
358
|
+
console.log("unknown command")
|
359
|
+
|
360
|
+
help()
|
361
|
+
}
|
362
|
+
}
|
363
|
+
|
364
|
+
updateConfig()
|
365
|
+
})()
|
366
|
+
|
367
|
+
function help() {
|
368
|
+
switch (commands[0]) {
|
369
|
+
case "config": {
|
370
|
+
switch (commands[1]) {
|
371
|
+
case "get": {
|
372
|
+
console.log("hsm config get <key>")
|
373
|
+
} break
|
374
|
+
|
375
|
+
case "set": {
|
376
|
+
console.log("hsm config set <key> <value>")
|
377
|
+
} break
|
378
|
+
|
379
|
+
case "delete": {
|
380
|
+
console.log("hsm config delete <key>")
|
381
|
+
} break
|
382
|
+
|
383
|
+
default: {
|
384
|
+
console.log("hsm config <get, delete, set>")
|
385
|
+
}
|
386
|
+
}
|
387
|
+
} break
|
388
|
+
|
389
|
+
case "push": {
|
390
|
+
console.log("hsm push [<dir> [...\"<script user>.<script name>\"]]")
|
391
|
+
} break
|
392
|
+
|
393
|
+
case "watch": {
|
394
|
+
console.log("hsm watch [dir]")
|
395
|
+
} break
|
396
|
+
|
397
|
+
case "pull": {
|
398
|
+
console.log("hsm pull <script user>.<script name>")
|
399
|
+
} break
|
400
|
+
|
401
|
+
case "minify":
|
402
|
+
case "golf": {
|
403
|
+
console.log(`${getBaseName(process.argv[1])} ${commands[0]} <target> [output]`)
|
404
|
+
} break
|
405
|
+
|
406
|
+
default: {
|
407
|
+
console.log("hsm <push, watch, pull, config, golf>")
|
408
|
+
}
|
409
|
+
}
|
410
|
+
}
|
411
|
+
|
412
|
+
async function version() {
|
413
|
+
console.log(moduleVersion)
|
414
|
+
}
|
415
|
+
|
416
|
+
async function getConfig() {
|
417
|
+
if (config)
|
418
|
+
return config
|
419
|
+
|
420
|
+
return config = await readFile(configFilePath, { encoding: "utf-8" })
|
421
|
+
.then(configFile => {
|
422
|
+
let tempConfig
|
423
|
+
|
424
|
+
try {
|
425
|
+
tempConfig = JSON.parse(configFile)
|
426
|
+
} catch {
|
427
|
+
// TODO log to error log file
|
428
|
+
console.log("config file was corrupted, resetting")
|
429
|
+
return {}
|
430
|
+
}
|
431
|
+
|
432
|
+
if (!tempConfig || typeof tempConfig != "object") {
|
433
|
+
console.log("config file was corrupted, resetting")
|
434
|
+
return {}
|
435
|
+
}
|
436
|
+
|
437
|
+
return tempConfig
|
438
|
+
}, () => {
|
439
|
+
console.log(`creating config file at ${configFilePath}`)
|
440
|
+
return {}
|
441
|
+
})
|
442
|
+
}
|
443
|
+
|
444
|
+
function exploreObject(object: any, keys: string[], createPath = false) {
|
445
|
+
for (const key of keys) {
|
446
|
+
if (createPath)
|
447
|
+
object = typeof object[key] == "object" ? object[key] : object[key] = {}
|
448
|
+
else
|
449
|
+
object = object?.[key]
|
450
|
+
}
|
451
|
+
|
452
|
+
return object
|
453
|
+
}
|
454
|
+
|
455
|
+
function updateConfig() {
|
456
|
+
if (config) {
|
457
|
+
const json = JSON.stringify(config)
|
458
|
+
|
459
|
+
writeFile(configFilePath, json).catch(async error => {
|
460
|
+
switch (error.code) {
|
461
|
+
case "EISDIR": {
|
462
|
+
await removeDirectory(configFilePath)
|
463
|
+
} break
|
464
|
+
|
465
|
+
case "ENOENT": {
|
466
|
+
await makeDirectory(configDirPath)
|
467
|
+
} break
|
468
|
+
|
469
|
+
default: {
|
470
|
+
throw error
|
471
|
+
}
|
472
|
+
}
|
473
|
+
|
474
|
+
writeFile(configFilePath, json)
|
475
|
+
})
|
476
|
+
}
|
477
|
+
}
|
478
|
+
|
479
|
+
function onPushLogger({ file, users, srcLength, minLength, error }: Info) {
|
480
|
+
if (!users.length)
|
481
|
+
return
|
482
|
+
|
483
|
+
if (error) {
|
484
|
+
console.log(`error "${chalk.bold(error.message)}" in ${chalk.bold(file)}`)
|
485
|
+
return
|
486
|
+
}
|
487
|
+
|
488
|
+
console.log(
|
489
|
+
`pushed ${
|
490
|
+
chalk.bold(file)
|
491
|
+
} to ${
|
492
|
+
users.map(user => chalk.bold(userColours.get(user))).join(", ")
|
493
|
+
} | ${
|
494
|
+
chalk.bold(String(minLength))
|
495
|
+
} chars from ${
|
496
|
+
chalk.bold(String(srcLength))
|
497
|
+
} | saved ${
|
498
|
+
chalk.bold(String(srcLength - minLength))
|
499
|
+
} (${
|
500
|
+
chalk.bold(`${Math.round((1 - (minLength / srcLength)) * 100)}%`)
|
501
|
+
}) | ${
|
502
|
+
chalk.bold(`${resolvePath(config!.hackmudPath!, users[0], "scripts", getBaseName(file, getFileExtension(file)))}.js`)
|
503
|
+
}`
|
504
|
+
)
|
505
|
+
}
|
@@ -0,0 +1,116 @@
|
|
1
|
+
import fs from "fs"
|
2
|
+
import { basename as getBaseName, extname as getFileExtension, resolve as resolvePath } from "path"
|
3
|
+
|
4
|
+
const { readdir: readDirectory, writeFile } = fs.promises
|
5
|
+
|
6
|
+
export async function generateTypings(srcDir: string, target: string, hackmudPath?: string) {
|
7
|
+
const users = new Set<string>()
|
8
|
+
|
9
|
+
if (hackmudPath) {
|
10
|
+
for (const dirent of await readDirectory(hackmudPath, { withFileTypes: true })) {
|
11
|
+
if (dirent.isFile() && getFileExtension(dirent.name) == ".key")
|
12
|
+
users.add(getBaseName(dirent.name, ".key"))
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
const wildScripts: string[] = []
|
17
|
+
const wildAnyScripts: string[] = []
|
18
|
+
const allScripts: Record<string, string[]> = {}
|
19
|
+
const allAnyScripts: Record<string, string[]> = {}
|
20
|
+
|
21
|
+
for (const dirent of await readDirectory(srcDir, { withFileTypes: true })) {
|
22
|
+
if (dirent.isFile()) {
|
23
|
+
if (getFileExtension(dirent.name) == ".ts")
|
24
|
+
wildScripts.push(getBaseName(dirent.name, ".ts"))
|
25
|
+
else if (getFileExtension(dirent.name) == ".js")
|
26
|
+
wildAnyScripts.push(getBaseName(dirent.name, ".js"))
|
27
|
+
} else if (dirent.isDirectory()) {
|
28
|
+
const scripts: string[] = allScripts[dirent.name] = []
|
29
|
+
const anyScripts: string[] = allAnyScripts[dirent.name] = []
|
30
|
+
|
31
|
+
users.add(dirent.name)
|
32
|
+
|
33
|
+
for (const file of await readDirectory(resolvePath(srcDir, dirent.name), { withFileTypes: true })) {
|
34
|
+
if (file.isFile()) {
|
35
|
+
if (getFileExtension(file.name) == ".ts")
|
36
|
+
scripts.push(getBaseName(file.name, ".ts"))
|
37
|
+
else if (getFileExtension(file.name) == ".js")
|
38
|
+
anyScripts.push(getBaseName(file.name, ".js"))
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
let o = ""
|
45
|
+
|
46
|
+
for (const script of wildScripts)
|
47
|
+
o += `import { script as $${script}$ } from "./src/${script}"\n`
|
48
|
+
|
49
|
+
o += "\n"
|
50
|
+
|
51
|
+
for (const user in allScripts) {
|
52
|
+
const scripts = allScripts[user]
|
53
|
+
|
54
|
+
for (const script of scripts)
|
55
|
+
o += `import { script as $${user}$${script}$ } from "./src/${user}/${script}"\n`
|
56
|
+
}
|
57
|
+
|
58
|
+
// TODO detect security level and generate apropriate code
|
59
|
+
|
60
|
+
// TODO accurate function signatures
|
61
|
+
// currently I lose the generic-ness of my functions when I wrap them
|
62
|
+
// just regexing isn't enough and it looks like I'm going to need to parse the files in TypeScript to extract the signature
|
63
|
+
|
64
|
+
o += `
|
65
|
+
type ArrayRemoveFirst<A> = A extends [ infer FirstItem, ...infer Rest ] ? Rest : never
|
66
|
+
|
67
|
+
type Subscript<T extends (...args: any) => any> =
|
68
|
+
(...args: ArrayRemoveFirst<Parameters<T>>) => ReturnType<T> | ScriptFailure
|
69
|
+
|
70
|
+
type WildFullsec = Record<string, () => ScriptFailure> & {
|
71
|
+
`
|
72
|
+
|
73
|
+
for (const script of wildScripts)
|
74
|
+
o += `\t${script}: Subscript<typeof $${script}$>\n`
|
75
|
+
|
76
|
+
for (const script of wildAnyScripts)
|
77
|
+
o += `\t${script}: (...args: any) => any\n`
|
78
|
+
|
79
|
+
o += "}\n\ndeclare global {\n\tinterface PlayerFullsec {"
|
80
|
+
|
81
|
+
let lastWasMultiLine = true
|
82
|
+
|
83
|
+
for (const user of users) {
|
84
|
+
const scripts = allScripts[user]
|
85
|
+
const anyScripts = allAnyScripts[user]
|
86
|
+
|
87
|
+
if ((scripts && scripts.length) || (anyScripts && anyScripts.length)) {
|
88
|
+
lastWasMultiLine = true
|
89
|
+
|
90
|
+
o += `\n\t\t${user}: WildFullsec & {\n`
|
91
|
+
|
92
|
+
for (const script of scripts)
|
93
|
+
o += `\t\t\t${script}: Subscript<typeof $${user}$${script}$>\n`
|
94
|
+
|
95
|
+
for (const script of anyScripts)
|
96
|
+
o += `\t\t\t${script}: (...args: any) => any\n`
|
97
|
+
|
98
|
+
o += "\t\t}"
|
99
|
+
} else {
|
100
|
+
if (lastWasMultiLine) {
|
101
|
+
o += "\n"
|
102
|
+
lastWasMultiLine = false
|
103
|
+
}
|
104
|
+
|
105
|
+
o += `\t\t${user}: WildFullsec`
|
106
|
+
}
|
107
|
+
|
108
|
+
o += "\n"
|
109
|
+
}
|
110
|
+
|
111
|
+
o += "\t}\n}\n"
|
112
|
+
|
113
|
+
await writeFile(target, o)
|
114
|
+
}
|
115
|
+
|
116
|
+
export default generateTypings
|
package/src/index.ts
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
export { supportedExtensions } from "./constants.json"
|
2
|
+
export { generateTypings } from "./generateTypings"
|
3
|
+
export { processScript } from "./processScript"
|
4
|
+
export { pull } from "./pull"
|
5
|
+
export { push } from "./push"
|
6
|
+
export { syncMacros } from "./syncMacros"
|
7
|
+
export { test } from "./test"
|
8
|
+
export { watch } from "./watch"
|
9
|
+
|
10
|
+
// TODO `clean()` function that delete all scripts in hackmud directory #70
|
11
|
+
// TODO optional argument (defaults to false) for `clean()` that makes it only remove scripts without a source file #70
|
12
|
+
|
13
|
+
export interface Info {
|
14
|
+
file: string
|
15
|
+
users: string[]
|
16
|
+
srcLength: number
|
17
|
+
minLength: number
|
18
|
+
error: Error | null
|
19
|
+
}
|