hackmud-script-manager 0.13.0-c14e977 → 0.13.0-c461329

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/.gitattributes +1 -0
  2. package/.github/workflows/codeql-analysis.yml +39 -0
  3. package/.github/workflows/publish.yml +42 -0
  4. package/.vscode/settings.json +6 -0
  5. package/babel.config.json +6 -0
  6. package/package.json +17 -23
  7. package/rollup.config.js +110 -0
  8. package/scripts/build-package-json.js +36 -0
  9. package/scripts/jsconfig.json +5 -0
  10. package/scripts/version-dev.js +25 -0
  11. package/src/bin/hsm.ts +505 -0
  12. package/src/constants.json +3 -0
  13. package/src/generateTypings.ts +116 -0
  14. package/src/index.ts +19 -0
  15. package/src/modules.d.ts +5 -0
  16. package/src/processScript/index.ts +198 -0
  17. package/src/processScript/minify.ts +529 -0
  18. package/src/processScript/postprocess.ts +38 -0
  19. package/src/processScript/preprocess.ts +146 -0
  20. package/src/processScript/transform.ts +760 -0
  21. package/src/pull.ts +16 -0
  22. package/src/push.ts +314 -0
  23. package/src/syncMacros.ts +52 -0
  24. package/src/test.ts +59 -0
  25. package/src/tsconfig.json +20 -0
  26. package/src/watch.ts +156 -0
  27. package/tsconfig.json +12 -0
  28. package/assert-1b7dada8.js +0 -1
  29. package/bin/hsm.d.ts +0 -2
  30. package/bin/hsm.js +0 -2
  31. package/generateTypings.d.ts +0 -2
  32. package/generateTypings.js +0 -1
  33. package/index.d.ts +0 -15
  34. package/index.js +0 -1
  35. package/processScript/compile.d.ts +0 -17
  36. package/processScript/compile.js +0 -1
  37. package/processScript/index.d.ts +0 -30
  38. package/processScript/index.js +0 -1
  39. package/processScript/minify.d.ts +0 -7
  40. package/processScript/minify.js +0 -1
  41. package/processScript/postProcess.d.ts +0 -2
  42. package/processScript/postProcess.js +0 -1
  43. package/processScript/preProcess.d.ts +0 -15
  44. package/processScript/preProcess.js +0 -1
  45. package/pull.d.ts +0 -9
  46. package/pull.js +0 -1
  47. package/push.d.ts +0 -26
  48. package/push.js +0 -1
  49. package/spliceString-2c6f214f.js +0 -1
  50. package/syncMacros.d.ts +0 -5
  51. package/syncMacros.js +0 -1
  52. package/test.d.ts +0 -6
  53. package/test.js +0 -1
  54. package/watch.d.ts +0 -14
  55. package/watch.js +0 -1
