hackmud-script-manager 0.20.0-b71a8be → 0.20.1-503b02c

Sign up to get free protection for your applications and to get access to all the features.
package/pull.d.ts CHANGED
@@ -1,9 +1,5 @@
1
- /**
2
- * Copies script from hackmud to local source folder.
3
- *
4
- * @param sourceFolderPath path to folder containing source files
5
- * @param hackmudPath path to hackmud directory
6
- * @param script to pull in `user.name` format
7
- */
8
- export declare const pull: (sourceFolderPath: string, hackmudPath: string, script: string) => Promise<void>;
9
- export default pull;
1
+ /** Copies script from hackmud to local source folder.
2
+ * @param sourceFolderPath path to folder containing source files
3
+ * @param hackmudPath path to hackmud directory
4
+ * @param script to pull in `user.name` format */
5
+ export declare function pull(sourceFolderPath: string, hackmudPath: string, script: string): Promise<void>;
package/pull.js CHANGED
@@ -1 +1,11 @@
1
- import{copyFilePersistent as t}from"@samual/lib/copyFilePersistent";import{resolve as r}from"path";const pull=async(s,a,i)=>{const[o,e]=i.split(".");if(!o||!e)throw new Error('`script` argument must be in "user.name" format');await t(r(a,o,"scripts",`${e}.js`),r(s,o,`${e}.js`))};export{pull as default,pull};
1
+ import { copyFilePersistent } from "@samual/lib/copyFilePersistent"
2
+ import { resolve } from "path"
3
+ async function pull(sourceFolderPath, hackmudPath, script) {
4
+ const [user, name] = script.split(".")
5
+ if (!user || !name) throw Error('`script` argument must be in "user.name" format')
6
+ await copyFilePersistent(
7
+ resolve(hackmudPath, user, "scripts", name + ".js"),
8
+ resolve(sourceFolderPath, user, name + ".js")
9
+ )
10
+ }
11
+ export { pull }
package/push.d.ts CHANGED
@@ -1,37 +1,28 @@
1
1
  import type { LaxPartial } from "@samual/lib";
2
2
  import type { Info } from ".";
