From 4433cf0d87b41697251afa1991a47cfc456f1049 Mon Sep 17 00:00:00 2001 From: Andreas Nef Date: Wed, 19 Aug 2026 14:08:24 +0200 Subject: [PATCH 1/5] fix to make internal links work --- fix-links.lua | 20 +++++++++++++------- md2pdf.sh | 9 +++++---- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/fix-links.lua b/fix-links.lua index baa81ae..051356a 100644 --- a/fix-links.lua +++ b/fix-links.lua @@ -1,14 +1,20 @@ --- Created with using Google Gemini AI function Link(el) - if el.target:match("%.md$") or el.target:match("%.md#") then - local base = el.target:gsub("%.md", "") - if not base:match("^#") then - el.target = "#" .. base:gsub(".*/", "") - else - el.target = base - end + local path, fragment = el.target:match("^([^#]+)%.md#(.+)$") + if path and fragment then + -- Keep explicit section fragments from cross-file links. + el.target = "#" .. fragment + return el end + + local only_path = el.target:match("^([^#]+)%.md$") + if only_path then + -- Resolve file links to the first-header anchor injected by add-anchor.lua. + el.target = "#" .. only_path:gsub(".*/", "") + return el + end + return el end diff --git a/md2pdf.sh b/md2pdf.sh index 06259cb..f1266c8 100755 --- a/md2pdf.sh +++ b/md2pdf.sh @@ -1,10 +1,11 @@ #!/bin/bash SOFFICE_PATH='/Applications/LibreOffice.app/Contents/MacOS/soffice' -mkdir ./mets-tmp +mkdir -p ./mets-tmp find ./METS-guide -iname "*.md" -type f -exec sh -c 'pandoc --lua-filter=add-anchor.lua -f gfm+yaml_metadata_block -t markdown "${0}" -o "./mets-tmp/${0%}"' {} \; -pandoc --lua-filter=include-files.lua --lua-filter=fix-links.lua -f markdown -t markdown chapter-builder.md > ./mets-tmp/mets-combined.md +# Build from the preprocessed copies so inserted file anchors are present. +sed 's#\./METS-guide/#./mets-tmp/./METS-guide/#g' chapter-builder.md | \ + pandoc --lua-filter=include-files.lua --lua-filter=fix-links.lua -f markdown -t markdown > ./mets-tmp/mets-combined.md pandoc --number-sections --reference-doc=template.docx -f markdown -t docx ./mets-tmp/mets-combined.md > ./mets-tmp/mets-combined.docx $SOFFICE_PATH --headless --convert-to pdf ./mets-tmp/mets-combined.docx -rm -rf ./mets-tmp - +#rm -rf ./mets-tmp From 1511f7355a1dc1835a8dd00b0de61eef8348da12 Mon Sep 17 00:00:00 2001 From: Andreas Nef Date: Wed, 19 Aug 2026 14:52:42 +0200 Subject: [PATCH 2/5] adjust how-to title levels --- chapter-builder.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapter-builder.md b/chapter-builder.md index 59b419b..cd77f62 100644 --- a/chapter-builder.md +++ b/chapter-builder.md @@ -36,7 +36,7 @@ ./METS-guide/mets_howtos.md ``` -``` {.include shift-heading-level-by=1} +``` {.include shift-heading-level-by=2} ./METS-guide/howto/altRecordID.md ./METS-guide/howto/agent.md ./METS-guide/howto/md.md From 5fadcbc262dabd9549f9a796f85f30fbb75e3059 Mon Sep 17 00:00:00 2001 From: Andreas Nef Date: Thu, 20 Aug 2026 08:39:42 +0200 Subject: [PATCH 3/5] de-duplicate header identifiers --- dedupe-header-ids.lua | 30 ++++++++++++++++++++++++++++++ md2pdf.sh | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 dedupe-header-ids.lua diff --git a/dedupe-header-ids.lua b/dedupe-header-ids.lua new file mode 100644 index 0000000..c1a636c --- /dev/null +++ b/dedupe-header-ids.lua @@ -0,0 +1,30 @@ +-- Ensure header identifiers are unique across the merged document. +-- Keep the original identifier if available, otherwise append a numeric suffix. + +local used = {} + +local function next_unique_id(base) + if not used[base] then + return base + end + + local n = 2 + local candidate = base .. '-' .. tostring(n) + while used[candidate] do + n = n + 1 + candidate = base .. '-' .. tostring(n) + end + return candidate +end + +function Header(h) + local id = h.identifier + if not id or id == '' then + return h + end + + local unique = next_unique_id(id) + used[unique] = true + h.identifier = unique + return h +end diff --git a/md2pdf.sh b/md2pdf.sh index f1266c8..3828977 100755 --- a/md2pdf.sh +++ b/md2pdf.sh @@ -5,7 +5,7 @@ mkdir -p ./mets-tmp find ./METS-guide -iname "*.md" -type f -exec sh -c 'pandoc --lua-filter=add-anchor.lua -f gfm+yaml_metadata_block -t markdown "${0}" -o "./mets-tmp/${0%}"' {} \; # Build from the preprocessed copies so inserted file anchors are present. sed 's#\./METS-guide/#./mets-tmp/./METS-guide/#g' chapter-builder.md | \ - pandoc --lua-filter=include-files.lua --lua-filter=fix-links.lua -f markdown -t markdown > ./mets-tmp/mets-combined.md + pandoc --lua-filter=include-files.lua --lua-filter=dedupe-header-ids.lua --lua-filter=fix-links.lua -f markdown -t markdown > ./mets-tmp/mets-combined.md pandoc --number-sections --reference-doc=template.docx -f markdown -t docx ./mets-tmp/mets-combined.md > ./mets-tmp/mets-combined.docx $SOFFICE_PATH --headless --convert-to pdf ./mets-tmp/mets-combined.docx #rm -rf ./mets-tmp From dafb03eae5f97a8b7f698b5424cef42526abb843 Mon Sep 17 00:00:00 2001 From: Andreas Nef Date: Thu, 20 Aug 2026 08:48:09 +0200 Subject: [PATCH 4/5] add chapter handling for how-to section --- chapter-builder.md | 36 ------------ expand-howtos.lua | 140 +++++++++++++++++++++++++++++++++++++++++++++ md2pdf.sh | 2 +- 3 files changed, 141 insertions(+), 37 deletions(-) create mode 100644 expand-howtos.lua diff --git a/chapter-builder.md b/chapter-builder.md index cd77f62..077c65b 100644 --- a/chapter-builder.md +++ b/chapter-builder.md @@ -36,42 +36,6 @@ ./METS-guide/mets_howtos.md ``` -``` {.include shift-heading-level-by=2} -./METS-guide/howto/altRecordID.md -./METS-guide/howto/agent.md -./METS-guide/howto/md.md -./METS-guide/howto/binary_marc.md -./METS-guide/howto/premis.md -./METS-guide/howto/source_metadata.md -./METS-guide/howto/mods.md -./METS-guide/howto/mets_rights.md -./METS-guide/howto/technical_metadata.md -./METS-guide/howto/mdRef.md -./METS-guide/howto/mdWrap.md -./METS-guide/howto/file.md -./METS-guide/howto/fileSec_example_audio.md -./METS-guide/howto/fileSec_example_images.md -./METS-guide/howto/fileGrp.md -./METS-guide/howto/transformFile.md -./METS-guide/howto/stream.md -./METS-guide/howto/FLocat.md -./METS-guide/howto/FContent.md -./METS-guide/howto/xmlData.md -./METS-guide/howto/binData.md -./METS-guide/howto/mptr.md -./METS-guide/howto/fptr.md -./METS-guide/howto/idref_namespaces.md -./METS-guide/howto/area.md -./METS-guide/howto/locref.md -./METS-guide/howto/seq.md -./METS-guide/howto/par.md -./METS-guide/howto/external_idref.md -./METS-guide/howto/idrefs_within_mets.md -./METS-guide/howto/begin_end_betype.md -./METS-guide/howto/id_idrefs.md -./METS-guide/howto/div.md -``` - ``` {.include} ./METS-guide/external_schema_vocabulary.md ./METS-guide/mets_profiles.md diff --git a/expand-howtos.lua b/expand-howtos.lua new file mode 100644 index 0000000..41cda84 --- /dev/null +++ b/expand-howtos.lua @@ -0,0 +1,140 @@ +-- Expand linked how-to pages under each H2 in the METS How-Tos chapter. + +local stringify = (require 'pandoc.utils').stringify +local List = require 'pandoc.List' + +local function slugify(text) + local s = text:lower() + s = s:gsub('[^%w%s-]', '') + s = s:gsub('%s+', '-') + s = s:gsub('%-+', '-') + s = s:gsub('^%-', ''):gsub('%-$', '') + return s +end + +local function build_h2_index(index_items) + local list_items = List:new() + for _, item in ipairs(index_items) do + local link = pandoc.Link(item.title, '#' .. item.id) + list_items:insert({ pandoc.Plain({ link }) }) + end + + return List:new({ + pandoc.Para({ pandoc.Strong({ pandoc.Str('Index') }) }), + pandoc.BulletList(list_items) + }) +end + +local function shift_headings(blocks, shift_by) + local filter = { + Header = function(h) + h.level = h.level + shift_by + return h + end + } + return pandoc.walk_block(pandoc.Div(blocks), filter).content +end + +local function collect_links_from_bullet_list(bullet_list) + local links = List:new() + + for _, item in ipairs(bullet_list.content) do + for _, blk in ipairs(item) do + if blk.t == 'Plain' or blk.t == 'Para' then + for _, inline in ipairs(blk.content) do + if inline.t == 'Link' and inline.target and inline.target:match('%.md$') then + links:insert(inline.target) + end + end + end + end + end + + return links +end + +local function read_markdown_file(path) + local fh = io.open(path) + if not fh then + io.stderr:write('Cannot open howto file ' .. path .. '\n') + return {} + end + + local src = fh:read('*a') + fh:close() + + local parsed = pandoc.read(src, 'markdown', PANDOC_READER_OPTIONS) + return parsed.blocks +end + +function Pandoc(doc) + local blocks = doc.blocks + local out = List:new() + + local howto_h2_index = List:new() + local collecting = false + for _, b in ipairs(blocks) do + if b.t == 'Header' and b.level == 1 then + collecting = (stringify(b.content) == 'METS How-Tos') + elseif collecting and b.t == 'Header' and b.level == 2 then + local title = stringify(b.content) + local id = b.identifier + if not id or id == '' then + id = slugify(title) + end + howto_h2_index:insert({ title = title, id = id }) + elseif collecting and b.t == 'Header' and b.level == 1 then + collecting = false + end + end + + local in_howtos = false + local index_inserted = false + local i = 1 + + while i <= #blocks do + local b = blocks[i] + + if b.t == 'Header' and b.level == 1 then + in_howtos = (stringify(b.content) == 'METS How-Tos') + out:insert(b) + i = i + 1 + elseif in_howtos and b.t == 'Header' and b.level == 2 then + if not index_inserted and #howto_h2_index > 0 then + out:extend(build_h2_index(howto_h2_index)) + index_inserted = true + end + + out:insert(b) + + local j = i + 1 + local section_links = List:new() + + while j <= #blocks do + local nxt = blocks[j] + if nxt.t == 'Header' and nxt.level <= 2 then + break + end + + out:insert(nxt) + if nxt.t == 'BulletList' then + section_links:extend(collect_links_from_bullet_list(nxt)) + end + j = j + 1 + end + + for _, link_target in ipairs(section_links) do + local included = read_markdown_file(link_target) + out:extend(shift_headings(included, 2)) + end + + i = j + else + out:insert(b) + i = i + 1 + end + end + + doc.blocks = out + return doc +end diff --git a/md2pdf.sh b/md2pdf.sh index 3828977..00ee82b 100755 --- a/md2pdf.sh +++ b/md2pdf.sh @@ -5,7 +5,7 @@ mkdir -p ./mets-tmp find ./METS-guide -iname "*.md" -type f -exec sh -c 'pandoc --lua-filter=add-anchor.lua -f gfm+yaml_metadata_block -t markdown "${0}" -o "./mets-tmp/${0%}"' {} \; # Build from the preprocessed copies so inserted file anchors are present. sed 's#\./METS-guide/#./mets-tmp/./METS-guide/#g' chapter-builder.md | \ - pandoc --lua-filter=include-files.lua --lua-filter=dedupe-header-ids.lua --lua-filter=fix-links.lua -f markdown -t markdown > ./mets-tmp/mets-combined.md + pandoc --lua-filter=include-files.lua --lua-filter=expand-howtos.lua --lua-filter=dedupe-header-ids.lua --lua-filter=fix-links.lua -f markdown -t markdown > ./mets-tmp/mets-combined.md pandoc --number-sections --reference-doc=template.docx -f markdown -t docx ./mets-tmp/mets-combined.md > ./mets-tmp/mets-combined.docx $SOFFICE_PATH --headless --convert-to pdf ./mets-tmp/mets-combined.docx #rm -rf ./mets-tmp From c66496d8cacc605c37e6a4321fedc32b491107fa Mon Sep 17 00:00:00 2001 From: Andreas Nef Date: Thu, 20 Aug 2026 08:48:41 +0200 Subject: [PATCH 5/5] add .gitignore for temp directory and output --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8a33b88 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +mets-combined.pdf +mets-tmp/