Por lo tanto, estoy trabajando para "normalizar" un JS AST de ciertas maneras para facilitar la transpilación a un idioma de destino en particular. Así que tengo que aprender los detalles internos del AST. Luego, para probarlo, lo estoy convirtiendo nuevamente en código fuente JS, usando funciones de impresión . He manejado casi todos los casos hasta ahora, pero el TemplateLiteral parece tener una estructura extraña.
Por ejemplo, tiene esta cadena de plantilla:
const str = 'const b83 = `foo${a100} bar ${b82}`' Analice esa str en un AST y obtendrá esta estructura:
{ "type": "TemplateLiteral", "start": 2692, "end": 2715, "expressions": [ { "type": "Identifier", "start": 2698, "end": 2702, "name": "a100" }, { "type": "Identifier", "start": 2710, "end": 2713, "name": "b82" } ], "quasis": [ { "type": "TemplateElement", "start": 2693, "end": 2696, "value": { "raw": "foo", "cooked": "foo" }, "tail": false }, { "type": "TemplateElement", "start": 2703, "end": 2708, "value": { "raw": " bar ", "cooked": " bar " }, "tail": false }, { "type": "TemplateElement", "start": 2714, "end": 2714, "value": { "raw": "", "cooked": "" }, "tail": true } ] }Tenga en cuenta que las "expresiones" y los "cuasis" no están entrelazados, se convierten en matrices separadas. ¿Cómo voy a regresar y colocarlos correctamente en el orden correcto para regenerar el código fuente de la cadena de plantilla? Suponga que este nodo AST podría ser parte de un AST más grande, y el árbol podría reescribirse, por lo que cualquier información que use con respecto a las posiciones de texto inicial y final solo será útil desde una perspectiva relativa, no absoluta. Simplemente no estoy muy seguro de cuál es la mejor manera de leer el principio y el final para volver a entrelazar las expresiones y cuasi.
Siempre vas a tener quasis.length == expressions.length+1 . Simplemente toma el primer cuasi, luego la primera expresión, luego el siguiente cuasi, luego la siguiente expresión, etc., hasta el último cuasi.
function getResultFromTemplateLiteral(ret, path) { const { expressions, quasis } = ret // 拼接模板let str = '' for (let i = 0; i < quasis.length; i++) { if (i) { str += '__' + expressions[i - 1].name + '__' } str += quasis[i].value.cooked } // 收集变量引用const expMap = new Map() for (let i = 0; i < expressions.length; i++) { const { name } = expressions[i] if (!expMap.has(name)) { const ref = path.scope.getBinding(name) if (ref) { let { init, init: { type, value } } = ref.path.node if (type === 'StringLiteral') { expMap.set(name, value) } else if (type === 'TemplateLiteral') { expMap.set(name, getResultFromTemplateLiteral(init, path)) } } else { expMap.set(name, '') } } } return str = str.replace(/__(.*?)__/gim, name => expMap.get(name.replace(/__/g, ''))) }