compile.spec.ts 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. import { baseCompile as compile } from '../src'
  2. import { SourceMapConsumer, RawSourceMap } from 'source-map'
  3. describe('compiler: integration tests', () => {
  4. const source = `
  5. <div id="foo" :class="bar.baz">
  6. {{ world.burn() }}
  7. <div v-if="ok">yes</div>
  8. <template v-else>no</template>
  9. <div v-for="(value, index) in list"><span>{{ value + index }}</span></div>
  10. </div>
  11. `.trim()
  12. interface Pos {
  13. line: number
  14. column: number
  15. name?: string
  16. }
  17. function getPositionInCode(
  18. code: string,
  19. token: string,
  20. expectName: string | boolean = false
  21. ): Pos {
  22. const generatedOffset = code.indexOf(token)
  23. let line = 1
  24. let lastNewLinePos = -1
  25. for (let i = 0; i < generatedOffset; i++) {
  26. if (code.charCodeAt(i) === 10 /* newline char code */) {
  27. line++
  28. lastNewLinePos = i
  29. }
  30. }
  31. const res: Pos = {
  32. line,
  33. column:
  34. lastNewLinePos === -1
  35. ? generatedOffset
  36. : generatedOffset - lastNewLinePos - 1
  37. }
  38. if (expectName) {
  39. res.name = typeof expectName === 'string' ? expectName : token
  40. }
  41. return res
  42. }
  43. test('function mode', async () => {
  44. const { code, map } = compile(source, {
  45. sourceMap: true,
  46. filename: `foo.vue`
  47. })
  48. expect(code).toMatch(
  49. `const { createVNode: _createVNode, toString: _toString, renderList: _renderList } = _Vue`
  50. )
  51. expect(code).toMatchSnapshot()
  52. expect(map!.sources).toEqual([`foo.vue`])
  53. expect(map!.sourcesContent).toEqual([source])
  54. const consumer = await new SourceMapConsumer(map as RawSourceMap)
  55. expect(
  56. consumer.originalPositionFor(getPositionInCode(code, `id`))
  57. ).toMatchObject(getPositionInCode(source, `id`))
  58. expect(
  59. consumer.originalPositionFor(getPositionInCode(code, `"foo"`))
  60. ).toMatchObject(getPositionInCode(source, `"foo"`))
  61. expect(
  62. consumer.originalPositionFor(getPositionInCode(code, `class:`))
  63. ).toMatchObject(getPositionInCode(source, `class=`))
  64. expect(
  65. consumer.originalPositionFor(getPositionInCode(code, `bar`))
  66. ).toMatchObject(getPositionInCode(source, `bar`))
  67. // without prefixIdentifiers: true, identifiers inside compound expressions
  68. // are mapped to closest parent expression.
  69. expect(
  70. consumer.originalPositionFor(getPositionInCode(code, `baz`))
  71. ).toMatchObject(getPositionInCode(source, `bar`))
  72. expect(
  73. consumer.originalPositionFor(getPositionInCode(code, `world`))
  74. ).toMatchObject(getPositionInCode(source, `world`))
  75. // without prefixIdentifiers: true, identifiers inside compound expressions
  76. // are mapped to closest parent expression.
  77. expect(
  78. consumer.originalPositionFor(getPositionInCode(code, `burn()`))
  79. ).toMatchObject(getPositionInCode(source, `world`))
  80. expect(
  81. consumer.originalPositionFor(getPositionInCode(code, `ok`))
  82. ).toMatchObject(getPositionInCode(source, `ok`))
  83. expect(
  84. consumer.originalPositionFor(getPositionInCode(code, `list`))
  85. ).toMatchObject(getPositionInCode(source, `list`))
  86. expect(
  87. consumer.originalPositionFor(getPositionInCode(code, `value`))
  88. ).toMatchObject(getPositionInCode(source, `value`))
  89. expect(
  90. consumer.originalPositionFor(getPositionInCode(code, `index`))
  91. ).toMatchObject(getPositionInCode(source, `index`))
  92. expect(
  93. consumer.originalPositionFor(getPositionInCode(code, `value + index`))
  94. ).toMatchObject(getPositionInCode(source, `value + index`))
  95. })
  96. test('function mode w/ prefixIdentifiers: true', async () => {
  97. const { code, map } = compile(source, {
  98. sourceMap: true,
  99. filename: `foo.vue`,
  100. prefixIdentifiers: true
  101. })
  102. expect(code).toMatch(`const { createVNode, toString, renderList } = Vue`)
  103. expect(code).toMatchSnapshot()
  104. expect(map!.sources).toEqual([`foo.vue`])
  105. expect(map!.sourcesContent).toEqual([source])
  106. const consumer = await new SourceMapConsumer(map as RawSourceMap)
  107. expect(
  108. consumer.originalPositionFor(getPositionInCode(code, `id`))
  109. ).toMatchObject(getPositionInCode(source, `id`))
  110. expect(
  111. consumer.originalPositionFor(getPositionInCode(code, `"foo"`))
  112. ).toMatchObject(getPositionInCode(source, `"foo"`))
  113. expect(
  114. consumer.originalPositionFor(getPositionInCode(code, `class:`))
  115. ).toMatchObject(getPositionInCode(source, `class=`))
  116. expect(
  117. consumer.originalPositionFor(getPositionInCode(code, `bar`))
  118. ).toMatchObject(getPositionInCode(source, `bar`))
  119. expect(
  120. consumer.originalPositionFor(getPositionInCode(code, `_ctx.bar`, `bar`))
  121. ).toMatchObject(getPositionInCode(source, `bar`, true))
  122. expect(
  123. consumer.originalPositionFor(getPositionInCode(code, `baz`))
  124. ).toMatchObject(getPositionInCode(source, `baz`))
  125. expect(
  126. consumer.originalPositionFor(getPositionInCode(code, `world`, true))
  127. ).toMatchObject(getPositionInCode(source, `world`, `world`))
  128. expect(
  129. consumer.originalPositionFor(
  130. getPositionInCode(code, `_ctx.world`, `world`)
  131. )
  132. ).toMatchObject(getPositionInCode(source, `world`, `world`))
  133. expect(
  134. consumer.originalPositionFor(getPositionInCode(code, `burn()`))
  135. ).toMatchObject(getPositionInCode(source, `burn()`))
  136. expect(
  137. consumer.originalPositionFor(getPositionInCode(code, `ok`))
  138. ).toMatchObject(getPositionInCode(source, `ok`))
  139. expect(
  140. consumer.originalPositionFor(getPositionInCode(code, `_ctx.ok`, `ok`))
  141. ).toMatchObject(getPositionInCode(source, `ok`, true))
  142. expect(
  143. consumer.originalPositionFor(getPositionInCode(code, `list`))
  144. ).toMatchObject(getPositionInCode(source, `list`))
  145. expect(
  146. consumer.originalPositionFor(getPositionInCode(code, `_ctx.list`, `list`))
  147. ).toMatchObject(getPositionInCode(source, `list`, true))
  148. expect(
  149. consumer.originalPositionFor(getPositionInCode(code, `value`))
  150. ).toMatchObject(getPositionInCode(source, `value`))
  151. expect(
  152. consumer.originalPositionFor(getPositionInCode(code, `index`))
  153. ).toMatchObject(getPositionInCode(source, `index`))
  154. expect(
  155. consumer.originalPositionFor(getPositionInCode(code, `value + index`))
  156. ).toMatchObject(getPositionInCode(source, `value + index`))
  157. })
  158. test('module mode', async () => {
  159. const { code, map } = compile(source, {
  160. mode: 'module',
  161. sourceMap: true,
  162. filename: `foo.vue`
  163. })
  164. expect(code).toMatch(
  165. `import { createVNode, toString, renderList } from "vue"`
  166. )
  167. expect(code).toMatchSnapshot()
  168. expect(map!.sources).toEqual([`foo.vue`])
  169. expect(map!.sourcesContent).toEqual([source])
  170. const consumer = await new SourceMapConsumer(map as RawSourceMap)
  171. expect(
  172. consumer.originalPositionFor(getPositionInCode(code, `id`))
  173. ).toMatchObject(getPositionInCode(source, `id`))
  174. expect(
  175. consumer.originalPositionFor(getPositionInCode(code, `"foo"`))
  176. ).toMatchObject(getPositionInCode(source, `"foo"`))
  177. expect(
  178. consumer.originalPositionFor(getPositionInCode(code, `class:`))
  179. ).toMatchObject(getPositionInCode(source, `class=`))
  180. expect(
  181. consumer.originalPositionFor(getPositionInCode(code, `bar`))
  182. ).toMatchObject(getPositionInCode(source, `bar`))
  183. expect(
  184. consumer.originalPositionFor(getPositionInCode(code, `_ctx.bar`, `bar`))
  185. ).toMatchObject(getPositionInCode(source, `bar`, true))
  186. expect(
  187. consumer.originalPositionFor(getPositionInCode(code, `baz`))
  188. ).toMatchObject(getPositionInCode(source, `baz`))
  189. expect(
  190. consumer.originalPositionFor(getPositionInCode(code, `world`, true))
  191. ).toMatchObject(getPositionInCode(source, `world`, `world`))
  192. expect(
  193. consumer.originalPositionFor(
  194. getPositionInCode(code, `_ctx.world`, `world`)
  195. )
  196. ).toMatchObject(getPositionInCode(source, `world`, `world`))
  197. expect(
  198. consumer.originalPositionFor(getPositionInCode(code, `burn()`))
  199. ).toMatchObject(getPositionInCode(source, `burn()`))
  200. expect(
  201. consumer.originalPositionFor(getPositionInCode(code, `ok`))
  202. ).toMatchObject(getPositionInCode(source, `ok`))
  203. expect(
  204. consumer.originalPositionFor(getPositionInCode(code, `_ctx.ok`, `ok`))
  205. ).toMatchObject(getPositionInCode(source, `ok`, true))
  206. expect(
  207. consumer.originalPositionFor(getPositionInCode(code, `list`))
  208. ).toMatchObject(getPositionInCode(source, `list`))
  209. expect(
  210. consumer.originalPositionFor(getPositionInCode(code, `_ctx.list`, `list`))
  211. ).toMatchObject(getPositionInCode(source, `list`, true))
  212. expect(
  213. consumer.originalPositionFor(getPositionInCode(code, `value`))
  214. ).toMatchObject(getPositionInCode(source, `value`))
  215. expect(
  216. consumer.originalPositionFor(getPositionInCode(code, `index`))
  217. ).toMatchObject(getPositionInCode(source, `index`))
  218. expect(
  219. consumer.originalPositionFor(getPositionInCode(code, `value + index`))
  220. ).toMatchObject(getPositionInCode(source, `value + index`))
  221. })
  222. })