|
| 1 | +'use strict' |
| 2 | + |
| 3 | +/** |
| 4 | + * Shared catalog mechanics for publishing an alias version segment -- a segment |
| 5 | + * that is not a real version folder but a tree of redirect stubs mirroring one |
| 6 | + * (`latest`, `next`). Used by antora-extensions/latest-alias.js and |
| 7 | + * antora-extensions/next-alias.js: only the segment name and the source version |
| 8 | + * differ between them, while the two Antora quirks that make the mirroring work |
| 9 | + * are subtle enough to be worth stating once. |
| 10 | + * |
| 11 | + * Under `redirect_facility: static` (see site.yml) every file added to the `alias` |
| 12 | + * family renders as a <meta http-equiv="refresh"> stub, which is what makes such a |
| 13 | + * segment work on a static host like GitHub Pages. |
| 14 | + */ |
| 15 | + |
| 16 | +/** |
| 17 | + * Mirror every published page of `sourceVersion` into `segment` as a redirect. |
| 18 | + * |
| 19 | + * @param {Object} contentCatalog Antora's content catalog |
| 20 | + * @param {Object} component the component to mirror within |
| 21 | + * @param {String} sourceVersion the real version to point at ('' for versionless) |
| 22 | + * @param {String} segment the alias version segment to publish under |
| 23 | + */ |
| 24 | +function mirrorPages (contentCatalog, component, sourceVersion, segment) { |
| 25 | + contentCatalog |
| 26 | + .findBy({ component: component.name, version: sourceVersion, family: 'page' }) |
| 27 | + .forEach((page) => { |
| 28 | + // Only real published pages are valid redirect targets. AsciiDoc partials |
| 29 | + // (_*.adoc include fragments) are in the page family but have no pub/out; |
| 30 | + // aliasing them makes @antora/redirect-producer throw "Cannot read |
| 31 | + // properties of undefined (reading 'url')". Guard on both. |
| 32 | + if (!page.pub || !page.pub.url || !page.out) return |
| 33 | + addAlias(contentCatalog, component, segment, page.src.module, page.src.relative, page) |
| 34 | + }) |
| 35 | +} |
| 36 | + |
| 37 | +/** |
| 38 | + * Mirror the move-redirects of `sourceVersion` -- the stubs Antora registers for |
| 39 | + * `page-aliases` attributes -- into `segment`. |
| 40 | + * |
| 41 | + * Antora registers those stubs while it converts documents, so at |
| 42 | + * contentClassified they do not exist yet and mirrorPages() cannot see them: they |
| 43 | + * are in the `alias` family, not `page`. Without this pass, an old page path that |
| 44 | + * survives in the source version only as a redirect (e.g. a page renamed in server |
| 45 | + * 11.0) resolves under the real version but 404s under the alias segment. The |
| 46 | + * legacy go.php short links (ui/supplemental/js/go-redirect.js) are keyed on those |
| 47 | + * older page paths and resolve inside these trees, so they depend on the redirects |
| 48 | + * being mirrored here. |
| 49 | + * |
| 50 | + * Call this from a `documentsConverted` listener, never earlier. |
| 51 | + * |
| 52 | + * @param {Object} contentCatalog Antora's content catalog |
| 53 | + * @param {Object} component the component to mirror within |
| 54 | + * @param {String} sourceVersion the real version whose redirects to mirror |
| 55 | + * @param {String} segment the alias version segment to publish under |
| 56 | + */ |
| 57 | +function mirrorMoveRedirects (contentCatalog, component, sourceVersion, segment) { |
| 58 | + contentCatalog |
| 59 | + .findBy({ component: component.name, version: sourceVersion, family: 'alias' }) |
| 60 | + .forEach((alias) => { |
| 61 | + // Chain the mirror straight to the redirect's ultimate target instead of to |
| 62 | + // the redirect itself: one hop from the alias segment to real content, and |
| 63 | + // `rel` must be a publishable page for the redirect producer. |
| 64 | + const target = alias.rel |
| 65 | + if (!target || !target.pub || !target.pub.url || !target.out) return |
| 66 | + addAlias(contentCatalog, component, segment, alias.src.module, alias.src.relative, target) |
| 67 | + }) |
| 68 | +} |
| 69 | + |
| 70 | +/** |
| 71 | + * Add one redirect stub at <component>/<segment>/<module>/<relative>. |
| 72 | + * |
| 73 | + * A path already claimed in `segment` is left untouched, so the first caller wins: |
| 74 | + * re-adding it would replace a live page with a redirect, or a closer redirect |
| 75 | + * target with a more distant one. next-alias.js depends on this to layer a release |
| 76 | + * version underneath a prerelease one without overwriting it. |
| 77 | + */ |
| 78 | +function addAlias (contentCatalog, component, segment, module, relative, target) { |
| 79 | + const src = { component: component.name, version: segment, module, family: 'alias', relative } |
| 80 | + if (contentCatalog.getById(src)) return |
| 81 | + contentCatalog.addFile({ src, rel: target }) |
| 82 | +} |
| 83 | + |
| 84 | +module.exports = { mirrorPages, mirrorMoveRedirects } |
0 commit comments