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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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';