2
2
Copyright 2019-2022 DataRobot, Inc. and its affiliates.
3
3
All rights reserved.
4
4
"""
5
- import logging
5
+ from __future__ import annotations
6
+
6
7
import os
7
8
import posixpath
9
+ from typing import TypedDict
8
10
9
11
from mkdocs import utils
10
12
from mkdocs .config import config_options
13
15
14
16
log = get_plugin_logger (__name__ )
15
17
18
+
16
19
def gen_anchor_redirects (anchor_list : list ):
17
20
"""
18
21
Generate a dictionary of redirects for anchors.
19
22
20
23
:param anchor_list: A list of tuples containing old anchors and new links.
21
24
:return: A string of JavaScript redirects for the anchors.
22
25
"""
23
- js_redirects = ''
26
+ js_redirects = ""
24
27
for old_anchor , new_link in anchor_list :
25
28
# Create a JavaScript redirect for each anchor
26
29
js_redirects += f"""
@@ -59,7 +62,7 @@ def gen_anchor_redirects(anchor_list: list):
59
62
"""
60
63
61
64
62
- def write_html (site_dir , old_path , new_path , anchor_list ):
65
+ def write_html (site_dir : str , old_path : str , new_path : str , anchor_list : list [ tuple [ str , str ]] ):
63
66
"""Write an HTML file in the site_dir with a meta redirect to the new page"""
64
67
# Determine all relevant paths
65
68
old_path_abs = os .path .join (site_dir , old_path )
@@ -97,12 +100,38 @@ def get_html_path(path, use_directory_urls):
97
100
return f .dest_path .replace (os .sep , "/" )
98
101
99
102
103
+ class RedirectEntry (TypedDict ):
104
+ hashes : list [tuple [str , str ]]
105
+ overall : str
106
+
107
+
108
+ def build_redirect_entries (redirects : dict ):
109
+ redirect_entries : dict [str , RedirectEntry ] = {}
110
+ for page_old , page_new in redirects .items ():
111
+ page_old_without_hash , old_hash = _split_hash_fragment (str (page_old ))
112
+ if page_old_without_hash not in redirect_entries :
113
+ redirect_entries [page_old_without_hash ] = {"hashes" : [], "overall" : "" }
114
+ if old_hash == "" :
115
+ redirect_entries [page_old_without_hash ]["overall" ] = page_new
116
+ else :
117
+ redirect_entries [page_old_without_hash ]["hashes" ].append ((old_hash , page_new ))
118
+
119
+ # If a page doesn't have an overall redirect, use the first hash redirect
120
+ for page_old , redirect_map in redirect_entries .items ():
121
+ if redirect_map .get ("overall" , "" ) == "" :
122
+ redirect_entries [page_old ]["overall" ] = redirect_map ["hashes" ][0 ][1 ]
123
+
124
+ return redirect_entries
125
+
126
+
100
127
class RedirectPlugin (BasePlugin ):
101
128
# Any options that this plugin supplies should go here.
102
129
config_scheme = (
103
130
("redirect_maps" , config_options .Type (dict , default = {})), # note the trailing comma
104
131
)
105
132
133
+ redirect_entries : dict [str , RedirectEntry ] = {}
134
+
106
135
# Build a list of redirects on file generation
107
136
def on_files (self , files , config , ** kwargs ):
108
137
self .redirects = self .config .get ("redirect_maps" , {})
@@ -111,59 +140,51 @@ def on_files(self, files, config, **kwargs):
111
140
for page_old in self .redirects :
112
141
page_old_without_hash , _ = _split_hash_fragment (str (page_old ))
113
142
if not utils .is_markdown_file (page_old_without_hash ):
114
- log .warning ("redirects plugin: '%s' is not a valid markdown file!" , page_old_without_hash )
143
+ log .warning (
144
+ "redirects plugin: '%s' is not a valid markdown file!" , page_old_without_hash
145
+ )
115
146
116
147
# Build a dict of known document pages to validate against later
117
148
self .doc_pages = {}
118
149
for page in files .documentation_pages (): # object type: mkdocs.structure.files.File
119
150
self .doc_pages [page .src_path .replace (os .sep , "/" )] = page
120
151
121
152
# Create a dictionary to hold anchor maps for redirects
122
- redirect_maps = {}
123
- for page_old , page_new in self .redirects .items ():
124
- page_old_without_hash , old_hash = _split_hash_fragment (str (page_old ))
125
- if page_old_without_hash not in redirect_maps :
126
- redirect_maps [page_old_without_hash ] = {'hashes' : []}
127
- if old_hash == "" :
128
- redirect_maps [page_old_without_hash ]['overall' ] = page_new
129
- else :
130
- redirect_maps [page_old_without_hash ]['hashes' ].append ((old_hash , page_new ))
131
153
132
- # If a page doesn't have an overall redirect, use the first hash redirect
133
- for page_old , redirect_map in redirect_maps .items ():
134
- if 'overall' not in redirect_map :
135
- redirect_maps [page_old ]['overall' ] = redirect_map ['hashes' ][0 ][1 ]
136
-
137
- self .redirect_maps = redirect_maps
154
+ self .redirect_entries = build_redirect_entries (self .redirects )
138
155
139
156
def on_page_content (self , html , page , config , files ):
140
157
use_directory_urls = config .get ("use_directory_urls" )
141
158
page_old = page .file .src_uri
142
- if page_old not in self .redirect_maps :
159
+ if page_old not in self .redirect_entries :
143
160
return html
144
161
145
- # Fixup redirect_maps to use the correct path
146
- for i in range (len (self .redirect_maps [page_old ][' hashes' ])):
147
- old_hash , new_link = self .redirect_maps [page_old ][' hashes' ][i ]
162
+ # Fixup redirect_entries to use the correct path
163
+ for i in range (len (self .redirect_entries [page_old ][" hashes" ])):
164
+ old_hash , new_link = self .redirect_entries [page_old ][" hashes" ][i ]
148
165
hash_redirect_without_hash , new_hash = _split_hash_fragment (str (new_link ))
149
166
if hash_redirect_without_hash in self .doc_pages :
150
167
file = self .doc_pages [hash_redirect_without_hash ]
151
- dest_hash_path = get_relative_html_path (page_old , file .url + new_hash , use_directory_urls )
152
- self .redirect_maps [page_old ]['hashes' ][i ] = (old_hash , dest_hash_path )
168
+ dest_hash_path = get_relative_html_path (
169
+ page_old , file .url + new_hash , use_directory_urls
170
+ )
171
+ self .redirect_entries [page_old ]["hashes" ][i ] = (old_hash , dest_hash_path )
153
172
154
- for old_hash , new_link in self .redirect_maps [page_old ][' hashes' ]:
173
+ for old_hash , new_link in self .redirect_entries [page_old ][" hashes" ]:
155
174
log .info (f"Injecting redirect for '{ page_old } { old_hash } ' to '{ new_link } '" )
156
175
157
- js_redirects = JS_INJECT_EXISTS .format (redirects = gen_anchor_redirects (self .redirect_maps [page_old ]['hashes' ]))
176
+ js_redirects = JS_INJECT_EXISTS .format (
177
+ redirects = gen_anchor_redirects (self .redirect_entries [page_old ]["hashes" ])
178
+ )
158
179
return js_redirects + html
159
180
160
181
# Create HTML files for redirects after site dir has been built
161
182
def on_post_build (self , config , ** kwargs ):
162
183
# Determine if 'use_directory_urls' is set
163
184
use_directory_urls = config .get ("use_directory_urls" )
164
- for page_old , redirect_maps in self .redirect_maps .items ():
185
+ for page_old , redirect_entry in self .redirect_entries .items ():
165
186
# Need to remove hash fragment from new page to verify existence
166
- page_new = redirect_maps [ ' overall' ]
187
+ page_new = redirect_entry [ " overall" ]
167
188
page_old_without_hash , _ = _split_hash_fragment (str (page_old ))
168
189
page_new_without_hash , new_hash = _split_hash_fragment (str (page_new ))
169
190
@@ -174,37 +195,41 @@ def on_post_build(self, config, **kwargs):
174
195
# If the redirect target is a valid internal page, we need to create a relative path
175
196
elif page_new_without_hash in self .doc_pages :
176
197
file = self .doc_pages [page_new_without_hash ]
177
- dest_path = get_relative_html_path (page_old , file .url + new_hash , use_directory_urls )
198
+ dest_path = get_relative_html_path (
199
+ page_old , file .url + new_hash , use_directory_urls
200
+ )
178
201
179
202
# If the redirect target isn't external or a valid internal page, throw an error
180
203
# Note: we use 'warn' here specifically; mkdocs treats warnings specially when in strict mode
181
204
else :
182
205
log .warning ("Redirect target '%s' does not exist!" , page_new )
183
206
continue
184
207
185
- # Fixup redirect_maps to use the correct path
186
- for i in range (len (redirect_maps [ ' hashes' ])):
187
- old_hash , new_link = redirect_maps [ ' hashes' ][i ]
208
+ # Fixup redirect_entry to use the correct path
209
+ for i in range (len (redirect_entry [ " hashes" ])):
210
+ old_hash , new_link = redirect_entry [ " hashes" ][i ]
188
211
hash_redirect_without_hash , new_hash = _split_hash_fragment (str (new_link ))
189
212
if hash_redirect_without_hash in self .doc_pages :
190
213
file = self .doc_pages [hash_redirect_without_hash ]
191
- dest_hash_path = get_relative_html_path (page_old , file .url + new_hash , use_directory_urls )
192
- redirect_maps ['hashes' ][i ] = (old_hash , dest_hash_path )
214
+ dest_hash_path = get_relative_html_path (
215
+ page_old , file .url + new_hash , use_directory_urls
216
+ )
217
+ redirect_entry ["hashes" ][i ] = (old_hash , dest_hash_path )
193
218
194
219
if page_old_without_hash in self .doc_pages :
195
220
# If the old page is a valid document page, it was injected in `on_page_content`.
196
221
pass
197
222
else :
198
223
log .info (f"Creating redirect for '{ page_old } ' to '{ dest_path } '" )
199
- for old_hash , new_link in redirect_maps [ ' hashes' ]:
224
+ for old_hash , new_link in redirect_entry [ " hashes" ]:
200
225
log .info (f"Creating redirect for '{ page_old } { old_hash } ' to '{ new_link } '" )
201
226
# Otherwise, create a new HTML file for the redirect
202
227
dest_path = get_relative_html_path (page_old , dest_path , use_directory_urls )
203
228
write_html (
204
229
config ["site_dir" ],
205
230
get_html_path (page_old , use_directory_urls ),
206
231
dest_path ,
207
- redirect_maps [ ' hashes' ],
232
+ redirect_entry [ " hashes" ],
208
233
)
209
234
210
235
0 commit comments