@casual-simulation/aux-runtime 3.2.7-alpha.6226622763

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 (70) hide show
  1. package/LICENSE.txt +21 -0
  2. package/README.md +82 -0
  3. package/index.d.ts +26 -0
  4. package/index.js +26 -0
  5. package/index.js.map +1 -0
  6. package/package.json +79 -0
  7. package/runtime/AuxCompiler.d.ts +258 -0
  8. package/runtime/AuxCompiler.js +722 -0
  9. package/runtime/AuxCompiler.js.map +1 -0
  10. package/runtime/AuxDevice.d.ts +28 -0
  11. package/runtime/AuxDevice.js +2 -0
  12. package/runtime/AuxDevice.js.map +1 -0
  13. package/runtime/AuxGlobalContext.d.ts +572 -0
  14. package/runtime/AuxGlobalContext.js +606 -0
  15. package/runtime/AuxGlobalContext.js.map +1 -0
  16. package/runtime/AuxLibrary.d.ts +2566 -0
  17. package/runtime/AuxLibrary.js +10210 -0
  18. package/runtime/AuxLibrary.js.map +1 -0
  19. package/runtime/AuxLibraryDefinitions.def +12288 -0
  20. package/runtime/AuxPartitionRealtimeEditModeProvider.d.ts +9 -0
  21. package/runtime/AuxPartitionRealtimeEditModeProvider.js +21 -0
  22. package/runtime/AuxPartitionRealtimeEditModeProvider.js.map +1 -0
  23. package/runtime/AuxRealtimeEditModeProvider.d.ts +35 -0
  24. package/runtime/AuxRealtimeEditModeProvider.js +34 -0
  25. package/runtime/AuxRealtimeEditModeProvider.js.map +1 -0
  26. package/runtime/AuxResults.d.ts +77 -0
  27. package/runtime/AuxResults.js +6 -0
  28. package/runtime/AuxResults.js.map +1 -0
  29. package/runtime/AuxRuntime.d.ts +252 -0
  30. package/runtime/AuxRuntime.js +2688 -0
  31. package/runtime/AuxRuntime.js.map +1 -0
  32. package/runtime/AuxRuntimeDynamicImports.d.ts +14 -0
  33. package/runtime/AuxRuntimeDynamicImports.js +24 -0
  34. package/runtime/AuxRuntimeDynamicImports.js.map +1 -0
  35. package/runtime/AuxVersion.d.ts +39 -0
  36. package/runtime/AuxVersion.js +2 -0
  37. package/runtime/AuxVersion.js.map +1 -0
  38. package/runtime/CasualOSError.d.ts +37 -0
  39. package/runtime/CasualOSError.js +25 -0
  40. package/runtime/CasualOSError.js.map +1 -0
  41. package/runtime/CompiledBot.d.ts +107 -0
  42. package/runtime/CompiledBot.js +44 -0
  43. package/runtime/CompiledBot.js.map +1 -0
  44. package/runtime/PerformanceNowPolyfill.d.ts +1 -0
  45. package/runtime/PerformanceNowPolyfill.js +8 -0
  46. package/runtime/PerformanceNowPolyfill.js.map +1 -0
  47. package/runtime/RecordsEvents.d.ts +1025 -0
  48. package/runtime/RecordsEvents.js +449 -0
  49. package/runtime/RecordsEvents.js.map +1 -0
  50. package/runtime/RuntimeBot.d.ts +177 -0
  51. package/runtime/RuntimeBot.js +732 -0
  52. package/runtime/RuntimeBot.js.map +1 -0
  53. package/runtime/RuntimeEvents.d.ts +126 -0
  54. package/runtime/RuntimeEvents.js +29 -0
  55. package/runtime/RuntimeEvents.js.map +1 -0
  56. package/runtime/RuntimeStateVersion.d.ts +23 -0
  57. package/runtime/RuntimeStateVersion.js +22 -0
  58. package/runtime/RuntimeStateVersion.js.map +1 -0
  59. package/runtime/Transpiler.d.ts +174 -0
  60. package/runtime/Transpiler.js +611 -0
  61. package/runtime/Transpiler.js.map +1 -0
  62. package/runtime/Utils.d.ts +44 -0
  63. package/runtime/Utils.js +253 -0
  64. package/runtime/Utils.js.map +1 -0
  65. package/runtime/index.d.ts +13 -0
  66. package/runtime/index.js +13 -0
  67. package/runtime/index.js.map +1 -0
  68. package/runtime/test/TestScriptBotFactory.d.ts +16 -0
  69. package/runtime/test/TestScriptBotFactory.js +107 -0
  70. package/runtime/test/TestScriptBotFactory.js.map +1 -0
