@antora/content-classifier 3.2.0-alpha.6 → 3.2.0-alpha.9
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/lib/classify-content.js
CHANGED
|
@@ -20,7 +20,7 @@ const summarizeFileLocation = require('./util/summarize-file-location')
|
|
|
20
20
|
*
|
|
21
21
|
* @returns {ContentCatalog} A structured catalog of content components, versions, and virtual content files.
|
|
22
22
|
*/
|
|
23
|
-
function classifyContent (playbook, aggregate, siteAsciiDocConfig = {}, onComponentsRegistered) {
|
|
23
|
+
function classifyContent (playbook, aggregate, siteAsciiDocConfig = {}, onComponentsRegistered = undefined) {
|
|
24
24
|
const siteStartPage = playbook.site.startPage
|
|
25
25
|
let contentCatalog = registerComponentVersions(new ContentCatalog(playbook), aggregate, siteAsciiDocConfig)
|
|
26
26
|
return typeof onComponentsRegistered === 'function' &&
|
|
@@ -157,7 +157,7 @@ function getNavInfo (filepath, nav) {
|
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
function resolveAsciiDocConfig (siteAsciiDocConfig, { name, version, asciidoc, origins = [] }) {
|
|
160
|
-
const scopedAttributes =
|
|
160
|
+
const scopedAttributes = asciidoc?.attributes
|
|
161
161
|
if (scopedAttributes) {
|
|
162
162
|
const initial = Object.assign({}, siteAsciiDocConfig.attributes)
|
|
163
163
|
initial['antora-component-name'] = name
|
package/lib/content-catalog.js
CHANGED
|
@@ -11,7 +11,6 @@ const summarizeFileLocation = require('./util/summarize-file-location')
|
|
|
11
11
|
const versionCompare = require('./util/version-compare-desc')
|
|
12
12
|
|
|
13
13
|
const { ROOT_INDEX_ALIAS_ID, ROOT_INDEX_PAGE_ID } = require('./constants')
|
|
14
|
-
const SPACE_RX = / /g
|
|
15
14
|
const LOG_WRAP = '\n '
|
|
16
15
|
|
|
17
16
|
const $components = Symbol('components')
|
|
@@ -61,8 +60,13 @@ class ContentCatalog {
|
|
|
61
60
|
* @returns {Object} The constructed component version object.
|
|
62
61
|
*/
|
|
63
62
|
registerComponentVersion (name, version, descriptor = {}) {
|
|
64
|
-
const { asciidoc, displayVersion, prerelease, startPage:
|
|
65
|
-
const componentVersion = {
|
|
63
|
+
const { asciidoc, displayVersion, prerelease, startPage: startPageRef, title, versionSegment, origins } = descriptor
|
|
64
|
+
const componentVersion = {
|
|
65
|
+
displayVersion: displayVersion || version || 'default',
|
|
66
|
+
title: title || name,
|
|
67
|
+
version,
|
|
68
|
+
origins: new Set(origins && typeof origins[Symbol.iterator] === 'function' ? origins : []),
|
|
69
|
+
}
|
|
66
70
|
if (versionSegment != null) componentVersion.versionSegment = versionSegment
|
|
67
71
|
Object.defineProperty(componentVersion, 'name', { value: name, enumerable: true })
|
|
68
72
|
if (prerelease) {
|
|
@@ -87,10 +91,10 @@ class ContentCatalog {
|
|
|
87
91
|
let lastVerdict
|
|
88
92
|
const insertIdx = version
|
|
89
93
|
? componentVersions.findIndex(({ version: candidateVersion, prerelease: candidatePrerelease }) => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
+
return (lastVerdict = versionCompare(candidateVersion, version)) > 1
|
|
95
|
+
? !!prerelease === !!candidatePrerelease
|
|
96
|
+
: lastVerdict > 0 || (lastVerdict < -1 && prerelease && !candidatePrerelease)
|
|
97
|
+
})
|
|
94
98
|
: prerelease
|
|
95
99
|
? -1
|
|
96
100
|
: ~(~componentVersions.findIndex(({ prerelease: candidatePrerelease }) => !candidatePrerelease) || -1)
|
|
@@ -131,9 +135,9 @@ class ContentCatalog {
|
|
|
131
135
|
)
|
|
132
136
|
)
|
|
133
137
|
}
|
|
134
|
-
if (
|
|
138
|
+
if (startPageRef) {
|
|
135
139
|
// @deprecated use separate call to register start page for component version
|
|
136
|
-
this.registerComponentVersionStartPage(name, componentVersion,
|
|
140
|
+
this.registerComponentVersionStartPage(name, componentVersion, startPageRef === true ? undefined : startPageRef)
|
|
137
141
|
}
|
|
138
142
|
return componentVersion
|
|
139
143
|
}
|
|
@@ -147,22 +151,18 @@ class ContentCatalog {
|
|
|
147
151
|
if (filesForFamily.has(key)) {
|
|
148
152
|
if (family === 'alias') {
|
|
149
153
|
throw new Error(`Duplicate alias: ${generateResourceSpec(src)}`)
|
|
150
|
-
} else {
|
|
151
|
-
const details = [filesForFamily.get(key), file]
|
|
152
|
-
.map((it, idx) => `${idx + 1}: ${summarizeFileLocation(it)}`)
|
|
153
|
-
.join(LOG_WRAP)
|
|
154
|
-
if (family === 'nav') {
|
|
155
|
-
throw new Error(`Duplicate nav file: ${file.path} in ${version}@${component}${LOG_WRAP}${details}`)
|
|
156
|
-
} else {
|
|
157
|
-
throw new Error(`Duplicate ${family}: ${generateResourceSpec(src)}${LOG_WRAP}${details}`)
|
|
158
|
-
}
|
|
159
154
|
}
|
|
155
|
+
const details = [filesForFamily.get(key), file]
|
|
156
|
+
.map((it, idx) => `${idx + 1}: ${summarizeFileLocation(it)}`)
|
|
157
|
+
.join(LOG_WRAP)
|
|
158
|
+
if (family === 'nav') {
|
|
159
|
+
throw new Error(`Duplicate nav file: ${file.path} in ${version}@${component}${LOG_WRAP}${details}`)
|
|
160
|
+
}
|
|
161
|
+
throw new Error(`Duplicate ${family}: ${generateResourceSpec(src)}${LOG_WRAP}${details}`)
|
|
160
162
|
}
|
|
161
|
-
// NOTE: if the
|
|
162
|
-
// another option is to assume that if the file is not a vinyl object, the src likely needs to be prepared
|
|
163
|
+
// NOTE: assume that if the file is not a vinyl object, the src likely needs to be prepared
|
|
163
164
|
// a vinyl object is one indication the file was created and prepared by the content aggregator
|
|
164
|
-
//if
|
|
165
|
-
//if (!File.isVinyl(file)) file = new File(file)
|
|
165
|
+
// an alternate approach would be to call prepareSrc if the path property is not set
|
|
166
166
|
if (!File.isVinyl(file)) {
|
|
167
167
|
prepareSrc(src)
|
|
168
168
|
file = new File(file)
|
|
@@ -172,7 +172,7 @@ class ContentCatalog {
|
|
|
172
172
|
// NOTE: an alias masquerades as the target file
|
|
173
173
|
family = file.rel.src.family
|
|
174
174
|
// NOTE: short circuit in case of splat alias (alias -> alias)
|
|
175
|
-
if (family === 'alias' &&
|
|
175
|
+
if (family === 'alias' && file.pub?.splat) return filesForFamily.set(key, file) && file
|
|
176
176
|
src.mediaType = 'text/asciidoc'
|
|
177
177
|
} else if (!(file.mediaType = src.mediaType) && !('mediaType' in src)) {
|
|
178
178
|
// QUESTION: should we preserve the mediaType property on file if already defined?
|
|
@@ -185,18 +185,25 @@ class ContentCatalog {
|
|
|
185
185
|
} else if ('out' in file) {
|
|
186
186
|
delete file.out
|
|
187
187
|
} else if (
|
|
188
|
+
!file.private &&
|
|
188
189
|
(family === 'page' || family === 'image' || family === 'attachment') &&
|
|
189
|
-
('/' + src.relative).indexOf('/_') < 0
|
|
190
|
+
(file.private === false || ('/' + src.relative).indexOf('/_') < 0)
|
|
190
191
|
) {
|
|
191
192
|
publishable = true
|
|
192
193
|
if (componentVersion == null) componentVersion = this.getComponentVersion(component, version) || { version }
|
|
193
|
-
activeVersionSegment =
|
|
194
|
+
activeVersionSegment =
|
|
195
|
+
'activeVersionSegment' in componentVersion
|
|
196
|
+
? componentVersion.activeVersionSegment
|
|
197
|
+
: computeVersionSegment.call(this, componentVersion)
|
|
194
198
|
file.out = computeOut(src, family, activeVersionSegment, this.htmlUrlExtensionStyle)
|
|
195
199
|
}
|
|
196
200
|
if (!file.pub && (publishable || family === 'nav')) {
|
|
197
201
|
if (activeVersionSegment == null) {
|
|
198
202
|
if (componentVersion == null) componentVersion = this.getComponentVersion(component, version) || { version }
|
|
199
|
-
activeVersionSegment =
|
|
203
|
+
activeVersionSegment =
|
|
204
|
+
'activeVersionSegment' in componentVersion
|
|
205
|
+
? componentVersion.activeVersionSegment
|
|
206
|
+
: computeVersionSegment.call(this, componentVersion)
|
|
200
207
|
}
|
|
201
208
|
file.pub = computePub(src, file.out, family, activeVersionSegment, this.htmlUrlExtensionStyle)
|
|
202
209
|
}
|
|
@@ -243,7 +250,7 @@ class ContentCatalog {
|
|
|
243
250
|
}
|
|
244
251
|
|
|
245
252
|
getComponentVersion (component, version) {
|
|
246
|
-
return (component.versions ||
|
|
253
|
+
return (component.versions || this.getComponent(component)?.versions || []).find(
|
|
247
254
|
({ version: candidate }) => candidate === version
|
|
248
255
|
)
|
|
249
256
|
}
|
|
@@ -271,9 +278,8 @@ class ContentCatalog {
|
|
|
271
278
|
const accum = []
|
|
272
279
|
for (const candidate of candidates.values()) filter(candidate) && accum.push(candidate)
|
|
273
280
|
return accum
|
|
274
|
-
} else {
|
|
275
|
-
return [...candidates.values()]
|
|
276
281
|
}
|
|
282
|
+
return [...candidates.values()]
|
|
277
283
|
}
|
|
278
284
|
|
|
279
285
|
// TODO add `follow` argument to control whether alias is followed
|
|
@@ -370,7 +376,8 @@ class ContentCatalog {
|
|
|
370
376
|
if (rootIndexAlias) return rootIndexAlias.synthetic ? Object.assign(rootIndexAlias, { rel }) : undefined
|
|
371
377
|
const src = Object.assign({}, ROOT_INDEX_ALIAS_ID)
|
|
372
378
|
return this.addFile({ src, rel, synthetic: true }, { version: src.version })
|
|
373
|
-
}
|
|
379
|
+
}
|
|
380
|
+
if (rel === false) {
|
|
374
381
|
logger.warn('Start page specified for site has invalid syntax: %s', startPageSpec)
|
|
375
382
|
} else if (startPageSpec.lastIndexOf(':') > startPageSpec.indexOf(':')) {
|
|
376
383
|
logger.warn('Start page specified for site not found: %s', startPageSpec)
|
|
@@ -400,10 +407,10 @@ class ContentCatalog {
|
|
|
400
407
|
throw new Error(
|
|
401
408
|
existingPage === target
|
|
402
409
|
? `Page cannot define alias that references itself: ${generateResourceSpec(src)}` +
|
|
403
|
-
|
|
410
|
+
` (specified as: ${spec})${LOG_WRAP}source: ${summarizeFileLocation(existingPage)}`
|
|
404
411
|
: `Page alias cannot reference an existing page: ${generateResourceSpec(src)} (specified as: ${spec})` +
|
|
405
|
-
|
|
406
|
-
|
|
412
|
+
`${LOG_WRAP}source: ${summarizeFileLocation(target)}` +
|
|
413
|
+
`${LOG_WRAP}existing page: ${summarizeFileLocation(existingPage)}`
|
|
407
414
|
)
|
|
408
415
|
}
|
|
409
416
|
} else if (src.version == null) {
|
|
@@ -448,26 +455,48 @@ class ContentCatalog {
|
|
|
448
455
|
}
|
|
449
456
|
|
|
450
457
|
/**
|
|
451
|
-
* Attempts to resolve a
|
|
458
|
+
* Attempts to resolve a page reference within the given context to a page in the catalog.
|
|
452
459
|
*
|
|
453
|
-
* Parses the specified
|
|
454
|
-
*
|
|
455
|
-
*
|
|
456
|
-
* the search is attempted again for an "alias". If neither a page or alias can be resolved, the
|
|
457
|
-
* function returns undefined. If the spec does not match the page ID syntax, this function throws
|
|
458
|
-
* an error.
|
|
460
|
+
* Parses the specified page reference (i.e., page ID spec) into a partial page ID, expands it
|
|
461
|
+
* using the provided context, then attempts to locate a file in the page family with that page ID
|
|
462
|
+
* in this catalog. The family segment is optional.
|
|
459
463
|
*
|
|
460
|
-
*
|
|
461
|
-
*
|
|
462
|
-
*
|
|
464
|
+
* If a component is specified, but no version, the latest version of the component stored in the
|
|
465
|
+
* catalog is used. If a page cannot be resolved, the search is attempted again for an "alias". If
|
|
466
|
+
* neither a page or alias can be resolved, the function returns undefined. If the syntax of the
|
|
467
|
+
* reference is invalid, this function throws an error.
|
|
463
468
|
*
|
|
464
|
-
* @
|
|
465
|
-
*
|
|
469
|
+
* @param {String} spec - The contextual page reference (e.g., version@component:module:topic/page.adoc).
|
|
470
|
+
* @param {Object} [context={}] - The context to use to qualify the page reference.
|
|
471
|
+
*
|
|
472
|
+
* @returns {File} The virtual file to which the contextual page reference resolves, or undefined
|
|
473
|
+
* if the file cannot be resolved.
|
|
466
474
|
*/
|
|
467
475
|
resolvePage (spec, context = {}) {
|
|
468
476
|
return this.resolveResource(spec, context, 'page', ['page'])
|
|
469
477
|
}
|
|
470
478
|
|
|
479
|
+
/**
|
|
480
|
+
* Attempts to resolve a resource reference within the given context to a file in the catalog.
|
|
481
|
+
*
|
|
482
|
+
* Parses the specified resource reference (i.e., resource ID spec) into a partial resource ID,
|
|
483
|
+
* expands it using the provided context, then attempts to locate a file with that resource ID in
|
|
484
|
+
* this catalog.
|
|
485
|
+
*
|
|
486
|
+
* If a component is specified, but no version, the latest version of the component stored in the
|
|
487
|
+
* catalog is used. If a defaultFamily is not specified, the family must be specified either by
|
|
488
|
+
* the reference or the context. If permittedFamilies are stated, the family must resolve to a
|
|
489
|
+
* family in this list. If a file cannot be resolved, the function returns undefined. If the
|
|
490
|
+
* syntax of the reference is invalid, this function throws an error.
|
|
491
|
+
*
|
|
492
|
+
* @param {String} spec - The contextual resource reference (e.g., version@component:module:image$topic/image.png).
|
|
493
|
+
* @param {Object} [context={}] - The context to use to qualify the resource reference.
|
|
494
|
+
* @param {String} [defaultFamily=undefined] - The default family to use if one is not provided.
|
|
495
|
+
* @param {Array<String>} [permittedFamilies=undefined] - A list of families that are permitted.
|
|
496
|
+
*
|
|
497
|
+
* @returns {File} The virtual file to which the contextual resource reference resolves, or
|
|
498
|
+
* undefined if the file cannot be resolved.
|
|
499
|
+
*/
|
|
471
500
|
resolveResource (spec, context = {}, defaultFamily = undefined, permittedFamilies = undefined) {
|
|
472
501
|
return resolveResource(spec, this, context, defaultFamily, permittedFamilies)
|
|
473
502
|
}
|
|
@@ -509,29 +538,25 @@ function generateResourceSpec ({ component, version, module: module_, family, re
|
|
|
509
538
|
|
|
510
539
|
function prepareSrc (src) {
|
|
511
540
|
let { basename, extname, stem } = src
|
|
512
|
-
let update
|
|
513
541
|
if (basename == null) {
|
|
514
|
-
|
|
515
|
-
basename = path.basename(src.relative)
|
|
542
|
+
basename = src.basename = path.basename(src.relative)
|
|
516
543
|
}
|
|
517
544
|
if (stem == null) {
|
|
518
|
-
update = true
|
|
519
545
|
if (extname == null) {
|
|
520
546
|
if (~(extname = basename.lastIndexOf('.'))) {
|
|
521
|
-
stem = basename.substr(0, extname)
|
|
522
|
-
extname = basename.substr(extname)
|
|
547
|
+
src.stem = basename.substr(0, extname)
|
|
548
|
+
src.extname = basename.substr(extname)
|
|
523
549
|
} else {
|
|
524
|
-
stem = basename
|
|
525
|
-
extname = ''
|
|
550
|
+
src.stem = basename
|
|
551
|
+
src.extname = ''
|
|
526
552
|
}
|
|
527
553
|
} else {
|
|
528
|
-
stem = basename.substr(0, basename.length - extname.length)
|
|
554
|
+
src.stem = basename.substr(0, basename.length - extname.length)
|
|
529
555
|
}
|
|
530
556
|
} else if (extname == null) {
|
|
531
|
-
|
|
532
|
-
extname = basename.substr(stem.length)
|
|
557
|
+
src.extname = basename.substr(stem.length)
|
|
533
558
|
}
|
|
534
|
-
return
|
|
559
|
+
return src
|
|
535
560
|
}
|
|
536
561
|
|
|
537
562
|
function computeOut (src, family, versionSegment, htmlUrlExtensionStyle) {
|
|
@@ -591,7 +616,7 @@ function computePub (src, out, family, versionSegment, htmlUrlExtensionStyle) {
|
|
|
591
616
|
} else if ((url = '/' + out.path) === '/.') {
|
|
592
617
|
url = '/'
|
|
593
618
|
}
|
|
594
|
-
pub.url = ~url.indexOf(' ') ? url.
|
|
619
|
+
pub.url = ~url.indexOf(' ') ? url.replaceAll(' ', '%20') : url
|
|
595
620
|
return out ? Object.assign(pub, { moduleRootPath: out.moduleRootPath, rootPath: out.rootPath }) : pub
|
|
596
621
|
}
|
|
597
622
|
|
|
@@ -26,7 +26,6 @@ const parseResourceId = require('./parse-resource-id')
|
|
|
26
26
|
*/
|
|
27
27
|
function resolveResource (spec, catalog, ctx = {}, defaultFamily = undefined, permittedFamilies = undefined) {
|
|
28
28
|
const id = parseResourceId(spec, ctx, defaultFamily, permittedFamilies)
|
|
29
|
-
|
|
30
29
|
if (!id || !id.family) return false
|
|
31
30
|
if (id.version == null) {
|
|
32
31
|
const component = catalog.getComponent(id.component)
|
|
@@ -34,10 +33,9 @@ function resolveResource (spec, catalog, ctx = {}, defaultFamily = undefined, pe
|
|
|
34
33
|
id.version = component.latest.version
|
|
35
34
|
}
|
|
36
35
|
if (!id.module) id.module = 'ROOT'
|
|
37
|
-
|
|
38
36
|
return (
|
|
39
37
|
catalog.getById(id) ||
|
|
40
|
-
(id.family === 'page' ?
|
|
38
|
+
(id.family === 'page' ? catalog.getById(Object.assign({}, id, { family: 'alias' }))?.rel : undefined)
|
|
41
39
|
)
|
|
42
40
|
}
|
|
43
41
|
|
|
@@ -24,11 +24,8 @@ function versionCompareDesc (a, b) {
|
|
|
24
24
|
if (a && b) {
|
|
25
25
|
const semverA = resolveSemver(a)
|
|
26
26
|
const semverB = resolveSemver(b)
|
|
27
|
-
if (semverA)
|
|
28
|
-
|
|
29
|
-
} else {
|
|
30
|
-
return semverB ? -1 : -2 * a.localeCompare(b, 'en', { numeric: true })
|
|
31
|
-
}
|
|
27
|
+
if (semverA) return semverB ? -semverCompare(semverA, semverB) : 1
|
|
28
|
+
return semverB ? -1 : -2 * a.localeCompare(b, 'en', { numeric: true })
|
|
32
29
|
}
|
|
33
30
|
return a ? 1 : -1
|
|
34
31
|
}
|
|
@@ -64,23 +61,18 @@ function semverCompare (a, b) {
|
|
|
64
61
|
const numsA = a.split('.')
|
|
65
62
|
const numsB = b.split('.')
|
|
66
63
|
for (let i = 0; i < 3; i++) {
|
|
67
|
-
const numA = Number(numsA[i]
|
|
68
|
-
const numB = Number(numsB[i]
|
|
69
|
-
if (numA > numB)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return -1
|
|
73
|
-
} else if (isNaN(
|
|
74
|
-
if (!isNaN(numB)) return -1
|
|
75
|
-
} else if (isNaN(numB)) {
|
|
64
|
+
const numA = Number(numsA[i] ?? 0)
|
|
65
|
+
const numB = Number(numsB[i] ?? 0)
|
|
66
|
+
if (numA > numB) return 1
|
|
67
|
+
if (numB > numA) return -1
|
|
68
|
+
if (Number.isNaN(numA)) {
|
|
69
|
+
if (!Number.isNaN(numB)) return -1
|
|
70
|
+
} else if (Number.isNaN(numB)) {
|
|
76
71
|
return 1
|
|
77
72
|
}
|
|
78
73
|
}
|
|
79
|
-
if (preA == null)
|
|
80
|
-
|
|
81
|
-
} else {
|
|
82
|
-
return preB == null ? -1 : preA.localeCompare(preB, 'en', { numeric: true })
|
|
83
|
-
}
|
|
74
|
+
if (preA == null) return preB == null ? 0 : 1
|
|
75
|
+
return preB == null ? -1 : preA.localeCompare(preB, 'en', { numeric: true })
|
|
84
76
|
}
|
|
85
77
|
|
|
86
78
|
module.exports = versionCompareDesc
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antora/content-classifier",
|
|
3
|
-
"version": "3.2.0-alpha.
|
|
3
|
+
"version": "3.2.0-alpha.9",
|
|
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)",
|
|
@@ -10,7 +10,11 @@
|
|
|
10
10
|
"Hubert SABLONNIÈRE <hubert.sablonniere@gmail.com>"
|
|
11
11
|
],
|
|
12
12
|
"homepage": "https://antora.org",
|
|
13
|
-
"repository":
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://gitlab.com/antora/antora.git",
|
|
16
|
+
"directory": "packages/content-classifier"
|
|
17
|
+
},
|
|
14
18
|
"bugs": {
|
|
15
19
|
"url": "https://gitlab.com/antora/antora/issues"
|
|
16
20
|
},
|
|
@@ -27,8 +31,8 @@
|
|
|
27
31
|
"#constants": "./lib/constants.js"
|
|
28
32
|
},
|
|
29
33
|
"dependencies": {
|
|
30
|
-
"@antora/asciidoc-loader": "3.2.0-alpha.
|
|
31
|
-
"@antora/logger": "3.2.0-alpha.
|
|
34
|
+
"@antora/asciidoc-loader": "3.2.0-alpha.9",
|
|
35
|
+
"@antora/logger": "3.2.0-alpha.9",
|
|
32
36
|
"mime-types": "~2.1",
|
|
33
37
|
"vinyl": "~3.0"
|
|
34
38
|
},
|