hackmud-script-manager 0.19.1-003b022 → 0.19.1-07fc9cb

Sign up to get free protection for your applications and to get access to all the features.
@@ -29,7 +29,7 @@ import { supportedExtensions } from "../constants.js"
29
29
  import { minify } from "./minify.js"
30
30
  import { postprocess } from "./postprocess.js"
31
31
  import { preprocess } from "./preprocess.js"
32
- import { includesIllegalString, replaceUnsafeStrings } from "./shared.js"
32
+ import { getReferencePathsToGlobal, includesIllegalString, replaceUnsafeStrings } from "./shared.js"
33
33
  import { transform } from "./transform.js"
34
34
  import "@samual/lib/countHackmudCharacters"
35
35
  import "@samual/lib/spliceString"
@@ -39,140 +39,110 @@ import "import-meta-resolve"
39
39
  import "@samual/lib/clearObject"
40
40
  const { format } = prettier,
41
41
  { default: generate } = babelGenerator,
42
- { default: traverse } = babelTraverse,
43
- processScript = async (
44
- code,
45
- {
46
- minify: shouldMinify = !0,
47
- uniqueID = Math.floor(Math.random() * 2 ** 52)
48
- .toString(36)
49
- .padStart(11, "0"),
50
- scriptUser = "UNKNOWN",
51
- scriptName = "UNKNOWN",
52
- filePath,
53
- mangleNames = !1,
54
- forceQuineCheats
55
- } = {}
56
- ) => {
57
- assert(/^\w{11}$/.exec(uniqueID))
58
- const sourceCode = code
59
- let autocomplete, statedSeclevel
60
- const autocompleteMatch = /^function\s*\(.+\/\/(?<autocomplete>.+)/.exec(code)
61
- if (autocompleteMatch) {
62
- code = "export default " + code
63
- ;({ autocomplete } = autocompleteMatch.groups)
64
- } else
65
- for (const line of code.split("\n")) {
66
- const comment = /^\s*\/\/(?<commentContent>.+)/.exec(line)
67
- if (!comment) break
68
- const commentContent = comment.groups.commentContent.trim()
69
- if (commentContent.startsWith("@autocomplete ")) autocomplete = commentContent.slice(14).trimStart()
70
- else if (commentContent.startsWith("@seclevel ")) {
71
- const seclevelString = commentContent.slice(10).trimStart().toLowerCase()
72
- switch (seclevelString) {
73
- case "fullsec":
74
- case "full":
75
- case "fs":
76
- case "4s":
77
- case "f":
78
- case "4":
79
- statedSeclevel = 4
80
- break
81
- case "highsec":
82
- case "high":
83
- case "hs":
84
- case "3s":
85
- case "h":
86
- case "3":
87
- statedSeclevel = 3
88
- break
89
- case "midsec":
90
- case "mid":
91
- case "ms":
92
- case "2s":
93
- case "m":
94
- case "2":
95
- statedSeclevel = 2
96
- break
97
- case "lowsec":
98
- case "low":
99
- case "ls":
100
- case "1s":
101
- case "l":
102
- case "1":
103
- statedSeclevel = 1
104
- break
105
- case "nullsec":
106
- case "null":
107
- case "ns":
108
- case "0s":
109
- case "n":
110
- case "0":
111
- statedSeclevel = 0
112
- break
113
- default:
114
- throw Error(`unrecognised seclevel "${seclevelString}"`)
115
- }
42
+ { default: traverse } = babelTraverse
43
+ async function processScript(
44
+ code,
45
+ {
46
+ minify: shouldMinify = !0,
47
+ uniqueID = Math.floor(Math.random() * 2 ** 52)
48
+ .toString(36)
49
+ .padStart(11, "0"),
50
+ scriptUser = "UNKNOWN",
51
+ scriptName = "UNKNOWN",
52
+ filePath,
53
+ mangleNames = !1,
54
+ forceQuineCheats
55
+ } = {}
56
+ ) {
57
+ assert(/^\w{11}$/.exec(uniqueID), "src/processScript/index.ts:78:36")
58
+ const sourceCode = code
59
+ let autocomplete, statedSeclevel
60
+ const autocompleteMatch = /^function\s*\(.+\/\/(?<autocomplete>.+)/.exec(code)
61
+ if (autocompleteMatch) {
62
+ code = "export default " + code
63
+ ;({ autocomplete } = autocompleteMatch.groups)
64
+ } else
65
+ for (const line of code.split("\n")) {
66
+ const comment = /^\s*\/\/(?<commentContent>.+)/.exec(line)
67
+ if (!comment) break
68
+ const commentContent = comment.groups.commentContent.trim()
69
+ if (commentContent.startsWith("@autocomplete ")) autocomplete = commentContent.slice(14).trimStart()
70
+ else if (commentContent.startsWith("@seclevel ")) {
71
+ const seclevelString = commentContent.slice(10).trimStart().toLowerCase()
72
+ switch (seclevelString) {
73
+ case "fullsec":
74
+ case "full":
75
+ case "fs":
76
+ case "4s":
77
+ case "f":
78
+ case "4":
79
+ statedSeclevel = 4
80
+ break
81
+ case "highsec":
82
+ case "high":
83
+ case "hs":
84
+ case "3s":
85
+ case "h":
86
+ case "3":
87
+ statedSeclevel = 3
88
+ break
89
+ case "midsec":
90
+ case "mid":
91
+ case "ms":
92
+ case "2s":
93
+ case "m":
94
+ case "2":
95
+ statedSeclevel = 2
96
+ break
97
+ case "lowsec":
98
+ case "low":
99
+ case "ls":
100
+ case "1s":
101
+ case "l":
102
+ case "1":
103
+ statedSeclevel = 1
104
+ break
105
+ case "nullsec":
106
+ case "null":
107
+ case "ns":
108
+ case "0s":
109
+ case "n":
110
+ case "0":
111
+ statedSeclevel = 0
112
+ break
113
+ default:
114
+ throw Error(`unrecognised seclevel "${seclevelString}"`)
116
115
  }
117
116
  }
118
- assert(/^\w{11}$/.exec(uniqueID))
119
- const plugins = [
120
- [babelPluginProposalDecorators.default, { decoratorsBeforeExport: !0 }],
121
- [babelPluginTransformClassProperties.default],
122
- [babelPluginTransformClassStaticBlock.default],
123
- [babelPluginTransformPrivatePropertyInObject.default],
124
- [babelPluginTransformLogicalAssignmentOperators.default],
125
- [babelPluginTransformNumericSeparator.default],
126
- [babelPluginTransformNullishCoalescingOperator.default],
127
- [babelPluginTransformOptionalChaining.default],
128
- [babelPluginTransformOptionalCatchBinding.default],
129
- [babelPluginTransformJsonStrings.default],
130
- [babelPluginTransformObjectRestSpread.default],
131
- [babelPluginTransformExponentiationOperator.default],
132
- [babelPluginTransformUnicodeSetsRegex.default],
133
- [babelPluginProposalDestructuringPrivate.default],
134
- [babelPluginProposalExplicitResourceManagement.default]
135
- ]
136
- let filePathResolved
137
- if (filePath) {
138
- filePathResolved = resolve(filePath)
139
- if (filePath.endsWith(".ts"))
140
- plugins.push([
141
- (await import("@babel/plugin-transform-typescript")).default,
142
- { allowDeclareFields: !0, optimizeConstEnums: !0 }
143
- ])
144
- else {
145
- const [
146
- babelPluginProposalDoExpressions,
147
- babelPluginProposalFunctionBind,
148
- babelPluginProposalFunctionSent,
149
- babelPluginProposalPartialApplication,
150
- babelPluginProposalPipelineOperator,
151
- babelPluginProposalThrowExpressions,
152
- babelPluginProposalRecordAndTuple
153
- ] = await Promise.all([
154
- import("@babel/plugin-proposal-do-expressions"),
155
- import("@babel/plugin-proposal-function-bind"),
156
- import("@babel/plugin-proposal-function-sent"),
157
- import("@babel/plugin-proposal-partial-application"),
158
- import("@babel/plugin-proposal-pipeline-operator"),
159
- import("@babel/plugin-proposal-throw-expressions"),
160
- import("@babel/plugin-proposal-record-and-tuple")
161
- ])
162
- plugins.push(
163
- [babelPluginProposalDoExpressions.default],
164
- [babelPluginProposalFunctionBind.default],
165
- [babelPluginProposalFunctionSent.default],
166
- [babelPluginProposalPartialApplication.default],
167
- [babelPluginProposalPipelineOperator.default, { proposal: "hack", topicToken: "%" }],
168
- [babelPluginProposalThrowExpressions.default],
169
- [babelPluginProposalRecordAndTuple.default, { syntaxType: "hash", importPolyfill: !0 }]
170
- )
171
- }
172
- } else {
173
- filePathResolved = uniqueID + ".ts"
117
+ }
118
+ assert(/^\w{11}$/.exec(uniqueID), "src/processScript/index.ts:159:36")
119
+ const plugins = [
120
+ [babelPluginProposalDecorators.default, { decoratorsBeforeExport: !0 }],
121
+ [babelPluginTransformClassProperties.default],
122
+ [babelPluginTransformClassStaticBlock.default],
123
+ [babelPluginTransformPrivatePropertyInObject.default],
124
+ [babelPluginTransformLogicalAssignmentOperators.default],
125
+ [babelPluginTransformNumericSeparator.default],
126
+ [babelPluginTransformNullishCoalescingOperator.default],
127
+ [babelPluginTransformOptionalChaining.default],
128
+ [babelPluginTransformOptionalCatchBinding.default],
129
+ [babelPluginTransformJsonStrings.default],
130
+ [babelPluginTransformObjectRestSpread.default],
131
+ [babelPluginTransformExponentiationOperator.default],
132
+ [babelPluginTransformUnicodeSetsRegex.default],
133
+ [babelPluginProposalDestructuringPrivate.default],
134
+ [babelPluginProposalExplicitResourceManagement.default]
135
+ ]
136
+ let filePathResolved
137
+ if (filePath) {
138
+ filePathResolved = resolve(filePath)
139
+ if (filePath.endsWith(".ts"))
140
+ plugins.push([
141
+ (await import("@babel/plugin-transform-typescript")).default,
142
+ { allowDeclareFields: !0, optimizeConstEnums: !0 }
143
+ ])
144
+ else {
174
145
  const [
175
- babelPluginTransformTypescript,
176
146
  babelPluginProposalDoExpressions,
177
147
  babelPluginProposalFunctionBind,
178
148
  babelPluginProposalFunctionSent,
@@ -181,7 +151,6 @@ const { format } = prettier,
181
151
  babelPluginProposalThrowExpressions,
182
152
  babelPluginProposalRecordAndTuple
183
153
  ] = await Promise.all([
184
- import("@babel/plugin-transform-typescript"),
185
154
  import("@babel/plugin-proposal-do-expressions"),
186
155
  import("@babel/plugin-proposal-function-bind"),
187
156
  import("@babel/plugin-proposal-function-sent"),
@@ -191,7 +160,6 @@ const { format } = prettier,
191
160
  import("@babel/plugin-proposal-record-and-tuple")
192
161
  ])
193
162
  plugins.push(
194
- [babelPluginTransformTypescript.default, { allowDeclareFields: !0, optimizeConstEnums: !0 }],
195
163
  [babelPluginProposalDoExpressions.default],
196
164
  [babelPluginProposalFunctionBind.default],
197
165
  [babelPluginProposalFunctionSent.default],
@@ -201,116 +169,165 @@ const { format } = prettier,
201
169
  [babelPluginProposalRecordAndTuple.default, { syntaxType: "hash", importPolyfill: !0 }]
202
170
  )
203
171
  }
204
- const bundle = await rollup({
205
- input: filePathResolved,
206
- plugins: [
207
- {
208
- name: "hackmud-script-manager",
209
- transform: async code => (await preprocess(code, { uniqueID })).code
210
- },
211
- babel({ babelHelpers: "bundled", plugins, configFile: !1, extensions: supportedExtensions }),
212
- rollupPluginCommonJS(),
213
- rollupPluginNodeResolve({ extensions: supportedExtensions }),
214
- rollupPluginJSON()
215
- ],
216
- treeshake: { moduleSideEffects: !1 }
217
- }),
218
- seclevelNames = ["NULLSEC", "LOWSEC", "MIDSEC", "HIGHSEC", "FULLSEC"]
219
- code = (await bundle.generate({})).output[0].code
220
- const { file, seclevel } = transform(parse(code, { sourceType: "module" }), sourceCode, {
221
- uniqueID,
222
- scriptUser,
223
- scriptName
224
- })
225
- if (null != statedSeclevel && seclevel < statedSeclevel)
226
- throw Error(
227
- `detected seclevel ${seclevelNames[seclevel]} is lower than stated seclevel ${seclevelNames[statedSeclevel]}`
228
- )
229
- code = generate(file).code
230
- if (shouldMinify) code = await minify(file, { uniqueID, mangleNames, forceQuineCheats, autocomplete })
231
- else {
232
- traverse(file, {
233
- MemberExpression({ node: memberExpression }) {
234
- if (!memberExpression.computed) {
235
- assert("Identifier" == memberExpression.property.type)
236
- if ("prototype" == memberExpression.property.name) {
237
- memberExpression.computed = !0
238
- memberExpression.property = t.stringLiteral("prototype")
239
- } else if ("__proto__" == memberExpression.property.name) {
240
- memberExpression.computed = !0
241
- memberExpression.property = t.stringLiteral("__proto__")
242
- } else if (includesIllegalString(memberExpression.property.name)) {
243
- memberExpression.computed = !0
244
- memberExpression.property = t.stringLiteral(
245
- replaceUnsafeStrings(uniqueID, memberExpression.property.name)
246
- )
247
- }
172
+ } else {
173
+ filePathResolved = uniqueID + ".ts"
174
+ const [
175
+ babelPluginTransformTypescript,
176
+ babelPluginProposalDoExpressions,
177
+ babelPluginProposalFunctionBind,
178
+ babelPluginProposalFunctionSent,
179
+ babelPluginProposalPartialApplication,
180
+ babelPluginProposalPipelineOperator,
181
+ babelPluginProposalThrowExpressions,
182
+ babelPluginProposalRecordAndTuple
183
+ ] = await Promise.all([
184
+ import("@babel/plugin-transform-typescript"),
185
+ import("@babel/plugin-proposal-do-expressions"),
186
+ import("@babel/plugin-proposal-function-bind"),
187
+ import("@babel/plugin-proposal-function-sent"),
188
+ import("@babel/plugin-proposal-partial-application"),
189
+ import("@babel/plugin-proposal-pipeline-operator"),
190
+ import("@babel/plugin-proposal-throw-expressions"),
191
+ import("@babel/plugin-proposal-record-and-tuple")
192
+ ])
193
+ plugins.push(
194
+ [babelPluginTransformTypescript.default, { allowDeclareFields: !0, optimizeConstEnums: !0 }],
195
+ [babelPluginProposalDoExpressions.default],
196
+ [babelPluginProposalFunctionBind.default],
197
+ [babelPluginProposalFunctionSent.default],
198
+ [babelPluginProposalPartialApplication.default],
199
+ [babelPluginProposalPipelineOperator.default, { proposal: "hack", topicToken: "%" }],
200
+ [babelPluginProposalThrowExpressions.default],
201
+ [babelPluginProposalRecordAndTuple.default, { syntaxType: "hash", importPolyfill: !0 }]
202
+ )
203
+ }
204
+ const bundle = await rollup({
205
+ input: filePathResolved,
206
+ plugins: [
207
+ {
208
+ name: "hackmud-script-manager",
209
+ async transform(code, id) {
210
+ if (!id.includes("/node_modules/")) return (await preprocess(code, { uniqueID })).code
211
+ let program
212
+ traverse(parse(code, { sourceType: "module" }), {
213
+ Program(path) {
214
+ program = path
215
+ path.skip()
216
+ }
217
+ })
218
+ for (const referencePath of getReferencePathsToGlobal("JSON", program))
219
+ "MemberExpression" == referencePath.parentPath.node.type &&
220
+ "Identifier" == referencePath.parentPath.node.property.type &&
221
+ ("parse" == referencePath.parentPath.node.property.name ?
222
+ (referencePath.parentPath.node.property.name = "oparse")
223
+ : "stringify" == referencePath.parentPath.node.property.name &&
224
+ (referencePath.parentPath.node.property.name = "ostringify"))
225
+ return generate(program.node).code
248
226
  }
249
227
  },
250
- VariableDeclarator(path) {
251
- const renameVariables = lValue => {
252
- switch (lValue.type) {
253
- case "Identifier":
254
- includesIllegalString(lValue.name) &&
255
- path.scope.rename(
256
- lValue.name,
257
- "$" +
258
- Math.floor(Math.random() * 2 ** 52)
259
- .toString(36)
260
- .padStart(11, "0")
261
- )
262
- break
263
- case "ObjectPattern":
264
- for (const property of lValue.properties) {
265
- assert("ObjectProperty" == property.type)
266
- renameVariables(property.value)
267
- }
268
- break
269
- case "ArrayPattern":
270
- for (const element of lValue.elements) element && renameVariables(element)
271
- break
272
- default:
273
- throw Error(`unknown lValue type "${lValue.type}"`)
274
- }
228
+ babel({ babelHelpers: "bundled", plugins, configFile: !1, extensions: supportedExtensions }),
229
+ rollupPluginCommonJS(),
230
+ rollupPluginNodeResolve({ extensions: supportedExtensions }),
231
+ rollupPluginJSON()
232
+ ],
233
+ treeshake: { moduleSideEffects: !1 }
234
+ }),
235
+ seclevelNames = ["NULLSEC", "LOWSEC", "MIDSEC", "HIGHSEC", "FULLSEC"]
236
+ code = (await bundle.generate({})).output[0].code
237
+ const { file, seclevel } = transform(parse(code, { sourceType: "module" }), sourceCode, {
238
+ uniqueID,
239
+ scriptUser,
240
+ scriptName
241
+ })
242
+ if (null != statedSeclevel && seclevel < statedSeclevel)
243
+ throw Error(
244
+ `detected seclevel ${seclevelNames[seclevel]} is lower than stated seclevel ${seclevelNames[statedSeclevel]}`
245
+ )
246
+ code = generate(file).code
247
+ if (shouldMinify) code = await minify(file, { uniqueID, mangleNames, forceQuineCheats, autocomplete })
248
+ else {
249
+ traverse(file, {
250
+ MemberExpression({ node: memberExpression }) {
251
+ if (!memberExpression.computed) {
252
+ assert("Identifier" == memberExpression.property.type, "src/processScript/index.ts:322:60")
253
+ if ("prototype" == memberExpression.property.name) {
254
+ memberExpression.computed = !0
255
+ memberExpression.property = t.stringLiteral("prototype")
256
+ } else if ("__proto__" == memberExpression.property.name) {
257
+ memberExpression.computed = !0
258
+ memberExpression.property = t.stringLiteral("__proto__")
259
+ } else if (includesIllegalString(memberExpression.property.name)) {
260
+ memberExpression.computed = !0
261
+ memberExpression.property = t.stringLiteral(
262
+ replaceUnsafeStrings(uniqueID, memberExpression.property.name)
263
+ )
275
264
  }
276
- renameVariables(path.node.id)
277
- },
278
- ObjectProperty({ node: objectProperty }) {
279
- if ("Identifier" == objectProperty.key.type && includesIllegalString(objectProperty.key.name)) {
280
- objectProperty.key = t.stringLiteral(replaceUnsafeStrings(uniqueID, objectProperty.key.name))
281
- objectProperty.shorthand = !1
265
+ }
266
+ },
267
+ VariableDeclarator(path) {
268
+ const renameVariables = lValue => {
269
+ switch (lValue.type) {
270
+ case "Identifier":
271
+ includesIllegalString(lValue.name) &&
272
+ path.scope.rename(
273
+ lValue.name,
274
+ "$" +
275
+ Math.floor(Math.random() * 2 ** 52)
276
+ .toString(36)
277
+ .padStart(11, "0")
278
+ )
279
+ break
280
+ case "ObjectPattern":
281
+ for (const property of lValue.properties) {
282
+ assert("ObjectProperty" == property.type, "src/processScript/index.ts:352:51")
283
+ renameVariables(property.value)
284
+ }
285
+ break
286
+ case "ArrayPattern":
287
+ for (const element of lValue.elements) element && renameVariables(element)
288
+ break
289
+ default:
290
+ throw Error(`unknown lValue type "${lValue.type}"`)
282
291
  }
283
- },
284
- StringLiteral({ node }) {
285
- node.value = replaceUnsafeStrings(uniqueID, node.value)
286
- },
287
- TemplateLiteral({ node }) {
288
- for (const templateElement of node.quasis)
289
- if (templateElement.value.cooked) {
290
- templateElement.value.cooked = replaceUnsafeStrings(uniqueID, templateElement.value.cooked)
291
- templateElement.value.raw = templateElement.value.cooked
292
- .replaceAll("\\", "\\\\")
293
- .replaceAll("`", "\\`")
294
- .replaceAll("${", "$\\{")
295
- } else templateElement.value.raw = replaceUnsafeStrings(uniqueID, templateElement.value.raw)
296
- },
297
- RegExpLiteral(path) {
298
- path.node.pattern = replaceUnsafeStrings(uniqueID, path.node.pattern)
299
- delete path.node.extra
300
292
  }
301
- })
302
- code = await format(generate(file, { comments: !1 }).code, {
303
- parser: "babel",
304
- arrowParens: "avoid",
305
- semi: !1,
306
- trailingComma: "none"
307
- })
308
- }
309
- code = postprocess(code, seclevel, uniqueID)
310
- if (includesIllegalString(code))
311
- throw Error(
312
- 'you found a weird edge case where I wasn\'t able to replace illegal strings like "SC$", please report thx'
313
- )
314
- return { script: code, warnings: [] }
293
+ renameVariables(path.node.id)
294
+ },
295
+ ObjectProperty({ node: objectProperty }) {
296
+ if ("Identifier" == objectProperty.key.type && includesIllegalString(objectProperty.key.name)) {
297
+ objectProperty.key = t.stringLiteral(replaceUnsafeStrings(uniqueID, objectProperty.key.name))
298
+ objectProperty.shorthand = !1
299
+ }
300
+ },
301
+ StringLiteral({ node }) {
302
+ node.value = replaceUnsafeStrings(uniqueID, node.value)
303
+ },
304
+ TemplateLiteral({ node }) {
305
+ for (const templateElement of node.quasis)
306
+ if (templateElement.value.cooked) {
307
+ templateElement.value.cooked = replaceUnsafeStrings(uniqueID, templateElement.value.cooked)
308
+ templateElement.value.raw = templateElement.value.cooked
309
+ .replaceAll("\\", "\\\\")
310
+ .replaceAll("`", "\\`")
311
+ .replaceAll("${", "$\\{")
312
+ } else templateElement.value.raw = replaceUnsafeStrings(uniqueID, templateElement.value.raw)
313
+ },
314
+ RegExpLiteral(path) {
315
+ path.node.pattern = replaceUnsafeStrings(uniqueID, path.node.pattern)
316
+ delete path.node.extra
317
+ }
318
+ })
319
+ code = await format(generate(file, { comments: !1 }).code, {
320
+ parser: "babel",
321
+ arrowParens: "avoid",
322
+ semi: !1,
323
+ trailingComma: "none"
324
+ })
315
325
  }
326
+ code = postprocess(code, seclevel, uniqueID)
327
+ if (includesIllegalString(code))
328
+ throw Error(
329
+ 'you found a weird edge case where I wasn\'t able to replace illegal strings like "SC$", please report thx'
330
+ )
331
+ return { script: code, warnings: [] }
332
+ }
316
333
  export { processScript as default, minify, postprocess, preprocess, processScript, transform }