compile.spec.ts 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. import { baseCompile as compile } from '../src'
  2. import { type RawSourceMap, SourceMapConsumer } from 'source-map-js'
  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', () => {
  44. const { code, map } = compile(source, {
  45. sourceMap: true,
  46. filename: `foo.vue`,
  47. })
  48. expect(code).toMatchSnapshot()
  49. expect(map!.sources).toEqual([`foo.vue`])
  50. expect(map!.sourcesContent).toEqual([source])
  51. const consumer = new SourceMapConsumer(map as RawSourceMap)
  52. expect(
  53. consumer.originalPositionFor(getPositionInCode(code, `id`)),
  54. ).toMatchObject(getPositionInCode(source, `id`))
  55. expect(
  56. consumer.originalPositionFor(getPositionInCode(code, `"foo"`)),
  57. ).toMatchObject(getPositionInCode(source, `"foo"`))
  58. expect(
  59. consumer.originalPositionFor(getPositionInCode(code, `class:`)),
  60. ).toMatchObject(getPositionInCode(source, `class=`))
  61. expect(
  62. consumer.originalPositionFor(getPositionInCode(code, `bar`)),
  63. ).toMatchObject(getPositionInCode(source, `bar`))
  64. // without prefixIdentifiers: true, identifiers inside compound expressions
  65. // are mapped to closest parent expression.
  66. expect(
  67. consumer.originalPositionFor(getPositionInCode(code, `baz`)),
  68. ).toMatchObject(getPositionInCode(source, `bar`))
  69. expect(
  70. consumer.originalPositionFor(getPositionInCode(code, `world`)),
  71. ).toMatchObject(getPositionInCode(source, `world`))
  72. // without prefixIdentifiers: true, identifiers inside compound expressions
  73. // are mapped to closest parent expression.
  74. expect(
  75. consumer.originalPositionFor(getPositionInCode(code, `burn()`)),
  76. ).toMatchObject(getPositionInCode(source, `world`))
  77. expect(
  78. consumer.originalPositionFor(getPositionInCode(code, `ok`)),
  79. ).toMatchObject(getPositionInCode(source, `ok`))
  80. expect(
  81. consumer.originalPositionFor(getPositionInCode(code, `list`)),
  82. ).toMatchObject(getPositionInCode(source, `list`))
  83. expect(
  84. consumer.originalPositionFor(getPositionInCode(code, `value`)),
  85. ).toMatchObject(getPositionInCode(source, `value`))
  86. expect(
  87. consumer.originalPositionFor(getPositionInCode(code, `index`)),
  88. ).toMatchObject(getPositionInCode(source, `index`))
  89. expect(
  90. consumer.originalPositionFor(getPositionInCode(code, `value + index`)),
  91. ).toMatchObject(getPositionInCode(source, `value + index`))
  92. })
  93. test('function mode w/ prefixIdentifiers: true', () => {
  94. const { code, map } = compile(source, {
  95. sourceMap: true,
  96. filename: `foo.vue`,
  97. prefixIdentifiers: true,
  98. })
  99. expect(code).toMatchSnapshot()
  100. expect(map!.sources).toEqual([`foo.vue`])
  101. expect(map!.sourcesContent).toEqual([source])
  102. const consumer = new SourceMapConsumer(map as RawSourceMap)
  103. expect(
  104. consumer.originalPositionFor(getPositionInCode(code, `id`)),
  105. ).toMatchObject(getPositionInCode(source, `id`))
  106. expect(
  107. consumer.originalPositionFor(getPositionInCode(code, `"foo"`)),
  108. ).toMatchObject(getPositionInCode(source, `"foo"`))
  109. expect(
  110. consumer.originalPositionFor(getPositionInCode(code, `class:`)),
  111. ).toMatchObject(getPositionInCode(source, `class=`))
  112. expect(
  113. consumer.originalPositionFor(getPositionInCode(code, `bar`)),
  114. ).toMatchObject(getPositionInCode(source, `bar`))
  115. expect(
  116. consumer.originalPositionFor(getPositionInCode(code, `_ctx.bar`, `bar`)),
  117. ).toMatchObject(getPositionInCode(source, `bar`, true))
  118. expect(
  119. consumer.originalPositionFor(getPositionInCode(code, `baz`)),
  120. ).toMatchObject(getPositionInCode(source, `baz`))
  121. expect(
  122. consumer.originalPositionFor(getPositionInCode(code, `world`, true)),
  123. ).toMatchObject(getPositionInCode(source, `world`, `world`))
  124. expect(
  125. consumer.originalPositionFor(
  126. getPositionInCode(code, `_ctx.world`, `world`),
  127. ),
  128. ).toMatchObject(getPositionInCode(source, `world`, `world`))
  129. expect(
  130. consumer.originalPositionFor(getPositionInCode(code, `burn()`)),
  131. ).toMatchObject(getPositionInCode(source, `burn()`))
  132. expect(
  133. consumer.originalPositionFor(getPositionInCode(code, `ok`)),
  134. ).toMatchObject(getPositionInCode(source, `ok`))
  135. expect(
  136. consumer.originalPositionFor(getPositionInCode(code, `_ctx.ok`, `ok`)),
  137. ).toMatchObject(getPositionInCode(source, `ok`, true))
  138. expect(
  139. consumer.originalPositionFor(getPositionInCode(code, `list`)),
  140. ).toMatchObject(getPositionInCode(source, `list`))
  141. expect(
  142. consumer.originalPositionFor(
  143. getPositionInCode(code, `_ctx.list`, `list`),
  144. ),
  145. ).toMatchObject(getPositionInCode(source, `list`, true))
  146. expect(
  147. consumer.originalPositionFor(getPositionInCode(code, `value`)),
  148. ).toMatchObject(getPositionInCode(source, `value`))
  149. expect(
  150. consumer.originalPositionFor(getPositionInCode(code, `index`)),
  151. ).toMatchObject(getPositionInCode(source, `index`))
  152. expect(
  153. consumer.originalPositionFor(getPositionInCode(code, `value + index`)),
  154. ).toMatchObject(getPositionInCode(source, `value + index`))
  155. })
  156. test('module mode', () => {
  157. const { code, map } = compile(source, {
  158. mode: 'module',
  159. sourceMap: true,
  160. filename: `foo.vue`,
  161. })
  162. expect(code).toMatchSnapshot()
  163. expect(map!.sources).toEqual([`foo.vue`])
  164. expect(map!.sourcesContent).toEqual([source])
  165. const consumer = new SourceMapConsumer(map as RawSourceMap)
  166. expect(
  167. consumer.originalPositionFor(getPositionInCode(code, `id`)),
  168. ).toMatchObject(getPositionInCode(source, `id`))
  169. expect(
  170. consumer.originalPositionFor(getPositionInCode(code, `"foo"`)),
  171. ).toMatchObject(getPositionInCode(source, `"foo"`))
  172. expect(
  173. consumer.originalPositionFor(getPositionInCode(code, `class:`)),
  174. ).toMatchObject(getPositionInCode(source, `class=`))
  175. expect(
  176. consumer.originalPositionFor(getPositionInCode(code, `bar`)),
  177. ).toMatchObject(getPositionInCode(source, `bar`))
  178. expect(
  179. consumer.originalPositionFor(getPositionInCode(code, `_ctx.bar`, `bar`)),
  180. ).toMatchObject(getPositionInCode(source, `bar`, true))
  181. expect(
  182. consumer.originalPositionFor(getPositionInCode(code, `baz`)),
  183. ).toMatchObject(getPositionInCode(source, `baz`))
  184. expect(
  185. consumer.originalPositionFor(getPositionInCode(code, `world`, true)),
  186. ).toMatchObject(getPositionInCode(source, `world`, `world`))
  187. expect(
  188. consumer.originalPositionFor(
  189. getPositionInCode(code, `_ctx.world`, `world`),
  190. ),
  191. ).toMatchObject(getPositionInCode(source, `world`, `world`))
  192. expect(
  193. consumer.originalPositionFor(getPositionInCode(code, `burn()`)),
  194. ).toMatchObject(getPositionInCode(source, `burn()`))
  195. expect(
  196. consumer.originalPositionFor(getPositionInCode(code, `ok`)),
  197. ).toMatchObject(getPositionInCode(source, `ok`))
  198. expect(
  199. consumer.originalPositionFor(getPositionInCode(code, `_ctx.ok`, `ok`)),
  200. ).toMatchObject(getPositionInCode(source, `ok`, true))
  201. expect(
  202. consumer.originalPositionFor(getPositionInCode(code, `list`)),
  203. ).toMatchObject(getPositionInCode(source, `list`))
  204. expect(
  205. consumer.originalPositionFor(
  206. getPositionInCode(code, `_ctx.list`, `list`),
  207. ),
  208. ).toMatchObject(getPositionInCode(source, `list`, true))
  209. expect(
  210. consumer.originalPositionFor(getPositionInCode(code, `value`)),
  211. ).toMatchObject(getPositionInCode(source, `value`))
  212. expect(
  213. consumer.originalPositionFor(getPositionInCode(code, `index`)),
  214. ).toMatchObject(getPositionInCode(source, `index`))
  215. expect(
  216. consumer.originalPositionFor(getPositionInCode(code, `value + index`)),
  217. ).toMatchObject(getPositionInCode(source, `value + index`))
  218. })
  219. })