3
- export type PushOptions = {
4
- /** whether to do the minify step (defaults to `true`) */
5
- minify: boolean;
6
- /** whether to mangle function and class names (defaults to `false`) */
7
- mangleNames: boolean;
8
- /**
9
- * array of scripts in the format `foo.bar`
10
- *
11
- * also accepts wild card (`*`) e.g. `*.bar` or `foo.*`
12
- *
13
- * pushes everything by default (`*.*`)
14
- */
3
+ export type PushOptions = LaxPartial<{
4
+ /** whether to do the minify step (defaults to `true`) */ minify: boolean;
5
+ /** whether to mangle function and class names (defaults to `false`) */ mangleNames: boolean;
6
+ /** array of scripts in the format `foo.bar`
7
+ *
8
+ * also accepts wild card (`*`) e.g. `*.bar` or `foo.*`
9
+ *
10
+ * pushes everything by default (`*.*`) */
15
11
  scripts: string[];
16
- /** callback called on script push */
17
- onPush: (info: Info) => void;
18
- /**
19
- * when set to `true` forces use of quine cheats
20
- *
21
- * when set to `false` forces quine cheats not to be used
22
- *
23
- * when left unset or set to `undefined`, automatically uses or doesn't use quine cheats based on character count
24
- */
12
+ /** callback called on script push */ onPush: (info: Info) => void;
13
+ /** when set to `true` forces use of quine cheats
14
+ *
15
+ * when set to `false` forces quine cheats not to be used
16
+ *
17
+ * when left unset or set to `undefined`, automatically uses or doesn't use quine cheats based on character count
18
+ */
25
19
  forceQuineCheats: boolean;
26
- };
27
- /**
28
- * Push scripts from a source directory to the hackmud directory.
29
- *
30
- * Pushes files directly in the source folder to all users
31
- * @param sourceDirectory directory containing source code
32
- * @param hackmudDirectory directory created by hackmud containing user data including scripts
33
- * @param options {@link PushOptions details}
34
- * @returns array of info on pushed scripts
35
- */
36
- export declare const push: (sourceDirectory: string, hackmudDirectory: string, { scripts, onPush, minify, mangleNames, forceQuineCheats }?: LaxPartial<PushOptions>) => Promise<Info[]>;
37
- export default push;
20
+ }>;
21
+ /** Push scripts from a source directory to the hackmud directory.
22
+ *
23
+ * Pushes files directly in the source folder to all users
24
+ * @param sourcePath directory containing source code
25
+ * @param hackmudPath directory created by hackmud containing user data including scripts
26
+ * @param options {@link PushOptions details}
27
+ * @returns array of info on pushed scripts */
28
+ export declare function push(sourcePath: string, hackmudPath: string, { scripts, onPush, minify, mangleNames, forceQuineCheats }?: PushOptions): Promise<Info[]>;
package/push.js CHANGED
@@ -1 +1,138 @@
1
- import{DynamicMap as e}from"@samual/lib/DynamicMap";import{countHackmudCharacters as t}from"@samual/lib/countHackmudCharacters";import{writeFilePersistent as r}from"@samual/lib/writeFilePersistent";import{readdir as i,readFile as a}from"fs/promises";import{resolve as s,extname as o,basename as n}from"path";import{supportedExtensions as p}from"./constants.js";import{processScript as m}from"./processScript/index.js";import"@babel/generator";import"@babel/parser";import"@babel/plugin-proposal-decorators";import"@babel/plugin-proposal-destructuring-private";import"@babel/plugin-proposal-explicit-resource-management";import"@babel/plugin-transform-class-properties";import"@babel/plugin-transform-class-static-block";import"@babel/plugin-transform-exponentiation-operator";import"@babel/plugin-transform-json-strings";import"@babel/plugin-transform-logical-assignment-operators";import"@babel/plugin-transform-nullish-coalescing-operator";import"@babel/plugin-transform-numeric-separator";import"@babel/plugin-transform-object-rest-spread";import"@babel/plugin-transform-optional-catch-binding";import"@babel/plugin-transform-optional-chaining";import"@babel/plugin-transform-private-property-in-object";import"@babel/plugin-transform-unicode-sets-regex";import"@babel/traverse";import"@babel/types";import"@rollup/plugin-babel";import"@rollup/plugin-commonjs";import"@rollup/plugin-json";import"@rollup/plugin-node-resolve";import"@samual/lib/assert";import"prettier";import"rollup";import"./processScript/minify.js";import"@samual/lib/spliceString";import"acorn";import"terser";import"./processScript/shared.js";import"./processScript/postprocess.js";import"./processScript/preprocess.js";import"import-meta-resolve";import"./processScript/transform.js";import"@samual/lib/clearObject";const push=async(l,c,{scripts:f=["*.*"],onPush:u=(()=>{}),minify:g=!0,mangleNames:b=!1,forceQuineCheats:d}={})=>{const h=new e((e=>new Set)),w=new Set,$=new Set;let y=!1;for(const e of f){const[t,r]=e.split(".");t&&"*"!=t?r&&"*"!=r?h.get(t).add(r):w.add(t):r&&"*"!=r?$.add(r):y=!0}const S=new e((e=>new Set)),P=[],j=new e((e=>new Set));let N;if($.size||y){const e=await i(s(c),{withFileTypes:!0}),t=new Set([...(N=await i(s(l),{withFileTypes:!0})).filter((e=>e.isDirectory())).map((e=>e.name)),...e.filter((e=>e.isDirectory())).map((e=>e.name)),...e.filter((e=>e.isFile()&&e.name.endsWith(".key"))).map((e=>e.name.slice(0,-4))),...h.keys(),...w]);if(y)for(const e of t)w.add(e);else for(const e of t){const t=h.get(e);for(const e of $)t.add(e)}}return await Promise.all([...w].map((async e=>{await i(s(l,e),{withFileTypes:!0}).then((async i=>{await Promise.all(i.map((async i=>{if(i.name.endsWith(".d.ts"))return;const f=o(i.name);if(i.isFile()&&p.includes(f)){const o=n(i.name,f),p=s(l,e,i.name),{script:h}=await m(await a(p,{encoding:"utf-8"}),{minify:g,scriptUser:e,scriptName:o,filePath:p,mangleNames:b,forceQuineCheats:d}),w={file:`${e}/${i.name}`,users:[e],minLength:t(h),error:void 0};j.get(e).add(o),P.push(w),await r(s(c,e,`scripts/${o}.js`),h),u(w)}})))}),(e=>{if("ENOENT"!=e.code)throw e}))}))),await Promise.all([...h].map((async([e,i])=>{w.has(e)||await Promise.all([...i].map((async i=>{let o,n,f;for(const t of p)try{n=`${i}${t}`,o=await a(f=s(l,e,n),{encoding:"utf-8"});break}catch{}if(o){const{script:a}=await m(o,{minify:g,scriptUser:e,scriptName:i,filePath:f,mangleNames:b,forceQuineCheats:d}),p={file:`${e}/${n}`,users:[e],minLength:t(a),error:void 0};P.push(p),await r(s(c,e,"scripts",`${i}.js`),a),u(p)}else S.get(i).add(e)})))}))),await(w.size?Promise.all((N||await i(s(l),{withFileTypes:!0})).map((async e=>{if(e.name.endsWith(".d.ts"))return;const i=o(e.name);if(!e.isFile()||!p.includes(i))return;const f=n(e.name,i),h=[...w,...S.get(f)].filter((e=>!j.get(e).has(f)));if(!h.length)return;const $=Math.floor(Math.random()*2**52).toString(36).padStart(11,"0"),y=s(l,e.name),{script:N}=await m(await a(y,{encoding:"utf-8"}),{minify:g,scriptUser:!0,scriptName:f,uniqueID:$,filePath:y,mangleNames:b,forceQuineCheats:d}),C={file:e.name,users:h,minLength:t(N),error:void 0};await Promise.all(h.map((e=>r(s(c,e,`scripts/${f}.js`),N.replace(new RegExp(`\\$${$}\\$SCRIPT_USER\\$`,"g"),e).replace(new RegExp(`\\$${$}\\$FULL_SCRIPT_NAME\\$`,"g"),`${e}.${f}`))))),P.push(C),u(C)}))):Promise.all([...S].map((async([e,i])=>{let o,n,f;for(const t of p)try{n=`${e}${t}`,o=await a(f=s(l,n),{encoding:"utf-8"});break}catch{}if(o){const a=Math.floor(Math.random()*2**52).toString(36).padStart(11,"0"),{script:p}=await m(o,{minify:g,scriptUser:!0,scriptName:e,uniqueID:a,filePath:f,mangleNames:b,forceQuineCheats:d}),l={file:n,users:[...i],minLength:t(p),error:void 0};await Promise.all([...i].map((t=>r(s(c,t,`scripts/${e}.js`),p.replace(new RegExp(`\\$${a}\\$SCRIPT_USER\\$`,"g"),t).replace(new RegExp(`\\$${a}\\$FULL_SCRIPT_NAME\\$`,"g"),`${t}.${e}`))))),P.push(l),u(l)}})))),P};export{push as default,push};
1
+ import { Cache } from "@samual/lib/Cache"
2
+ import { ensure, assert } from "@samual/lib/assert"
3
+ import { countHackmudCharacters } from "@samual/lib/countHackmudCharacters"
4
+ import { readDirectoryWithStats } from "@samual/lib/readDirectoryWithStats"
5
+ import { writeFilePersistent } from "@samual/lib/writeFilePersistent"
6
+ import { readFile } from "fs/promises"
7
+ import { basename, resolve } from "path"
8
+ import { processScript } from "./processScript/index.js"
9
+ import "@babel/generator"
10
+ import "@babel/parser"
11
+ import "@babel/plugin-proposal-decorators"
12
+ import "@babel/plugin-proposal-destructuring-private"
13
+ import "@babel/plugin-proposal-explicit-resource-management"
14
+ import "@babel/plugin-transform-class-properties"
15
+ import "@babel/plugin-transform-class-static-block"
16
+ import "@babel/plugin-transform-exponentiation-operator"
17
+ import "@babel/plugin-transform-json-strings"
18
+ import "@babel/plugin-transform-logical-assignment-operators"
19
+ import "@babel/plugin-transform-nullish-coalescing-operator"
20
+ import "@babel/plugin-transform-numeric-separator"
21
+ import "@babel/plugin-transform-object-rest-spread"
22
+ import "@babel/plugin-transform-optional-catch-binding"
23
+ import "@babel/plugin-transform-optional-chaining"
24
+ import "@babel/plugin-transform-private-property-in-object"
25
+ import "@babel/plugin-transform-unicode-sets-regex"
26
+ import "@babel/traverse"
27
+ import "@babel/types"
28
+ import "@rollup/plugin-babel"
29
+ import "@rollup/plugin-commonjs"
30
+ import "@rollup/plugin-json"
31
+ import "@rollup/plugin-node-resolve"
32
+ import "prettier"
33
+ import "rollup"
34
+ import "./constants.js"
35
+ import "./processScript/minify.js"
36
+ import "@samual/lib/spliceString"
37
+ import "acorn"
38
+ import "terser"
39
+ import "./processScript/shared.js"
40
+ import "./processScript/postprocess.js"
41
+ import "./processScript/preprocess.js"
42
+ import "import-meta-resolve"
43
+ import "./processScript/transform.js"
44
+ import "@samual/lib/clearObject"
45
+ async function push(
46
+ sourcePath,
47
+ hackmudPath,
48
+ { scripts = ["*.*"], onPush = () => {}, minify = !0, mangleNames = !1, forceQuineCheats } = {}
49
+ ) {
50
+ const [sourceFolder, hackmudFolder] = await Promise.all([
51
+ readDirectoryWithStats(sourcePath),
52
+ readDirectoryWithStats(hackmudPath)
53
+ ]),
54
+ sourceFolderFolders = sourceFolder.filter(({ stats }) => stats.isDirectory()),
55
+ allUsers = new Set([
56
+ ...scripts
57
+ .map(scriptName => ensure(scriptName.split(".")[0], "src/push.ts:52:65"))
58
+ .filter(name => "*" != name),
59
+ ...sourceFolderFolders.map(({ name }) => name),
60
+ ...hackmudFolder.filter(({ stats }) => stats.isDirectory()).map(({ name }) => name),
61
+ ...hackmudFolder
62
+ .filter(({ stats, name }) => stats.isFile() && name.endsWith(".key"))
63
+ .map(({ name }) => name.slice(0, -4))
64
+ ]),
65
+ usersToScriptsToPush = new Cache(_user => new Map()),
66
+ scriptNamesToUsers = new Cache(_scriptName => new Set())
67
+ for (const script of scripts) {
68
+ const [user, scriptName] = script.split(".")
69
+ assert(user, "src/push.ts:69:16")
70
+ assert(scriptName, "src/push.ts:70:22")
71
+ "*" == user ? scriptNamesToUsers.set(scriptName, allUsers) : scriptNamesToUsers.get(scriptName).add(user)
72
+ }
73
+ const sourceFolderFiles = sourceFolder.filter(({ stats }) => stats.isFile()),
74
+ wildScriptUsers_ = scriptNamesToUsers.get("*")
75
+ scriptNamesToUsers.delete("*")
76
+ for (const { name, path } of [
77
+ ...sourceFolderFiles.filter(({ name }) => name.endsWith(".js")),
78
+ ...sourceFolderFiles.filter(({ name }) => name.endsWith(".ts"))
79
+ ]) {
80
+ const scriptName = name.slice(0, -3)
81
+ for (const user of [...wildScriptUsers_, ...scriptNamesToUsers.get(scriptName)])
82
+ usersToScriptsToPush.get(user).set(scriptName, path)
83
+ }
84
+ await Promise.all(
85
+ sourceFolderFolders.map(async ({ name: user, path }) => {
86
+ const files = (await readDirectoryWithStats(path)).filter(({ stats }) => stats.isFile()),
87
+ scriptFiles = [
88
+ ...files.filter(({ name }) => name.endsWith(".js")),
89
+ ...files.filter(({ name }) => name.endsWith(".ts"))
90
+ ]
91
+ for (const { name, path } of scriptFiles) {
92
+ const scriptName = name.slice(0, -3)
93
+ ;[...wildScriptUsers_, ...scriptNamesToUsers.get(scriptName)].includes(user) &&
94
+ usersToScriptsToPush.get(user).set(scriptName, path)
95
+ }
96
+ })
97
+ )
98
+ for (const [scriptName, users] of scriptNamesToUsers)
99
+ for (const user of users)
100
+ if (!usersToScriptsToPush.get(user).has(scriptName))
101
+ throw Error(`Could not find script ${user}.${scriptName} to push`)
102
+ const pathsToUsers = new Cache(_path => new Set())
103
+ for (const [user, scriptsToPush] of usersToScriptsToPush)
104
+ for (const path of scriptsToPush.values()) pathsToUsers.get(path).add(user)
105
+ const allInfo = []
106
+ await Promise.all(
107
+ [...pathsToUsers].map(async ([path, [...users]]) => {
108
+ const scriptName = basename(path.slice(0, -3)),
109
+ uniqueId = Math.floor(Math.random() * 2 ** 52)
110
+ .toString(36)
111
+ .padStart(11, "0"),
112
+ { script: minifiedCode } = await processScript(await readFile(path, { encoding: "utf8" }), {
113
+ minify,
114
+ scriptUser: !0,
115
+ scriptName,
116
+ uniqueId,
117
+ filePath: path,
118
+ mangleNames,
119
+ forceQuineCheats
120
+ }),
121
+ info = { path, users, characterCount: countHackmudCharacters(minifiedCode), error: void 0 }
122
+ await Promise.all(
123
+ users.map(user =>
124
+ writeFilePersistent(
125
+ resolve(hackmudPath, user, `scripts/${scriptName}.js`),
126
+ minifiedCode
127
+ .replace(RegExp(`\\$${uniqueId}\\$SCRIPT_USER\\$`, "g"), user)
128
+ .replace(RegExp(`\\$${uniqueId}\\$FULL_SCRIPT_NAME\\$`, "g"), `${user}.${scriptName}`)
129
+ )
130
+ )
131
+ )
132
+ allInfo.push(info)
133
+ onPush(info)
134
+ })
135
+ )
136
+ return allInfo
137
+ }
138
+ export { push }
package/syncMacros.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- export declare const syncMacros: (hackmudPath: string) => Promise<{
1
+ export declare function syncMacros(hackmudPath: string): Promise<{
2
2
  macrosSynced: number;
3
3
  usersSynced: number;
4
4
  }>;
5
- export default syncMacros;
package/syncMacros.js CHANGED
@@ -1 +1,43 @@
1
- import{readdir as e,readFile as t,stat as a,writeFile as s}from"fs/promises";import{extname as o,basename as n,resolve as r}from"path";const syncMacros=async c=>{const m=await e(c,{withFileTypes:!0}),i=new Map,l=[];await Promise.all(m.map((async e=>{if(e.isFile())switch(o(e.name)){case".macros":{const[s,o]=await Promise.all([t(r(c,e.name),{encoding:"utf-8"}).then((e=>e.split("\n"))),a(r(c,e.name)).then((({mtime:e})=>e))]);for(let e=0;e<s.length/2-1;e++){const t=s[2*e],a=i.get(t);(!a||o>a.date)&&i.set(t,{date:o,macro:s[2*e+1]})}}break;case".key":l.push(n(e.name,".key"))}})));let f="",p=0;for(const[e,{macro:t}]of[...i].sort((([e],[t])=>(e>t)-(e<t))))t[0]==t[0].toLowerCase()&&(f+=`${e}\n${t}\n`,p++);for(const e of l)s(r(c,`${e}.macros`),f);return{macrosSynced:p,usersSynced:l.length}};export{syncMacros as default,syncMacros};
1
+ import { readDirectoryWithStats } from "@samual/lib/readDirectoryWithStats"
2
+ import { readFile, stat, writeFile } from "fs/promises"
3
+ import { extname, basename, resolve } from "path"
4
+ async function syncMacros(hackmudPath) {
5
+ const files = await readDirectoryWithStats(hackmudPath),
6
+ macros = new Map(),
7
+ users = []
8
+ await Promise.all(
9
+ files.map(async file => {
10
+ if (file.stats.isFile())
11
+ switch (extname(file.name)) {
12
+ case ".macros":
13
+ {
14
+ const [lines, date] = await Promise.all([
15
+ readFile(resolve(hackmudPath, file.name), { encoding: "utf8" }).then(file =>
16
+ file.split("\n")
17
+ ),
18
+ stat(resolve(hackmudPath, file.name)).then(({ mtime }) => mtime)
19
+ ])
20
+ for (let index = 0; index < lines.length / 2 - 1; index++) {
21
+ const macroName = lines[2 * index],
22
+ currentMacro = macros.get(macroName)
23
+ ;(!currentMacro || date > currentMacro.date) &&
24
+ macros.set(macroName, { date, macro: lines[2 * index + 1] })
25
+ }
26
+ }
27
+ break
28
+ case ".key":
29
+ users.push(basename(file.name, ".key"))
30
+ }
31
+ })
32
+ )
33
+ let macroFile = "",
34
+ macrosSynced = 0
35
+ for (const [name, { macro }] of [...macros].sort(([a], [b]) => (a > b) - (a < b)))
36
+ if (macro[0] == macro[0].toLowerCase()) {
37
+ macroFile += `${name}\n${macro}\n`
38
+ macrosSynced++
39
+ }
40
+ for (const user of users) writeFile(resolve(hackmudPath, user + ".macros"), macroFile)
41
+ return { macrosSynced, usersSynced: users.length }
42
+ }
43
+ export { syncMacros }
package/watch.d.ts CHANGED
@@ -1,20 +1,14 @@
1
1
  import type { LaxPartial } from "@samual/lib";
2
2
  import type { PushOptions } from "./push";
3
- export type WatchOptions = PushOptions & {
4
- /**
5
- * if provided, will write typescript type declarations for all the scripts on every change detected
6
- *
7
- * writing the type declarations enables interscript type checking and autocompletetes for the args
8
- */
3
+ export type WatchOptions = PushOptions & LaxPartial<{
4
+ /** if provided, will write typescript type declarations for all the scripts on every change detected
5
+ *
6
+ * writing the type declarations enables interscript type checking and autocompletetes for the args */
9
7
  typeDeclarationPath: string;
10
8
  onReady: () => void;
11
- };
12
- /**
13
- * Watches target file or folder for updates and builds and pushes updated file.
14
- *
15
- * @param sourceDirectory path to folder containing source files
16
- * @param hackmudDirectory path to hackmud directory
17
- * @param options {@link WatchOptions details} and {@link PushOptions more details}
18
- */
19
- export declare const watch: (sourceDirectory: string, hackmudDirectory: string, { scripts, onPush, minify, mangleNames, typeDeclarationPath: typeDeclarationPath_, onReady, forceQuineCheats }?: LaxPartial<WatchOptions>) => Promise<void>;
20
- export default watch;
9
+ }>;
10
+ /** Watches target file or folder for updates and builds and pushes updated file.
11
+ * @param sourceDirectory path to folder containing source files
12
+ * @param hackmudDirectory path to hackmud directory
13
+ * @param options {@link WatchOptions details} and {@link PushOptions more details} */
14
+ export declare function watch(sourceDirectory: string, hackmudDirectory: string, { scripts, onPush, minify, mangleNames, typeDeclarationPath: typeDeclarationPath_, onReady, forceQuineCheats }?: WatchOptions): Promise<void>;
package/watch.js CHANGED
@@ -1 +1,208 @@
1
- import{DynamicMap as r}from"@samual/lib/DynamicMap";import{assert as t}from"@samual/lib/assert";import{countHackmudCharacters as e}from"@samual/lib/countHackmudCharacters";import{writeFilePersistent as i}from"@samual/lib/writeFilePersistent";import{watch as o}from"chokidar";import{readdir as a,readFile as s,writeFile as n}from"fs/promises";import{extname as p,basename as l,resolve as m}from"path";import{supportedExtensions as c}from"./constants.js";import{generateTypeDeclaration as f}from"./generateTypeDeclaration.js";import{processScript as u}from"./processScript/index.js";import"@babel/generator";import"@babel/parser";import"@babel/plugin-proposal-decorators";import"@babel/plugin-proposal-destructuring-private";import"@babel/plugin-proposal-explicit-resource-management";import"@babel/plugin-transform-class-properties";import"@babel/plugin-transform-class-static-block";import"@babel/plugin-transform-exponentiation-operator";import"@babel/plugin-transform-json-strings";import"@babel/plugin-transform-logical-assignment-operators";import"@babel/plugin-transform-nullish-coalescing-operator";import"@babel/plugin-transform-numeric-separator";import"@babel/plugin-transform-object-rest-spread";import"@babel/plugin-transform-optional-catch-binding";import"@babel/plugin-transform-optional-chaining";import"@babel/plugin-transform-private-property-in-object";import"@babel/plugin-transform-unicode-sets-regex";import"@babel/traverse";import"@babel/types";import"@rollup/plugin-babel";import"@rollup/plugin-commonjs";import"@rollup/plugin-json";import"@rollup/plugin-node-resolve";import"prettier";import"rollup";import"./processScript/minify.js";import"@samual/lib/spliceString";import"acorn";import"terser";import"./processScript/shared.js";import"./processScript/postprocess.js";import"./processScript/preprocess.js";import"import-meta-resolve";import"./processScript/transform.js";import"@samual/lib/clearObject";const watch=async(d,g,{scripts:b=["*.*"],onPush:h,minify:w=!0,mangleNames:y=!1,typeDeclarationPath:j,onReady:S,forceQuineCheats:v}={})=>{if(!b.length)throw new Error("scripts option was an empty array");const $=new r((r=>new Set)),E=new Set,F=new Set;let P=!1;for(const r of b){const[t,e]=r.split(".");t&&"*"!=t?e&&"*"!=e?$.get(e).add(t):E.add(t):e&&"*"!=e?F.add(e):P=!0}const D=o(["*/*.ts","*/*.js"],{cwd:d,awaitWriteFinish:{stabilityThreshold:100},ignored:"*.d.ts"}).on("change",(async o=>{if(o.endsWith(".d.ts"))return;const n=p(o);if(!c.includes(n))return;const f=l(o,n);if(o==l(o)){if(!(P||E.size||F.has(f)||$.has(f)))return;const n=new r((r=>[]));await Promise.all((await a(d,{withFileTypes:!0})).map((async r=>{if(r.isDirectory())for(const t of await a(m(d,r.name),{withFileTypes:!0})){if(!t.isFile())continue;const e=p(t.name);c.includes(e)&&n.get(l(t.name,e)).push(r.name)}})));const b=new Set;if(P||F.has(f)){for(const r of await a(m(d),{withFileTypes:!0}))r.isDirectory()&&b.add(r.name);for(const r of await a(m(g),{withFileTypes:!0}))r.isDirectory()?b.add(r.name):r.isFile()&&r.name.endsWith(".key")&&b.add(r.name.slice(0,-4));for(const r of $.values())for(const t of r)b.add(t)}for(const r of E)b.add(r);for(const r of $.get(f))b.add(r);const j=[...b].filter((r=>!n.has(r)));if(!j.length)return void h?.({file:o,users:[],minLength:0,error:new Error("no users to push to")});const S=Math.floor(Math.random()*2**52).toString(36).padStart(11,"0"),D=m(d,o);let T;try{({script:T}=await u(await s(D,{encoding:"utf-8"}),{minify:w,scriptUser:!0,scriptName:f,uniqueID:S,filePath:D,mangleNames:y,forceQuineCheats:v}))}catch(r){return t(r instanceof Error),void h?.({file:o,users:[],minLength:0,error:r})}return await Promise.all(j.map((r=>i(m(g,r,`scripts/${f}.js`),T.replace(new RegExp(`\\$${S}\\$SCRIPT_USER\\$`,"g"),r).replace(new RegExp(`\\$${S}\\$FULL_SCRIPT_NAME\\$`,"g"),`${r}.${f}`))))),void h?.({file:o,users:j,minLength:e(T),error:void 0})}const b=l(m(o,".."));if(!(P||E.size||F.has(f)||$.get(f).has(b)))return;const j=m(d,o),S=await s(j,{encoding:"utf-8"});let D;try{({script:D}=await u(S,{minify:w,scriptUser:b,scriptName:f,filePath:j,mangleNames:y,forceQuineCheats:v}))}catch(r){return t(r instanceof Error),void h?.({file:o,users:[],minLength:0,error:r})}await i(m(g,b,"scripts",`${f}.js`),D),h?.({file:o,users:[b],minLength:e(D),error:void 0})}));if(S&&D.on("ready",S),!j)return;let T=j;const writeTypeDeclaration=async()=>{const r=await f(d,g);try{await n(T,r)}catch(e){if(t(e instanceof Error),"EISDIR"!=e.code)throw e;T=m(T,"player.d.ts"),await n(T,r)}};await writeTypeDeclaration(),D.on("add",writeTypeDeclaration),D.on("unlink",writeTypeDeclaration)};export{watch as default,watch};
1
+ import { Cache } from "@samual/lib/Cache"
2
+ import { assert } from "@samual/lib/assert"
3
+ import { countHackmudCharacters } from "@samual/lib/countHackmudCharacters"
4
+ import { readDirectoryWithStats } from "@samual/lib/readDirectoryWithStats"
5
+ import { writeFilePersistent } from "@samual/lib/writeFilePersistent"
6
+ import { watch as watch$1 } from "chokidar"
7
+ import { readFile, writeFile } from "fs/promises"
8
+ import { extname, basename, resolve } from "path"
9
+ import { supportedExtensions } from "./constants.js"
10
+ import { generateTypeDeclaration } from "./generateTypeDeclaration.js"
11
+ import { processScript } from "./processScript/index.js"
12
+ import "@babel/generator"
13
+ import "@babel/parser"
14
+ import "@babel/plugin-proposal-decorators"
15
+ import "@babel/plugin-proposal-destructuring-private"
16
+ import "@babel/plugin-proposal-explicit-resource-management"
17
+ import "@babel/plugin-transform-class-properties"
18
+ import "@babel/plugin-transform-class-static-block"
19
+ import "@babel/plugin-transform-exponentiation-operator"
20
+ import "@babel/plugin-transform-json-strings"
21
+ import "@babel/plugin-transform-logical-assignment-operators"
22
+ import "@babel/plugin-transform-nullish-coalescing-operator"
23
+ import "@babel/plugin-transform-numeric-separator"
24
+ import "@babel/plugin-transform-object-rest-spread"
25
+ import "@babel/plugin-transform-optional-catch-binding"
26
+ import "@babel/plugin-transform-optional-chaining"
27
+ import "@babel/plugin-transform-private-property-in-object"
28
+ import "@babel/plugin-transform-unicode-sets-regex"
29
+ import "@babel/traverse"
30
+ import "@babel/types"
31
+ import "@rollup/plugin-babel"
32
+ import "@rollup/plugin-commonjs"
33
+ import "@rollup/plugin-json"
34
+ import "@rollup/plugin-node-resolve"
35
+ import "prettier"
36
+ import "rollup"
37
+ import "./processScript/minify.js"
38
+ import "@samual/lib/spliceString"
39
+ import "acorn"
40
+ import "terser"
41
+ import "./processScript/shared.js"
42
+ import "./processScript/postprocess.js"
43
+ import "./processScript/preprocess.js"
44
+ import "import-meta-resolve"
45
+ import "./processScript/transform.js"
46
+ import "@samual/lib/clearObject"
47
+ async function watch(
48
+ sourceDirectory,
49
+ hackmudDirectory,
50
+ {
51
+ scripts = ["*.*"],
52
+ onPush,
53
+ minify = !0,
54
+ mangleNames = !1,
55
+ typeDeclarationPath: typeDeclarationPath_,
56
+ onReady,
57
+ forceQuineCheats
58
+ } = {}
59
+ ) {
60
+ if (!scripts.length) throw Error("scripts option was an empty array")
61
+ const scriptNamesToUsers = new Cache(_scriptName => new Set()),
62
+ wildScriptUsers = new Set(),
63
+ wildUserScripts = new Set()
64
+ let pushEverything = !1
65
+ for (const fullScriptName of scripts) {
66
+ const [user, scriptName] = fullScriptName.split(".")
67
+ user && "*" != user ?
68
+ scriptName && "*" != scriptName ?
69
+ scriptNamesToUsers.get(scriptName).add(user)
70
+ : wildScriptUsers.add(user)
71
+ : scriptName && "*" != scriptName ? wildUserScripts.add(scriptName)
72
+ : (pushEverything = !0)
73
+ }
74
+ const watcher = watch$1(["*.ts", "*.js", "*/*.ts", "*/*.js"], {
75
+ cwd: sourceDirectory,
76
+ awaitWriteFinish: { stabilityThreshold: 100 },
77
+ ignored: "*.d.ts"
78
+ }).on("change", async path => {
79
+ if (path.endsWith(".d.ts")) return
80
+ const extension = extname(path)
81
+ if (!supportedExtensions.includes(extension)) return
82
+ const scriptName = basename(path, extension)
83
+ if (path == basename(path)) {
84
+ if (
85
+ !(
86
+ pushEverything ||
87
+ wildScriptUsers.size ||
88
+ wildUserScripts.has(scriptName) ||
89
+ scriptNamesToUsers.has(scriptName)
90
+ )
91
+ )
92
+ return
93
+ const scriptNamesToUsersToSkip = new Cache(_scriptName => [])
94
+ await Promise.all(
95
+ (await readDirectoryWithStats(sourceDirectory)).map(async ({ stats, name, path }) => {
96
+ if (stats.isDirectory())
97
+ for (const child of await readDirectoryWithStats(path))
98
+ if (child.stats.isFile()) {
99
+ const fileExtension = extname(child.name)
100
+ supportedExtensions.includes(fileExtension) &&
101
+ scriptNamesToUsersToSkip.get(basename(child.name, fileExtension)).push(name)
102
+ }
103
+ })
104
+ )
105
+ const usersToPushToSet = new Set()
106
+ if (pushEverything || wildUserScripts.has(scriptName)) {
107
+ for (const { stats, name } of await readDirectoryWithStats(sourceDirectory))
108
+ stats.isDirectory() && usersToPushToSet.add(name)
109
+ for (const { stats, name } of await readDirectoryWithStats(hackmudDirectory))
110
+ stats.isDirectory() ?
111
+ usersToPushToSet.add(name)
112
+ : stats.isFile() && name.endsWith(".key") && usersToPushToSet.add(name.slice(0, -4))
113
+ for (const users of scriptNamesToUsers.values()) for (const user of users) usersToPushToSet.add(user)
114
+ }
115
+ for (const user of wildScriptUsers) usersToPushToSet.add(user)
116
+ for (const user of scriptNamesToUsers.get(scriptName)) usersToPushToSet.add(user)
117
+ const usersToPushTo = [...usersToPushToSet].filter(user => !scriptNamesToUsersToSkip.has(user))
118
+ if (!usersToPushTo.length) {
119
+ onPush?.({ path, users: [], characterCount: 0, error: Error("no users to push to") })
120
+ return
121
+ }
122
+ const uniqueId = Math.floor(Math.random() * 2 ** 52)
123
+ .toString(36)
124
+ .padStart(11, "0"),
125
+ filePath = resolve(sourceDirectory, path)
126
+ let minifiedCode
127
+ try {
128
+ ;({ script: minifiedCode } = await processScript(await readFile(filePath, { encoding: "utf8" }), {
129
+ minify,
130
+ scriptUser: !0,
131
+ scriptName,
132
+ uniqueId,
133
+ filePath,
134
+ mangleNames,
135
+ forceQuineCheats
136
+ }))
137
+ } catch (error) {
138
+ assert(error instanceof Error, "src/watch.ts:141:36")
139
+ onPush?.({ path, users: [], characterCount: 0, error })
140
+ return
141
+ }
142
+ await Promise.all(
143
+ usersToPushTo.map(user =>
144
+ writeFilePersistent(
145
+ resolve(hackmudDirectory, user, `scripts/${scriptName}.js`),
146
+ minifiedCode
147
+ .replace(RegExp(`\\$${uniqueId}\\$SCRIPT_USER\\$`, "g"), user)
148
+ .replace(RegExp(`\\$${uniqueId}\\$FULL_SCRIPT_NAME\\$`, "g"), `${user}.${scriptName}`)
149
+ )
150
+ )
151
+ )
152
+ onPush?.({
153
+ path,
154
+ users: usersToPushTo,
155
+ characterCount: countHackmudCharacters(minifiedCode),
156
+ error: void 0
157
+ })
158
+ return
159
+ }
160
+ const user = basename(resolve(path, ".."))
161
+ if (
162
+ !(
163
+ pushEverything ||
164
+ wildScriptUsers.size ||
165
+ wildUserScripts.has(scriptName) ||
166
+ scriptNamesToUsers.get(scriptName).has(user)
167
+ )
168
+ )
169
+ return
170
+ const filePath = resolve(sourceDirectory, path),
171
+ sourceCode = await readFile(filePath, { encoding: "utf8" })
172
+ let script
173
+ try {
174
+ ;({ script } = await processScript(sourceCode, {
175
+ minify,
176
+ scriptUser: user,
177
+ scriptName,
178
+ filePath,
179
+ mangleNames,
180
+ forceQuineCheats
181
+ }))
182
+ } catch (error) {
183
+ assert(error instanceof Error, "src/watch.ts:177:35")
184
+ onPush?.({ path, users: [], characterCount: 0, error })
185
+ return
186
+ }
187
+ await writeFilePersistent(resolve(hackmudDirectory, user, "scripts", scriptName + ".js"), script)
188
+ onPush?.({ path, users: [user], characterCount: countHackmudCharacters(script), error: void 0 })
189
+ })
190
+ onReady && watcher.on("ready", onReady)
191
+ if (!typeDeclarationPath_) return
192
+ let typeDeclarationPath = typeDeclarationPath_
193
+ const writeTypeDeclaration = async () => {
194
+ const typeDeclaration = await generateTypeDeclaration(sourceDirectory, hackmudDirectory)
195
+ try {
196
+ await writeFile(typeDeclarationPath, typeDeclaration)
197
+ } catch (error) {
198
+ assert(error instanceof Error, "src/watch.ts:210:35")
199
+ if ("EISDIR" != error.code) throw error
200
+ typeDeclarationPath = resolve(typeDeclarationPath, "player.d.ts")
201
+ await writeFile(typeDeclarationPath, typeDeclaration)
202
+ }
203
+ }
204
+ await writeTypeDeclaration()
205
+ watcher.on("add", writeTypeDeclaration)
206
+ watcher.on("unlink", writeTypeDeclaration)
207
+ }
208
+ export { watch }