Skip to content

Commit ea96d66

Browse files
author
Fernando Basello
committed
fix: the transpilation was not handling correctyle the string templates
1 parent a5d4989 commit ea96d66

2 files changed

Lines changed: 270 additions & 34 deletions

File tree

src/plugins/index.js

Lines changed: 167 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,171 @@ module.exports = function (babel) {
9292
(binding.path.parent &&
9393
t.isImportDeclaration(binding.path.parent))
9494
) {
95-
// Get the arguments as a string
96-
const argsString = arg.arguments
97-
.map((argNode) =>
98-
path.hub.file.code.slice(argNode.start, argNode.end)
99-
)
100-
.join(', ');
101-
102-
path.node.arguments[0] = t.stringLiteral(
103-
`${callee.name}(${argsString})`
104-
);
95+
// Check arguments for runtime values
96+
const args = arg.arguments.map((argNode) => {
97+
if (t.isIdentifier(argNode)) {
98+
const argBinding = path.scope.getBinding(argNode.name);
99+
if (argBinding) {
100+
return {
101+
value: argNode.name,
102+
isRuntime: true,
103+
};
104+
}
105+
} else if (t.isBinaryExpression(argNode)) {
106+
// For binary expressions, we need to handle the entire expression as one unit
107+
const hasRuntimeValue = (node) => {
108+
if (t.isIdentifier(node)) {
109+
return path.scope.getBinding(node.name) != null;
110+
}
111+
if (t.isBinaryExpression(node)) {
112+
return (
113+
hasRuntimeValue(node.left) ||
114+
hasRuntimeValue(node.right)
115+
);
116+
}
117+
return false;
118+
};
119+
120+
const isRuntime = hasRuntimeValue(argNode);
121+
return {
122+
value: path.hub.file.code.slice(
123+
argNode.start,
124+
argNode.end
125+
),
126+
isRuntime,
127+
isBinaryExpression: true,
128+
};
129+
} else if (t.isObjectExpression(argNode)) {
130+
const properties = argNode.properties
131+
.map((prop) => {
132+
if (t.isObjectProperty(prop)) {
133+
if (t.isIdentifier(prop.value)) {
134+
const objectBinding = path.scope.getBinding(
135+
prop.value.name
136+
);
137+
if (objectBinding) {
138+
return {
139+
key: prop.key.name,
140+
value: prop.value.name,
141+
isRuntime: true,
142+
};
143+
}
144+
}
145+
return {
146+
key: prop.key.name,
147+
value: path.hub.file.code.slice(
148+
prop.value.start,
149+
prop.value.end
150+
),
151+
isRuntime: false,
152+
};
153+
}
154+
return null;
155+
})
156+
.filter(Boolean);
157+
158+
const hasRuntimeProps = properties.some((p) => p.isRuntime);
159+
if (hasRuntimeProps) {
160+
return {
161+
properties,
162+
isObject: true,
163+
isRuntime: true,
164+
};
165+
}
166+
}
167+
return {
168+
value: path.hub.file.code.slice(argNode.start, argNode.end),
169+
isRuntime: false,
170+
};
171+
});
172+
173+
if (args.some((runtimeArg) => runtimeArg.isRuntime)) {
174+
// Create template elements for each argument
175+
const quasis = [];
176+
const expressions = [];
177+
178+
// Add the function name and opening parenthesis
179+
quasis.push(
180+
t.templateElement(
181+
{ raw: `${callee.name}(`, cooked: `${callee.name}(` },
182+
false
183+
)
184+
);
185+
186+
// Add each argument
187+
args.forEach((objectArg, index) => {
188+
if (objectArg.isObject) {
189+
const prev = quasis.pop();
190+
let objStr = prev.value.raw + '{ ';
191+
192+
arg.properties.forEach((prop, propIndex) => {
193+
if (prop.isRuntime) {
194+
objStr += `${prop.key}: `;
195+
quasis.push(
196+
t.templateElement(
197+
{ raw: objStr, cooked: objStr },
198+
false
199+
)
200+
);
201+
expressions.push(t.identifier(prop.value));
202+
objStr =
203+
propIndex < arg.properties.length - 1 ? ', ' : '';
204+
} else {
205+
objStr += `${prop.key}: ${prop.value}${propIndex < arg.properties.length - 1 ? ', ' : ''}`;
206+
}
207+
});
208+
209+
objStr += ' }' + (index === args.length - 1 ? ')' : ', ');
210+
quasis.push(
211+
t.templateElement(
212+
{ raw: objStr, cooked: objStr },
213+
index === args.length - 1
214+
)
215+
);
216+
} else if (arg.isRuntime) {
217+
if (arg.isBinaryExpression) {
218+
expressions.push(t.identifier(arg.value));
219+
} else {
220+
expressions.push(t.identifier(arg.value));
221+
}
222+
const separator = index === args.length - 1 ? ')' : ', ';
223+
quasis.push(
224+
t.templateElement(
225+
{
226+
raw: separator,
227+
cooked: separator,
228+
},
229+
index === args.length - 1
230+
)
231+
);
232+
} else {
233+
const prev = quasis.pop();
234+
const separator = index === args.length - 1 ? ')' : ', ';
235+
const newRaw = prev.value.raw + arg.value + separator;
236+
const newCooked =
237+
prev.value.cooked + arg.value + separator;
238+
quasis.push(
239+
t.templateElement(
240+
{ raw: newRaw, cooked: newCooked },
241+
index === args.length - 1
242+
)
243+
);
244+
}
245+
});
246+
247+
path.node.arguments[0] = t.templateLiteral(
248+
quasis,
249+
expressions
250+
);
251+
} else {
252+
// If no runtime values, use string literal
253+
const argsString = args
254+
.map((stringArg) => stringArg.value)
255+
.join(', ');
256+
path.node.arguments[0] = t.stringLiteral(
257+
`${callee.name}(${argsString})`
258+
);
259+
}
105260
return;
106261
}
107262

