hackmud-script-manager 0.20.4-12b9eb8 → 0.20.4-1d688c1
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 +7 -1
- package/bin/hsm.js +291 -258
- package/env.d.ts +844 -1423
- package/generateTypeDeclaration.js +2 -1
- package/index.js +2 -1
- package/package.json +43 -39
- package/processScript/index.js +3 -3
- package/processScript/minify.js +18 -21
- 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/syncMacros.js +1 -1
- package/watch.js +12 -9
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-12b9eb8",
|
|
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,222 @@ 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-1d688c1")
|
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
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
if (null != shouldMangleNames && "boolean" != typeof shouldMangleNames) {
|
88
|
+
)
|
89
|
+
const mangleNamesOption = popOption("mangle-names"),
|
90
|
+
forceQuineCheatsOption = popOption("force-quine-cheats"),
|
91
|
+
noQuineCheatsOptions = popOption("no-quine-cheats"),
|
92
|
+
noMinifyIncompatibleOption = mangleNamesOption || forceQuineCheatsOption || noQuineCheatsOptions
|
93
|
+
if (noMinifyOption && noMinifyIncompatibleOption) {
|
108
94
|
logError(
|
109
|
-
`
|
95
|
+
`Options ${formatOption(noMinifyOption.name)} and ${formatOption(noMinifyIncompatibleOption.name)} are incompatible\n`
|
110
96
|
)
|
111
97
|
logHelp()
|
112
|
-
|
98
|
+
process.exit(1)
|
113
99
|
}
|
114
|
-
|
115
|
-
if (null != shouldforceQuineCheats && "boolean" != typeof shouldforceQuineCheats) {
|
100
|
+
if (forceQuineCheatsOption && noQuineCheatsOptions) {
|
116
101
|
logError(
|
117
|
-
`
|
102
|
+
`Options ${formatOption(forceQuineCheatsOption.name)} and ${formatOption(noQuineCheatsOptions.name)} are incompatible\n`
|
118
103
|
)
|
119
104
|
logHelp()
|
120
|
-
|
105
|
+
process.exit(1)
|
121
106
|
}
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
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
|
143
|
-
}
|
144
|
-
const scripts = commands.slice(2)
|
145
|
-
if (scripts.length) {
|
146
|
-
const invalidScript = scripts.find(
|
147
|
-
script => !/^(?:[a-z_][a-z\d_]{0,24}|\*)\.(?:[a-z_][a-z\d_]{0,24}|\*)$/.test(script)
|
148
|
-
)
|
149
|
-
if (invalidScript) {
|
150
|
-
logError(`Invalid script name: ${JSON.stringify(invalidScript)}\n`)
|
107
|
+
noMinifyOption && assertOptionIsBoolean(noMinifyOption)
|
108
|
+
mangleNamesOption && assertOptionIsBoolean(mangleNamesOption)
|
109
|
+
forceQuineCheatsOption && assertOptionIsBoolean(forceQuineCheatsOption)
|
110
|
+
noQuineCheatsOptions && assertOptionIsBoolean(noQuineCheatsOptions)
|
111
|
+
if ("golf" == commands[0] || "minify" == commands[0]) {
|
112
|
+
const watchOption = popOption("watch"),
|
113
|
+
target = commands[1]
|
114
|
+
if (!target) {
|
115
|
+
logError("Must provide target\n")
|
151
116
|
logHelp()
|
152
|
-
|
117
|
+
process.exit(1)
|
153
118
|
}
|
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) {
|
119
|
+
const fileExtension = extname(target)
|
120
|
+
if (!supportedExtensions.includes(fileExtension)) {
|
167
121
|
logError(
|
168
|
-
`
|
122
|
+
`Unsupported file extension "${chalk.bold(fileExtension)}"\nSupported extensions are "${supportedExtensions.map(extension => chalk.bold(extension)).join('", "')}"`
|
169
123
|
)
|
124
|
+
process.exit(1)
|
125
|
+
}
|
126
|
+
complainAboutUnrecognisedOptions()
|
127
|
+
const { processScript } = await processScriptModule,
|
128
|
+
fileBaseName = basename(target, fileExtension),
|
129
|
+
fileBaseNameEndsWithDotSrc = fileBaseName.endsWith(".src"),
|
130
|
+
scriptName = fileBaseNameEndsWithDotSrc ? fileBaseName.slice(0, -4) : fileBaseName,
|
131
|
+
scriptUser =
|
132
|
+
(
|
133
|
+
"scripts" == basename(resolve(target, "..")) &&
|
134
|
+
"hackmud" == basename(resolve(target, "../../.."))
|
135
|
+
) ?
|
136
|
+
basename(resolve(target, "../.."))
|
137
|
+
: void 0
|
138
|
+
let outputPath =
|
139
|
+
commands[2] ||
|
140
|
+
resolve(
|
141
|
+
dirname(target),
|
142
|
+
fileBaseNameEndsWithDotSrc ? scriptName + ".js"
|
143
|
+
: ".js" == fileExtension ? fileBaseName + ".min.js"
|
144
|
+
: fileBaseName + ".js"
|
145
|
+
)
|
146
|
+
const golfFile = () =>
|
147
|
+
readFile(target, { encoding: "utf8" }).then(async source => {
|
148
|
+
const timeStart = performance.now(),
|
149
|
+
{ script, warnings } = await processScript(source, {
|
150
|
+
minify: noMinifyOption && !noMinifyOption.value,
|
151
|
+
scriptUser,
|
152
|
+
scriptName,
|
153
|
+
filePath: target,
|
154
|
+
mangleNames: mangleNamesOption?.value,
|
155
|
+
forceQuineCheats: forceQuineCheatsOption?.value ?? !noQuineCheatsOptions?.value
|
156
|
+
}),
|
157
|
+
timeTook = performance.now() - timeStart
|
158
|
+
for (const { message, line } of warnings)
|
159
|
+
log(`Warning "${chalk.bold(message)}" on line ${chalk.bold(line + "")}`)
|
160
|
+
await writeFilePersistent(outputPath, script)
|
161
|
+
.catch(error => {
|
162
|
+
if (!commands[2] || "EISDIR" != error.code) throw error
|
163
|
+
outputPath = resolve(outputPath, basename(target, fileExtension) + ".js")
|
164
|
+
return writeFilePersistent(outputPath, script)
|
165
|
+
})
|
166
|
+
.then(() =>
|
167
|
+
log(
|
168
|
+
`Wrote ${chalk.bold(countHackmudCharacters(script))} chars to ${chalk.bold(relative(".", outputPath))} | took ${Math.round(100 * timeTook) / 100}ms`
|
169
|
+
)
|
170
|
+
)
|
171
|
+
})
|
172
|
+
if (watchOption) {
|
173
|
+
const { watch: watchFile } = await chokidarModule
|
174
|
+
watchFile(target, { awaitWriteFinish: { stabilityThreshold: 100 } })
|
175
|
+
.on("ready", () => log("Watching " + target))
|
176
|
+
.on("change", golfFile)
|
177
|
+
autoExit = !1
|
178
|
+
} else await golfFile()
|
179
|
+
} else {
|
180
|
+
const hackmudPath = getHackmudPath(),
|
181
|
+
sourcePath = commands[1]
|
182
|
+
if (!sourcePath) {
|
183
|
+
logError(`Must provide the directory to ${"push" == commands[0] ? "push from" : "watch"}\n`)
|
170
184
|
logHelp()
|
171
|
-
|
185
|
+
process.exit(1)
|
186
|
+
}
|
187
|
+
const scripts = commands.slice(2)
|
188
|
+
if (scripts.length) {
|
189
|
+
const invalidScript = scripts.find(
|
190
|
+
script => !/^(?:[a-z_][a-z\d_]{0,24}|\*)\.(?:[a-z_][a-z\d_]{0,24}|\*)$/.test(script)
|
191
|
+
)
|
192
|
+
if (invalidScript) {
|
193
|
+
logError(`Invalid script name: ${JSON.stringify(invalidScript)}\n`)
|
194
|
+
logHelp()
|
195
|
+
process.exit(1)
|
196
|
+
}
|
197
|
+
} else scripts.push("*.*")
|
198
|
+
const watchOption = popOption("watch")
|
199
|
+
if ("push" != commands[0] || watchOption?.value) {
|
200
|
+
const dtsPathOption = popOption(
|
201
|
+
"dts-path",
|
202
|
+
"type-declaration-path",
|
203
|
+
"type-declaration",
|
204
|
+
"dts",
|
205
|
+
"gen-types"
|
206
|
+
)
|
207
|
+
dtsPathOption &&
|
208
|
+
"dts-path" != dtsPathOption.name &&
|
209
|
+
"type-declaration-path" != dtsPathOption.name &&
|
210
|
+
console.warn(
|
211
|
+
colourF(
|
212
|
+
`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`
|
213
|
+
)
|
214
|
+
)
|
215
|
+
complainAboutUnrecognisedOptions()
|
216
|
+
const { watch } = await watchModule
|
217
|
+
watch(sourcePath, hackmudPath, {
|
218
|
+
scripts,
|
219
|
+
onPush: info => logInfo(info, hackmudPath),
|
220
|
+
typeDeclarationPath: dtsPathOption?.value.toString(),
|
221
|
+
minify: noMinifyOption && !noMinifyOption.value,
|
222
|
+
mangleNames: mangleNamesOption?.value,
|
223
|
+
onReady: () => log("Watching"),
|
224
|
+
forceQuineCheats: forceQuineCheatsOption?.value ?? !noQuineCheatsOptions?.value
|
225
|
+
})
|
226
|
+
autoExit = !1
|
227
|
+
} else {
|
228
|
+
const dtsPathOption = popOption("dts-path")
|
229
|
+
complainAboutUnrecognisedOptions()
|
230
|
+
let declarationPathPromise
|
231
|
+
if (dtsPathOption) {
|
232
|
+
if ("string" != typeof dtsPathOption.value) {
|
233
|
+
logError(
|
234
|
+
`Option ${formatOption(dtsPathOption.name)} must be a string, got ${colourV(dtsPathOption.value)}\n`
|
235
|
+
)
|
236
|
+
logHelp()
|
237
|
+
process.exit(1)
|
238
|
+
}
|
239
|
+
let typeDeclarationPath = resolve(dtsPathOption.value)
|
240
|
+
const typeDeclaration = await generateTypeDeclaration(sourcePath, hackmudPath)
|
241
|
+
declarationPathPromise = writeFile(typeDeclarationPath, typeDeclaration)
|
242
|
+
.catch(error => {
|
243
|
+
assert(error instanceof Error, "src/bin/hsm.ts:288:38")
|
244
|
+
if ("EISDIR" != error.code) throw error
|
245
|
+
typeDeclarationPath = resolve(typeDeclarationPath, "player.d.ts")
|
246
|
+
return writeFile(typeDeclarationPath, typeDeclaration)
|
247
|
+
})
|
248
|
+
.then(() => typeDeclarationPath)
|
249
|
+
}
|
250
|
+
const { push, MissingSourceFolderError, MissingHackmudFolderError, NoUsersError } =
|
251
|
+
await pushModule,
|
252
|
+
infos = await push(sourcePath, hackmudPath, {
|
253
|
+
scripts,
|
254
|
+
onPush: info => logInfo(info, hackmudPath),
|
255
|
+
minify: noMinifyOption && !noMinifyOption.value,
|
256
|
+
mangleNames: mangleNamesOption?.value,
|
257
|
+
forceQuineCheats: forceQuineCheatsOption?.value ?? !noQuineCheatsOptions?.value
|
258
|
+
})
|
259
|
+
if (infos instanceof Error) {
|
260
|
+
logError(infos.message)
|
261
|
+
if (infos instanceof MissingSourceFolderError || infos instanceof NoUsersError) {
|
262
|
+
console.log()
|
263
|
+
logHelp()
|
264
|
+
} else
|
265
|
+
infos instanceof MissingHackmudFolderError &&
|
266
|
+
log(
|
267
|
+
`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`
|
268
|
+
)
|
269
|
+
} else infos.length || logError("Could not find any scripts to push")
|
270
|
+
declarationPathPromise &&
|
271
|
+
log("Wrote type declaration to " + chalk.bold(await declarationPathPromise))
|
172
272
|
}
|
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
273
|
}
|
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
274
|
}
|
208
275
|
break
|
209
276
|
case "pull":
|
@@ -213,8 +280,9 @@ switch (commands[0]) {
|
|
213
280
|
if (!script) {
|
214
281
|
logError("Must provide the script to pull\n")
|
215
282
|
logHelp()
|
216
|
-
|
283
|
+
process.exit(1)
|
217
284
|
}
|
285
|
+
complainAboutUnrecognisedOptions()
|
218
286
|
const sourcePath = commands[2] || "."
|
219
287
|
await pull(sourcePath, hackmudPath, script).catch(error => {
|
220
288
|
console.error(error)
|
@@ -224,8 +292,9 @@ switch (commands[0]) {
|
|
224
292
|
break
|
225
293
|
case "sync-macros":
|
226
294
|
{
|
227
|
-
const hackmudPath = getHackmudPath()
|
228
|
-
|
295
|
+
const hackmudPath = getHackmudPath()
|
296
|
+
complainAboutUnrecognisedOptions()
|
297
|
+
const { macrosSynced, usersSynced } = await syncMacros(hackmudPath)
|
229
298
|
log(`Synced ${macrosSynced} macros to ${usersSynced} users`)
|
230
299
|
}
|
231
300
|
break
|
@@ -233,19 +302,30 @@ switch (commands[0]) {
|
|
233
302
|
case "gen-type-declaration":
|
234
303
|
case "gen-dts":
|
235
304
|
case "gen-types":
|
305
|
+
case "emit-dts":
|
236
306
|
{
|
237
|
-
|
307
|
+
if ("emit-dts" != commands[0] && "gen-dts" != commands[0]) {
|
308
|
+
warnedDeprecatedEmitDtsAlias = !0
|
309
|
+
console.warn(
|
310
|
+
colourF(
|
311
|
+
`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`
|
312
|
+
)
|
313
|
+
)
|
314
|
+
}
|
315
|
+
const hackmudPath = getHackmudPath(),
|
316
|
+
target = commands[1]
|
238
317
|
if (!target) {
|
239
318
|
logError("Must provide target directory\n")
|
240
319
|
logHelp()
|
241
|
-
|
320
|
+
process.exit(1)
|
242
321
|
}
|
322
|
+
complainAboutUnrecognisedOptions()
|
243
323
|
const sourcePath = resolve(target),
|
244
324
|
outputPath = commands[2] || "./player.d.ts",
|
245
|
-
typeDeclaration = await generateTypeDeclaration(sourcePath,
|
325
|
+
typeDeclaration = await generateTypeDeclaration(sourcePath, hackmudPath)
|
246
326
|
let typeDeclarationPath = resolve(outputPath)
|
247
327
|
await writeFile(typeDeclarationPath, typeDeclaration).catch(error => {
|
248
|
-
assert(error instanceof Error, "src/bin/hsm.ts:
|
328
|
+
assert(error instanceof Error, "src/bin/hsm.ts:422:35")
|
249
329
|
if ("EISDIR" != error.code) throw error
|
250
330
|
typeDeclarationPath = resolve(typeDeclarationPath, "player.d.ts")
|
251
331
|
return writeFile(typeDeclarationPath, typeDeclaration)
|
@@ -254,102 +334,8 @@ switch (commands[0]) {
|
|
254
334
|
}
|
255
335
|
break
|
256
336
|
case "help":
|
257
|
-
case "h":
|
258
337
|
logHelp()
|
259
338
|
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
339
|
default:
|
354
340
|
commands[0] && logError(`Unknown command: ${colourL(commands[0])}\n`)
|
355
341
|
logHelp()
|
@@ -357,23 +343,21 @@ switch (commands[0]) {
|
|
357
343
|
autoExit && process.exit()
|
358
344
|
function logHelp() {
|
359
345
|
const pushCommandDescription = "Push scripts from a directory to hackmud user's scripts directories",
|
360
|
-
forceQuineCheatsOptionDescription = `Force quine cheats on. Use ${colourN("--force-quine-cheats")}=${colourV("false")} to force off`,
|
361
346
|
hackmudPathOption = `${colourN("--hackmud-path")}=${colourB("<path>")}\n Override hackmud path`
|
362
|
-
console.log(colourN("Version") + colourS(": ") + colourV(version))
|
363
347
|
switch (commands[0]) {
|
364
348
|
case "dev":
|
365
349
|
case "watch":
|
366
350
|
case "push":
|
367
351
|
console.log(
|
368
352
|
colourS(
|
369
|
-
|
353
|
+
`${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")}, ${colourN("--no-quine-cheats")}\n Force quine cheats on or off\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
354
|
)
|
371
355
|
)
|
372
356
|
break
|
373
357
|
case "pull":
|
374
358
|
console.log(
|
375
359
|
colourS(
|
376
|
-
|
360
|
+
`${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
361
|
)
|
378
362
|
)
|
379
363
|
break
|
@@ -381,7 +365,7 @@ function logHelp() {
|
|
381
365
|
case "golf":
|
382
366
|
console.log(
|
383
367
|
colourS(
|
384
|
-
|
368
|
+
`${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")}, ${colourN("--no-quine-cheats")}\n Force quine cheats on or off\n${colourN("--watch")}\n Watch for changes`
|
385
369
|
)
|
386
370
|
)
|
387
371
|
break
|
@@ -389,6 +373,15 @@ function logHelp() {
|
|
389
373
|
case "gen-type-declaration":
|
390
374
|
case "gen-dts":
|
391
375
|
case "gen-types":
|
376
|
+
case "emit-dts":
|
377
|
+
warnedDeprecatedEmitDtsAlias ||
|
378
|
+
"emit-dts" == commands[0] ||
|
379
|
+
"gen-dts" == commands[0] ||
|
380
|
+
console.warn(
|
381
|
+
colourF(
|
382
|
+
`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`
|
383
|
+
)
|
384
|
+
)
|
392
385
|
console.log(
|
393
386
|
colourS(
|
394
387
|
`${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 +391,14 @@ function logHelp() {
|
|
398
391
|
case "sync-macros":
|
399
392
|
console.log(
|
400
393
|
colourS(
|
401
|
-
|
394
|
+
`${colourJ("Sync macros across all hackmud users")}\n\n${colourA("Options:")}\n${hackmudPathOption}`
|
402
395
|
)
|
403
396
|
)
|
404
397
|
break
|
405
398
|
default:
|
406
399
|
console.log(
|
407
400
|
colourS(
|
408
|
-
|
401
|
+
`${colourJ("Hackmud Script Manager")}\n${colourN("Version") + colourS(": ") + colourV("0.20.4-1d688c1")}\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
402
|
)
|
410
403
|
)
|
411
404
|
}
|
@@ -423,15 +416,55 @@ function logError(message) {
|
|
423
416
|
process.exitCode = 1
|
424
417
|
}
|
425
418
|
function getHackmudPath() {
|
426
|
-
const hackmudPathOption =
|
427
|
-
if (
|
428
|
-
|
419
|
+
const hackmudPathOption = popOption("hackmud-path")
|
420
|
+
if (hackmudPathOption) {
|
421
|
+
if ("string" != typeof hackmudPathOption.value) {
|
422
|
+
logError(`Option ${colourN("--hackmud-path")} must be a string, got ${colourV(hackmudPathOption.value)}\n`)
|
423
|
+
logHelp()
|
424
|
+
process.exit(1)
|
425
|
+
}
|
426
|
+
if (!hackmudPathOption.value) {
|
427
|
+
logError(`Option ${colourN("--hackmud-path")} was specified but empty\n`)
|
428
|
+
logHelp()
|
429
|
+
process.exit(1)
|
430
|
+
}
|
431
|
+
return hackmudPathOption.value
|
432
|
+
}
|
433
|
+
if (null != process.env.HSM_HACKMUD_PATH) {
|
434
|
+
if (!process.env.HSM_HACKMUD_PATH) {
|
435
|
+
logError(`Environment variable ${colourN("HSM_HACKMUD_PATH")} was specified but empty\n`)
|
436
|
+
logHelp()
|
437
|
+
process.exit(1)
|
438
|
+
}
|
439
|
+
return process.env.HSM_HACKMUD_PATH
|
440
|
+
}
|
441
|
+
return "win32" == process.platform ? resolve(process.env.APPDATA, "hackmud") : resolve(homedir(), ".config/hackmud")
|
442
|
+
}
|
443
|
+
function assertOptionIsBoolean(option) {
|
444
|
+
if ("boolean" != typeof option.value) {
|
445
|
+
logError(`The value for ${formatOption(option.name)} must be ${colourV("true")} or ${colourV("false")}\n`)
|
429
446
|
logHelp()
|
430
447
|
process.exit(1)
|
431
448
|
}
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
)
|
449
|
+
}
|
450
|
+
function popOption(...names) {
|
451
|
+
const presentOptionNames = names.filter(name => options.has(name))
|
452
|
+
if (!presentOptionNames.length) return
|
453
|
+
if (presentOptionNames.length > 1) {
|
454
|
+
logError(
|
455
|
+
`The options ${presentOptionNames.map(formatOption).join(", ")} are aliases for each other. Please only specify one`
|
456
|
+
)
|
457
|
+
process.exit(1)
|
458
|
+
}
|
459
|
+
const value = options.get(presentOptionNames[0])
|
460
|
+
options.delete(presentOptionNames[0])
|
461
|
+
return { name: presentOptionNames[0], value }
|
462
|
+
}
|
463
|
+
function complainAboutUnrecognisedOptions() {
|
464
|
+
if (options.size) {
|
465
|
+
logError(
|
466
|
+
`Unrecognised option${options.size > 1 ? "s" : ""}: ${[...options.keys()].map(formatOption).join(", ")}`
|
467
|
+
)
|
468
|
+
process.exit(1)
|
469
|
+
}
|
437
470
|
}
|