Hoy publicamos la primera parte de la traducción del material, que se dedica a crear sus propias construcciones de sintaxis para JavaScript utilizando Babel.

Revisar
Primero, echemos un vistazo a lo que lograremos cuando lleguemos al final de este material:
Vamos a implementar la sintaxis 
@@ que permite funciones de 
currículum . Esta sintaxis es similar a la utilizada para crear 
funciones generadoras , pero en nuestro caso, en lugar del signo 
* , se coloca una secuencia de caracteres 
@@ entre la palabra clave de la 
function y el nombre de la 
function . Como resultado, al declarar funciones, puede usar una construcción de la 
function @@ name(arg1, arg2) formulario 
function @@ name(arg1, arg2) .
En el ejemplo anterior, cuando trabaje con la función 
foo , puede usar su 
aplicación parcial . Llamar a la función 
foo con pasarle tantos parámetros que sea menor que la cantidad de argumentos que necesita, devolverá una nueva función que puede tomar los argumentos restantes:
 foo(1, 2, 3);  
Elegí la secuencia de caracteres 
@@ porque el símbolo 
@ no se puede usar en nombres de variables. Esto significa que una construcción de la 
function@@foo(){} forma 
function@@foo(){} también será sintácticamente correcta. Además, el "operador" 
@ se usa para las 
funciones de decorador , y quería usar algo completamente nuevo. Como resultado, elegí la construcción 
@@ .
Para lograr nuestro objetivo, debemos realizar las siguientes acciones:
- Crea un tenedor del analizador Babel.
- Crea tu propio complemento Babel para la transformación del código.
Parece algo imposible?
De hecho, no hay nada terrible aquí, analizaremos todo en detalle juntos. Espero que cuando leas esto, domines magistralmente las complejidades de Babel.
Creando un tenedor Babel
Vaya al 
repositorio de Babel en GitHub y haga clic en el botón 
Fork , que se encuentra en la esquina superior izquierda de la página.
Crear un tenedor de Babel ( imagen a tamaño completo )Y, por cierto, si acaba de crear la bifurcación del popular proyecto de código abierto por primera vez, ¡felicidades!
Ahora clone el tenedor Babel en su computadora y 
prepárelo para el trabajo .
 $ git clone https: 
Ahora permítanme hablar brevemente sobre la organización del repositorio de Babel.
Babel usa un monorepository. Todos los paquetes (por ejemplo, 
@babel/core , 
@babel/parser , 
@babel/plugin-transform-react-jsx etc.) se encuentran en la carpeta 
packages/ . Se ve así:
 - doc - packages  - babel-core  - babel-parser  - babel-plugin-transform-react-jsx  - ... - Gulpfile.js - Makefile - ... 
