codegen.spec.ts 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. import {
  2. locStub,
  3. generate,
  4. NodeTypes,
  5. RootNode,
  6. createSimpleExpression,
  7. createObjectExpression,
  8. createObjectProperty,
  9. createArrayExpression,
  10. createCompoundExpression,
  11. createInterpolation,
  12. createSequenceExpression,
  13. createCallExpression,
  14. createConditionalExpression
  15. } from '../src'
  16. import { CREATE_VNODE, COMMENT, TO_STRING } from '../src/runtimeConstants'
  17. import { createElementWithCodegen } from './testUtils'
  18. function createRoot(options: Partial<RootNode> = {}): RootNode {
  19. return {
  20. type: NodeTypes.ROOT,
  21. children: [],
  22. imports: [],
  23. statements: [],
  24. hoists: [],
  25. codegenNode: undefined,
  26. loc: locStub,
  27. ...options
  28. }
  29. }
  30. describe('compiler: codegen', () => {
  31. test('module mode preamble', () => {
  32. const root = createRoot({
  33. imports: [`helperOne`, `helperTwo`]
  34. })
  35. const { code } = generate(root, { mode: 'module' })
  36. expect(code).toMatch(`import { helperOne, helperTwo } from "vue"`)
  37. expect(code).toMatchSnapshot()
  38. })
  39. test('function mode preamble', () => {
  40. const root = createRoot({
  41. imports: [`helperOne`, `helperTwo`]
  42. })
  43. const { code } = generate(root, { mode: 'function' })
  44. expect(code).toMatch(`const _Vue = Vue`)
  45. expect(code).toMatch(
  46. `const { helperOne: _helperOne, helperTwo: _helperTwo } = _Vue`
  47. )
  48. expect(code).toMatchSnapshot()
  49. })
  50. test('function mode preamble w/ prefixIdentifiers: true', () => {
  51. const root = createRoot({
  52. imports: [`helperOne`, `helperTwo`]
  53. })
  54. const { code } = generate(root, {
  55. mode: 'function',
  56. prefixIdentifiers: true
  57. })
  58. expect(code).not.toMatch(`const _Vue = Vue`)
  59. expect(code).toMatch(`const { helperOne, helperTwo } = Vue`)
  60. expect(code).toMatchSnapshot()
  61. })
  62. test('statements', () => {
  63. const root = createRoot({
  64. statements: [`const a = 1`, `const b = 2`]
  65. })
  66. const { code } = generate(root, { mode: 'function' })
  67. expect(code).toMatch(`const a = 1\n`)
  68. expect(code).toMatch(`const b = 2\n`)
  69. expect(code).toMatchSnapshot()
  70. })
  71. test('hoists', () => {
  72. const root = createRoot({
  73. hoists: [
  74. createSimpleExpression(`hello`, false, locStub),
  75. createObjectExpression(
  76. [
  77. createObjectProperty(
  78. createSimpleExpression(`id`, true, locStub),
  79. createSimpleExpression(`foo`, true, locStub)
  80. )
  81. ],
  82. locStub
  83. )
  84. ]
  85. })
  86. const { code } = generate(root)
  87. expect(code).toMatch(`const _hoisted_1 = hello`)
  88. expect(code).toMatch(`const _hoisted_2 = { id: "foo" }`)
  89. expect(code).toMatchSnapshot()
  90. })
  91. test('prefixIdentifiers: true should inject _ctx statement', () => {
  92. const { code } = generate(createRoot(), { prefixIdentifiers: true })
  93. expect(code).toMatch(`const _ctx = this\n`)
  94. expect(code).toMatchSnapshot()
  95. })
  96. test('static text', () => {
  97. const { code } = generate(
  98. createRoot({
  99. codegenNode: {
  100. type: NodeTypes.TEXT,
  101. content: 'hello',
  102. isEmpty: false,
  103. loc: locStub
  104. }
  105. })
  106. )
  107. expect(code).toMatch(`return "hello"`)
  108. expect(code).toMatchSnapshot()
  109. })
  110. test('interpolation', () => {
  111. const { code } = generate(
  112. createRoot({
  113. codegenNode: createInterpolation(`hello`, locStub)
  114. })
  115. )
  116. expect(code).toMatch(`return _${TO_STRING}(hello)`)
  117. expect(code).toMatchSnapshot()
  118. })
  119. test('comment', () => {
  120. const { code } = generate(
  121. createRoot({
  122. codegenNode: {
  123. type: NodeTypes.COMMENT,
  124. content: 'foo',
  125. loc: locStub
  126. }
  127. })
  128. )
  129. expect(code).toMatch(`return _${CREATE_VNODE}(_${COMMENT}, 0, "foo")`)
  130. expect(code).toMatchSnapshot()
  131. })
  132. test('compound expression', () => {
  133. const { code } = generate(
  134. createRoot({
  135. codegenNode: createCompoundExpression([
  136. `_ctx.`,
  137. createSimpleExpression(`foo`, false, locStub),
  138. ` + `,
  139. {
  140. type: NodeTypes.INTERPOLATION,
  141. loc: locStub,
  142. content: createSimpleExpression(`bar`, false, locStub)
  143. }
  144. ])
  145. })
  146. )
  147. expect(code).toMatch(`return _ctx.foo + _${TO_STRING}(bar)`)
  148. expect(code).toMatchSnapshot()
  149. })
  150. test('ifNode', () => {
  151. const { code } = generate(
  152. createRoot({
  153. codegenNode: {
  154. type: NodeTypes.IF,
  155. loc: locStub,
  156. branches: [],
  157. codegenNode: createSequenceExpression([
  158. createSimpleExpression('foo', false),
  159. createSimpleExpression('bar', false)
  160. ])
  161. }
  162. })
  163. )
  164. expect(code).toMatch(`return (foo, bar)`)
  165. expect(code).toMatchSnapshot()
  166. })
  167. test('forNode', () => {
  168. const { code } = generate(
  169. createRoot({
  170. codegenNode: {
  171. type: NodeTypes.FOR,
  172. loc: locStub,
  173. source: createSimpleExpression('foo', false),
  174. valueAlias: undefined,
  175. keyAlias: undefined,
  176. objectIndexAlias: undefined,
  177. children: [],
  178. codegenNode: createSequenceExpression([
  179. createSimpleExpression('foo', false),
  180. createSimpleExpression('bar', false)
  181. ])
  182. }
  183. })
  184. )
  185. expect(code).toMatch(`return (foo, bar)`)
  186. expect(code).toMatchSnapshot()
  187. })
  188. test('Element (callExpression + objectExpression + arrayExpression)', () => {
  189. const { code } = generate(
  190. createRoot({
  191. codegenNode: createElementWithCodegen([
  192. // string
  193. `"div"`,
  194. // ObjectExpression
  195. createObjectExpression(
  196. [
  197. createObjectProperty(
  198. createSimpleExpression(`id`, true, locStub),
  199. createSimpleExpression(`foo`, true, locStub)
  200. ),
  201. createObjectProperty(
  202. createSimpleExpression(`prop`, false, locStub),
  203. createSimpleExpression(`bar`, false, locStub)
  204. ),
  205. // compound expression as computed key
  206. createObjectProperty(
  207. {
  208. type: NodeTypes.COMPOUND_EXPRESSION,
  209. loc: locStub,
  210. children: [
  211. `foo + `,
  212. createSimpleExpression(`bar`, false, locStub)
  213. ]
  214. },
  215. createSimpleExpression(`bar`, false, locStub)
  216. )
  217. ],
  218. locStub
  219. ),
  220. // ChildNode[]
  221. [
  222. createElementWithCodegen([
  223. `"p"`,
  224. createObjectExpression(
  225. [
  226. createObjectProperty(
  227. // should quote the key!
  228. createSimpleExpression(`some-key`, true, locStub),
  229. createSimpleExpression(`foo`, true, locStub)
  230. )
  231. ],
  232. locStub
  233. )
  234. ])
  235. ],
  236. // ArrayExpression
  237. createArrayExpression(
  238. [
  239. 'foo',
  240. {
  241. type: NodeTypes.JS_CALL_EXPRESSION,
  242. loc: locStub,
  243. callee: CREATE_VNODE,
  244. arguments: [`"p"`]
  245. }
  246. ],
  247. locStub
  248. )
  249. ])
  250. })
  251. )
  252. expect(code).toMatch(`
  253. return ${CREATE_VNODE}("div", {
  254. id: "foo",
  255. [prop]: bar,
  256. [foo + bar]: bar
  257. }, [
  258. ${CREATE_VNODE}("p", { "some-key": "foo" })
  259. ], [
  260. foo,
  261. ${CREATE_VNODE}("p")
  262. ])`)
  263. expect(code).toMatchSnapshot()
  264. })
  265. test('SequenceExpression', () => {
  266. const { code } = generate(
  267. createRoot({
  268. codegenNode: createSequenceExpression([
  269. createSimpleExpression(`foo`, false),
  270. createCallExpression(`bar`, [`baz`])
  271. ])
  272. })
  273. )
  274. expect(code).toMatch(`return (foo, bar(baz))`)
  275. expect(code).toMatchSnapshot()
  276. })
  277. test('ConditionalExpression', () => {
  278. const { code } = generate(
  279. createRoot({
  280. codegenNode: createConditionalExpression(
  281. createSimpleExpression(`ok`, false),
  282. createCallExpression(`foo`),
  283. createConditionalExpression(
  284. createSimpleExpression(`orNot`, false),
  285. createCallExpression(`bar`),
  286. createCallExpression(`baz`)
  287. )
  288. )
  289. })
  290. )
  291. expect(code).toMatch(
  292. `return ok
  293. ? foo()
  294. : orNot
  295. ? bar()
  296. : baz()`
  297. )
  298. expect(code).toMatchSnapshot()
  299. })
  300. })