 All right. Let's do this. All good. Perfect. So, hi everyone for this last session before the evening. It's going to be a workshop. It's a one-hour workshop, so it might be hard to, like, we cannot afford to go through the tables, etc. We will need to move on. So, that's why we did a repo and you can basically follow step by step if you need to. But we're here to, like, present you, guide you through the steps to show you how to build your first VS Code extension. My name is Nicholas. I'm a web developer working at the company named BuzzBud here in Montreal. We're developing a web application which is like the Expedia, but for buses. So, if you want to take a bus to go from Montreal to Ottawa, you can go on BuzzBud. You will compare all the operators and you can do that not only in Canada, but in 80 countries in the world and still paying Canadian dollars, for example. That's what we do. And I'm Floran. I've been working with Nicholas in the past year and now I'm a senior engineer at Shurestock. Shurestock has an office in Montreal where we build most of our product, footage, and premium bits. So, if you need cool images for your project, awesome sound tracks, or 3D effects, go to Shurestock.com or PremierBit.com and we'll find something good for your next YouTube video or Instagram story. Quick question to start with. Who here is using VS Code at work or personally? Yeah. And among you, who is using JavaScript or TypeScript? Most of you. So, that's perfect. You're in the right room and even if you're not doing JavaScript TypeScript, what you will learn today, it's going to be helpful. So, I'm not going to present VS Code. You know that. I'm going to insist on the fact that VS Code is a text editor with a marketplace where you can find a bunch of different extensions that allows you to configure your editor to the project you are working on. So, if you want to work with Vue, you will have some nice extension to improve your tooling to work with Vue projects. And if you want to move to Elixir, well, you can install extensions to work with Elixir. But not only you can install different extensions, you could actually build your own extension. It's not that hard and that's what we're going to do today. The extension we're going to build is going to do automated refactorings for you. When I said refactoring, I mean a transformation of the code that doesn't change the behavior of the code. That's important because we tend to use refactoring for almost every time we change the code without a business need for it. Here, we really mean that transformation of the code to redesign it in a different way, but the behavior doesn't change. That's what we're going to do. So, let's dive in directly and have a look at what we want to achieve. This is called the Gilded Rose Refactoring Cata. Who knows that cata? I'm going to teach you something today. This cata is a coding exercise. The goal is for you to implement a feature in that code base and, as you can see, it's not a very nicely written code. It's quite dirty. So, the goal of this exercise is for you to practice refactoring so you are cleaning the code first and then you can implement the feature. So, when you do this exercise, you need to do a bunch of transformation. Usually, the first step is to change that imperative for loop to a more declarative forage on the items. Then, yes, you copy paste the rest of the code. You replace this. I'm going to do it. So, I do that. Then, I need to replace all of this for the item. Then, maybe I want to extract this. Yeah, this is a magic string. I want to put that in a variable, hbree. And then, I replace that and this one, too, to the same reference, etc., etc. So, you do that kind of operation. And, as you can see, it takes me some time to do it manually. Let's rewind a bit. Actually, I'm going to rewind with git. Okay, let's restart that. What if I could do that? So, see, the difference of doing that because of the tooling allow me to just do it automatically. In terms of productivity, this is awesome. So, this is the kind of tooling that we're going to build today together. Unfortunately, one hour, we won't have the time to do the convert for loop to the forage or the extract variable. There are too many edge cases inside. But, what we're going to do is convert that kind of function. So, imagine you have an asynchronous get function that takes a new array and a query and that, you know, fetch some data. So, let's say for some reason, instead of having a function declaration like that, you would like to convert that to a variable declaration of a narrow function expression. So, you want to have something like that instead. What we're going to build today is this automatic transformation. Okay? So, we need to build a VS Code extension. To do that, you need to create a new project, a not project. You need to compile your project so you are exposing to VS Code an API it can use to trigger operation in the editor. And, fortunately for us, we don't have to do that by hand for every time we want to do that. Microsoft, well, the team developing VS Code, they are providing a generator for us. So, we don't have to do the boilerplate code every single time. Kind of like create react app, if you will. This is based on something called Yo-man. Yo-man, it's an old tool. You can actually use it. With Yo-man, you can create code generators and Yo-man will ask you some questions. You will fill the blanks and it will bootstrap, like scaffold the application, the basic application for you. So, you don't have to do the boilerplate by hand. So, we're going to do that. What you need, is it big enough? Yeah. So, you need to install globally on your machine Yo-man, which is Yo. And then, the generator you want to use, which in this case is generator code. I already did that. When you have that, you can say Yo-code and here is Yo-man in action. So, here you can see the different options that you can have. You can create a new extension or other things that we're not going to get into. And you can even select if you want to do that in TypeScript or in JavaScript. So, in our case, it will be TypeScript. Then you give it a name and then you select if you want to use npm or yarn. And at the end, what you end up with is the code I made you clone at the beginning of this session. So, when you have cloned that repository, this has been generated by Yo-man. We're starting from here. I don't like when code has been created and I don't know what's inside. So, let's make a tour of the created files. The first thing you have here is a VS code giving you some useful links and resources to know how to build an extension. Fortunately, for us, we're doing that today. So, we don't need this. I choose to use a TypeScript project. So, we have a TS lint and a TS configuration. So, everything is already ready to compile the code, etc. for you. A readme. The readme is important because when you are done with coding your extension and you want to package it and publish that online, that will be the front page of your extension. That will be what the people will see when they want to install your extension. Then you have a package JSON. It's a regular one. We're going to get back to the VS code custom elements which are inside. You have a change log. You're encouraged to maintain a change log. You have a git ignore. You know a git ignore. And you also have a VS code ignore, which is serving the same purpose. But again, when you're packaging your application and serving that to everyone, you don't want to include the test file, the source code. You don't want to include the VS code extension, quick stock markdown that we deleted, all of that. So, you only want to get what's packaged and ignore the rest. Then you have the source code. Inside you have the test folder. So, you already have an environment where you can test code against the VS code API. So, if you want to do integration tests with VS code API, you will write tests in there. And finally, you have the entry point of your extension. So, I'm going to present that. A bunch of comments, but I'm here to do the comments for you. So, let's get rid of that and see what we have inside. So, an extension really is two X public functions for VS code. An activate function that VS code will call whenever your extension is activated. And a deactivate function. In case the user deactivate your extension, for example, this is a moment where you clean the things that you're maybe storing in the global state or anything. Let's link into the activate function. So, you receive the current context of execution. You can start doing things like logging, and you will see that in the console, the output of your extension. But we don't need that for the moment. And then, what do we have here? Here, we are registering a comment. And a comment is the thing that the user will trigger to make your extension do some work. In our case, convert to a narrow function expression. And we make the context subscribe to that new comment. This is the comment ID. Comment IDs are shared. So, usually you prefix that with the name of your extension. And then, this is usually the name of your command. But it's a convention. You can come up with any unique string. What's important is, in the package json, you're telling VS code that this comment needs to be activated. And you're even giving it a name to be displayed. I'm going to see that in a moment. Okay. What this comment is doing? It's using VS code API to show an information message. Now, when you are here, you can debug your extension in a sandbox environment. To do so, you can use a shortcut of VS code to launch debugging, which is F5. So, you can do that, press F5. And what this will do? Yeah. It will open a new VS code window. Close my VS code window. Oh, sorry. I run the test. I want to run the extension. So, it opens a VS code window, a new one. It's a bit tiny to see, but you can see on top of the window title, you have an extension development host prefix. This is telling you you are in a sandbox. And in this specific VS code, you have your regular VS code, but it compiled your extension and it made it available in this sandbox. So, you can test your extension as if it was published and you installed it. So, if I open the command palette and I look for hello world, I can see the command that has been generated from human. And I can execute that. When I execute that, I can see it show me an information message here. And if I try to change that message and that I recompile and run that again, it works. So, so far, we have followed the getting started of the VS code tutorial. You could have done that at home. Now, we are getting into the interesting part, which is like doing something from this extension. So, I told you we're going to do an automated refactoring. The first thing I want to do is to change that hello world to something more meaningful. So, convert to arrow function. And I will change that also in the package.json. And I will change that text to, now we're not going to show an information message. And this is my first question to you. What is the first step we will need to do if you want to transform the existing code to our new code? First step. Yeah, so, yeah, read the existing code. Is it your input? No, that's the next step. So, yes, the first step is to retrieve the existing code. I want to read the code from the editor. Then, yes, I want to transform that code. So, I'm writing high level implementation for the moment. And finally, what do I need to do? Write this transform code back. Okay. So, let's implement these three functions. So, read code, text nothing and it should return me a string containing the code of the editor. So, this is a part where I'm giving you information about the VS Code API. But all of this you can find on the VS Code documentation. And that's also why I choose TypeScript because you will see that the auto completion help you discover what's available in the API. So, in VS Code you can access the window and inside the window you have the active text editor. The active text editor, for example now, it's this very file extension.ts. TypeScript is telling me that either you receive a text editor, either you receive nothing because maybe you don't have an active text editor open when you run that command. So, I retrieve that editor and if there is no editor, well too bad, so sad, I'm going to just throw a new error for the moment. No active editor. So, yeah, there is nothing I can do from there. But once I got the editor I can access the document and this has a method getText and this getText is returning me the content of the file. That's it. Then let's implement the transform function. So, the transform function takes some code and returns some transform code. For the moment we're just going to show that it works and I will append to a new line like a dumb comment just to see that it works when I run the code. So, transform from extension. Finally, I need to cannot see what. Unplug and re-plug again. So, I'm going to implement the write function. The write function takes some code and returns nothing. It will write to the editor again. I'm not calling, I'm waiting for you. No problem. So, the write function, you don't have a VS code method to write directly. This is a part where you're, when you're building an extension you need to go into the documentation, see what's available. You have lower level methods and you need to come up with your own write function. The good news is once you have done that you don't have to do it anymore. And that could probably be published in some package to give you more high level functions to manipulate VS code API. You need me to do anything? What can I say? Thank you very much. Nice. Thank you. We're back. Thank you. So, how do we write into VS code? In VS code you have that concept of workspace that you probably have encountered when you open a new folder. You're creating a workspace to work on. And on this workspace you can apply modifications. So, apply edit is expecting me to provide a workspace edit. So, let's provide that. I'm going to create a workspace edit. And what's available in the workspace edit? Well, I can do a bunch of things. I can create files, delete files, etc., etc. What I'm interested into is to update the content of a file. To update the content of a file, I need to provide the identifier of that file. So, that will be my document URI and a list of text editions. How do I retrieve the documents? Well, I had that in the editor. So, I need to get the active text editor again and then I can have my document. Okay. I need to do some updates. There is only one update I want to do. So, I'm going to call that update code. This should be a text edit based on the signature. So, I'm going to create a text edit. So, see I'm leaning on the types and documentation to know what the next step is. Okay. A text edit is taking two things. A range and the text to insert. The range, that's because I could select some text in a partial selection in my document. But in our case, we want to select the whole document. So, let's pretend it exists and the text I want to put, it's the code I received as an input. Okay. So, I need to create that whole document range, creating that, and it takes two positions. The first position, what do you think it will be? Zero. Yes. I'm going to start from the very top of the file, zero, zero. And I want to go to the very end of the file. Hope VS got worked when it creates range. If you provide a very big number, it will cap yourself to the end of the file. So, I could do that. I could provide a very big number and hope you never get past that. I have a less hacky solution, though, which is to use the document that we have. We can access the line count. And the position is zero indexed. So, pretty much like an array, the line count will always be the index of the line after the last line. So, I can get there and I know that I will always be at the end of the document. You do that once and then you never think about it again. So, we're done. Looks that there is no more red. Let's recompile and try that. So, let's get rid of this. If I look for convert to our function, I execute and it works. It transforms my code and adds my comment. That's cool. Now, we need to think about this transform function. So, we're done with the VS Code API. When you have done that, basically, you can forget about VS Code API. You have done that. You're good. And then, the core of our logic of our extension or domain, if I may, will be the transform function. And this doesn't depend on VS Code. This, I could extract and you need test. How would you transform the code? Yes. That's a very good first answer. Transformation of, you receive a string. You want another string. Regular expression usually works until some point. Because it will be very hard to handle, like, you only get a primitive string. So, it will be hard for you to get all of the nuances and the more you are getting into edge cases, and that can come very quickly, the more it will be difficult to create and maintain regular expression transformation. Now, instead, yeah, we need to have a better data structure. Is that your answer, too? Yeah. Abstract syntax tree. Yes. Who here have never heard about abstract syntax tree, AST? Okay. Who knows a lot about AST? So, sorry for you, because we're going to explain what you already know. But knowing what's an abstract syntax tree, AST, I'm going to say AST, is important. And this is exactly what Flora is going to present to you. Thank you. Back to the presentation. So, I guess there were a few issues with launching the configuration. I guess there is a fight that wasn't committed, like the launch.json. And, you know, if the fight didn't work, is everybody okay with that now? Or, yeah, I could show the launch.json. Or, if we can take a minute, so this way you've got it up and running. Oh, it was ignored. Yes, sorry. It was generated by Yeoman, but my default configuration made it in yours, so I didn't push the VS Code config. But you need that to launch the debugger. Otherwise, you can write it. All right. So, what do you have here? So, run extension, runtime executable, exact path, outfile, et cetera. And as a pre-launch, it does an NPM watch because I guess, yeah, building TSC, et cetera. I would recommend you to use the Yeoman. I will update the report to push that so you get the files. I didn't write them. These are files you can write, not just in extension code. Like, if you want to automate things that happen when you press F5, this is in VS Code. You configure that and it runs it for you. It's just a convenient way to, you know, open the debugger mode. So, you have the proper debugger. You can add break points, et cetera. That's it. So, yeah, Yeoman, your code, and then grab those files, put them in the folder, and it's going to be all good. All right. So, ASTs. So far, our code is just a bunch of characters, right? It's a string and the computer cannot really reason about it, besides being a string and we cannot do much. There is a nifty data structure, which is called a syntax real and abstract syntax tree. There is different flavors of syntax trees. The one that we care about is AST. To produce an AST, we'll use a parser. You may have heard this term parser. Who uses a parser every day? Who uses Babel? Who uses... Okay. So, everybody pretty much, right? Who uses Webpack? Yeah, everybody. So, underneath, you use a parser, because in order to make sense of your code, Webpack and Babel use a parser. There is a lot of flavors of ASTs. They are all the same, but all a bit different. It's kind of all the same cousins. They talk the same language, but with different words. The AST is lossy. It doesn't really care whether or not you put the semicolons at the end of your lines, right? It doesn't really care if you put extra parenthesis around your binary statements. It only cares about your program. It represents your program. So, many different source code can produce the same AST, because there is this representation that gets lost in the middle. But that's okay for us, because we want to understand our program and write it out again. It doesn't really matter what's written exactly, because we're going to transform it. You may have heard of Esprima, Acorn, or Babylon, which is the Babel parser. Those are all parsers. So, depending your project, depending your company, depending where you live, you may use Esprima instead of Babel parser. There is not one that is better than the other, in my opinion. It's just a matter of preference, personal preference. In our case, we will use Babel because it's widespread and it makes for a nice use case in our demonstration. I mentioned Recast and JS Code Shift. You may have heard of them. They are both tools that help you transform your code and automate refactoring, but at the last case. So, basically, there are tools that do what we want to achieve today, but for your whole code base, they're not part of just a nifty VS Code extension. You could actually build a VS Code extension based on Recast with some transformation of Recast or JS Code Shift. That would be totally feasible. So, yeah, yes, T. So, what is that? Who knows what's the name of that data structure? A tree. A green tree. All right. And the tree is composed of nodes. Each node has a class and it has children, which are the node's properties, right? Nothing really crazy so far. Each node, as I mentioned, is a certain type. Each parser will implement a different kind of type. So, the transformation that you implement for Esprimo are not working with Babel, right? These are not the same objects. They are very similar. They are named similarly, but these are not the same objects. So, if you try to use Babel types to transform something that has been processed with Esprimo, it's not going to work as expected. Let's take this small example. Console.log.l will likely be the first line of code you have ever written in JavaScript. Let's go through it and see it as the AST is. So, the first thing that you see is that it's an expression statement. So, this is the whole line as an expression statement. This expression statement is connected as a child, a single child, which is the expression itself. The expression in blue is really a call expression. And it's really just those parentheses. If you want to think about what kind of expression it is, the expression is putting two things together. A callee on the left and a call argument, a list of arguments on the right. So, this call expression is really just the parentheses. The callee, who guesses what the callee is? Is it console.log? Is it log? Is it .log? What is the callee? Console.log, yes. And on the right, the argument's quite easy. There is a single argument, so let's not spend too much time on that. This console.log is actually broken down even more as a member expression. It's made of two things because you're calling a member on A to get the left part, which is the object. And on the right, the property that is getting called on the object. So, every time you see something that A dot B, it is going to be a member expression. If you consider A dot B dot C, it's going to be a member expression made of another member expression. This member expression is that you got the object and the property, and then the string literal. String literal is a final node. There is nothing much more we can do to it. It's just a string. And this member expression is made of two parts, the object, which is an identifier, and the property, which is also an identifier. Identifiers are also final nodes in the AST. When you see identifier, it's ever something that you've written yourself, not as a string, but as, you know, like an identifier in the code. Let's write this one. So, the previous one was six elements, right? It's a tree of six elements. This one, how many elements? You want to make the price one? And, and, and, and, and, and I got shirtless socks from shirtless socks for the one who's got the right answer. Guesses. Three, four. So, it's going to be less than the console log, right? Five. Three, four, five. I guess I will keep my socks. Okay, why six? Can you go with me? I come here. Okay, let's go together. All right, six. All right. So, what is the first thing you think? How do you call that? The first thing? The first node in the tree. What would it be? Yeah. Yeah. And what would we call that? It's a declaration. Can you, can you step, step from the light? So, the first thing is the declaration, really. It's, we have the const. So, you have const declaration, you have let declaration, and the kind of the declaration is a const declaration. If we had let t equal object dot t, it would be a let. If you used var, just replace kind by var, and you got yourself a var declaration. We see where we can go with this AST. You know, we can reason about our code and we can start, you know, thinking on the hot sheet things. What is the next thing you think we do in there? After declaring our const key, object key. What is the next thing? There is a declarator, which is, yeah, technically the assignment part. So, it has two parts. On the left, the identifier that we assign, and on the right, the initialization expression for your thing. Then the identifier, what is the identifier thing? It's key, definitely. And on the right, what, what kind of thing we got on the right? The volume, but what kind we've just seen it? A member expression, but a computed member expression, right? So, there is a slight difference. But for the computer, whether you call something dot something or something braces quotes, it's exactly the same. It's represented the same for your compiler. Just with this computed true that is different. If we remove computed true and reprint the code, it's going to just write console.t. And then we've got an identifier and a string literal. Awesome. Which is six. Thank you. So, let's check it out. As you can see, even a small thing like that can be really hard to get our head around. You know, like a simple console log is six, six members. This, this member is six things as well. So, here I've opened up. Oh, wait. So, this website, who knows asexper.net? You know it. Cool. So, this website works with JavaScript, but it works also with a bunch of other languages. It helps you print the first representation of your programs. So, you can walk around it and go around it. So, let's go back to our console.log. We've got our expression statement. There are call expression. We've got the call leader is the member, identifier, et cetera. So, when you're actually in AST world, don't spend your time trying to print stuff out to your console, because it's always going to be ugly and impossible, and you will explode the console buffer. Just go there, paste your program, and try to understand what's going on. This is an amazing website. If you're interested in understanding more of the AST, I would recommend that you just go there and have fun with, you know, some lines of code that you know or that you want to play with. All right. So, now I want to talk about transformations, right? What we want to do is take this function and transform it into a narrow function. So, how are we going to do that is just by transforming the program representation in memory. So, we're going to take this syntax tree and we're going to transform it into something different by creating new nodes and removing nodes and removing elements from that tree. But it's just that, and because it's all represented with a grammar and some objects that we can manipulate and understand what they are, is it a call expression or is it a function declaration? Like, we can make the difference and we can really find what matters. As I mentioned, many libraries can offer transformation, but we're going to focus on Babel for today. So, Babel, how does it work? It's a compiler, right? It takes a blob of string, which is JavaScript or TypeScript or anything actually, puts it into a parser with some syntax plugin. If you're using TypeScript, you're using a syntax plugin because a TypeScript syntax is actually not understood by your JavaScript parser, right? It's not the same language. So, you've got plugins, this parser, the parser, we spit out an AST, then Babel will run a bunch of plugins like, hey, make it compatible with ES5 because I'm targeting browsers and boom, you got yourself new JavaScript in the end. But you can imagine plugins that transform your JavaScript code into PHP code. Like, why not? No problem. You can do whatever you want. Babel plugins are abstract syntax-free transformers. The thing they do, once they got the AST in memory, is that they take it, they try to figure it out, and they transform it into something different, something that is compatible with an older version of JavaScript. I don't have any big example in mind, but let's say we want to remove all snake keys from our code. We'll write a Babel plugin that for each identifier that we find in our code, we'll replace its name. So, here, we are back in ASC Explorer, and it's really practical because they got this transform element here, where you can say, okay, I want Babel as a transformer, and here we see this visitor, and what it says is that each time you encounter something that isn't an identifier, run this function. And in this function, we're going to take the node name and replace it with the camelCase version. So, this is a very simple transformation, but this is what we want to do in the end. We want to take our function declaration and transform it into a narrow function. So, we know how to do that now, and as you can see, we started with the code on the top left with the user underscore name John Smith, and at once we've replaced all the occurrences of the underscore username by a camelCase username, but it works also with any other key, if, oh yeah, you've got a weird keyboard, you've got a name. All right, yes. So, if I do that, and I call it not age because there is no underscore, but birthday, you see that birthday is not also automatically converted because I've not used the regex, I've used something that for each identifier will transform the contents of my code. So, it's a bit smarter. Next, we want to replace the function declaration. So, what we'll do is that we'll implement something very similar through the same visitor pattern. So, for each function declaration, we'll replace it with a narrow function, and we'll write this to a row function together that takes the node and replaces it. All right, so let's start with that. We've got the get function as we've written, as Nicolas has written on the on the screen with this body that is empty. So, this is a function declaration as an identifier get. It has the parameters, the list of parameters that are passed to the function as the list of identifiers. It has the body, and it has a sync flag. It's got more properties, but these are the ones that we really care about today. So, it's very simple, only one node in the ASC is needed to declare this function, right? So, now, if we go for this one, how many nodes do you think we need to do this counts get equal as sync URL query with the body? How many? I've got a bag. I've got a bag of sort of goodies. It doesn't. So, the question is, how many nodes in the tree do we need to have, or how many nodes does this second implementation, the counts get equal, we'll represent in the syntax tree, given that we left the body out. But the body is a single, you know, entry point as we can see in the function. It's a block statement. And we can assume that it's going to be the same on the other side. Six or seven, five. Okay. Let's go through it. I don't remember the answer. All right. So, first, we got a variable declaration the same way before we declare a variable and it's a count variable, right? We'll have a variable declarator the same way we have before. So, that's two. There is an identifier, three, the get, and then the arrow function expression. Four. Four. Who said four? Nobody. I will keep my shirt good. All right. So, now that we have our identifier, we see that we can map one on one everything. So, let's go backwards. We're going to stop. So, here I'm going to stop by the end. When you code, you may find yourself in a situation where you prefer starting by the end, starting by the beginning, inside out, outside in. Nicholas and I have different ways of thinking about it. It's find your own way. You have to practice a bit to transform the trees, et cetera, and you'll find a way where you're comfortable. So, here we're going to start with the arrow function expression, which is the deepest element of the tree where we pass the params and the body. Then we'll copy the identifier and next put it into a declarator and then finally return our variable declaration. This is exactly what we want to do in our extension, right? We take a function in and we transform it as an arrow function. And this is what Nico will show you right away and that will implement in the extension. Nice. So, let's do this for real. So, back in our transform function, let's move that to a new file so we can start working on it. So, we need to install a bunch of stuff from the internet because we need Babel. I'm going to do that. Get my keyboard back. So, again, this is the thing you discover progressively. I'm guiding you through it. We need to install four packages. All of them are from Babel. I'm going to use the short end syntax. The first one is the parser because we receive that code string. We need to parse that code string to get our AST. Once we get our AST, we will need to traverse that AST so we can transform with the visitor pattern. Finally, we want to generate from that transform AST. We want to get back to the code that we return to the editor. And in the middle, we also need Babel types so we are able to generate new nodes in our AST. Installing the internet, yeah, it works. Okay, so let's do that. Oh, sorry. So, Babel generator, Babel parser, Babel types, and Babel traverse alphabetically. You can also install Babel and it will come with everything. I like to grow granular. So, first step, I parse the code. Okay, I need to import pars from Babel parser, yes. By the way, this is a moment where I can provide parser options. So, if I want to tap into Babel plugins, for example, hey, Babel, can you handle typescript files for me? I will just ask it, like, to use that plugin. Typescript, yes. And yay, now it works with Typescript too. And all the kind of, you know, the new syntax that doesn't is not yet existing, but you want to handle. So, you provide plugins and Babel will be able to parse the code for you and generate a valid AST behind. So, in the case of Typescript, I think it's because I think it's the only one with different file extension. Yes, I think it will look at the file extension to determine that it's Typescript code. For the rest, I guess it's a matter of I can convert that syntax to a valid AST or I can't. And it depends on the grammar you are giving to me. So, for example, here, I'm giving to you, you can know, understand what a nullish coalescing operator is. So, when you encounter that syntax, you know how to translate that. If I don't provide, when it encounters, the syntax is invalid and it will throw an error saying I cannot, the code is invalid, I cannot parse that. That's how it works. In our case, I'm going to keep that simple, we only need basic JavaScript code so let's parse it. We got our AST. Oh yeah, auto import, nice. So, I want to traverse that AST and I will provide, you know, the visitor pattern, a handler, to transform that AST every time I visit a node. That will mutate my AST and from that, I want to regenerate, no, it doesn't understand this one. I want to regenerate the code. So, I need to import here and I'm doing it for real so you see what's behind the curtain. Turns out, you cannot find the type declaration for this module because I'm in TypeScript and for Babel parser or Babel types, they provide me with type declarations, not Babel Generator. So, when you're in that situation and that's why I wanted to show you, you need to install them from the types packages which contains like types for a bunch of libraries that doesn't provide you the packages. So, in that case, Babel Generator and actually Babel, yeah, the Babel Traverse was wrong. Babel Traverse too needs some love. So, I'm going to install from types, Babel Generator and Babel Traverse. Yes, now it understands what's behind this. Okay, it complains again, that's because Generate doesn't return me a code string, it returns me a result which contains the code string and the source map. In case you need that, we don't. All right, almost there. So, we're traveling that AST now. We want to do exactly what Ferrand teaches you. So, when we encounter a function declaration, we want to replace that pass with a new arrow function that will create from the current pass node. I need to create that function now to arrow function. So, it takes a node which is, and this is where I will need the Babel types. So, I'm going to import all of them. This is a nice convention so I can access all of the little helpers of Babel. This is a function declaration, right? And it will return me actually not a narrow function but a variable declaration because this is what we have decided to do. All right, I need to implement that because for the moment I return nothing. So, personally, I start from the end. That's why Flo mentioned that we're not going the same way but at the end it works the same. So, I'm starting from the very end. Okay, you need a variable declaration. I'm giving you a variable declaration. Okay, to create a variable declaration you need to provide me what kind of a declaration is it. So, in our case it's a const and a bunch of declarators. So, I'm giving you an empty list. Let me give you a first declarator. So, I need to create that again, a declarator. Can you create a variable declarator for me? Yes, but you need to provide me an identifier. Okay, I will give you an identifier. And what's, so, identifier on the left, what's on the right? The arrow function expression, yes. Thank you. Oh, yeah. So, traverse, yeah, it's not super easy to read but the first argument is the AST. The second argument is an object which is, like, it's the implementation of the visitor pattern. So, it will take as methods, the methods will be named as the node name. So, for example, I could provide an enter method that will work for every single node. In our case we want to target only the function declaration nodes. So, I'm providing function declaration. The key is actually the function declaration. Yeah, so basically in the visitor pattern you provide the names of the nodes, the type of the node that you want to mutate. So, if we put identifier, let's say, instead of function, as well as function declaration, every time there is an identifier encountered in the AST while traversing, this method is going to be executed. Right? Does that make sense? So, that's why. So, traversing the AST can be also expensive as you may think. You know, like, if you got, like, thousands of nodes, you're going to traverse every single node of your AST and et cetera, et cetera. So, you have to also be careful when you write those kind of kind of transformations that it doesn't take forever. Yes. Let's finish this. Identifier. What is this? Well, I'm creating a new identifier and I need to provide it a name. What's the name of this identifier? Yeah, at some point I will reach the input. So, that will be the node as an ID. And this as a name, maybe not what it, why is it telling me no? That's because TypeScript is telling me, oh, okay, it can be an identifier or it can be null also. It can be in a certain area where you don't have any identifier. So, thank you TypeScript for this. So, in that case, there is an identifier. I want to use the name. Otherwise, well, I will need to give up a fallback name. So, converted, maybe. So, it forces you to, this is more TypeScript-related stuff, but it forces you to, like, have a strategy for all the cases, hopefully. And finally, that arrow function expression, I'm going to build arrow function expression. And here, I will just pipe the parameters from the function declaration node to create my arrow function expression. So, it takes the params, then it takes the body, good news, I got the body, and I will also provide it the async boolean value. So, this is, in the end, the code that Florent showed you. And this should work. So, let's compile that and run this. So, convert to arrow function. Oh, yeah, I was too fast. Convert to arrow function. No, it didn't work. I need to reopen the debugger. So, recompile, convert to arrow function. Oh, thank you. Thank you. Yeah, I inserted, I told you it's an actual debugger, so I inserted the breakpoint and I exited, and because it's live coding, I wasn't concentrated. Yeah, it executed, it worked, but I want to, I want to see that again. Sorry, I'm redoing it. Okay. So, no more breakpoints. Yes, it works. So, here we are. At the end of the session, we did this together. Today, you learn to create a new VS Code extension, use the VS Code API to read the code, then you learn a bunch of AST stuff so you are able now to transform any kind of code, and this doesn't apply just to JavaScript. This concept of AST existed before. It applies to any kind of languages, so that's knowledge that can be useful to leverage. And then we use the VS Code API to write back the code, and we make that a VS Code extension. The next step will be to package and publish that. So, for this, you can just follow the official documentation. It's very good. They give you advices on the, you know, the readme, the images, the colors, the things like that, if you want to pimp your extension page. And next steps will be to do cover more things that we didn't have time to cover. First, you can see that I coded, and then after some time, I recompiled, and I tested that manually. That's fine because it's a workshop. Honestly, when you're really working to a project, don't do that. You will spend so much time testing manually, and you will like miss so much that bugs. So, I showed you. You can have an integration test using the VS Code API. Honestly, the transform function, I will usually unit test that because I don't need the VS Code API. So, just saying. Also, so far, we have created an extension. It will execute on all the function declaration of your file and convert all of them. Maybe that's what you want to do. Maybe what you want to do is what I demode before. I want to only convert the selected function declaration. That's probably more like it. Also, and this is where the existing refactorings you have in VS Code or in the existing extensions stop, but we could also handle partial selection. We have the AST, so we know the location of the nodes. With VS Code, you know also where your cursor is, so you could say, when my cursor is inside that node, I consider it's working on that node. Finally, you could explore that refactoring as a quick fix. You know the little light bulb that sometimes appear. That's a code action or a quick fix. You could explore it like that, so your extension is telling the user, A, on this code, you can actually convert that function to a narrow function if that's what you want to do. If you like what you've learned here, I've got good news for you. We have made an extension that is doing automated refactorings like that, like intuitive automated refactorings. If you're doing JavaScript or TypeScript with VS Code, I will encourage you to install it and use it to see how it goes. It can help you do exactly the things that I've done at the beginning of the session. It's open source, so if you want to contribute, you are very welcome. You have the knowledge now. You know how ASTExplorer.com. There are good first issues in the repository, so you're very welcome to help us build more. That's it. Thank you very much. We have some time for questions. Maybe if you have some final question. Yeah, we've got 10 minutes for questions, so do we? Yeah. Yeah, so this is the launch.json problem. So what you can do is do your code to generate a new project and then copy-paste the .vscode folder into it. That's our mistake. I didn't double check what I pushed. I didn't version the .vscode file that we're generated, so you don't have that launch.json. But if you run your code, it will generate it for you. Nice. More issues. Yeah. Another question? Global question? Yeah. Yeah. Oh, wow. So the whole code actions work, the quick fixes. Instead of registering a comment, you register that quick fix and .vscode is going to call your code, your extension. I think every time the user is changing the selection, for example, or the code, it will call your function and tell you, okay, tell me if there is a light bulb I need to show with something. What you do in that case when you are called, you take the current code, you take your current position, and you try to determine if you are in a node where it will be relevant to execute some refactorings. And if so, you get that list and you send it back to .vscode. And if you send a list back, it will display to the user. So that will be for them a shortcut to run that comment. You're welcome. Yes. Yes. Exactly. So if you use Babel Generate, it won't care about what you had before as an indentation, for example. So you can configure four or two spaces. But for example, if you add like at some point a custom indentation, it won't preserve that. It will regenerate everything. So that's exactly what Recast is for. Recast was built on top. And Recast is trying to solve that problem by preserving this missing information, like the spaces, the breaks. They do a better job with comments also to preserve that when you transform the code. Another way is not to rewrite in like the whole file only the parts that you need. That's also another way to limit the risk. And that's a personal preference, but I know that we've standardized pretty much all our code bases now, and that the style is enforced on us more than it's on us. So it makes very good workflows with that, because this way you can really focus your transformations, etc., on actually the code and not really the aspect of it. When you start adding all these extra information, like in Recast, it gets very noisy in terms of what you want to output and what kind of code you need to generate. So I think enforcing Predeer is also a good practice. I know that we are at it. And if you think about it, Predeer is also an ASC transformer. It takes an ASD and produce code out of it. All right, you can all go home. Thank you very much.