parse_link_destination.mjs 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. // Parse link destination
  2. //
  3. import { unescapeAll } from '../common/utils.mjs'
  4. export default function parseLinkDestination (str, start, max) {
  5. let code
  6. let pos = start
  7. const result = {
  8. ok: false,
  9. pos: 0,
  10. str: ''
  11. }
  12. if (str.charCodeAt(pos) === 0x3C /* < */) {
  13. pos++
  14. while (pos < max) {
  15. code = str.charCodeAt(pos)
  16. if (code === 0x0A /* \n */) { return result }
  17. if (code === 0x3C /* < */) { return result }
  18. if (code === 0x3E /* > */) {
  19. result.pos = pos + 1
  20. result.str = unescapeAll(str.slice(start + 1, pos))
  21. result.ok = true
  22. return result
  23. }
  24. if (code === 0x5C /* \ */ && pos + 1 < max) {
  25. pos += 2
  26. continue
  27. }
  28. pos++
  29. }
  30. // no closing '>'
  31. return result
  32. }
  33. // this should be ... } else { ... branch
  34. let level = 0
  35. while (pos < max) {
  36. code = str.charCodeAt(pos)
  37. if (code === 0x20) { break }
  38. // ascii control characters
  39. if (code < 0x20 || code === 0x7F) { break }
  40. if (code === 0x5C /* \ */ && pos + 1 < max) {
  41. if (str.charCodeAt(pos + 1) === 0x20) { break }
  42. pos += 2
  43. continue
  44. }
  45. if (code === 0x28 /* ( */) {
  46. level++
  47. if (level > 32) { return result }
  48. }
  49. if (code === 0x29 /* ) */) {
  50. if (level === 0) { break }
  51. level--
  52. }
  53. pos++
  54. }
  55. if (start === pos) { return result }
  56. if (level !== 0) { return result }
  57. result.str = unescapeAll(str.slice(start, pos))
  58. result.pos = pos
  59. result.ok = true
  60. return result
  61. }