@@ -0,0 +1,722 @@
1
+ import { calculateFinalLineLocation, calculateOriginalLineLocation, Transpiler, } from './Transpiler';
2
+ import { isScript, parseScript, hasValue, } from '@casual-simulation/aux-common/bots';
3
+ import { flatMap } from 'lodash';
4
+ import ErrorStackParser from '@casual-simulation/error-stack-parser';
5
+ import StackFrame from 'stackframe';
6
+ import { unwind, INTERPRETER_OBJECT, } from '@casual-simulation/js-interpreter/InterpreterUtils';
7
+ /**
8
+ * A symbol that identifies a function as having been compiled using the AuxCompiler.
9
+ */
10
+ export const COMPILED_SCRIPT_SYMBOL = Symbol('compiled_script');
11
+ /**
12
+ * The symbol that is used to tag specific functions as interpretable.
13
+ */
14
+ export const INTERPRETABLE_FUNCTION = Symbol('interpretable_function');
15
+ /**
16
+ * The symbol that is used to tag function modules with the metadata for a function.
17
+ */
18
+ export const FUNCTION_METADATA = Symbol('function_metadata');
19
+ /**
20
+ * Creates a new interpretable function based on the given function.
21
+ * @param interpretableFunc
22
+ */
23
+ export function createInterpretableFunction(interpretableFunc) {
24
+ const normalFunc = ((...args) => unwind(interpretableFunc(...args)));
25
+ normalFunc[INTERPRETABLE_FUNCTION] = interpretableFunc;
26
+ return normalFunc;
27
+ }
28
+ /**
29
+ * Sets the INTERPRETABLE_FUNCTION property on the given object (semantically a function) to the given interpretable version and returns the object.
30
+ * @param interpretableFunc The version of the function that should be used as the interpretable version of the function.
31
+ * @param normalFunc The function that should be tagged.
32
+ */
33
+ export function tagAsInterpretableFunction(interpretableFunc, normalFunc) {
34
+ normalFunc[INTERPRETABLE_FUNCTION] = interpretableFunc;
35
+ return normalFunc;
36
+ }
37
+ /**
38
+ * Determines if the given object has been tagged with the GENERATOR_FUNCTION_TAG.
39
+ * @param obj The object.
40
+ */
41
+ export function isInterpretableFunction(obj) {
42
+ return ((typeof obj === 'function' || typeof obj === 'object') &&
43
+ obj !== null &&
44
+ !!obj[INTERPRETABLE_FUNCTION]);
45
+ }
46
+ /**
47
+ * Gets the interpretable version of the given function.
48
+ */
49
+ export function getInterpretableFunction(obj) {
50
+ return isInterpretableFunction(obj)
51
+ ? obj[INTERPRETABLE_FUNCTION]
52
+ : null;
53
+ }
54
+ const JSX_FACTORY = 'html.h';
55
+ const JSX_FRAGMENT_FACTORY = 'html.f';
56
+ /**
57
+ * Defines a class that can compile scripts and formulas
58
+ * into functions.
59
+ */
60
+ export class AuxCompiler {
61
+ constructor() {
62
+ this._transpiler = new Transpiler({
63
+ jsxFactory: JSX_FACTORY,
64
+ jsxFragment: JSX_FRAGMENT_FACTORY,
65
+ });
66
+ this._functionCache = new Map();
67
+ /**
68
+ * The offset that should be applied to error line numbers when calculating their original
69
+ * position. Needed because Node.js Windows produces different line numbers than Mac/Linux.
70
+ *
71
+ * Node.js versions greater than v12.14.0 have an issue with identifying the correct line number
72
+ * for errors and stack traces. This issue is fixed in Node.js v14 and later (possibly also fixed in v13 but I didn't check that).
73
+ */
74
+ this.functionErrorLineOffset = 0;
75
+ }
76
+ /**
77
+ * Calculates the "original" stack trace that the given error occurred at
78
+ * within the given function.
79
+ * Returns null if the original stack trace was unable to be determined.
80
+ * @param functionNameMap A map of function names to their scripts.
81
+ * @param error The error that occurred.
82
+ */
83
+ calculateOriginalStackTrace(functionNameMap, error) {
84
+ if (INTERPRETER_OBJECT in error) {
85
+ return this._calculateInterpreterErrorOriginalStackTrace(functionNameMap, error);
86
+ }
87
+ else {
88
+ return this._calculateNativeErrorOriginalStackTrace(functionNameMap, error);
89
+ }
90
+ }
91
+ _calculateInterpreterErrorOriginalStackTrace(functionNameMap, error) {
92
+ var _a, _b, _c, _d, _e, _f;
93
+ const frames = ErrorStackParser.parse(error);
94
+ if (frames.length < 1) {
95
+ return null;
96
+ }
97
+ let transformedFrames = [];
98
+ let lastScriptFrameIndex = -1;
99
+ let lastScript;
100
+ for (let i = frames.length - 1; i >= 0; i--) {
101
+ const frame = frames[i];
102
+ let savedFrame = false;
103
+ let functionName = frame.functionName;
104
+ const lastDotIndex = functionName.lastIndexOf('.');
105
+ if (lastDotIndex >= 0) {
106
+ functionName = functionName.slice(lastDotIndex + 1);
107
+ }
108
+ const script = functionNameMap.get(functionName);
109
+ let isWrapperFunc = false;
110
+ if (!/^__wrapperFunc/.test(frame.functionName)) {
111
+ if (script) {
112
+ lastScript = script;
113
+ const location = {
114
+ lineNumber: frame.lineNumber + this.functionErrorLineOffset,
115
+ column: frame.columnNumber,
116
+ };
117
+ const originalLocation = this.calculateOriginalLineLocation(script, location);
118
+ savedFrame = true;
119
+ if (lastScriptFrameIndex < 0) {
120
+ lastScriptFrameIndex = i;
121
+ }
122
+ transformedFrames.unshift(new StackFrame({
123
+ functionName: (_a = lastScript.metadata.diagnosticFunctionName) !== null && _a !== void 0 ? _a : functionName,
124
+ fileName: (_b = script.metadata.fileName) !== null && _b !== void 0 ? _b : functionName,
125
+ lineNumber: Math.max(originalLocation.lineNumber + 1, 1),
126
+ columnNumber: Math.max(originalLocation.column + 1, 1),
127
+ }));
128
+ }
129
+ else if (lastScript) {
130
+ if (typeof frame.lineNumber === 'number' &&
131
+ typeof frame.columnNumber === 'number') {
132
+ const location = {
133
+ lineNumber: frame.lineNumber + this.functionErrorLineOffset,
134
+ column: frame.columnNumber,
135
+ };
136
+ const originalLocation = this.calculateOriginalLineLocation(lastScript, location);
137
+ savedFrame = true;
138
+ transformedFrames.unshift(new StackFrame({
139
+ functionName: (_c = lastScript.metadata
140
+ .diagnosticFunctionName) !== null && _c !== void 0 ? _c : functionName,
141
+ fileName: (_d = lastScript.metadata.fileName) !== null && _d !== void 0 ? _d : functionName,
142
+ lineNumber: Math.max(originalLocation.lineNumber + 1, 1),
143
+ columnNumber: Math.max(originalLocation.column + 1, 1),
144
+ }));
145
+ }
146
+ else {
147
+ savedFrame = true;
148
+ transformedFrames.unshift(new StackFrame({
149
+ functionName: (_e = lastScript.metadata
150
+ .diagnosticFunctionName) !== null && _e !== void 0 ? _e : functionName,
151
+ fileName: (_f = lastScript.metadata.fileName) !== null && _f !== void 0 ? _f : functionName,
152
+ }));
153
+ }
154
+ }
155
+ }
156
+ else {
157
+ isWrapperFunc = true;
158
+ }
159
+ if (!savedFrame && isWrapperFunc) {
160
+ savedFrame = true;
161
+ if (lastScriptFrameIndex > i) {
162
+ lastScriptFrameIndex -= 1;
163
+ }
164
+ }
165
+ if (!savedFrame) {
166
+ transformedFrames.unshift(frame);
167
+ }
168
+ }
169
+ if (lastScriptFrameIndex >= 0) {
170
+ const finalFrames = [
171
+ ...transformedFrames.slice(0, lastScriptFrameIndex + 1),
172
+ new StackFrame({
173
+ fileName: '[Native CasualOS Code]',
174
+ functionName: '<CasualOS>',
175
+ }),
176
+ ];
177
+ const stack = finalFrames
178
+ .map((frame) => ' at ' + frame.toString())
179
+ .join('\n');
180
+ return error.toString() + '\n' + stack;
181
+ }
182
+ return null;
183
+ }
184
+ _calculateNativeErrorOriginalStackTrace(functionNameMap, error) {
185
+ var _a, _b, _c, _d;
186
+ const frames = ErrorStackParser.parse(error);
187
+ if (frames.length < 1) {
188
+ return null;
189
+ }
190
+ let transformedFrames = [];
191
+ let lastScriptFrameIndex = -1;
192
+ let lastScript;
193
+ for (let i = frames.length - 1; i >= 0; i--) {
194
+ const frame = frames[i];
195
+ const originFrame = frame.evalOrigin;
196
+ let savedFrame = false;
197
+ if (!!originFrame &&
198
+ originFrame.functionName === '__constructFunction') {
199
+ let functionName = frame.functionName;
200
+ const lastDotIndex = functionName.lastIndexOf('.');
201
+ if (lastDotIndex >= 0) {
202
+ functionName = functionName.slice(lastDotIndex + 1);
203
+ }
204
+ const script = functionNameMap.get(functionName);
205
+ if (script) {
206
+ lastScript = script;
207
+ const location = {
208
+ lineNumber: originFrame.lineNumber +
209
+ this.functionErrorLineOffset,
210
+ column: originFrame.columnNumber,
211
+ };
212
+ const originalLocation = this.calculateOriginalLineLocation(script, location);
213
+ savedFrame = true;
214
+ if (lastScriptFrameIndex < 0) {
215
+ lastScriptFrameIndex = i;
216
+ }
217
+ transformedFrames.unshift(new StackFrame({
218
+ functionName: (_a = lastScript.metadata.diagnosticFunctionName) !== null && _a !== void 0 ? _a : functionName,
219
+ fileName: (_b = script.metadata.fileName) !== null && _b !== void 0 ? _b : functionName,
220
+ lineNumber: originalLocation.lineNumber + 1,
221
+ columnNumber: originalLocation.column + 1,
222
+ }));
223
+ }
224
+ else if (lastScript) {
225
+ const location = {
226
+ lineNumber: originFrame.lineNumber +
227
+ this.functionErrorLineOffset,
228
+ column: originFrame.columnNumber,
229
+ };
230
+ const originalLocation = this.calculateOriginalLineLocation(lastScript, location);
231
+ savedFrame = true;
232
+ transformedFrames.unshift(new StackFrame({
233
+ functionName: (_c = lastScript.metadata.diagnosticFunctionName) !== null && _c !== void 0 ? _c : functionName,
234
+ fileName: (_d = lastScript.metadata.fileName) !== null && _d !== void 0 ? _d : functionName,
235
+ lineNumber: originalLocation.lineNumber + 1,
236
+ columnNumber: originalLocation.column + 1,
237
+ }));
238
+ }
239
+ }
240
+ if (!savedFrame) {
241
+ if (frame.functionName === '__wrapperFunc') {
242
+ savedFrame = true;
243
+ if (lastScriptFrameIndex > i) {
244
+ lastScriptFrameIndex -= 1;
245
+ }
246
+ }
247
+ }
248
+ if (!savedFrame) {
249
+ transformedFrames.unshift(frame);
250
+ }
251
+ }
252
+ if (lastScriptFrameIndex >= 0) {
253
+ const finalFrames = [
254
+ ...transformedFrames.slice(0, lastScriptFrameIndex + 1),
255
+ new StackFrame({
256
+ fileName: '[Native CasualOS Code]',
257
+ functionName: '<CasualOS>',
258
+ }),
259
+ ];
260
+ const stack = finalFrames
261
+ .map((frame) => ' at ' + frame.toString())
262
+ .join('\n');
263
+ return error.toString() + '\n' + stack;
264
+ }
265
+ return null;
266
+ }
267
+ /**
268
+ * Calculates the original location within the given function for the given location.
269
+ * The returned location uses zero-based line and column numbers.
270
+ * @param func The function.
271
+ * @param location The location. Line and column numbers are one-based.
272
+ */
273
+ calculateOriginalLineLocation(func, location) {
274
+ // Line numbers should be one based
275
+ if (location.lineNumber <
276
+ func.metadata.scriptLineOffset + func.metadata.transpilerLineOffset) {
277
+ return {
278
+ lineNumber: 0,
279
+ column: 0,
280
+ };
281
+ }
282
+ let transpiledLocation = {
283
+ lineNumber: location.lineNumber - func.metadata.scriptLineOffset - 1,
284
+ column: location.column - 1,
285
+ };
286
+ let result = calculateOriginalLineLocation(func.metadata.transpilerResult, transpiledLocation);
287
+ return {
288
+ lineNumber: result.lineNumber - func.metadata.transpilerLineOffset,
289
+ column: result.column,
290
+ };
291
+ }
292
+ /**
293
+ * Calculates the final location within the given function for the given location.
294
+ * @param func The function.
295
+ * @param location The location. Line and column numbers are zero based.
296
+ */
297
+ calculateFinalLineLocation(func, location) {
298
+ // Line numbers should be zero based
299
+ if (location.lineNumber < 0) {
300
+ return {
301
+ lineNumber: 0,
302
+ column: 0,
303
+ };
304
+ }
305
+ let transpiledLocation = {
306
+ lineNumber: location.lineNumber + func.metadata.transpilerLineOffset,
307
+ column: location.column,
308
+ };
309
+ let result = calculateFinalLineLocation(func.metadata.transpilerResult, transpiledLocation);
310
+ return {
311
+ lineNumber: result.lineNumber + func.metadata.scriptLineOffset,
312
+ column: result.column,
313
+ };
314
+ }
315
+ /**
316
+ * Compiles the given script into a function.
317
+ * @param script The script to compile.
318
+ * @param options The options that should be used to compile the script.
319
+ */
320
+ compile(script, options) {
321
+ var _a;
322
+ let { func, scriptLineOffset, transpilerLineOffset, async, transpilerResult, constructedFunction, } = this._compileFunction(script, options || {});
323
+ const scriptFunction = func;
324
+ const meta = {
325
+ scriptFunction,
326
+ scriptLineOffset,
327
+ transpilerLineOffset,
328
+ transpilerResult,
329
+ fileName: options === null || options === void 0 ? void 0 : options.fileName,
330
+ diagnosticFunctionName: options === null || options === void 0 ? void 0 : options.diagnosticFunctionName,
331
+ isAsync: async,
332
+ constructedFunction,
333
+ context: options === null || options === void 0 ? void 0 : options.context,
334
+ };
335
+ if (options) {
336
+ if (options.before ||
337
+ options.after ||
338
+ options.onError ||
339
+ options.invoke ||
340
+ async) {
341
+ const before = options.before || (() => { });
342
+ const after = options.after || (() => { });
343
+ const onError = options.onError ||
344
+ ((err) => {
345
+ throw err;
346
+ });
347
+ const invoke = options.invoke;
348
+ const context = options.context;
349
+ const scriptFunc = func;
350
+ const finalFunc = invoke
351
+ ? (...args) => invoke(() => scriptFunc(...args), context)
352
+ : scriptFunc;
353
+ if (async) {
354
+ func = function __wrapperFunc(...args) {
355
+ before(context);
356
+ try {
357
+ let result = finalFunc(...args);
358
+ if (!(result instanceof Promise)) {
359
+ result = new Promise((resolve, reject) => {
360
+ result.then(resolve, reject);
361
+ });
362
+ }
363
+ return result.catch((ex) => {
364
+ onError(ex, context, meta);
365
+ });
366
+ }
367
+ catch (ex) {
368
+ onError(ex, context, meta);
369
+ }
370
+ finally {
371
+ after(context);
372
+ }
373
+ };
374
+ if (isInterpretableFunction(scriptFunc)) {
375
+ const interpretableFunc = getInterpretableFunction(scriptFunc);
376
+ const finalFunc = invoke
377
+ ? (...args) => invoke(() => interpretableFunc(...args), context)
378
+ : interpretableFunc;
379
+ const interpretable = function* __wrapperFunc(...args) {
380
+ before(context);
381
+ try {
382
+ let result = yield* finalFunc(...args);
383
+ if (!(result instanceof Promise)) {
384
+ result = new Promise((resolve, reject) => {
385
+ result.then(resolve, reject);
386
+ });
387
+ }
388
+ return result.catch((ex) => {
389
+ onError(ex, context, meta);
390
+ });
391
+ }
392
+ catch (ex) {
393
+ onError(ex, context, meta);
394
+ }
395
+ finally {
396
+ after(context);
397
+ }
398
+ };
399
+ tagAsInterpretableFunction(interpretable, func);
400
+ }
401
+ }
402
+ else {
403
+ func = function __wrapperFunc(...args) {
404
+ before(context);
405
+ try {
406
+ return finalFunc(...args);
407
+ }
408
+ catch (ex) {
409
+ onError(ex, context, meta);
410
+ }
411
+ finally {
412
+ after(context);
413
+ }
414
+ };
415
+ if (isInterpretableFunction(scriptFunc)) {
416
+ const interpretableFunc = getInterpretableFunction(scriptFunc);
417
+ const finalFunc = invoke
418
+ ? (...args) => invoke(() => interpretableFunc(...args), context)
419
+ : interpretableFunc;
420
+ const interpretable = function* __wrapperFunc(...args) {
421
+ before(context);
422
+ try {
423
+ return yield* finalFunc(...args);
424
+ }
425
+ catch (ex) {
426
+ onError(ex, context, meta);
427
+ }
428
+ finally {
429
+ after(context);
430
+ }
431
+ };
432
+ tagAsInterpretableFunction(interpretable, func);
433
+ }
434
+ }
435
+ }
436
+ }
437
+ const final = func;
438
+ final.metadata = meta;
439
+ if ((_a = meta.constructedFunction) === null || _a === void 0 ? void 0 : _a.module) {
440
+ Object.defineProperty(meta.constructedFunction.module, FUNCTION_METADATA, {
441
+ value: meta,
442
+ writable: false,
443
+ enumerable: false,
444
+ configurable: true,
445
+ });
446
+ }
447
+ return final;
448
+ }
449
+ /**
450
+ * Finds the line number information for a function created with this compiler using the
451
+ * given stack trace and metadata.
452
+ * @param stackTrace The stack trace.
453
+ * @param metadata The metadata.
454
+ */
455
+ findLineInfo(stackTrace, metadata) {
456
+ const frame = stackTrace.find((f) => {
457
+ const func = f.getFunction();
458
+ return func && func[COMPILED_SCRIPT_SYMBOL] === true;
459
+ });
460
+ if (frame) {
461
+ const line = frame.getLineNumber();
462
+ const column = frame.getColumnNumber();
463
+ const result = {
464
+ line: null,
465
+ column: null,
466
+ };
467
+ if (hasValue(line)) {
468
+ result.line = line - metadata.scriptLineOffset;
469
+ }
470
+ if (hasValue(column)) {
471
+ result.column = column;
472
+ }
473
+ return result;
474
+ }
475
+ return null;
476
+ }
477
+ /**
478
+ * Sets the given breakpoint.
479
+ * @param breakpoint The breakpoint that should be set.
480
+ */
481
+ setBreakpoint(breakpoint) {
482
+ const metadata = breakpoint.func.metadata;
483
+ if (!metadata.constructedFunction) {
484
+ throw new Error('Cannot set breakpoints for non-interpreted functions.');
485
+ }
486
+ if (!breakpoint.interpreter) {
487
+ throw new Error('You must provide an interpreter when setting a breakpoint.');
488
+ }
489
+ const func = metadata.constructedFunction;
490
+ const interpreter = breakpoint.interpreter;
491
+ const loc = this.calculateFinalLineLocation(breakpoint.func, {
492
+ lineNumber: breakpoint.lineNumber - 1,
493
+ column: breakpoint.columnNumber - 1,
494
+ });
495
+ interpreter.setBreakpoint({
496
+ id: breakpoint.id,
497
+ func,
498
+ lineNumber: loc.lineNumber + 1,
499
+ columnNumber: loc.column + 1,
500
+ states: breakpoint.states,
501
+ });
502
+ }
503
+ listPossibleBreakpoints(func, interpreter) {
504
+ const metadata = func.metadata;
505
+ if (!metadata.constructedFunction) {
506
+ throw new Error('Cannot list possible breakpoints for non-interpreted functions.');
507
+ }
508
+ if (!interpreter) {
509
+ throw new Error('You must provide an interpreter when listing possible breakpoints.');
510
+ }
511
+ const code = metadata.constructedFunction.func
512
+ .ECMAScriptCode;
513
+ const returnStatement = code.FunctionStatementList.find((s) => s.type === 'ReturnStatement');
514
+ const functionDeclaration = returnStatement.Expression;
515
+ const body = 'FunctionBody' in functionDeclaration
516
+ ? functionDeclaration.FunctionBody
517
+ : functionDeclaration.AsyncFunctionBody;
518
+ const possibleBreakpoints = interpreter.listPossibleBreakpoints(body);
519
+ let returnedValues = [];
520
+ for (let pb of possibleBreakpoints) {
521
+ if (pb.lineNumber <
522
+ metadata.scriptLineOffset + metadata.transpilerLineOffset) {
523
+ continue;
524
+ }
525
+ const loc = this.calculateOriginalLineLocation(func, {
526
+ lineNumber: pb.lineNumber,
527
+ column: pb.columnNumber,
528
+ });
529
+ if (loc.lineNumber < 0 || loc.column < 0) {
530
+ continue;
531
+ }
532
+ returnedValues.push({
533
+ lineNumber: loc.lineNumber + 1,
534
+ columnNumber: loc.column + 1,
535
+ possibleStates: pb.possibleStates,
536
+ });
537
+ }
538
+ return returnedValues;
539
+ }
540
+ _parseScript(script) {
541
+ return script;
542
+ }
543
+ _compileFunction(script, options) {
544
+ // Yes this code is super ugly.
545
+ // Some day we will engineer this into a real
546
+ // compiler, but for now this ad-hoc method
547
+ // seems to work.
548
+ var _a, _b;
549
+ let async = false;
550
+ if (isScript(script)) {
551
+ script = parseScript(script);
552
+ }
553
+ if (script.indexOf('await ') >= 0) {
554
+ async = true;
555
+ }
556
+ script = this._parseScript(script);
557
+ let transpilerLineOffset = 0;
558
+ let scriptLineOffset = 0;
559
+ let customGlobalThis = false;
560
+ let constantsCode = '';
561
+ if (options.constants) {
562
+ const lines = Object.keys(options.constants)
563
+ .filter((v) => v !== 'this')
564
+ .map((v) => `const ${v} = constants["${v}"];`);
565
+ customGlobalThis =
566
+ !options.interpreter && 'globalThis' in options.constants;
567
+ constantsCode = lines.join('\n') + '\n';
568
+ scriptLineOffset += 1 + Math.max(lines.length - 1, 0);
569
+ }
570
+ let variablesCode = '';
571
+ if (options.variables) {
572
+ const lines = Object.keys(options.variables)
573
+ .filter((v) => v !== 'this')
574
+ .map((v) => `const ${v} = variables["${v}"](context);`);
575
+ variablesCode = '\n' + lines.join('\n');
576
+ transpilerLineOffset += 1 + Math.max(lines.length - 1, 0);
577
+ }
578
+ let argumentsCode = '';
579
+ if (options.arguments) {
580
+ const lines = flatMap(options.arguments
581
+ .filter((v) => v !== 'this')
582
+ .map((v, i) => Array.isArray(v)
583
+ ? [v, i]
584
+ : [[v], i]), ([v, i]) => v.map((name) => `const ${name} = args[${i}];`));
585
+ argumentsCode = '\n' + lines.join('\n');
586
+ transpilerLineOffset += 1 + Math.max(lines.length - 1, 0);
587
+ }
588
+ let scriptCode;
589
+ scriptCode = `\n { \n${script}\n }`;
590
+ transpilerLineOffset += 2;
591
+ let withCodeStart = '';
592
+ let withCodeEnd = '';
593
+ if (customGlobalThis) {
594
+ withCodeStart = 'with(__globalObj) {\n';
595
+ withCodeEnd = '}';
596
+ scriptLineOffset += 1;
597
+ }
598
+ let syntaxErrorLineOffset = 0;
599
+ // Function needs a name because acorn doesn't understand
600
+ // that this function is allowed to be anonymous.
601
+ let functionCode = `function ${(_a = options.functionName) !== null && _a !== void 0 ? _a : '_'}(...args) { ${argumentsCode}${variablesCode}${scriptCode}\n }`;
602
+ if (async) {
603
+ functionCode = `async ` + functionCode;
604
+ }
605
+ try {
606
+ if (options.forceSync) {
607
+ async = false;
608
+ }
609
+ this._transpiler.forceSync = (_b = options.forceSync) !== null && _b !== void 0 ? _b : false;
610
+ const transpiled = this._transpiler.transpileWithMetadata(functionCode);
611
+ if (options.interpreter) {
612
+ const finalCode = `${constantsCode}return ${transpiled.code};`;
613
+ syntaxErrorLineOffset += 1;
614
+ scriptLineOffset += 1;
615
+ const func = options.interpreter.createFunction('test', finalCode, 'constants', 'variables', 'context');
616
+ let result = unwind(options.interpreter.callFunction(func, options.constants, options.variables, options.interpreter.proxyObject(options.context)));
617
+ let finalFunc = result;
618
+ if (options.variables) {
619
+ if ('this' in options.variables) {
620
+ finalFunc = result.bind(options.variables['this'](options.context));
621
+ }
622
+ }
623
+ if (INTERPRETER_OBJECT in result) {
624
+ finalFunc = createInterpretableFunction(finalFunc);
625
+ finalFunc[INTERPRETER_OBJECT] = result[INTERPRETER_OBJECT];
626
+ }
627
+ return {
628
+ func: finalFunc,
629
+ scriptLineOffset,
630
+ transpilerLineOffset,
631
+ async,
632
+ transpilerResult: transpiled,
633
+ constructedFunction: func,
634
+ };
635
+ }
636
+ else {
637
+ const finalCode = `${withCodeStart}return function(constants, variables, context) { ${constantsCode}return ${transpiled.code}; }${withCodeEnd}`;
638
+ let func = this._buildFunction(finalCode, options);
639
+ func[COMPILED_SCRIPT_SYMBOL] = true;
640
+ // Add 1 extra line to count the line feeds that
641
+ // is automatically inserted at the start of the script as part of the process of
642
+ // compiling the dynamic script.
643
+ // See https://tc39.es/ecma262/#sec-createdynamicfunction
644
+ scriptLineOffset += 2;
645
+ if (options.variables) {
646
+ if ('this' in options.variables) {
647
+ func = func.bind(options.variables['this'](options.context));
648
+ }
649
+ }
650
+ return {
651
+ func,
652
+ scriptLineOffset: scriptLineOffset,
653
+ transpilerLineOffset: transpilerLineOffset,
654
+ async,
655
+ transpilerResult: transpiled,
656
+ constructedFunction: null,
657
+ };
658
+ }
659
+ }
660
+ catch (err) {
661
+ if (err instanceof SyntaxError) {
662
+ const replaced = replaceSyntaxErrorLineNumber(err, (location) => ({
663
+ lineNumber: location.lineNumber -
664
+ transpilerLineOffset -
665
+ syntaxErrorLineOffset,
666
+ column: location.column,
667
+ }));
668
+ if (replaced) {
669
+ throw replaced;
670
+ }
671
+ }
672
+ throw err;
673
+ }
674
+ }
675
+ _buildFunction(finalCode, options) {
676
+ var _a;
677
+ return this.__constructFunction(finalCode)((_a = options.constants) === null || _a === void 0 ? void 0 : _a.globalThis)(options.constants, options.variables, options.context);
678
+ }
679
+ __constructFunction(finalCode) {
680
+ let existing = this._functionCache.get(finalCode);
681
+ if (!existing) {
682
+ existing = Function('__globalObj', finalCode);
683
+ this._functionCache.set(finalCode, existing);
684
+ }
685
+ return existing;
686
+ }
687
+ }
688
+ const SYNTAX_ERROR_LINE_NUMBER_REGEX = /\((\d+):(\d+)\)$/;
689
+ /**
690
+ * Parses the line and column numbers from the the given syntax error, transforms them with the given function,
691
+ * and returns a new syntax error that contains the new location. Returns null if the line and column numbers could not be parsed.
692
+ * @param error The error to transform.
693
+ * @param transform The function that should be used to transform the errors.
694
+ * @returns
695
+ */
696
+ export function replaceSyntaxErrorLineNumber(error, transform) {
697
+ const matches = SYNTAX_ERROR_LINE_NUMBER_REGEX.exec(error.message);
698
+ if (matches) {
699
+ const [str, line, column] = matches;
700
+ const lineNumber = parseInt(line);
701
+ const columnNumber = parseInt(column);
702
+ const location = transform({
703
+ lineNumber,
704
+ column: columnNumber,
705
+ });
706
+ return new SyntaxError(error.message.replace(str, `(${location.lineNumber}:${location.column})`));
707
+ }
708
+ else {
709
+ return null;
710
+ }
711
+ }
712
+ // export class CompiledScriptError extends Error {
713
+ // /**
714
+ // * The inner error.
715
+ // */
716
+ // error: Error;
717
+ // constructor(error: Error) {
718
+ // super(error.message);
719
+ // this.error = error;
720
+ // }
721
+ // }
722
+ //# sourceMappingURL=AuxCompiler.js.map