| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812 |
- import { isString } from '@vue/shared'
- import { ForParseResult } from './transforms/vFor'
- import {
- RENDER_SLOT,
- CREATE_SLOTS,
- RENDER_LIST,
- OPEN_BLOCK,
- FRAGMENT,
- WITH_DIRECTIVES,
- WITH_MEMO
- } from './runtimeHelpers'
- import { PropsExpression } from './transforms/transformElement'
- import { ImportItem, TransformContext } from './transform'
- import { getVNodeBlockHelper, getVNodeHelper } from './utils'
- // Vue template is a platform-agnostic superset of HTML (syntax only).
- // More namespaces like SVG and MathML are declared by platform specific
- // compilers.
- export type Namespace = number
- export const enum Namespaces {
- HTML
- }
- export const enum NodeTypes {
- ROOT,
- ELEMENT,
- TEXT,
- COMMENT,
- SIMPLE_EXPRESSION,
- INTERPOLATION,
- ATTRIBUTE,
- DIRECTIVE,
- // containers
- COMPOUND_EXPRESSION,
- IF,
- IF_BRANCH,
- FOR,
- TEXT_CALL,
- // codegen
- VNODE_CALL,
- JS_CALL_EXPRESSION,
- JS_OBJECT_EXPRESSION,
- JS_PROPERTY,
- JS_ARRAY_EXPRESSION,
- JS_FUNCTION_EXPRESSION,
- JS_CONDITIONAL_EXPRESSION,
- JS_CACHE_EXPRESSION,
- // ssr codegen
- JS_BLOCK_STATEMENT,
- JS_TEMPLATE_LITERAL,
- JS_IF_STATEMENT,
- JS_ASSIGNMENT_EXPRESSION,
- JS_SEQUENCE_EXPRESSION,
- JS_RETURN_STATEMENT
- }
- export const enum ElementTypes {
- ELEMENT,
- COMPONENT,
- SLOT,
- TEMPLATE
- }
- export interface Node {
- type: NodeTypes
- 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 ExpressionNode = SimpleExpressionNode | CompoundExpressionNode
- export type TemplateChildNode =
- | ElementNode
- | InterpolationNode
- | CompoundExpressionNode
- | TextNode
- | CommentNode
- | IfNode
- | IfBranchNode
- | ForNode
- | TextCallNode
- export interface RootNode extends Node {
- type: NodeTypes.ROOT
- children: TemplateChildNode[]
- helpers: symbol[]
- components: string[]
- directives: string[]
- hoists: (JSChildNode | null)[]
- imports: ImportItem[]
- cached: number
- temps: number
- ssrHelpers?: symbol[]
- codegenNode?: TemplateChildNode | JSChildNode | BlockStatement
- // v2 compat only
- filters?: string[]
- }
- export type ElementNode =
- | PlainElementNode
- | ComponentNode
- | SlotOutletNode
- | TemplateNode
- export interface BaseElementNode extends Node {
- type: NodeTypes.ELEMENT
- ns: Namespace
- tag: string
- tagType: ElementTypes
- isSelfClosing: boolean
- props: Array<AttributeNode | DirectiveNode>
- children: TemplateChildNode[]
- }
- export interface PlainElementNode extends BaseElementNode {
- tagType: ElementTypes.ELEMENT
- codegenNode:
- | VNodeCall
- | SimpleExpressionNode // when hoisted
- | CacheExpression // when cached by v-once
- | MemoExpression // when cached by v-memo
- | undefined
- ssrCodegenNode?: TemplateLiteral
- }
- export interface ComponentNode extends BaseElementNode {
- tagType: ElementTypes.COMPONENT
- codegenNode:
- | VNodeCall
- | CacheExpression // when cached by v-once
- | MemoExpression // when cached by v-memo
- | undefined
- ssrCodegenNode?: CallExpression
- }
- export interface SlotOutletNode extends BaseElementNode {
- tagType: ElementTypes.SLOT
- codegenNode:
- | RenderSlotCall
- | CacheExpression // when cached by v-once
- | undefined
- ssrCodegenNode?: CallExpression
- }
- export interface TemplateNode extends BaseElementNode {
- tagType: ElementTypes.TEMPLATE
- // TemplateNode is a container type that always gets compiled away
- codegenNode: undefined
- }
- export interface TextNode extends Node {
- type: NodeTypes.TEXT
- content: string
- }
- export interface CommentNode extends Node {
- type: NodeTypes.COMMENT
- content: string
- }
- export interface AttributeNode extends Node {
- type: NodeTypes.ATTRIBUTE
- name: string
- value: TextNode | undefined
- }
- export interface DirectiveNode extends Node {
- type: NodeTypes.DIRECTIVE
- name: string
- exp: ExpressionNode | undefined
- arg: ExpressionNode | undefined
- modifiers: string[]
- /**
- * optional property to cache the expression parse result for v-for
- */
- parseResult?: ForParseResult
- }
- /**
- * Static types have several levels.
- * Higher levels implies lower levels. e.g. a node that can be stringified
- * can always be hoisted and skipped for patch.
- */
- export const enum ConstantTypes {
- NOT_CONSTANT = 0,
- CAN_SKIP_PATCH,
- CAN_HOIST,
- CAN_STRINGIFY
- }
- export interface SimpleExpressionNode extends Node {
- type: NodeTypes.SIMPLE_EXPRESSION
- content: string
- isStatic: boolean
- constType: ConstantTypes
- /**
- * Indicates this is an identifier for a hoist vnode call and points to the
- * hoisted node.
- */
- hoisted?: JSChildNode
- /**
- * an expression parsed as the params of a function will track
- * the identifiers declared inside the function body.
- */
- identifiers?: string[]
- isHandlerKey?: boolean
- }
- export interface InterpolationNode extends Node {
- type: NodeTypes.INTERPOLATION
- content: ExpressionNode
- }
- export interface CompoundExpressionNode extends Node {
- type: NodeTypes.COMPOUND_EXPRESSION
- children: (
- | SimpleExpressionNode
- | CompoundExpressionNode
- | InterpolationNode
- | TextNode
- | string
- | symbol
- )[]
- /**
- * an expression parsed as the params of a function will track
- * the identifiers declared inside the function body.
- */
- identifiers?: string[]
- isHandlerKey?: boolean
- }
- export interface IfNode extends Node {
- type: NodeTypes.IF
- branches: IfBranchNode[]
- codegenNode?: IfConditionalExpression | CacheExpression // <div v-if v-once>
- }
- export interface IfBranchNode extends Node {
- type: NodeTypes.IF_BRANCH
- condition: ExpressionNode | undefined // else
- children: TemplateChildNode[]
- userKey?: AttributeNode | DirectiveNode
- isTemplateIf?: boolean
- }
- export interface ForNode extends Node {
- type: NodeTypes.FOR
- source: ExpressionNode
- valueAlias: ExpressionNode | undefined
- keyAlias: ExpressionNode | undefined
- objectIndexAlias: ExpressionNode | undefined
- parseResult: ForParseResult
- children: TemplateChildNode[]
- codegenNode?: ForCodegenNode
- }
- export interface TextCallNode extends Node {
- type: NodeTypes.TEXT_CALL
- content: TextNode | InterpolationNode | CompoundExpressionNode
- codegenNode: CallExpression | SimpleExpressionNode // when hoisted
- }
- export type TemplateTextChildNode =
- | TextNode
- | InterpolationNode
- | CompoundExpressionNode
- export interface VNodeCall extends Node {
- type: NodeTypes.VNODE_CALL
- tag: string | symbol | CallExpression
- props: PropsExpression | undefined
- children:
- | TemplateChildNode[] // multiple children
- | TemplateTextChildNode // single text child
- | SlotsExpression // component slots
- | ForRenderListExpression // v-for fragment call
- | SimpleExpressionNode // hoisted
- | undefined
- patchFlag: string | undefined
- dynamicProps: string | SimpleExpressionNode | undefined
- directives: DirectiveArguments | undefined
- isBlock: boolean
- disableTracking: boolean
- isComponent: boolean
- }
- // JS Node Types ---------------------------------------------------------------
- // We also include a number of JavaScript AST nodes for code generation.
- // The AST is an intentionally minimal subset just to meet the exact needs of
- // Vue render function generation.
- export type JSChildNode =
- | VNodeCall
- | CallExpression
- | ObjectExpression
- | ArrayExpression
- | ExpressionNode
- | FunctionExpression
- | ConditionalExpression
- | CacheExpression
- | AssignmentExpression
- | SequenceExpression
- export interface CallExpression extends Node {
- type: NodeTypes.JS_CALL_EXPRESSION
- callee: string | symbol
- arguments: (
- | string
- | symbol
- | JSChildNode
- | SSRCodegenNode
- | TemplateChildNode
- | TemplateChildNode[]
- )[]
- }
- export interface ObjectExpression extends Node {
- type: NodeTypes.JS_OBJECT_EXPRESSION
- properties: Array<Property>
- }
- export interface Property extends Node {
- type: NodeTypes.JS_PROPERTY
- key: ExpressionNode
- value: JSChildNode
- }
- export interface ArrayExpression extends Node {
- type: NodeTypes.JS_ARRAY_EXPRESSION
- elements: Array<string | Node>
- }
- export interface FunctionExpression extends Node {
- type: NodeTypes.JS_FUNCTION_EXPRESSION
- params: ExpressionNode | string | (ExpressionNode | string)[] | undefined
- returns?: TemplateChildNode | TemplateChildNode[] | JSChildNode
- body?: BlockStatement | IfStatement
- newline: boolean
- /**
- * This flag is for codegen to determine whether it needs to generate the
- * withScopeId() wrapper
- */
- isSlot: boolean
- /**
- * __COMPAT__ only, indicates a slot function that should be excluded from
- * the legacy $scopedSlots instance property.
- */
- isNonScopedSlot?: boolean
- }
- export interface ConditionalExpression extends Node {
- type: NodeTypes.JS_CONDITIONAL_EXPRESSION
- test: JSChildNode
- consequent: JSChildNode
- alternate: JSChildNode
- newline: boolean
- }
- export interface CacheExpression extends Node {
- type: NodeTypes.JS_CACHE_EXPRESSION
- index: number
- value: JSChildNode
- isVNode: boolean
- }
- export interface MemoExpression extends CallExpression {
- callee: typeof WITH_MEMO
- arguments: [ExpressionNode, MemoFactory, string, string]
- }
- interface MemoFactory extends FunctionExpression {
- returns: BlockCodegenNode
- }
- // SSR-specific Node Types -----------------------------------------------------
- export type SSRCodegenNode =
- | BlockStatement
- | TemplateLiteral
- | IfStatement
- | AssignmentExpression
- | ReturnStatement
- | SequenceExpression
- export interface BlockStatement extends Node {
- type: NodeTypes.JS_BLOCK_STATEMENT
- body: (JSChildNode | IfStatement)[]
- }
- export interface TemplateLiteral extends Node {
- type: NodeTypes.JS_TEMPLATE_LITERAL
- elements: (string | JSChildNode)[]
- }
- export interface IfStatement extends Node {
- type: NodeTypes.JS_IF_STATEMENT
- test: ExpressionNode
- consequent: BlockStatement
- alternate: IfStatement | BlockStatement | ReturnStatement | undefined
- }
- export interface AssignmentExpression extends Node {
- type: NodeTypes.JS_ASSIGNMENT_EXPRESSION
- left: SimpleExpressionNode
- right: JSChildNode
- }
- export interface SequenceExpression extends Node {
- type: NodeTypes.JS_SEQUENCE_EXPRESSION
- expressions: JSChildNode[]
- }
- export interface ReturnStatement extends Node {
- type: NodeTypes.JS_RETURN_STATEMENT
- returns: TemplateChildNode | TemplateChildNode[] | JSChildNode
- }
- // Codegen Node Types ----------------------------------------------------------
- export interface DirectiveArguments extends ArrayExpression {
- elements: DirectiveArgumentNode[]
- }
- export interface DirectiveArgumentNode extends ArrayExpression {
- elements: // dir, exp, arg, modifiers
- | [string]
- | [string, ExpressionNode]
- | [string, ExpressionNode, ExpressionNode]
- | [string, ExpressionNode, ExpressionNode, ObjectExpression]
- }
- // renderSlot(...)
- export interface RenderSlotCall extends CallExpression {
- callee: typeof RENDER_SLOT
- arguments: // $slots, name, props, fallback
- | [string, string | ExpressionNode]
- | [string, string | ExpressionNode, PropsExpression]
- | [
- string,
- string | ExpressionNode,
- PropsExpression | '{}',
- TemplateChildNode[]
- ]
- }
- export type SlotsExpression = SlotsObjectExpression | DynamicSlotsExpression
- // { foo: () => [...] }
- export interface SlotsObjectExpression extends ObjectExpression {
- properties: SlotsObjectProperty[]
- }
- export interface SlotsObjectProperty extends Property {
- value: SlotFunctionExpression
- }
- export interface SlotFunctionExpression extends FunctionExpression {
- returns: TemplateChildNode[]
- }
- // createSlots({ ... }, [
- // foo ? () => [] : undefined,
- // renderList(list, i => () => [i])
- // ])
- export interface DynamicSlotsExpression extends CallExpression {
- callee: typeof CREATE_SLOTS
- arguments: [SlotsObjectExpression, DynamicSlotEntries]
- }
- export interface DynamicSlotEntries extends ArrayExpression {
- elements: (ConditionalDynamicSlotNode | ListDynamicSlotNode)[]
- }
- export interface ConditionalDynamicSlotNode extends ConditionalExpression {
- consequent: DynamicSlotNode
- alternate: DynamicSlotNode | SimpleExpressionNode
- }
- export interface ListDynamicSlotNode extends CallExpression {
- callee: typeof RENDER_LIST
- arguments: [ExpressionNode, ListDynamicSlotIterator]
- }
- export interface ListDynamicSlotIterator extends FunctionExpression {
- returns: DynamicSlotNode
- }
- export interface DynamicSlotNode extends ObjectExpression {
- properties: [Property, DynamicSlotFnProperty]
- }
- export interface DynamicSlotFnProperty extends Property {
- value: SlotFunctionExpression
- }
- export type BlockCodegenNode = VNodeCall | RenderSlotCall
- export interface IfConditionalExpression extends ConditionalExpression {
- consequent: BlockCodegenNode | MemoExpression
- alternate: BlockCodegenNode | IfConditionalExpression | MemoExpression
- }
- export interface ForCodegenNode extends VNodeCall {
- isBlock: true
- tag: typeof FRAGMENT
- props: undefined
- children: ForRenderListExpression
- patchFlag: string
- disableTracking: boolean
- }
- export interface ForRenderListExpression extends CallExpression {
- callee: typeof RENDER_LIST
- arguments: [ExpressionNode, ForIteratorExpression]
- }
- export interface ForIteratorExpression extends FunctionExpression {
- returns: BlockCodegenNode
- }
- // AST Utilities ---------------------------------------------------------------
- // Some expressions, e.g. sequence and conditional expressions, are never
- // associated with template nodes, so their source locations are just a stub.
- // Container types like CompoundExpression also don't need a real location.
- export const locStub: SourceLocation = {
- source: '',
- start: { line: 1, column: 1, offset: 0 },
- end: { line: 1, column: 1, offset: 0 }
- }
- export function createRoot(
- children: TemplateChildNode[],
- loc = locStub
- ): RootNode {
- return {
- type: NodeTypes.ROOT,
- children,
- helpers: [],
- components: [],
- directives: [],
- hoists: [],
- imports: [],
- cached: 0,
- temps: 0,
- codegenNode: undefined,
- loc
- }
- }
- export function createVNodeCall(
- context: TransformContext | null,
- tag: VNodeCall['tag'],
- props?: VNodeCall['props'],
- children?: VNodeCall['children'],
- patchFlag?: VNodeCall['patchFlag'],
- dynamicProps?: VNodeCall['dynamicProps'],
- directives?: VNodeCall['directives'],
- isBlock: VNodeCall['isBlock'] = false,
- disableTracking: VNodeCall['disableTracking'] = false,
- isComponent: VNodeCall['isComponent'] = false,
- loc = locStub
- ): VNodeCall {
- if (context) {
- if (isBlock) {
- context.helper(OPEN_BLOCK)
- context.helper(getVNodeBlockHelper(context.inSSR, isComponent))
- } else {
- context.helper(getVNodeHelper(context.inSSR, isComponent))
- }
- if (directives) {
- context.helper(WITH_DIRECTIVES)
- }
- }
- return {
- type: NodeTypes.VNODE_CALL,
- tag,
- props,
- children,
- patchFlag,
- dynamicProps,
- directives,
- isBlock,
- disableTracking,
- isComponent,
- loc
- }
- }
- export function createArrayExpression(
- elements: ArrayExpression['elements'],
- loc: SourceLocation = locStub
- ): ArrayExpression {
- return {
- type: NodeTypes.JS_ARRAY_EXPRESSION,
- loc,
- elements
- }
- }
- export function createObjectExpression(
- properties: ObjectExpression['properties'],
- loc: SourceLocation = locStub
- ): ObjectExpression {
- return {
- type: NodeTypes.JS_OBJECT_EXPRESSION,
- loc,
- properties
- }
- }
- export function createObjectProperty(
- key: Property['key'] | string,
- value: Property['value']
- ): Property {
- return {
- type: NodeTypes.JS_PROPERTY,
- loc: locStub,
- key: isString(key) ? createSimpleExpression(key, true) : key,
- value
- }
- }
- export function createSimpleExpression(
- content: SimpleExpressionNode['content'],
- isStatic: SimpleExpressionNode['isStatic'] = false,
- loc: SourceLocation = locStub,
- constType: ConstantTypes = ConstantTypes.NOT_CONSTANT
- ): SimpleExpressionNode {
- return {
- type: NodeTypes.SIMPLE_EXPRESSION,
- loc,
- content,
- isStatic,
- constType: isStatic ? ConstantTypes.CAN_STRINGIFY : constType
- }
- }
- export function createInterpolation(
- content: InterpolationNode['content'] | string,
- loc: SourceLocation
- ): InterpolationNode {
- return {
- type: NodeTypes.INTERPOLATION,
- loc,
- content: isString(content)
- ? createSimpleExpression(content, false, loc)
- : content
- }
- }
- export function createCompoundExpression(
- children: CompoundExpressionNode['children'],
- loc: SourceLocation = locStub
- ): CompoundExpressionNode {
- return {
- type: NodeTypes.COMPOUND_EXPRESSION,
- loc,
- children
- }
- }
- type InferCodegenNodeType<T> = T extends typeof RENDER_SLOT
- ? RenderSlotCall
- : CallExpression
- export function createCallExpression<T extends CallExpression['callee']>(
- callee: T,
- args: CallExpression['arguments'] = [],
- loc: SourceLocation = locStub
- ): InferCodegenNodeType<T> {
- return {
- type: NodeTypes.JS_CALL_EXPRESSION,
- loc,
- callee,
- arguments: args
- } as InferCodegenNodeType<T>
- }
- export function createFunctionExpression(
- params: FunctionExpression['params'],
- returns: FunctionExpression['returns'] = undefined,
- newline: boolean = false,
- isSlot: boolean = false,
- loc: SourceLocation = locStub
- ): FunctionExpression {
- return {
- type: NodeTypes.JS_FUNCTION_EXPRESSION,
- params,
- returns,
- newline,
- isSlot,
- loc
- }
- }
- export function createConditionalExpression(
- test: ConditionalExpression['test'],
- consequent: ConditionalExpression['consequent'],
- alternate: ConditionalExpression['alternate'],
- newline = true
- ): ConditionalExpression {
- return {
- type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
- test,
- consequent,
- alternate,
- newline,
- loc: locStub
- }
- }
- export function createCacheExpression(
- index: number,
- value: JSChildNode,
- isVNode: boolean = false
- ): CacheExpression {
- return {
- type: NodeTypes.JS_CACHE_EXPRESSION,
- index,
- value,
- isVNode,
- loc: locStub
- }
- }
- export function createBlockStatement(
- body: BlockStatement['body']
- ): BlockStatement {
- return {
- type: NodeTypes.JS_BLOCK_STATEMENT,
- body,
- loc: locStub
- }
- }
- export function createTemplateLiteral(
- elements: TemplateLiteral['elements']
- ): TemplateLiteral {
- return {
- type: NodeTypes.JS_TEMPLATE_LITERAL,
- elements,
- loc: locStub
- }
- }
- export function createIfStatement(
- test: IfStatement['test'],
- consequent: IfStatement['consequent'],
- alternate?: IfStatement['alternate']
- ): IfStatement {
- return {
- type: NodeTypes.JS_IF_STATEMENT,
- test,
- consequent,
- alternate,
- loc: locStub
- }
- }
- export function createAssignmentExpression(
- left: AssignmentExpression['left'],
- right: AssignmentExpression['right']
- ): AssignmentExpression {
- return {
- type: NodeTypes.JS_ASSIGNMENT_EXPRESSION,
- left,
- right,
- loc: locStub
- }
- }
- export function createSequenceExpression(
- expressions: SequenceExpression['expressions']
- ): SequenceExpression {
- return {
- type: NodeTypes.JS_SEQUENCE_EXPRESSION,
- expressions,
- loc: locStub
- }
- }
- export function createReturnStatement(
- returns: ReturnStatement['returns']
- ): ReturnStatement {
- return {
- type: NodeTypes.JS_RETURN_STATEMENT,
- returns,
- loc: locStub
- }
- }
|