parse.spec.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. import { parse } from '../src'
  2. import { mockWarn } from '@vue/shared'
  3. import { baseParse, baseCompile } from '@vue/compiler-core'
  4. import { SourceMapConsumer } from 'source-map'
  5. describe('compiler:sfc', () => {
  6. mockWarn()
  7. describe('source map', () => {
  8. test('style block', () => {
  9. // Padding determines how many blank lines will there be before the style block
  10. const padding = Math.round(Math.random() * 10)
  11. const style = parse(
  12. `${'\n'.repeat(padding)}<style>\n.color {\n color: red;\n }\n</style>\n`
  13. ).descriptor.styles[0]
  14. expect(style.map).not.toBeUndefined()
  15. const consumer = new SourceMapConsumer(style.map!)
  16. consumer.eachMapping(mapping => {
  17. expect(mapping.originalLine - mapping.generatedLine).toBe(padding)
  18. })
  19. })
  20. test('script block', () => {
  21. // Padding determines how many blank lines will there be before the style block
  22. const padding = Math.round(Math.random() * 10)
  23. const script = parse(
  24. `${'\n'.repeat(padding)}<script>\nconsole.log(1)\n }\n</script>\n`
  25. ).descriptor.script
  26. expect(script!.map).not.toBeUndefined()
  27. const consumer = new SourceMapConsumer(script!.map!)
  28. consumer.eachMapping(mapping => {
  29. expect(mapping.originalLine - mapping.generatedLine).toBe(padding)
  30. })
  31. })
  32. })
  33. test('pad content', () => {
  34. const content = `
  35. <template>
  36. <div></div>
  37. </template>
  38. <script>
  39. export default {}
  40. </script>
  41. <style>
  42. h1 { color: red }
  43. </style>`
  44. const padFalse = parse(content.trim(), { pad: false }).descriptor
  45. expect(padFalse.template!.content).toBe('\n<div></div>\n')
  46. expect(padFalse.script!.content).toBe('\nexport default {}\n')
  47. expect(padFalse.styles[0].content).toBe('\nh1 { color: red }\n')
  48. const padTrue = parse(content.trim(), { pad: true }).descriptor
  49. expect(padTrue.script!.content).toBe(
  50. Array(3 + 1).join('//\n') + '\nexport default {}\n'
  51. )
  52. expect(padTrue.styles[0].content).toBe(
  53. Array(6 + 1).join('\n') + '\nh1 { color: red }\n'
  54. )
  55. const padLine = parse(content.trim(), { pad: 'line' }).descriptor
  56. expect(padLine.script!.content).toBe(
  57. Array(3 + 1).join('//\n') + '\nexport default {}\n'
  58. )
  59. expect(padLine.styles[0].content).toBe(
  60. Array(6 + 1).join('\n') + '\nh1 { color: red }\n'
  61. )
  62. const padSpace = parse(content.trim(), { pad: 'space' }).descriptor
  63. expect(padSpace.script!.content).toBe(
  64. `<template>\n<div></div>\n</template>\n<script>`.replace(/./g, ' ') +
  65. '\nexport default {}\n'
  66. )
  67. expect(padSpace.styles[0].content).toBe(
  68. `<template>\n<div></div>\n</template>\n<script>\nexport default {}\n</script>\n<style>`.replace(
  69. /./g,
  70. ' '
  71. ) + '\nh1 { color: red }\n'
  72. )
  73. })
  74. test('should ignore nodes with no content', () => {
  75. expect(parse(`<template/>`).descriptor.template).toBe(null)
  76. expect(parse(`<script/>`).descriptor.script).toBe(null)
  77. expect(parse(`<style/>`).descriptor.styles.length).toBe(0)
  78. expect(parse(`<custom/>`).descriptor.customBlocks.length).toBe(0)
  79. })
  80. test('handle empty nodes with src attribute', () => {
  81. const { descriptor } = parse(`<script src="com"/>`)
  82. expect(descriptor.script).toBeTruthy()
  83. expect(descriptor.script!.content).toBeFalsy()
  84. expect(descriptor.script!.attrs['src']).toBe('com')
  85. })
  86. test('nested templates', () => {
  87. const content = `
  88. <template v-if="ok">ok</template>
  89. <div><div></div></div>
  90. `
  91. const { descriptor } = parse(`<template>${content}</template>`)
  92. expect(descriptor.template!.content).toBe(content)
  93. })
  94. test('error tolerance', () => {
  95. const { errors } = parse(`<template>`)
  96. expect(errors.length).toBe(1)
  97. })
  98. test('should parse as DOM by default', () => {
  99. const { errors } = parse(`<template><input></template>`)
  100. expect(errors.length).toBe(0)
  101. })
  102. test('custom compiler', () => {
  103. const { errors } = parse(`<template><input></template>`, {
  104. compiler: {
  105. parse: baseParse,
  106. compile: baseCompile
  107. }
  108. })
  109. expect(errors.length).toBe(1)
  110. })
  111. test('treat custom blocks as raw text', () => {
  112. const { errors, descriptor } = parse(`<foo> <-& </foo>`)
  113. expect(errors.length).toBe(0)
  114. expect(descriptor.customBlocks[0].content).toBe(` <-& `)
  115. })
  116. describe('warnings', () => {
  117. test('should only allow single template element', () => {
  118. parse(`<template><div/></template><template><div/></template>`)
  119. expect(
  120. `Single file component can contain only one template element`
  121. ).toHaveBeenWarned()
  122. })
  123. test('should only allow single script element', () => {
  124. parse(`<script>console.log(1)</script><script>console.log(1)</script>`)
  125. expect(
  126. `Single file component can contain only one script element`
  127. ).toHaveBeenWarned()
  128. })
  129. })
  130. })