wip: element transforms
This commit is contained in:
parent
b275f8697d
commit
93440bba97
@ -15,9 +15,15 @@ export const enum NodeTypes {
|
||||
EXPRESSION,
|
||||
ATTRIBUTE,
|
||||
DIRECTIVE,
|
||||
// containers
|
||||
IF,
|
||||
IF_BRANCH,
|
||||
FOR
|
||||
FOR,
|
||||
// codegen
|
||||
CALL_EXPRESSION,
|
||||
OBJECT_EXPRESSION,
|
||||
PROPERTY,
|
||||
ARRAY_EXPRESSION
|
||||
}
|
||||
|
||||
export const enum ElementTypes {
|
||||
@ -32,7 +38,22 @@ export interface Node {
|
||||
loc: SourceLocation
|
||||
}
|
||||
|
||||
// The node's range. The `start` is inclusive and `end` is exclusive.
|
||||
// [start, end)
|
||||
export interface SourceLocation {
|
||||
start: Position
|
||||
end: Position
|
||||
source: string
|
||||
}
|
||||
|
||||
export interface Position {
|
||||
offset: number // from start of file
|
||||
line: number
|
||||
column: number
|
||||
}
|
||||
|
||||
export type ParentNode = RootNode | ElementNode | IfBranchNode | ForNode
|
||||
|
||||
export type ChildNode =
|
||||
| ElementNode
|
||||
| ExpressionNode
|
||||
@ -55,6 +76,7 @@ export interface ElementNode extends Node {
|
||||
attrs: AttributeNode[]
|
||||
directives: DirectiveNode[]
|
||||
children: ChildNode[]
|
||||
codegenNode: CallExpression | undefined
|
||||
}
|
||||
|
||||
export interface TextNode extends Node {
|
||||
@ -108,16 +130,34 @@ export interface ForNode extends Node {
|
||||
children: ChildNode[]
|
||||
}
|
||||
|
||||
export interface Position {
|
||||
offset: number // from start of file
|
||||
line: number
|
||||
column: number
|
||||
// We also include a subset of JavaScript AST for code generation
|
||||
// purposes. The AST is intentioanlly minimal just to meet the exact needs of
|
||||
// Vue render function generation.
|
||||
type CodegenNode =
|
||||
| string
|
||||
| CallExpression
|
||||
| ObjectExpression
|
||||
| ArrayExpression
|
||||
| ExpressionNode
|
||||
|
||||
export interface CallExpression extends Node {
|
||||
type: NodeTypes.CALL_EXPRESSION
|
||||
callee: string // can only be imported runtime helpers, so no source location
|
||||
arguments: Array<CodegenNode | ChildNode[]>
|
||||
}
|
||||
|
||||
// The node's range. The `start` is inclusive and `end` is exclusive.
|
||||
// [start, end)
|
||||
export interface SourceLocation {
|
||||
start: Position
|
||||
end: Position
|
||||
source: string
|
||||
export interface ObjectExpression extends Node {
|
||||
type: NodeTypes.OBJECT_EXPRESSION
|
||||
properties: Array<Property>
|
||||
}
|
||||
|
||||
export interface Property extends Node {
|
||||
type: NodeTypes.PROPERTY
|
||||
key: ExpressionNode
|
||||
value: ExpressionNode
|
||||
}
|
||||
|
||||
export interface ArrayExpression extends Node {
|
||||
type: NodeTypes.ARRAY_EXPRESSION
|
||||
elements: Array<CodegenNode>
|
||||
}
|
||||
|
@ -26,14 +26,15 @@ export interface CodegenResult {
|
||||
map?: RawSourceMap
|
||||
}
|
||||
|
||||
interface CodegenContext extends Required<CodegenOptions> {
|
||||
export interface CodegenContext extends Required<CodegenOptions> {
|
||||
source: string
|
||||
code: string
|
||||
line: number
|
||||
column: number
|
||||
offset: number
|
||||
indent: number
|
||||
identifiers: Set<string>
|
||||
imports: Set<string>
|
||||
knownIdentifiers: Set<string>
|
||||
map?: SourceMapGenerator
|
||||
push(generatedCode: string, astNode?: ChildNode): void
|
||||
}
|
||||
@ -77,11 +78,14 @@ function createCodegenContext(
|
||||
line: 1,
|
||||
offset: 0,
|
||||
indent: 0,
|
||||
identifiers: new Set(),
|
||||
imports: new Set(),
|
||||
knownIdentifiers: new Set(),
|
||||
|
||||
// lazy require source-map implementation, only in non-browser builds!
|
||||
map: __BROWSER__
|
||||
? undefined
|
||||
: new (require('source-map')).SourceMapGenerator(),
|
||||
|
||||
push(generatedCode, node) {
|
||||
// TODO handle indent
|
||||
context.code += generatedCode
|
||||
@ -145,7 +149,7 @@ function genNode(node: ChildNode, context: CodegenContext) {
|
||||
}
|
||||
}
|
||||
|
||||
function genElement(el: ElementNode, context: CodegenContext) {}
|
||||
function genElement(node: ElementNode, context: CodegenContext) {}
|
||||
|
||||
function genText(node: TextNode | ExpressionNode, context: CodegenContext) {
|
||||
context.push(JSON.stringify(node.content), node)
|
||||
|
@ -1,14 +1,16 @@
|
||||
import { parse, ParserOptions } from './parse'
|
||||
import { transform, TransformOptions } from './transform'
|
||||
import { generate, CodegenOptions, CodegenResult } from './codegen'
|
||||
import { RootNode } from './ast'
|
||||
import { isString } from '@vue/shared'
|
||||
|
||||
export type CompilerOptions = ParserOptions & TransformOptions & CodegenOptions
|
||||
|
||||
export function compile(
|
||||
template: string,
|
||||
template: string | RootNode,
|
||||
options: CompilerOptions = {}
|
||||
): CodegenResult {
|
||||
const ast = parse(template, options)
|
||||
const ast = isString(template) ? parse(template, options) : template
|
||||
|
||||
transform(ast, {
|
||||
...options,
|
||||
@ -27,9 +29,15 @@ export {
|
||||
transform,
|
||||
createDirectiveTransform,
|
||||
TransformOptions,
|
||||
TransformContext,
|
||||
Transform,
|
||||
DirectiveTransform
|
||||
} from './transform'
|
||||
export { generate, CodegenOptions, CodegenResult } from './codegen'
|
||||
export {
|
||||
generate,
|
||||
CodegenOptions,
|
||||
CodegenContext,
|
||||
CodegenResult
|
||||
} from './codegen'
|
||||
export { ErrorCodes, CompilerError, createCompilerError } from './errors'
|
||||
export * from './ast'
|
||||
|
@ -22,7 +22,7 @@ export interface TransformOptions {
|
||||
onError?: (error: CompilerError) => void
|
||||
}
|
||||
|
||||
interface TransformContext {
|
||||
export interface TransformContext {
|
||||
transforms: Transform[]
|
||||
emitError: (error: CompilerError) => void
|
||||
parent: ParentNode
|
||||
|
87
packages/compiler-core/src/transforms/element.ts
Normal file
87
packages/compiler-core/src/transforms/element.ts
Normal file
@ -0,0 +1,87 @@
|
||||
import { Transform, TransformContext } from '../transform'
|
||||
import {
|
||||
NodeTypes,
|
||||
ElementTypes,
|
||||
CallExpression,
|
||||
ObjectExpression,
|
||||
ElementNode
|
||||
} from '../ast'
|
||||
|
||||
// generate a JavaScript AST for this element's codegen
|
||||
export const prepareElementForCodegen: Transform = (node, context) => {
|
||||
if (node.type === NodeTypes.ELEMENT) {
|
||||
if (
|
||||
node.tagType === ElementTypes.ELEMENT ||
|
||||
node.tagType === ElementTypes.COMPONENT
|
||||
) {
|
||||
const isComponent = node.tagType === ElementTypes.ELEMENT
|
||||
const hasProps = node.attrs.length > 0 || node.directives.length > 0
|
||||
const hasChildren = node.children.length > 0
|
||||
|
||||
const args: CallExpression['arguments'] = [
|
||||
isComponent ? node.tag : `"${node.tag}"`
|
||||
]
|
||||
// props
|
||||
if (hasProps) {
|
||||
args.push(buildProps(node))
|
||||
}
|
||||
// children
|
||||
if (hasChildren) {
|
||||
if (!hasProps) {
|
||||
// placeholder for null props, but use `0` for more condense code
|
||||
args.push(`0`)
|
||||
}
|
||||
args.push(isComponent ? buildSlots(node, context) : node.children)
|
||||
}
|
||||
|
||||
node.codegenNode = {
|
||||
type: NodeTypes.CALL_EXPRESSION,
|
||||
loc: node.loc,
|
||||
callee: `h`,
|
||||
arguments: args
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildProps({ loc, attrs }: ElementNode): ObjectExpression {
|
||||
return {
|
||||
type: NodeTypes.OBJECT_EXPRESSION,
|
||||
loc,
|
||||
// At this stage we will only process static attrs. Directive bindings will
|
||||
// be handled by their respective transforms which adds/modifies the props.
|
||||
properties: attrs.map(({ name, value, loc }) => {
|
||||
return {
|
||||
type: NodeTypes.PROPERTY,
|
||||
loc,
|
||||
key: {
|
||||
type: NodeTypes.EXPRESSION,
|
||||
loc,
|
||||
content: name,
|
||||
isStatic: true
|
||||
},
|
||||
value: {
|
||||
type: NodeTypes.EXPRESSION,
|
||||
loc: value ? value.loc : loc,
|
||||
content: value ? value.content : '',
|
||||
isStatic: true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function buildSlots(
|
||||
{ loc, children }: ElementNode,
|
||||
context: TransformContext
|
||||
): ObjectExpression {
|
||||
const slots: ObjectExpression = {
|
||||
type: NodeTypes.OBJECT_EXPRESSION,
|
||||
loc,
|
||||
properties: []
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
||||
return slots
|
||||
}
|
Loading…
Reference in New Issue
Block a user