44from typing import TypeAlias
55from typing import TypeGuard
66
7+ import json
8+ from pyld import jsonld
9+
710import mistune
811from mistune import BlockState
912from mistune .plugins .abbr import abbr
@@ -149,9 +152,96 @@ def is_blurry_renderer(
149152 + [plugin .load () for plugin in discovered_markdown_plugins ],
150153)
151154
155+ SCHEMA_ORG = json .loads ('{ "@vocab": "https://schema.org/" }' )
156+ def jsonld_document_loader (secure = False , fragments = [], ** kwargs ):
157+ """
158+ Create a Requests document loader.
159+
160+ Can be used to setup extra Requests args such as verify, cert, timeout,
161+ or others.
162+
163+ :param secure: require all requests to use HTTPS (default: False).
164+ :param fragments: the fragments of schema loaded as dicts
165+ :param **kwargs: extra keyword args for Requests get() call.
166+
167+ :return: the RemoteDocument loader function.
168+ """
169+ from pyld .jsonld import JsonLdError
170+
171+ def loader (ignored , options = {}):
172+ """
173+ Retrieves JSON-LD from the dicts provided as fragments.
174+
175+ :param ignored: this positional paramter is ignored, because the tomls fragments are side loaded
176+
177+ :return: the RemoteDocument.
178+ """
179+ fragments_str = []
180+ for fragment in fragments :
181+ if not fragment .get ('@context' ):
182+ fragment ['@context' ] = SCHEMA_ORG
183+ fragments_str .append (json .dumps (fragment ))
184+ # print("==========================")
185+ # print(json.dumps(fragment, indent=2))
186+
187+ result = '[' + ',' .join (fragments_str ) + ']'
188+ # print(">>>>>>>>> ",result)
189+
190+ doc = {
191+ 'contentType' : 'application/ld+json' ,
192+ 'contextUrl' : None ,
193+ 'documentUrl' : None ,
194+ 'document' : result
195+ }
196+ return doc
152197
153- def convert_markdown_file_to_html (filepath : Path ) -> tuple [str , dict [str , Any ]]:
198+ return loader
199+
200+ def add_inferred_schema (local_front_matter : dict , filepath : Path ) -> dict :
154201 CONTENT_DIR = get_content_directory ()
202+
203+ # Add inferred/computed/relative values
204+ local_front_matter .update ({"url" : content_path_to_url (filepath .relative_to (CONTENT_DIR ))})
205+
206+ # Add inferred/computed/relative values
207+ # https://schema.org/image
208+ # https://schema.org/thumbnailUrl
209+ if image := front_matter .get ("image" ):
210+ image_copy = deepcopy (image )
211+ relative_image_path = get_relative_image_path_from_image_property (image_copy )
212+ image_path = resolve_relative_path_in_markdown (relative_image_path , filepath )
213+ front_matter ["image" ] = update_image_with_url (image_copy , image_path )
214+ front_matter ["thumbnailUrl" ] = image_path_to_thumbnailUrl (image_path )
215+
216+ return local_front_matter
217+
218+ def resolve_front_matter (state : dict , filepath : Path ) -> tuple [dict [str , Any ], str ]:
219+ if SETTINGS .get ("FRONT_MATTER_RESOLUTION" ) == "merge" :
220+ try :
221+ global_schema = dict (SETTINGS .get ("SCHEMA_DATA" , {}))
222+ if not global_schema .get ('@context' ):
223+ global_schema ['@context' ] = SCHEMA_ORG
224+
225+ local_schema = state .env .get ("front_matter" , {})
226+ top_level_type = local_schema .get ("@type" , None )
227+ if not local_schema .get ('@context' ):
228+ local_schema ['@context' ] = SCHEMA_ORG
229+ local_schema = add_inferred_schema (local_schema , filepath )
230+ jsonld .set_document_loader (jsonld_document_loader (fragments = [global_schema , local_schema ]))
231+ front_matter : dict [str , Any ] = jsonld .compact ("ignore" , SCHEMA_ORG )
232+ except Exception as e :
233+ print ("merging front matter failed:" , e )
234+ raise e
235+ else :
236+ # Seed front_matter with schema_data from config file
237+ front_matter : dict [str , Any ] = dict (SETTINGS .get ("SCHEMA_DATA" , {}))
238+ front_matter .update (state .env .get ("front_matter" , {}))
239+ front_matter = add_inferred_schema (front_matter , filepath )
240+
241+ top_level_type = None
242+ return front_matter , top_level_type
243+
244+ def convert_markdown_file_to_html (filepath : Path ) -> tuple [str , dict [str , Any ], str ]:
155245 if not markdown .renderer :
156246 raise Exception ("Blurry markdown renderer not set on Mistune Markdown instance" )
157247
@@ -167,26 +257,13 @@ def convert_markdown_file_to_html(filepath: Path) -> tuple[str, dict[str, Any]]:
167257 html , state = markdown .parse (markdown_text , state = state )
168258
169259 if not is_str (html ):
170- raise Exception (f"Expected html to be a string but got: { type (html )} " )
260+ raise Exception (f"Expected html to be a string but got: { top_level_type (html )} " )
171261
172262 # Post-process HTML
173263 html = remove_lazy_loading_from_first_image (html )
174264
175- # Seed front_matter with schema_data from config file
176- front_matter : dict [str , Any ] = dict (SETTINGS .get ("SCHEMA_DATA" , {}))
177- front_matter .update (state .env .get ("front_matter" , {}))
178-
179- # Add inferred/computed/relative values
180- # https://schema.org/image
181- # https://schema.org/thumbnailUrl
182- front_matter .update ({"url" : content_path_to_url (filepath .relative_to (CONTENT_DIR ))})
183- if image := front_matter .get ("image" ):
184- image_copy = deepcopy (image )
185- relative_image_path = get_relative_image_path_from_image_property (image_copy )
186- image_path = resolve_relative_path_in_markdown (relative_image_path , filepath )
187- front_matter ["image" ] = update_image_with_url (image_copy , image_path )
188- front_matter ["thumbnailUrl" ] = image_path_to_thumbnailUrl (image_path )
189- return html , front_matter
265+ front_matter , top_level_type = resolve_front_matter (state , filepath )
266+ return html , front_matter , top_level_type
190267
191268
192269def image_path_to_thumbnailUrl (image_path : Path ):
0 commit comments