hackmud-script-manager 0.20.4-c524114 → 0.20.4-c908d16
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/README.md +4 -0
- package/bin/hsm.js +285 -260
- package/env.d.ts +353 -282
- package/generateTypeDeclaration.js +2 -1
- package/index.js +2 -1
- package/package.json +38 -38
- package/processScript/index.js +3 -3
- package/processScript/minify.js +14 -19
- package/processScript/postprocess.d.ts +1 -1
- package/processScript/postprocess.js +3 -3
- package/processScript/preprocess.js +5 -3
- package/processScript/transform.js +102 -96
- package/push.d.ts +9 -1
- package/push.js +36 -14
- package/watch.js +9 -7
package/bin/hsm.js
CHANGED
@@ -1,21 +1,22 @@
|
|
1
1
|
#!/usr/bin/env node
|
2
|
-
import {
|
2
|
+
import { AutoMap } from "@samual/lib/AutoMap"
|
3
3
|
import { assert } from "@samual/lib/assert"
|
4
4
|
import { countHackmudCharacters } from "@samual/lib/countHackmudCharacters"
|
5
5
|
import { writeFilePersistent } from "@samual/lib/writeFilePersistent"
|
6
6
|
import { writeFile, readFile } from "fs/promises"
|
7
7
|
import { homedir } from "os"
|
8
|
-
import { extname, basename,
|
8
|
+
import { resolve, extname, basename, dirname, relative } from "path"
|
9
9
|
import { supportedExtensions } from "../constants.js"
|
10
10
|
import { generateTypeDeclaration } from "../generateTypeDeclaration.js"
|
11
11
|
import { pull } from "../pull.js"
|
12
12
|
import { syncMacros } from "../syncMacros.js"
|
13
13
|
import "@samual/lib/readDirectoryWithStats"
|
14
|
+
import "path/posix"
|
14
15
|
import "@samual/lib/copyFilePersistent"
|
15
|
-
const
|
16
|
+
const formatOption = name => colourN(`-${1 == name.length ? "" : "-"}${name}`),
|
16
17
|
options = new Map(),
|
17
18
|
commands = [],
|
18
|
-
userColours = new
|
19
|
+
userColours = new AutoMap(user => {
|
19
20
|
let hash = 0
|
20
21
|
for (const char of user) hash += (hash >> 1) + hash + "xi1_8ratvsw9hlbgm02y5zpdcn7uekof463qj".indexOf(char) + 1
|
21
22
|
return [colourJ, colourK, colourM, colourW, colourL, colourB][hash % 6](user)
|
@@ -23,23 +24,19 @@ const version = "0.20.4-c524114",
|
|
23
24
|
log = message => console.log(colourS(message))
|
24
25
|
for (const argument of process.argv.slice(2))
|
25
26
|
if ("-" == argument[0]) {
|
26
|
-
const
|
27
|
-
let value
|
28
|
-
if (
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
27
|
+
const argumentEqualsIndex = argument.indexOf("=")
|
28
|
+
let key, value
|
29
|
+
if (-1 == argumentEqualsIndex) {
|
30
|
+
key = argument
|
31
|
+
value = !0
|
32
|
+
} else {
|
33
|
+
key = argument.slice(0, argumentEqualsIndex)
|
34
|
+
value = argument.slice(argumentEqualsIndex + 1)
|
35
|
+
"true" == value ? (value = !0) : "false" == value && (value = !1)
|
36
|
+
}
|
36
37
|
if ("-" == argument[1]) options.set(key.slice(2), value)
|
37
38
|
else for (const option of key.slice(1)) options.set(option, value)
|
38
39
|
} else commands.push(argument)
|
39
|
-
if ("v" == commands[0] || "version" == commands[0] || options.get("version") || options.get("v")) {
|
40
|
-
console.log(version)
|
41
|
-
process.exit()
|
42
|
-
}
|
43
40
|
const pushModule = import("../push.js"),
|
44
41
|
processScriptModule = import("../processScript/index.js"),
|
45
42
|
watchModule = import("../watch.js"),
|
@@ -49,6 +46,7 @@ const pushModule = import("../push.js"),
|
|
49
46
|
colourB = chalk.rgb(202, 202, 202),
|
50
47
|
colourC = chalk.rgb(155, 155, 155),
|
51
48
|
colourD = chalk.rgb(255, 0, 0),
|
49
|
+
colourF = chalk.rgb(255, 128, 0),
|
52
50
|
colourJ = chalk.rgb(255, 244, 4),
|
53
51
|
colourK = chalk.rgb(243, 249, 152),
|
54
52
|
colourL = chalk.rgb(30, 255, 0),
|
@@ -57,153 +55,213 @@ const pushModule = import("../push.js"),
|
|
57
55
|
colourS = chalk.rgb(122, 178, 244),
|
58
56
|
colourV = chalk.rgb(255, 0, 236),
|
59
57
|
colourW = chalk.rgb(255, 150, 224)
|
60
|
-
|
58
|
+
process.version.startsWith("v21.") &&
|
59
|
+
console.warn(
|
60
|
+
colourF(
|
61
|
+
`Warning: Support for Node.js 21 will be dropped in the next minor version of HSM\n Your current version of Node.js is ${chalk.bold(process.version)}\n You should update your version of Node.js\n https://nodejs.org/en/download/package-manager\n`
|
62
|
+
)
|
63
|
+
)
|
64
|
+
if ("v" == commands[0] || "version" == commands[0] || popOption("version", "v")?.value) {
|
65
|
+
console.log("0.20.4-c908d16")
|
66
|
+
process.exit()
|
67
|
+
}
|
68
|
+
let warnedDeprecatedEmitDtsAlias = !1
|
69
|
+
if (popOption("help", "h")?.value) {
|
61
70
|
logHelp()
|
62
71
|
process.exit()
|
63
72
|
}
|
64
73
|
let autoExit = !0
|
65
74
|
switch (commands[0]) {
|
66
75
|
case "push":
|
76
|
+
case "dev":
|
77
|
+
case "watch":
|
78
|
+
case "golf":
|
79
|
+
case "minify":
|
67
80
|
{
|
68
|
-
const
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
}
|
75
|
-
const scripts = commands.slice(2)
|
76
|
-
if (scripts.length) {
|
77
|
-
const invalidScript = scripts.find(
|
78
|
-
script => !/^(?:[a-z_][a-z\d_]{0,24}|\*)\.(?:[a-z_][a-z\d_]{0,24}|\*)$/.test(script)
|
79
|
-
)
|
80
|
-
if (invalidScript) {
|
81
|
-
logError(`Invalid script name: ${JSON.stringify(invalidScript)}\n`)
|
82
|
-
logHelp()
|
83
|
-
break
|
84
|
-
}
|
85
|
-
} else scripts.push("*.*")
|
86
|
-
const optionsHasNoMinify = options.has("no-minify")
|
87
|
-
if ((optionsHasNoMinify || options.has("skip-minify")) && options.has("mangle-names")) {
|
88
|
-
logError(
|
89
|
-
`Options ${colourN("--mangle-names")} and ${colourN(optionsHasNoMinify ? "--no-minify" : "--skip-minify")} are incompatible\n`
|
90
|
-
)
|
91
|
-
logHelp()
|
92
|
-
break
|
93
|
-
}
|
94
|
-
const shouldSkipMinify = options.get("no-minify") || options.get("skip-minify")
|
95
|
-
let shouldMinify
|
96
|
-
if (null != shouldSkipMinify) {
|
97
|
-
if ("boolean" != typeof shouldSkipMinify) {
|
98
|
-
logError(
|
99
|
-
`The value for ${colourN(optionsHasNoMinify ? "--no-minify" : "--skip-minify")} must be ${colourV("true")} or ${colourV("false")}\n`
|
81
|
+
const noMinifyOption = popOption("no-minify", "skip-minify")
|
82
|
+
noMinifyOption &&
|
83
|
+
"no-minify" != noMinifyOption.name &&
|
84
|
+
console.warn(
|
85
|
+
colourF(
|
86
|
+
`Warning: ${formatOption(noMinifyOption.name)} is being deprecated and will be removed in the next minor\n release of HSM\n You should switch to using its alias ${colourN("--no-minify")}\n`
|
100
87
|
)
|
101
|
-
logHelp()
|
102
|
-
break
|
103
|
-
}
|
104
|
-
shouldMinify = !shouldSkipMinify
|
105
|
-
}
|
106
|
-
const shouldMangleNames = options.get("mangle-names")
|
107
|
-
if (null != shouldMangleNames && "boolean" != typeof shouldMangleNames) {
|
108
|
-
logError(
|
109
|
-
`The value for ${colourN("--mangle-names")} must be ${colourV("true")} or ${colourV("false")}\n`
|
110
88
|
)
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
if (null != shouldforceQuineCheats && "boolean" != typeof shouldforceQuineCheats) {
|
89
|
+
const mangleNamesOption = popOption("mangle-names"),
|
90
|
+
forceQuineCheatsOption = popOption("force-quine-cheats"),
|
91
|
+
noMinifyIncompatibleOption = mangleNamesOption || forceQuineCheatsOption
|
92
|
+
if (noMinifyOption && noMinifyIncompatibleOption) {
|
116
93
|
logError(
|
117
|
-
`
|
94
|
+
`Options ${formatOption(noMinifyOption.name)} and ${formatOption(noMinifyIncompatibleOption.name)} are incompatible\n`
|
118
95
|
)
|
119
96
|
logHelp()
|
120
|
-
|
121
|
-
}
|
122
|
-
const { push } = await pushModule
|
123
|
-
;(
|
124
|
-
await push(sourcePath, hackmudPath, {
|
125
|
-
scripts,
|
126
|
-
onPush: info => logInfo(info, hackmudPath),
|
127
|
-
minify: shouldMinify,
|
128
|
-
mangleNames: shouldMangleNames,
|
129
|
-
forceQuineCheats: shouldforceQuineCheats
|
130
|
-
})
|
131
|
-
).length || logError("Could not find any scripts to push")
|
132
|
-
}
|
133
|
-
break
|
134
|
-
case "dev":
|
135
|
-
case "watch":
|
136
|
-
{
|
137
|
-
const hackmudPath = getHackmudPath(),
|
138
|
-
sourcePath = commands[1]
|
139
|
-
if (!sourcePath) {
|
140
|
-
logError("Must provide the directory to watch\n")
|
141
|
-
logHelp()
|
142
|
-
break
|
97
|
+
process.exit(1)
|
143
98
|
}
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
)
|
149
|
-
|
150
|
-
|
99
|
+
noMinifyOption && assertOptionIsBoolean(noMinifyOption)
|
100
|
+
mangleNamesOption && assertOptionIsBoolean(mangleNamesOption)
|
101
|
+
forceQuineCheatsOption && assertOptionIsBoolean(forceQuineCheatsOption)
|
102
|
+
if ("golf" == commands[0] || "minify" == commands[0]) {
|
103
|
+
const watchOption = popOption("watch"),
|
104
|
+
target = commands[1]
|
105
|
+
if (!target) {
|
106
|
+
logError("Must provide target\n")
|
151
107
|
logHelp()
|
152
|
-
|
108
|
+
process.exit(1)
|
153
109
|
}
|
154
|
-
|
155
|
-
|
156
|
-
if ((optionsHasNoMinify || options.has("skip-minify")) && options.has("mangle-names")) {
|
157
|
-
logError(
|
158
|
-
`Options ${colourN("--mangle-names")} and ${colourN(optionsHasNoMinify ? "--no-minify" : "--skip-minify")} are incompatible\n`
|
159
|
-
)
|
160
|
-
logHelp()
|
161
|
-
break
|
162
|
-
}
|
163
|
-
const shouldSkipMinify = options.get("no-minify") || options.get("skip-minify")
|
164
|
-
let shouldMinify
|
165
|
-
if (null != shouldSkipMinify) {
|
166
|
-
if ("boolean" != typeof shouldSkipMinify) {
|
110
|
+
const fileExtension = extname(target)
|
111
|
+
if (!supportedExtensions.includes(fileExtension)) {
|
167
112
|
logError(
|
168
|
-
`
|
113
|
+
`Unsupported file extension "${chalk.bold(fileExtension)}"\nSupported extensions are "${supportedExtensions.map(extension => chalk.bold(extension)).join('", "')}"`
|
169
114
|
)
|
115
|
+
process.exit(1)
|
116
|
+
}
|
117
|
+
complainAboutUnrecognisedOptions()
|
118
|
+
const { processScript } = await processScriptModule,
|
119
|
+
fileBaseName = basename(target, fileExtension),
|
120
|
+
fileBaseNameEndsWithDotSrc = fileBaseName.endsWith(".src"),
|
121
|
+
scriptName = fileBaseNameEndsWithDotSrc ? fileBaseName.slice(0, -4) : fileBaseName,
|
122
|
+
scriptUser =
|
123
|
+
(
|
124
|
+
"scripts" == basename(resolve(target, "..")) &&
|
125
|
+
"hackmud" == basename(resolve(target, "../../.."))
|
126
|
+
) ?
|
127
|
+
basename(resolve(target, "../.."))
|
128
|
+
: void 0
|
129
|
+
let outputPath =
|
130
|
+
commands[2] ||
|
131
|
+
resolve(
|
132
|
+
dirname(target),
|
133
|
+
fileBaseNameEndsWithDotSrc ? scriptName + ".js"
|
134
|
+
: ".js" == fileExtension ? fileBaseName + ".min.js"
|
135
|
+
: fileBaseName + ".js"
|
136
|
+
)
|
137
|
+
const golfFile = () =>
|
138
|
+
readFile(target, { encoding: "utf8" }).then(async source => {
|
139
|
+
const timeStart = performance.now(),
|
140
|
+
{ script, warnings } = await processScript(source, {
|
141
|
+
minify: noMinifyOption && !noMinifyOption.value,
|
142
|
+
scriptUser,
|
143
|
+
scriptName,
|
144
|
+
filePath: target,
|
145
|
+
mangleNames: mangleNamesOption?.value,
|
146
|
+
forceQuineCheats: forceQuineCheatsOption?.value
|
147
|
+
}),
|
148
|
+
timeTook = performance.now() - timeStart
|
149
|
+
for (const { message, line } of warnings)
|
150
|
+
log(`Warning "${chalk.bold(message)}" on line ${chalk.bold(line + "")}`)
|
151
|
+
await writeFilePersistent(outputPath, script)
|
152
|
+
.catch(error => {
|
153
|
+
if (!commands[2] || "EISDIR" != error.code) throw error
|
154
|
+
outputPath = resolve(outputPath, basename(target, fileExtension) + ".js")
|
155
|
+
return writeFilePersistent(outputPath, script)
|
156
|
+
})
|
157
|
+
.then(() =>
|
158
|
+
log(
|
159
|
+
`Wrote ${chalk.bold(countHackmudCharacters(script))} chars to ${chalk.bold(relative(".", outputPath))} | took ${Math.round(100 * timeTook) / 100}ms`
|
160
|
+
)
|
161
|
+
)
|
162
|
+
})
|
163
|
+
if (watchOption) {
|
164
|
+
const { watch: watchFile } = await chokidarModule
|
165
|
+
watchFile(target, { awaitWriteFinish: { stabilityThreshold: 100 } })
|
166
|
+
.on("ready", () => log("Watching " + target))
|
167
|
+
.on("change", golfFile)
|
168
|
+
autoExit = !1
|
169
|
+
} else await golfFile()
|
170
|
+
} else {
|
171
|
+
const hackmudPath = getHackmudPath(),
|
172
|
+
sourcePath = commands[1]
|
173
|
+
if (!sourcePath) {
|
174
|
+
logError(`Must provide the directory to ${"push" == commands[0] ? "push from" : "watch"}\n`)
|
170
175
|
logHelp()
|
171
|
-
|
176
|
+
process.exit(1)
|
177
|
+
}
|
178
|
+
const scripts = commands.slice(2)
|
179
|
+
if (scripts.length) {
|
180
|
+
const invalidScript = scripts.find(
|
181
|
+
script => !/^(?:[a-z_][a-z\d_]{0,24}|\*)\.(?:[a-z_][a-z\d_]{0,24}|\*)$/.test(script)
|
182
|
+
)
|
183
|
+
if (invalidScript) {
|
184
|
+
logError(`Invalid script name: ${JSON.stringify(invalidScript)}\n`)
|
185
|
+
logHelp()
|
186
|
+
process.exit(1)
|
187
|
+
}
|
188
|
+
} else scripts.push("*.*")
|
189
|
+
const watchOption = popOption("watch")
|
190
|
+
if ("push" != commands[0] || watchOption?.value) {
|
191
|
+
const dtsPathOption = popOption(
|
192
|
+
"dts-path",
|
193
|
+
"type-declaration-path",
|
194
|
+
"type-declaration",
|
195
|
+
"dts",
|
196
|
+
"gen-types"
|
197
|
+
)
|
198
|
+
dtsPathOption &&
|
199
|
+
"dts-path" != dtsPathOption.name &&
|
200
|
+
"type-declaration-path" != dtsPathOption.name &&
|
201
|
+
console.warn(
|
202
|
+
colourF(
|
203
|
+
`Warning: ${formatOption(dtsPathOption.name)} is being deprecated and will be removed in the\n next minor release of HSM\n You should switch to using its alias ${colourN("--dts-path")}\n`
|
204
|
+
)
|
205
|
+
)
|
206
|
+
complainAboutUnrecognisedOptions()
|
207
|
+
const { watch } = await watchModule
|
208
|
+
watch(sourcePath, hackmudPath, {
|
209
|
+
scripts,
|
210
|
+
onPush: info => logInfo(info, hackmudPath),
|
211
|
+
typeDeclarationPath: dtsPathOption?.value.toString(),
|
212
|
+
minify: noMinifyOption && !noMinifyOption.value,
|
213
|
+
mangleNames: mangleNamesOption?.value,
|
214
|
+
onReady: () => log("Watching"),
|
215
|
+
forceQuineCheats: forceQuineCheatsOption?.value
|
216
|
+
})
|
217
|
+
autoExit = !1
|
218
|
+
} else {
|
219
|
+
const dtsPathOption = popOption("dts-path")
|
220
|
+
complainAboutUnrecognisedOptions()
|
221
|
+
let declarationPathPromise
|
222
|
+
if (dtsPathOption) {
|
223
|
+
if ("string" != typeof dtsPathOption.value) {
|
224
|
+
logError(
|
225
|
+
`Option ${formatOption(dtsPathOption.name)} must be a string, got ${colourV(dtsPathOption.value)}\n`
|
226
|
+
)
|
227
|
+
logHelp()
|
228
|
+
process.exit(1)
|
229
|
+
}
|
230
|
+
let typeDeclarationPath = resolve(dtsPathOption.value)
|
231
|
+
const typeDeclaration = await generateTypeDeclaration(sourcePath, hackmudPath)
|
232
|
+
declarationPathPromise = writeFile(typeDeclarationPath, typeDeclaration)
|
233
|
+
.catch(error => {
|
234
|
+
assert(error instanceof Error, "src/bin/hsm.ts:274:38")
|
235
|
+
if ("EISDIR" != error.code) throw error
|
236
|
+
typeDeclarationPath = resolve(typeDeclarationPath, "player.d.ts")
|
237
|
+
return writeFile(typeDeclarationPath, typeDeclaration)
|
238
|
+
})
|
239
|
+
.then(() => typeDeclarationPath)
|
240
|
+
}
|
241
|
+
const { push, MissingSourceFolderError, MissingHackmudFolderError, NoUsersError } =
|
242
|
+
await pushModule,
|
243
|
+
infos = await push(sourcePath, hackmudPath, {
|
244
|
+
scripts,
|
245
|
+
onPush: info => logInfo(info, hackmudPath),
|
246
|
+
minify: noMinifyOption && !noMinifyOption.value,
|
247
|
+
mangleNames: mangleNamesOption?.value,
|
248
|
+
forceQuineCheats: forceQuineCheatsOption?.value
|
249
|
+
})
|
250
|
+
if (infos instanceof Error) {
|
251
|
+
logError(infos.message)
|
252
|
+
if (infos instanceof MissingSourceFolderError || infos instanceof NoUsersError) {
|
253
|
+
console.log()
|
254
|
+
logHelp()
|
255
|
+
} else
|
256
|
+
infos instanceof MissingHackmudFolderError &&
|
257
|
+
log(
|
258
|
+
`If this is not where your hackmud folder is, you can specify it with the\n${colourN("--hackmud-path")}=${colourB("<path>")} option or ${colourN("HSM_HACKMUD_PATH")} environment variable`
|
259
|
+
)
|
260
|
+
} else infos.length || logError("Could not find any scripts to push")
|
261
|
+
declarationPathPromise &&
|
262
|
+
log("Wrote type declaration to " + chalk.bold(await declarationPathPromise))
|
172
263
|
}
|
173
|
-
shouldMinify = !shouldSkipMinify
|
174
|
-
}
|
175
|
-
const shouldMangleNames = options.get("mangle-names")
|
176
|
-
if (null != shouldMangleNames && "boolean" != typeof shouldMangleNames) {
|
177
|
-
logError(
|
178
|
-
`The value for ${colourN("--mangle-names")} must be ${colourV("true")} or ${colourV("false")}\n`
|
179
|
-
)
|
180
|
-
logHelp()
|
181
|
-
break
|
182
|
-
}
|
183
|
-
const shouldforceQuineCheats = options.get("force-quine-cheats")
|
184
|
-
if (null != shouldforceQuineCheats && "boolean" != typeof shouldforceQuineCheats) {
|
185
|
-
logError(
|
186
|
-
`The value for ${colourN("--force-quine-cheats")} must be ${colourV("true")} or ${colourV("false")}\n`
|
187
|
-
)
|
188
|
-
logHelp()
|
189
|
-
break
|
190
264
|
}
|
191
|
-
const { watch } = await watchModule
|
192
|
-
watch(sourcePath, hackmudPath, {
|
193
|
-
scripts,
|
194
|
-
onPush: info => logInfo(info, hackmudPath),
|
195
|
-
typeDeclarationPath: (
|
196
|
-
options.get("type-declaration-path") ||
|
197
|
-
options.get("type-declaration") ||
|
198
|
-
options.get("dts") ||
|
199
|
-
options.get("gen-types")
|
200
|
-
)?.toString(),
|
201
|
-
minify: shouldMinify,
|
202
|
-
mangleNames: shouldMangleNames,
|
203
|
-
onReady: () => log("Watching"),
|
204
|
-
forceQuineCheats: shouldforceQuineCheats
|
205
|
-
})
|
206
|
-
autoExit = !1
|
207
265
|
}
|
208
266
|
break
|
209
267
|
case "pull":
|
@@ -213,8 +271,9 @@ switch (commands[0]) {
|
|
213
271
|
if (!script) {
|
214
272
|
logError("Must provide the script to pull\n")
|
215
273
|
logHelp()
|
216
|
-
|
274
|
+
process.exit(1)
|
217
275
|
}
|
276
|
+
complainAboutUnrecognisedOptions()
|
218
277
|
const sourcePath = commands[2] || "."
|
219
278
|
await pull(sourcePath, hackmudPath, script).catch(error => {
|
220
279
|
console.error(error)
|
@@ -224,8 +283,9 @@ switch (commands[0]) {
|
|
224
283
|
break
|
225
284
|
case "sync-macros":
|
226
285
|
{
|
227
|
-
const hackmudPath = getHackmudPath()
|
228
|
-
|
286
|
+
const hackmudPath = getHackmudPath()
|
287
|
+
complainAboutUnrecognisedOptions()
|
288
|
+
const { macrosSynced, usersSynced } = await syncMacros(hackmudPath)
|
229
289
|
log(`Synced ${macrosSynced} macros to ${usersSynced} users`)
|
230
290
|
}
|
231
291
|
break
|
@@ -233,19 +293,30 @@ switch (commands[0]) {
|
|
233
293
|
case "gen-type-declaration":
|
234
294
|
case "gen-dts":
|
235
295
|
case "gen-types":
|
296
|
+
case "emit-dts":
|
236
297
|
{
|
237
|
-
|
298
|
+
if ("emit-dts" != commands[0] && "gen-dts" != commands[0]) {
|
299
|
+
warnedDeprecatedEmitDtsAlias = !0
|
300
|
+
console.warn(
|
301
|
+
colourF(
|
302
|
+
`Warning: ${colourC("hsm")} ${colourL(commands[0])} is being deprecated and will be removed\n in the next minor release of HSM\n You should switch to using its alias ${colourC("hsm")} ${colourL("emit-dts")}\n`
|
303
|
+
)
|
304
|
+
)
|
305
|
+
}
|
306
|
+
const hackmudPath = getHackmudPath(),
|
307
|
+
target = commands[1]
|
238
308
|
if (!target) {
|
239
309
|
logError("Must provide target directory\n")
|
240
310
|
logHelp()
|
241
|
-
|
311
|
+
process.exit(1)
|
242
312
|
}
|
313
|
+
complainAboutUnrecognisedOptions()
|
243
314
|
const sourcePath = resolve(target),
|
244
315
|
outputPath = commands[2] || "./player.d.ts",
|
245
|
-
typeDeclaration = await generateTypeDeclaration(sourcePath,
|
316
|
+
typeDeclaration = await generateTypeDeclaration(sourcePath, hackmudPath)
|
246
317
|
let typeDeclarationPath = resolve(outputPath)
|
247
318
|
await writeFile(typeDeclarationPath, typeDeclaration).catch(error => {
|
248
|
-
assert(error instanceof Error, "src/bin/hsm.ts:
|
319
|
+
assert(error instanceof Error, "src/bin/hsm.ts:408:35")
|
249
320
|
if ("EISDIR" != error.code) throw error
|
250
321
|
typeDeclarationPath = resolve(typeDeclarationPath, "player.d.ts")
|
251
322
|
return writeFile(typeDeclarationPath, typeDeclaration)
|
@@ -254,102 +325,8 @@ switch (commands[0]) {
|
|
254
325
|
}
|
255
326
|
break
|
256
327
|
case "help":
|
257
|
-
case "h":
|
258
328
|
logHelp()
|
259
329
|
break
|
260
|
-
case "golf":
|
261
|
-
case "minify":
|
262
|
-
{
|
263
|
-
const target = commands[1]
|
264
|
-
if (!target) {
|
265
|
-
logError("Must provide target\n")
|
266
|
-
logHelp()
|
267
|
-
break
|
268
|
-
}
|
269
|
-
const fileExtension = extname(target)
|
270
|
-
if (!supportedExtensions.includes(fileExtension)) {
|
271
|
-
logError(
|
272
|
-
`Unsupported file extension "${chalk.bold(fileExtension)}"\nSupported extensions are "${supportedExtensions.map(extension => chalk.bold(extension)).join('", "')}"`
|
273
|
-
)
|
274
|
-
break
|
275
|
-
}
|
276
|
-
const { processScript } = await processScriptModule,
|
277
|
-
fileBaseName = basename(target, fileExtension),
|
278
|
-
fileBaseNameEndsWithDotSrc = fileBaseName.endsWith(".src"),
|
279
|
-
scriptName = fileBaseNameEndsWithDotSrc ? fileBaseName.slice(0, -4) : fileBaseName,
|
280
|
-
scriptUser =
|
281
|
-
"scripts" == basename(resolve(target, "..")) && "hackmud" == basename(resolve(target, "../../..")) ?
|
282
|
-
basename(resolve(target, "../.."))
|
283
|
-
: void 0,
|
284
|
-
optionsHasNoMinify = options.has("no-minify")
|
285
|
-
if ((optionsHasNoMinify || options.has("skip-minify")) && options.has("mangle-names")) {
|
286
|
-
logError(
|
287
|
-
`Options ${colourN("--mangle-names")} and ${colourN(optionsHasNoMinify ? "--no-minify" : "--skip-minify")} are incompatible\n`
|
288
|
-
)
|
289
|
-
logHelp()
|
290
|
-
break
|
291
|
-
}
|
292
|
-
const mangleNames_ = options.get("mangle-names")
|
293
|
-
if (null != mangleNames_ && "boolean" != typeof mangleNames_) {
|
294
|
-
logError(
|
295
|
-
`The value for ${colourN("--mangle-names")} must be ${colourV("true")} or ${colourV("false")}\n`
|
296
|
-
)
|
297
|
-
logHelp()
|
298
|
-
break
|
299
|
-
}
|
300
|
-
const mangleNames = mangleNames_,
|
301
|
-
forceQuineCheats_ = options.get("force-quine-cheats")
|
302
|
-
if (null != forceQuineCheats_ && "boolean" != typeof forceQuineCheats_) {
|
303
|
-
logError(
|
304
|
-
`the value for ${colourN("--force-quine-cheats")} must be ${colourV("true")} or ${colourV("false")}\n`
|
305
|
-
)
|
306
|
-
logHelp()
|
307
|
-
break
|
308
|
-
}
|
309
|
-
const forceQuineCheats = forceQuineCheats_
|
310
|
-
let outputPath =
|
311
|
-
commands[2] ||
|
312
|
-
resolve(
|
313
|
-
dirname(target),
|
314
|
-
fileBaseNameEndsWithDotSrc ? scriptName + ".js"
|
315
|
-
: ".js" == fileExtension ? fileBaseName + ".min.js"
|
316
|
-
: fileBaseName + ".js"
|
317
|
-
)
|
318
|
-
const golfFile = () =>
|
319
|
-
readFile(target, { encoding: "utf8" }).then(async source => {
|
320
|
-
const timeStart = performance.now(),
|
321
|
-
{ script, warnings } = await processScript(source, {
|
322
|
-
minify: !(options.get("no-minify") || options.get("skip-minify")),
|
323
|
-
scriptUser,
|
324
|
-
scriptName,
|
325
|
-
filePath: target,
|
326
|
-
mangleNames,
|
327
|
-
forceQuineCheats
|
328
|
-
}),
|
329
|
-
timeTook = performance.now() - timeStart
|
330
|
-
for (const { message, line } of warnings)
|
331
|
-
log(`Warning "${chalk.bold(message)}" on line ${chalk.bold(line + "")}`)
|
332
|
-
await writeFilePersistent(outputPath, script)
|
333
|
-
.catch(error => {
|
334
|
-
if (!commands[2] || "EISDIR" != error.code) throw error
|
335
|
-
outputPath = resolve(outputPath, basename(target, fileExtension) + ".js")
|
336
|
-
return writeFilePersistent(outputPath, script)
|
337
|
-
})
|
338
|
-
.then(() =>
|
339
|
-
log(
|
340
|
-
`Wrote ${chalk.bold(countHackmudCharacters(script))} chars to ${chalk.bold(relative(".", outputPath))} | took ${Math.round(100 * timeTook) / 100}ms`
|
341
|
-
)
|
342
|
-
)
|
343
|
-
})
|
344
|
-
if (options.get("watch")) {
|
345
|
-
const { watch: watchFile } = await chokidarModule
|
346
|
-
watchFile(target, { awaitWriteFinish: { stabilityThreshold: 100 } })
|
347
|
-
.on("ready", () => log("Watching " + target))
|
348
|
-
.on("change", golfFile)
|
349
|
-
autoExit = !1
|
350
|
-
} else await golfFile()
|
351
|
-
}
|
352
|
-
break
|
353
330
|
default:
|
354
331
|
commands[0] && logError(`Unknown command: ${colourL(commands[0])}\n`)
|
355
332
|
logHelp()
|
@@ -359,21 +336,20 @@ function logHelp() {
|
|
359
336
|
const pushCommandDescription = "Push scripts from a directory to hackmud user's scripts directories",
|
360
337
|
forceQuineCheatsOptionDescription = `Force quine cheats on. Use ${colourN("--force-quine-cheats")}=${colourV("false")} to force off`,
|
361
338
|
hackmudPathOption = `${colourN("--hackmud-path")}=${colourB("<path>")}\n Override hackmud path`
|
362
|
-
console.log(colourN("Version") + colourS(": ") + colourV(version))
|
363
339
|
switch (commands[0]) {
|
364
340
|
case "dev":
|
365
341
|
case "watch":
|
366
342
|
case "push":
|
367
343
|
console.log(
|
368
344
|
colourS(
|
369
|
-
|
345
|
+
`${colourJ("push" == commands[0] ? pushCommandDescription : "Watch a directory and push a script when modified")}\n\n${colourA("Usage:")}\n${colourC("hsm")} ${colourL(commands[0])} ${colourB('<directory> ["<script user>.<script name>"...]')}\n\n${colourA("Arguments:")}\n${colourB("<directory>")}\n The source directory containing your scripts\n${colourB("<script user>")}\n A user to push script(s) to. Can be set to wild card (${colourV("*")}) which will try\n and discover users to push to\n${colourB("<script name>")}\n Name of a script to push. Can be set to wild card (${colourV("*")}) to find all scripts\n\n${colourA("Options:")}\n${colourN("--no-minify")}\n Skip minification to produce a "readable" script\n${colourN("--mangle-names")}\n Reduce character count further but lose function names in error call stacks\n${colourN("--force-quine-cheats")}\n ${forceQuineCheatsOptionDescription}\n${hackmudPathOption}\n${colourN("--dts-path")}=${colourB("<path>")}\n Path to generate a type declaration (.d.ts) file for the scripts\n${colourN("--watch")}\n Watch for changes\n\n${colourA("Examples:")}\n${colourC("hsm")} ${colourL(commands[0])} ${colourV("src")}\n Pushes all scripts found in ${colourV("src")} folder to all users\n${colourC("hsm")} ${colourL(commands[0])} ${colourV("src")} ${colourC("foo")}${colourV(".")}${colourL("bar")}\n Pushes a script named ${colourL("bar")} found in ${colourV("src")} folder to user ${userColours.get("foo")}\n${colourC("hsm")} ${colourL(commands[0])} ${colourV("src")} ${colourC("foo")}${colourV(".")}${colourL("bar")} ${colourC("baz")}${colourV(".")}${colourL("qux")}\n Multiple can be specified\n${colourC("hsm")} ${colourL(commands[0])} ${colourV("src")} ${colourC("foo")}${colourV(".")}${colourL("*")}\n Pushes all scripts found in ${colourV("src")} folder to user ${userColours.get("foo")}\n${colourC("hsm")} ${colourL(commands[0])} ${colourV("src")} ${colourC("*")}${colourV(".")}${colourL("foo")}\n Pushes all scripts named ${colourL("foo")} found in ${colourV("src")} folder to all user\n${colourC("hsm")} ${colourL(commands[0])} ${colourV("src")} ${colourC("*")}${colourV(".")}${colourL("*")}\n Pushes all scripts found in ${colourV("src")} folder to all users`
|
370
346
|
)
|
371
347
|
)
|
372
348
|
break
|
373
349
|
case "pull":
|
374
350
|
console.log(
|
375
351
|
colourS(
|
376
|
-
|
352
|
+
`${colourJ("Pull a script a from a hackmud user's script directory")}\n\n${colourA("Usage:")}\n${colourC("hsm")} ${colourL(commands[0])} ${colourB("<script user>")}${colourV(".")}${colourB("<script name>")}\n\n${colourA("Options:")}\n${hackmudPathOption}`
|
377
353
|
)
|
378
354
|
)
|
379
355
|
break
|
@@ -381,7 +357,7 @@ function logHelp() {
|
|
381
357
|
case "golf":
|
382
358
|
console.log(
|
383
359
|
colourS(
|
384
|
-
|
360
|
+
`${colourJ("Minify a script file on the spot")}\n\n${colourA("Usage:")}\n${colourC("hsm")} ${colourL(commands[0])} ${colourB("<target> [output path]")}\n\n${colourA("Options:")}\n${colourN("--no-minify")}\n Skip minification to produce a "readable" script\n${colourN("--mangle-names")}\n Reduce character count further but lose function names in error call stacks\n${colourN("--force-quine-cheats")}\n ${forceQuineCheatsOptionDescription}\n${colourN("--watch")}\n Watch for changes`
|
385
361
|
)
|
386
362
|
)
|
387
363
|
break
|
@@ -389,6 +365,15 @@ function logHelp() {
|
|
389
365
|
case "gen-type-declaration":
|
390
366
|
case "gen-dts":
|
391
367
|
case "gen-types":
|
368
|
+
case "emit-dts":
|
369
|
+
warnedDeprecatedEmitDtsAlias ||
|
370
|
+
"emit-dts" == commands[0] ||
|
371
|
+
"gen-dts" == commands[0] ||
|
372
|
+
console.warn(
|
373
|
+
colourF(
|
374
|
+
`Warning: ${colourC("hsm")} ${colourL(commands[0])} is being deprecated and will be removed\n in the next minor release of HSM\n You should switch to using its alias ${colourC("hsm")} ${colourL("emit-dts")}\n`
|
375
|
+
)
|
376
|
+
)
|
392
377
|
console.log(
|
393
378
|
colourS(
|
394
379
|
`${colourJ("Generate a type declaration file for a directory of scripts")}\n\n${colourA("Usage:")}\n${colourC("hsm")} ${colourL(commands[0])} ${colourB("<directory> [output path]")}\n\n${colourA("Options:")}\n${hackmudPathOption}`
|
@@ -398,14 +383,14 @@ function logHelp() {
|
|
398
383
|
case "sync-macros":
|
399
384
|
console.log(
|
400
385
|
colourS(
|
401
|
-
|
386
|
+
`${colourJ("Sync macros across all hackmud users")}\n\n${colourA("Options:")}\n${hackmudPathOption}`
|
402
387
|
)
|
403
388
|
)
|
404
389
|
break
|
405
390
|
default:
|
406
391
|
console.log(
|
407
392
|
colourS(
|
408
|
-
|
393
|
+
`${colourJ("Hackmud Script Manager")}\n${colourN("Version") + colourS(": ") + colourV("0.20.4-c908d16")}\n\n${colourA("Commands:")}\n${colourL("push")}\n ${pushCommandDescription}\n${colourL("minify")}\n Minify a script file on the spot\n${colourL("emit-dts")}\n Generate a type declaration file for a directory of scripts\n${colourL("sync-macros")}\n Sync macros across all hackmud users\n${colourL("pull")}\n Pull a script a from a hackmud user's script directory\n\n${colourA("Options:")}\n${colourN("--help")}\n Can be used on any command e.g. ${colourC("hsm")} ${colourL("push")} ${colourN("--help")} to show helpful information`
|
409
394
|
)
|
410
395
|
)
|
411
396
|
}
|
@@ -423,15 +408,55 @@ function logError(message) {
|
|
423
408
|
process.exitCode = 1
|
424
409
|
}
|
425
410
|
function getHackmudPath() {
|
426
|
-
const hackmudPathOption =
|
427
|
-
if (
|
428
|
-
|
411
|
+
const hackmudPathOption = popOption("hackmud-path")
|
412
|
+
if (hackmudPathOption) {
|
413
|
+
if ("string" != typeof hackmudPathOption.value) {
|
414
|
+
logError(`Option ${colourN("--hackmud-path")} must be a string, got ${colourV(hackmudPathOption.value)}\n`)
|
415
|
+
logHelp()
|
416
|
+
process.exit(1)
|
417
|
+
}
|
418
|
+
if (!hackmudPathOption.value) {
|
419
|
+
logError(`Option ${colourN("--hackmud-path")} was specified but empty\n`)
|
420
|
+
logHelp()
|
421
|
+
process.exit(1)
|
422
|
+
}
|
423
|
+
return hackmudPathOption.value
|
424
|
+
}
|
425
|
+
if (null != process.env.HSM_HACKMUD_PATH) {
|
426
|
+
if (!process.env.HSM_HACKMUD_PATH) {
|
427
|
+
logError(`Environment variable ${colourN("HSM_HACKMUD_PATH")} was specified but empty\n`)
|
428
|
+
logHelp()
|
429
|
+
process.exit(1)
|
430
|
+
}
|
431
|
+
return process.env.HSM_HACKMUD_PATH
|
432
|
+
}
|
433
|
+
return "win32" == process.platform ? resolve(process.env.APPDATA, "hackmud") : resolve(homedir(), ".config/hackmud")
|
434
|
+
}
|
435
|
+
function assertOptionIsBoolean(option) {
|
436
|
+
if ("boolean" != typeof option.value) {
|
437
|
+
logError(`The value for ${formatOption(option.name)} must be ${colourV("true")} or ${colourV("false")}\n`)
|
429
438
|
logHelp()
|
430
439
|
process.exit(1)
|
431
440
|
}
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
)
|
441
|
+
}
|
442
|
+
function popOption(...names) {
|
443
|
+
const presentOptionNames = names.filter(name => options.has(name))
|
444
|
+
if (!presentOptionNames.length) return
|
445
|
+
if (presentOptionNames.length > 1) {
|
446
|
+
logError(
|
447
|
+
`The options ${presentOptionNames.map(formatOption).join(", ")} are aliases for each other. Please only specify one`
|
448
|
+
)
|
449
|
+
process.exit(1)
|
450
|
+
}
|
451
|
+
const value = options.get(presentOptionNames[0])
|
452
|
+
options.delete(presentOptionNames[0])
|
453
|
+
return { name: presentOptionNames[0], value }
|
454
|
+
}
|
455
|
+
function complainAboutUnrecognisedOptions() {
|
456
|
+
if (options.size) {
|
457
|
+
logError(
|
458
|
+
`Unrecognised option${options.size > 1 ? "s" : ""}: ${[...options.keys()].map(formatOption).join(", ")}`
|
459
|
+
)
|
460
|
+
process.exit(1)
|
461
|
+
}
|
437
462
|
}
|