ast.ts 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  1. import { isString } from '@vue/shared'
  2. import {
  3. CREATE_BLOCK,
  4. CREATE_ELEMENT_BLOCK,
  5. CREATE_ELEMENT_VNODE,
  6. type CREATE_SLOTS,
  7. CREATE_VNODE,
  8. type FRAGMENT,
  9. OPEN_BLOCK,
  10. type RENDER_LIST,
  11. type RENDER_SLOT,
  12. WITH_DIRECTIVES,
  13. type WITH_MEMO,
  14. } from './runtimeHelpers'
  15. import type { PropsExpression } from './transforms/transformElement'
  16. import type { ImportItem, TransformContext } from './transform'
  17. import type { Node as BabelNode } from '@babel/types'
  18. // Vue template is a platform-agnostic superset of HTML (syntax only).
  19. // More namespaces can be declared by platform specific compilers.
  20. export type Namespace = number
  21. export enum Namespaces {
  22. HTML,
  23. SVG,
  24. MATH_ML,
  25. }
  26. export enum NodeTypes {
  27. ROOT,
  28. ELEMENT,
  29. TEXT,
  30. COMMENT,
  31. SIMPLE_EXPRESSION,
  32. INTERPOLATION,
  33. ATTRIBUTE,
  34. DIRECTIVE,
  35. // containers
  36. COMPOUND_EXPRESSION,
  37. IF,
  38. IF_BRANCH,
  39. FOR,
  40. TEXT_CALL,
  41. // codegen
  42. VNODE_CALL,
  43. JS_CALL_EXPRESSION,
  44. JS_OBJECT_EXPRESSION,
  45. JS_PROPERTY,
  46. JS_ARRAY_EXPRESSION,
  47. JS_FUNCTION_EXPRESSION,
  48. JS_CONDITIONAL_EXPRESSION,
  49. JS_CACHE_EXPRESSION,
  50. // ssr codegen
  51. JS_BLOCK_STATEMENT,
  52. JS_TEMPLATE_LITERAL,
  53. JS_IF_STATEMENT,
  54. JS_ASSIGNMENT_EXPRESSION,
  55. JS_SEQUENCE_EXPRESSION,
  56. JS_RETURN_STATEMENT,
  57. }
  58. export enum ElementTypes {
  59. ELEMENT,
  60. COMPONENT,
  61. SLOT,
  62. TEMPLATE,
  63. }
  64. export interface Node {
  65. type: NodeTypes
  66. loc: SourceLocation
  67. }
  68. // The node's range. The `start` is inclusive and `end` is exclusive.
  69. // [start, end)
  70. export interface SourceLocation {
  71. start: Position
  72. end: Position
  73. source: string
  74. }
  75. export interface Position {
  76. offset: number // from start of file
  77. line: number
  78. column: number
  79. }
  80. export type AllNode =
  81. | ParentNode
  82. | ExpressionNode
  83. | TemplateChildNode
  84. | AttributeNode
  85. | DirectiveNode
  86. export type ParentNode = RootNode | ElementNode | IfBranchNode | ForNode
  87. export type ExpressionNode = SimpleExpressionNode | CompoundExpressionNode
  88. export type TemplateChildNode =
  89. | ElementNode
  90. | InterpolationNode
  91. | CompoundExpressionNode
  92. | TextNode
  93. | CommentNode
  94. | IfNode
  95. | IfBranchNode
  96. | ForNode
  97. | TextCallNode
  98. export interface RootNode extends Node {
  99. type: NodeTypes.ROOT
  100. source: string
  101. children: TemplateChildNode[]
  102. helpers: Set<symbol>
  103. components: string[]
  104. directives: string[]
  105. hoists: (JSChildNode | null)[]
  106. imports: ImportItem[]
  107. cached: number
  108. temps: number
  109. ssrHelpers?: symbol[]
  110. codegenNode?: TemplateChildNode | JSChildNode | BlockStatement
  111. transformed?: boolean
  112. // v2 compat only
  113. filters?: string[]
  114. }
  115. export type ElementNode =
  116. | PlainElementNode
  117. | ComponentNode
  118. | SlotOutletNode
  119. | TemplateNode
  120. export interface BaseElementNode extends Node {
  121. type: NodeTypes.ELEMENT
  122. ns: Namespace
  123. tag: string
  124. tagType: ElementTypes
  125. props: Array<AttributeNode | DirectiveNode>
  126. children: TemplateChildNode[]
  127. isSelfClosing?: boolean
  128. innerLoc?: SourceLocation // only for SFC root level elements
  129. }
  130. export interface PlainElementNode extends BaseElementNode {
  131. tagType: ElementTypes.ELEMENT
  132. codegenNode:
  133. | VNodeCall
  134. | SimpleExpressionNode // when hoisted
  135. | CacheExpression // when cached by v-once
  136. | MemoExpression // when cached by v-memo
  137. | undefined
  138. ssrCodegenNode?: TemplateLiteral
  139. }
  140. export interface ComponentNode extends BaseElementNode {
  141. tagType: ElementTypes.COMPONENT
  142. codegenNode:
  143. | VNodeCall
  144. | CacheExpression // when cached by v-once
  145. | MemoExpression // when cached by v-memo
  146. | undefined
  147. ssrCodegenNode?: CallExpression
  148. }
  149. export interface SlotOutletNode extends BaseElementNode {
  150. tagType: ElementTypes.SLOT
  151. codegenNode:
  152. | RenderSlotCall
  153. | CacheExpression // when cached by v-once
  154. | undefined
  155. ssrCodegenNode?: CallExpression
  156. }
  157. export interface TemplateNode extends BaseElementNode {
  158. tagType: ElementTypes.TEMPLATE
  159. // TemplateNode is a container type that always gets compiled away
  160. codegenNode: undefined
  161. }
  162. export interface TextNode extends Node {
  163. type: NodeTypes.TEXT
  164. content: string
  165. }
  166. export interface CommentNode extends Node {
  167. type: NodeTypes.COMMENT
  168. content: string
  169. }
  170. export interface AttributeNode extends Node {
  171. type: NodeTypes.ATTRIBUTE
  172. name: string
  173. nameLoc: SourceLocation
  174. value: TextNode | undefined
  175. }
  176. export interface DirectiveNode extends Node {
  177. type: NodeTypes.DIRECTIVE
  178. /**
  179. * the normalized name without prefix or shorthands, e.g. "bind", "on"
  180. */
  181. name: string
  182. /**
  183. * the raw attribute name, preserving shorthand, and including arg & modifiers
  184. * this is only used during parse.
  185. */
  186. rawName?: string
  187. exp: ExpressionNode | undefined
  188. arg: ExpressionNode | undefined
  189. modifiers: string[]
  190. /**
  191. * optional property to cache the expression parse result for v-for
  192. */
  193. forParseResult?: ForParseResult
  194. }
  195. /**
  196. * Static types have several levels.
  197. * Higher levels implies lower levels. e.g. a node that can be stringified
  198. * can always be hoisted and skipped for patch.
  199. */
  200. export enum ConstantTypes {
  201. NOT_CONSTANT = 0,
  202. CAN_SKIP_PATCH,
  203. CAN_HOIST,
  204. CAN_STRINGIFY,
  205. }
  206. export interface SimpleExpressionNode extends Node {
  207. type: NodeTypes.SIMPLE_EXPRESSION
  208. content: string
  209. isStatic: boolean
  210. constType: ConstantTypes
  211. /**
  212. * - `null` means the expression is a simple identifier that doesn't need
  213. * parsing
  214. * - `false` means there was a parsing error
  215. */
  216. ast?: BabelNode | null | false
  217. /**
  218. * Indicates this is an identifier for a hoist vnode call and points to the
  219. * hoisted node.
  220. */
  221. hoisted?: JSChildNode
  222. /**
  223. * an expression parsed as the params of a function will track
  224. * the identifiers declared inside the function body.
  225. */
  226. identifiers?: string[]
  227. isHandlerKey?: boolean
  228. }
  229. export interface InterpolationNode extends Node {
  230. type: NodeTypes.INTERPOLATION
  231. content: ExpressionNode
  232. }
  233. export interface CompoundExpressionNode extends Node {
  234. type: NodeTypes.COMPOUND_EXPRESSION
  235. /**
  236. * - `null` means the expression is a simple identifier that doesn't need
  237. * parsing
  238. * - `false` means there was a parsing error
  239. */
  240. ast?: BabelNode | null | false
  241. children: (
  242. | SimpleExpressionNode
  243. | CompoundExpressionNode
  244. | InterpolationNode
  245. | TextNode
  246. | string
  247. | symbol
  248. )[]
  249. /**
  250. * an expression parsed as the params of a function will track
  251. * the identifiers declared inside the function body.
  252. */
  253. identifiers?: string[]
  254. isHandlerKey?: boolean
  255. }
  256. export interface IfNode extends Node {
  257. type: NodeTypes.IF
  258. branches: IfBranchNode[]
  259. codegenNode?: IfConditionalExpression | CacheExpression // <div v-if v-once>
  260. }
  261. export interface IfBranchNode extends Node {
  262. type: NodeTypes.IF_BRANCH
  263. condition: ExpressionNode | undefined // else
  264. children: TemplateChildNode[]
  265. userKey?: AttributeNode | DirectiveNode
  266. isTemplateIf?: boolean
  267. }
  268. export interface ForNode extends Node {
  269. type: NodeTypes.FOR
  270. source: ExpressionNode
  271. valueAlias: ExpressionNode | undefined
  272. keyAlias: ExpressionNode | undefined
  273. objectIndexAlias: ExpressionNode | undefined
  274. parseResult: ForParseResult
  275. children: TemplateChildNode[]
  276. codegenNode?: ForCodegenNode
  277. }
  278. export interface ForParseResult {
  279. source: ExpressionNode
  280. value: ExpressionNode | undefined
  281. key: ExpressionNode | undefined
  282. index: ExpressionNode | undefined
  283. finalized: boolean
  284. }
  285. export interface TextCallNode extends Node {
  286. type: NodeTypes.TEXT_CALL
  287. content: TextNode | InterpolationNode | CompoundExpressionNode
  288. codegenNode: CallExpression | SimpleExpressionNode // when hoisted
  289. }
  290. export type TemplateTextChildNode =
  291. | TextNode
  292. | InterpolationNode
  293. | CompoundExpressionNode
  294. export interface VNodeCall extends Node {
  295. type: NodeTypes.VNODE_CALL
  296. tag: string | symbol | CallExpression
  297. props: PropsExpression | undefined
  298. children:
  299. | TemplateChildNode[] // multiple children
  300. | TemplateTextChildNode // single text child
  301. | SlotsExpression // component slots
  302. | ForRenderListExpression // v-for fragment call
  303. | SimpleExpressionNode // hoisted
  304. | undefined
  305. patchFlag: string | undefined
  306. dynamicProps: string | SimpleExpressionNode | undefined
  307. directives: DirectiveArguments | undefined
  308. isBlock: boolean
  309. disableTracking: boolean
  310. isComponent: boolean
  311. }
  312. // JS Node Types ---------------------------------------------------------------
  313. // We also include a number of JavaScript AST nodes for code generation.
  314. // The AST is an intentionally minimal subset just to meet the exact needs of
  315. // Vue render function generation.
  316. export type JSChildNode =
  317. | VNodeCall
  318. | CallExpression
  319. | ObjectExpression
  320. | ArrayExpression
  321. | ExpressionNode
  322. | FunctionExpression
  323. | ConditionalExpression
  324. | CacheExpression
  325. | AssignmentExpression
  326. | SequenceExpression
  327. export interface CallExpression extends Node {
  328. type: NodeTypes.JS_CALL_EXPRESSION
  329. callee: string | symbol
  330. arguments: (
  331. | string
  332. | symbol
  333. | JSChildNode
  334. | SSRCodegenNode
  335. | TemplateChildNode
  336. | TemplateChildNode[]
  337. )[]
  338. }
  339. export interface ObjectExpression extends Node {
  340. type: NodeTypes.JS_OBJECT_EXPRESSION
  341. properties: Array<Property>
  342. }
  343. export interface Property extends Node {
  344. type: NodeTypes.JS_PROPERTY
  345. key: ExpressionNode
  346. value: JSChildNode
  347. }
  348. export interface ArrayExpression extends Node {
  349. type: NodeTypes.JS_ARRAY_EXPRESSION
  350. elements: Array<string | Node>
  351. }
  352. export interface FunctionExpression extends Node {
  353. type: NodeTypes.JS_FUNCTION_EXPRESSION
  354. params: ExpressionNode | string | (ExpressionNode | string)[] | undefined
  355. returns?: TemplateChildNode | TemplateChildNode[] | JSChildNode
  356. body?: BlockStatement | IfStatement
  357. newline: boolean
  358. /**
  359. * This flag is for codegen to determine whether it needs to generate the
  360. * withScopeId() wrapper
  361. */
  362. isSlot: boolean
  363. /**
  364. * __COMPAT__ only, indicates a slot function that should be excluded from
  365. * the legacy $scopedSlots instance property.
  366. */
  367. isNonScopedSlot?: boolean
  368. }
  369. export interface ConditionalExpression extends Node {
  370. type: NodeTypes.JS_CONDITIONAL_EXPRESSION
  371. test: JSChildNode
  372. consequent: JSChildNode
  373. alternate: JSChildNode
  374. newline: boolean
  375. }
  376. export interface CacheExpression extends Node {
  377. type: NodeTypes.JS_CACHE_EXPRESSION
  378. index: number
  379. value: JSChildNode
  380. isVNode: boolean
  381. }
  382. export interface MemoExpression extends CallExpression {
  383. callee: typeof WITH_MEMO
  384. arguments: [ExpressionNode, MemoFactory, string, string]
  385. }
  386. interface MemoFactory extends FunctionExpression {
  387. returns: BlockCodegenNode
  388. }
  389. // SSR-specific Node Types -----------------------------------------------------
  390. export type SSRCodegenNode =
  391. | BlockStatement
  392. | TemplateLiteral
  393. | IfStatement
  394. | AssignmentExpression
  395. | ReturnStatement
  396. | SequenceExpression
  397. export interface BlockStatement extends Node {
  398. type: NodeTypes.JS_BLOCK_STATEMENT
  399. body: (JSChildNode | IfStatement)[]
  400. }
  401. export interface TemplateLiteral extends Node {
  402. type: NodeTypes.JS_TEMPLATE_LITERAL
  403. elements: (string | JSChildNode)[]
  404. }
  405. export interface IfStatement extends Node {
  406. type: NodeTypes.JS_IF_STATEMENT
  407. test: ExpressionNode
  408. consequent: BlockStatement
  409. alternate: IfStatement | BlockStatement | ReturnStatement | undefined
  410. }
  411. export interface AssignmentExpression extends Node {
  412. type: NodeTypes.JS_ASSIGNMENT_EXPRESSION
  413. left: SimpleExpressionNode
  414. right: JSChildNode
  415. }
  416. export interface SequenceExpression extends Node {
  417. type: NodeTypes.JS_SEQUENCE_EXPRESSION
  418. expressions: JSChildNode[]
  419. }
  420. export interface ReturnStatement extends Node {
  421. type: NodeTypes.JS_RETURN_STATEMENT
  422. returns: TemplateChildNode | TemplateChildNode[] | JSChildNode
  423. }
  424. // Codegen Node Types ----------------------------------------------------------
  425. export interface DirectiveArguments extends ArrayExpression {
  426. elements: DirectiveArgumentNode[]
  427. }
  428. export interface DirectiveArgumentNode extends ArrayExpression {
  429. elements: // dir, exp, arg, modifiers
  430. | [string]
  431. | [string, ExpressionNode]
  432. | [string, ExpressionNode, ExpressionNode]
  433. | [string, ExpressionNode, ExpressionNode, ObjectExpression]
  434. }
  435. // renderSlot(...)
  436. export interface RenderSlotCall extends CallExpression {
  437. callee: typeof RENDER_SLOT
  438. arguments: // $slots, name, props, fallback
  439. | [string, string | ExpressionNode]
  440. | [string, string | ExpressionNode, PropsExpression]
  441. | [
  442. string,
  443. string | ExpressionNode,
  444. PropsExpression | '{}',
  445. TemplateChildNode[],
  446. ]
  447. }
  448. export type SlotsExpression = SlotsObjectExpression | DynamicSlotsExpression
  449. // { foo: () => [...] }
  450. export interface SlotsObjectExpression extends ObjectExpression {
  451. properties: SlotsObjectProperty[]
  452. }
  453. export interface SlotsObjectProperty extends Property {
  454. value: SlotFunctionExpression
  455. }
  456. export interface SlotFunctionExpression extends FunctionExpression {
  457. returns: TemplateChildNode[]
  458. }
  459. // createSlots({ ... }, [
  460. // foo ? () => [] : undefined,
  461. // renderList(list, i => () => [i])
  462. // ])
  463. export interface DynamicSlotsExpression extends CallExpression {
  464. callee: typeof CREATE_SLOTS
  465. arguments: [SlotsObjectExpression, DynamicSlotEntries]
  466. }
  467. export interface DynamicSlotEntries extends ArrayExpression {
  468. elements: (ConditionalDynamicSlotNode | ListDynamicSlotNode)[]
  469. }
  470. export interface ConditionalDynamicSlotNode extends ConditionalExpression {
  471. consequent: DynamicSlotNode
  472. alternate: DynamicSlotNode | SimpleExpressionNode
  473. }
  474. export interface ListDynamicSlotNode extends CallExpression {
  475. callee: typeof RENDER_LIST
  476. arguments: [ExpressionNode, ListDynamicSlotIterator]
  477. }
  478. export interface ListDynamicSlotIterator extends FunctionExpression {
  479. returns: DynamicSlotNode
  480. }
  481. export interface DynamicSlotNode extends ObjectExpression {
  482. properties: [Property, DynamicSlotFnProperty]
  483. }
  484. export interface DynamicSlotFnProperty extends Property {
  485. value: SlotFunctionExpression
  486. }
  487. export type BlockCodegenNode = VNodeCall | RenderSlotCall
  488. export interface IfConditionalExpression extends ConditionalExpression {
  489. consequent: BlockCodegenNode | MemoExpression
  490. alternate: BlockCodegenNode | IfConditionalExpression | MemoExpression
  491. }
  492. export interface ForCodegenNode extends VNodeCall {
  493. isBlock: true
  494. tag: typeof FRAGMENT
  495. props: undefined
  496. children: ForRenderListExpression
  497. patchFlag: string
  498. disableTracking: boolean
  499. }
  500. export interface ForRenderListExpression extends CallExpression {
  501. callee: typeof RENDER_LIST
  502. arguments: [ExpressionNode, ForIteratorExpression]
  503. }
  504. export interface ForIteratorExpression extends FunctionExpression {
  505. returns: BlockCodegenNode
  506. }
  507. // AST Utilities ---------------------------------------------------------------
  508. // Some expressions, e.g. sequence and conditional expressions, are never
  509. // associated with template nodes, so their source locations are just a stub.
  510. // Container types like CompoundExpression also don't need a real location.
  511. export const locStub: SourceLocation = {
  512. start: { line: 1, column: 1, offset: 0 },
  513. end: { line: 1, column: 1, offset: 0 },
  514. source: '',
  515. }
  516. export function createRoot(
  517. children: TemplateChildNode[],
  518. source = '',
  519. ): RootNode {
  520. return {
  521. type: NodeTypes.ROOT,
  522. source,
  523. children,
  524. helpers: new Set(),
  525. components: [],
  526. directives: [],
  527. hoists: [],
  528. imports: [],
  529. cached: 0,
  530. temps: 0,
  531. codegenNode: undefined,
  532. loc: locStub,
  533. }
  534. }
  535. export function createVNodeCall(
  536. context: TransformContext | null,
  537. tag: VNodeCall['tag'],
  538. props?: VNodeCall['props'],
  539. children?: VNodeCall['children'],
  540. patchFlag?: VNodeCall['patchFlag'],
  541. dynamicProps?: VNodeCall['dynamicProps'],
  542. directives?: VNodeCall['directives'],
  543. isBlock: VNodeCall['isBlock'] = false,
  544. disableTracking: VNodeCall['disableTracking'] = false,
  545. isComponent: VNodeCall['isComponent'] = false,
  546. loc = locStub,
  547. ): VNodeCall {
  548. if (context) {
  549. if (isBlock) {
  550. context.helper(OPEN_BLOCK)
  551. context.helper(getVNodeBlockHelper(context.inSSR, isComponent))
  552. } else {
  553. context.helper(getVNodeHelper(context.inSSR, isComponent))
  554. }
  555. if (directives) {
  556. context.helper(WITH_DIRECTIVES)
  557. }
  558. }
  559. return {
  560. type: NodeTypes.VNODE_CALL,
  561. tag,
  562. props,
  563. children,
  564. patchFlag,
  565. dynamicProps,
  566. directives,
  567. isBlock,
  568. disableTracking,
  569. isComponent,
  570. loc,
  571. }
  572. }
  573. export function createArrayExpression(
  574. elements: ArrayExpression['elements'],
  575. loc: SourceLocation = locStub,
  576. ): ArrayExpression {
  577. return {
  578. type: NodeTypes.JS_ARRAY_EXPRESSION,
  579. loc,
  580. elements,
  581. }
  582. }
  583. export function createObjectExpression(
  584. properties: ObjectExpression['properties'],
  585. loc: SourceLocation = locStub,
  586. ): ObjectExpression {
  587. return {
  588. type: NodeTypes.JS_OBJECT_EXPRESSION,
  589. loc,
  590. properties,
  591. }
  592. }
  593. export function createObjectProperty(
  594. key: Property['key'] | string,
  595. value: Property['value'],
  596. ): Property {
  597. return {
  598. type: NodeTypes.JS_PROPERTY,
  599. loc: locStub,
  600. key: isString(key) ? createSimpleExpression(key, true) : key,
  601. value,
  602. }
  603. }
  604. export function createSimpleExpression(
  605. content: SimpleExpressionNode['content'],
  606. isStatic: SimpleExpressionNode['isStatic'] = false,
  607. loc: SourceLocation = locStub,
  608. constType: ConstantTypes = ConstantTypes.NOT_CONSTANT,
  609. ): SimpleExpressionNode {
  610. return {
  611. type: NodeTypes.SIMPLE_EXPRESSION,
  612. loc,
  613. content,
  614. isStatic,
  615. constType: isStatic ? ConstantTypes.CAN_STRINGIFY : constType,
  616. }
  617. }
  618. export function createInterpolation(
  619. content: InterpolationNode['content'] | string,
  620. loc: SourceLocation,
  621. ): InterpolationNode {
  622. return {
  623. type: NodeTypes.INTERPOLATION,
  624. loc,
  625. content: isString(content)
  626. ? createSimpleExpression(content, false, loc)
  627. : content,
  628. }
  629. }
  630. export function createCompoundExpression(
  631. children: CompoundExpressionNode['children'],
  632. loc: SourceLocation = locStub,
  633. ): CompoundExpressionNode {
  634. return {
  635. type: NodeTypes.COMPOUND_EXPRESSION,
  636. loc,
  637. children,
  638. }
  639. }
  640. type InferCodegenNodeType<T> = T extends typeof RENDER_SLOT
  641. ? RenderSlotCall
  642. : CallExpression
  643. export function createCallExpression<T extends CallExpression['callee']>(
  644. callee: T,
  645. args: CallExpression['arguments'] = [],
  646. loc: SourceLocation = locStub,
  647. ): InferCodegenNodeType<T> {
  648. return {
  649. type: NodeTypes.JS_CALL_EXPRESSION,
  650. loc,
  651. callee,
  652. arguments: args,
  653. } as InferCodegenNodeType<T>
  654. }
  655. export function createFunctionExpression(
  656. params: FunctionExpression['params'],
  657. returns: FunctionExpression['returns'] = undefined,
  658. newline: boolean = false,
  659. isSlot: boolean = false,
  660. loc: SourceLocation = locStub,
  661. ): FunctionExpression {
  662. return {
  663. type: NodeTypes.JS_FUNCTION_EXPRESSION,
  664. params,
  665. returns,
  666. newline,
  667. isSlot,
  668. loc,
  669. }
  670. }
  671. export function createConditionalExpression(
  672. test: ConditionalExpression['test'],
  673. consequent: ConditionalExpression['consequent'],
  674. alternate: ConditionalExpression['alternate'],
  675. newline = true,
  676. ): ConditionalExpression {
  677. return {
  678. type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
  679. test,
  680. consequent,
  681. alternate,
  682. newline,
  683. loc: locStub,
  684. }
  685. }
  686. export function createCacheExpression(
  687. index: number,
  688. value: JSChildNode,
  689. isVNode: boolean = false,
  690. ): CacheExpression {
  691. return {
  692. type: NodeTypes.JS_CACHE_EXPRESSION,
  693. index,
  694. value,
  695. isVNode,
  696. loc: locStub,
  697. }
  698. }
  699. export function createBlockStatement(
  700. body: BlockStatement['body'],
  701. ): BlockStatement {
  702. return {
  703. type: NodeTypes.JS_BLOCK_STATEMENT,
  704. body,
  705. loc: locStub,
  706. }
  707. }
  708. export function createTemplateLiteral(
  709. elements: TemplateLiteral['elements'],
  710. ): TemplateLiteral {
  711. return {
  712. type: NodeTypes.JS_TEMPLATE_LITERAL,
  713. elements,
  714. loc: locStub,
  715. }
  716. }
  717. export function createIfStatement(
  718. test: IfStatement['test'],
  719. consequent: IfStatement['consequent'],
  720. alternate?: IfStatement['alternate'],
  721. ): IfStatement {
  722. return {
  723. type: NodeTypes.JS_IF_STATEMENT,
  724. test,
  725. consequent,
  726. alternate,
  727. loc: locStub,
  728. }
  729. }
  730. export function createAssignmentExpression(
  731. left: AssignmentExpression['left'],
  732. right: AssignmentExpression['right'],
  733. ): AssignmentExpression {
  734. return {
  735. type: NodeTypes.JS_ASSIGNMENT_EXPRESSION,
  736. left,
  737. right,
  738. loc: locStub,
  739. }
  740. }
  741. export function createSequenceExpression(
  742. expressions: SequenceExpression['expressions'],
  743. ): SequenceExpression {
  744. return {
  745. type: NodeTypes.JS_SEQUENCE_EXPRESSION,
  746. expressions,
  747. loc: locStub,
  748. }
  749. }
  750. export function createReturnStatement(
  751. returns: ReturnStatement['returns'],
  752. ): ReturnStatement {
  753. return {
  754. type: NodeTypes.JS_RETURN_STATEMENT,
  755. returns,
  756. loc: locStub,
  757. }
  758. }
  759. export function getVNodeHelper(ssr: boolean, isComponent: boolean) {
  760. return ssr || isComponent ? CREATE_VNODE : CREATE_ELEMENT_VNODE
  761. }
  762. export function getVNodeBlockHelper(ssr: boolean, isComponent: boolean) {
  763. return ssr || isComponent ? CREATE_BLOCK : CREATE_ELEMENT_BLOCK
  764. }
  765. export function convertToBlock(
  766. node: VNodeCall,
  767. { helper, removeHelper, inSSR }: TransformContext,
  768. ) {
  769. if (!node.isBlock) {
  770. node.isBlock = true
  771. removeHelper(getVNodeHelper(inSSR, node.isComponent))
  772. helper(OPEN_BLOCK)
  773. helper(getVNodeBlockHelper(inSSR, node.isComponent))
  774. }
  775. }