Skip to content

Commit 0a5b4cb

Browse files
author
Robert Jackson
committed
Process this.on statements.
1 parent c43f7fb commit 0a5b4cb

File tree

3 files changed

+154
-33
lines changed

3 files changed

+154
-33
lines changed

__testfixtures__/ember-qunit-codemod/on.input.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,22 @@ test('it happens', function(assert) {
1212
this.render(hbs`{{test-component test="test"}}`);
1313
});
1414

15+
test('it happens non-dotable identifier e.g. [test-foo]', function(assert) {
16+
assert.expect(1);
17+
18+
this.on('test-foo', () => assert.ok(true));
19+
this.render(hbs`{{test-component test="test"}}`);
20+
});
21+
22+
moduleForComponent('foo-bar', 'Integration | Component | FooBar', {
23+
integration: true,
24+
beforeEach(assert) {
25+
this.on('test', () => assert.ok(true));
26+
}
27+
});
28+
29+
test('it happens', function(assert) {
30+
assert.expect(1);
31+
32+
this.render(hbs`{{test-component test="test"}}`);
33+
});

__testfixtures__/ember-qunit-codemod/on.output.js

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,36 @@ module('Integration | Component | FooBar', function(hooks) {
1111
this.send = (actionName, ...args) => this.actions[actionName].apply(this, args);
1212
});
1313

14-
test('it invokes a sendAction action', function(assert) {
14+
test('it happens', async function(assert) {
1515
assert.expect(1);
1616

1717
this.actions.test = () => assert.ok(true);
18-
this.render(hbs`{{test-component test="test"}}`);
18+
await render(hbs`{{test-component test="test"}}`);
19+
});
20+
21+
test('it happens non-dotable identifier e.g. [test-foo]', async function(assert) {
22+
assert.expect(1);
23+
24+
this.actions['test-foo'] = () => assert.ok(true);
25+
await render(hbs`{{test-component test="test"}}`);
1926
});
2027
});
2128

29+
module('Integration | Component | FooBar', function(hooks) {
30+
setupRenderingTest(hooks);
31+
32+
hooks.beforeEach(function() {
33+
this.actions = {};
34+
this.send = (actionName, ...args) => this.actions[actionName].apply(this, args);
35+
});
36+
37+
hooks.beforeEach(function(assert) {
38+
this.actions.test = () => assert.ok(true);
39+
});
40+
41+
test('it happens', async function(assert) {
42+
assert.expect(1);
43+
44+
await render(hbs`{{test-component test="test"}}`);
45+
});
46+
});

ember-qunit-codemod.js

Lines changed: 108 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,38 @@ module.exports = function(file, api) {
200200
});
201201
}
202202

