From c13829ecddb5e5bf8630cbb4bead25840c5b2204 Mon Sep 17 00:00:00 2001 From: jindy <296596955@qq..com> Date: Mon, 27 Jun 2022 22:19:30 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E4=BB=A3=E7=A0=81=E7=94=9F?= =?UTF-8?q?=E6=88=90=E4=B8=89=E7=A7=8D=E8=81=94=E5=90=88=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/compiler-core/src/ast.ts | 14 +++++ src/compiler-core/src/codegen.ts | 62 ++++++++++++++++++- src/compiler-core/src/runtimeHelpers.ts | 2 + src/compiler-core/src/transform.ts | 20 ++++-- .../src/transform/transformElement.ts | 33 ++++++++++ .../src/transform/transformText.ts | 34 ++++++++++ src/compiler-core/src/util.ts | 5 ++ .../tests/__snapshots__/codegen.spec.ts.snap | 5 ++ src/compiler-core/tests/codegen.spec.ts | 14 +++++ src/shared/index.ts | 2 + 10 files changed, 186 insertions(+), 5 deletions(-) create mode 100644 src/compiler-core/src/transform/transformElement.ts create mode 100644 src/compiler-core/src/transform/transformText.ts create mode 100644 src/compiler-core/src/util.ts diff --git a/src/compiler-core/src/ast.ts b/src/compiler-core/src/ast.ts index fe0f38f..94d77c6 100644 --- a/src/compiler-core/src/ast.ts +++ b/src/compiler-core/src/ast.ts @@ -1,3 +1,5 @@ +import { CREATE_ELEMENT_VNODE } from "./runtimeHelpers" + export const enum NodeTypes { // interpolation INTERPOLATION, @@ -6,4 +8,16 @@ export const enum NodeTypes { ELEMENT, TEXT, ROOT, + COMPOUND_EXPRESSION, +} + +export function createVNodeCall(context, tag, props, children) { + context.helper(CREATE_ELEMENT_VNODE) + + return { + type: NodeTypes.ELEMENT, + tag, + props, + children, + } } diff --git a/src/compiler-core/src/codegen.ts b/src/compiler-core/src/codegen.ts index 0807acc..467f8d3 100644 --- a/src/compiler-core/src/codegen.ts +++ b/src/compiler-core/src/codegen.ts @@ -1,5 +1,10 @@ -import { helperMapName, TO_DISPLAY_STRING } from "./runtimeHelpers" +import { + CREATE_ELEMENT_VNODE, + helperMapName, + TO_DISPLAY_STRING, +} from "./runtimeHelpers" import { NodeTypes } from "./ast" +import { isString } from "../../shared" export function generate(ast) { // let code = "" @@ -65,11 +70,66 @@ function genNode(node, context) { break case NodeTypes.SIMPLE_EXPRESSION: genExpression(node, context) + break + case NodeTypes.ELEMENT: + genElement(node, context) + break + case NodeTypes.COMPOUND_EXPRESSION: + genCompoundExpression(node, context) + break default: break } } +function genCompoundExpression(node, context) { + const { children } = node + const { push } = context + for (let index = 0; index < children.length; index++) { + const child = children[index] + if (isString(child)) { + push(child) + } else { + genNode(child, context) + } + } +} + +function genElement(node, context) { + const { push, helper } = context + const { tag, children, props } = node + push(`${helper(CREATE_ELEMENT_VNODE)}(`) + // const child = children[0] + // for (let index = 0; index < children.length; index++) { + // const child = children[index] + // genNode(child, context) + // } + genNodeList(genNullable([tag, props, children]), context) + // genNode(children, context) + push(")") +} + +function genNodeList(nodes, context) { + const { push } = context + + for (let index = 0; index < nodes.length; index++) { + const node = nodes[index] + if (isString(node)) { + push(node) + } else { + genNode(node, context) + } + + if (index < nodes.length - 1) { + push(",") + } + } +} + +function genNullable(args: any) { + return args.map((arg) => arg || "null") +} + function genExpression(node, context) { const { push } = context push(`${node.content}`) diff --git a/src/compiler-core/src/runtimeHelpers.ts b/src/compiler-core/src/runtimeHelpers.ts index c60d28c..ea87df7 100644 --- a/src/compiler-core/src/runtimeHelpers.ts +++ b/src/compiler-core/src/runtimeHelpers.ts @@ -1,5 +1,7 @@ export const TO_DISPLAY_STRING = Symbol("toDisplayString") +export const CREATE_ELEMENT_VNODE = Symbol("createElementVNode") export const helperMapName = { [TO_DISPLAY_STRING]: "toDisplayString", + [CREATE_ELEMENT_VNODE]: "createElementVNode", } diff --git a/src/compiler-core/src/transform.ts b/src/compiler-core/src/transform.ts index 89c69e6..e370c08 100644 --- a/src/compiler-core/src/transform.ts +++ b/src/compiler-core/src/transform.ts @@ -7,13 +7,18 @@ export function transform(root, options = {}) { traverseNode(root, context) // 2.修改 text content - createCodegen(root) + createRootCodegen(root) root.helpers = [...context.helpers.keys()] } -function createCodegen(root) { - root.codegenNode = root.children[0] +function createRootCodegen(root) { + const child = root.children[0] + if (child.type === NodeTypes.ELEMENT) { + root.codegenNode = child.codegenNode + } else { + root.codegenNode = root.children[0] + } } function createTransformContext(root, options) { @@ -35,9 +40,11 @@ function traverseNode(node, context) { // node.content = node.content + "mini-vue" // } const nodeTransforms = context.nodeTransforms + const exitFns: any = [] for (let index = 0; index < nodeTransforms.length; index++) { const transform = nodeTransforms[index] - transform(node) + const onExit = transform(node, context) + if (onExit) exitFns.push(onExit) } switch (node.type) { @@ -51,6 +58,11 @@ function traverseNode(node, context) { default: break } + + let i = exitFns.length + while (i--) { + exitFns[i]() + } } function traverseChildren(node, context) { diff --git a/src/compiler-core/src/transform/transformElement.ts b/src/compiler-core/src/transform/transformElement.ts new file mode 100644 index 0000000..ed12298 --- /dev/null +++ b/src/compiler-core/src/transform/transformElement.ts @@ -0,0 +1,33 @@ +import { createVNodeCall, NodeTypes } from "../ast" +import { CREATE_ELEMENT_VNODE } from "../runtimeHelpers" + +export function transformElement(node: any, context) { + if (node.type === NodeTypes.ELEMENT) { + return () => { + // context.helper(CREATE_ELEMENT_VNODE) + + // 中间层 + // tag + const vnodeTag = `'${node.tag}'` + // children + const children = node.children + const vnodeChildren = children[0] + // props + let vnodeProps + + // const vnodeElement = { + // type: NodeTypes.ELEMENT, + // tag: vnodeTag, + // props: vnodeProps, + // children: vnodeChildren, + // } + + node.codegenNode = createVNodeCall( + context, + vnodeTag, + vnodeProps, + vnodeChildren + ) + } + } +} diff --git a/src/compiler-core/src/transform/transformText.ts b/src/compiler-core/src/transform/transformText.ts new file mode 100644 index 0000000..d05ff6f --- /dev/null +++ b/src/compiler-core/src/transform/transformText.ts @@ -0,0 +1,34 @@ +import { NodeTypes } from "../ast" +import { isText } from "../util" + +export function transformText(node) { + return () => { + const { children, type } = node + if (type === NodeTypes.ELEMENT) { + let currentContainer + for (let index = 0; index < children.length; index++) { + const child = children[index] + if (isText(child)) { + for (let j = index + 1; j < children.length; j++) { + const next = children[j] + if (isText(next)) { + if (!currentContainer) { + currentContainer = children[index] = { + type: NodeTypes.COMPOUND_EXPRESSION, + children: [child], + } + } + currentContainer.children.push(" + ") + currentContainer.children.push(next) + children.splice(j, 1) + j-- + } else { + currentContainer = undefined + break + } + } + } + } + } + } +} diff --git a/src/compiler-core/src/util.ts b/src/compiler-core/src/util.ts new file mode 100644 index 0000000..30e0bf4 --- /dev/null +++ b/src/compiler-core/src/util.ts @@ -0,0 +1,5 @@ +import { NodeTypes } from "./ast" + +export function isText(node) { + return node.type === NodeTypes.INTERPOLATION || node.type === NodeTypes.TEXT +} diff --git a/src/compiler-core/tests/__snapshots__/codegen.spec.ts.snap b/src/compiler-core/tests/__snapshots__/codegen.spec.ts.snap index 71244f2..fa7a016 100644 --- a/src/compiler-core/tests/__snapshots__/codegen.spec.ts.snap +++ b/src/compiler-core/tests/__snapshots__/codegen.spec.ts.snap @@ -1,5 +1,10 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`codegen element 1`] = ` +"const { toDisplayString: _toDisplayString,createElementVNode: _createElementVNode } = Vue +return function render(_ctx,_cache){return _createElementVNode('div',null,'hi,' + _toDisplayString(_ctx.message))}" +`; + exports[`codegen interpolation 1`] = ` "const { toDisplayString: _toDisplayString } = Vue return function render(_ctx,_cache){return _toDisplayString(_ctx.message)}" diff --git a/src/compiler-core/tests/codegen.spec.ts b/src/compiler-core/tests/codegen.spec.ts index 1170776..81558a7 100644 --- a/src/compiler-core/tests/codegen.spec.ts +++ b/src/compiler-core/tests/codegen.spec.ts @@ -1,7 +1,9 @@ import { generate } from "../src/codegen" import { baseParse } from "../src/parse" import { transform } from "../src/transform" +import { transformElement } from "../src/transform/transformElement" import { transformExpression } from "../src/transform/transformExpression" +import { transformText } from "../src/transform/transformText" describe("codegen", () => { it("string", () => { @@ -21,4 +23,16 @@ describe("codegen", () => { // 快照测试 expect(code).toMatchSnapshot() }) + + it("element", () => { + const ast = baseParse("