Observo que Babel usa un 
Makefile para automatizar tareas. Al construir un proyecto mediante el 
make build , 
Gulp se usa como administrador de tareas.
Conversión de Código a Curso Corto AST
Si no está familiarizado con conceptos como "analizador sintáctico" y "Árbol de sintaxis abstracta" (AST), antes de continuar leyendo, le recomiendo que eche un vistazo a 
este material.
Si habla brevemente sobre lo que sucede al analizar (analizar) el código, obtiene lo siguiente:
- El código presentado como una cadena (tipo string) parece una larga lista de caracteres:f, u, n, c, t, i, o, n, , @, @, f, ...
- Al principio, Babel realiza la tokenización de código. En este paso, Babel escanea el código y crea tokens. Por ejemplo, algo así como la function, @@, foo, (, a, ...
- Luego, las fichas se pasan a través del analizador para su análisis. Aquí Babel, basado en la especificación del lenguaje JavaScript, crea un árbol de sintaxis abstracta.
Aquí hay un gran recurso para aquellos que quieran aprender más sobre compiladores.
Si crees que el "compilador" es algo muy complejo e incomprensible, entonces debes saber que en realidad no todo es tan misterioso. La compilación simplemente analiza el código y crea un nuevo código sobre la base, que llamaremos XXX. El código XXX puede ser representado por el código de la máquina (quizás, el código de la máquina es lo que aparece primero en la mente de la mayoría de nosotros cuando pensamos en el compilador). Este puede ser un código JavaScript compatible con navegadores heredados. En realidad, una de las funciones principales de Babel es la compilación del código JS moderno en un código que sea comprensible para los navegadores obsoletos.
Desarrollando su propio analizador para Babel
Vamos a trabajar en los 
packages/babel-parser/ folder:
 - src/  - tokenizer/  - parser/  - plugins/    - jsx/    - typescript/    - flow/    - ... - test/ 
Ya hemos hablado de tokenización y análisis. Puede encontrar el código que implementa estos procesos en carpetas con los nombres correspondientes. Los 
plugins/ carpeta contienen complementos (complementos) que amplían las capacidades del analizador base y agregan soporte para sintaxis adicionales en el sistema. Así es exactamente cómo, por ejemplo, se implementa 
jsx y 
flow soporte de 
flow .
Solucionemos nuestro problema utilizando la tecnología de 
desarrollo a través de pruebas (desarrollo basado en pruebas, TDD). En mi opinión, es más fácil escribir una prueba primero, y luego, trabajando gradualmente en el sistema, hacer que esta prueba se ejecute sin errores. Este enfoque es especialmente bueno cuando se trabaja en una base de código desconocida. TDD facilita la comprensión de dónde debe realizar cambios en el código para implementar la funcionalidad deseada.
 packages/babel-parser/test/curry-function.js import { parse } from '../lib'; function getParser(code) {  return () => parse(code, { sourceType: 'module' }); } describe('curry function syntax', function() {  it('should parse', function() {    expect(getParser(`function @@ foo() {}`)()).toMatchSnapshot();  }); }); 
Puede ejecutar la prueba para 
babel-parser siguiente manera: 
TEST_ONLY=babel-parser TEST_GREP="curry function" make test-only . Esto le permitirá ver los errores:
 SyntaxError: Unexpected token (1:9) at Parser.raise (packages/babel-parser/src/parser/location.js:39:63) at Parser.raise [as unexpected] (packages/babel-parser/src/parser/util.js:133:16) at Parser.unexpected [as parseIdentifierName] (packages/babel-parser/src/parser/expression.js:2090:18) at Parser.parseIdentifierName [as parseIdentifier] (packages/babel-parser/src/parser/expression.js:2052:23) at Parser.parseIdentifier (packages/babel-parser/src/parser/statement.js:1096:52) 
Si encuentra que ver todas las pruebas lleva demasiado tiempo, puede, para ejecutar la prueba deseada, llamar directamente a 
jest :
 BABEL_ENV=test node_modules/.bin/jest -u packages/babel-parser/test/curry-function.js 
Nuestro analizador descubrió tokens 2 
@ , aparentemente completamente inocentes, donde no deberían estar.
¿Cómo lo supe? La respuesta a esta pregunta nos ayudará a encontrar el uso del modo de monitoreo de código lanzado por el 
make watch .
Mirar la pila de llamadas nos lleva a los 
paquetes / babel-parser / src / parser / expression.js , donde 
this.unexpected() lanza la excepción 
this.unexpected() .
Agregue un par de comandos de registro a este archivo:
 packages/babel-parser/src/parser/expression.js parseIdentifierName(pos: number, liberal?: boolean): string {  if (this.match(tt.name)) {     
Como puede ver, ambos tokens son 
@ :
 TokenType {  label: '@',   
¿Cómo descubrí que las construcciones 
this.state.type y 
this.lookahead().type me darán los tokens actuales y siguientes?
Hablaré sobre esto en la sección de este material dedicada a las funciones 
this.eat , 
this.match y 
this.next .
Antes de continuar, resumamos:
- Escribimos una prueba para babel-parser.
- Ejecutamos la prueba usando make test-only.
- Utilizamos el modo de monitoreo de código usando make watch.
- Aprendimos sobre el estado del analizador y this.state.typeinformación sobre el tipo de token actual (this.state.type) en la consola.
Y ahora nos aseguraremos de que los caracteres 2 
@ no se perciban como tokens separados, sino como un nuevo token 
@@ , el que decidimos usar para las funciones de currículum.
Nuevo token: "@@"
Primero, veamos dónde se determinan los tipos de tokens. Este es el 
paquete de archivos 
/ babel-parser / src / tokenizer / types.js .
Aquí puedes encontrar una lista de tokens. Agregue aquí la definición del nuevo token de 
atat :
 packages/babel-parser/src/tokenizer/types.js export const types: { [name: string]: TokenType } = {   
Ahora busquemos el lugar en el código donde, en el proceso de tokenización, se crean tokens. La búsqueda de la secuencia de caracteres 
tt.at en 
babel-parser/src/tokenizer nos lleva al archivo: 
packages / babel-parser / src / tokenizer / index.js . En 
babel-parser tipos de tokens se importan como 
tt .
Ahora, si después del símbolo 
@ actual aparece otro 
@ , cree un nuevo token 
tt.atat lugar del token 
tt.at :
 packages/babel-parser/src/tokenizer/index.js getTokenFromCode(code: number): void {  switch (code) {     
Si ejecuta la prueba nuevamente, notará que la información sobre los tokens actuales y siguientes ha cambiado:
 
Ya se ve bastante bien. Continuaremos el trabajo.
Nuevo analizador
Antes de continuar, observe cómo se representan las funciones del generador en AST.
AST para la función de generador ( imagen a tamaño completo )Como puede ver, el atributo 
generator: true de la entidad 
FunctionDeclaration indica que esta es una 
FunctionDeclaration generadora.
Podemos adoptar un enfoque similar para describir una función que admita curry. A saber, podemos agregar el atributo 
curry: true a 
FunctionDeclaration .
AST para la función de curry ( imagen a tamaño completo )En realidad, ahora tenemos un plan. Tratemos con su implementación.
Si busca en el código la palabra 
FunctionDeclaration , puede ir a la función 
parseFunction , que se declara en 
paquetes / babel-parser / src / parser / Statement.js . Aquí puede encontrar la línea donde se establece el atributo 
generator . Agregue otra línea al código:
 packages/babel-parser/src/parser/statement.js export default class StatementParser extends ExpressionParser {   
Si volvemos a ejecutar la prueba, nos espera una agradable sorpresa. ¡El código se ha probado con éxito!
 PASS packages/babel-parser/test/curry-function.js  curry function syntax    ✓ should parse (12ms) 
¿Eso es todo? ¿Qué hemos hecho para que la prueba pase milagrosamente?
Para averiguarlo, hablemos sobre cómo funciona el análisis. En el curso de esta conversación, espero que comprenda cómo funciona la línea 
node.curry = this.eat(tt.atat); .
Continuará ...
Estimados lectores! ¿Usas babel?
