hackmud-script-manager 0.13.0-c461329 → 0.13.0-f373e9c

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. package/assert-1b7dada8.js +1 -0
  2. package/bin/hsm.d.ts +2 -0
  3. package/bin/hsm.js +2 -0
  4. package/generateTypings.d.ts +2 -0
  5. package/generateTypings.js +1 -0
  6. package/index.d.ts +15 -0
  7. package/index.js +1 -0
  8. package/package.json +35 -11
  9. package/processScript/index.d.ts +33 -0
  10. package/processScript/index.js +1 -0
  11. package/processScript/minify.d.ts +14 -0
  12. package/processScript/minify.js +1 -0
  13. package/processScript/postprocess.d.ts +2 -0
  14. package/processScript/postprocess.js +1 -0
  15. package/processScript/preprocess.d.ts +13 -0
  16. package/processScript/preprocess.js +1 -0
  17. package/processScript/shared.d.ts +3 -0
  18. package/processScript/shared.js +1 -0
  19. package/processScript/transform.d.ts +22 -0
  20. package/processScript/transform.js +1 -0
  21. package/pull.d.ts +9 -0
  22. package/pull.js +1 -0
  23. package/push.d.ts +28 -0
  24. package/push.js +1 -0
  25. package/spliceString-2c6f214f.js +1 -0
  26. package/syncMacros.d.ts +5 -0
  27. package/syncMacros.js +1 -0
  28. package/test.d.ts +6 -0
  29. package/test.js +1 -0
  30. package/watch.d.ts +14 -0
  31. package/watch.js +1 -0
  32. package/.gitattributes +0 -1
  33. package/.github/workflows/codeql-analysis.yml +0 -39
  34. package/.github/workflows/publish.yml +0 -42
  35. package/.vscode/settings.json +0 -6
  36. package/babel.config.json +0 -6
  37. package/rollup.config.js +0 -110
  38. package/scripts/build-package-json.js +0 -36
  39. package/scripts/jsconfig.json +0 -5
  40. package/scripts/version-dev.js +0 -25
  41. package/src/bin/hsm.ts +0 -505
  42. package/src/constants.json +0 -3
  43. package/src/generateTypings.ts +0 -116
  44. package/src/index.ts +0 -19
  45. package/src/modules.d.ts +0 -5
  46. package/src/processScript/index.ts +0 -198
  47. package/src/processScript/minify.ts +0 -529
  48. package/src/processScript/postprocess.ts +0 -38
  49. package/src/processScript/preprocess.ts +0 -146
  50. package/src/processScript/transform.ts +0 -760
  51. package/src/pull.ts +0 -16
  52. package/src/push.ts +0 -314
  53. package/src/syncMacros.ts +0 -52
  54. package/src/test.ts +0 -59
  55. package/src/tsconfig.json +0 -20
  56. package/src/watch.ts +0 -156
  57. package/tsconfig.json +0 -12
