hackmud-script-manager 0.12.0-9309192 → 0.12.0-c276bb2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. package/bin/hsm.js +55 -53
  2. package/index.js +10 -857
  3. package/package.json +11 -7
  4. package/shared.js +902 -0
  5. package/lib.js +0 -71
package/bin/hsm.js CHANGED
@@ -1,28 +1,30 @@
1
1
  #!/usr/bin/env node
2
- "use strict";
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
5
- };
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- const path_1 = require("path");
8
- const os_1 = require("os");
9
- const chalk_1 = __importDefault(require("chalk"));
10
- const fs_1 = __importDefault(require("fs"));
11
- const __1 = require("..");
12
- const lib_1 = require("../lib");
13
- const { readFile: readFile, rmdir: removeDirectory, writeFile: writeFile, mkdir: makeDirectory } = fs_1.default.promises;
14
- const configDirPath = (0, path_1.resolve)((0, os_1.homedir)(), ".config");
15
- const configFilePath = (0, path_1.resolve)(configDirPath, "hsm.json");
2
+ import { resolve, basename, extname, dirname, relative } from 'path';
3
+ import { homedir } from 'os';
4
+ import chalk from 'chalk';
5
+ import fs from 'fs';
6
+ import { D as DynamicMap, s as supportedExtensions, p as processScript, h as hackmudLength, w as writeFilePersist, g as generateTypings, t as test, a as syncMacros, b as pull, c as watch, d as push } from '../shared.js';
7
+ import 'acorn';
8
+ import 'chokidar';
9
+ import 'escodegen';
10
+ import 'esprima';
11
+ import 'esquery';
12
+ import 'terser';
13
+ import 'typescript';
14
+
15
+ const { readFile: readFile, rmdir: removeDirectory, writeFile: writeFile, mkdir: makeDirectory } = fs.promises;
16
+ const configDirPath = resolve(homedir(), ".config");
17
+ const configFilePath = resolve(configDirPath, "hsm.json");
16
18
  const options = new Map();
17
19
  const commands = [];
18
20
  let config;
