hackmud-script-manager 0.20.4-459d480 → 0.20.4-484afbe
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 +291 -267
- package/env.d.ts +318 -310
- 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 +11 -17
- package/processScript/postprocess.d.ts +1 -1
- package/processScript/postprocess.js +3 -3
- package/processScript/preprocess.js +5 -3
- package/processScript/transform.js +102 -95
- package/push.js +4 -4
- 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-459d480",
|
|
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,162 +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-484afbe")
|
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
|
-
logError(infos.message)
|
132
|
-
if (infos instanceof MissingSourceFolderError || infos instanceof NoUsersError) {
|
133
|
-
console.log()
|
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")
|
134
116
|
logHelp()
|
135
|
-
|
136
|
-
infos instanceof MissingHackmudFolderError &&
|
137
|
-
log(
|
138
|
-
`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`
|
139
|
-
)
|
140
|
-
} else infos.length || logError("Could not find any scripts to push")
|
141
|
-
}
|
142
|
-
break
|
143
|
-
case "dev":
|
144
|
-
case "watch":
|
145
|
-
{
|
146
|
-
const hackmudPath = getHackmudPath(),
|
147
|
-
sourcePath = commands[1]
|
148
|
-
if (!sourcePath) {
|
149
|
-
logError("Must provide the directory to watch\n")
|
150
|
-
logHelp()
|
151
|
-
break
|
152
|
-
}
|
153
|
-
const scripts = commands.slice(2)
|
154
|
-
if (scripts.length) {
|
155
|
-
const invalidScript = scripts.find(
|
156
|
-
script => !/^(?:[a-z_][a-z\d_]{0,24}|\*)\.(?:[a-z_][a-z\d_]{0,24}|\*)$/.test(script)
|
157
|
-
)
|
158
|
-
if (invalidScript) {
|
159
|
-
logError(`Invalid script name: ${JSON.stringify(invalidScript)}\n`)
|
160
|
-
logHelp()
|
161
|
-
break
|
117
|
+
process.exit(1)
|
162
118
|
}
|
163
|
-
|
164
|
-
|
165
|
-
if ((optionsHasNoMinify || options.has("skip-minify")) && options.has("mangle-names")) {
|
166
|
-
logError(
|
167
|
-
`Options ${colourN("--mangle-names")} and ${colourN(optionsHasNoMinify ? "--no-minify" : "--skip-minify")} are incompatible\n`
|
168
|
-
)
|
169
|
-
logHelp()
|
170
|
-
break
|
171
|
-
}
|
172
|
-
const shouldSkipMinify = options.get("no-minify") || options.get("skip-minify")
|
173
|
-
let shouldMinify
|
174
|
-
if (null != shouldSkipMinify) {
|
175
|
-
if ("boolean" != typeof shouldSkipMinify) {
|
119
|
+
const fileExtension = extname(target)
|
120
|
+
if (!supportedExtensions.includes(fileExtension)) {
|
176
121
|
logError(
|
177
|
-
`
|
122
|
+
`Unsupported file extension "${chalk.bold(fileExtension)}"\nSupported extensions are "${supportedExtensions.map(extension => chalk.bold(extension)).join('", "')}"`
|
178
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`)
|
179
184
|
logHelp()
|
180
|
-
|
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))
|
181
272
|
}
|
182
|
-
shouldMinify = !shouldSkipMinify
|
183
|
-
}
|
184
|
-
const shouldMangleNames = options.get("mangle-names")
|
185
|
-
if (null != shouldMangleNames && "boolean" != typeof shouldMangleNames) {
|
186
|
-
logError(
|
187
|
-
`The value for ${colourN("--mangle-names")} must be ${colourV("true")} or ${colourV("false")}\n`
|
188
|
-
)
|
189
|
-
logHelp()
|
190
|
-
break
|
191
|
-
}
|
192
|
-
const shouldforceQuineCheats = options.get("force-quine-cheats")
|
193
|
-
if (null != shouldforceQuineCheats && "boolean" != typeof shouldforceQuineCheats) {
|
194
|
-
logError(
|
195
|
-
`The value for ${colourN("--force-quine-cheats")} must be ${colourV("true")} or ${colourV("false")}\n`
|
196
|
-
)
|
197
|
-
logHelp()
|
198
|
-
break
|
199
273
|
}
|
200
|
-
const { watch } = await watchModule
|
201
|
-
watch(sourcePath, hackmudPath, {
|
202
|
-
scripts,
|
203
|
-
onPush: info => logInfo(info, hackmudPath),
|
204
|
-
typeDeclarationPath: (
|
205
|
-
options.get("type-declaration-path") ||
|
206
|
-
options.get("type-declaration") ||
|
207
|
-
options.get("dts") ||
|
208
|
-
options.get("gen-types")
|
209
|
-
)?.toString(),
|
210
|
-
minify: shouldMinify,
|
211
|
-
mangleNames: shouldMangleNames,
|
212
|
-
onReady: () => log("Watching"),
|
213
|
-
forceQuineCheats: shouldforceQuineCheats
|
214
|
-
})
|
215
|
-
autoExit = !1
|
216
274
|
}
|
217
275
|
break
|
218
276
|
case "pull":
|
@@ -222,8 +280,9 @@ switch (commands[0]) {
|
|
222
280
|
if (!script) {
|
223
281
|
logError("Must provide the script to pull\n")
|
224
282
|
logHelp()
|
225
|
-
|
283
|
+
process.exit(1)
|
226
284
|
}
|
285
|
+
complainAboutUnrecognisedOptions()
|
227
286
|
const sourcePath = commands[2] || "."
|
228
287
|
await pull(sourcePath, hackmudPath, script).catch(error => {
|
229
288
|
console.error(error)
|
@@ -233,8 +292,9 @@ switch (commands[0]) {
|
|
233
292
|
break
|
234
293
|
case "sync-macros":
|
235
294
|
{
|
236
|
-
const hackmudPath = getHackmudPath()
|
237
|
-
|
295
|
+
const hackmudPath = getHackmudPath()
|
296
|
+
complainAboutUnrecognisedOptions()
|
297
|
+
const { macrosSynced, usersSynced } = await syncMacros(hackmudPath)
|
238
298
|
log(`Synced ${macrosSynced} macros to ${usersSynced} users`)
|
239
299
|
}
|
240
300
|
break
|
@@ -242,19 +302,30 @@ switch (commands[0]) {
|
|
242
302
|
case "gen-type-declaration":
|
243
303
|
case "gen-dts":
|
244
304
|
case "gen-types":
|
305
|
+
case "emit-dts":
|
245
306
|
{
|
246
|
-
|
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]
|
247
317
|
if (!target) {
|
248
318
|
logError("Must provide target directory\n")
|
249
319
|
logHelp()
|
250
|
-
|
320
|
+
process.exit(1)
|
251
321
|
}
|
322
|
+
complainAboutUnrecognisedOptions()
|
252
323
|
const sourcePath = resolve(target),
|
253
324
|
outputPath = commands[2] || "./player.d.ts",
|
254
|
-
typeDeclaration = await generateTypeDeclaration(sourcePath,
|
325
|
+
typeDeclaration = await generateTypeDeclaration(sourcePath, hackmudPath)
|
255
326
|
let typeDeclarationPath = resolve(outputPath)
|
256
327
|
await writeFile(typeDeclarationPath, typeDeclaration).catch(error => {
|
257
|
-
assert(error instanceof Error, "src/bin/hsm.ts:
|
328
|
+
assert(error instanceof Error, "src/bin/hsm.ts:422:35")
|
258
329
|
if ("EISDIR" != error.code) throw error
|
259
330
|
typeDeclarationPath = resolve(typeDeclarationPath, "player.d.ts")
|
260
331
|
return writeFile(typeDeclarationPath, typeDeclaration)
|
@@ -263,102 +334,8 @@ switch (commands[0]) {
|
|
263
334
|
}
|
264
335
|
break
|
265
336
|
case "help":
|
266
|
-
case "h":
|
267
337
|
logHelp()
|
268
338
|
break
|
269
|
-
case "golf":
|
270
|
-
case "minify":
|
271
|
-
{
|
272
|
-
const target = commands[1]
|
273
|
-
if (!target) {
|
274
|
-
logError("Must provide target\n")
|
275
|
-
logHelp()
|
276
|
-
break
|
277
|
-
}
|
278
|
-
const fileExtension = extname(target)
|
279
|
-
if (!supportedExtensions.includes(fileExtension)) {
|
280
|
-
logError(
|
281
|
-
`Unsupported file extension "${chalk.bold(fileExtension)}"\nSupported extensions are "${supportedExtensions.map(extension => chalk.bold(extension)).join('", "')}"`
|
282
|
-
)
|
283
|
-
break
|
284
|
-
}
|
285
|
-
const { processScript } = await processScriptModule,
|
286
|
-
fileBaseName = basename(target, fileExtension),
|
287
|
-
fileBaseNameEndsWithDotSrc = fileBaseName.endsWith(".src"),
|
288
|
-
scriptName = fileBaseNameEndsWithDotSrc ? fileBaseName.slice(0, -4) : fileBaseName,
|
289
|
-
scriptUser =
|
290
|
-
"scripts" == basename(resolve(target, "..")) && "hackmud" == basename(resolve(target, "../../..")) ?
|
291
|
-
basename(resolve(target, "../.."))
|
292
|
-
: void 0,
|
293
|
-
optionsHasNoMinify = options.has("no-minify")
|
294
|
-
if ((optionsHasNoMinify || options.has("skip-minify")) && options.has("mangle-names")) {
|
295
|
-
logError(
|
296
|
-
`Options ${colourN("--mangle-names")} and ${colourN(optionsHasNoMinify ? "--no-minify" : "--skip-minify")} are incompatible\n`
|
297
|
-
)
|
298
|
-
logHelp()
|
299
|
-
break
|
300
|
-
}
|
301
|
-
const mangleNames_ = options.get("mangle-names")
|
302
|
-
if (null != mangleNames_ && "boolean" != typeof mangleNames_) {
|
303
|
-
logError(
|
304
|
-
`The value for ${colourN("--mangle-names")} must be ${colourV("true")} or ${colourV("false")}\n`
|
305
|
-
)
|
306
|
-
logHelp()
|
307
|
-
break
|
308
|
-
}
|
309
|
-
const mangleNames = mangleNames_,
|
310
|
-
forceQuineCheats_ = options.get("force-quine-cheats")
|
311
|
-
if (null != forceQuineCheats_ && "boolean" != typeof forceQuineCheats_) {
|
312
|
-
logError(
|
313
|
-
`the value for ${colourN("--force-quine-cheats")} must be ${colourV("true")} or ${colourV("false")}\n`
|
314
|
-
)
|
315
|
-
logHelp()
|
316
|
-
break
|
317
|
-
}
|
318
|
-
const forceQuineCheats = forceQuineCheats_
|
319
|
-
let outputPath =
|
320
|
-
commands[2] ||
|
321
|
-
resolve(
|
322
|
-
dirname(target),
|
323
|
-
fileBaseNameEndsWithDotSrc ? scriptName + ".js"
|
324
|
-
: ".js" == fileExtension ? fileBaseName + ".min.js"
|
325
|
-
: fileBaseName + ".js"
|
326
|
-
)
|
327
|
-
const golfFile = () =>
|
328
|
-
readFile(target, { encoding: "utf8" }).then(async source => {
|
329
|
-
const timeStart = performance.now(),
|
330
|
-
{ script, warnings } = await processScript(source, {
|
331
|
-
minify: !(options.get("no-minify") || options.get("skip-minify")),
|
332
|
-
scriptUser,
|
333
|
-
scriptName,
|
334
|
-
filePath: target,
|
335
|
-
mangleNames,
|
336
|
-
forceQuineCheats
|
337
|
-
}),
|
338
|
-
timeTook = performance.now() - timeStart
|
339
|
-
for (const { message, line } of warnings)
|
340
|
-
log(`Warning "${chalk.bold(message)}" on line ${chalk.bold(line + "")}`)
|
341
|
-
await writeFilePersistent(outputPath, script)
|
342
|
-
.catch(error => {
|
343
|
-
if (!commands[2] || "EISDIR" != error.code) throw error
|
344
|
-
outputPath = resolve(outputPath, basename(target, fileExtension) + ".js")
|
345
|
-
return writeFilePersistent(outputPath, script)
|
346
|
-
})
|
347
|
-
.then(() =>
|
348
|
-
log(
|
349
|
-
`Wrote ${chalk.bold(countHackmudCharacters(script))} chars to ${chalk.bold(relative(".", outputPath))} | took ${Math.round(100 * timeTook) / 100}ms`
|
350
|
-
)
|
351
|
-
)
|
352
|
-
})
|
353
|
-
if (options.get("watch")) {
|
354
|
-
const { watch: watchFile } = await chokidarModule
|
355
|
-
watchFile(target, { awaitWriteFinish: { stabilityThreshold: 100 } })
|
356
|
-
.on("ready", () => log("Watching " + target))
|
357
|
-
.on("change", golfFile)
|
358
|
-
autoExit = !1
|
359
|
-
} else await golfFile()
|
360
|
-
}
|
361
|
-
break
|
362
339
|
default:
|
363
340
|
commands[0] && logError(`Unknown command: ${colourL(commands[0])}\n`)
|
364
341
|
logHelp()
|
@@ -366,23 +343,21 @@ switch (commands[0]) {
|
|
366
343
|
autoExit && process.exit()
|
367
344
|
function logHelp() {
|
368
345
|
const pushCommandDescription = "Push scripts from a directory to hackmud user's scripts directories",
|
369
|
-
forceQuineCheatsOptionDescription = `Force quine cheats on. Use ${colourN("--force-quine-cheats")}=${colourV("false")} to force off`,
|
370
346
|
hackmudPathOption = `${colourN("--hackmud-path")}=${colourB("<path>")}\n Override hackmud path`
|
371
|
-
console.log(colourN("Version") + colourS(": ") + colourV(version))
|
372
347
|
switch (commands[0]) {
|
373
348
|
case "dev":
|
374
349
|
case "watch":
|
375
350
|
case "push":
|
376
351
|
console.log(
|
377
352
|
colourS(
|
378
|
-
|
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`
|
379
354
|
)
|
380
355
|
)
|
381
356
|
break
|
382
357
|
case "pull":
|
383
358
|
console.log(
|
384
359
|
colourS(
|
385
|
-
|
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}`
|
386
361
|
)
|
387
362
|
)
|
388
363
|
break
|
@@ -390,7 +365,7 @@ function logHelp() {
|
|
390
365
|
case "golf":
|
391
366
|
console.log(
|
392
367
|
colourS(
|
393
|
-
|
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`
|
394
369
|
)
|
395
370
|
)
|
396
371
|
break
|
@@ -398,6 +373,15 @@ function logHelp() {
|
|
398
373
|
case "gen-type-declaration":
|
399
374
|
case "gen-dts":
|
400
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
|
+
)
|
401
385
|
console.log(
|
402
386
|
colourS(
|
403
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}`
|
@@ -407,14 +391,14 @@ function logHelp() {
|
|
407
391
|
case "sync-macros":
|
408
392
|
console.log(
|
409
393
|
colourS(
|
410
|
-
|
394
|
+
`${colourJ("Sync macros across all hackmud users")}\n\n${colourA("Options:")}\n${hackmudPathOption}`
|
411
395
|
)
|
412
396
|
)
|
413
397
|
break
|
414
398
|
default:
|
415
399
|
console.log(
|
416
400
|
colourS(
|
417
|
-
|
401
|
+
`${colourJ("Hackmud Script Manager")}\n${colourN("Version") + colourS(": ") + colourV("0.20.4-484afbe")}\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`
|
418
402
|
)
|
419
403
|
)
|
420
404
|
}
|
@@ -432,15 +416,55 @@ function logError(message) {
|
|
432
416
|
process.exitCode = 1
|
433
417
|
}
|
434
418
|
function getHackmudPath() {
|
435
|
-
const hackmudPathOption =
|
436
|
-
if (
|
437
|
-
|
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`)
|
438
446
|
logHelp()
|
439
447
|
process.exit(1)
|
440
448
|
}
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
)
|
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
|
+
}
|
446
470
|
}
|