hackmud-script-manager 0.19.0-50a29ed → 0.19.0-cd5548c

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