@gwigz/slua-tstl-plugin 1.3.1 → 1.4.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.
@@ -0,0 +1,31 @@
1
+ import * as ts from "typescript";
2
+ import * as tstl from "typescript-to-lua";
3
+ import type { BuilderRootDef, BuilderSetDef } from "./generated/builder-data.js";
4
+ interface ChainEntry {
5
+ methodName: string;
6
+ args: ts.Expression[];
7
+ /** For .link() callbacks */
8
+ callback?: ts.ArrowFunction | ts.FunctionExpression;
9
+ }
10
+ interface BuilderChain {
11
+ /** The root call expression (e.g. setPrimParams(LINK_THIS)) */
12
+ rootCall: ts.CallExpression;
13
+ /** Name of the root function */
14
+ rootName: string;
15
+ /** Config for this root function */
16
+ rootDef: BuilderRootDef;
17
+ /** Config for the param set */
18
+ setDef: BuilderSetDef;
19
+ /** Chained method calls in order */
20
+ entries: ChainEntry[];
21
+ }
22
+ /**
23
+ * Attempt to match an expression as a builder chain.
24
+ * Walks from the outermost call inward to find the root.
25
+ */
26
+ export declare function matchBuilderChain(node: ts.CallExpression): BuilderChain | null;
27
+ /**
28
+ * Emit a builder chain as a flat Lua call to the corresponding ll.* function.
29
+ */
30
+ export declare function emitBuilderChain(chain: BuilderChain, context: tstl.TransformationContext, node: ts.Node): tstl.Statement;
31
+ export {};
@@ -0,0 +1,138 @@
1
+ import * as ts from "typescript";
2
+ import * as tstl from "typescript-to-lua";
3
+ import { BUILDER_ROOTS, BUILDER_SETS } from "./generated/builder-data.js";
4
+ /**
5
+ * Attempt to match an expression as a builder chain.
6
+ * Walks from the outermost call inward to find the root.
7
+ */
8
+ export function matchBuilderChain(node) {
9
+ const entries = [];
10
+ let current = node;
11
+ // Walk inside-out: outermost call first, peel layers
12
+ while (ts.isCallExpression(current) && ts.isPropertyAccessExpression(current.expression)) {
13
+ const methodName = current.expression.name.text;
14
+ const args = [...current.arguments];
15
+ // Check for callback arg (last arg being arrow/function)
16
+ const lastArg = args[args.length - 1];
17
+ let callback;
18
+ if (lastArg && (ts.isArrowFunction(lastArg) || ts.isFunctionExpression(lastArg))) {
19
+ callback = lastArg;
20
+ args.pop();
21
+ }
22
+ entries.unshift({ methodName, args, callback });
23
+ current = current.expression.expression;
24
+ }
25
+ // `current` should now be the root call: setPrimParams(LINK_THIS)
26
+ if (!ts.isCallExpression(current) || !ts.isIdentifier(current.expression)) {
27
+ return null;
28
+ }
29
+ const rootName = current.expression.text;
30
+ const rootDef = BUILDER_ROOTS[rootName];
31
+ if (!rootDef)
32
+ return null;
33
+ const setDef = BUILDER_SETS[rootDef.paramSet];
34
+ if (!setDef)
35
+ return null;
36
+ return { rootCall: current, rootName, rootDef, setDef, entries };
37
+ }
38
+ /**
39
+ * Emit a builder chain as a flat Lua call to the corresponding ll.* function.
40
+ */
41
+ export function emitBuilderChain(chain, context, node) {
42
+ const { rootCall, rootDef, setDef, entries } = chain;
43
+ // Transform root call args
44
+ const rootArgs = rootCall.arguments.map((a) => context.transformExpression(a));
45
+ // Build the flat list elements
46
+ const listElements = flattenEntries(entries, setDef, context);
47
+ // Build the ll.FunctionName call
48
+ const llCall = tstl.createCallExpression(tstl.createTableIndexExpression(tstl.createIdentifier("ll"), tstl.createStringLiteral(rootDef.llFunction)), [
49
+ ...rootArgs.slice(0, rootDef.preListArgs),
50
+ tstl.createTableExpression(listElements.map((e) => tstl.createTableFieldExpression(e)), node),
51
+ ...rootArgs.slice(rootDef.preListArgs, rootDef.preListArgs + rootDef.postListArgs),
52
+ ], node);
53
+ return tstl.createExpressionStatement(llCall, node);
54
+ }
55
+ /**
56
+ * Flatten chain entries into a list of Lua expressions (constant, args, constant, args, ...).
57
+ */
58
+ function flattenEntries(entries, setDef, context) {
59
+ const elements = [];
60
+ for (const entry of entries) {
61
+ // Check for link callback
62
+ if (setDef.linkMethod && entry.methodName === setDef.linkMethod) {
63
+ elements.push(tstl.createIdentifier(setDef.linkConstant));
64
+ for (const arg of entry.args) {
65
+ elements.push(context.transformExpression(arg));
66
+ }
67
+ // Flatten the callback's chain
68
+ if (entry.callback) {
69
+ const innerEntries = extractCallbackChain(entry.callback);
70
+ if (innerEntries) {
71
+ elements.push(...flattenEntries(innerEntries, setDef, context));
72
+ }
73
+ }
74
+ continue;
75
+ }
76
+ // Check for sub-dispatch (e.g. .typeBox())
77
+ const subMatch = setDef.subDispatch?.find((s) => s.methodName === entry.methodName);
78
+ if (subMatch) {
79
+ elements.push(tstl.createIdentifier(subMatch.dispatchConstant));
80
+ elements.push(tstl.createIdentifier(subMatch.shapeConstant));
81
+ for (const arg of entry.args) {
82
+ elements.push(context.transformExpression(arg));
83
+ }
84
+ continue;
85
+ }
86
+ // Regular method
87
+ const methodDef = setDef.methods[entry.methodName];
88
+ if (methodDef) {
89
+ elements.push(tstl.createIdentifier(methodDef.constant));
90
+ for (const arg of entry.args) {
91
+ elements.push(context.transformExpression(arg));
92
+ }
93
+ }
94
+ }
95
+ return elements;
96
+ }
97
+ /**
98
+ * Extract chain entries from a callback body.
99
+ * Handles: `link => link.color(...)` (expression body)
100
+ * and: `link => { return link.color(...) }` (block body with return)
101
+ */
102
+ function extractCallbackChain(cb) {
103
+ let expr;
104
+ if (ts.isBlock(cb.body)) {
105
+ // Block body, look for a single return statement
106
+ const returnStmt = cb.body.statements.find(ts.isReturnStatement);
107
+ if (!returnStmt?.expression)
108
+ return null;
109
+ expr = returnStmt.expression;
110
+ }
111
+ else {
112
+ // Expression body
113
+ expr = cb.body;
114
+ }
115
+ // The parameter name (e.g. "link"), we walk until we hit an identifier matching it
116
+ const paramName = cb.parameters[0]?.name;
117
+ if (!paramName || !ts.isIdentifier(paramName))
118
+ return null;
119
+ const paramText = paramName.text;
120
+ const entries = [];
121
+ let current = expr;
122
+ while (ts.isCallExpression(current) && ts.isPropertyAccessExpression(current.expression)) {
123
+ const methodName = current.expression.name.text;
124
+ const args = [...current.arguments];
125
+ let callback;
126
+ const lastArg = args[args.length - 1];
127
+ if (lastArg && (ts.isArrowFunction(lastArg) || ts.isFunctionExpression(lastArg))) {
128
+ callback = lastArg;
129
+ args.pop();
130
+ }
131
+ entries.unshift({ methodName, args, callback });
132
+ current = current.expression.expression;
133
+ }
134
+ // current should be the parameter identifier
135
+ if (!ts.isIdentifier(current) || current.text !== paramText)
136
+ return null;
137
+ return entries;
138
+ }
@@ -0,0 +1,24 @@
1
+ export interface BuilderRootDef {
2
+ llFunction: string;
3
+ paramSet: string;
4
+ preListArgs: number;
5
+ postListArgs: number;
6
+ }
7
+ export interface BuilderMethodDef {
8
+ constant: string;
9
+ argCount: number;
10
+ }
11
+ export interface BuilderSubDispatchDef {
12
+ dispatchConstant: string;
13
+ shapeConstant: string;
14
+ argCount: number;
15
+ methodName: string;
16
+ }
17
+ export interface BuilderSetDef {
18
+ methods: Record<string, BuilderMethodDef>;
19
+ subDispatch?: BuilderSubDispatchDef[];
20
+ linkConstant?: string;
21
+ linkMethod?: string;
22
+ }
23
+ export declare const BUILDER_ROOTS: Record<string, BuilderRootDef>;
24
+ export declare const BUILDER_SETS: Record<string, BuilderSetDef>;
@@ -0,0 +1,256 @@
1
+ // Auto-generated by gen-types, do not edit manually.
2
+ export const BUILDER_ROOTS = {
3
+ setPrimParams: {
4
+ llFunction: "SetLinkPrimitiveParamsFast",
5
+ paramSet: "PrimParam",
6
+ preListArgs: 1,
7
+ postListArgs: 0,
8
+ },
9
+ particleSystem: {
10
+ llFunction: "ParticleSystem",
11
+ paramSet: "ParticleSystemParam",
12
+ preListArgs: 0,
13
+ postListArgs: 0,
14
+ },
15
+ linkParticleSystem: {
16
+ llFunction: "LinkParticleSystem",
17
+ paramSet: "ParticleSystemParam",
18
+ preListArgs: 1,
19
+ postListArgs: 0,
20
+ },
21
+ setCameraParams: {
22
+ llFunction: "SetCameraParams",
23
+ paramSet: "CameraParam",
24
+ preListArgs: 0,
25
+ postListArgs: 0,
26
+ },
27
+ httpRequest: {
28
+ llFunction: "HTTPRequest",
29
+ paramSet: "HttpParam",
30
+ preListArgs: 1,
31
+ postListArgs: 1,
32
+ },
33
+ castRay: { llFunction: "CastRay", paramSet: "CastRayParam", preListArgs: 2, postListArgs: 0 },
34
+ createCharacter: {
35
+ llFunction: "CreateCharacter",
36
+ paramSet: "CharacterParam",
37
+ preListArgs: 0,
38
+ postListArgs: 0,
39
+ },
40
+ updateCharacter: {
41
+ llFunction: "UpdateCharacter",
42
+ paramSet: "CharacterParam",
43
+ preListArgs: 0,
44
+ postListArgs: 0,
45
+ },
46
+ rezObjectWithParams: {
47
+ llFunction: "RezObjectWithParams",
48
+ paramSet: "RezParam",
49
+ preListArgs: 1,
50
+ postListArgs: 0,
51
+ },
52
+ };
53
+ export const BUILDER_SETS = {
54
+ PrimParam: {
55
+ methods: {
56
+ name: { constant: "PRIM_NAME", argCount: 1 },
57
+ desc: { constant: "PRIM_DESC", argCount: 1 },
58
+ slice: { constant: "PRIM_SLICE", argCount: 1 },
59
+ physicsShapeType: { constant: "PRIM_PHYSICS_SHAPE_TYPE", argCount: 1 },
60
+ material: { constant: "PRIM_MATERIAL", argCount: 1 },
61
+ physics: { constant: "PRIM_PHYSICS", argCount: 1 },
62
+ tempOnRez: { constant: "PRIM_TEMP_ON_REZ", argCount: 1 },
63
+ phantom: { constant: "PRIM_PHANTOM", argCount: 1 },
64
+ position: { constant: "PRIM_POSITION", argCount: 1 },
65
+ posLocal: { constant: "PRIM_POS_LOCAL", argCount: 1 },
66
+ rotation: { constant: "PRIM_ROTATION", argCount: 1 },
67
+ rotLocal: { constant: "PRIM_ROT_LOCAL", argCount: 1 },
68
+ size: { constant: "PRIM_SIZE", argCount: 1 },
69
+ texture: { constant: "PRIM_TEXTURE", argCount: 5 },
70
+ renderMaterial: { constant: "PRIM_RENDER_MATERIAL", argCount: 2 },
71
+ text: { constant: "PRIM_TEXT", argCount: 3 },
72
+ color: { constant: "PRIM_COLOR", argCount: 3 },
73
+ bumpShiny: { constant: "PRIM_BUMP_SHINY", argCount: 3 },
74
+ pointLight: { constant: "PRIM_POINT_LIGHT", argCount: 5 },
75
+ reflectionProbe: { constant: "PRIM_REFLECTION_PROBE", argCount: 4 },
76
+ fullbright: { constant: "PRIM_FULLBRIGHT", argCount: 2 },
77
+ flexible: { constant: "PRIM_FLEXIBLE", argCount: 7 },
78
+ texgen: { constant: "PRIM_TEXGEN", argCount: 2 },
79
+ glow: { constant: "PRIM_GLOW", argCount: 2 },
80
+ omega: { constant: "PRIM_OMEGA", argCount: 3 },
81
+ normal: { constant: "PRIM_NORMAL", argCount: 5 },
82
+ specular: { constant: "PRIM_SPECULAR", argCount: 8 },
83
+ alphaMode: { constant: "PRIM_ALPHA_MODE", argCount: 3 },
84
+ castShadows: { constant: "PRIM_CAST_SHADOWS", argCount: 1 },
85
+ allowUnsit: { constant: "PRIM_ALLOW_UNSIT", argCount: 1 },
86
+ scriptedSitOnly: { constant: "PRIM_SCRIPTED_SIT_ONLY", argCount: 1 },
87
+ sitTarget: { constant: "PRIM_SIT_TARGET", argCount: 3 },
88
+ projector: { constant: "PRIM_PROJECTOR", argCount: 4 },
89
+ clickAction: { constant: "PRIM_CLICK_ACTION", argCount: 1 },
90
+ gltfBaseColor: { constant: "PRIM_GLTF_BASE_COLOR", argCount: 10 },
91
+ gltfNormal: { constant: "PRIM_GLTF_NORMAL", argCount: 5 },
92
+ gltfMetallicRoughness: { constant: "PRIM_GLTF_METALLIC_ROUGHNESS", argCount: 7 },
93
+ gltfEmissive: { constant: "PRIM_GLTF_EMISSIVE", argCount: 6 },
94
+ sitFlags: { constant: "PRIM_SIT_FLAGS", argCount: 1 },
95
+ damage: { constant: "PRIM_DAMAGE", argCount: 2 },
96
+ health: { constant: "PRIM_HEALTH", argCount: 1 },
97
+ },
98
+ subDispatch: [
99
+ {
100
+ dispatchConstant: "PRIM_TYPE",
101
+ shapeConstant: "PRIM_TYPE_BOX",
102
+ argCount: 6,
103
+ methodName: "typeBox",
104
+ },
105
+ {
106
+ dispatchConstant: "PRIM_TYPE",
107
+ shapeConstant: "PRIM_TYPE_CYLINDER",
108
+ argCount: 6,
109
+ methodName: "typeCylinder",
110
+ },
111
+ {
112
+ dispatchConstant: "PRIM_TYPE",
113
+ shapeConstant: "PRIM_TYPE_PRISM",
114
+ argCount: 6,
115
+ methodName: "typePrism",
116
+ },
117
+ {
118
+ dispatchConstant: "PRIM_TYPE",
119
+ shapeConstant: "PRIM_TYPE_SPHERE",
120
+ argCount: 5,
121
+ methodName: "typeSphere",
122
+ },
123
+ {
124
+ dispatchConstant: "PRIM_TYPE",
125
+ shapeConstant: "PRIM_TYPE_TORUS",
126
+ argCount: 11,
127
+ methodName: "typeTorus",
128
+ },
129
+ {
130
+ dispatchConstant: "PRIM_TYPE",
131
+ shapeConstant: "PRIM_TYPE_TUBE",
132
+ argCount: 11,
133
+ methodName: "typeTube",
134
+ },
135
+ {
136
+ dispatchConstant: "PRIM_TYPE",
137
+ shapeConstant: "PRIM_TYPE_RING",
138
+ argCount: 11,
139
+ methodName: "typeRing",
140
+ },
141
+ {
142
+ dispatchConstant: "PRIM_TYPE",
143
+ shapeConstant: "PRIM_TYPE_SCULPT",
144
+ argCount: 2,
145
+ methodName: "typeSculpt",
146
+ },
147
+ ],
148
+ linkConstant: "PRIM_LINK_TARGET",
149
+ linkMethod: "link",
150
+ },
151
+ ParticleSystemParam: {
152
+ methods: {
153
+ partFlags: { constant: "PSYS_PART_FLAGS", argCount: 1 },
154
+ srcPattern: { constant: "PSYS_SRC_PATTERN", argCount: 1 },
155
+ srcBurstRadius: { constant: "PSYS_SRC_BURST_RADIUS", argCount: 1 },
156
+ srcAngleBegin: { constant: "PSYS_SRC_ANGLE_BEGIN", argCount: 1 },
157
+ srcAngleEnd: { constant: "PSYS_SRC_ANGLE_END", argCount: 1 },
158
+ srcInnerangle: { constant: "PSYS_SRC_INNERANGLE", argCount: 1 },
159
+ srcOuterangle: { constant: "PSYS_SRC_OUTERANGLE", argCount: 1 },
160
+ srcTargetKey: { constant: "PSYS_SRC_TARGET_KEY", argCount: 1 },
161
+ partStartColor: { constant: "PSYS_PART_START_COLOR", argCount: 1 },
162
+ partEndColor: { constant: "PSYS_PART_END_COLOR", argCount: 1 },
163
+ partStartAlpha: { constant: "PSYS_PART_START_ALPHA", argCount: 1 },
164
+ partEndAlpha: { constant: "PSYS_PART_END_ALPHA", argCount: 1 },
165
+ partStartScale: { constant: "PSYS_PART_START_SCALE", argCount: 1 },
166
+ partEndScale: { constant: "PSYS_PART_END_SCALE", argCount: 1 },
167
+ srcTexture: { constant: "PSYS_SRC_TEXTURE", argCount: 1 },
168
+ partStartGlow: { constant: "PSYS_PART_START_GLOW", argCount: 1 },
169
+ partEndGlow: { constant: "PSYS_PART_END_GLOW", argCount: 1 },
170
+ partBlendFuncSource: { constant: "PSYS_PART_BLEND_FUNC_SOURCE", argCount: 1 },
171
+ partBlendFuncDest: { constant: "PSYS_PART_BLEND_FUNC_DEST", argCount: 1 },
172
+ srcMaxAge: { constant: "PSYS_SRC_MAX_AGE", argCount: 1 },
173
+ partMaxAge: { constant: "PSYS_PART_MAX_AGE", argCount: 1 },
174
+ srcBurstRate: { constant: "PSYS_SRC_BURST_RATE", argCount: 1 },
175
+ srcBurstPartCount: { constant: "PSYS_SRC_BURST_PART_COUNT", argCount: 1 },
176
+ srcAccel: { constant: "PSYS_SRC_ACCEL", argCount: 1 },
177
+ srcOmega: { constant: "PSYS_SRC_OMEGA", argCount: 1 },
178
+ srcBurstSpeedMin: { constant: "PSYS_SRC_BURST_SPEED_MIN", argCount: 1 },
179
+ srcBurstSpeedMax: { constant: "PSYS_SRC_BURST_SPEED_MAX", argCount: 1 },
180
+ },
181
+ },
182
+ CameraParam: {
183
+ methods: {
184
+ active: { constant: "CAMERA_ACTIVE", argCount: 1 },
185
+ behindnessAngle: { constant: "CAMERA_BEHINDNESS_ANGLE", argCount: 1 },
186
+ behindnessLag: { constant: "CAMERA_BEHINDNESS_LAG", argCount: 1 },
187
+ distance: { constant: "CAMERA_DISTANCE", argCount: 1 },
188
+ focus: { constant: "CAMERA_FOCUS", argCount: 1 },
189
+ focusLag: { constant: "CAMERA_FOCUS_LAG", argCount: 1 },
190
+ focusLocked: { constant: "CAMERA_FOCUS_LOCKED", argCount: 1 },
191
+ focusOffset: { constant: "CAMERA_FOCUS_OFFSET", argCount: 1 },
192
+ focusThreshold: { constant: "CAMERA_FOCUS_THRESHOLD", argCount: 1 },
193
+ pitch: { constant: "CAMERA_PITCH", argCount: 1 },
194
+ position: { constant: "CAMERA_POSITION", argCount: 1 },
195
+ positionLag: { constant: "CAMERA_POSITION_LAG", argCount: 1 },
196
+ positionLocked: { constant: "CAMERA_POSITION_LOCKED", argCount: 1 },
197
+ positionThreshold: { constant: "CAMERA_POSITION_THRESHOLD", argCount: 1 },
198
+ },
199
+ },
200
+ HttpParam: {
201
+ methods: {
202
+ method: { constant: "HTTP_METHOD", argCount: 1 },
203
+ mimetype: { constant: "HTTP_MIMETYPE", argCount: 1 },
204
+ bodyMaxlength: { constant: "HTTP_BODY_MAXLENGTH", argCount: 1 },
205
+ verifyCert: { constant: "HTTP_VERIFY_CERT", argCount: 1 },
206
+ verboseThrottle: { constant: "HTTP_VERBOSE_THROTTLE", argCount: 1 },
207
+ customHeader: { constant: "HTTP_CUSTOM_HEADER", argCount: 2 },
208
+ pragmaNoCache: { constant: "HTTP_PRAGMA_NO_CACHE", argCount: 1 },
209
+ userAgent: { constant: "HTTP_USER_AGENT", argCount: 1 },
210
+ accept: { constant: "HTTP_ACCEPT", argCount: 1 },
211
+ extendedError: { constant: "HTTP_EXTENDED_ERROR", argCount: 1 },
212
+ },
213
+ },
214
+ CastRayParam: {
215
+ methods: {
216
+ rejectTypes: { constant: "RC_REJECT_TYPES", argCount: 1 },
217
+ dataFlags: { constant: "RC_DATA_FLAGS", argCount: 1 },
218
+ maxHits: { constant: "RC_MAX_HITS", argCount: 1 },
219
+ detectPhantom: { constant: "RC_DETECT_PHANTOM", argCount: 1 },
220
+ },
221
+ },
222
+ CharacterParam: {
223
+ methods: {
224
+ desiredSpeed: { constant: "CHARACTER_DESIRED_SPEED", argCount: 1 },
225
+ radius: { constant: "CHARACTER_RADIUS", argCount: 1 },
226
+ length: { constant: "CHARACTER_LENGTH", argCount: 1 },
227
+ orientation: { constant: "CHARACTER_ORIENTATION", argCount: 1 },
228
+ type: { constant: "CHARACTER_TYPE", argCount: 1 },
229
+ avoidanceMode: { constant: "CHARACTER_AVOIDANCE_MODE", argCount: 1 },
230
+ maxAccel: { constant: "CHARACTER_MAX_ACCEL", argCount: 1 },
231
+ maxDecel: { constant: "CHARACTER_MAX_DECEL", argCount: 1 },
232
+ desiredTurnSpeed: { constant: "CHARACTER_DESIRED_TURN_SPEED", argCount: 1 },
233
+ maxTurnRadius: { constant: "CHARACTER_MAX_TURN_RADIUS", argCount: 1 },
234
+ maxSpeed: { constant: "CHARACTER_MAX_SPEED", argCount: 1 },
235
+ accountForSkippedFrames: { constant: "CHARACTER_ACCOUNT_FOR_SKIPPED_FRAMES", argCount: 1 },
236
+ stayWithinParcel: { constant: "CHARACTER_STAY_WITHIN_PARCEL", argCount: 1 },
237
+ },
238
+ },
239
+ RezParam: {
240
+ methods: {
241
+ param: { constant: "REZ_PARAM", argCount: 1 },
242
+ flags: { constant: "REZ_FLAGS", argCount: 1 },
243
+ pos: { constant: "REZ_POS", argCount: 3 },
244
+ rot: { constant: "REZ_ROT", argCount: 2 },
245
+ vel: { constant: "REZ_VEL", argCount: 3 },
246
+ accel: { constant: "REZ_ACCEL", argCount: 2 },
247
+ omega: { constant: "REZ_OMEGA", argCount: 4 },
248
+ damage: { constant: "REZ_DAMAGE", argCount: 1 },
249
+ sound: { constant: "REZ_SOUND", argCount: 3 },
250
+ soundCollide: { constant: "REZ_SOUND_COLLIDE", argCount: 2 },
251
+ lockAxes: { constant: "REZ_LOCK_AXES", argCount: 1 },
252
+ damageType: { constant: "REZ_DAMAGE_TYPE", argCount: 1 },
253
+ paramString: { constant: "REZ_PARAM_STRING", argCount: 1 },
254
+ },
255
+ },
256
+ };
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import * as tstl from "typescript-to-lua";
3
3
  import { PASCAL_TO_LOWER, TSTL_KEYWORD_FIXUPS, BINARY_BITWISE_OPS, COMPOUND_BITWISE_OPS, } from "./constants.js";
