ast.ts 21 KB

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