@flamework-experimental/transformer 2.0.0-alpha.0

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 (72) hide show
  1. package/README.md +66 -0
  2. package/flamework-schema.json +76 -0
  3. package/flamework.config.schema.json +197 -0
  4. package/out/classes/buildInfo.js +467 -0
  5. package/out/classes/diagnostics.js +110 -0
  6. package/out/classes/logger.js +201 -0
  7. package/out/classes/nodeMetadata.js +232 -0
  8. package/out/classes/transformState.js +623 -0
  9. package/out/index.js +75 -0
  10. package/out/transformations/expressions/transformAccessExpression.js +35 -0
  11. package/out/transformations/expressions/transformBinaryExpression.js +57 -0
  12. package/out/transformations/expressions/transformCallExpression.js +33 -0
  13. package/out/transformations/expressions/transformDeleteExpression.js +22 -0
  14. package/out/transformations/expressions/transformNewExpression.js +17 -0
  15. package/out/transformations/expressions/transformUnaryExpression.js +63 -0
  16. package/out/transformations/macros/intrinsics/components.js +64 -0
  17. package/out/transformations/macros/intrinsics/env.js +31 -0
  18. package/out/transformations/macros/intrinsics/guards.js +43 -0
  19. package/out/transformations/macros/intrinsics/inlining.js +22 -0
  20. package/out/transformations/macros/intrinsics/networking.js +131 -0
  21. package/out/transformations/macros/intrinsics/parameters.js +81 -0
  22. package/out/transformations/macros/intrinsics/paths.js +42 -0
  23. package/out/transformations/macros/updateComponentConfig.js +409 -0
  24. package/out/transformations/plugins/nodeFactory.js +159 -0
  25. package/out/transformations/plugins/pluginHost.js +235 -0
  26. package/out/transformations/plugins/typeFacade.js +242 -0
  27. package/out/transformations/statements/transformClassDeclaration.js +282 -0
  28. package/out/transformations/transformExpression.js +34 -0
  29. package/out/transformations/transformFile.js +78 -0
  30. package/out/transformations/transformNetworkingCall.js +566 -0
  31. package/out/transformations/transformNode.js +27 -0
  32. package/out/transformations/transformStatement.js +57 -0
  33. package/out/transformations/transformStatementList.js +64 -0
  34. package/out/transformations/transformUserMacro.js +698 -0
  35. package/out/transformer.js +52 -0
  36. package/out/util/cache.js +10 -0
  37. package/out/util/constants.js +5 -0
  38. package/out/util/diagnosticsUtils.js +112 -0
  39. package/out/util/env.js +267 -0
  40. package/out/util/factory.js +583 -0
  41. package/out/util/functions/addLeadingComment.js +13 -0
  42. package/out/util/functions/arePathsEqual.js +14 -0
  43. package/out/util/functions/assert.js +17 -0
  44. package/out/util/functions/buildGuardFromType.js +713 -0
  45. package/out/util/functions/buildInstanceShape.js +156 -0
  46. package/out/util/functions/buildSerializerFromType.js +2309 -0
  47. package/out/util/functions/createPathTranslator.js +54 -0
  48. package/out/util/functions/emitTypescriptMismatch.js +80 -0
  49. package/out/util/functions/getDeclarationName.js +23 -0
  50. package/out/util/functions/getDeclarationOfType.js +7 -0
  51. package/out/util/functions/getIndexExpression.js +16 -0
  52. package/out/util/functions/getInstanceTypeFromType.js +75 -0
  53. package/out/util/functions/getNodeList.js +6 -0
  54. package/out/util/functions/getPackageJson.js +44 -0
  55. package/out/util/functions/getSuperClasses.js +51 -0
  56. package/out/util/functions/isAttributesAccess.js +23 -0
  57. package/out/util/functions/isCleanBuildDirectory.js +13 -0
  58. package/out/util/functions/isDefinedType.js +16 -0
  59. package/out/util/functions/isPathDescendantOf.js +25 -0
  60. package/out/util/functions/isTupleType.js +10 -0
  61. package/out/util/functions/parseCommandLine.js +31 -0
  62. package/out/util/functions/shuffle.js +39 -0
  63. package/out/util/functions/tryResolve.js +15 -0
  64. package/out/util/functions/validateConstraintMetadata.js +60 -0
  65. package/out/util/packages.js +12 -0
  66. package/out/util/projectConfig.js +221 -0
  67. package/out/util/schema.js +80 -0
  68. package/out/util/tsInternals.js +16 -0
  69. package/out/util/uid.js +227 -0
  70. package/package.json +45 -0
  71. package/rojo-schema.json +34 -0
  72. package/types.d.ts +4 -0