package/src/pull.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { copyFilePersistent } from "@samual/lib"
2
+ import { resolve as resolvePath } from "path"
3
+
4
+ /**
5
+ * Copies script from hackmud to local source folder.
6
+ *
7
+ * @param sourceFolderPath path to folder containing source files
8
+ * @param hackmudPath path to hackmud directory
9
+ * @param script script to pull in `user.name` format
10
+ */
11
+ export async function pull(sourceFolderPath: string, hackmudPath: string, script: string) {
12
+ const [ user, name ] = script.split(".")
13
+ await copyFilePersistent(resolvePath(hackmudPath, user, "scripts", `${name}.js`), resolvePath(sourceFolderPath, user, `${name}.js`))
14
+ }
15
+
16
+ export default pull
package/src/push.ts ADDED
@@ -0,0 +1,314 @@
1
+ import { countHackmudCharacters, DynamicMap, forEachParallel, writeFilePersistent } from "@samual/lib"
2
+ import fs from "fs"
3
+ import { basename as getBaseName, extname as getFileExtension, resolve as resolvePath } from "path"
4
+ import type { Info } from "."
5
+ import { supportedExtensions } from "./constants.json"
6
+ import processScript from "./processScript"
7
+
8
+ const { readFile, readdir: readDirectory } = fs.promises
9
+
10
+ interface PushOptions {
11
+ /**
12
+ * array of scripts in the format `foo.bar`
13
+ *
14
+ * also accepts wild card e.g. `*.bar` or `foo.*`
15
+ *
16
+ * pushes everything by default
17
+ */
18
+ scripts: string | string[]
19
+
20
+ /** callback when a script is pushed */
21
+ onPush: (info: Info) => void
22
+
23
+ /** whether to do the minify step (defaults to `true`) */
24
+ minify: boolean
25
+
26
+ /** whether to mangle function and class names (defaults to `false`) */
27
+ mangleNames: boolean
28
+ }
29
+
30
+ /**
31
+ * Push scripts from a source directory to the hackmud directory.
32
+ *
33
+ * Files directly in the source folder are pushed to all users
34
+ * @param sourceDirectory directory containing source code
35
+ * @param hackmudDirectory directory created by hackmud containing user data including scripts
36
+ * @param options {@link PushOptions details}
37
+ * @returns array of info on pushed scripts
38
+ */
39
+ export async function push(
40
+ sourceDirectory: string,
41
+ hackmudDirectory: string,
42
+ {
43
+ scripts = "*.*",
44
+ onPush = (info: Info) => {},
45
+ minify = true,
46
+ mangleNames = false
47
+ }: Partial<PushOptions> = {}
48
+ ) {
49
+ if (typeof scripts == "string")
50
+ scripts = [ scripts ]
51
+
52
+ const scriptNamesByUser = new DynamicMap((user: string) => new Set<string>())
53
+ const wildScriptUsers = new Set<string>()
54
+ const wildUserScripts = new Set<string>()
55
+
56
+ let pushEverything = false
57
+
58
+ for (const fullScriptName of scripts) {
59
+ const [ user, scriptName ] = fullScriptName.split(".")
60
+
61
+ if (!user || user == "*") {
62
+ if (!scriptName || scriptName == "*")
63
+ pushEverything = true
64
+ else
65
+ wildUserScripts.add(scriptName)
66
+ } else if (!scriptName || scriptName == "*")
67
+ wildScriptUsers.add(user)
68
+ else
69
+ scriptNamesByUser.get(user).add(scriptName)
70
+ }
71
+
72
+ const usersByGlobalScriptsToPush = new DynamicMap((user: string) => new Set<string>())
73
+ const allInfo: Info[] = []
74
+ const scriptNamesAlreadyPushedByUser = new DynamicMap((user: string) => new Set<string>())
75
+
76
+ let sourceDirectoryDirents
77
+
78
+ // *.bar
79
+ if (wildUserScripts.size || pushEverything) {
80
+ const hackmudDirectoryDirents = await readDirectory(resolvePath(hackmudDirectory), { withFileTypes: true })
81
+
82
+ const allUsers = new Set([
83
+ ...(sourceDirectoryDirents = await readDirectory(resolvePath(sourceDirectory), { withFileTypes: true }))
84
+ .filter(dirent => dirent.isDirectory())
85
+ .map(dirent => dirent.name),
86
+ ...hackmudDirectoryDirents
87
+ .filter(dirent => dirent.isDirectory())
88
+ .map(dirent => dirent.name),
89
+ ...hackmudDirectoryDirents
90
+ .filter(dirent => dirent.isFile() && getFileExtension(dirent.name) == ".key")
91
+ .map(dirent => dirent.name.slice(0, -4)),
92
+ ...scriptNamesByUser.keys(),
93
+ ...wildScriptUsers
94
+ ])
95
+
96
+ if (pushEverything) {
97
+ for (const user of allUsers)
98
+ wildScriptUsers.add(user)
99
+ } else {
100
+ for (const user of allUsers) {
101
+ const scriptNames = scriptNamesByUser.get(user)
102
+
103
+ for (const scriptName of wildUserScripts)
104
+ scriptNames.add(scriptName)
105
+ }
106
+ }
107
+ }
108
+
109
+ // foo.*
110
+ await forEachParallel(wildScriptUsers, async user => {
111
+ await readDirectory(resolvePath(sourceDirectory, user), { withFileTypes: true }).then(async dirents => {
112
+ await forEachParallel(dirents, async dirent => {
113
+ const extension = getFileExtension(dirent.name)
114
+
115
+ if (dirent.isFile() && supportedExtensions.includes(extension)) {
116
+ const scriptName = getBaseName(dirent.name, extension)
117
+ const filePath = resolvePath(sourceDirectory, user, dirent.name)
118
+
119
+ const { srcLength, script: minifiedCode } = await processScript(
120
+ await readFile(filePath, { encoding: "utf-8" }),
121
+ {
122
+ minify,
123
+ scriptUser: user,
124
+ scriptName,
125
+ filePath,
126
+ mangleNames
127
+ }
128
+ )
129
+
130
+ const info: Info = {
131
+ file: `${user}/${dirent.name}`,
132
+ users: [ user ],
133
+ minLength: countHackmudCharacters(minifiedCode),
134
+ error: null,
135
+ srcLength
136
+ }
137
+
138
+ scriptNamesAlreadyPushedByUser.get(user).add(scriptName)
139
+ allInfo.push(info)
140
+
141
+ await writeFilePersistent(resolvePath(hackmudDirectory, user, `scripts/${scriptName}.js`), minifiedCode)
142
+
143
+ onPush(info)
144
+ }
145
+ })
146
+ }, (error: NodeJS.ErrnoException) => {
147
+ if (error.code != "ENOENT")
148
+ throw error
149
+ })
150
+ })
151
+
152
+ // foo.bar
153
+ await forEachParallel(scriptNamesByUser, async ([ user, scripts ]) => {
154
+ if (wildScriptUsers.has(user))
155
+ return
156
+
157
+ await forEachParallel(scripts, async scriptName => {
158
+ let code
159
+ let fileName
160
+
161
+ let filePath!: string
162
+
163
+ for (const extension of supportedExtensions) {
164
+ try {
165
+ fileName = `${scriptName}${extension}`
166
+ code = await readFile(filePath = resolvePath(sourceDirectory, user, fileName), { encoding: "utf-8" })
167
+ break
168
+ } catch {}
169
+ }
170
+
171
+ if (code) {
172
+ const { srcLength, script: minifiedCode } = await processScript(
173
+ code,
174
+ {
175
+ minify,
176
+ scriptUser: user,
177
+ scriptName,
178
+ filePath,
179
+ mangleNames
180
+ }
181
+ )
182
+
183
+ const info: Info = {
184
+ file: `${user}/${fileName}`,
185
+ users: [ user ],
186
+ minLength: countHackmudCharacters(minifiedCode),
187
+ error: null,
188
+ srcLength
189
+ }
190
+
191
+ allInfo.push(info)
192
+
193
+ await writeFilePersistent(resolvePath(hackmudDirectory, user, "scripts", `${scriptName}.js`), minifiedCode)
194
+
195
+ onPush(info)
196
+ } else
197
+ usersByGlobalScriptsToPush.get(scriptName).add(user)
198
+ })
199
+ })
200
+
201
+ // foo.* (global)
202
+ if (wildScriptUsers.size) {
203
+ await forEachParallel(sourceDirectoryDirents || await readDirectory(resolvePath(sourceDirectory), { withFileTypes: true }), async dirent => {
204
+ const extension = getFileExtension(dirent.name)
205
+
206
+ if (!dirent.isFile() || !supportedExtensions.includes(extension))
207
+ return
208
+
209
+ const scriptName = getBaseName(dirent.name, extension)
210
+ const usersToPushTo = [ ...wildScriptUsers, ...usersByGlobalScriptsToPush.get(scriptName) ].filter(user => !scriptNamesAlreadyPushedByUser.get(user).has(scriptName))
211
+
212
+ if (!usersToPushTo.length)
213
+ return
214
+
215
+ const uniqueID = Math.floor(Math.random() * (2 ** 52)).toString(36).padStart(11, "0")
216
+ const filePath = resolvePath(sourceDirectory, dirent.name)
217
+
218
+ const { srcLength, script: minifiedCode } = await processScript(
219
+ await readFile(filePath, { encoding: "utf-8" }),
220
+ {
221
+ minify,
222
+ scriptUser: true,
223
+ scriptName,
224
+ uniqueID,
225
+ filePath,
226
+ mangleNames
227
+ }
228
+ )
229
+
230
+ const info: Info = {
231
+ file: dirent.name,
232
+ users: usersToPushTo,
233
+ minLength: countHackmudCharacters(minifiedCode),
234
+ error: null,
235
+ srcLength
236
+ }
237
+
238
+ await forEachParallel(usersToPushTo, user =>
239
+ writeFilePersistent(
240
+ resolvePath(
241
+ hackmudDirectory,
242
+ user,
243
+ `scripts/${scriptName}.js`
244
+ ),
245
+ minifiedCode
246
+ .replace(new RegExp(`$${uniqueID}$SCRIPT_USER`, "g"), user)
247
+ .replace(new RegExp(`$${uniqueID}$FULL_SCRIPT_NAME`, "g"), `${user}.${scriptName}`)
248
+ )
249
+ )
250
+
251
+ allInfo.push(info)
252
+ onPush(info)
253
+ })
254
+ } else {
255
+ // foo.bar (global)
256
+ await forEachParallel(usersByGlobalScriptsToPush, async ([ scriptName, users ]) => {
257
+ let code
258
+ let fileName!: string
259
+ let filePath!: string
260
+
261
+ for (const extension of supportedExtensions) {
262
+ try {
263
+ fileName = `${scriptName}${extension}`
264
+ code = await readFile(filePath = resolvePath(sourceDirectory, fileName), { encoding: "utf-8" })
265
+ break
266
+ } catch {}
267
+ }
268
+
269
+ if (code) {
270
+ const uniqueID = Math.floor(Math.random() * (2 ** 52)).toString(36).padStart(11, "0")
271
+
272
+ const { srcLength, script: minifiedCode } = await processScript(
273
+ code,
274
+ {
275
+ minify,
276
+ scriptUser: true,
277
+ scriptName,
278
+ uniqueID,
279
+ filePath,
280
+ mangleNames
281
+ }
282
+ )
283
+
284
+ const info: Info = {
285
+ file: fileName,
286
+ users: [ ...users ],
287
+ minLength: countHackmudCharacters(minifiedCode),
288
+ error: null,
289
+ srcLength
290
+ }
291
+
292
+ await forEachParallel(users, user =>
293
+ writeFilePersistent(
294
+ resolvePath(
295
+ hackmudDirectory,
296
+ user,
297
+ `scripts/${scriptName}.js`
298
+ ),
299
+ minifiedCode
300
+ .replace(new RegExp(`$${uniqueID}$SCRIPT_USER`, "g"), user)
301
+ .replace(new RegExp(`$${uniqueID}$FULL_SCRIPT_NAME`, "g"), `${user}.${scriptName}`)
302
+ )
303
+ )
304
+
305
+ allInfo.push(info)
306
+ onPush(info)
307
+ }
308
+ })
309
+ }
310
+
311
+ return allInfo
312
+ }
313
+
314
+ export default push
@@ -0,0 +1,52 @@
1
+ import fs from "fs"
2
+ import { basename as getBaseName, extname as getFileExtension, resolve as resolvePath } from "path"
3
+
4
+ const { readFile, readdir: readDirectory, stat: getFileStatus, writeFile } = fs.promises
5
+
6
+ export async function syncMacros(hackmudPath: string) {
7
+ const files = await readDirectory(hackmudPath, { withFileTypes: true })
8
+ const macros = new Map<string, { macro: string, date: Date }>()
9
+ const users: string[] = []
10
+
11
+ for (const file of files) {
12
+ if (!file.isFile())
13
+ continue
14
+
15
+ switch (getFileExtension(file.name)) {
16
+ case ".macros": {
17
+ const lines = (await readFile(resolvePath(hackmudPath, file.name), { encoding: "utf-8" })).split("\n")
18
+ const date = (await getFileStatus(resolvePath(hackmudPath, file.name))).mtime
19
+
20
+ for (let i = 0; i < lines.length / 2 - 1; i++) {
21
+ const macroName = lines[i * 2]
22
+ const curMacro = macros.get(macroName)
23
+
24
+ if (!curMacro || date > curMacro.date)
25
+ macros.set(macroName, { date, macro: lines[i * 2 + 1] })
26
+ }
27
+ } break
28
+
29
+ case ".key": {
30
+ users.push(getBaseName(file.name, ".key"))
31
+ } break
32
+ }
33
+ }
34
+
35
+ let macroFile = ""
36
+ let macrosSynced = 0
37
+
38
+ for (const [ name, { macro } ] of [ ...macros ].sort(([ a ], [ b ]) => (a as any > b as any) - (a as any < b as any))) {
39
+ if (macro[0] != macro[0].toLowerCase())
40
+ continue
41
+
42
+ macroFile += `${name}\n${macro}\n`
43
+ macrosSynced++
44
+ }
45
+
46
+ for (const user of users)
47
+ writeFile(resolvePath(hackmudPath, user + ".macros"), macroFile)
48
+
49
+ return { macrosSynced, usersSynced: users.length }
50
+ }
51
+
52
+ export default syncMacros
package/src/test.ts ADDED
@@ -0,0 +1,59 @@
1
+ import fs from "fs"
2
+ import { extname as getFileExtension, resolve as resolvePath } from "path"
3
+ import { supportedExtensions } from "./constants.json"
4
+ import processScript from "./processScript"
5
+
6
+ const { readFile, readdir: readDirectory } = fs.promises
7
+
8
+ export async function test(srcPath: string) {
9
+ const promises: Promise<any>[] = []
10
+
11
+ const errors: {
12
+ file: string
13
+ message: string
14
+ line: number
15
+ }[] = []
16
+
17
+ for (const dirent of await readDirectory(srcPath, { withFileTypes: true })) {
18
+ if (dirent.isDirectory()) {
19
+ promises.push(readDirectory(resolvePath(srcPath, dirent.name), { withFileTypes: true }).then(files => {
20
+ const promises: Promise<any>[] = []
21
+
22
+ for (const file of files) {
23
+ if (!file.isFile() || !supportedExtensions.includes(getFileExtension(file.name)))
24
+ continue
25
+
26
+ promises.push(
27
+ readFile(resolvePath(srcPath, dirent.name, file.name), { encoding: "utf-8" })
28
+ .then(processScript)
29
+ .then(({ warnings }) =>
30
+ errors.push(...warnings.map(({ message, line }) => ({
31
+ file: `${dirent.name}/${file.name}`,
32
+ message, line
33
+ })))
34
+ )
35
+ )
36
+ }
37
+
38
+ return Promise.all(promises)
39
+ }))
40
+ } else if (dirent.isFile() && supportedExtensions.includes(getFileExtension(dirent.name))) {
41
+ promises.push(
42
+ readFile(resolvePath(srcPath, dirent.name), { encoding: "utf-8" })
43
+ .then(processScript)
44
+ .then(({ warnings }) =>
45
+ errors.push(...warnings.map(({ message, line }) => ({
46
+ file: dirent.name,
47
+ message, line
48
+ })))
49
+ )
50
+ )
51
+ }
52
+ }
53
+
54
+ await Promise.all(promises)
55
+
56
+ return errors
57
+ }
58
+
59
+ export default test
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2019", /* ES2019 is oldest properly supported ES version in Node 12 which is the oldest currently supported Node version */
4
+ "module": "ES2020",
5
+ "strict": true,
6
+ "esModuleInterop": true,
7
+ "skipLibCheck": true,
8
+ "forceConsistentCasingInFileNames": true,
9
+ "declaration": true,
10
+ "outDir": "../dist",
11
+ "useUnknownInCatchVariables": true,
12
+ "exactOptionalPropertyTypes": true,
13
+ "noImplicitOverride": true,
14
+ "moduleResolution": "Node",
15
+ "resolveJsonModule": true,
16
+ "emitDeclarationOnly": true
17
+ },
18
+ "exclude": [ "bin" ],
19
+ "references": [ { "path": ".." } ]
20
+ }
package/src/watch.ts ADDED
@@ -0,0 +1,156 @@
1
+ import { countHackmudCharacters, writeFilePersistent } from "@samual/lib"
2
+ import { watch as watchDirectory } from "chokidar"
3
+ import fs from "fs"
4
+ import { basename as getBaseName, extname as getFileExtension, resolve as resolvePath } from "path"
5
+ import type { Info } from "."
6
+ import { supportedExtensions } from "./constants.json"
7
+ import generateTypings from "./generateTypings"
8
+ import processScript from "./processScript"
9
+
10
+ const { readFile, readdir: readDirectory } = fs.promises
11
+
12
+ /**
13
+ * Watches target file or folder for updates and builds and pushes updated file.
14
+ *
15
+ * @param srcDir path to folder containing source files
16
+ * @param hackmudDir path to hackmud directory
17
+ * @param users users to push to (pushes to all if empty)
18
+ * @param scripts scripts to push from (pushes from all if empty)
19
+ * @param onPush function that's called after each script has been built and written
20
+ */
21
+ export function watch(srcDir: string, hackmudDir: string, users: string[], scripts: string[], onPush?: (info: Info) => void, { genTypes }: { genTypes?: string | undefined } = {}) {
22
+ const watcher = watchDirectory("", { depth: 1, cwd: srcDir, awaitWriteFinish: { stabilityThreshold: 100 } }).on("change", async path => {
23
+ const extension = getFileExtension(path)
24
+
25
+ if (supportedExtensions.includes(extension)) {
26
+ const name = getBaseName(path, extension)
27
+ const fileName = getBaseName(path)
28
+
29
+ if (path == fileName) {
30
+ if (!scripts.length || scripts.includes(name)) {
31
+ const sourceCode = await readFile(resolvePath(srcDir, path), { encoding: "utf-8" })
32
+ const skips = new Map<string, string[]>()
33
+ const promisesSkips: Promise<any>[] = []
34
+
35
+ for (const dir of await readDirectory(srcDir, { withFileTypes: true })) {
36
+ if (!dir.isDirectory())
37
+ continue
38
+
39
+ promisesSkips.push(readDirectory(resolvePath(srcDir, dir.name), { withFileTypes: true }).then(files => {
40
+ for (const file of files) {
41
+ if (!file.isFile())
42
+ continue
43
+
44
+ const fileExtension = getFileExtension(file.name)
45
+
46
+ if (!supportedExtensions.includes(fileExtension))
47
+ continue
48
+
49
+ const name = getBaseName(file.name, fileExtension)
50
+ const skip = skips.get(name)
51
+
52
+ if (skip)
53
+ skip.push(dir.name)
54
+ else
55
+ skips.set(name, [ dir.name ])
56
+ }
57
+ }))
58
+ }
59
+
60
+ await Promise.all(promisesSkips)
61
+
62
+ let error = null
63
+
64
+ const { script, srcLength } = await processScript(sourceCode).catch(reason => {
65
+ error = reason
66
+
67
+ return {
68
+ script: "",
69
+ srcLength: 0
70
+ }
71
+ })
72
+
73
+ const info: Info = {
74
+ file: path,
75
+ users: [],
76
+ minLength: 0,
77
+ error,
78
+ srcLength
79
+ }
80
+
81
+ const promises: Promise<any>[] = []
82
+
83
+ if (!error) {
84
+ if (script) {
85
+ const skip = skips.get(name) || []
86
+
87
+ info.minLength = countHackmudCharacters(script)
88
+
89
+ if (!users.length) {
90
+ users = (await readDirectory(hackmudDir, { withFileTypes: true }))
91
+ .filter(a => a.isFile() && getFileExtension(a.name) == ".key")
92
+ .map(a => getBaseName(a.name, ".key"))
93
+ }
94
+
95
+ for (const user of users) {
96
+ if (skip.includes(user))
97
+ continue
98
+
99
+ info.users.push(user)
100
+ promises.push(writeFilePersistent(resolvePath(hackmudDir, user, "scripts", `${name}.js`), script))
101
+ }
102
+ } else
103
+ info.error = new Error("processed script was empty")
104
+ }
105
+
106
+ if (onPush) {
107
+ await Promise.all(promises)
108
+ onPush(info)
109
+ }
110
+ }
111
+ } else {
112
+ const user = getBaseName(resolvePath(path, ".."))
113
+
114
+ if ((!users.length || users.includes(user)) && (!scripts.length || scripts.includes(name))) {
115
+ const sourceCode = await readFile(resolvePath(srcDir, path), { encoding: "utf-8" })
116
+ let error = null
117
+
118
+ const { script, srcLength } = await processScript(sourceCode).catch(reason => {
119
+ error = reason
120
+
121
+ return {
122
+ script: "",
123
+ srcLength: 0
124
+ }
125
+ })
126
+
127
+ const info: Info = {
128
+ file: path,
129
+ users: [ user ],
130
+ minLength: 0,
131
+ error,
132
+ srcLength
133
+ }
134
+
135
+ if (!error) {
136
+ if (script) {
137
+ info.minLength = countHackmudCharacters(script)
138
+ await writeFilePersistent(resolvePath(hackmudDir, user, "scripts", `${name}.js`), script)
139
+ } else
140
+ info.error = new Error("processed script was empty")
141
+ }
142
+
143
+ onPush?.(info)
144
+ }
145
+ }
146
+ }
147
+ })
148
+
149
+ if (genTypes) {
150
+ generateTypings(srcDir, resolvePath(srcDir, genTypes), hackmudDir)
151
+ watcher.on("add", () => generateTypings(srcDir, resolvePath(srcDir, genTypes), hackmudDir))
152
+ watcher.on("unlink", () => generateTypings(srcDir, resolvePath(srcDir, genTypes), hackmudDir))
153
+ }
154
+ }
155
+
156
+ export default watch
package/tsconfig.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "compilerOptions": {
3
+ "rootDir": ".",
4
+ "outDir": ".",
5
+ "resolveJsonModule": true,
6
+ "composite": true,
7
+ "emitDeclarationOnly": true,
8
+ "skipLibCheck": true
9
+ },
10
+ "files": [ "package.json" ],
11
+ "exclude": [ "src" ]
12
+ }
@@ -1 +0,0 @@
1
- class CustomError extends Error{constructor(...r){super(...r),function _defineProperty(r,e,s){return e in r?Object.defineProperty(r,e,{value:s,enumerable:!0,configurable:!0,writable:!0}):r[e]=s,r}(this,"name",this.constructor.name)}}class AssertError extends CustomError{}function assert(r,e="assertion failed"){if(!r)throw new AssertError(e)}function ensure(r,e="ensure failed"){return assert(r,e),r}export{assert as a,ensure as e};
package/bin/hsm.d.ts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
package/bin/hsm.js DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import o from"fs";import{resolve as e,basename as s,extname as t,dirname as r,relative as n}from"path";import{D as i,s as a,w as l,t as c,a as p,push as g}from"../push.js";import{g as b}from"../processScript/minify.js";import m from"chalk";import{homedir as u}from"os";import{processScript as f}from"../processScript/index.js";import{generateTypings as d}from"../generateTypings.js";import{syncMacros as h}from"../syncMacros.js";import{pull as k}from"../pull.js";import"chokidar";import"@babel/generator";import"@babel/parser";import"@babel/traverse";import"@babel/types";import"../assert-1b7dada8.js";import"../spliceString-2c6f214f.js";import"acorn";import"terser";import"perf_hooks";import"../processScript/compile.js";import"@babel/core";import"@babel/plugin-proposal-class-properties";import"@babel/plugin-proposal-class-static-block";import"@babel/plugin-proposal-decorators";import"@babel/plugin-proposal-do-expressions";import"@babel/plugin-proposal-function-bind";import"@babel/plugin-proposal-function-sent";import"@babel/plugin-proposal-json-strings";import"@babel/plugin-proposal-logical-assignment-operators";import"@babel/plugin-proposal-nullish-coalescing-operator";import"@babel/plugin-proposal-numeric-separator";import"@babel/plugin-proposal-object-rest-spread";import"@babel/plugin-proposal-optional-catch-binding";import"@babel/plugin-proposal-optional-chaining";import"@babel/plugin-proposal-partial-application";import"@babel/plugin-proposal-pipeline-operator";import"@babel/plugin-proposal-private-property-in-object";import"@babel/plugin-proposal-record-and-tuple";import"@babel/plugin-proposal-throw-expressions";import"@babel/plugin-transform-exponentiation-operator";import"@babel/plugin-transform-typescript";import"../processScript/postProcess.js";import"../processScript/preProcess.js";const{readFile:w,rmdir:y,writeFile:$,mkdir:j}=o.promises,v=e(u(),".config"),P=e(v,"hsm.json"),S=new Map,C=[];let x;const N=m.rgb(255,244,4),O=m.rgb(243,249,152),L=m.rgb(179,255,155),T=m.rgb(255,150,224),E=m.rgb(30,255,0),I=m.rgb(202,202,202),M=new i((o=>{let e=0;for(const s of o)e+=(e>>1)+e+"xi1_8ratvsw9hlbgm02y5zpdcn7uekof463qj".indexOf(s)+1;return[N,O,L,T,E,I][e%6](o)}));for(const o of process.argv.slice(2))if("-"==o[0]){const[e,s]=o.split("=");let t=s;if(t)if("true"==t)t=!0;else if("false"==t)t=!1;else{const o=Number(t);isFinite(o)&&(t=o)}else t=!0;if("-"==o[1])S.set(e.slice(2),t);else for(const o of e.slice(1))S.set(o,t)}else C.push(o);function help(){switch(C[0]){case"config":switch(C[1]){case"get":console.log("hsm config get <key>");break;case"set":console.log("hsm config set <key> <value>");break;case"delete":console.log("hsm config delete <key>");break;default:console.log("hsm config <get, delete, set>")}break;case"push":console.log('hsm push [<dir> [..."<script user>.<script name>"]]');break;case"watch":console.log("hsm watch [dir]");break;case"pull":console.log("hsm pull <script user>.<script name>");break;case"minify":case"golf":console.log(`${s(process.argv[1])} ${C[0]} <target> [output]`);break;default:console.log("hsm <push, watch, pull, config, golf>")}}async function version(){console.log("0.13.0-c14e977")}async function getConfig(){return x||(x=await w(P,{encoding:"utf-8"}).then((o=>{let e;try{e=JSON.parse(o)}catch{return console.log("config file was corrupted, resetting"),{}}return e&&"object"==typeof e?e:(console.log("config file was corrupted, resetting"),{})}),(()=>(console.log(`creating config file at ${P}`),{}))))}function exploreObject(o,e,s=!1){for(const r of e){var t;o=s?"object"==typeof o[r]?o[r]:o[r]={}:null===(t=o)||void 0===t?void 0:t[r]}return o}function updateConfig(){if(x){const o=JSON.stringify(x);$(P,o).catch((async e=>{switch(e.code){case"EISDIR":await y(P);break;case"ENOENT":await j(v);break;default:throw e}$(P,o)}))}}function onPushLogger({file:o,users:r,srcLength:n,minLength:i,error:a}){r.length&&(a?console.log(`error "${m.bold(a.message)}" in ${m.bold(o)}`):console.log(`pushed ${m.bold(o)} to ${r.map((o=>m.bold(M.get(o)))).join(", ")} | ${m.bold(String(i))} chars from ${m.bold(String(n))} | saved ${m.bold(String(n-i))} (${m.bold(`${Math.round(100*(1-i/n))}%`)}) | ${m.bold(`${e(x.hackmudPath,r[0],"scripts",s(o,t(o)))}.js`)}`))}(async()=>{if(S.get("version")||S.get("v"))version();else if(S.get("help")||S.get("h"))help();else{switch(C[0]){case"push":{const o=await getConfig();if(!o.hackmudPath){console.log("you need to set hackmudPath in config before you can use this command");break}const e=C[1]||".",s=o.hackmudPath,t=C.slice(2);t.length||t.push("*.*");(await g(e,s,{scripts:t,onPush:onPushLogger,minify:!S.get("skip-minify")})).length||console.warn("couldn't find any scripts to push"),updateConfig()}break;case"dev":case"watch":{var o,i,u;const e=await getConfig();if(!e.hackmudPath){console.log("you need to set hackmudPath in config before you can use this command");break}const s=C[1]||".",t=e.hackmudPath,r=(null===(o=S.get("users"))||void 0===o?void 0:o.toString().split(","))||[],n=(null===(i=S.get("scripts"))||void 0===i?void 0:i.toString().split(","))||[],a=null===(u=S.get("gen-types"))||void 0===u?void 0:u.toString();p(s,t,r,n,onPushLogger,{genTypes:a})}break;case"pull":{const o=await getConfig();if(!o.hackmudPath){console.log("you need to set hackmudPath in config before you can use this command");break}const e=C[1];if(!e){help();break}const s=C[2]||".",t=o.hackmudPath;try{await k(s,t,e)}catch(o){console.log("something went wrong, did you forget to #down the script?")}}break;case"sync-macros":{const{hackmudPath:o}=await getConfig();if(!o){console.log("you need to set hackmudPath in config before you can use this command");break}const{macrosSynced:e,usersSynced:s}=await h(o);console.log(`synced ${e} macros to ${s} users`)}break;case"test":{const o=e(C[1]||".");let s=0;console.log(`testing scripts in ${m.bold(o)}\n`);for(const{file:e,line:t,message:r}of await c(o))console.log(`error "${m.bold(r)}" in ${m.bold(e)} on line ${m.bold(String(t))}`),s++;if(!s){console.log("no errors found");break}if(s){process.exitCode=1,console.log(`\nencountered ${m.bold(String(s))} errors`);break}console.log("no errors found")}break;case"gen-types":{const o=e(C[1]||".");let s;s=C[2]?e(C[2]):e(o,"../player.d.ts"),d(o,s,(await getConfig()).hackmudPath)}break;case"config":switch(C[1]){case"get":console.log(exploreObject(await getConfig(),C[2].split(".")));break;case"delete":{var y;const o=C[2].split(".");if(!o.length){help();break}const e=await getConfig();null===(y=exploreObject(e,o))||void 0===y||delete y[C[3]],console.log(e)}break;case"set":{const o=C[2].split(".");if(!o.length){help();break}const s=await getConfig();let t=s;for(let e of o.slice(0,-1))t="object"==typeof t[e]?t[e]:t[e]={};t[o.slice(-1)[0]]=C[3],s.hackmudPath&&(s.hackmudPath=e(s.hackmudPath)),console.log(s)}break;default:C[1]&&console.log("unknown command"),help()}break;case"help":case"h":help();break;case"version":case"v":version();break;case"golf":case"minify":{if(!C[1]){console.log(`Target required\nUsage: ${s(process.argv[1])} ${C[0]} <target> [output]`);break}const o=t(C[1]);if(!a.includes(o)){console.log(`Unsupported file extension "${m.bold(o)}"\nSupported extensions are "${a.map((o=>m.bold(o))).join('", "')}"`);break}await w(C[1],{encoding:"utf-8"}).then((async t=>{const i=s(C[1],o),a=i.endsWith(".src"),c=a?i.slice(0,-4):i;let p="UNKNOWN";"scripts"==s(e(C[1],".."))&&"hackmud"==s(e(C[1],"../../.."))&&(p=s(e(C[1],"../..")));const{script:g,srcLength:u,warnings:d,timeTook:h}=await f(t,{minify:!S.get("skip-minify"),scriptUser:p,scriptName:c});for(const{message:o,line:e}of d)console.log(`warning "${m.bold(o)}" on line ${m.bold(String(e))}`);let k;k=C[2]?C[2]:e(r(C[1]),a?`${c}.js`:".js"==o?`${i}.min.js`:`${i}.js`);const w=b(g);await l(k,g).catch((async t=>{if(!C[2]||"EISDIR"!=t.code)throw t;k=e(k,`${s(C[1],o)}.js`),await l(k,g)})).then((()=>console.log(`wrote ${m.bold(w)} chars to ${m.bold(n(".",k))} | saved ${m.bold(u-w)} chars | took ${Math.round(100*h)/100}ms`)),(o=>console.log(o.message)))}),(o=>console.log(o.message)))}break;default:C[0]&&console.log("unknown command"),help()}updateConfig()}})();
@@ -1,2 +0,0 @@
1
- export declare function generateTypings(srcDir: string, target: string, hackmudPath?: string): Promise<void>;
2
- export default generateTypings;
@@ -1 +0,0 @@
1
- import{promises as t}from"fs";import{extname as e,basename as n,resolve as s}from"path";const{readdir:r,writeFile:o}=t;async function generateTypings(t,a,i){const f=new Set;if(i)for(const t of await r(i,{withFileTypes:!0}))t.isFile()&&".key"==e(t.name)&&f.add(n(t.name,".key"));const c=[],l=[],p={},m={};for(const o of await r(t,{withFileTypes:!0}))if(o.isFile())".ts"==e(o.name)?c.push(n(o.name,".ts")):".js"==e(o.name)&&l.push(n(o.name,".js"));else if(o.isDirectory()){const a=p[o.name]=[],i=m[o.name]=[];f.add(o.name);for(const f of await r(s(t,o.name),{withFileTypes:!0}))f.isFile()&&(".ts"==e(f.name)?a.push(n(f.name,".ts")):".js"==e(f.name)&&i.push(n(f.name,".js")))}let y="";for(const t of c)y+=`import { script as $${t}$ } from "./src/${t}"\n`;y+="\n";for(const t in p){const e=p[t];for(const n of e)y+=`import { script as $${t}$${n}$ } from "./src/${t}/${n}"\n`}y+="\ntype ArrayRemoveFirst<A> = A extends [ infer FirstItem, ...infer Rest ] ? Rest : never\n\ntype Subscript<T extends (...args: any) => any> =\n\t(...args: ArrayRemoveFirst<Parameters<T>>) => ReturnType<T> | ScriptFailure\n\ntype WildFullsec = Record<string, () => ScriptFailure> & {\n";for(const t of c)y+=`\t${t}: Subscript<typeof $${t}$>\n`;for(const t of l)y+=`\t${t}: (...args: any) => any\n`;y+="}\n\ndeclare global {\n\tinterface PlayerFullsec {";let $=!0;for(const t of f){const e=p[t],n=m[t];if(e&&e.length||n&&n.length){$=!0,y+=`\n\t\t${t}: WildFullsec & {\n`;for(const n of e)y+=`\t\t\t${n}: Subscript<typeof $${t}$${n}$>\n`;for(const t of n)y+=`\t\t\t${t}: (...args: any) => any\n`;y+="\t\t}"}else $&&(y+="\n",$=!1),y+=`\t\t${t}: WildFullsec`;y+="\n"}y+="\t}\n}\n",await o(a,y)}export{generateTypings as default,generateTypings};
package/index.d.ts DELETED
@@ -1,15 +0,0 @@
1
- export interface Info {
2
- file: string;
3
- users: string[];
4
- srcLength: number;
5
- minLength: number;
6
- error: Error | null;
7
- }
8
- export declare const supportedExtensions: string[];
9
- export { generateTypings } from "./generateTypings";
10
- export { processScript } from "./processScript";
11
- export { pull } from "./pull";
12
- export { push } from "./push";
13
- export { syncMacros } from "./syncMacros";
14
- export { test } from "./test";
15
- export { watch } from "./watch";