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