4
4
  import { createBit32Call, isMathFloor, isStringOrNumberLike, extractBtestPattern, extractIndexOfPresence, extractConcatSelfAssignment, extractSpreadSelfAssignment, emitChainedExtend, getLLIndexSemantics, emitLLIndexCall, isDetectedEventIndex, createNamespacedCall, createStringFindCall, } from "./utils.js";
5
5
  import { CALL_TRANSFORMS } from "./transforms.js";
6
+ import { matchBuilderChain, emitBuilderChain } from "./builder-transform.js";
6
7
  import { createOptimizeTransforms, countFilterCalls, ALL_OPTIMIZE } from "./optimize.js";
7
8
  import { tryEvaluateCondition, shouldStripDefineGuard } from "./define.js";
8
9
  import { stripInternalJSDocTags, stripEmptyModuleBoilerplate, collapseDefaultParamNilChecks, shortenTempNames, collapseFieldAccesses, inlineForwardDeclarations, } from "./lua-transforms.js";
@@ -175,6 +176,13 @@ function createPlugin(options = {}) {
175
176
  return [tstl.createExpressionStatement(call, node)];
176
177
  }
177
178
  }
179
+ // Builder chain detection (e.g. setPrimParams(LINK_THIS).color(0, v, 1))
180
+ if (ts.isCallExpression(node.expression)) {
181
+ const chain = matchBuilderChain(node.expression);
182
+ if (chain) {
183
+ return [emitBuilderChain(chain, context, node)];
184
+ }
185
+ }
178
186
  return context.superTransformStatements(node);
179
187
  },
180
188
  [ts.SyntaxKind.CallExpression]: (node, context) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gwigz/slua-tstl-plugin",
3
- "version": "1.3.1",
3
+ "version": "1.4.0",
4
4
  "description": "TypeScriptToLua plugin for targeting Second Life's SLua runtime",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -32,7 +32,7 @@
32
32
  "test": "bun test"
33
33
  },
34
34
  "dependencies": {
35
- "@gwigz/slua-types": "^1.2.0",
35
+ "@gwigz/slua-types": "^1.3.0",
36
36
  "typescript-to-lua": "^1.33.0"
37
37
  },
38
38
  "peerDependencies": {