19
- const colourJ = chalk_1.default.rgb(0xFF, 0xF4, 0x04);
20
- const colourK = chalk_1.default.rgb(0xF3, 0xF9, 0x98);
21
- const colourM = chalk_1.default.rgb(0xB3, 0xFF, 0x9B);
22
- const colourW = chalk_1.default.rgb(0xFF, 0x96, 0xE0);
23
- const colourL = chalk_1.default.rgb(0x1E, 0xFF, 0x00);
24
- const colourB = chalk_1.default.rgb(0xCA, 0xCA, 0xCA);
25
- const userColours = new lib_1.DynamicMap(user => {
21
+ const colourJ = chalk.rgb(0xFF, 0xF4, 0x04);
22
+ const colourK = chalk.rgb(0xF3, 0xF9, 0x98);
23
+ const colourM = chalk.rgb(0xB3, 0xFF, 0x9B);
24
+ const colourW = chalk.rgb(0xFF, 0x96, 0xE0);
25
+ const colourL = chalk.rgb(0x1E, 0xFF, 0x00);
26
+ const colourB = chalk.rgb(0xCA, 0xCA, 0xCA);
27
+ const userColours = new DynamicMap(user => {
26
28
  let hash = 0;
27
29
  for (const char of user)
28
30
  hash += (hash >> 1) + hash + "xi1_8ratvsw9hlbgm02y5zpdcn7uekof463qj".indexOf(char) + 1;
@@ -80,7 +82,7 @@ for (const arg of process.argv.slice(2)) {
80
82
  if (commands[2]) {
81
83
  const match = commands[2].match(/^([a-z_][a-z_0-9]{0,24})\.([a-z_][a-z_0-9]{0,24})$/);
82
84
  if (!match) {
83
- console.log(`"${chalk_1.default.bold(commands[2])}" is not a valid script name`);
85
+ console.log(`"${chalk.bold(commands[2])}" is not a valid script name`);
84
86
  break;
85
87
  }
86
88
  users = [match[1]];
@@ -90,7 +92,7 @@ for (const arg of process.argv.slice(2)) {
90
92
  users = ((_a = options.get("users")) === null || _a === void 0 ? void 0 : _a.toString().split(",")) || [];
91
93
  scripts = ((_b = options.get("scripts")) === null || _b === void 0 ? void 0 : _b.toString().split(",")) || [];
92
94
  }
93
- await (0, __1.push)(srcPath, hackmudPath, users, scripts, onPushLogger);
95
+ await push(srcPath, hackmudPath, users, scripts, onPushLogger);
94
96
  updateConfig();
95
97
  }
96
98
  break;
@@ -107,7 +109,7 @@ for (const arg of process.argv.slice(2)) {
107
109
  const users = ((_c = options.get("users")) === null || _c === void 0 ? void 0 : _c.toString().split(",")) || [];
108
110
  const scripts = ((_d = options.get("scripts")) === null || _d === void 0 ? void 0 : _d.toString().split(",")) || [];
109
111
  const genTypes = (_e = options.get("gen-types")) === null || _e === void 0 ? void 0 : _e.toString();
110
- (0, __1.watch)(srcPath, hackmudPath, users, scripts, onPushLogger, { genTypes });
112
+ watch(srcPath, hackmudPath, users, scripts, onPushLogger, { genTypes });
111
113
  }
112
114
  break;
113
115
  case "pull":
@@ -125,7 +127,7 @@ for (const arg of process.argv.slice(2)) {
125
127
  const srcPath = commands[2] || ".";
126
128
  const hackmudPath = config.hackmudPath;
127
129
  try {
128
- await (0, __1.pull)(srcPath, hackmudPath, script);
130
+ await pull(srcPath, hackmudPath, script);
129
131
  }
130
132
  catch (error) {
131
133
  console.log("something went wrong, did you forget to #down the script?");
@@ -139,17 +141,17 @@ for (const arg of process.argv.slice(2)) {
139
141
  console.log("you need to set hackmudPath in config before you can use this command");
140
142
  break;
141
143
  }
142
- const { macrosSynced, usersSynced } = await (0, __1.syncMacros)(hackmudPath);
144
+ const { macrosSynced, usersSynced } = await syncMacros(hackmudPath);
143
145
  console.log(`synced ${macrosSynced} macros to ${usersSynced} users`);
144
146
  }
145
147
  break;
146
148
  case "test":
147
149
  {
148
- const srcPath = (0, path_1.resolve)(commands[1] || ".");
150
+ const srcPath = resolve(commands[1] || ".");
149
151
  let errors = 0;
150
- console.log(`testing scripts in ${chalk_1.default.bold(srcPath)}\n`);
151
- for (const { file, line, message } of await (0, __1.test)(srcPath)) {
152
- console.log(`error "${chalk_1.default.bold(message)}" in ${chalk_1.default.bold(file)} on line ${chalk_1.default.bold(String(line))}`);
152
+ console.log(`testing scripts in ${chalk.bold(srcPath)}\n`);
153
+ for (const { file, line, message } of await test(srcPath)) {
154
+ console.log(`error "${chalk.bold(message)}" in ${chalk.bold(file)} on line ${chalk.bold(String(line))}`);
153
155
  errors++;
154
156
  }
155
157
  if (!errors) {
@@ -158,7 +160,7 @@ for (const arg of process.argv.slice(2)) {
158
160
  }
159
161
  if (errors) {
160
162
  process.exitCode = 1;
161
- console.log(`\nencountered ${chalk_1.default.bold(String(errors))} errors`);
163
+ console.log(`\nencountered ${chalk.bold(String(errors))} errors`);
162
164
  break;
163
165
  }
164
166
  console.log("no errors found");
@@ -166,13 +168,13 @@ for (const arg of process.argv.slice(2)) {
166
168
  break;
167
169
  case "gen-types":
168
170
  {
169
- const srcPath = (0, path_1.resolve)(commands[1] || ".");
171
+ const srcPath = resolve(commands[1] || ".");
170
172
  let targetPath;
171
173
  if (commands[2])
172
- targetPath = (0, path_1.resolve)(commands[2]);
174
+ targetPath = resolve(commands[2]);
173
175
  else
174
- targetPath = (0, path_1.resolve)(srcPath, "../player.d.ts");
175
- (0, __1.generateTypings)(srcPath, targetPath, (await getConfig()).hackmudPath);
176
+ targetPath = resolve(srcPath, "../player.d.ts");
177
+ generateTypings(srcPath, targetPath, (await getConfig()).hackmudPath);
176
178
  }
177
179
  break;
178
180
  case "config":
@@ -208,7 +210,7 @@ for (const arg of process.argv.slice(2)) {
208
210
  object = typeof object[key] == "object" ? object[key] : object[key] = {};
209
211
  object[keys.slice(-1)[0]] = value;
210
212
  if (config.hackmudPath)
211
- config.hackmudPath = (0, path_1.resolve)(config.hackmudPath);
213
+ config.hackmudPath = resolve(config.hackmudPath);
212
214
  console.log(config);
213
215
  }
214
216
  break;
@@ -235,38 +237,38 @@ for (const arg of process.argv.slice(2)) {
235
237
  case "minify":
236
238
  {
237
239
  if (!commands[1]) {
238
- console.log(`Target required\nUsage: ${(0, path_1.basename)(process.argv[1])} ${commands[0]} <target> [output]`);
240
+ console.log(`Target required\nUsage: ${basename(process.argv[1])} ${commands[0]} <target> [output]`);
239
241
  break;
240
242
  }
241
- const fileExtension = (0, path_1.extname)(commands[1]);
242
- if (!__1.supportedExtensions.includes(fileExtension)) {
243
- console.log(`Unsupported file extension "${chalk_1.default.bold(fileExtension)}"\nSupported extensions are "${__1.supportedExtensions.map(extension => chalk_1.default.bold(extension)).join('", "')}"`);
243
+ const fileExtension = extname(commands[1]);
244
+ if (!supportedExtensions.includes(fileExtension)) {
245
+ console.log(`Unsupported file extension "${chalk.bold(fileExtension)}"\nSupported extensions are "${supportedExtensions.map(extension => chalk.bold(extension)).join('", "')}"`);
244
246
  break;
245
247
  }
246
248
  await readFile(commands[1], { encoding: "utf-8" }).then(async (source) => {
247
- const { script, srcLength, warnings } = await (0, __1.processScript)(source);
249
+ const { script, srcLength, warnings } = await processScript(source);
248
250
  for (const { message, line } of warnings)
249
- console.log(`warning "${chalk_1.default.bold(message)}" on line ${chalk_1.default.bold(String(line))}`);
251
+ console.log(`warning "${chalk.bold(message)}" on line ${chalk.bold(String(line))}`);
250
252
  let outputPath;
251
253
  if (commands[2])
252
254
  outputPath = commands[2];
253
255
  else {
254
- const fileBaseName = (0, path_1.basename)(commands[1], fileExtension);
255
- outputPath = (0, path_1.resolve)((0, path_1.dirname)(commands[1]), fileBaseName.endsWith(".src")
256
+ const fileBaseName = basename(commands[1], fileExtension);
257
+ outputPath = resolve(dirname(commands[1]), fileBaseName.endsWith(".src")
256
258
  ? `${fileBaseName.slice(0, -4)}.js` :
257
259
  fileExtension == ".js"
258
260
  ? `${fileBaseName}.min.js`
259
261
  : `${fileBaseName}.js`);
260
262
  }
261
- const scriptLength = (0, lib_1.hackmudLength)(script);
262
- await (0, lib_1.writeFilePersist)(outputPath, script)
263
+ const scriptLength = hackmudLength(script);
264
+ await writeFilePersist(outputPath, script)
263
265
  .catch(async (error) => {
264
266
  if (!commands[2] || error.code != "EISDIR")
265
267
  throw error;
266
- outputPath = (0, path_1.resolve)(outputPath, `${(0, path_1.basename)(commands[1], fileExtension)}.js`);
267
- await (0, lib_1.writeFilePersist)(outputPath, script);
268
+ outputPath = resolve(outputPath, `${basename(commands[1], fileExtension)}.js`);
269
+ await writeFilePersist(outputPath, script);
268
270
  })
269
- .then(() => console.log(`wrote ${chalk_1.default.bold(scriptLength)} chars to ${chalk_1.default.bold((0, path_1.relative)(".", outputPath))} | saved ${chalk_1.default.bold(srcLength - scriptLength)} chars`), (error) => console.log(error.message));
271
+ .then(() => console.log(`wrote ${chalk.bold(scriptLength)} chars to ${chalk.bold(relative(".", outputPath))} | saved ${chalk.bold(srcLength - scriptLength)} chars`), (error) => console.log(error.message));
270
272
  }, (error) => console.log(error.message));
271
273
  }
272
274
  break;
@@ -322,7 +324,7 @@ function help() {
322
324
  case "minify":
323
325
  case "golf":
324
326
  {
325
- console.log(`${(0, path_1.basename)(process.argv[1])} ${commands[0]} <target> [output]`);
327
+ console.log(`${basename(process.argv[1])} ${commands[0]} <target> [output]`);
326
328
  }
327
329
  break;
328
330
  default: {
@@ -331,7 +333,7 @@ function help() {
331
333
  }
332
334
  }
333
335
  async function version() {
334
- console.log(JSON.parse(await readFile((0, path_1.resolve)(__dirname, "../package.json"), { encoding: "utf-8" })).version || "unknown");
336
+ console.log(JSON.parse(await readFile(resolve(__dirname, "../package.json"), { encoding: "utf-8" })).version || "unknown");
335
337
  }
336
338
  async function getConfig() {
337
339
  if (config)
@@ -393,8 +395,8 @@ function onPushLogger({ file, users, srcLength, minLength, error }) {
393
395
  if (!users.length)
394
396
  return;
395
397
  if (error) {
396
- console.log(`error "${chalk_1.default.bold(error.message)}" in ${chalk_1.default.bold(file)}`);
398
+ console.log(`error "${chalk.bold(error.message)}" in ${chalk.bold(file)}`);
397
399
  return;
398
400
  }
399
- console.log(`pushed ${chalk_1.default.bold(file)} to ${users.map(user => chalk_1.default.bold(userColours.get(user))).join(", ")} | ${chalk_1.default.bold(String(minLength))} chars from ${chalk_1.default.bold(String(srcLength))} | saved ${chalk_1.default.bold(String(srcLength - minLength))} (${chalk_1.default.bold(`${Math.round((1 - (minLength / srcLength)) * 100)}%`)}) | ${chalk_1.default.bold(`${(0, path_1.resolve)(config.hackmudPath, users[0], "scripts", (0, path_1.basename)(file, (0, path_1.extname)(file)))}.js`)}`);
401
+ console.log(`pushed ${chalk.bold(file)} to ${users.map(user => chalk.bold(userColours.get(user))).join(", ")} | ${chalk.bold(String(minLength))} chars from ${chalk.bold(String(srcLength))} | saved ${chalk.bold(String(srcLength - minLength))} (${chalk.bold(`${Math.round((1 - (minLength / srcLength)) * 100)}%`)}) | ${chalk.bold(`${resolve(config.hackmudPath, users[0], "scripts", basename(file, extname(file)))}.js`)}`);
400
402
  }
package/index.js CHANGED
@@ -1,857 +1,10 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getFunctionBodyStart = exports.processScript = exports.generateTypings = exports.test = exports.syncMacros = exports.pull = exports.watch = exports.push = exports.supportedExtensions = void 0;
7
- const acorn_1 = require("acorn");
8
- const chokidar_1 = require("chokidar");
9
- const escodegen_1 = require("escodegen");
10
- const esprima_1 = require("esprima");
11
- const esquery_1 = require("esquery");
12
- const fs_1 = __importDefault(require("fs"));
13
- const path_1 = require("path");
14
- const terser_1 = require("terser");
15
- const typescript_1 = __importDefault(require("typescript"));
16
- const lib_1 = require("./lib");
17
- const { readFile: readFile, readdir: readDirectory, stat: getFileStatus, writeFile: writeFile } = fs_1.default.promises;
18
- exports.supportedExtensions = [".js", ".ts"];
19
- // TODO `clean()` function that delete all scripts in hackmud directory #70
20
- // TODO optional argument (defaults to false) for `clean()` that makes it only remove scripts without a source file #70
21
- /**
22
- * Push a specific or all scripts to a specific or all users.
23
- * In source directory, scripts in folders will override scripts with same name for user with folder name.
24
- *
25
- * e.g. foo/bar.js overrides other bar.js script just for user foo.
26
- *
27
- * @param srcDir path to folder containing source files
28
- * @param hackmudDir path to hackmud directory
29
- * @param users users to push to (pushes to all if empty)
30
- * @param scripts scripts to push from (pushes from all if empty)
31
- * @param onPush function that's called when a script has been pushed
32
- */
33
- function push(srcDir, hackmudDir, users, scripts, onPush) {
34
- return new Promise(async (resolve) => {
35
- const infoAll = [];
36
- const files = await readDirectory(srcDir, { withFileTypes: true });
37
- const skips = new Map();
38
- const promises = [];
39
- for (const dir of files) {
40
- const user = dir.name;
41
- if (dir.isDirectory() && (!users.length || users.includes(user))) {
42
- promises.push(readDirectory((0, path_1.resolve)(srcDir, user), { withFileTypes: true }).then(files => {
43
- for (const file of files) {
44
- const extension = (0, path_1.extname)(file.name);
45
- const name = (0, path_1.basename)(file.name, extension);
46
- if (exports.supportedExtensions.includes(extension) && file.isFile() && (!scripts.length || scripts.includes(name))) {
47
- let skip = skips.get(name);
48
- if (skip)
49
- skip.push(user);
50
- else
51
- skips.set(name, [user]);
52
- readFile((0, path_1.resolve)(srcDir, user, file.name), { encoding: "utf-8" }).then(async (code) => {
53
- let error = null;
54
- const { srcLength, script: minCode } = await processScript(code).catch(reason => {
55
- error = reason;
56
- return {
57
- srcLength: 0,
58
- script: ""
59
- };
60
- });
61
- const info = {
62
- file: `${user}/${file.name}`,
63
- users: [user],
64
- minLength: 0,
65
- error,
66
- srcLength
67
- };
68
- infoAll.push(info);
69
- if (!error) {
70
- if (minCode) {
71
- info.minLength = (0, lib_1.hackmudLength)(minCode);
72
- await (0, lib_1.writeFilePersist)((0, path_1.resolve)(hackmudDir, user, "scripts", `${name}.js`), minCode);
73
- }
74
- else
75
- info.error = new Error("processed script was empty");
76
- }
77
- onPush === null || onPush === void 0 ? void 0 : onPush(info);
78
- });
79
- }
80
- }
81
- }));
82
- }
83
- }
84
- if (!users.length) {
85
- users = (await readDirectory(hackmudDir, { withFileTypes: true }))
86
- .filter(a => a.isFile() && (0, path_1.extname)(a.name) == ".key")
87
- .map(a => (0, path_1.basename)(a.name, ".key"));
88
- }
89
- Promise.all(promises).then(() => {
90
- const promises = [];
91
- for (const file of files) {
92
- if (file.isFile()) {
93
- const extension = (0, path_1.extname)(file.name);
94
- if (exports.supportedExtensions.includes(extension)) {
95
- const name = (0, path_1.basename)(file.name, extension);
96
- if (!scripts.length || scripts.includes(name)) {
97
- promises.push(readFile((0, path_1.resolve)(srcDir, file.name), { encoding: "utf-8" }).then(async (code) => {
98
- let error = null;
99
- const { script: minCode, srcLength } = await processScript(code).catch(reason => {
100
- error = reason;
101
- return {
102
- script: "",
103
- srcLength: 0
104
- };
105
- });
106
- const info = {
107
- file: file.name,
108
- users: [],
109
- minLength: 0,
110
- error,
111
- srcLength
112
- };
113
- infoAll.push(info);
114
- if (!error) {
115
- if (minCode) {
116
- info.minLength = (0, lib_1.hackmudLength)(minCode);
117
- const skip = skips.get(name) || [];
118
- const promises = [];
119
- for (const user of users) {
120
- if (!skip.includes(user)) {
121
- info.users.push(user);
122
- promises.push((0, lib_1.writeFilePersist)((0, path_1.resolve)(hackmudDir, user, "scripts", `${name}.js`), minCode));
123
- }
124
- }
125
- }
126
- else
127
- info.error = new Error("processed script was empty");
128
- }
129
- if (onPush)
130
- Promise.all(promises).then(() => onPush(info));
131
- }));
132
- }
133
- }
134
- }
135
- }
136
- Promise.all(promises).then(() => resolve(infoAll));
137
- });
138
- });
139
- }
140
- exports.push = push;
141
- /**
142
- * Watches target file or folder for updates and builds and pushes updated file.
143
- *
144
- * @param srcDir path to folder containing source files
145
- * @param hackmudDir path to hackmud directory
146
- * @param users users to push to (pushes to all if empty)
147
- * @param scripts scripts to push from (pushes from all if empty)
148
- * @param onPush function that's called after each script has been built and written
149
- */
150
- function watch(srcDir, hackmudDir, users, scripts, onPush, { genTypes } = {}) {
151
- const watcher = (0, chokidar_1.watch)("", { depth: 1, cwd: srcDir, awaitWriteFinish: { stabilityThreshold: 100 } }).on("change", async (path) => {
152
- const extension = (0, path_1.extname)(path);
153
- if (exports.supportedExtensions.includes(extension)) {
154
- const name = (0, path_1.basename)(path, extension);
155
- const fileName = (0, path_1.basename)(path);
156
- if (path == fileName) {
157
- if (!scripts.length || scripts.includes(name)) {
158
- const sourceCode = await readFile((0, path_1.resolve)(srcDir, path), { encoding: "utf-8" });
159
- const skips = new Map();
160
- const promisesSkips = [];
161
- for (const dir of await readDirectory(srcDir, { withFileTypes: true })) {
162
- if (!dir.isDirectory())
163
- continue;
164
- promisesSkips.push(readDirectory((0, path_1.resolve)(srcDir, dir.name), { withFileTypes: true }).then(files => {
165
- for (const file of files) {
166
- if (!file.isFile())
167
- continue;
168
- const fileExtension = (0, path_1.extname)(file.name);
169
- if (!exports.supportedExtensions.includes(fileExtension))
170
- continue;
171
- const name = (0, path_1.basename)(file.name, fileExtension);
172
- const skip = skips.get(name);
173
- if (skip)
174
- skip.push(dir.name);
175
- else
176
- skips.set(name, [dir.name]);
177
- }
178
- }));
179
- }
180
- await Promise.all(promisesSkips);
181
- let error = null;
182
- const { script, srcLength } = await processScript(sourceCode).catch(reason => {
183
- error = reason;
184
- return {
185
- script: "",
186
- srcLength: 0
187
- };
188
- });
189
- const info = {
190
- file: path,
191
- users: [],
192
- minLength: 0,
193
- error,
194
- srcLength
195
- };
196
- const promises = [];
197
- if (!error) {
198
- if (script) {
199
- const skip = skips.get(name) || [];
200
- info.minLength = (0, lib_1.hackmudLength)(script);
201
- if (!users.length) {
202
- users = (await readDirectory(hackmudDir, { withFileTypes: true }))
203
- .filter(a => a.isFile() && (0, path_1.extname)(a.name) == ".key")
204
- .map(a => (0, path_1.basename)(a.name, ".key"));
205
- }
206
- for (const user of users) {
207
- if (skip.includes(user))
208
- continue;
209
- info.users.push(user);
210
- promises.push((0, lib_1.writeFilePersist)((0, path_1.resolve)(hackmudDir, user, "scripts", `${name}.js`), script));
211
- }
212
- }
213
- else
214
- info.error = new Error("processed script was empty");
215
- }
216
- if (onPush) {
217
- await Promise.all(promises);
218
- onPush(info);
219
- }
220
- }
221
- }
222
- else {
223
- const user = (0, path_1.basename)((0, path_1.resolve)(path, ".."));
224
- if ((!users.length || users.includes(user)) && (!scripts.length || scripts.includes(name))) {
225
- const sourceCode = await readFile((0, path_1.resolve)(srcDir, path), { encoding: "utf-8" });
226
- let error = null;
227
- const { script, srcLength } = await processScript(sourceCode).catch(reason => {
228
- error = reason;
229
- return {
230
- script: "",
231
- srcLength: 0
232
- };
233
- });
234
- const info = {
235
- file: path,
236
- users: [user],
237
- minLength: 0,
238
- error,
239
- srcLength
240
- };
241
- if (!error) {
242
- if (script) {
243
- info.minLength = (0, lib_1.hackmudLength)(script);
244
- await (0, lib_1.writeFilePersist)((0, path_1.resolve)(hackmudDir, user, "scripts", `${name}.js`), script);
245
- }
246
- else
247
- info.error = new Error("processed script was empty");
248
- }
249
- onPush === null || onPush === void 0 ? void 0 : onPush(info);
250
- }
251
- }
252
- }
253
- });
254
- if (genTypes) {
255
- generateTypings(srcDir, (0, path_1.resolve)(srcDir, genTypes), hackmudDir);
256
- watcher.on("add", () => generateTypings(srcDir, (0, path_1.resolve)(srcDir, genTypes), hackmudDir));
257
- watcher.on("unlink", () => generateTypings(srcDir, (0, path_1.resolve)(srcDir, genTypes), hackmudDir));
258
- }
259
- }
260
- exports.watch = watch;
261
- /**
262
- * Copies script from hackmud to local source folder.
263
- *
264
- * @param sourceFolderPath path to folder containing source files
265
- * @param hackmudPath path to hackmud directory
266
- * @param script script to pull in `user.name` format
267
- */
268
- async function pull(sourceFolderPath, hackmudPath, script) {
269
- const [user, name] = script.split(".");
270
- await (0, lib_1.copyFilePersist)((0, path_1.resolve)(hackmudPath, user, "scripts", `${name}.js`), (0, path_1.resolve)(sourceFolderPath, user, `${name}.js`));
271
- }
272
- exports.pull = pull;
273
- async function syncMacros(hackmudPath) {
274
- const files = await readDirectory(hackmudPath, { withFileTypes: true });
275
- const macros = new Map();
276
- const users = [];
277
- for (const file of files) {
278
- if (!file.isFile())
279
- continue;
280
- switch ((0, path_1.extname)(file.name)) {
281
- case ".macros":
282
- {
283
- const lines = (await readFile((0, path_1.resolve)(hackmudPath, file.name), { encoding: "utf-8" })).split("\n");
284
- const date = (await getFileStatus((0, path_1.resolve)(hackmudPath, file.name))).mtime;
285
- for (let i = 0; i < lines.length / 2 - 1; i++) {
286
- const macroName = lines[i * 2];
287
- const curMacro = macros.get(macroName);
288
- if (!curMacro || date > curMacro.date)
289
- macros.set(macroName, { date, macro: lines[i * 2 + 1] });
290
- }
291
- }
292
- break;
293
- case ".key":
294
- {
295
- users.push((0, path_1.basename)(file.name, ".key"));
296
- }
297
- break;
298
- }
299
- }
300
- let macroFile = "";
301
- let macrosSynced = 0;
302
- for (const [name, { macro }] of [...macros].sort(([a], [b]) => (a > b) - (a < b))) {
303
- if (macro[0] != macro[0].toLowerCase())
304
- continue;
305
- macroFile += `${name}\n${macro}\n`;
306
- macrosSynced++;
307
- }
308
- for (const user of users)
309
- writeFile((0, path_1.resolve)(hackmudPath, user + ".macros"), macroFile);
310
- return { macrosSynced, usersSynced: users.length };
311
- }
312
- exports.syncMacros = syncMacros;
313
- async function test(srcPath) {
314
- const promises = [];
315
- const errors = [];
316
- for (const dirent of await readDirectory(srcPath, { withFileTypes: true })) {
317
- if (dirent.isDirectory()) {
318
- promises.push(readDirectory((0, path_1.resolve)(srcPath, dirent.name), { withFileTypes: true }).then(files => {
319
- const promises = [];
320
- for (const file of files) {
321
- if (!file.isFile() || !exports.supportedExtensions.includes((0, path_1.extname)(file.name)))
322
- continue;
323
- promises.push(readFile((0, path_1.resolve)(srcPath, dirent.name, file.name), { encoding: "utf-8" })
324
- .then(processScript)
325
- .then(({ warnings }) => errors.push(...warnings.map(({ message, line }) => ({
326
- file: `${dirent.name}/${file.name}`,
327
- message, line
328
- })))));
329
- }
330
- return Promise.all(promises);
331
- }));
332
- }
333
- else if (dirent.isFile() && exports.supportedExtensions.includes((0, path_1.extname)(dirent.name))) {
334
- promises.push(readFile((0, path_1.resolve)(srcPath, dirent.name), { encoding: "utf-8" })
335
- .then(processScript)
336
- .then(({ warnings }) => errors.push(...warnings.map(({ message, line }) => ({
337
- file: dirent.name,
338
- message, line
339
- })))));
340
- }
341
- }
342
- await Promise.all(promises);
343
- return errors;
344
- }
345
- exports.test = test;
346
- async function generateTypings(srcDir, target, hackmudPath) {
347
- const users = new Set();
348
- if (hackmudPath) {
349
- for (const dirent of await readDirectory(hackmudPath, { withFileTypes: true })) {
350
- if (dirent.isFile() && (0, path_1.extname)(dirent.name) == ".key")
351
- users.add((0, path_1.basename)(dirent.name, ".key"));
352
- }
353
- }
354
- const wildScripts = [];
355
- const wildAnyScripts = [];
356
- const allScripts = {};
357
- const allAnyScripts = {};
358
- for (const dirent of await readDirectory(srcDir, { withFileTypes: true })) {
359
- if (dirent.isFile()) {
360
- if ((0, path_1.extname)(dirent.name) == ".ts")
361
- wildScripts.push((0, path_1.basename)(dirent.name, ".ts"));
362
- else if ((0, path_1.extname)(dirent.name) == ".js")
363
- wildAnyScripts.push((0, path_1.basename)(dirent.name, ".js"));
364
- }
365
- else if (dirent.isDirectory()) {
366
- const scripts = allScripts[dirent.name] = [];
367
- const anyScripts = allAnyScripts[dirent.name] = [];
368
- users.add(dirent.name);
369
- for (const file of await readDirectory((0, path_1.resolve)(srcDir, dirent.name), { withFileTypes: true })) {
370
- if (file.isFile()) {
371
- if ((0, path_1.extname)(file.name) == ".ts")
372
- scripts.push((0, path_1.basename)(file.name, ".ts"));
373
- else if ((0, path_1.extname)(file.name) == ".js")
374
- anyScripts.push((0, path_1.basename)(file.name, ".js"));
375
- }
376
- }
377
- }
378
- }
379
- let o = "";
380
- for (const script of wildScripts)
381
- o += `import { script as $${script}$ } from "./src/${script}"\n`;
382
- o += "\n";
383
- for (const user in allScripts) {
384
- const scripts = allScripts[user];
385
- for (const script of scripts)
386
- o += `import { script as $${user}$${script}$ } from "./src/${user}/${script}"\n`;
387
- }
388
- // TODO detect security level and generate apropriate code
389
- // TODO accurate function signatures
390
- // currently I lose the generic-ness of my functions when I wrap them
391
- // just regexing isn't enough and it looks like I'm going to need to parse the files in TypeScript to extract the signature
392
- o += `
393
- type ArrayRemoveFirst<A> = A extends [ infer FirstItem, ...infer Rest ] ? Rest : never
394
-
395
- type Subscript<T extends (...args: any) => any> =
396
- (...args: ArrayRemoveFirst<Parameters<T>>) => ReturnType<T> | ScriptFailure
397
-
398
- type WildFullsec = Record<string, () => ScriptFailure> & {
399
- `;
400
- for (const script of wildScripts)
401
- o += `\t${script}: Subscript<typeof $${script}$>\n`;
402
- for (const script of wildAnyScripts)
403
- o += `\t${script}: (...args: any) => any\n`;
404
- o += "}\n\ndeclare global {\n\tinterface PlayerFullsec {";
405
- let lastWasMultiLine = true;
406
- for (const user of users) {
407
- const scripts = allScripts[user];
408
- const anyScripts = allAnyScripts[user];
409
- if ((scripts && scripts.length) || (anyScripts && anyScripts.length)) {
410
- lastWasMultiLine = true;
411
- o += `\n\t\t${user}: WildFullsec & {\n`;
412
- for (const script of scripts)
413
- o += `\t\t\t${script}: Subscript<typeof $${user}$${script}$>\n`;
414
- for (const script of anyScripts)
415
- o += `\t\t\t${script}: (...args: any) => any\n`;
416
- o += "\t\t}";
417
- }
418
- else {
419
- if (lastWasMultiLine) {
420
- o += "\n";
421
- lastWasMultiLine = false;
422
- }
423
- o += `\t\t${user}: WildFullsec`;
424
- }
425
- o += "\n";
426
- }
427
- o += "\t}\n}\n";
428
- await writeFile(target, o);
429
- }
430
- exports.generateTypings = generateTypings;
431
- /**
432
- * Minifies a given script
433
- *
434
- * @param script JavaScript or TypeScript code
435
- */
436
- async function processScript(script) {
437
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
438
- let preScriptComments;
439
- let autocomplete;
440
- [, preScriptComments, script, autocomplete] = script.match(/((?:^\s*\/\/.*\n)*)\s*((?:.+?\/\/\s*(.+?)\s*$)?[^]*)/m);
441
- if (!script)
442
- throw new Error("script was empty");
443
- if (script.match(/(?:SC|DB)\$/))
444
- throw new Error("SC$ and DB$ are protected and cannot appear in a script");
445
- let seclevel;
446
- for (const line of preScriptComments.split("\n")) {
447
- let [, autocompleteMatch, seclevelMatch] = (line.match(/^\s*\/\/\s*(?:@autocomplete\s*([^\s].*?)|@seclevel\s*([^\s].*?))\s*$/) || []);
448
- if (autocompleteMatch)
449
- autocomplete = autocompleteMatch;
450
- else if (seclevelMatch) {
451
- if (seclevelMatch.match(/^(?:fullsec|f|4|fs|full)$/i))
452
- seclevel = 4;
453
- else if (seclevelMatch.match(/^(?:highsec|h|3|hs|high)$/i))
454
- seclevel = 3;
455
- else if (seclevelMatch.match(/^(?:midsec|m|2|ms|mid)$/i))
456
- seclevel = 2;
457
- else if (seclevelMatch.match(/^(?:lowsec|l|1|ls|low)$/i))
458
- seclevel = 1;
459
- else if (seclevelMatch.match(/^(?:nullsec|n|0|ns|null)$/i))
460
- seclevel = 0;
461
- }
462
- }
463
- let detectedSeclevel;
464
- if (script.match(/[#$][n0]s\.[a-z_][a-z_0-9]{0,24}\.[a-z_][a-z_0-9]{0,24}\(/))
465
- detectedSeclevel = 0;
466
- else if (script.match(/[#$][l1]s\.[a-z_][a-z_0-9]{0,24}\.[a-z_][a-z_0-9]{0,24}\(/))
467
- detectedSeclevel = 1;
468
- else if (script.match(/[#$][m2]s\.[a-z_][a-z_0-9]{0,24}\.[a-z_][a-z_0-9]{0,24}\(/))
469
- detectedSeclevel = 2;
470
- else if (script.match(/[#$][h3]s\.[a-z_][a-z_0-9]{0,24}\.[a-z_][a-z_0-9]{0,24}\(/))
471
- detectedSeclevel = 3;
472
- else if (script.match(/[#$][f4]s\.[a-z_][a-z_0-9]{0,24}\.[a-z_][a-z_0-9]{0,24}\(/))
473
- detectedSeclevel = 4;
474
- const seclevelNames = ["NULLSEC", "LOWSEC", "MIDSEC", "HIGHSEC", "FULLSEC"];
475
- if (seclevel == undefined)
476
- seclevel = (_a = seclevel !== null && seclevel !== void 0 ? seclevel : detectedSeclevel) !== null && _a !== void 0 ? _a : 0;
477
- else if (detectedSeclevel != undefined && seclevel > detectedSeclevel)
478
- throw new Error(`detected seclevel of ${seclevelNames[detectedSeclevel]} is lower than the provided seclevel of ${seclevelNames[seclevel]}`);
479
- const semicolons = (_c = (_b = script.match(/;/g)) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0;
480
- script = script
481
- .replace(/#[fhmln43210]s\.scripts\.quine\(\)/g, JSON.stringify(script))
482
- .replace(/[#$][fhmln43210]?s\.([a-z_][a-z_0-9]{0,24})\.([a-z_][a-z_0-9]{0,24})\(/g, "SC$$$1$$$2(")
483
- .replace(/^function\s*\(/, "function script(")
484
- .replace(/#D\(/g, "$D(")
485
- .replace(/#FMCL/g, "$FMCL")
486
- .replace(/#G/g, "$G")
487
- .replace(/[#$]db\./g, "DB$");
488
- // typescript compilation, this runs on regular javascript too to convert
489
- // any post es2015 syntax into es2015 syntax
490
- const { outputText, diagnostics = [] } = typescript_1.default.transpileModule(script, {
491
- compilerOptions: { target: typescript_1.default.ScriptTarget.ES2015 },
492
- reportDiagnostics: true
493
- });
494
- const warnings = diagnostics.map(({ messageText, start }) => ({
495
- message: typeof messageText == "string" ? messageText : messageText.messageText,
496
- line: (0, lib_1.positionToLineNumber)(start, script)
497
- }));
498
- script = outputText.replace(/^export /, "");
499
- await writeFile("./test.json", JSON.stringify((0, esprima_1.parseScript)(script), null, "\t"));
500
- const ast = (0, esprima_1.parseScript)(script);
501
- for (const node of (0, esquery_1.query)(ast, "ClassBody > MethodDefinition[kind=constructor] > FunctionExpression > BlockStatement")) {
502
- node.body.unshift({
503
- type: "VariableDeclaration",
504
- declarations: [
505
- {
506
- type: "VariableDeclarator",
507
- id: {
508
- type: "Identifier",
509
- name: "__THIS__"
510
- }
511
- }
512
- ],
513
- kind: "let"
514
- });
515
- }
516
- for (const node of (0, esquery_1.query)(ast, "ClassBody > MethodDefinition[kind=constructor] > FunctionExpression > BlockStatement !CallExpression > Super")) {
517
- const newNode = {
518
- type: "AssignmentExpression",
519
- operator: "=",
520
- left: {
521
- type: "Identifier",
522
- name: "__THIS__"
523
- },
524
- right: { ...node }
525
- };
526
- Object.assign((0, lib_1.clearObject)(node), newNode);
527
- }
528
- for (const node of (0, esquery_1.query)(ast, "ClassBody > MethodDefinition > FunctionExpression > BlockStatement !ThisExpression")) {
529
- const newNode = {
530
- type: "Identifier",
531
- name: "__THIS__"
532
- };
533
- Object.assign((0, lib_1.clearObject)(node), newNode);
534
- }
535
- for (const node of (0, esquery_1.query)(ast, "ClassBody > MethodDefinition[kind=method] > FunctionExpression > BlockStatement")) {
536
- node.body.unshift({
537
- type: "VariableDeclaration",
538
- declarations: [{
539
- type: "VariableDeclarator",
540
- id: {
541
- type: "Identifier",
542
- name: "__THIS__"
543
- },
544
- init: {
545
- type: "CallExpression",
546
- callee: {
547
- type: "MemberExpression",
548
- computed: false,
549
- object: {
550
- type: "Super"
551
- },
552
- property: {
553
- type: "Identifier",
554
- name: "valueOf"
555
- },
556
- optional: false
557
- },
558
- arguments: [],
559
- optional: false
560
- }
561
- }],
562
- "kind": "let"
563
- });
564
- }
565
- script = (0, escodegen_1.generate)(ast);
566
- // the typescript inserts semicolons where they weren't already so we take
567
- // all semicolons out of the count and add the number of semicolons in the
568
- // source to make things fair
569
- let srcLength = (0, lib_1.hackmudLength)(script.replace(/^function\s*\w+\(/, "function("))
570
- - ((_e = (_d = script.match(/;/g)) === null || _d === void 0 ? void 0 : _d.length) !== null && _e !== void 0 ? _e : 0)
571
- + semicolons
572
- + ((_g = (_f = script.match(/SC\$[a-zA-Z_][a-zA-Z0-9_]*\$[a-zA-Z_][a-zA-Z0-9_]*\(/g)) === null || _f === void 0 ? void 0 : _f.length) !== null && _g !== void 0 ? _g : 0)
573
- + ((_j = (_h = script.match(/DB\$/g)) === null || _h === void 0 ? void 0 : _h.length) !== null && _j !== void 0 ? _j : 0);
574
- // remove dead code (so we don't waste chracters quine cheating strings
575
- // that aren't even used)
576
- script = (await (0, terser_1.minify)(script, {
577
- ecma: 2015,
578
- parse: { bare_returns: true },
579
- compress: { booleans: false }
580
- })).code || "";
581
- let blockStatementIndex;
582
- if (script.startsWith("function "))
583
- blockStatementIndex = getFunctionBodyStart(script);
584
- else {
585
- script = `function script(context, args) {\n${script}\n}`;
586
- blockStatementIndex = 31;
587
- srcLength += 24;
588
- }
589
- let scriptBeforeJSONValueReplacement = (await (0, terser_1.minify)(script, {
590
- ecma: 2015,
591
- compress: {
592
- passes: Infinity,
593
- unsafe: true,
594
- unsafe_arrows: true,
595
- unsafe_comps: true,
596
- unsafe_symbols: true,
597
- unsafe_methods: true,
598
- unsafe_proto: true,
599
- unsafe_regexp: true,
600
- unsafe_undefined: true
601
- },
602
- format: { semicolons: false }
603
- })).code || "";
604
- {
605
- const tokens = [...(0, acorn_1.tokenizer)(scriptBeforeJSONValueReplacement, { ecmaVersion: 2015 })].reverse().values();
606
- for (const token of tokens) {
607
- // we can't replace any tokens before the block statement or we'll break stuff
608
- if (token.start < blockStatementIndex)
609
- break;
610
- switch (token.type) {
611
- case acorn_1.tokTypes.name:
612
- {
613
- if (token.value != "prototype" && token.value != "__proto__")
614
- break;
615
- const tokenBefore = tokens.next().value;
616
- if (tokenBefore.type != acorn_1.tokTypes.dot)
617
- break;
618
- srcLength += 3;
619
- scriptBeforeJSONValueReplacement = (0, lib_1.stringSplice)(scriptBeforeJSONValueReplacement, `["${token.value}"]`, tokenBefore.start, token.end);
620
- }
621
- break;
622
- case acorn_1.tokTypes._const:
623
- {
624
- scriptBeforeJSONValueReplacement = (0, lib_1.stringSplice)(scriptBeforeJSONValueReplacement, "let", token.start, token.end);
625
- }
626
- break;
627
- case acorn_1.tokTypes._this:
628
- throw new Error('"this" keyword is not supported in hackmud');
629
- }
630
- }
631
- }
632
- const jsonValues = [];
633
- let undefinedIsReferenced = false;
634
- // we iterate through the tokens backwards so that substring replacements
635
- // don't affect future replacements since a part of the string could be
636
- // replaced with a string of a different length which messes up indexes
637
- const tokens = [...(0, acorn_1.tokenizer)(script, { ecmaVersion: 2015 })].reverse().values();
638
- let templateToRightOfPlaceholder = false;
639
- for (const token of tokens) {
640
- // we can't replace any tokens before the block statement or we'll break stuff
641
- if (token.start < blockStatementIndex)
642
- break;
643
- switch (token.type) {
644
- case acorn_1.tokTypes.backQuote:
645
- {
646
- const templateToken = tokens.next().value;
647
- if (tokens.next().value.type == acorn_1.tokTypes.backQuote)
648
- throw new Error("tagged templates not supported yet");
649
- // no point in concatenating an empty string
650
- if (templateToken.value == "") {
651
- script = (0, lib_1.stringSplice)(script, "))", templateToken.start - 1, token.end);
652
- break;
653
- }
654
- let jsonValueIndex = jsonValues.indexOf(templateToken.value);
655
- if (jsonValueIndex == -1)
656
- jsonValueIndex += jsonValues.push(templateToken.value);
657
- script = (0, lib_1.stringSplice)(script, `)+_JSON_VALUE_${jsonValueIndex}_)`, templateToken.start - 1, token.end);
658
- }
659
- break;
660
- case acorn_1.tokTypes.template:
661
- {
662
- if (tokens.next().value.type == acorn_1.tokTypes.backQuote) {
663
- if (tokens.next().value.type == acorn_1.tokTypes.name)
664
- throw new Error("tagged templates not supported yet");
665
- // there *is* a point in concatenating an empty string at the
666
- // start because foo + bar is not the same thing as "" + foo + bar
667
- // ...but foo + "<template>" + bar *is* the same thing as "" + foo + "<template>" + bar
668
- // so we just need to check if there's a template to the right of the placeholder and skip that case
669
- if (token.value == "" && templateToRightOfPlaceholder) {
670
- templateToRightOfPlaceholder = false;
671
- script = (0, lib_1.stringSplice)(script, "((", token.start - 1, token.end + 2);
672
- break;
673
- }
674
- templateToRightOfPlaceholder = false;
675
- let jsonValueIndex = jsonValues.indexOf(token.value);
676
- if (jsonValueIndex == -1)
677
- jsonValueIndex += jsonValues.push(token.value);
678
- script = (0, lib_1.stringSplice)(script, `(_JSON_VALUE_${jsonValueIndex}_+(`, token.start - 1, token.end + 2);
679
- break;
680
- }
681
- // no point in concatenating an empty string
682
- if (token.value == "") {
683
- templateToRightOfPlaceholder = false;
684
- script = (0, lib_1.stringSplice)(script, ")+(", token.start - 1, token.end + 2);
685
- break;
686
- }
687
- templateToRightOfPlaceholder = true;
688
- let jsonValueIndex = jsonValues.indexOf(token.value);
689
- if (jsonValueIndex == -1)
690
- jsonValueIndex += jsonValues.push(token.value);
691
- script = (0, lib_1.stringSplice)(script, `)+_JSON_VALUE_${jsonValueIndex}_+(`, token.start - 1, token.end + 2);
692
- }
693
- break;
694
- case acorn_1.tokTypes.name:
695
- {
696
- if (token.value.length < 3)
697
- break;
698
- const tokenBefore = tokens.next().value;
699
- if (tokenBefore.type == acorn_1.tokTypes.dot) {
700
- let jsonValueIndex = jsonValues.indexOf(token.value);
701
- if (jsonValueIndex == -1)
702
- jsonValueIndex += jsonValues.push(token.value);
703
- script = (0, lib_1.stringSplice)(script, `[_JSON_VALUE_${jsonValueIndex}_]`, tokenBefore.start, token.end);
704
- break;
705
- }
706
- if (token.value == "undefined") {
707
- script = (0, lib_1.stringSplice)(script, " _UNDEFINED_ ", token.start, token.end);
708
- undefinedIsReferenced = true;
709
- }
710
- }
711
- break;
712
- case acorn_1.tokTypes._null:
713
- {
714
- let jsonValueIndex = jsonValues.indexOf(null);
715
- if (jsonValueIndex == -1)
716
- jsonValueIndex += jsonValues.push(null);
717
- script = (0, lib_1.stringSplice)(script, ` _JSON_VALUE_${jsonValueIndex}_ `, token.start, token.end);
718
- }
719
- break;
720
- case acorn_1.tokTypes._true:
721
- {
722
- let jsonValueIndex = jsonValues.indexOf(true);
723
- if (jsonValueIndex == -1)
724
- jsonValueIndex += jsonValues.push(true);
725
- script = (0, lib_1.stringSplice)(script, ` _JSON_VALUE_${jsonValueIndex}_ `, token.start, token.end);
726
- }
727
- break;
728
- case acorn_1.tokTypes._false:
729
- {
730
- let jsonValueIndex = jsonValues.indexOf(false);
731
- if (jsonValueIndex == -1)
732
- jsonValueIndex += jsonValues.push(false);
733
- script = (0, lib_1.stringSplice)(script, ` _JSON_VALUE_${jsonValueIndex}_ `, token.start, token.end);
734
- }
735
- break;
736
- case acorn_1.tokTypes.num:
737
- {
738
- if (token.value == 0) {
739
- const tokenBefore = tokens.next().value;
740
- if (tokenBefore.type == acorn_1.tokTypes._void) {
741
- script = (0, lib_1.stringSplice)(script, " _UNDEFINED_ ", tokenBefore.start, token.end);
742
- undefinedIsReferenced = true;
743
- }
744
- // may as well break here since we're gonna break anyway
745
- break;
746
- }
747
- if (token.value < 10)
748
- break;
749
- let jsonValueIndex = jsonValues.indexOf(token.value);
750
- if (jsonValueIndex == -1)
751
- jsonValueIndex += jsonValues.push(token.value);
752
- script = (0, lib_1.stringSplice)(script, ` _JSON_VALUE_${jsonValueIndex}_ `, token.start, token.end);
753
- }
754
- break;
755
- case acorn_1.tokTypes.string:
756
- {
757
- if (token.value.includes("\u0000"))
758
- break;
759
- let jsonValueIndex = jsonValues.indexOf(token.value);
760
- if (jsonValueIndex == -1)
761
- jsonValueIndex += jsonValues.push(token.value);
762
- script = (0, lib_1.stringSplice)(script, ` _JSON_VALUE_${jsonValueIndex}_ `, token.start, token.end);
763
- }
764
- break;
765
- case acorn_1.tokTypes._const:
766
- {
767
- script = (0, lib_1.stringSplice)(script, "let", token.start, token.end);
768
- }
769
- break;
770
- case acorn_1.tokTypes._this:
771
- throw new Error('"this" keyword is not supported in hackmud');
772
- }
773
- }
774
- let comment = null;
775
- let hasComment = false;
776
- if (jsonValues.length) {
777
- hasComment = true;
778
- if (jsonValues.length == 1) {
779
- if (typeof jsonValues[0] == "string" && !jsonValues[0].includes("\n") && !jsonValues[0].includes("\t")) {
780
- script = (0, lib_1.stringSplice)(script, `\nlet _JSON_VALUE_0_ = SC$scripts$quine().split\`\t\`[_SPLIT_INDEX_]${undefinedIsReferenced ? ", _UNDEFINED_" : ""}\n`, blockStatementIndex + 1);
781
- comment = jsonValues[0];
782
- }
783
- else {
784
- script = (0, lib_1.stringSplice)(script, `\nlet _JSON_VALUE_0_ = JSON.parse(SC$scripts$quine().split\`\t\`[_SPLIT_INDEX_])${undefinedIsReferenced ? ", _UNDEFINED_" : ""}\n`, blockStatementIndex + 1);
785
- comment = JSON.stringify(jsonValues[0]);
786
- }
787
- }
788
- else {
789
- script = (0, lib_1.stringSplice)(script, `\nlet [ ${jsonValues.map((_, i) => `_JSON_VALUE_${i}_`).join(", ")} ] = JSON.parse(SC$scripts$quine().split\`\t\`[_SPLIT_INDEX_])${undefinedIsReferenced ? ", _UNDEFINED_" : ""}\n`, blockStatementIndex + 1);
790
- comment = JSON.stringify(jsonValues);
791
- }
792
- }
793
- else
794
- script = script.replace(/_UNDEFINED_/g, "void 0");
795
- script = (await (0, terser_1.minify)(script, {
796
- ecma: 2015,
797
- compress: {
798
- passes: Infinity,
799
- unsafe: true,
800
- unsafe_arrows: true,
801
- unsafe_comps: true,
802
- unsafe_symbols: true,
803
- unsafe_methods: true,
804
- unsafe_proto: true,
805
- unsafe_regexp: true,
806
- unsafe_undefined: true
807
- },
808
- format: { semicolons: false }
809
- })).code || "";
810
- // this step affects the chracter count and can't be done after the count comparison
811
- if (comment != null) {
812
- script = (0, lib_1.stringSplice)(script, `${autocomplete ? `//${autocomplete}\n` : ""}\n//\t${comment}\t\n`, getFunctionBodyStart(script) + 1);
813
- for (const [i, part] of script.split("\t").entries()) {
814
- if (part != comment)
815
- continue;
816
- script = script.replace("_SPLIT_INDEX_", (await (0, terser_1.minify)(`$(${i})`, { ecma: 2015 })).code.match(/\$\((.+)\)/)[1]);
817
- break;
818
- }
819
- }
820
- // if the script has a comment, it's gonna contain `SC$scripts$quine()`
821
- // which is gonna eventually compile to `#fs.scripts.quine()` which contains
822
- // an extra character so we have to account for that
823
- if ((0, lib_1.hackmudLength)(scriptBeforeJSONValueReplacement) <= ((0, lib_1.hackmudLength)(script) + Number(hasComment))) {
824
- script = scriptBeforeJSONValueReplacement;
825
- if (autocomplete)
826
- script = (0, lib_1.stringSplice)(script, `//${autocomplete}\n`, getFunctionBodyStart(script) + 1);
827
- }
828
- script = script
829
- .replace(/^function\s*\w+\(/, "function(")
830
- .replace(/SC\$([a-zA-Z_][a-zA-Z0-9_]*)\$([a-zA-Z_][a-zA-Z0-9_]*)\(/g, `#${"nlmhf"[seclevel]}s.$1.$2(`)
831
- .replace(/\$D\(/g, "#D(")
832
- .replace(/\$FMCL/g, "#FMCL")
833
- .replace(/\$G/g, "#G")
834
- .replace(/DB\$/g, "#db.");
835
- return {
836
- srcLength,
837
- script,
838
- warnings
839
- };
840
- }
841
- exports.processScript = processScript;
842
- function getFunctionBodyStart(code) {
843
- const tokens = (0, acorn_1.tokenizer)(code, { ecmaVersion: 2015 });
844
- tokens.getToken(); // function
845
- tokens.getToken(); // name
846
- tokens.getToken(); // (
847
- let nests = 1;
848
- while (nests) {
849
- const token = tokens.getToken();
850
- if (token.type == acorn_1.tokTypes.parenL)
851
- nests++;
852
- else if (token.type == acorn_1.tokTypes.parenR)
853
- nests--;
854
- }
855
- return tokens.getToken().start; // {
856
- }
857
- exports.getFunctionBodyStart = getFunctionBodyStart;
1
+ import 'acorn';
2
+ import 'chokidar';
3
+ import 'escodegen';
4
+ import 'esprima';
5
+ import 'esquery';
6
+ import 'fs';
7
+ import 'path';
8
+ import 'terser';
9
+ import 'typescript';
10
+ export { g as generateTypings, e as getFunctionBodyStart, p as processScript, b as pull, d as push, s as supportedExtensions, a as syncMacros, t as test, c as watch } from './shared.js';