@@ -205,8 +360,8 @@ module.exports = function (babel) {
205360
);
206361

207362
// Add each argument
208-
args.forEach((arg, index) => {
209-
if (arg.isBinaryExpression) {
363+
args.forEach((expressionArg, index) => {
364+
if (expressionArg.isBinaryExpression) {
210365
const { left, operator, right } = arg.value;
211366
if (left.isRuntime) {
212367
expressions.push(t.identifier(left.value));

src/plugins/tests/plugin.test.js

Lines changed: 103 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ pluginTester({
411411
import { processData } from 'worker-functions';
412412
const count = 1000;
413413
const label = 'processing';
414-
enqueueItem('processData(count * 2, label + "_task")');
414+
enqueueItem(\`processData(\${count * 2}, \${label + '_task'})\`);
415415
`,
416416
},
417417
{
@@ -490,26 +490,107 @@ pluginTester({
490490
);
491491
`,
492492
},
493-
// {
494-
// title: 'Transforms async function with multiple runtime values',
495-
// code: `
496-
// const delay = 1000;
497-
// const message = "completed";
498-
// const asyncLoop = async (waitTime, result) => {
499-
// await new Promise(resolve => setTimeout(resolve, waitTime));
500-
// return result;
501-
// };
502-
// enqueueItem(asyncLoop(delay, message));
503-
// `,
504-
// output: `
505-
// const delay = 1000;
506-
// const message = "completed";
507-
// const asyncLoop = async (waitTime, result) => {
508-
// await new Promise(resolve => setTimeout(resolve, waitTime));
509-
// return result;
510-
// };
511-
// enqueueItem(\`async function asyncLoop(waitTime, result) { await new Promise(resolve => setTimeout(resolve, waitTime)); return result; } return asyncLoop(\${delay}, \${message});\`);
512-
// `,
513-
// },
493+
// New test cases for imported functions with runtime values
494+
{
495+
title: 'Handles imported function with runtime value argument',
496+
code: `
497+
import { processData } from 'worker-functions';
498+
const data = getData();
499+
enqueueItem(processData(data));
500+
`,
501+
output: `
502+
import { processData } from 'worker-functions';
503+
const data = getData();
504+
enqueueItem(\`processData(\${data})\`);
505+
`,
506+
},
507+
{
508+
title: 'Handles imported function with multiple runtime value arguments',
509+
code: `
510+
import { transform } from 'worker-functions';
511+
const code = getCode();
512+
const options = getOptions();
513+
enqueueItem(transform(code, options));
514+
`,
515+
output: `
516+
import { transform } from 'worker-functions';
517+
const code = getCode();
518+
const options = getOptions();
519+
enqueueItem(\`transform(\${code}, \${options})\`);
520+
`,
521+
},
522+
{
523+
title:
524+
'Handles imported function with mixed runtime and literal arguments',
525+
code: `
526+
import { process } from 'worker-functions';
527+
const data = getData();
528+
enqueueItem(process(data, "strict", true));
529+
`,
530+
output: `
531+
import { process } from 'worker-functions';
532+
const data = getData();
533+
enqueueItem(\`process(\${data}, "strict", true)\`);
534+
`,
535+
},
536+
{
537+
title:
538+
'Handles imported function with binary expression containing runtime value',
539+
code: `
540+
import { calculate } from 'worker-functions';
541+
const base = getValue();
542+
enqueueItem(calculate(base * 2 + 1));
543+
`,
544+
output: `
545+
import { calculate } from 'worker-functions';
546+
const base = getValue();
547+
enqueueItem(\`calculate(\${base * 2 + 1})\`);
548+
`,
549+
},
550+
{
551+
title:
552+
'Handles imported function with complex binary expressions and multiple runtime values',
553+
code: `
554+
import { compute } from 'worker-functions';
555+
const x = getX();
556+
const y = getY();
557+
enqueueItem(compute(x * 2, y + 1));
558+
`,
559+
output: `
560+
import { compute } from 'worker-functions';
561+
const x = getX();
562+
const y = getY();
563+
enqueueItem(\`compute(\${x * 2}, \${y + 1})\`);
564+
`,
565+
},
566+
{
567+
title: 'Handles imported function with string template literal argument',
568+
code: `
569+
import { format } from 'worker-functions';
570+
const name = getName();
571+
enqueueItem(format(\`Hello \${name}!\`));
572+
`,
573+
output: `
574+
import { format } from 'worker-functions';
575+
const name = getName();
576+
enqueueItem('format(\`Hello \${name}!\`)');
577+
`,
578+
},
579+
{
580+
title:
581+
'Handles imported function with object expression containing runtime values',
582+
code: `
583+
import { configure } from 'worker-functions';
584+
const mode = getMode();
585+
const level = getLevel();
586+
enqueueItem(configure({ mode, level, debug: true }));
587+
`,
588+
output: `
589+
import { configure } from 'worker-functions';
590+
const mode = getMode();
591+
const level = getLevel();
592+
enqueueItem(\`configure({ mode: \${mode}, level: \${level}, debug: true })\`);
593+
`,
594+
},
514595
],
515596
});

0 commit comments

Comments
 (0)