highlight.ts 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. // ref https://github.com/vuejs/vitepress/blob/main/src/node/markdown/plugins/highlight.ts
  2. import chalk from 'chalk'
  3. import escapeHtml from 'escape-html'
  4. import prism from 'prismjs'
  5. import consola from 'consola'
  6. // prism is listed as actual dep so it's ok to require
  7. // eslint-disable-next-line @typescript-eslint/no-var-requires
  8. const loadLanguages = require('prismjs/components/index')
  9. // required to make embedded highlighting work...
  10. loadLanguages(['markup', 'css', 'javascript'])
  11. function wrap(code: string, lang: string): string {
  12. if (lang === 'text') {
  13. code = escapeHtml(code)
  14. }
  15. return `<pre v-pre><code>${code}</code></pre>`
  16. }
  17. export const highlight = (str: string, lang: string) => {
  18. if (!lang) {
  19. return wrap(str, 'text')
  20. }
  21. lang = lang.toLowerCase()
  22. const rawLang = lang
  23. if (lang === 'vue' || lang === 'html') {
  24. lang = 'markup'
  25. }
  26. if (lang === 'md') {
  27. lang = 'markdown'
  28. }
  29. if (lang === 'ts') {
  30. lang = 'typescript'
  31. }
  32. if (lang === 'py') {
  33. lang = 'python'
  34. }
  35. if (!prism.languages[lang]) {
  36. try {
  37. loadLanguages([lang])
  38. } catch {
  39. // eslint-disable-next-line no-console
  40. consola.warn(
  41. chalk.yellow(
  42. `[vitepress] Syntax highlight for language "${lang}" is not supported.`
  43. )
  44. )
  45. }
  46. }
  47. if (prism.languages[lang]) {
  48. const code = prism.highlight(str, prism.languages[lang], lang)
  49. return wrap(code, rawLang)
  50. }
  51. return wrap(str, 'text')
  52. }