fix(export): handle metadata-only notes and HTML image resources
This commit is contained in:
@@ -178,6 +178,8 @@ class _AstMapper:
|
||||
type="link", node_id=self.next_id(), attributes=attributes,
|
||||
children=self.map_inline(token.get("children", [])),
|
||||
)
|
||||
if kind == "inline_html":
|
||||
return DocumentNode(type="text", node_id=self.next_id(), text=token.get("raw", ""), attributes={"raw_html": True})
|
||||
if kind == "codespan":
|
||||
return DocumentNode(type="codespan", node_id=self.next_id(), text=token.get("raw", ""))
|
||||
if kind == "image":
|
||||
|
||||
@@ -411,12 +411,23 @@ async def preview_resources(request: ExportRequest):
|
||||
from app.export.assets import enrich_document
|
||||
from app.plot.parser import parse_source
|
||||
from app.plot.render import render_svg
|
||||
from app.export.document import Document
|
||||
from app.export.document import Document, DocumentNode
|
||||
from html.parser import HTMLParser
|
||||
markdown, _, metadata = await _resolve_source(request.source, True)
|
||||
def prepare():
|
||||
document = parse_document(markdown)
|
||||
images, plots = [], []
|
||||
class HtmlImages(HTMLParser):
|
||||
def handle_starttag(self, tag, attrs):
|
||||
if tag == 'img':
|
||||
src = dict(attrs).get('src')
|
||||
if src:
|
||||
visit(DocumentNode(type='image', node_id='html-image', attributes={'src':src}))
|
||||
def visit(node):
|
||||
if node.type == 'html_block' or node.attributes.get('raw_html'):
|
||||
parser = HtmlImages(convert_charrefs=True)
|
||||
parser.feed(node.text)
|
||||
parser.close()
|
||||
if node.type == 'image':
|
||||
warnings = enrich_document(Document(node_id='pdf-resources', children=[node]), (metadata or {}).get('file_path'), True, request.options, preserve_alpha=True)
|
||||
raw = node.attributes.get('static_png')
|
||||
|
||||
@@ -45,3 +45,25 @@ def test_browser_prints_css_without_executing_document_scripts(tmp_path):
|
||||
text=subprocess.check_output(['pdftotext',str(pdf),'-']).decode('utf-8')
|
||||
assert 'Theme Snapshot' in text
|
||||
assert 'EXECUTED' not in text
|
||||
|
||||
|
||||
@pytest.mark.parametrize('source', ['<div><IMG SRC="assets/a&b.png"></div>', 'inline <img src="assets/a&b.png"/> image'])
|
||||
def test_preview_embeds_html_images(source):
|
||||
from app.config import get_settings
|
||||
from PIL import Image
|
||||
import base64
|
||||
folder=get_settings().vault_path/'notes'/'assets'
|
||||
folder.mkdir(parents=True)
|
||||
Image.new('RGBA',(2,2),(10,20,30,128)).save(folder/'a&b.png')
|
||||
resources=asyncio.run(service.preview_resources(ExportRequest(format='pdf',source={'type':'markdown','markdown':source,'file_path':'notes/test.md'})))
|
||||
image=resources['images'][0]
|
||||
assert image['source']=='assets/a&b.png'
|
||||
assert base64.b64decode(image['data'].split(',')[1]).startswith(b'\x89PNG')
|
||||
assert image['warnings']==[]
|
||||
|
||||
|
||||
def test_html_images_keep_path_validation_and_code_is_not_an_image():
|
||||
source='<img src="../../private.png">\n\ninline <img src="https://example.com/a.png">\n\n`<img src="code.png">`\n\n```html\n<img src="fenced.png">\n```'
|
||||
resources=asyncio.run(service.preview_resources(ExportRequest(format='pdf',source={'type':'markdown','markdown':source})))
|
||||
assert [image['source'] for image in resources['images']]==['../../private.png','https://example.com/a.png']
|
||||
assert all(image['data'] is None and image['warnings'] for image in resources['images'])
|
||||
|
||||
Reference in New Issue
Block a user