@@ -0,0 +1,566 @@
1
+ "use strict";
2
+ var __read = (this && this.__read) || function (o, n) {
3
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
4
+ if (!m) return o;
5
+ var i = m.call(o), r, ar = [], e;
6
+ try {
7
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
8
+ }
9
+ catch (error) { e = { error: error }; }
10
+ finally {
11
+ try {
12
+ if (r && !r.done && (m = i["return"])) m.call(i);
13
+ }
14
+ finally { if (e) throw e.error; }
15
+ }
16
+ return ar;
17
+ };
18
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
19
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
20
+ if (ar || !(i in from)) {
21
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
22
+ ar[i] = from[i];
23
+ }
24
+ }
25
+ return to.concat(ar || Array.prototype.slice.call(from));
26
+ };
27
+ var __values = (this && this.__values) || function(o) {
28
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
29
+ if (m) return m.call(o);
30
+ if (o && typeof o.length === "number") return {
31
+ next: function () {
32
+ if (o && i >= o.length) o = void 0;
33
+ return { value: o && o[i++], done: !o };
34
+ }
35
+ };
36
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
37
+ };
38
+ var __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.transformNetworkingCall = transformNetworkingCall;
43
+ var typescript_1 = __importDefault(require("typescript"));
44
+ var diagnostics_1 = require("../classes/diagnostics");
45
+ var factory_1 = require("../util/factory");
46
+ var buildSerializerFromType_1 = require("../util/functions/buildSerializerFromType");
47
+ var packages_1 = require("../util/packages");
48
+ /**
49
+ * With `networking.serialization` on, a call that sends over a networking handler packs its
50
+ * argument list right where it is made: the encoding is generated inline from the handler's types
51
+ * and the packed `(payload, blobs?)` goes to the handler's hidden `_fire` / `_invoke` entry point.
52
+ * A function receiver's callback is wrapped the same way so that its results leave packed.
53
+ *
54
+ * Nothing in the output can encode on its own; only these call sites do. Decoding stays in the
55
+ * handler metadata, because a remote's payload has to be unpacked before the guards and middleware
56
+ * see it, which is why the receiving side needs a function and the sending side does not.
57
+ *
58
+ * Call sites are found by type: the handler members carry hidden `_flamework_send` /
59
+ * `_flamework_fn` markers. A member declared `Networking.Raw*` has no marker and is left alone, as is
60
+ * a handler reached through a widened type (which then sends unpacked values that the peer rejects
61
+ * as malformed). A handler reached through `?.` is typed with `undefined` in it; the marker is looked
62
+ * for on the rest. An argument list that carries nothing (`bump(): void`) sends no payload at all.
63
+ */
64
+ /** Sending methods and the hidden entry point each becomes. */
65
+ var SENDERS = {
66
+ fire: "_fire",
67
+ except: "_except",
68
+ broadcast: "_broadcast",
69
+ invoke: "_invoke",
70
+ invokeWithTimeout: "_invokeWithTimeout",
71
+ };
72
+ function transformNetworkingCall(state, node) {
73
+ var _a;
74
+ if (((_a = state.projectConfig.networking) === null || _a === void 0 ? void 0 : _a.serialization) !== true)
75
+ return;
76
+ var typeChecker = state.typeChecker;
77
+ var callee = node.expression;
78
+ if (factory_1.f.is.propertyAccessExpression(callee)) {
79
+ var name_1 = callee.name.text;
80
+ var target_1 = typeChecker.getNonNullableType(typeChecker.getTypeAtLocation(callee.expression));
81
+ var optional = callee.questionDotToken !== undefined;
82
+ if (name_1 === "setCallback" && target_1.getProperty("_flamework_fn")) {
83
+ return transformReceiverCallback(state, node, callee.expression, target_1, optional);
84
+ }
85
+ if (SENDERS[name_1] !== undefined && target_1.getProperty("_flamework_send")) {
86
+ return transformSend(state, node, callee.expression, target_1, SENDERS[name_1], optional);
87
+ }
88
+ }
89
+ // `handler.event(...)` and `handler.fn(...)`: the call signature is the sender itself.
90
+ var target = typeChecker.getNonNullableType(typeChecker.getTypeAtLocation(callee));
91
+ if (target.getProperty("_flamework_send")) {
92
+ var method = target.getProperty("_invoke") ? "_invoke" : "_fire";
93
+ return transformSend(state, node, callee, target, method, node.questionDotToken !== undefined);
94
+ }
95
+ }
96
+ /**
97
+ * `handler.x.fire(lead..., a, b)` becomes `handler.x._fire(lead..., payload, blobs?)`, with the packing
98
+ * emitted ahead of the statement. The leading arguments (players, a timeout) pass through. The
99
+ * target is evaluated first, as the call would: one that is more than a plain read is bound to a
100
+ * local ahead of the arguments.
101
+ */
102
+ function transformSend(state, node, target, targetType, method, optionalTarget) {
103
+ var typeChecker = state.typeChecker;
104
+ var signature = typeChecker.getResolvedSignature(node);
105
+ var declaration = signature === null || signature === void 0 ? void 0 : signature.declaration;
106
+ if (!declaration || !typescript_1.default.isFunctionLike(declaration))
107
+ return;
108
+ // The declared signature is `(lead..., ...args: I)`; the resolved one has `I` expanded.
109
+ var restIndex = declaration.parameters.findIndex(function (parameter) { return parameter.dotDotDotToken !== undefined; });
110
+ if (restIndex === -1)
111
+ return;
112
+ var listType = markerType(state, targetType, "_flamework_send", node);
113
+ if (!listType)
114
+ return;
115
+ var args = node.arguments.map(function (argument) { return state.transformNode(argument); });
116
+ var leading = args.slice(0, restIndex);
117
+ var packed = args.slice(restIndex);
118
+ if (leading.some(typescript_1.default.isSpreadElement)) {
119
+ diagnostics_1.Diagnostics.error(node, "Flamework cannot pack this call: a spread argument ahead of the payload is not supported with networking.serialization enabled.");
120
+ }
121
+ var statements = new Array();
122
+ var chained = guardOptionalChain(state, statements, target, optionalTarget);
123
+ var transformedTarget = chained.target;
124
+ var leadingValues = leading.map(function (argument, index) {
125
+ return bindArgument(statements, argument, "target", emptyListAnnotation(state, node.arguments[index]));
126
+ });
127
+ var encoding;
128
+ if (packed.some(typescript_1.default.isSpreadElement)) {
129
+ // A spread makes the count a runtime matter: gather the list first, as `fire` itself would.
130
+ var table = factory_1.f.identifier("args", true);
131
+ statements.push(factory_1.f.variableStatement(table, factory_1.f.as(factory_1.f.array(packed, false), arrayType())));
132
+ encoding = (0, buildSerializerFromType_1.buildInlineEncoding)(state, node, listType, { table: table });
133
+ }
134
+ else {
135
+ var values = packed.map(function (argument) { return bindArgument(statements, argument, "arg"); });
136
+ encoding = (0, buildSerializerFromType_1.buildInlineEncoding)(state, node, listType, values);
137
+ }
138
+ statements.push.apply(statements, __spreadArray([], __read(encoding.statements), false));
139
+ var call = factory_1.f.call(factory_1.f.propertyAccessExpression(transformedTarget, factory_1.f.identifier(method)), __spreadArray(__spreadArray([], __read(leadingValues), false), __read(packedArguments(encoding)), false));
140
+ return emitWithStatements(state, node, statements, call, __spreadArray([target], __read(args), false), chained.wrap);
141
+ }
142
+ /**
143
+ * The target of a send or `setCallback`, evaluated ahead of the arguments the way the call would
144
+ * evaluate it: a plain read stays where it is, anything else is bound to a local first.
145
+ *
146
+ * A target reached through `?.` decides whether the call happens at all, so the packing has to
147
+ * stay behind that decision: the call is wrapped in a function (`wrap`) that returns `undefined`
148
+ * where the chain would short-circuit. The test goes on the operand ahead of each `?.` when every
149
+ * one of them is a reference, which keeps the narrowing the chain gave the arguments; otherwise
150
+ * the target is bound to a local and the test goes on that.
151
+ */
152
+ function guardOptionalChain(state, statements, target, optionalTarget) {
153
+ var e_1, _a;
154
+ var transformedTarget = state.transformNode(target);
155
+ var operands = optionalOperands(target, optionalTarget);
156
+ if (operands.length > 0 && operands.every(isReference)) {
157
+ try {
158
+ for (var operands_1 = __values(operands), operands_1_1 = operands_1.next(); !operands_1_1.done; operands_1_1 = operands_1.next()) {
159
+ var operand = operands_1_1.value;
160
+ statements.push(shortCircuit(state.transformNode(operand)));
161
+ }
162
+ }
163
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
164
+ finally {
165
+ try {
166
+ if (operands_1_1 && !operands_1_1.done && (_a = operands_1.return)) _a.call(operands_1);
167
+ }
168
+ finally { if (e_1) throw e_1.error; }
169
+ }
170
+ }
171
+ else if (operands.length > 0) {
172
+ var bound_1 = bindArgument(statements, transformedTarget, "target");
173
+ statements.push(shortCircuit(bound_1));
174
+ return { target: bound_1, wrap: true };
175
+ }
176
+ var bound = isPure(target) ? transformedTarget : bindArgument(statements, transformedTarget, "target");
177
+ return { target: bound, wrap: operands.length > 0 };
178
+ }
179
+ /** `if (value === undefined) return undefined;` */
180
+ function shortCircuit(value) {
181
+ return typescript_1.default.factory.createIfStatement(factory_1.f.binary(value, typescript_1.default.SyntaxKind.EqualsEqualsEqualsToken, factory_1.f.nil()), factory_1.f.block([factory_1.f.returnStatement(factory_1.f.nil())]));
182
+ }
183
+ /**
184
+ * The operands ahead of each `?.` in `target`, outermost first, then `target` itself when the
185
+ * access after it is the optional one (`handler.x?.fire(...)`).
186
+ */
187
+ function optionalOperands(target, optionalTarget) {
188
+ var operands = new Array();
189
+ var current = target;
190
+ while (typescript_1.default.isPropertyAccessExpression(current) ||
191
+ typescript_1.default.isElementAccessExpression(current) ||
192
+ typescript_1.default.isCallExpression(current) ||
193
+ typescript_1.default.isNonNullExpression(current)) {
194
+ if (!typescript_1.default.isNonNullExpression(current) && current.questionDotToken)
195
+ operands.unshift(current.expression);
196
+ current = current.expression;
197
+ }
198
+ if (optionalTarget)
199
+ operands.push(target);
200
+ return operands;
201
+ }
202
+ /** A reference TypeScript narrows: an identifier, `this`, or a property (or literal index) of one. */
203
+ function isReference(node) {
204
+ if (typescript_1.default.isIdentifier(node) || node.kind === typescript_1.default.SyntaxKind.ThisKeyword)
205
+ return true;
206
+ if (typescript_1.default.isParenthesizedExpression(node) || typescript_1.default.isPropertyAccessExpression(node))
207
+ return isReference(node.expression);
208
+ if (typescript_1.default.isElementAccessExpression(node)) {
209
+ var index = node.argumentExpression;
210
+ return (typescript_1.default.isStringLiteral(index) || typescript_1.default.isNumericLiteral(index)) && isReference(node.expression);
211
+ }
212
+ return false;
213
+ }
214
+ /** `payload, blobs`, `payload`, or nothing at all when the list carries nothing. */
215
+ function packedArguments(encoding) {
216
+ if (!encoding.payload)
217
+ return [];
218
+ return encoding.blobs ? [encoding.payload, encoding.blobs] : [encoding.payload];
219
+ }
220
+ /**
221
+ * The packing statements go ahead of the enclosing statement when that keeps them in the call's
222
+ * scope and runs them exactly when the call runs: once, unconditionally, and ahead of nothing that
223
+ * could tell the difference. Anywhere else -- behind `&&`, `||`, `??` or a conditional, in a loop
224
+ * condition, after a sibling with side effects, or inside an expression-bodied arrow, which has no
225
+ * statement of its own -- the call is wrapped in an immediately invoked function that holds them.
226
+ * `wrap` asks for that function outright: the statements then hold a short-circuit of their own.
227
+ */
228
+ function emitWithStatements(state, node, statements, call, hoisted, wrap) {
229
+ if (wrap === void 0) { wrap = false; }
230
+ if (statements.length === 0)
231
+ return call;
232
+ if (wrap || !hoistsCleanly(node, hoisted)) {
233
+ return factory_1.f.call(factory_1.f.arrowFunction(factory_1.f.block(__spreadArray(__spreadArray([], __read(statements), false), [factory_1.f.returnStatement(call)], false))), []);
234
+ }
235
+ state.prereqList(statements);
236
+ return call;
237
+ }
238
+ /**
239
+ * Whether evaluating `hoisted` ahead of the statement that holds `node` is the same as evaluating it
240
+ * where `node` is: the position must be reached once and unconditionally, and whatever the
241
+ * statement evaluates before it must be unable to notice the difference -- plain reads on both
242
+ * sides, or nothing that reads at all on that side.
243
+ */
244
+ function hoistsCleanly(node, hoisted) {
245
+ var ahead = new Array();
246
+ var child = node;
247
+ var parent = node.parent;
248
+ while (parent !== undefined && !typescript_1.default.isStatement(parent)) {
249
+ if (typescript_1.default.isFunctionLike(parent))
250
+ return false;
251
+ var before = evaluatedBefore(parent, child);
252
+ if (before === undefined)
253
+ return false;
254
+ ahead.push.apply(ahead, __spreadArray([], __read(before), false));
255
+ child = parent;
256
+ parent = parent.parent;
257
+ }
258
+ if (parent !== undefined && isRepeatedIn(parent, child))
259
+ return false;
260
+ if (!ahead.every(isPure))
261
+ return false;
262
+ return ahead.every(isConstant) || hoisted.every(isPure);
263
+ }
264
+ /**
265
+ * The expressions `parent` evaluates before `child` when `child` is evaluated once and
266
+ * unconditionally as part of it, or `undefined` when it is not (a short-circuited operand, a
267
+ * conditional branch, a `case` label) or the position is not one this understands.
268
+ */
269
+ function evaluatedBefore(parent, child) {
270
+ var e_2, _a;
271
+ var _b;
272
+ if (typescript_1.default.isParenthesizedExpression(parent) ||
273
+ typescript_1.default.isAsExpression(parent) ||
274
+ typescript_1.default.isTypeAssertionExpression(parent) ||
275
+ typescript_1.default.isNonNullExpression(parent) ||
276
+ typescript_1.default.isSatisfiesExpression(parent) ||
277
+ typescript_1.default.isAwaitExpression(parent) ||
278
+ typescript_1.default.isYieldExpression(parent) ||
279
+ typescript_1.default.isVoidExpression(parent) ||
280
+ typescript_1.default.isTypeOfExpression(parent) ||
281
+ typescript_1.default.isDeleteExpression(parent) ||
282
+ typescript_1.default.isPrefixUnaryExpression(parent) ||
283
+ typescript_1.default.isSpreadElement(parent) ||
284
+ typescript_1.default.isSpreadAssignment(parent) ||
285
+ typescript_1.default.isTemplateSpan(parent)) {
286
+ return [];
287
+ }
288
+ if (typescript_1.default.isPropertyAccessExpression(parent)) {
289
+ return child === parent.expression ? [] : undefined;
290
+ }
291
+ if (typescript_1.default.isElementAccessExpression(parent)) {
292
+ return child === parent.expression ? [] : [parent.expression];
293
+ }
294
+ if (typescript_1.default.isCallExpression(parent) || typescript_1.default.isNewExpression(parent)) {
295
+ if (child === parent.expression)
296
+ return [];
297
+ var args = (_b = parent.arguments) !== null && _b !== void 0 ? _b : [];
298
+ var index = args.indexOf(child);
299
+ return index === -1 ? undefined : __spreadArray([parent.expression], __read(args.slice(0, index)), false);
300
+ }
301
+ if (typescript_1.default.isBinaryExpression(parent)) {
302
+ if (child === parent.left)
303
+ return [];
304
+ var operator = parent.operatorToken.kind;
305
+ if (operator === typescript_1.default.SyntaxKind.AmpersandAmpersandToken ||
306
+ operator === typescript_1.default.SyntaxKind.BarBarToken ||
307
+ operator === typescript_1.default.SyntaxKind.QuestionQuestionToken) {
308
+ return undefined;
309
+ }
310
+ if (!isAssignmentOperator(operator))
311
+ return [parent.left];
312
+ // An assignment target is not a value: what runs ahead of the right-hand side is the object
313
+ // (and index) it is stored into.
314
+ if (typescript_1.default.isIdentifier(parent.left))
315
+ return [];
316
+ if (typescript_1.default.isPropertyAccessExpression(parent.left))
317
+ return [parent.left.expression];
318
+ if (typescript_1.default.isElementAccessExpression(parent.left)) {
319
+ return [parent.left.expression, parent.left.argumentExpression];
320
+ }
321
+ return undefined;
322
+ }
323
+ if (typescript_1.default.isConditionalExpression(parent)) {
324
+ return child === parent.condition ? [] : undefined;
325
+ }
326
+ if (typescript_1.default.isArrayLiteralExpression(parent)) {
327
+ var index = parent.elements.indexOf(child);
328
+ return index === -1 ? undefined : parent.elements.slice(0, index);
329
+ }
330
+ if (typescript_1.default.isPropertyAssignment(parent)) {
331
+ if (child !== parent.initializer)
332
+ return undefined;
333
+ return typescript_1.default.isComputedPropertyName(parent.name) ? [parent.name.expression] : [];
334
+ }
335
+ if (typescript_1.default.isObjectLiteralExpression(parent)) {
336
+ var index = parent.properties.indexOf(child);
337
+ if (index === -1)
338
+ return undefined;
339
+ var before = new Array();
340
+ try {
341
+ for (var _c = __values(parent.properties.slice(0, index)), _d = _c.next(); !_d.done; _d = _c.next()) {
342
+ var property = _d.value;
343
+ if (typescript_1.default.isPropertyAssignment(property)) {
344
+ if (typescript_1.default.isComputedPropertyName(property.name))
345
+ before.push(property.name.expression);
346
+ before.push(property.initializer);
347
+ }
348
+ else if (typescript_1.default.isShorthandPropertyAssignment(property)) {
349
+ before.push(property.name);
350
+ }
351
+ else if (typescript_1.default.isSpreadAssignment(property)) {
352
+ before.push(property.expression);
353
+ }
354
+ }
355
+ }
356
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
357
+ finally {
358
+ try {
359
+ if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
360
+ }
361
+ finally { if (e_2) throw e_2.error; }
362
+ }
363
+ return before;
364
+ }
365
+ if (typescript_1.default.isTemplateExpression(parent)) {
366
+ var index = parent.templateSpans.indexOf(child);
367
+ return index === -1 ? undefined : parent.templateSpans.slice(0, index).map(function (span) { return span.expression; });
368
+ }
369
+ if (typescript_1.default.isVariableDeclaration(parent)) {
370
+ return child === parent.initializer ? [] : undefined;
371
+ }
372
+ if (typescript_1.default.isVariableDeclarationList(parent)) {
373
+ var index = parent.declarations.indexOf(child);
374
+ if (index === -1)
375
+ return undefined;
376
+ return parent.declarations
377
+ .slice(0, index)
378
+ .map(function (declaration) { return declaration.initializer; })
379
+ .filter(function (initializer) { return initializer !== undefined; });
380
+ }
381
+ return undefined;
382
+ }
383
+ /** Whether `statement` evaluates `child` on every pass of a loop rather than once on the way in. */
384
+ function isRepeatedIn(statement, child) {
385
+ if (typescript_1.default.isWhileStatement(statement) || typescript_1.default.isDoStatement(statement))
386
+ return child === statement.expression;
387
+ if (typescript_1.default.isForStatement(statement))
388
+ return child === statement.condition || child === statement.incrementor;
389
+ return false;
390
+ }
391
+ /** An expression that evaluates without touching state: a literal, a closure, or a plain read. */
392
+ function isPure(node) {
393
+ if (isConstant(node) || typescript_1.default.isIdentifier(node) || node.kind === typescript_1.default.SyntaxKind.ThisKeyword)
394
+ return true;
395
+ if (typescript_1.default.isPropertyAccessExpression(node))
396
+ return isPure(node.expression);
397
+ if (typescript_1.default.isElementAccessExpression(node))
398
+ return isPure(node.expression) && isPure(node.argumentExpression);
399
+ if (typescript_1.default.isParenthesizedExpression(node) ||
400
+ typescript_1.default.isAsExpression(node) ||
401
+ typescript_1.default.isTypeAssertionExpression(node) ||
402
+ typescript_1.default.isNonNullExpression(node) ||
403
+ typescript_1.default.isSatisfiesExpression(node) ||
404
+ typescript_1.default.isTypeOfExpression(node)) {
405
+ return isPure(node.expression);
406
+ }
407
+ if (typescript_1.default.isPrefixUnaryExpression(node)) {
408
+ var mutates = node.operator === typescript_1.default.SyntaxKind.PlusPlusToken || node.operator === typescript_1.default.SyntaxKind.MinusMinusToken;
409
+ return !mutates && isPure(node.operand);
410
+ }
411
+ if (typescript_1.default.isBinaryExpression(node)) {
412
+ return !isAssignmentOperator(node.operatorToken.kind) && isPure(node.left) && isPure(node.right);
413
+ }
414
+ if (typescript_1.default.isTemplateExpression(node))
415
+ return node.templateSpans.every(function (span) { return isPure(span.expression); });
416
+ if (typescript_1.default.isArrayLiteralExpression(node))
417
+ return node.elements.every(isPure);
418
+ if (typescript_1.default.isSpreadElement(node))
419
+ return isPure(node.expression);
420
+ if (typescript_1.default.isObjectLiteralExpression(node)) {
421
+ return node.properties.every(function (property) {
422
+ if (typescript_1.default.isPropertyAssignment(property)) {
423
+ var name_2 = property.name;
424
+ return (!typescript_1.default.isComputedPropertyName(name_2) || isPure(name_2.expression)) && isPure(property.initializer);
425
+ }
426
+ return !typescript_1.default.isSpreadAssignment(property) || isPure(property.expression);
427
+ });
428
+ }
429
+ return false;
430
+ }
431
+ /** `=` and the compound assignments, which TypeScript numbers in one run. */
432
+ function isAssignmentOperator(operator) {
433
+ return operator >= typescript_1.default.SyntaxKind.FirstAssignment && operator <= typescript_1.default.SyntaxKind.LastAssignment;
434
+ }
435
+ /** An expression that reads nothing: a literal, a keyword, or a closure that is only being created. */
436
+ function isConstant(node) {
437
+ return (typescript_1.default.isLiteralExpression(node) ||
438
+ node.kind === typescript_1.default.SyntaxKind.TrueKeyword ||
439
+ node.kind === typescript_1.default.SyntaxKind.FalseKeyword ||
440
+ node.kind === typescript_1.default.SyntaxKind.NullKeyword ||
441
+ typescript_1.default.isArrowFunction(node) ||
442
+ typescript_1.default.isFunctionExpression(node));
443
+ }
444
+ /**
445
+ * `handler.fn.setCallback(cb)` becomes `handler.fn._setCallback((lead..., a, b) => pack(cb(lead..., a, b)))`,
446
+ * where `pack` turns a successful result into `[payload, blobs?]` (or nothing, for a `void` result),
447
+ * follows a Promise if the callback returned one, and lets `Networking.Skip` through untouched.
448
+ */
449
+ function transformReceiverCallback(state, node, target, targetType, optionalTarget) {
450
+ var _a;
451
+ var typeChecker = state.typeChecker;
452
+ var callbackArgument = node.arguments[0];
453
+ if (!callbackArgument)
454
+ return;
455
+ var listType = markerType(state, targetType, "_flamework_receive", node);
456
+ var fnType = markerType(state, targetType, "_flamework_fn", node);
457
+ if (!listType || !fnType)
458
+ return;
459
+ // How many arguments precede the list: the callback type is declared `(lead..., ...args: I) => ...`.
460
+ var signature = typeChecker.getResolvedSignature(node);
461
+ var declaration = signature === null || signature === void 0 ? void 0 : signature.declaration;
462
+ if (!declaration || !typescript_1.default.isFunctionLike(declaration))
463
+ return;
464
+ var callbackType = (_a = declaration.parameters[0]) === null || _a === void 0 ? void 0 : _a.type;
465
+ if (!callbackType || !typescript_1.default.isFunctionTypeNode(callbackType))
466
+ return;
467
+ var leadingCount = callbackType.parameters.filter(function (parameter) { return parameter.dotDotDotToken === undefined; }).length;
468
+ var statements = new Array();
469
+ // The callback keeps the parameter types `setCallback` would have given it: an arrow bound to a
470
+ // plain local would lose its contextual typing and end up with implicit `any` parameters.
471
+ var chained = guardOptionalChain(state, statements, target, optionalTarget);
472
+ var boundTarget = bindArgument(statements, chained.target, "target");
473
+ var callbackAnnotation = factory_1.f.indexedAccessType(factory_1.f.referenceType("Parameters", [factory_1.f.queryType(factory_1.f.qualifiedNameType(boundTarget, "setCallback"))]), factory_1.f.literalType(factory_1.f.number(0)));
474
+ var callback = factory_1.f.identifier("callback", true);
475
+ var transformedCallback = state.transformNode(callbackArgument);
476
+ statements.push(factory_1.f.variableStatement(callback, transformedCallback, callbackAnnotation));
477
+ // The wrapper mirrors the callback's parameters, so nothing is gathered into a table per call.
478
+ var parameters = new Array();
479
+ var forwarded = new Array();
480
+ for (var i = 0; i < leadingCount; i++) {
481
+ var id = factory_1.f.identifier("lead", true);
482
+ parameters.push(factory_1.f.parameterDeclaration(id, factory_1.f.keywordType(typescript_1.default.SyntaxKind.UnknownKeyword)));
483
+ forwarded.push(id);
484
+ }
485
+ if (typeChecker.isTupleType(listType)) {
486
+ var tuple = listType;
487
+ tuple.target.elementFlags.forEach(function (flags) {
488
+ var id = factory_1.f.identifier("arg", true);
489
+ if (flags & typescript_1.default.ElementFlags.Rest) {
490
+ parameters.push(factory_1.f.parameterDeclaration(id, arrayType(), undefined, false, true));
491
+ forwarded.push(typescript_1.default.factory.createSpreadElement(id));
492
+ }
493
+ else {
494
+ parameters.push(factory_1.f.parameterDeclaration(id, factory_1.f.keywordType(typescript_1.default.SyntaxKind.UnknownKeyword)));
495
+ forwarded.push(id);
496
+ }
497
+ });
498
+ }
499
+ var callable = factory_1.f.functionType([factory_1.f.parameterDeclaration("args", arrayType(), undefined, false, true)], factory_1.f.keywordType(typescript_1.default.SyntaxKind.UnknownKeyword));
500
+ var result = factory_1.f.identifier("result", true);
501
+ var body = new Array();
502
+ body.push(factory_1.f.variableStatement(result, factory_1.f.call(factory_1.f.as(callback, callable), forwarded)));
503
+ // A Promise is followed; its value is packed once it resolves.
504
+ var value = factory_1.f.identifier("value", true);
505
+ var packLater = factory_1.f.arrowFunction(factory_1.f.block(packResult(state, node, fnType, value, true)), [
506
+ factory_1.f.parameterDeclaration(value),
507
+ ]);
508
+ body.push(typescript_1.default.factory.createIfStatement(factory_1.f.call(factory_1.f.propertyAccessExpression(factory_1.f.identifier("Promise"), factory_1.f.identifier("is")), [result]), factory_1.f.block([factory_1.f.returnStatement(factory_1.f.call(factory_1.f.propertyAccessExpression(result, factory_1.f.identifier("then")), [packLater]))])));
509
+ body.push.apply(body, __spreadArray([], __read(packResult(state, node, fnType, result, false)), false));
510
+ var wrapper = factory_1.f.arrowFunction(factory_1.f.block(body), parameters);
511
+ var call = factory_1.f.call(factory_1.f.propertyAccessExpression(boundTarget, factory_1.f.identifier("_setCallback")), [wrapper]);
512
+ return emitWithStatements(state, node, statements, call, [target, transformedCallback], chained.wrap);
513
+ }
514
+ /**
515
+ * `if (v === Networking.Skip) return v; <pack v>; return [payload, blobs?]`, or `return undefined`
516
+ * when the result type carries nothing.
517
+ */
518
+ function packResult(state, node, fnType, value, isParameter) {
519
+ var networking = state.addFileImport(state.getSourceFile(node), packages_1.NETWORKING_PACKAGE, "Networking");
520
+ var skip = factory_1.f.propertyAccessExpression(networking, factory_1.f.identifier("Skip"));
521
+ var encoding = (0, buildSerializerFromType_1.buildInlineResultEncoding)(state, node, fnType, value, isParameter);
522
+ var packed = packedArguments(encoding);
523
+ return __spreadArray(__spreadArray([
524
+ typescript_1.default.factory.createIfStatement(factory_1.f.binary(value, typescript_1.default.SyntaxKind.EqualsEqualsEqualsToken, skip), factory_1.f.block([factory_1.f.returnStatement(value)]))
525
+ ], __read(encoding.statements), false), [
526
+ factory_1.f.returnStatement(packed.length > 0 ? factory_1.f.as(factory_1.f.array(packed, false), arrayType()) : factory_1.f.nil()),
527
+ ], false);
528
+ }
529
+ /** The type a hidden marker property carries, without the `undefined` its optionality adds. */
530
+ function markerType(state, type, marker, node) {
531
+ var property = type.getProperty(marker);
532
+ if (!property)
533
+ return;
534
+ var markerType = state.typeChecker.getTypeOfSymbolAtLocation(property, node);
535
+ return state.typeChecker.getNonNullableType(markerType);
536
+ }
537
+ /**
538
+ * An argument that is read more than once is evaluated once, in call order, into a local. Identifiers
539
+ * and literals are returned as they are; anything else comes back as the new local's identifier.
540
+ */
541
+ function bindArgument(statements, argument, hint, annotation) {
542
+ if (typescript_1.default.isIdentifier(argument) ||
543
+ typescript_1.default.isLiteralExpression(argument) ||
544
+ argument.kind === typescript_1.default.SyntaxKind.TrueKeyword ||
545
+ argument.kind === typescript_1.default.SyntaxKind.FalseKeyword) {
546
+ return argument;
547
+ }
548
+ var id = factory_1.f.identifier(hint, true);
549
+ statements.push(factory_1.f.variableStatement(id, argument, annotation));
550
+ return id;
551
+ }
552
+ /**
553
+ * `const target = []` is an implicit `any[]`, which a project compiled with `noImplicitAny` rejects: an
554
+ * empty list (`fire([], value)`) is bound with the type its context gave it.
555
+ */
556
+ function emptyListAnnotation(state, original) {
557
+ if (!original || !typescript_1.default.isArrayLiteralExpression(original) || original.elements.length > 0)
558
+ return;
559
+ var type = state.typeChecker.getContextualType(original);
560
+ if (!type)
561
+ return;
562
+ return state.typeChecker.typeToTypeNode(type, original, typescript_1.default.NodeBuilderFlags.IgnoreErrors | typescript_1.default.NodeBuilderFlags.NoTruncation);
563
+ }
564
+ function arrayType() {
565
+ return factory_1.f.referenceType("Array", [factory_1.f.keywordType(typescript_1.default.SyntaxKind.UnknownKeyword)]);
566
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.transformNode = transformNode;
7
+ var typescript_1 = __importDefault(require("typescript"));
8
+ var diagnostics_1 = require("../classes/diagnostics");
9
+ var transformExpression_1 = require("./transformExpression");
10
+ var transformStatement_1 = require("./transformStatement");
11
+ function transformNode(state, node) {
12
+ try {
13
+ if (typescript_1.default.isExpression(node)) {
14
+ return (0, transformExpression_1.transformExpression)(state, node);
15
+ }
16
+ else if (typescript_1.default.isStatement(node)) {
17
+ return (0, transformStatement_1.transformStatement)(state, node);
18
+ }
19
+ }
20
+ catch (e) {
21
+ if (e instanceof Error && !("diagnostic" in e)) {
22
+ diagnostics_1.Diagnostics.error(node, "Flamework failure occurred here\n".concat(e.stack));
23
+ }
24
+ throw e;
25
+ }
26
+ return typescript_1.default.visitEachChild(node, function (newNode) { return transformNode(state, newNode); }, state.context);
27
+ }
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ var __read = (this && this.__read) || function (o, n) {
3
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
4
+ if (!m) return o;
5
+ var i = m.call(o), r, ar = [], e;
6
+ try {
7
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
8
+ }
9
+ catch (error) { e = { error: error }; }
10
+ finally {
11
+ try {
12
+ if (r && !r.done && (m = i["return"])) m.call(i);
13
+ }
14
+ finally { if (e) throw e.error; }
15
+ }
16
+ return ar;
17
+ };
18
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
19
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
20
+ if (ar || !(i in from)) {
21
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
22
+ ar[i] = from[i];
23
+ }
24
+ }
25
+ return to.concat(ar || Array.prototype.slice.call(from));
26
+ };
27
+ var __importDefault = (this && this.__importDefault) || function (mod) {
28
+ return (mod && mod.__esModule) ? mod : { "default": mod };
29
+ };
30
+ Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.transformStatement = transformStatement;
32
+ var typescript_1 = __importDefault(require("typescript"));
33
+ var diagnosticsUtils_1 = require("../util/diagnosticsUtils");
34
+ var getNodeList_1 = require("../util/functions/getNodeList");
35
+ var transformClassDeclaration_1 = require("./statements/transformClassDeclaration");
36
+ var transformNode_1 = require("./transformNode");
37
+ var factory_1 = require("../util/factory");
38
+ var TRANSFORMERS = new Map([
39
+ [typescript_1.default.SyntaxKind.ClassDeclaration, transformClassDeclaration_1.transformClassDeclaration],
40
+ ]);
41
+ function transformStatement(state, statement) {
42
+ return (0, diagnosticsUtils_1.catchDiagnostic)(statement, function () {
43
+ var _a = __read(state.capture(function () {
44
+ var transformer = TRANSFORMERS.get(statement.kind);
45
+ if (transformer) {
46
+ return transformer(state, statement);
47
+ }
48
+ return typescript_1.default.visitEachChild(statement, function (newNode) { return (0, transformNode_1.transformNode)(state, newNode); }, state.context);
49
+ }), 2), node = _a[0], prereqs = _a[1];
50
+ if (factory_1.f.is.file(statement.parent)) {
51
+ var nextRootStatements = state.nextRootStatements;
52
+ state.nextRootStatements = [];
53
+ return __spreadArray(__spreadArray(__spreadArray([], __read(nextRootStatements), false), __read(prereqs), false), __read((0, getNodeList_1.getNodeList)(node)), false);
54
+ }
55
+ return __spreadArray(__spreadArray([], __read(prereqs), false), __read((0, getNodeList_1.getNodeList)(node)), false);
56
+ });
57
+ }