203+
function addHooksParam(moduleInfo) {
204+
moduleInfo.moduleCallback.params = [j.identifier('hooks')];
205+
}
206+
207+
function addToBeforeEach(moduleInfo, expression) {
208+
let beforeEachBody = moduleInfo.moduleBeforeEachBody;
209+
if (!beforeEachBody) {
210+
if (moduleInfo.moduleCallback) {
211+
addHooksParam(moduleInfo);
212+
}
213+
214+
let beforeEachBlockStatement = j.blockStatement([]);
215+
let beforeEachExpression = j.expressionStatement(
216+
j.callExpression(j.memberExpression(j.identifier('hooks'), j.identifier('beforeEach')), [
217+
j.functionExpression(
218+
null,
219+
[
220+
/* no arguments */
221+
],
222+
beforeEachBlockStatement
223+
),
224+
])
225+
);
226+
227+
beforeEachBody = moduleInfo.moduleBeforeEachBody = beforeEachBlockStatement.body;
228+
let insertAt = moduleInfo.setupType ? 1 : 0;
229+
moduleInfo.moduleCallbackBody.splice(insertAt, 0, beforeEachExpression);
230+
}
231+
232+
beforeEachBody.push(expression);
233+
}
234+
203235
function updateModuleForToNestedModule() {
204236
const LIFE_CYCLE_METHODS = [
205237
{ key: { name: 'before' }, value: { type: 'FunctionExpression' } },
@@ -212,37 +244,6 @@ module.exports = function(file, api) {
212244
return LIFE_CYCLE_METHODS.some(matcher => j.match(nodePath, matcher));
213245
}
214246

215-
function addHooksParam(moduleInfo) {
216-
moduleInfo.moduleCallback.params = [j.identifier('hooks')];
217-
}
218-
219-
function addToBeforeEach(moduleInfo, expression) {
220-
let beforeEachBody = moduleInfo.moduleBeforeEachBody;
221-
if (!beforeEachBody) {
222-
if (moduleInfo.moduleCallback) {
223-
addHooksParam(moduleInfo);
224-
}
225-
226-
let beforeEachBlockStatement = j.blockStatement([]);
227-
let beforeEachExpression = j.expressionStatement(
228-
j.callExpression(j.memberExpression(j.identifier('hooks'), j.identifier('beforeEach')), [
229-
j.functionExpression(
230-
null,
231-
[
232-
/* no arguments */
233-
],
234-
beforeEachBlockStatement
235-
),
236-
])
237-
);
238-
239-
beforeEachBody = moduleInfo.moduleBeforeEachBody = beforeEachBlockStatement.body;
240-
moduleInfo.moduleCallbackBody.push(beforeEachExpression);
241-
}
242-
243-
beforeEachBody.push(expression);
244-
}
245-
246247
function createModule(p) {
247248
let moduleInfo = new ModuleInfo(p);
248249

@@ -257,6 +258,7 @@ module.exports = function(file, api) {
257258
moduleSetupExpression = j.expressionStatement(
258259
j.callExpression(j.identifier(moduleInfo.setupType), [j.identifier('hooks')])
259260
);
261+
moduleInfo.moduleSetupExpression = moduleSetupExpression;
260262
}
261263

262264
// Create the new `module(moduleName, function(hooks) {});` invocation
@@ -308,6 +310,7 @@ module.exports = function(file, api) {
308310
updateLookupCalls(expressionCollection);
309311
updateRegisterCalls(expressionCollection);
310312
updateInjectCalls(expressionCollection);
313+
updateOnCalls(expressionCollection, moduleInfo);
311314
}
312315

313316
if (isLifecycleHook(property)) {
@@ -506,6 +509,7 @@ module.exports = function(file, api) {
506509
updateLookupCalls(expressionCollection);
507510
updateRegisterCalls(expressionCollection);
508511
updateInjectCalls(expressionCollection);
512+
updateOnCalls(expressionCollection, currentModuleInfo);
509513
// passing the specific function callback here, because `getOwner` is only
510514
// transformed if the call site's scope is the same as the expression passed
511515
updateGetOwnerThisUsage(j(expression.expression.arguments[1]));
@@ -563,6 +567,79 @@ module.exports = function(file, api) {
563567
});
564568
}
565569

570+
function updateOnCalls(ctx, moduleInfo) {
571+
let usages = ctx.find(j.CallExpression, {
572+
callee: {
573+
type: 'MemberExpression',
574+
object: {
575+
type: 'ThisExpression',
576+
},
577+
property: {
578+
name: 'on',
579+
},
580+
},
581+
});
582+
583+
usages.forEach(p => {
584+
let actionName = p.node.arguments[0].value;
585+
let property = j.identifier(actionName);
586+
587+
if (!actionName.match(/^[a-zA-Z_][a-zA-Z0-9]+$/)) {
588+
// if not, use `this['property-name']`
589+
property = j.literal(actionName);
590+
}
591+
592+
let assignment = j.assignmentExpression(
593+
'=',
594+
j.memberExpression(
595+
j.memberExpression(j.thisExpression(), j.identifier('actions')),
596+
property
597+
),
598+
p.node.arguments[1]
599+
);
600+
p.replace(assignment);
601+
});
602+
603+
if (usages.size() > 0 && !moduleInfo.hasSendFunctionInBeforeEach) {
604+
moduleInfo.hasSendFunctionInBeforeEach = true;
605+
606+
addToBeforeEach(
607+
moduleInfo,
608+
j.expressionStatement(
609+
j.assignmentExpression(
610+
'=',
611+
j.memberExpression(j.thisExpression(), j.identifier('actions')),
612+
j.objectExpression([])
613+
)
614+
)
615+
);
616+
617+
addToBeforeEach(
618+
moduleInfo,
619+
j.expressionStatement(
620+
j.assignmentExpression(
621+
'=',
622+
j.memberExpression(j.thisExpression(), j.identifier('send')),
623+
j.arrowFunctionExpression(
624+
[j.identifier('actionName'), j.restElement(j.identifier('args'))],
625+
j.callExpression(
626+
j.memberExpression(
627+
j.memberExpression(
628+
j.memberExpression(j.thisExpression(), j.identifier('actions')),
629+
j.identifier('actionName'),
630+
true
631+
),
632+
j.identifier('apply')
633+
),
634+
[j.thisExpression(), j.identifier('args')]
635+
)
636+
)
637+
)
638+
)
639+
);
640+
}
641+
}
642+
566643
function updateInjectCalls(ctx) {
567644
ctx
568645
.find(j.CallExpression, {

0 commit comments

Comments
 (0)