2
0

major-minor-segment.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. // https://gitlab.com/antora/antora/-/issues/132#note_712132072
  2. 'use strict'
  3. const { posix: path } = require('path')
  4. module.exports.register = function({ config }) {
  5. this.on('contentClassified', ({ contentCatalog }) => {
  6. contentCatalog.getComponents().forEach(component => {
  7. const componentName = component.name;
  8. const generationToVersion = new Map();
  9. component.versions.forEach(version => {
  10. const generation = getGeneration(version.version);
  11. const original = generationToVersion.get(generation);
  12. if (original === undefined || (original.prerelease && !version.prerelease)) {
  13. generationToVersion.set(generation, version);
  14. }
  15. });
  16. const versionToGeneration = Array.from(generationToVersion.entries()).reduce((acc, entry) => {
  17. const [ generation, version ] = entry;
  18. acc.set(version.version, generation);
  19. return acc;
  20. }, new Map());
  21. contentCatalog.findBy({ component: componentName }).forEach((file) => {
  22. const candidateVersion = file.src.version;
  23. if (versionToGeneration.has(candidateVersion)) {
  24. const generation = versionToGeneration.get(candidateVersion);
  25. if (file.out) {
  26. if (file.out) {
  27. file.out.dirname = file.out.dirname.replace(candidateVersion, generation)
  28. file.out.path = file.out.path.replace(candidateVersion, generation);
  29. }
  30. }
  31. if (file.pub) {
  32. file.pub.url = file.pub.url.replace(candidateVersion, generation)
  33. }
  34. }
  35. });
  36. versionToGeneration.forEach((generation, mappedVersion) => {
  37. contentCatalog.getComponent(componentName).versions.filter(version => version.version === mappedVersion).forEach((version) => {
  38. version.url = version.url.replace(mappedVersion, generation);
  39. })
  40. const symbolicVersionAlias = createSymbolicVersionAlias(
  41. componentName,
  42. mappedVersion,
  43. generation,
  44. 'redirect:to'
  45. )
  46. symbolicVersionAlias.src.version = generation;
  47. contentCatalog.addFile(symbolicVersionAlias);
  48. });
  49. })
  50. })
  51. }
  52. function createSymbolicVersionAlias (component, version, symbolicVersionSegment, strategy) {
  53. if (symbolicVersionSegment == null || symbolicVersionSegment === version) return
  54. const family = 'alias'
  55. const baseVersionAliasSrc = { component, module: 'ROOT', family, relative: '', basename: '', stem: '', extname: '' }
  56. const symbolicVersionAliasSrc = Object.assign({}, baseVersionAliasSrc, { version: symbolicVersionSegment })
  57. const symbolicVersionAlias = {
  58. src: symbolicVersionAliasSrc,
  59. pub: computePub(
  60. symbolicVersionAliasSrc,
  61. computeOut(symbolicVersionAliasSrc, family, symbolicVersionSegment),
  62. family
  63. ),
  64. }
  65. const originalVersionAliasSrc = Object.assign({}, baseVersionAliasSrc, { version })
  66. const originalVersionSegment = computeVersionSegment(component, version, 'original')
  67. const originalVersionAlias = {
  68. src: originalVersionAliasSrc,
  69. pub: computePub(
  70. originalVersionAliasSrc,
  71. computeOut(originalVersionAliasSrc, family, originalVersionSegment),
  72. family
  73. ),
  74. }
  75. if (strategy === 'redirect:to') {
  76. originalVersionAlias.out = undefined
  77. originalVersionAlias.rel = symbolicVersionAlias
  78. return originalVersionAlias
  79. } else {
  80. symbolicVersionAlias.out = undefined
  81. symbolicVersionAlias.rel = originalVersionAlias
  82. return symbolicVersionAlias
  83. }
  84. }
  85. function computeOut (src, family, version, htmlUrlExtensionStyle) {
  86. let { component, module: module_, basename, extname, relative, stem } = src
  87. if (module_ === 'ROOT') module_ = ''
  88. let indexifyPathSegment = ''
  89. let familyPathSegment = ''
  90. if (family === 'page') {
  91. if (stem !== 'index' && htmlUrlExtensionStyle === 'indexify') {
  92. basename = 'index.html'
  93. indexifyPathSegment = stem
  94. } else if (extname === '.adoc') {
  95. basename = stem + '.html'
  96. }
  97. } else if (family === 'image') {
  98. familyPathSegment = '_images'
  99. } else if (family === 'attachment') {
  100. familyPathSegment = '_attachments'
  101. }
  102. const modulePath = path.join(component, version, module_)
  103. const dirname = path.join(modulePath, familyPathSegment, path.dirname(relative), indexifyPathSegment)
  104. const path_ = path.join(dirname, basename)
  105. const moduleRootPath = path.relative(dirname, modulePath) || '.'
  106. const rootPath = path.relative(dirname, '') || '.'
  107. return { dirname, basename, path: path_, moduleRootPath, rootPath }
  108. }
  109. function computePub (src, out, family, version, htmlUrlExtensionStyle) {
  110. const pub = {}
  111. let url
  112. if (family === 'nav') {
  113. const urlSegments = version ? [src.component, version] : [src.component]
  114. if (src.module && src.module !== 'ROOT') urlSegments.push(src.module)
  115. // an artificial URL used for resolving page references in navigation model
  116. url = '/' + urlSegments.join('/') + '/'
  117. pub.moduleRootPath = '.'
  118. } else if (family === 'page') {
  119. const urlSegments = out.path.split('/')
  120. const lastUrlSegmentIdx = urlSegments.length - 1
  121. if (htmlUrlExtensionStyle === 'drop') {
  122. // drop just the .html extension or, if the filename is index.html, the whole segment
  123. const lastUrlSegment = urlSegments[lastUrlSegmentIdx]
  124. urlSegments[lastUrlSegmentIdx] =
  125. lastUrlSegment === 'index.html' ? '' : lastUrlSegment.substr(0, lastUrlSegment.length - 5)
  126. } else if (htmlUrlExtensionStyle === 'indexify') {
  127. urlSegments[lastUrlSegmentIdx] = ''
  128. }
  129. url = '/' + urlSegments.join('/')
  130. } else {
  131. url = '/' + out.path
  132. if (family === 'alias' && !src.relative.length) pub.splat = true
  133. }
  134. pub.url = ~url.indexOf(' ') ? url.replace(SPACE_RX, '%20') : url
  135. if (out) {
  136. pub.moduleRootPath = out.moduleRootPath
  137. pub.rootPath = out.rootPath
  138. }
  139. return pub
  140. }
  141. function computeVersionSegment (name, version, mode) {
  142. if (mode === 'original') return !version || version === 'master' ? '' : version
  143. const strategy = this.latestVersionUrlSegmentStrategy
  144. // NOTE: special exception; revisit in Antora 3
  145. if (!version || version === 'master') {
  146. if (mode !== 'alias') return ''
  147. if (strategy === 'redirect:to') return
  148. }
  149. if (strategy === 'redirect:to' || strategy === (mode === 'alias' ? 'redirect:from' : 'replace')) {
  150. const component = this.getComponent(name)
  151. const componentVersion = component && this.getComponentVersion(component, version)
  152. if (componentVersion) {
  153. const segment =
  154. componentVersion === component.latest
  155. ? this.latestVersionUrlSegment
  156. : componentVersion === component.latestPrerelease
  157. ? this.latestPrereleaseVersionUrlSegment
  158. : undefined
  159. return segment == null ? version : segment
  160. }
  161. }
  162. return version
  163. }
  164. function getGeneration(version) {
  165. if (!version) return version;
  166. const firstIndex = version.indexOf('.')
  167. if (firstIndex < 0) {
  168. return version;
  169. }
  170. const secondIndex = version.indexOf('.', firstIndex + 1);
  171. const result = version.substr(0, secondIndex);
  172. return result;
  173. }
  174. function out(args) {
  175. console.log(JSON.stringify(args, no_data, 2));
  176. }
  177. function no_data(key, value) {
  178. if (key == "data" || key == "files") {
  179. return value ? "__data__" : value;
  180. }
  181. return value;
  182. }