 So, my name is Adolfo Willis. I come from Medellin, Colombia. So it looks like some people actually has problem trying to say my last name. So if you are running on a Mac, you can say something like Willis using the Thomas voice and that will fix your problem. So some of you might recognize me from my profile picture on Twitter. And to this appointment of many, I am not really a talking cat. So there was Jeffrey Bytes during the Ember Conf. I've self-published the Ember GS book called Ember CLI 101. And I'm super excited to announce that yesterday we released the Chinese Mandarin version. I work for a company called Emboy, where we love Ember. And I also like to go on motorcycles, do open source and a bunch of other stuff. But lately it's mostly about motorcycles. But what am I here anyways, right? Let's start with a story. Before joining Emboy, I used to do like Ember consulting. And I was working with a bunch of different companies to help them adopt Ember, train their teams and just like be there as an Ember facilitator. So if they were having issues with Ember or something like that, I would just jump in. And one of my tasks was to help them leap on the edge. So if a new Ember was out, I would help them to upgrade and use new features into their applications. Or if there was a new Ember CLI, then I would just do the upgrade for them since I'm familiar with that. So one day, if you remember, Ember CLI 0.1.13 came out. Probably because of the version you don't remember. But that version caused a bunch of people to feel like this. Like, what is this? I wanna kill the old Jackson. He just break my test. So what happened was that key units syntax change, right? If you recall, we used to call equal and okay, just as a globals, and used to work fine. But on this particular version, we adopted the 2.0 syntax. So that was the default, which was being shipped with the blueprints. And we removed all those globals from the gshin.gshin.rs. So of course, all your tests were failing with gshin issues. So the way to fix this code was to go through your test and add an assert argument over there and then say assert.equal or assert.ok. This is a really boring task for someone, right? So I was like, okay, how can I fix this without wasting too much time? And the first solution I was was to use spare, right? So I used one line that I learned a while ago, which I called a pairpy, and actually people on the internet call it like that. So I was just doing fine, getting all my files, and calling pair, doing regular expressions, replacements on that. It was great, the first time. And the reason why it worked great was because it run it on my personal project. So I knew my code in this style. I knew that I was using single code instead of double codes. I knew which spacing I was using and all that kind of stuff. But then I started to share these scripts with other people and even to run it on a couple of my clients and it just didn't work. Like, people were using double codes, so I wasn't handling that scenario or people have different spacing ways to do things. So anyways, it wasn't working that well. So I thought, how can I get this to work on any project without exposing people to the way in how I am doing it? And also without caring about their styling, the way they are styling their code if there is single code, double code, or anything like that. And to answer this question, let's go back a little back in time. Is there here like any early embassy like I adopted? Like from one year ago, cool, yeah. Yeah, there are a bunch of them. So if you remember, like back in the days, if we have a router like this, after running the route generator, we'll end up with something like this, right? That's not what we were expecting. It should have been like inside the route friends. It shouldn't have had like another route over there. So the reason why this didn't work properly was that we were doing regular expressions replacements. So you can see it in there, but basically we're going through the router and then changing the code using regular expressions. So it's very hard. I think it can be done, but it is hard on error prone to do it with regular expressions to do like the proper replacement where it should do or to remove a code. So to fix this issue, we wrote a micro library called the Ember Router Generator which encapsulates all the logic behind. So if we want to add a new route, we just call this micro library and then if we want to remove or whatever, we just call it and it's everything encapsulated in there. And the way we solved the issue was using a concept called abstract syntax trace or ESTs. There are only three representation of our code. I don't really go to explain like all the concepts behind abstract syntax trace, but how can we use it to fix these kind of issues? So if we look at this code, which says these are route friends. According to the Emacs-Trips language specification, the three for this will look like something like this. Like we have a program body which has like many kind of nodes. This particular node is an expression statement. And then over there, we can see that we have like the identifier which is the route and we have the arguments that we are passing to that. If we look at this as a JavaScript object, it might look something like that. So we have a type which is a program and then it has a body and it's just like a plain JavaScript object and it has more information about it. So to solve this problem and to get an EST, we needed to have an Emacs-Trips parser. And also we needed to support a transversion, identifying nodes, replacing nodes, create new nodes and also print that back. Right now, there are like different libraries on the JavaScript ecosystem to solve this issue. But two of the most famous ones are Esprima and Recast. I think Esprima was like the pioneer on these type of libraries. But it's not really friendly right now. We want to do like changes on the EST and then print that back into source code. And that's what Recast was written for. It was written specifically to allow you to modify your ESC and then put that back into your code like keeping the spacing you have, the information of only the quotes. So you were using a single code, double code. You will keep info of that. And also it has great support for ESNex or ES2.15, 16, 17, whatever. So how does Recast work? The first part is ESD generation. How do we generate an ESD given a source code? It has like a function called parse. We just require Recast and then parse a source code to that. The output might look something like this, which is what I just showed you previously. Once we have the ESD, we can start to go through all the nodes. And to do that, Recast implements the visitor pattern. So here for every type of node, we are specifying a callback function. On visit import declaration is gonna get called. Every time we have something like import a Qunit from Qunit or import ember from ember. On this particular scenario, we are checking if it is a Qunit, ember Qunit import or a Qunit import. And then just like setting a flag with that. For the expression statement, we are like going to check like if we... Okay, are you gonna write that? Here we are checking if the node that we are currently visiting is a model definition. If it is a test, if it is an escape or an assertion. And then we are just saving that into a list. Let's check out the definition to identify a node. To identify a node, Recast has like some helpers as well. We can just get them called in Recast.names types. And here, there is assertion function. We are checking if the type of the node is a code expression. And then we just see if the name is like any of the Qunit assertions. So it is deep equal, equal, expect or whatever. So if we have like okay through the through, like really smart test, it will match that specifically node. So once we have identified all our nodes, which is what we're doing up there on the Visitor pattern. So once we have identified all our nodes, we are gonna go through all of them and do transformations. So we have like a test call, we'll add the assert argument to its callback function, and then go inside that function and replace all the assertions with assert.equal or assert.whatever. The implementation for transform assertion looks like this. So we just take the name and append.assert, which is very simple. So we have something like this, like okay through the through, the output will be assert.okay. And to transform the test callback, we just do like a sanity check to see that it is a function expression. And then we see we pass a callback if we are passing an argument to the callback function. If we are not, we just assume that it is empty and pass the assert function. So it might look something like this. We have test, it works, function empty, and then the result from this will be like test, it works, with function having callback as the argument. And here we are seeing that we are calling builders.identifier assert. That's how we create new nodes. And key recall has like an API for this as well, which are called the builders. So here we are just building at the identifier, and that's how an identifier looks like. But we have another type of builders, like here we are using the builder for import declarations. So we are passing something called the specifiers, which is the things we are bringing from that module. And then we create like the module name. The output for that is a node like that one. And then if we transfer that ESD back into code, it will look something like that, like import module and test from key unit. So we already covered how to go through the whole tree, how to identify nodes, and how to replace nodes. So the final question is, how can we print that back into source code? Printing, right? And to do this, Rick has also a helper, which is called print. And we can also pass like information about like, yeah, like the coding style. So we say like we are using two spaces on the top with, we are using single code instead of double code. And that would be like the output for the first example. The final result with this was an addon called Ember Watson, which some of you might use. And the idea behind this addon is to encapsulate custom formulas that we'll use to upgrade like things on Ember. ESDs are pretty cool and they're a really cool concept. But why are we talking about it here on an Ember conference, right? It doesn't have anything to do with Ember so far. But as most of you might know, Ember 2.0 is coming. Dark times are coming. I will have to grade a bunch of code, right? So what if we could make Ember 2.0 a self-upgradable framework? There are many things that we could automate using this concept. So to look at how we are using this today, let's start with some examples on how some frameworks are actually adopting Ember Watson to help with the upgrade story. And also we will see some things that we might want to work in. So let's start. We know that we stop like promoting the use of prototype extensions, right? So you should use Ember.computer and Ember.observer. So it's the fun of putting requests on the Ember.js guides, like, oh, don't use this, use this. And then it was like, oh, but why? We have been doing it like this all this time, right? Like, do you know how much code I will have to update? And then like two days after that, we have a put request from someone else with a new Ember Watson command called convert prototype extensions. So if we have something like that where we are calling like property, subscribe, pay, after running the command, we'll have Ember.computer, subscribe, pay, and functions. It also converts observers. And as you have things like on in it, it will convert that like to the new way. Ember data is also adopting Ember Watson to help people to upgrade to the new applications. So this one was a new command added by Stanley Stewart. Before, if we were passing like common case string to a relationship, or if we were passing like an class object, that would work. But on the latest release or two, yeah, like dot 19 or something like that, that thing was deprecated. So now we have to pass the name as a string using kebab case, which is what the Ember data, the new Ember resolver uses. So we use a Ember Watson convert Ember data model lookups and we can pass like a file or just call it like that and it will go through all your models, fixing your code. Also, I think it's gonna be like the default relationships pretty soon on Ember data. So Igor opened an issue a couple of days ago asking if we could add a command to support this. So if you have a relationship like this for the next release, I think it is gonna be a sync by default, so a sync through. But you might not want to use that jet, right? You, I don't know. So after running this command, it will have a sync false to all your relationships so your code won't break. This one is a big one. We know that the initializers change. So now we have like app initializers and instance initializers. So if we have something like that, after moving to this new format, we'll need to have like an initializer and instance initializer. I think this can be automated. People are doing like crazy stuff on their initializers. So there might be cases where it won't work. But if we manage to work on the 50 or 60% of the scenarios, sorry, if we manage to work like 60% of the time it is used, I think I will be more than happy with that. And people will be like really happy to just don't have to think about this. Just oh, fix me my code. Yet another command to update the computer property syntax. So we know like the new way is to do Ember computed and then specify get unset. So it will be pretty cool to have a command to fix this. This one should be like pretty straightforward. And if you are feeling brave, we could work with decorator style, get unset. So using Roberts Ember computer decorators, we could have code like this. And I think that's very easy to do. So it would be pretty cool if someone had the time to do it. This one is a big one. But what if we could automate the whole process of migrating from proxy controllers to only the Ember.controller? To do this, we need something like an HTML barcast or something like that, which allows to create an ESD from the template and then write that back into code, keep it info about like the indentation and all that kind of stuff. So if we have something like ember.object.controller.extend, we'll have like ember.controller.extend with all sort of craziness in there. I think this one is kind of difficult, but again, I think we can cover a bunch of cases with this. So once we have the HTML barcast thing, we could have something like a replacement app, which will go through all our templates fixing this stuff for us. And also it would be cool if we could have some kind of static analysis. So this is like common scenario when people is like starting to work with ember. They overwrite the setup controller and they forgot to call this.sopper. Yeah, this.sopper, right? And there are like a bunch of other places, like bad practices that people is doing and that could be identified using this kind of thing. So we just talk a little bit about the present. So the shunter goal with this project is to help people migrate easily to ember 2.0. But I think we could be a little more ambitious with all these things. So the long term goal for me is to get rich using... Yeah, so Ben Lege put this to it like a couple of weeks ago. Hey, Ben, over there, thanks for the name. I'm just kidding. But I think Ben represents the feeling that a bunch of people is also having, like, oh man, there's a new release. I have to read my code. And a lot of companies stay behind because, I mean, it costs money, right? You don't have people who is only in charge of reading ember every time there is a new release. So what if we could make ember self-upgradable through custom formulas, right? Imagine if for every RFC, we have an ember Watson formula attached. Or at least we have like a draw, like initial draft of that thing. More people might jump into the rapid release train. More people will give it a try. And with this, we'll be sharing the cost among the community, which is something that we all love, right? While we help ember move forward. So I would like to call for help, such as if you're upgrading to ember 2.0 and you're planning to spend, I don't know, a day or so on this kind of stuff, just think a little bit, look at the ember Watson formulas and see how can you contribute bad to the community. There are already some things in there that we could use some help in. So yeah, just keep that in mind. And also, I would like to mention Ember Swave by Dojja, which kind of enforces the JavaScript and Ember Style Guide by Dojja. I think it's a pretty cool project. And I think with these, we'll be able to identify as well, like bad practices and stuff. By the way, I always was saying Ember Swave, like just written in Spanish. So it sounds more like a merengue song to me. So thank you very much. Don't forget to buy my book. You can go to BGEOutwillers.com and yeah, we are hiring. So I guess we have time for questions. Hey, so we're really interested in using Watson, but we have one of those old non-CLI apps with just like compiles down to all one file. Can we still get this translation stuff or do we have to get on CLI before we can do that? You can run Ember Watson without being an addon. So if you say Ember Watson, it really is not like binary, right? So you can just say Ember Watson and then run any of the commands. And it should work in with globals. Great, thank you. Can you control how much of the source tree it does or does it convert everything all at once? Meaning like if you convert all of say like the O113 stuff, when you convert everything all your test break as opposed to just like changing a couple at a time and then seeing that those work and then at least establishing a pattern before you run it across the entire code base, can you control how much of this runs or you just convert everything and then fix everything? You can connect with only one file. So you can just yeah, just pass that single file and keep control of that, yeah. Can you also do like everything? Or do you just? Yeah, it does everything by default, but you can't pacify. So by default it just does everything. It's like crazy, like wow. But I mean like. All right, that's good. Thank you very much. Cool, man.