index.js 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. 'use strict'
  2. var visit = require('unist-util-visit')
  3. module.exports = referenceLinks
  4. var own = {}.hasOwnProperty
  5. function referenceLinks() {
  6. return transformer
  7. }
  8. function transformer(node) {
  9. var definitions = {}
  10. var existing = []
  11. visit(node, 'definition', find(definitions, existing))
  12. visit(node, ['image', 'link'], factory(node, definitions, existing))
  13. }
  14. // Find existing definitions.
  15. function find(definitions, existing) {
  16. return one
  17. function one(node) {
  18. var url = node.url
  19. existing.push(node.identifier)
  20. if (!own.call(definitions, url)) {
  21. definitions[url] = {}
  22. }
  23. definitions[url][node.title] = node
  24. }
  25. }
  26. // Transform normal links and images into references and definitions, replaces
  27. // the current node, and adds a definition if needed.
  28. function factory(root, definitions, existing) {
  29. var id = 0
  30. return one
  31. // Transform a normal link/image based on bound `definitions`.
  32. function one(node, index, parent) {
  33. var url = node.url
  34. var title = node.title
  35. var replacement
  36. var identifier
  37. var titles
  38. var definition
  39. if (own.call(definitions, url)) {
  40. titles = definitions[url]
  41. } else {
  42. titles = {}
  43. definitions[url] = titles
  44. }
  45. if (own.call(titles, title)) {
  46. identifier = titles[title].identifier
  47. } else {
  48. do {
  49. identifier = String(++id)
  50. } while (existing.indexOf(identifier) !== -1)
  51. definition = {
  52. type: 'definition',
  53. identifier: identifier,
  54. title: title,
  55. url: url
  56. }
  57. titles[title] = definition
  58. root.children.push(definition)
  59. }
  60. replacement = {
  61. type: node.type + 'Reference',
  62. identifier: identifier,
  63. referenceType: 'full'
  64. }
  65. if (node.type === 'image') {
  66. replacement.alt = node.alt
  67. } else {
  68. replacement.children = node.children
  69. }
  70. parent.children[index] = replacement
  71. }
  72. }