@antora/content-classifier 3.0.0-alpha.8 → 3.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  The Content Classifier is a component in Antora responsible for organizing aggregated content into a virtual file catalog for use in an Antora documentation pipeline.
4
4
 
5
5
  [Antora](https://antora.org) is a modular static site generator designed for creating documentation sites from AsciiDoc documents.
6
- Its site generator pipeline aggregates documents from versioned content repositories and processes them using [Asciidoctor](https://asciidoctor.org).
6
+ Its site generator aggregates documents from versioned content repositories and processes them using [Asciidoctor](https://asciidoctor.org).
7
7
 
8
8
  ## Copyright and License
9
9
 
package/lib/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
3
  module.exports = Object.freeze({
4
- START_ALIAS_ID: Object.freeze({ component: '', version: '', module: '', family: 'alias', relative: 'index.adoc' }),
5
- START_PAGE_ID: Object.freeze({ component: '', version: '', module: '', family: 'page', relative: 'index.adoc' }),
4
+ ROOT_INDEX_ALIAS_ID: { component: 'ROOT', version: '', module: 'ROOT', family: 'alias', relative: 'index.adoc' },
5
+ ROOT_INDEX_PAGE_ID: { component: 'ROOT', version: '', module: 'ROOT', family: 'page', relative: 'index.adoc' },
6
6
  })
@@ -9,7 +9,7 @@ const { posix: path } = require('path')
9
9
  const resolveResource = require('./util/resolve-resource')
10
10
  const versionCompare = require('./util/version-compare-desc')
11
11
 
12
- const { START_ALIAS_ID, START_PAGE_ID } = require('./constants')
12
+ const { ROOT_INDEX_ALIAS_ID, ROOT_INDEX_PAGE_ID } = require('./constants')
13
13
  const SPACE_RX = / /g
14
14
 
15
15
  const $components = Symbol('components')
@@ -73,15 +73,17 @@ class ContentCatalog {
73
73
  const component = this[$components].get(name)
74
74
  if (component) {
75
75
  const componentVersions = component.versions
76
- const insertIdx = componentVersions.findIndex(({ version: candidate }) => {
77
- if (candidate === version) throw new Error(`Duplicate version detected for component ${name}: ${version}`)
78
- return versionCompare(candidate, version) > 0
79
- })
80
- if (~insertIdx) {
81
- componentVersions.splice(insertIdx, 0, componentVersion)
82
- } else {
83
- componentVersions.push(componentVersion)
76
+ if (componentVersions.find(({ version: candidate }) => candidate === version)) {
77
+ throw new Error(`Duplicate version detected for component ${name}: ${version}`)
84
78
  }
79
+ const insertIdx = prerelease
80
+ ? componentVersions.findIndex(({ version: candidateVersion, prerelease: candidatePrerelease }) =>
81
+ candidatePrerelease ? versionCompare(candidateVersion, version) > 0 : true
82
+ )
83
+ : componentVersions.findIndex(({ version: candidateVersion, prerelease: candidatePrerelease }) =>
84
+ candidatePrerelease ? false : versionCompare(candidateVersion, version) > 0
85
+ )
86
+ ~insertIdx ? componentVersions.splice(insertIdx, 0, componentVersion) : componentVersions.push(componentVersion)
85
87
  if ((component.latest = componentVersions.find((candidate) => !candidate.prerelease))) {
86
88
  if (componentVersions[0] !== component.latest) component.latestPrerelease = componentVersions[0]
87
89
  } else {
@@ -167,11 +169,11 @@ class ContentCatalog {
167
169
  ('/' + src.relative).indexOf('/_') < 0
168
170
  ) {
169
171
  publishable = true
170
- versionSegment = computeVersionSegment.bind(this)(src.component, src.version)
172
+ versionSegment = computeVersionSegment.call(this, src.component, src.version)
171
173
  file.out = computeOut(src, family, versionSegment, this.htmlUrlExtensionStyle)
172
174
  }
173
175
  if (!file.pub && (publishable || family === 'nav')) {
174
- if (versionSegment == null) versionSegment = computeVersionSegment.bind(this)(src.component, src.version)
176
+ if (versionSegment == null) versionSegment = computeVersionSegment.call(this, src.component, src.version)
175
177
  file.pub = computePub(src, file.out, family, versionSegment, this.htmlUrlExtensionStyle)
176
178
  }
177
179
  filesForFamily.set(key, file)
@@ -247,7 +249,7 @@ class ContentCatalog {
247
249
 
248
250
  // TODO add `follow` argument to control whether alias is followed
249
251
  getSiteStartPage () {
250
- return this.getById(START_PAGE_ID) || (this.getById(START_ALIAS_ID) || {}).rel
252
+ return this.getById(ROOT_INDEX_PAGE_ID) || (this.getById(ROOT_INDEX_ALIAS_ID) || {}).rel
251
253
  }
252
254
 
253
255
  registerComponentVersionStartPage (name, componentVersion, startPageSpec = undefined) {
@@ -259,7 +261,7 @@ class ContentCatalog {
259
261
  }
260
262
  let startPage
261
263
  let startPageSrc
262
- const indexPageId = { component: name, version, module: 'ROOT', family: 'page', relative: 'index.adoc' }
264
+ const indexPageId = Object.assign({}, ROOT_INDEX_PAGE_ID, { component: name, version })
263
265
  if (startPageSpec) {
264
266
  if (
265
267
  (startPage = this.resolvePage(startPageSpec, indexPageId)) &&
@@ -287,7 +289,7 @@ class ContentCatalog {
287
289
  componentVersion.url = startPage.pub.url
288
290
  } else {
289
291
  // QUESTION: should we warn if the default start page cannot be found?
290
- const versionSegment = computeVersionSegment.bind(this)(name, version)
292
+ const versionSegment = computeVersionSegment.call(this, name, version)
291
293
  componentVersion.url = computePub(
292
294
  (startPageSrc = prepareSrc(Object.assign({}, indexPageId, { family: 'page' }))),
293
295
  computeOut(startPageSrc, startPageSrc.family, versionSegment, this.htmlUrlExtensionStyle),
@@ -300,7 +302,7 @@ class ContentCatalog {
300
302
  const symbolicVersionAlias = createSymbolicVersionAlias(
301
303
  name,
302
304
  version,
303
- computeVersionSegment.bind(this)(name, version, 'alias'),
305
+ computeVersionSegment.call(this, name, version, 'alias'),
304
306
  this.latestVersionUrlSegmentStrategy
305
307
  )
306
308
  if (symbolicVersionAlias) this.addFile(symbolicVersionAlias)
@@ -310,7 +312,8 @@ class ContentCatalog {
310
312
  if (!startPageSpec) return
311
313
  const rel = this.resolvePage(startPageSpec)
312
314
  if (rel) {
313
- return this.addFile({ src: Object.assign({}, START_ALIAS_ID), rel })
315
+ if (!(this.getSiteStartPage() || { synthetic: true }).synthetic) return
316
+ return this.addFile({ src: Object.assign({}, ROOT_INDEX_ALIAS_ID), rel, synthetic: true })
314
317
  } else if (rel === false) {
315
318
  logger.warn('Start page specified for site has invalid syntax: %s', startPageSpec)
316
319
  } else if (~startPageSpec.indexOf(':')) {
@@ -365,9 +368,10 @@ class ContentCatalog {
365
368
  *
366
369
  * Parses the specified contextual page ID spec into a page ID object, then attempts to lookup a
367
370
  * file with this page ID in the catalog. If a component is specified, but not a version, the
368
- * latest version of the component stored in the catalog is used. If a file cannot be resolved,
369
- * the function returns undefined. If the spec does not match the page ID syntax, this function
370
- * throws an error.
371
+ * latest version of the component stored in the catalog is used. If a page cannot be resolved,
372
+ * the search is attempted again for an "alias". If neither a page or alias can be resolved, the
373
+ * function returns undefined. If the spec does not match the page ID syntax, this function throws
374
+ * an error.
371
375
  *
372
376
  * @param {String} spec - The contextual page ID spec (e.g., version@component:module:topic/page.adoc).
373
377
  * @param {ContentCatalog} catalog - The content catalog in which to resolve the page file.
@@ -448,6 +452,7 @@ function prepareSrc (src) {
448
452
 
449
453
  function computeOut (src, family, version, htmlUrlExtensionStyle) {
450
454
  let { component, module: module_, basename, extname, relative, stem } = src
455
+ if (component === 'ROOT') component = ''
451
456
  if (module_ === 'ROOT') module_ = ''
452
457
  let indexifyPathSegment = ''
453
458
  let familyPathSegment = ''
@@ -478,8 +483,11 @@ function computePub (src, out, family, version, htmlUrlExtensionStyle) {
478
483
  const pub = {}
479
484
  let url
480
485
  if (family === 'nav') {
481
- const urlSegments = version ? [src.component, version] : [src.component]
482
- if (src.module && src.module !== 'ROOT') urlSegments.push(src.module)
486
+ const component = src.component || 'ROOT'
487
+ const urlSegments = component === 'ROOT' ? [] : [component]
488
+ if (version) urlSegments.push(version)
489
+ const module_ = src.module || 'ROOT'
490
+ if (module_ !== 'ROOT') urlSegments.push(module_)
483
491
  // an artificial URL used for resolving page references in navigation model
484
492
  url = '/' + urlSegments.join('/') + '/'
485
493
  pub.moduleRootPath = '.'
@@ -56,9 +56,16 @@ function parseResourceId (spec, ctx = {}, defaultFamily = 'page', permittedFamil
56
56
  }
57
57
 
58
58
  if (~relative.indexOf('/')) {
59
- relative = relative
60
- .split('/')
61
- .filter((it) => it && it !== '.' && it !== '..')
59
+ const relativeSegments = relative.split('/')
60
+ let from
61
+ if (relativeSegments[0] === '.' && (from = ctx.relative)) {
62
+ relativeSegments[0] = from.substr(0, (from.lastIndexOf('/') + 1 || 1) - 1)
63
+ }
64
+ relative = relativeSegments
65
+ .reduce((accum, segment) => {
66
+ segment === '..' ? accum.pop() : (segment || '.') !== '.' && accum.push(segment)
67
+ return accum
68
+ }, [])
62
69
  .join('/')
63
70
  }
64
71
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antora/content-classifier",
3
- "version": "3.0.0-alpha.8",
3
+ "version": "3.0.0-beta.3",
4
4
  "description": "Organizes aggregated content into a virtual file catalog for use in an Antora documentation pipeline.",
5
5
  "license": "MPL-2.0",
6
6
  "author": "OpenDevise Inc. (https://opendevise.com)",
@@ -16,12 +16,12 @@
16
16
  },
17
17
  "main": "lib/index.js",
18
18
  "dependencies": {
19
- "@antora/logger": "3.0.0-alpha.8",
19
+ "@antora/logger": "3.0.0-beta.3",
20
20
  "mime-types": "~2.1",
21
21
  "vinyl": "~2.2"
22
22
  },
23
23
  "engines": {
24
- "node": ">=10.17.0"
24
+ "node": ">=12.21.0"
25
25
  },
26
26
  "files": [
27
27
  "lib/"
@@ -34,5 +34,5 @@
34
34
  "static site",
35
35
  "web publishing"
36
36
  ],
37
- "gitHead": "2e5695bea11fb5719989c329c97e66d36e29659f"
37
+ "gitHead": "45da95a2e2dea538379d2d9f42013d2208fb86c3"
38
38
  }