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

Sign up to get free protection for your applications and to get access to all the features.
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";