From 438f41b55277ba9c4451b9c2a046f24c750d7ece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=E5=9F=8E=E5=85=94Maziyo?= <247948681@qq.com> Date: Tue, 21 Feb 2023 16:31:37 +0800 Subject: [PATCH] feat: codegen --- src/compiler/codegen.js | 103 +++++++++++++++++++++++++++++++++++++-- src/compiler/parse.js | 12 +++-- src/examples/test.html | 46 +++++++++++++++++ src/runtime/component.js | 10 ++++ src/runtime/createApp.js | 3 +- src/utils/index.js | 3 ++ 6 files changed, 169 insertions(+), 8 deletions(-) create mode 100644 src/examples/test.html diff --git a/src/compiler/codegen.js b/src/compiler/codegen.js index 0fd9ee0..b0df437 100644 --- a/src/compiler/codegen.js +++ b/src/compiler/codegen.js @@ -1,5 +1,102 @@ +import { capitalize } from '../utils' +import { NodeTypes } from './ast' export function generate(ast) { - return ` - console.log('hello world') - ` + const codegen = traverseNode(ast) + const exeCode = ` + with(_ctx){ + const { + createApp, + render, + h, + Text, + Fragment, + nextTick, + reactive, + ref, + computed, + effect, + compile + } = MiniVue + return ${codegen} + } + ` + return exeCode +} + +export function traverseNode(node) { + switch (node.type) { + case NodeTypes.ROOT: + if (node.children.length > 1) { + return traverseChildren(node.children) + } else if (node.children.length === 1) { + return traverseNode(node.children[0]) + } + break + case NodeTypes.ELEMENT: + return createElement(node) + case NodeTypes.TEXT: + return createTextVNode(node) + case NodeTypes.INTERPOLATION: + return createTextVNode(node.content) + default: + break + } +} + +function createTextVNode(node) { + const child = createText(node) + return `h(Text,null,${child})` +} + +function createText({ isStatic = true, content = '' } = {}) { + return isStatic ? JSON.stringify(content) : content +} + +function createElement(node) { + let result = traverseChildren(node.children) + const propsArr = createPropsArr(node) + + const propsStr = propsArr.length ? `{${propsArr.join(', ')}}` : `null` + + return result + ? `h("${node.tag}",${propsStr},${result})` + : `h("${node.tag}",${propsStr})` +} + +function createPropsArr({ props, directives }) { + return [ + ...props.map(({ name, value }) => `${name}:${createText(value)}`), + ...directives.map(({ name, exp, arg }) => { + switch (name) { + case 'on': + const value = createText(exp) + if (/^\w+\(\w*\)/.test(value)) { + return `on${capitalize(arg.content)}:($event) => ${value}` + } else { + return `on${capitalize(arg.content)}:${value}` + } + case 'bind': + return `${arg.content}:${createText(exp)}` + case 'html': + return `innerHTML:${createText(exp)}` + default: + break + } + }) + ] +} + +function traverseChildren(children) { + if (!children.length) { + return + } + if (children.length === 1) { + const child = children[0] + if (child.type === NodeTypes.TEXT) { + return createText(child) + } else if (child.type === NodeTypes.INTERPOLATION) { + return child.content.content + } + } + return `[${children.map(child => traverseNode(child)).join(', ')}]` } diff --git a/src/compiler/parse.js b/src/compiler/parse.js index b7a677a..5151730 100644 --- a/src/compiler/parse.js +++ b/src/compiler/parse.js @@ -134,7 +134,7 @@ function parseTag(context) { advanceSpaces(context) // parse Attributes - let props = parseAttributes(context) + let { props, directives } = parseAttributes(context) // 检测是否为SelfClose let isSelfClosing = context.source.startsWith('/>') @@ -153,6 +153,7 @@ function parseTag(context) { props, isSelfClosing, children: [], + directives, codegenNode: undefined // to be created during transform phase } } @@ -174,6 +175,7 @@ function advanceSpaces(context) { function parseAttributes(context) { const props = [] + const directives = [] while ( context.source.length && !context.source.startsWith('>') && @@ -181,10 +183,14 @@ function parseAttributes(context) { !context.source.startsWith('/>') ) { const attr = parseAttribute(context) - props.push(attr) + if (attr.type === NodeTypes.DIRECTIVE) { + directives.push(attr) + } else { + props.push(attr) + } advanceSpaces(context) } - return props + return { directives, props } } function parseAttribute(context) { diff --git a/src/examples/test.html b/src/examples/test.html new file mode 100644 index 0000000..c637b91 --- /dev/null +++ b/src/examples/test.html @@ -0,0 +1,46 @@ + + +
+ + + +