hackmud-script-manager 0.19.0-43367ba → 0.19.0-c12fd7c

Sign up to get free protection for your applications and to get access to all the features.
package/watch.js CHANGED
@@ -1 +1,228 @@
1
- import{watch as r}from"chokidar";import{readdir as t,readFile as o,writeFile as e}from"fs/promises";import{extname as i,basename as s,resolve as a}from"path";import{s as n}from"./constants-9bb78688.js";import{generateTypeDeclaration as p}from"./generateTypeDeclaration.js";import{processScript as l}from"./processScript/index.js";import{D as c,w as m}from"./writeFilePersistent-ee9c9bfd.js";import{a as f}from"./assert-22a7ef8a.js";import{c as u}from"./countHackmudCharacters-a08a265f.js";import"@babel/generator";import"@babel/parser";import"@babel/plugin-proposal-class-properties";import"@babel/plugin-proposal-class-static-block";import"@babel/plugin-proposal-decorators";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-private-property-in-object";import"@babel/plugin-transform-exponentiation-operator";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"acorn";import"terser";import"./processScript/shared.js";import"./spliceString-0e6b5d6d.js";import"./processScript/postprocess.js";import"./processScript/preprocess.js";import"import-meta-resolve";import"./processScript/transform.js";import"fs";const watch=async(d,g,{scripts:h=["*.*"],onPush:b,minify:w=!0,mangleNames:y=!1,typeDeclarationPath:j,onReady:S,forceQuineCheats:$}={})=>{if(!h.length)throw new Error("scripts option was an empty array");const v=new c((r=>new Set)),E=new Set,F=new Set;let P=!1;for(const r of h){const[t,o]=r.split(".");t&&"*"!=t?o&&"*"!=o?v.get(o).add(t):E.add(t):o&&"*"!=o?F.add(o):P=!0}const D=r(["*.ts","*.js"],{depth:1,cwd:d,awaitWriteFinish:{stabilityThreshold:100},ignored:"*.d.ts"}).on("change",(async r=>{if(r.endsWith(".d.ts"))return;const e=i(r);if(!n.includes(e))return;const p=s(r,e);if(r==s(r)){if(!(P||E.size||F.has(p)||v.has(p)))return;const e=new c((r=>[]));await Promise.all((await t(d,{withFileTypes:!0})).map((async r=>{if(r.isDirectory())for(const o of await t(a(d,r.name),{withFileTypes:!0})){if(!o.isFile())continue;const t=i(o.name);n.includes(t)&&e.get(s(o.name,t)).push(r.name)}})));const h=new Set;if(P||F.has(p)){for(const r of await t(a(d),{withFileTypes:!0}))r.isDirectory()&&h.add(r.name);for(const r of await t(a(g),{withFileTypes:!0}))r.isDirectory()?h.add(r.name):r.isFile()&&r.name.endsWith(".key")&&h.add(r.name.slice(0,-4));for(const r of v.values())for(const t of r)h.add(t)}for(const r of E)h.add(r);for(const r of v.get(p))h.add(r);const j=[...h].filter((r=>!e.has(r)));if(!j.length)return void(null==b||b({file:r,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=a(d,r);let T;try{({script:T}=await l(await o(D,{encoding:"utf-8"}),{minify:w,scriptUser:!0,scriptName:p,uniqueID:S,filePath:D,mangleNames:y,forceQuineCheats:$}))}catch(t){return f(t instanceof Error),void(null==b||b({file:r,users:[],minLength:0,error:t}))}return await Promise.all(j.map((r=>m(a(g,r,`scripts/${p}.js`),T.replace(new RegExp(`\\$${S}\\$SCRIPT_USER\\$`,"g"),r).replace(new RegExp(`\\$${S}\\$FULL_SCRIPT_NAME\\$`,"g"),`${r}.${p}`))))),void(null==b||b({file:r,users:j,minLength:u(T),error:void 0}))}const h=s(a(r,".."));if(!(P||E.size||F.has(p)||v.get(p).has(h)))return;const j=a(d,r),S=await o(j,{encoding:"utf-8"});let D;try{({script:D}=await l(S,{minify:w,scriptUser:h,scriptName:p,filePath:j,mangleNames:y,forceQuineCheats:$}))}catch(t){return f(t instanceof Error),void(null==b||b({file:r,users:[],minLength:0,error:t}))}await m(a(g,h,"scripts",`${p}.js`),D),null==b||b({file:r,users:[h],minLength:u(D),error:void 0})}));if(S&&D.on("ready",S),!j)return;let T=j;const writeTypeDeclaration=async()=>{const r=await p(d,g);try{await e(T,r)}catch(t){if(f(t instanceof Error),"EISDIR"!=t.code)throw t;T=a(T,"player.d.ts"),await e(T,r)}};await writeTypeDeclaration(),D.on("add",writeTypeDeclaration),D.on("unlink",writeTypeDeclaration)};export{watch as default,watch};
1
+ import { DynamicMap } from '@samual/lib/DynamicMap';
2
+ import { assert } from '@samual/lib/assert';
3
+ import { countHackmudCharacters } from '@samual/lib/countHackmudCharacters';
4
+ import { writeFilePersistent } from '@samual/lib/writeFilePersistent';
5
+ import { watch as watch$1 } from 'chokidar';
6
+ import { readdir, readFile, writeFile } from 'fs/promises';
7
+ import { extname, basename, resolve } from 'path';
8
+ import { supportedExtensions } from './constants.js';
9
+ import { generateTypeDeclaration } from './generateTypeDeclaration.js';
10
+ import { processScript } from './processScript/index.js';
11
+ import '@babel/generator';
12
+ import '@babel/parser';
13
+ import '@babel/plugin-proposal-class-properties';
14
+ import '@babel/plugin-proposal-class-static-block';
15
+ import '@babel/plugin-proposal-decorators';
16
+ import '@babel/plugin-proposal-json-strings';
17
+ import '@babel/plugin-proposal-logical-assignment-operators';
18
+ import '@babel/plugin-proposal-nullish-coalescing-operator';
19
+ import '@babel/plugin-proposal-numeric-separator';
20
+ import '@babel/plugin-proposal-object-rest-spread';
21
+ import '@babel/plugin-proposal-optional-catch-binding';
22
+ import '@babel/plugin-proposal-optional-chaining';
23
+ import '@babel/plugin-proposal-private-property-in-object';
24
+ import '@babel/plugin-transform-exponentiation-operator';
25
+ import '@babel/traverse';
26
+ import '@babel/types';
27
+ import '@rollup/plugin-babel';
28
+ import '@rollup/plugin-commonjs';
29
+ import '@rollup/plugin-json';
30
+ import '@rollup/plugin-node-resolve';
31
+ import 'prettier';
32
+ import 'rollup';
33
+ import './processScript/minify.js';
34
+ import '@samual/lib/spliceString';
35
+ import 'acorn';
36
+ import 'terser';
37
+ import './processScript/shared.js';
38
+ import './processScript/postprocess.js';
39
+ import './processScript/preprocess.js';
40
+ import 'import-meta-resolve';
41
+ import './processScript/transform.js';
42
+ import '@samual/lib/clearObject';
43
+
44
+ /**
45
+ * Watches target file or folder for updates and builds and pushes updated file.
46
+ *
47
+ * @param sourceDirectory path to folder containing source files
48
+ * @param hackmudDirectory path to hackmud directory
49
+ * @param options {@link WatchOptions details} and {@link PushOptions more details}
50
+ */
51
+ const watch = async (sourceDirectory, hackmudDirectory, {
52
+ scripts = [`*.*`],
53
+ onPush,
54
+ minify = true,
55
+ mangleNames = false,
56
+ typeDeclarationPath: typeDeclarationPath_,
57
+ onReady,
58
+ forceQuineCheats
59
+ } = {}) => {
60
+ if (!scripts.length) throw new Error(`scripts option was an empty array`);
61
+ const scriptNamesToUsers = new DynamicMap(_scriptName => new Set());
62
+ const wildScriptUsers = new Set();
63
+ const wildUserScripts = new Set();
64
+ let pushEverything = false;
65
+ for (const fullScriptName of scripts) {
66
+ const [user, scriptName] = fullScriptName.split(`.`);
67
+ if (!user || user == `*`) {
68
+ if (!scriptName || scriptName == `*`) pushEverything = true;else wildUserScripts.add(scriptName);
69
+ } else if (!scriptName || scriptName == `*`) wildScriptUsers.add(user);else scriptNamesToUsers.get(scriptName).add(user);
70
+ }
71
+ const watcher = watch$1([`*.ts`, `*.js`], {
72
+ depth: 1,
73
+ cwd: sourceDirectory,
74
+ awaitWriteFinish: {
75
+ stabilityThreshold: 100
76
+ },
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
+
84
+ // if the path is still the same after getting just the base, it means it's directly in the source directory (global)
85
+ if (path == basename(path)) {
86
+ if (!pushEverything && !wildScriptUsers.size && !wildUserScripts.has(scriptName) && !scriptNamesToUsers.has(scriptName)) return;
87
+ const scriptNamesToUsersToSkip = new DynamicMap(_scriptName => []);
88
+ await Promise.all((await readdir(sourceDirectory, {
89
+ withFileTypes: true
90
+ })).map(async dirent => {
91
+ if (!dirent.isDirectory()) return;
92
+ for (const file of await readdir(resolve(sourceDirectory, dirent.name), {
93
+ withFileTypes: true
94
+ })) {
95
+ if (!file.isFile()) continue;
96
+ const fileExtension = extname(file.name);
97
+ if (supportedExtensions.includes(fileExtension)) scriptNamesToUsersToSkip.get(basename(file.name, fileExtension)).push(dirent.name);
98
+ }
99
+ }));
100
+ const usersToPushToSet = new Set();
101
+ if (pushEverything || wildUserScripts.has(scriptName)) {
102
+ for (const dirent of await readdir(resolve(sourceDirectory), {
103
+ withFileTypes: true
104
+ })) {
105
+ if (dirent.isDirectory()) usersToPushToSet.add(dirent.name);
106
+ }
107
+ for (const dirent of await readdir(resolve(hackmudDirectory), {
108
+ withFileTypes: true
109
+ })) {
110
+ if (dirent.isDirectory()) usersToPushToSet.add(dirent.name);else if (dirent.isFile() && dirent.name.endsWith(`.key`)) usersToPushToSet.add(dirent.name.slice(0, -4));
111
+ }
112
+ for (const users of scriptNamesToUsers.values()) {
113
+ for (const user of users) usersToPushToSet.add(user);
114
+ }
115
+ }
116
+ for (const user of wildScriptUsers) usersToPushToSet.add(user);
117
+ for (const user of scriptNamesToUsers.get(scriptName)) usersToPushToSet.add(user);
118
+ const usersToPushTo = [...usersToPushToSet].filter(user => !scriptNamesToUsersToSkip.has(user));
119
+ if (!usersToPushTo.length) {
120
+ onPush === null || onPush === void 0 ? void 0 : onPush({
121
+ file: path,
122
+ users: [],
123
+ minLength: 0,
124
+ error: new Error(`no users to push to`)
125
+ });
126
+ return;
127
+ }
128
+ const uniqueID = Math.floor(Math.random() * 2 ** 52).toString(36).padStart(11, `0`);
129
+ const filePath = resolve(sourceDirectory, path);
130
+ let minifiedCode;
131
+ try {
132
+ ({
133
+ script: minifiedCode
134
+ } = await processScript(await readFile(filePath, {
135
+ encoding: `utf-8`
136
+ }), {
137
+ minify,
138
+ scriptUser: true,
139
+ scriptName,
140
+ uniqueID,
141
+ filePath,
142
+ mangleNames,
143
+ forceQuineCheats
144
+ }));
145
+ } catch (error) {
146
+ assert(error instanceof Error);
147
+ onPush === null || onPush === void 0 ? void 0 : onPush({
148
+ file: path,
149
+ users: [],
150
+ minLength: 0,
151
+ error
152
+ });
153
+ return;
154
+ }
155
+ await Promise.all(usersToPushTo.map(user => writeFilePersistent(resolve(hackmudDirectory, user, `scripts/${scriptName}.js`), minifiedCode.replace(new RegExp(`\\$${uniqueID}\\$SCRIPT_USER\\$`, `g`), user).replace(new RegExp(`\\$${uniqueID}\\$FULL_SCRIPT_NAME\\$`, `g`), `${user}.${scriptName}`))));
156
+ onPush === null || onPush === void 0 ? void 0 : onPush({
157
+ file: path,
158
+ users: usersToPushTo,
159
+ minLength: countHackmudCharacters(minifiedCode),
160
+ error: undefined
161
+ });
162
+ return;
163
+ }
164
+ const user = basename(resolve(path, `..`));
165
+ if (!pushEverything && !wildScriptUsers.size && !wildUserScripts.has(scriptName) && !scriptNamesToUsers.get(scriptName).has(user)) return;
166
+ const filePath = resolve(sourceDirectory, path);
167
+ const sourceCode = await readFile(filePath, {
168
+ encoding: `utf-8`
169
+ });
170
+ let script;
171
+ try {
172
+ ({
173
+ script
174
+ } = 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);
184
+ onPush === null || onPush === void 0 ? void 0 : onPush({
185
+ file: path,
186
+ users: [],
187
+ minLength: 0,
188
+ error
189
+ });
190
+ return;
191
+ }
192
+ await writeFilePersistent(resolve(hackmudDirectory, user, `scripts`, `${scriptName}.js`), script);
193
+ onPush === null || onPush === void 0 ? void 0 : onPush({
194
+ file: path,
195
+ users: [user],
196
+ minLength: countHackmudCharacters(script),
197
+ error: undefined
198
+ });
199
+ });
200
+ if (onReady) watcher.on(`ready`, onReady);
201
+ if (!typeDeclarationPath_) return;
202
+ let typeDeclarationPath = typeDeclarationPath_;
203
+
204
+ /*
205
+ this currently works because the generated type declaration effectively
206
+ just connects things and doesn't actually read the scripts it's
207
+ generating type declarations for
208
+ if I ever change `generateTypings()` to actually read the scripts to
209
+ grab their types, this will need to change
210
+ */
211
+
212
+ const writeTypeDeclaration = async () => {
213
+ const typeDeclaration = await generateTypeDeclaration(sourceDirectory, hackmudDirectory);
214
+ try {
215
+ await writeFile(typeDeclarationPath, typeDeclaration);
216
+ } catch (error) {
217
+ assert(error instanceof Error);
218
+ if (!(error.code == `EISDIR`)) throw error;
219
+ typeDeclarationPath = resolve(typeDeclarationPath, `player.d.ts`);
220
+ await writeFile(typeDeclarationPath, typeDeclaration);
221
+ }
222
+ };
223
+ await writeTypeDeclaration();
224
+ watcher.on(`add`, writeTypeDeclaration);
225
+ watcher.on(`unlink`, writeTypeDeclaration);
226
+ };
227
+
228
+ export { watch as default, watch };
@@ -1 +0,0 @@
1
- const e=function createErrorClass(e){const r={[e]:class extends Error{}}[e];return Object.defineProperty(r.prototype,"name",{value:e}),r}("AssertError");function assert(r,s="assertion failed"){if(!r)throw new e(s)}function ensure(e,r="ensure failed"){return assert(e,r),e}export{assert as a,ensure as e};
@@ -1 +0,0 @@
1
- const s=[".js",".ts"],t=["i","r","f","u","u1","us","ObjectId"];export{s,t as v};
@@ -1 +0,0 @@
1
- function countHackmudCharacters(u){return u.replace(/\/\/.*/g,"").replace(/[ \t\n\r\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000]/g,"").length}export{countHackmudCharacters as c};
@@ -1 +0,0 @@
1
- function spliceString(i,e,s,c=0){return i.slice(0,s)+e+i.slice(s+c)}export{spliceString as s};
@@ -1 +0,0 @@
1
- import e from"fs";import{dirname as r}from"path";class DynamicMap extends Map{constructor(e){super(),this.fallbackHandler=e}get(e){if(super.has(e))return super.get(e);const r=this.fallbackHandler(e);return super.set(e,r),r}}const{writeFile:t,mkdir:s}=e.promises;function writeFilePersistent(e,a,i){return t(e,a,i).catch((async n=>{if("ENOENT"!=n.code)throw n;await s(r(e),{recursive:!0}),await t(e,a,i)}))}export{DynamicMap as D,writeFilePersistent as w};