hackmud-script-manager 0.19.0-50a29ed → 0.19.0-7c69a3b

Sign up to get free protection for your applications and to get access to all the features.
@@ -1 +1,313 @@
1
- import e from"@babel/generator";import{parse as o}from"@babel/parser";import r from"@babel/plugin-proposal-class-properties";import t from"@babel/plugin-proposal-class-static-block";import a from"@babel/plugin-proposal-decorators";import p from"@babel/plugin-proposal-json-strings";import s from"@babel/plugin-proposal-logical-assignment-operators";import l from"@babel/plugin-proposal-nullish-coalescing-operator";import i from"@babel/plugin-proposal-numeric-separator";import n from"@babel/plugin-proposal-object-rest-spread";import m from"@babel/plugin-proposal-optional-catch-binding";import c from"@babel/plugin-proposal-optional-chaining";import u from"@babel/plugin-proposal-private-property-in-object";import f from"@babel/plugin-transform-exponentiation-operator";import d from"@babel/traverse";import b from"@babel/types";import g from"@rollup/plugin-babel";import h from"@rollup/plugin-commonjs";import y from"@rollup/plugin-json";import w from"@rollup/plugin-node-resolve";import{resolve as k}from"path";import x from"prettier";import{rollup as j}from"rollup";import{s as v}from"../constants-9bb78688.js";import{minify as C}from"./minify.js";export{minify}from"./minify.js";import{postprocess as E}from"./postprocess.js";export{postprocess}from"./postprocess.js";import{preprocess as S}from"./preprocess.js";export{preprocess}from"./preprocess.js";import{includesIllegalString as L,replaceUnsafeStrings as $}from"./shared.js";import{transform as N}from"./transform.js";export{transform}from"./transform.js";import{a as I}from"../assert-22a7ef8a.js";import"acorn";import"terser";import"../spliceString-0e6b5d6d.js";import"../countHackmudCharacters-a08a265f.js";import"import-meta-resolve";const{default:P}=g,{format:D}=x,{default:_}=e,{default:M}=d,processScript=async(e,{minify:d=!0,uniqueID:g=Math.floor(Math.random()*2**52).toString(36).padStart(11,"0"),scriptUser:x="UNKNOWN",scriptName:O="UNKNOWN",filePath:T,mangleNames:U=!1,forceQuineCheats:W}={})=>{I(/^\w{11}$/.exec(g));const q=e;let F,H;const z=/^function\s*\(.+\/\/(?<autocomplete>.+)/.exec(e);if(z)e=`export default ${e}`,({autocomplete:F}=z.groups);else for(const o of e.split("\n")){const e=/^\s*\/\/(?<commentContent>.+)/.exec(o);if(!e)break;const r=e.groups.commentContent.trim();if(r.startsWith("@autocomplete "))F=r.slice(14).trimStart();else if(r.startsWith("@seclevel ")){const e=r.slice(10).trimStart().toLowerCase();switch(e){case"fullsec":case"full":case"fs":case"4s":case"f":case"4":H=4;break;case"highsec":case"high":case"hs":case"3s":case"h":case"3":H=3;break;case"midsec":case"mid":case"ms":case"2s":case"m":case"2":H=2;break;case"lowsec":case"low":case"ls":case"1s":case"l":case"1":H=1;break;case"nullsec":case"null":case"ns":case"0s":case"n":case"0":H=0;break;default:throw new Error(`unrecognised seclevel "${e}"`)}}}I(/^\w{11}$/.exec(g));const K=[[a.default,{decoratorsBeforeExport:!0}],[r.default],[t.default],[u.default],[s.default],[i.default],[l.default],[c.default],[m.default],[p.default],[n.default],[f.default]];let Q;if(T)if(Q=k(T),T.endsWith(".ts"))K.push([(await import("@babel/plugin-transform-typescript")).default,{allowDeclareFields:!0,optimizeConstEnums:!0}]);else{const[e,o,r,t,a,p,s]=await Promise.all([import("@babel/plugin-proposal-do-expressions"),import("@babel/plugin-proposal-function-bind"),import("@babel/plugin-proposal-function-sent"),import("@babel/plugin-proposal-partial-application"),import("@babel/plugin-proposal-pipeline-operator"),import("@babel/plugin-proposal-throw-expressions"),import("@babel/plugin-proposal-record-and-tuple")]);K.push([e.default],[o.default],[r.default],[t.default],[a.default,{proposal:"hack",topicToken:"%"}],[p.default],[s.default,{syntaxType:"hash",importPolyfill:!0}])}else{Q=`${g}.ts`;const[e,o,r,t,a,p,s,l]=await Promise.all([import("@babel/plugin-transform-typescript"),import("@babel/plugin-proposal-do-expressions"),import("@babel/plugin-proposal-function-bind"),import("@babel/plugin-proposal-function-sent"),import("@babel/plugin-proposal-partial-application"),import("@babel/plugin-proposal-pipeline-operator"),import("@babel/plugin-proposal-throw-expressions"),import("@babel/plugin-proposal-record-and-tuple")]);K.push([e.default,{allowDeclareFields:!0,optimizeConstEnums:!0}],[o.default],[r.default],[t.default],[a.default],[p.default,{proposal:"hack",topicToken:"%"}],[s.default],[l.default,{syntaxType:"hash",importPolyfill:!0}])}const V=await j({input:Q,plugins:[{name:"hackmud-script-manager",transform:async e=>(await S(e,{uniqueID:g})).code},P({babelHelpers:"bundled",plugins:K,configFile:!1,extensions:v}),h(),w({extensions:v}),y()],treeshake:{moduleSideEffects:!1}}),A=["NULLSEC","LOWSEC","MIDSEC","HIGHSEC","FULLSEC"];e=(await V.generate({})).output[0].code;const{file:B,seclevel:G}=N(o(e,{sourceType:"module"}),q,{uniqueID:g,scriptUser:x,scriptName:O});if(null!=H&&G<H)throw new Error(`detected seclevel ${A[G]} is lower than stated seclevel ${A[H]}`);if(e=_(B).code,d?e=await C(B,{uniqueID:g,mangleNames:U,forceQuineCheats:W,autocomplete:F}):(M(B,{MemberExpression({node:e}){e.computed||(I("Identifier"==e.property.type),"prototype"==e.property.name?(e.computed=!0,e.property=b.stringLiteral("prototype")):"__proto__"==e.property.name?(e.computed=!0,e.property=b.stringLiteral("__proto__")):L(e.property.name)&&(e.computed=!0,e.property=b.stringLiteral($(g,e.property.name))))},VariableDeclarator(e){const renameVariables=o=>{switch(o.type){case"Identifier":L(o.name)&&e.scope.rename(o.name,`$${Math.floor(Math.random()*2**52).toString(36).padStart(11,"0")}`);break;case"ObjectPattern":for(const e of o.properties)I("ObjectProperty"==e.type),renameVariables(e.value);break;case"ArrayPattern":for(const e of o.elements)e&&renameVariables(e);break;default:throw new Error(`unknown lValue type "${o.type}"`)}};renameVariables(e.node.id)},ObjectProperty({node:e}){"Identifier"==e.key.type&&L(e.key.name)&&(e.key=b.stringLiteral($(g,e.key.name)),e.shorthand=!1)},StringLiteral({node:e}){e.value=$(g,e.value)},TemplateLiteral({node:e}){for(const o of e.quasis)o.value.cooked?(o.value.cooked=$(g,o.value.cooked),o.value.raw=o.value.cooked.replace(/\\/g,"\\\\").replace(/`/g,"\\`").replace(/\$\{/g,"$\\{")):o.value.raw=$(g,o.value.raw)},RegExpLiteral(e){e.node.pattern=$(g,e.node.pattern),delete e.node.extra}}),e=D(_(B,{comments:!1}).code,{parser:"babel",arrowParens:"avoid",semi:!1,trailingComma:"none"})),e=E(e,G,g),L(e))throw new Error('you found a weird edge case where I wasn\'t able to replace illegal strings like "SC$", please report thx');return{script:e,warnings:[]}};export{processScript as default,processScript};
1
+ import babelGenerator from '@babel/generator';
2
+ import { parse } from '@babel/parser';
3
+ import babelPluginProposalDecorators from '@babel/plugin-proposal-decorators';
4
+ import babelPluginProposalDestructuringPrivate from '@babel/plugin-proposal-destructuring-private';
5
+ import babelPluginProposalExplicitResourceManagement from '@babel/plugin-proposal-explicit-resource-management';
6
+ import babelPluginTransformClassProperties from '@babel/plugin-transform-class-properties';
7
+ import babelPluginTransformClassStaticBlock from '@babel/plugin-transform-class-static-block';
8
+ import babelPluginTransformExponentiationOperator from '@babel/plugin-transform-exponentiation-operator';
9
+ import babelPluginTransformJsonStrings from '@babel/plugin-transform-json-strings';
10
+ import babelPluginTransformLogicalAssignmentOperators from '@babel/plugin-transform-logical-assignment-operators';
11
+ import babelPluginTransformNullishCoalescingOperator from '@babel/plugin-transform-nullish-coalescing-operator';
12
+ import babelPluginTransformNumericSeparator from '@babel/plugin-transform-numeric-separator';
13
+ import babelPluginTransformObjectRestSpread from '@babel/plugin-transform-object-rest-spread';
14
+ import babelPluginTransformOptionalCatchBinding from '@babel/plugin-transform-optional-catch-binding';
15
+ import babelPluginTransformOptionalChaining from '@babel/plugin-transform-optional-chaining';
16
+ import babelPluginTransformPrivatePropertyInObject from '@babel/plugin-transform-private-property-in-object';
17
+ import babelPluginTransformUnicodeSetsRegex from '@babel/plugin-transform-unicode-sets-regex';
18
+ import babelTraverse from '@babel/traverse';
19
+ import t from '@babel/types';
20
+ import { babel } from '@rollup/plugin-babel';
21
+ import rollupPluginCommonJS from '@rollup/plugin-commonjs';
22
+ import rollupPluginJSON from '@rollup/plugin-json';
23
+ import rollupPluginNodeResolve from '@rollup/plugin-node-resolve';
24
+ import { assert } from '@samual/lib/assert';
25
+ import { resolve } from 'path';
26
+ import prettier from 'prettier';
27
+ import { rollup } from 'rollup';
28
+ import { supportedExtensions } from '../constants.js';
29
+ import { minify } from './minify.js';
30
+ import { postprocess } from './postprocess.js';
31
+ import { preprocess } from './preprocess.js';
32
+ import { includesIllegalString, replaceUnsafeStrings } from './shared.js';
33
+ import { transform } from './transform.js';
34
+ import '@samual/lib/countHackmudCharacters';
35
+ import '@samual/lib/spliceString';
36
+ import 'acorn';
37
+ import 'terser';
38
+ import 'import-meta-resolve';
39
+ import '@samual/lib/clearObject';
40
+
41
+ const {
42
+ format
43
+ } = prettier;
44
+ // eslint-disable-next-line @typescript-eslint/consistent-type-imports
45
+ const {
46
+ default: generate
47
+ } = babelGenerator;
48
+ // eslint-disable-next-line @typescript-eslint/consistent-type-imports
49
+ const {
50
+ default: traverse
51
+ } = babelTraverse;
52
+ /**
53
+ * Minifies a given script
54
+ *
55
+ * @param code JavaScript or TypeScript code
56
+ * @param options {@link ProcessOptions details}
57
+ */
58
+ const processScript = async (code, {
59
+ minify: shouldMinify = true,
60
+ uniqueID = Math.floor(Math.random() * 2 ** 52).toString(36).padStart(11, `0`),
61
+ scriptUser = `UNKNOWN`,
62
+ scriptName = `UNKNOWN`,
63
+ filePath,
64
+ mangleNames = false,
65
+ forceQuineCheats
66
+ } = {}) => {
67
+ assert(/^\w{11}$/.exec(uniqueID));
68
+ const sourceCode = code;
69
+ let autocomplete;
70
+ let statedSeclevel;
71
+
72
+ // TODO do seclevel detection and verification per module
73
+
74
+ const autocompleteMatch = /^function\s*\(.+\/\/(?<autocomplete>.+)/.exec(code);
75
+ if (autocompleteMatch) {
76
+ code = `export default ${code}`;
77
+ ({
78
+ autocomplete
79
+ } = autocompleteMatch.groups);
80
+ } else {
81
+ for (const line of code.split(`\n`)) {
82
+ const comment = /^\s*\/\/(?<commentContent>.+)/.exec(line);
83
+ if (!comment) break;
84
+ const commentContent = comment.groups.commentContent.trim();
85
+ if (commentContent.startsWith(`@autocomplete `)) autocomplete = commentContent.slice(14).trimStart();else if (commentContent.startsWith(`@seclevel `)) {
86
+ const seclevelString = commentContent.slice(10).trimStart().toLowerCase();
87
+ switch (seclevelString) {
88
+ case `fullsec`:
89
+ case `full`:
90
+ case `fs`:
91
+ case `4s`:
92
+ case `f`:
93
+ case `4`:
94
+ {
95
+ statedSeclevel = 4;
96
+ }
97
+ break;
98
+ case `highsec`:
99
+ case `high`:
100
+ case `hs`:
101
+ case `3s`:
102
+ case `h`:
103
+ case `3`:
104
+ {
105
+ statedSeclevel = 3;
106
+ }
107
+ break;
108
+ case `midsec`:
109
+ case `mid`:
110
+ case `ms`:
111
+ case `2s`:
112
+ case `m`:
113
+ case `2`:
114
+ {
115
+ statedSeclevel = 2;
116
+ }
117
+ break;
118
+ case `lowsec`:
119
+ case `low`:
120
+ case `ls`:
121
+ case `1s`:
122
+ case `l`:
123
+ case `1`:
124
+ {
125
+ statedSeclevel = 1;
126
+ }
127
+ break;
128
+ case `nullsec`:
129
+ case `null`:
130
+ case `ns`:
131
+ case `0s`:
132
+ case `n`:
133
+ case `0`:
134
+ {
135
+ statedSeclevel = 0;
136
+ }
137
+ break;
138
+ default:
139
+ // TODO turn into warning when I get round to those
140
+ throw new Error(`unrecognised seclevel "${seclevelString}"`);
141
+ }
142
+ }
143
+ }
144
+ }
145
+ assert(/^\w{11}$/.exec(uniqueID));
146
+ const plugins = [[babelPluginProposalDecorators.default, {
147
+ decoratorsBeforeExport: true
148
+ }], [babelPluginTransformClassProperties.default], [babelPluginTransformClassStaticBlock.default], [babelPluginTransformPrivatePropertyInObject.default], [babelPluginTransformLogicalAssignmentOperators.default], [babelPluginTransformNumericSeparator.default], [babelPluginTransformNullishCoalescingOperator.default], [babelPluginTransformOptionalChaining.default], [babelPluginTransformOptionalCatchBinding.default], [babelPluginTransformJsonStrings.default], [babelPluginTransformObjectRestSpread.default], [babelPluginTransformExponentiationOperator.default], [babelPluginTransformUnicodeSetsRegex.default], [babelPluginProposalDestructuringPrivate.default], [babelPluginProposalExplicitResourceManagement.default]];
149
+ let filePathResolved;
150
+ if (filePath) {
151
+ filePathResolved = resolve(filePath);
152
+ if (filePath.endsWith(`.ts`)) plugins.push([(await import('@babel/plugin-transform-typescript')).default, {
153
+ allowDeclareFields: true,
154
+ optimizeConstEnums: true
155
+ }]);else {
156
+ const [babelPluginProposalDoExpressions, babelPluginProposalFunctionBind, babelPluginProposalFunctionSent, babelPluginProposalPartialApplication, babelPluginProposalPipelineOperator, babelPluginProposalThrowExpressions, babelPluginProposalRecordAndTuple] = await Promise.all([import('@babel/plugin-proposal-do-expressions'), import('@babel/plugin-proposal-function-bind'), import('@babel/plugin-proposal-function-sent'), import('@babel/plugin-proposal-partial-application'), import('@babel/plugin-proposal-pipeline-operator'), import('@babel/plugin-proposal-throw-expressions'), import('@babel/plugin-proposal-record-and-tuple')]);
157
+ plugins.push([babelPluginProposalDoExpressions.default], [babelPluginProposalFunctionBind.default], [babelPluginProposalFunctionSent.default], [babelPluginProposalPartialApplication.default], [babelPluginProposalPipelineOperator.default, {
158
+ proposal: `hack`,
159
+ topicToken: `%`
160
+ }], [babelPluginProposalThrowExpressions.default], [babelPluginProposalRecordAndTuple.default, {
161
+ syntaxType: `hash`,
162
+ importPolyfill: true
163
+ }]);
164
+ }
165
+ } else {
166
+ filePathResolved = `${uniqueID}.ts`;
167
+ const [babelPluginTransformTypescript, babelPluginProposalDoExpressions, babelPluginProposalFunctionBind, babelPluginProposalFunctionSent, babelPluginProposalPartialApplication, babelPluginProposalPipelineOperator, babelPluginProposalThrowExpressions, babelPluginProposalRecordAndTuple] = await Promise.all([import('@babel/plugin-transform-typescript'), import('@babel/plugin-proposal-do-expressions'), import('@babel/plugin-proposal-function-bind'), import('@babel/plugin-proposal-function-sent'), import('@babel/plugin-proposal-partial-application'), import('@babel/plugin-proposal-pipeline-operator'), import('@babel/plugin-proposal-throw-expressions'), import('@babel/plugin-proposal-record-and-tuple')]);
168
+ plugins.push([babelPluginTransformTypescript.default, {
169
+ allowDeclareFields: true,
170
+ optimizeConstEnums: true
171
+ }], [babelPluginProposalDoExpressions.default], [babelPluginProposalFunctionBind.default], [babelPluginProposalFunctionSent.default], [babelPluginProposalPartialApplication.default], [babelPluginProposalPipelineOperator.default, {
172
+ proposal: `hack`,
173
+ topicToken: `%`
174
+ }], [babelPluginProposalThrowExpressions.default], [babelPluginProposalRecordAndTuple.default, {
175
+ syntaxType: `hash`,
176
+ importPolyfill: true
177
+ }]);
178
+ }
179
+ const bundle = await rollup({
180
+ input: filePathResolved,
181
+ plugins: [{
182
+ name: `hackmud-script-manager`,
183
+ transform: async code => (await preprocess(code, {
184
+ uniqueID
185
+ })).code
186
+ }, babel({
187
+ babelHelpers: `bundled`,
188
+ plugins,
189
+ configFile: false,
190
+ extensions: supportedExtensions
191
+ }), rollupPluginCommonJS(), rollupPluginNodeResolve({
192
+ extensions: supportedExtensions
193
+ }), rollupPluginJSON()],
194
+ treeshake: {
195
+ moduleSideEffects: false
196
+ }
197
+ });
198
+ const seclevelNames = [`NULLSEC`, `LOWSEC`, `MIDSEC`, `HIGHSEC`, `FULLSEC`];
199
+ code = (await bundle.generate({})).output[0].code;
200
+ const {
201
+ file,
202
+ seclevel
203
+ } = transform(parse(code, {
204
+ sourceType: `module`
205
+ }), sourceCode, {
206
+ uniqueID,
207
+ scriptUser,
208
+ scriptName
209
+ });
210
+ if (statedSeclevel != undefined && seclevel < statedSeclevel)
211
+ // TODO replace with a warning and build script anyway
212
+ throw new Error(`detected seclevel ${seclevelNames[seclevel]} is lower than stated seclevel ${seclevelNames[statedSeclevel]}`);
213
+ code = generate(file).code;
214
+ if (shouldMinify) code = await minify(file, {
215
+ uniqueID,
216
+ mangleNames,
217
+ forceQuineCheats,
218
+ autocomplete
219
+ });else {
220
+ traverse(file, {
221
+ MemberExpression({
222
+ node: memberExpression
223
+ }) {
224
+ if (memberExpression.computed) return;
225
+ assert(memberExpression.property.type == `Identifier`);
226
+ if (memberExpression.property.name == `prototype`) {
227
+ memberExpression.computed = true;
228
+ memberExpression.property = t.stringLiteral(`prototype`);
229
+ } else if (memberExpression.property.name == `__proto__`) {
230
+ memberExpression.computed = true;
231
+ memberExpression.property = t.stringLiteral(`__proto__`);
232
+ } else if (includesIllegalString(memberExpression.property.name)) {
233
+ memberExpression.computed = true;
234
+ memberExpression.property = t.stringLiteral(replaceUnsafeStrings(uniqueID, memberExpression.property.name));
235
+ }
236
+ },
237
+ VariableDeclarator(path) {
238
+ const renameVariables = lValue => {
239
+ switch (lValue.type) {
240
+ case `Identifier`:
241
+ {
242
+ if (includesIllegalString(lValue.name)) path.scope.rename(lValue.name, `$${Math.floor(Math.random() * 2 ** 52).toString(36).padStart(11, `0`)}`);
243
+ }
244
+ break;
245
+ case `ObjectPattern`:
246
+ {
247
+ for (const property of lValue.properties) {
248
+ assert(property.type == `ObjectProperty`);
249
+ renameVariables(property.value);
250
+ }
251
+ }
252
+ break;
253
+ case `ArrayPattern`:
254
+ {
255
+ for (const element of lValue.elements) {
256
+ if (element) renameVariables(element);
257
+ }
258
+ }
259
+ break;
260
+ default:
261
+ throw new Error(`unknown lValue type "${lValue.type}"`);
262
+ }
263
+ };
264
+ renameVariables(path.node.id);
265
+ },
266
+ ObjectProperty({
267
+ node: objectProperty
268
+ }) {
269
+ if (objectProperty.key.type == `Identifier` && includesIllegalString(objectProperty.key.name)) {
270
+ objectProperty.key = t.stringLiteral(replaceUnsafeStrings(uniqueID, objectProperty.key.name));
271
+ objectProperty.shorthand = false;
272
+ }
273
+ },
274
+ StringLiteral({
275
+ node
276
+ }) {
277
+ node.value = replaceUnsafeStrings(uniqueID, node.value);
278
+ },
279
+ TemplateLiteral({
280
+ node
281
+ }) {
282
+ for (const templateElement of node.quasis) {
283
+ if (templateElement.value.cooked) {
284
+ templateElement.value.cooked = replaceUnsafeStrings(uniqueID, templateElement.value.cooked);
285
+ templateElement.value.raw = templateElement.value.cooked.replaceAll(`\\`, `\\\\`).replaceAll(`\``, `\\\``).replaceAll(`\${`, `$\\{`);
286
+ } else templateElement.value.raw = replaceUnsafeStrings(uniqueID, templateElement.value.raw);
287
+ }
288
+ },
289
+ RegExpLiteral(path) {
290
+ path.node.pattern = replaceUnsafeStrings(uniqueID, path.node.pattern);
291
+ delete path.node.extra;
292
+ }
293
+ });
294
+
295
+ // we can't have comments because they may contain illegal strings
296
+ code = await format(generate(file, {
297
+ comments: false
298
+ }).code, {
299
+ parser: `babel`,
300
+ arrowParens: `avoid`,
301
+ semi: false,
302
+ trailingComma: `none`
303
+ });
304
+ }
305
+ code = postprocess(code, seclevel, uniqueID);
306
+ if (includesIllegalString(code)) throw new Error(`you found a weird edge case where I wasn't able to replace illegal strings like "SC$", please report thx`);
307
+ return {
308
+ script: code,
309
+ warnings: []
310
+ };
311
+ };
312
+
313
+ export { processScript as default, minify, postprocess, preprocess, processScript, transform };
@@ -1,6 +1,6 @@
1
- import { File } from "@babel/types";
2
- import { LaxPartial } from "@samual/lib";
3
- declare type MinifyOptions = {
1
+ import type { File } from "@babel/types";
2
+ import type { LaxPartial } from "@samual/lib";
3
+ type MinifyOptions = {
4
4
  /** 11 a-z 0-9 characters */
5
5
  uniqueID: string;
6
6
  /** whether to mangle function and class names (defaults to `false`) */