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