@@ -1,529 +0,0 @@
1
- import babelGenerator from "@babel/generator"
2
- import { parse } from "@babel/parser"
3
- import babelTraverse from "@babel/traverse"
4
- import t, { Expression } from "@babel/types"
5
- import { assert, countHackmudCharacters, spliceString } from "@samual/lib"
6
- import { tokenizer as tokenize, tokTypes as tokenTypes } from "acorn"
7
- import * as terser from "terser"
8
-
9
- const { default: generate } = babelGenerator as any as typeof import("@babel/generator")
10
- const { default: traverse } = babelTraverse as any as typeof import("@babel/traverse")
11
-
12
- type MinifyOptions = {
13
- /** 11 a-z 0-9 characters */
14
- uniqueID: string
15
-
16
- /** whether to mangle function and class names (defaults to `false`) */
17
- mangleNames: boolean
18
- }
19
-
20
- // TODO when there are more than 3 references to `$G`, place a `let _GLOBAL_0_ = $G` at the top and replace references with `_GLOBAL_0_`
21
- // TODO move autocomplete stuff outside this function
22
- // TODO allow not mangling class and function names
23
-
24
- /**
25
- * @param code compiled code and/or hackmud compatible code
26
- * @param autocomplete the comment inserted after the function signature
27
- * @param options {@link MinifyOptions details}
28
- */
29
- export async function minify(code: string, autocomplete: string, {
30
- uniqueID = "00000000000",
31
- mangleNames = false
32
- }: Partial<MinifyOptions> = {}) {
33
- assert(uniqueID.match(/^\w{11}$/))
34
-
35
- const jsonValues: any[] = []
36
- let undefinedIsReferenced = false
37
-
38
- // remove dead code (so we don't waste chracters quine cheating strings
39
- // that aren't even used)
40
- code = (await terser.minify(code, {
41
- ecma: 2015,
42
- parse: { bare_returns: true },
43
- compress: {
44
- passes: Infinity,
45
- unsafe: true,
46
- booleans: false,
47
- sequences: false
48
- },
49
- keep_classnames: !mangleNames,
50
- keep_fnames: !mangleNames
51
- })).code || ""
52
-
53
- let scriptBeforeJSONValueReplacement
54
-
55
- {
56
- // BUG when this script is used, the source char count is off
57
-
58
- const file = await parse(code)
59
-
60
- traverse(file, {
61
- MemberExpression({ node: memberExpression }) {
62
- if (memberExpression.computed)
63
- return
64
-
65
- assert(memberExpression.property.type == "Identifier")
66
-
67
- if (memberExpression.property.name == "prototype") {
68
- memberExpression.computed = true
69
- memberExpression.property = t.identifier(`_PROTOTYPE_PROPERTY_${uniqueID}_`)
70
- } else if (memberExpression.property.name == "__proto__") {
71
- memberExpression.computed = true
72
- memberExpression.property = t.identifier(`_PROTO_PROPERTY_${uniqueID}_`)
73
- }
74
- }
75
- })
76
-
77
- scriptBeforeJSONValueReplacement = (await terser.minify(generate(file!).code, {
78
- ecma: 2015,
79
- compress: {
80
- passes: Infinity,
81
- unsafe: true,
82
- unsafe_arrows: true,
83
- unsafe_comps: true,
84
- unsafe_symbols: true,
85
- unsafe_methods: true,
86
- unsafe_proto: true,
87
- unsafe_regexp: true,
88
- unsafe_undefined: true,
89
- sequences: false
90
- },
91
- format: { semicolons: false },
92
- keep_classnames: !mangleNames,
93
- keep_fnames: !mangleNames
94
- })).code!
95
- .replace(new RegExp(`_PROTOTYPE_PROPERTY_${uniqueID}_`, "g"), `"prototype"`)
96
- .replace(new RegExp(`_PROTO_PROPERTY_${uniqueID}_`, "g"), `"__proto__"`)
97
- }
98
-
99
- let comment: string | null = null
100
- let hasComment = false
101
-
102
- {
103
- const file = await parse(code)
104
- const promises: Promise<any>[] = []
105
-
106
- traverse(file, {
107
- FunctionDeclaration(path) {
108
- path.traverse({
109
- Function(path) {
110
- if (path.parent.type != "CallExpression" && path.parentKey != "callee")
111
- path.skip()
112
- },
113
-
114
- Loop(path) {
115
- path.skip()
116
- },
117
-
118
- ObjectExpression(path) {
119
- const o: Record<string, unknown> = {}
120
-
121
- if (parseObjectExpression(path.node, o))
122
- path.replaceWith(t.identifier(`_JSON_VALUE_${jsonValues.push(o) - 1}_${uniqueID}_`))
123
- },
124
-
125
- ArrayExpression(path) {
126
- const o: unknown[] = []
127
-
128
- if (parseArrayExpression(path.node, o))
129
- path.replaceWith(t.identifier(`_JSON_VALUE_${jsonValues.push(o) - 1}_${uniqueID}_`))
130
- }
131
- })
132
-
133
- path.traverse({
134
- TemplateLiteral(path) {
135
- const templateLiteral = path.node
136
- let replacement: babel.Node = t.stringLiteral(templateLiteral.quasis[0].value.cooked!)
137
-
138
- for (let i = 0; i < templateLiteral.expressions.length; i++) {
139
- const expression = templateLiteral.expressions[i] as Expression
140
- const templateElement = templateLiteral.quasis[i + 1]
141
-
142
- replacement = t.binaryExpression(
143
- "+",
144
- replacement,
145
- expression
146
- )
147
-
148
- if (!templateElement.value.cooked)
149
- continue
150
-
151
- replacement = t.binaryExpression(
152
- "+",
153
- replacement,
154
- t.stringLiteral(templateElement.value.cooked!)
155
- )
156
- }
157
-
158
- path.replaceWith(replacement)
159
- },
160
-
161
- MemberExpression({ node: memberExpression }) {
162
- if (memberExpression.computed)
163
- return
164
-
165
- assert(memberExpression.property.type == "Identifier")
166
-
167
- if (memberExpression.property.name.length < 3)
168
- return
169
-
170
- memberExpression.computed = true
171
- memberExpression.property = t.stringLiteral(memberExpression.property.name)
172
- },
173
-
174
- UnaryExpression(path) {
175
- if (path.node.operator == "void") {
176
- if (path.node.argument.type == "NumericLiteral" && !path.node.argument.value) {
177
- path.replaceWith(t.identifier(`_UNDEFINED_${uniqueID}_`))
178
- undefinedIsReferenced = true
179
- }
180
- } else if (path.node.operator == "-" && path.node.argument.type == "NumericLiteral") {
181
- const value = -path.node.argument.value
182
-
183
- promises.push((async () => {
184
- if ((await minifyNumber(value)).length <= 3)
185
- return
186
-
187
- if (path.parentKey == "key" && path.parent.type == "ObjectProperty")
188
- path.parent.computed = true
189
-
190
- let jsonValueIndex = jsonValues.indexOf(value)
191
-
192
- if (jsonValueIndex == -1)
193
- jsonValueIndex += jsonValues.push(value)
194
-
195
- path.replaceWith(t.identifier(`_JSON_VALUE_${jsonValueIndex}_${uniqueID}_`))
196
- })())
197
-
198
- path.skip()
199
- }
200
- },
201
-
202
- NullLiteral(path) {
203
- let jsonValueIndex = jsonValues.indexOf(null)
204
-
205
- if (jsonValueIndex == -1)
206
- jsonValueIndex += jsonValues.push(null)
207
-
208
- path.replaceWith(t.identifier(`_JSON_VALUE_${jsonValueIndex}_${uniqueID}_`))
209
- },
210
-
211
- BooleanLiteral(path) {
212
- let jsonValueIndex = jsonValues.indexOf(path.node.value)
213
-
214
- if (jsonValueIndex == -1)
215
- jsonValueIndex += jsonValues.push(path.node.value)
216
-
217
- path.replaceWith(t.identifier(`_JSON_VALUE_${jsonValueIndex}_${uniqueID}_`))
218
- },
219
-
220
- NumericLiteral(path) {
221
- promises.push((async () => {
222
- if ((await minifyNumber(path.node.value)).length <= 3)
223
- return
224
-
225
- if (path.parentKey == "key" && path.parent.type == "ObjectProperty")
226
- path.parent.computed = true
227
-
228
- let jsonValueIndex = jsonValues.indexOf(path.node.value)
229
-
230
- if (jsonValueIndex == -1)
231
- jsonValueIndex += jsonValues.push(path.node.value)
232
-
233
- path.replaceWith(t.identifier(`_JSON_VALUE_${jsonValueIndex}_${uniqueID}_`))
234
- })())
235
- },
236
-
237
- StringLiteral(path) {
238
- if (path.node.value.includes("\u0000") || path.toString().length < 4)
239
- return
240
-
241
- if (path.parentKey == "key" && path.parent.type == "ObjectProperty")
242
- path.parent.computed = true
243
-
244
- let jsonValueIndex = jsonValues.indexOf(path.node.value)
245
-
246
- if (jsonValueIndex == -1)
247
- jsonValueIndex += jsonValues.push(path.node.value)
248
-
249
- path.replaceWith(t.identifier(`_JSON_VALUE_${jsonValueIndex}_${uniqueID}_`))
250
- },
251
-
252
- ObjectProperty({ node }) {
253
- if (node.computed || node.key.type != "Identifier" || node.key.name.length < 4)
254
- return
255
-
256
- let jsonValueIndex = jsonValues.indexOf(node.key.name)
257
-
258
- if (jsonValueIndex == -1)
259
- jsonValueIndex += jsonValues.push(node.key.name)
260
-
261
- node.computed = true
262
- node.key = t.identifier(`_JSON_VALUE_${jsonValueIndex}_${uniqueID}_`)
263
- }
264
- })
265
-
266
- path.skip()
267
- }
268
- })
269
-
270
- await Promise.all(promises)
271
-
272
- const [ functionDeclaration ] = file.program.body
273
-
274
- assert(functionDeclaration.type == "FunctionDeclaration")
275
-
276
- if (jsonValues.length) {
277
- hasComment = true
278
-
279
- if (jsonValues.length == 1) {
280
- if (typeof jsonValues[0] == "string" && !jsonValues[0].includes("\n") && !jsonValues[0].includes("\t")) {
281
- const variableDeclaration = t.variableDeclaration(
282
- "let",
283
- [
284
- t.variableDeclarator(
285
- t.identifier(`_JSON_VALUE_0_${uniqueID}_`),
286
- t.memberExpression(
287
- t.taggedTemplateExpression(
288
- t.memberExpression(
289
- t.callExpression(t.identifier(`$${uniqueID}$SUBSCRIPT$scripts$quine`), []),
290
- t.identifier("split")
291
- ),
292
- t.templateLiteral([ t.templateElement({ raw: "\t", cooked: "\t" }, true) ], [])
293
- ),
294
- t.identifier(`$${uniqueID}$SPLIT_INDEX`),
295
- true
296
- )
297
- )
298
- ]
299
- )
300
-
301
- if (undefinedIsReferenced)
302
- variableDeclaration.declarations.push(t.variableDeclarator(t.identifier(`_UNDEFINED_${uniqueID}_`)))
303
-
304
- functionDeclaration.body.body.unshift(variableDeclaration)
305
-
306
- comment = jsonValues[0]
307
- } else {
308
- const variableDeclaration = t.variableDeclaration(
309
- "let",
310
- [
311
- t.variableDeclarator(
312
- t.identifier(`_JSON_VALUE_0_${uniqueID}_`),
313
- t.callExpression(
314
- t.memberExpression(
315
- t.identifier("JSON"),
316
- t.identifier("parse")
317
- ),
318
- [
319
- t.memberExpression(
320
- t.taggedTemplateExpression(
321
- t.memberExpression(
322
- t.callExpression(t.identifier(`$${uniqueID}$SUBSCRIPT$scripts$quine`), []),
323
- t.identifier("split")
324
- ),
325
- t.templateLiteral([ t.templateElement({ raw: "\t", cooked: "\t" }, true) ], [])
326
- ),
327
- t.identifier(`$${uniqueID}$SPLIT_INDEX`),
328
- true
329
- )
330
- ]
331
- )
332
- )
333
- ]
334
- )
335
-
336
- if (undefinedIsReferenced)
337
- variableDeclaration.declarations.push(t.variableDeclarator(t.identifier(`_UNDEFINED_${uniqueID}_`)))
338
-
339
- functionDeclaration.body.body.unshift(variableDeclaration)
340
-
341
- comment = JSON.stringify(jsonValues[0])
342
- }
343
- } else {
344
- const variableDeclaration = t.variableDeclaration(
345
- "let",
346
- [
347
- t.variableDeclarator(
348
- t.arrayPattern(jsonValues.map((_, i) => t.identifier(`_JSON_VALUE_${i}_${uniqueID}_`))),
349
- t.callExpression(
350
- t.memberExpression(
351
- t.identifier("JSON"),
352
- t.identifier("parse")
353
- ),
354
- [
355
- t.memberExpression(
356
- t.taggedTemplateExpression(
357
- t.memberExpression(
358
- t.callExpression(t.identifier(`$${uniqueID}$SUBSCRIPT$scripts$quine`), []),
359
- t.identifier("split")
360
- ),
361
- t.templateLiteral([ t.templateElement({ raw: "\t", cooked: "\t" }, true) ], [])
362
- ),
363
- t.identifier(`$${uniqueID}$SPLIT_INDEX`),
364
- true
365
- )
366
- ]
367
- )
368
- )
369
- ]
370
- )
371
-
372
- if (undefinedIsReferenced)
373
- variableDeclaration.declarations.push(t.variableDeclarator(t.identifier(`_UNDEFINED_${uniqueID}_`)))
374
-
375
- functionDeclaration.body.body.unshift(variableDeclaration)
376
-
377
- comment = JSON.stringify(jsonValues)
378
- }
379
- } else if (undefinedIsReferenced) {
380
- functionDeclaration.body.body.unshift(
381
- t.variableDeclaration(
382
- "let",
383
- [ t.variableDeclarator(t.identifier(`_UNDEFINED_${uniqueID}_`)) ]
384
- )
385
- )
386
- }
387
-
388
- code = generate(file!).code
389
- }
390
-
391
- code = (await terser.minify(code, {
392
- ecma: 2015,
393
- compress: {
394
- passes: Infinity,
395
- unsafe: true,
396
- unsafe_arrows: true,
397
- unsafe_comps: true,
398
- unsafe_symbols: true,
399
- unsafe_methods: true,
400
- unsafe_proto: true,
401
- unsafe_regexp: true,
402
- unsafe_undefined: true,
403
- sequences: false
404
- },
405
- format: { semicolons: false },
406
- keep_classnames: !mangleNames,
407
- keep_fnames: !mangleNames
408
- })).code || ""
409
-
410
-
411
- // this step affects the character count and can't be done after the count comparison
412
- if (comment != null) {
413
- code = spliceString(code, `${autocomplete ? `//${autocomplete}\n` : ""}\n//\t${comment}\t\n`, getFunctionBodyStart(code) + 1)
414
-
415
- for (const [ i, part ] of code.split("\t").entries()) {
416
- if (part == comment) {
417
- code = code.replace(`$${uniqueID}$SPLIT_INDEX`, await minifyNumber(i))
418
- break
419
- }
420
- }
421
- }
422
-
423
- // if the script has a comment, it's gonna contain `SC$scripts$quine()`
424
- // which is gonna eventually compile to `#fs.scripts.quine()` which contains
425
- // an extra character so we have to account for that
426
- if (countHackmudCharacters(scriptBeforeJSONValueReplacement) <= (countHackmudCharacters(code) + Number(hasComment))) {
427
- code = scriptBeforeJSONValueReplacement
428
-
429
- if (autocomplete)
430
- code = spliceString(code, `//${autocomplete}\n`, getFunctionBodyStart(code) + 1)
431
- }
432
-
433
- return code
434
- }
435
-
436
- export default minify
437
-
438
- function parseObjectExpression(node: babel.types.ObjectExpression, o: Record<string, unknown>) {
439
- if (!node.properties.length)
440
- return false
441
-
442
- for (const property of node.properties) {
443
- if (property.type != "ObjectProperty" || property.computed)
444
- return false
445
-
446
- assert(property.key.type == "Identifier" || property.key.type == "NumericLiteral" || property.key.type == "StringLiteral")
447
-
448
- if (property.value.type == "ArrayExpression") {
449
- const childArray: unknown[] = []
450
-
451
- if (parseArrayExpression(property.value, childArray))
452
- o[property.key.type == "Identifier" ? property.key.name : property.key.value] = childArray
453
- else
454
- return false
455
- } else if (property.value.type == "ObjectExpression") {
456
- const childObject: Record<string, unknown> = {}
457
-
458
- if (parseObjectExpression(property.value, childObject))
459
- o[property.key.type == "Identifier" ? property.key.name : property.key.value] = childObject
460
- else
461
- return false
462
- } else if (property.value.type == "NullLiteral")
463
- o[property.key.type == "Identifier" ? property.key.name : property.key.value] = null
464
- else if (property.value.type == "BooleanLiteral" || property.value.type == "NumericLiteral" || property.value.type == "StringLiteral")
465
- o[property.key.type == "Identifier" ? property.key.name : property.key.value] = property.value.value
466
- else
467
- return false
468
- }
469
-
470
- return true
471
- }
472
-
473
- function parseArrayExpression(node: babel.types.ArrayExpression, o: unknown[]) {
474
- if (!node.elements.length)
475
- return false
476
-
477
- for (const element of node.elements) {
478
- if (!element)
479
- return false
480
-
481
- if (element.type == "ArrayExpression") {
482
- const childArray: unknown[] = []
483
-
484
- if (parseArrayExpression(element, childArray))
485
- childArray.push(childArray)
486
- else
487
- return false
488
- } else if (element.type == "ObjectExpression") {
489
- const childObject: Record<string, unknown> = {}
490
-
491
- if (parseObjectExpression(element, childObject))
492
- o.push(childObject)
493
- else
494
- return false
495
- } else if (element.type == "NullLiteral")
496
- o.push(null)
497
- else if (element.type == "BooleanLiteral" || element.type == "NumericLiteral" || element.type == "StringLiteral")
498
- o.push(element.value)
499
- else
500
- return false
501
- }
502
-
503
- return true
504
- }
505
-
506
- async function minifyNumber(number: number) {
507
- return (await terser.minify(`$(${number})`, { ecma: 2015 })).code!.match(/\$\((.+)\)/)![1]
508
- }
509
-
510
- function getFunctionBodyStart(code: string) {
511
- const tokens = tokenize(code, { ecmaVersion: 2015 })
512
-
513
- tokens.getToken() // function
514
- tokens.getToken() // name
515
- tokens.getToken() // (
516
-
517
- let nests = 1
518
-
519
- while (nests) {
520
- const token = tokens.getToken()
521
-
522
- if (token.type == tokenTypes.parenL)
523
- nests++
524
- else if (token.type == tokenTypes.parenR)
525
- nests--
526
- }
527
-
528
- return tokens.getToken().start // {
529
- }
@@ -1,38 +0,0 @@
1
- import { findMatches, spliceString } from "@samual/lib"
2
-
3
- export function postprocess(code: string, seclevel: number, uniqueID: string) {
4
- code = code.replace(/^function\s*\w+\(/, "function(")
5
-
6
- for (const { index, match } of [ ...findMatches(new RegExp(`\\$${uniqueID}\\$[\\w$]+`, "g"), code) ].reverse()) {
7
- const [ type, ...args ] = match.slice(13).split("$")
8
-
9
- switch (type) {
10
- case "SUBSCRIPT": {
11
- code = spliceString(code, `#${"nlmhf"[seclevel]}s.${args[0]}.${args[1]}`, index, match.length)
12
- } break
13
-
14
- case "DEBUG": {
15
- code = spliceString(code, `#D`, index, match.length)
16
- } break
17
-
18
- case "FMCL": {
19
- code = spliceString(code, `#FMCL`, index, match.length)
20
- } break
21
-
22
- case "GLOBAL": {
23
- code = spliceString(code, `#G`, index, match.length)
24
- } break
25
-
26
- case "DB": {
27
- code = spliceString(code, `#db.${args[0]}`, index, match.length)
28
- } break
29
-
30
- default:
31
- throw new Error(`unknown preprocessor directive type "${type}"`)
32
- }
33
- }
34
-
35
- return code
36
- }
37
-
38
- export default postprocess
@@ -1,146 +0,0 @@
1
- import { parse } from "@babel/parser"
2
- import { assert, spliceString } from "@samual/lib"
3
-
4
- export type PreprocessOptions = {
5
- /** 11 a-z 0-9 characters */
6
- uniqueID: string
7
- }
8
-
9
- /**
10
- * @param code source code to be preprocessed
11
- * @param options {@link PreprocessOptions details}
12
- */
13
- export function preprocess(code: string, { uniqueID = "00000000000" }: Partial<PreprocessOptions> = {}) {
14
- assert(uniqueID.match(/^\w{11}$/))
15
-
16
- let preScriptComments: string | undefined
17
- let autocomplete: string | undefined
18
-
19
- [ , preScriptComments, code, autocomplete ] = code.match(/((?:^\s*\/\/.*\n)*)\s*((?:.+?\/\/\s*(.+?)\s*$)?[^]*)/m)!
20
-
21
- if (code.match(/(?:SC|DB)\$/))
22
- throw new Error("SC$ and DB$ are protected and cannot appear in a script")
23
-
24
- let seclevel: number | undefined
25
-
26
- for (const line of preScriptComments.split("\n")) {
27
- let [ , autocompleteMatch, seclevelMatch ] = (line.match(/^\s*\/\/\s*(?:@autocomplete\s*([^\s].*?)|@seclevel\s*([^\s].*?))\s*$/) || []) as [ never, string | undefined, string | undefined ]
28
-
29
- if (autocompleteMatch)
30
- autocomplete = autocompleteMatch
31
- else if (seclevelMatch) {
32
- if (seclevelMatch.match(/^(?:fullsec|f|4|fs|full)$/i))
33
- seclevel = 4
34
- else if (seclevelMatch.match(/^(?:highsec|h|3|hs|high)$/i))
35
- seclevel = 3
36
- else if (seclevelMatch.match(/^(?:midsec|m|2|ms|mid)$/i))
37
- seclevel = 2
38
- else if (seclevelMatch.match(/^(?:lowsec|l|1|ls|low)$/i))
39
- seclevel = 1
40
- else if (seclevelMatch.match(/^(?:nullsec|n|0|ns|null)$/i))
41
- seclevel = 0
42
- }
43
- }
44
-
45
- // TODO move this over to using the new system for finding subscripts
46
-
47
- let detectedSeclevel = 4
48
-
49
- if (code.match(/[#$][n0]s\.[a-z_][a-z_0-9]{0,24}\.[a-z_][a-z_0-9]{0,24}\(/))
50
- detectedSeclevel = 0
51
- else if (code.match(/[#$][l1]s\.[a-z_][a-z_0-9]{0,24}\.[a-z_][a-z_0-9]{0,24}\(/))
52
- detectedSeclevel = 1
53
- else if (code.match(/[#$][m2]s\.[a-z_][a-z_0-9]{0,24}\.[a-z_][a-z_0-9]{0,24}\(/))
54
- detectedSeclevel = 2
55
- else if (code.match(/[#$][h3]s\.[a-z_][a-z_0-9]{0,24}\.[a-z_][a-z_0-9]{0,24}\(/))
56
- detectedSeclevel = 3
57
-
58
- const seclevelNames = [ "NULLSEC", "LOWSEC", "MIDSEC", "HIGHSEC", "FULLSEC" ]
59
-
60
- if (seclevel == undefined)
61
- seclevel = detectedSeclevel
62
- else if (detectedSeclevel < seclevel)
63
- // TODO replace with a warning and build script anyway
64
- throw new Error(`detected seclevel ${seclevelNames[detectedSeclevel]} is lower than stated seclevel ${seclevelNames[seclevel]}`)
65
-
66
- const semicolons = code.match(/;/g)?.length ?? 0
67
- const sourceCode = code
68
-
69
- code = code.replace(/^function\s*\(/, "export default function (")
70
-
71
- // TODO I'm not actually doing anything with this yet
72
- let file
73
-
74
- while (true) {
75
- let error
76
-
77
- try {
78
- file = parse(code, {
79
- plugins: [
80
- "typescript",
81
- [ "decorators", { decoratorsBeforeExport: true } ],
82
- "doExpressions",
83
- "functionBind",
84
- "functionSent",
85
- "partialApplication",
86
- [ "pipelineOperator", { proposal: "hack", topicToken: "%" } ],
87
- "throwExpressions",
88
- [ "recordAndTuple", { syntaxType: "hash" } ],
89
- "classProperties",
90
- "classPrivateProperties",
91
- "classPrivateMethods",
92
- "logicalAssignment",
93
- "numericSeparator",
94
- "nullishCoalescingOperator",
95
- "optionalChaining",
96
- "optionalCatchBinding",
97
- "objectRestSpread"
98
- ],
99
- sourceType: "module"
100
- })
101
- break
102
- } catch (error_) {
103
- assert(error_ instanceof SyntaxError)
104
-
105
- error = error_ as SyntaxError & {
106
- pos: number
107
- code: string
108
- reasonCode: String
109
- }
110
- }
111
-
112
- if (error.code != "BABEL_PARSER_SYNTAX_ERROR" || error.reasonCode != "PrivateInExpectedIn") {
113
- console.log(code.slice(error.pos).match(/.+/)?.[0])
114
- throw error
115
- }
116
-
117
- const codeSlice = code.slice(error.pos)
118
-
119
- let match
120
-
121
- // TODO detect typos and warn e.g. we throw on `#db.ObjectID(` and it makes it look like we don't support it
122
- if (match = codeSlice.match(/^#[fhmln43210]s\.scripts\.quine\(\)/))
123
- code = spliceString(code, JSON.stringify(sourceCode), error.pos, match[0].length)
124
- else if (match = codeSlice.match(/^#[fhmln43210]?s\.([a-z_][a-z_0-9]{0,24})\.([a-z_][a-z_0-9]{0,24})\(/))
125
- code = spliceString(code, `$${uniqueID}$SUBSCRIPT$${match[1]}$${match[2]}(`, error.pos, match[0].length)
126
- else if (match = codeSlice.match(/^#D\(/))
127
- code = spliceString(code, `$${uniqueID}$DEBUG(`, error.pos, match[0].length)
128
- else if (match = codeSlice.match(/^#FMCL/))
129
- code = spliceString(code, `$${uniqueID}$FMCL`, error.pos, match[0].length)
130
- else if (match = codeSlice.match(/^#G/))
131
- code = spliceString(code, `$${uniqueID}$GLOBAL`, error.pos, match[0].length)
132
- else if (match = codeSlice.match(/^#db\.(i|r|f|u|u1|us|ObjectId)\(/))
133
- code = spliceString(code, `$${uniqueID}$DB$${match[1]}(`, error.pos, match[0].length)
134
- else
135
- throw error
136
- }
137
-
138
- return {
139
- semicolons,
140
- autocomplete,
141
- seclevel,
142
- code
143
- }
144
- }
145
-
146
- export default preprocess