Skip to content

feat(componentes): conversor reutilizable md-a-documento (Word/PDF) (#21) - #37

Open
blippip69 wants to merge 1 commit into
Bitcoindefi:mainfrom
blippip69:feat/md-a-documento
Open

feat(componentes): conversor reutilizable md-a-documento (Word/PDF) (#21)#37
blippip69 wants to merge 1 commit into
Bitcoindefi:mainfrom
blippip69:feat/md-a-documento

Conversation

@blippip69

Copy link
Copy Markdown

feat(componentes): conversor reutilizable Markdown → Word/PDF (#21)

ES

Agrega componentes/md-a-documento.py, el conversor reutilizable que pide la
issue — se termina de reescribir un script Python por cada escrito.

  • Entrada: Markdown con la convención del sistema (negritas, cursivas,
    #/##/###, listas con viñeta y numeradas).
  • Salida: .docx (python-docx, Times New Roman 12, interlineado 1.5,
    justificado, márgenes A4) y .pdf (reportlab, mismo criterio).
  • Manejo correcto de acentos y comillas tipográficas vía NFC + mapeo explícito
    (sin escapes manuales \u201c).
  • Verificación automática: extrae el texto plano del .docx generado y
    comprueba que cada bloque del .md esté presente; si falta algo, lista las
    diferencias y sale con código 2.
  • CLI: python md-a-documento.py escrito.md [--solo docx|pdf] [--out carpeta/].
  • argentina-bucles ahora lo referencia como método estándar en la entrega.

Probado end-to-end con un escrito de muestra (encabezados, negritas,
cursivas, listas numeradas/viñetas, acentos y comillas): genera ambos archivos
y la verificación pasa (VERIFICACIÓN OK). Compatible con reportlab ≥4/5
(fallback de import para el renombre de getSampleStyleSheet).

EN

Adds componentes/md-a-documento.py: a reusable Markdown → DOCX/PDF converter
with consistent styling, proper typographic quote/accent handling, and an
automatic content-verification pass that diffs the generated document against
the source markdown. argentina-bucles now references it as the standard
closing step. Tested end to end.

Comment on lines +182 to +196
def esc(text: str) -> str:
return text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")

story = []
for kind, payload in blocks:
if kind == "h1":
story.append(Paragraph(esc(payload), h1))
elif kind == "h2":
story.append(Paragraph(esc(payload), h2))
elif kind == "h3":
story.append(Paragraph(f"<b>{esc(payload)}</b>", body))
elif kind == "ul":
for item in payload:
story.append(Paragraph("\u2022 " + esc(item), body))
story.append(Spacer(1, 6))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Bug: PDF output shows literal * and instead of bold/italic

In build_pdf the text is passed through esc() only, which escapes &<> but leaves the Markdown emphasis markers untouched. Unlike build_docx (which parses */ into runs via add_runs), the PDF path never converts **texto** / *texto* into reportlab's <b>/<i> tags, so the generated PDF displays the raw asterisks and no bold/italic formatting. Convert the inline markers to tags before building each Paragraph, e.g. run esc() first then re.sub the marker pairs into <b>/<i>.

Escape XML first, then translate ** and * emphasis into reportlab <b>/<i> tags so the PDF renders formatting instead of literal asterisks.:

def esc(text: str) -> str:
    text = text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
    text = re.sub(r"\*\*(.+?)\*\*", r"<b>\1</b>", text)
    text = re.sub(r"\*(.+?)\*", r"<i>\1</i>", text)
    return text
  • Apply fix

Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎

Comment on lines +165 to +168
try:
from reportlab.lib.styles import getSampleStyleSheet as _gss
except ImportError:
from reportlab.lib.styles import get_sample_stylesheet as _gss

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Quality: reportlab fallback import references nonexistent function

The except ImportError branch imports get_sample_stylesheet, but reportlab has always exported this as getSampleStyleSheet (never a snake_case variant across v3/v4/v5). The primary import therefore always succeeds and the fallback is dead code; if it ever executed it would raise ImportError again. Drop the try/except and import getSampleStyleSheet directly.

Use the single correct import name and remove the misleading fallback.:

from reportlab.lib.styles import getSampleStyleSheet as _gss
  • Apply fix

Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎

Comment on lines +208 to +222
def verify(blocks, docx_path: Path, pdf_path: Path) -> list[str]:
"""Verificación automática: el texto plano extraído debe contener cada
bloque del .md origen (normalizado). Devuelve lista de faltantes."""
problems: list[str] = []
expected = [
normalize(line)
for line in plain_text(blocks).split("\n")
if line.strip()
]
try:
from docx import Document as _Doc

docx_text = normalize(
"\n".join(p.text for p in _Doc(str(docx_path)).paragraphs)
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Quality: verify() takes pdf_path but never checks the PDF

verify() accepts pdf_path and its docstring claims to validate the generated document, but it only extracts and compares text from the .docx; the PDF is never verified. This means a corrupt or content-incomplete PDF still yields 'VERIFICACIÓN OK'. Either drop the unused pdf_path parameter or actually extract and diff the PDF text (e.g. via pdfminer/pypdf).

Was this helpful? React with 👍 / 👎

@gitar-bot

gitar-bot Bot commented Aug 25, 2026

Copy link
Copy Markdown
Code Review ⚠️ Changes requested 0 resolved / 3 findings

Adds a reusable Markdown to Word/PDF converter component, but the PDF build outputs literal markdown markers, the reportlab fallback import references a nonexistent function, and the verification step ignores the PDF output entirely.

⚠️ Bug: PDF output shows literal * and instead of bold/italic

📄 componentes/md-a-documento.py:182-196

In build_pdf the text is passed through esc() only, which escapes &<> but leaves the Markdown emphasis markers untouched. Unlike build_docx (which parses */ into runs via add_runs), the PDF path never converts **texto** / *texto* into reportlab's <b>/<i> tags, so the generated PDF displays the raw asterisks and no bold/italic formatting. Convert the inline markers to tags before building each Paragraph, e.g. run esc() first then re.sub the marker pairs into <b>/<i>.

Escape XML first, then translate ** and * emphasis into reportlab <b>/<i> tags so the PDF renders formatting instead of literal asterisks.
def esc(text: str) -> str:
    text = text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
    text = re.sub(r"\*\*(.+?)\*\*", r"<b>\1</b>", text)
    text = re.sub(r"\*(.+?)\*", r"<i>\1</i>", text)
    return text
💡 Quality: reportlab fallback import references nonexistent function

📄 componentes/md-a-documento.py:165-168

The except ImportError branch imports get_sample_stylesheet, but reportlab has always exported this as getSampleStyleSheet (never a snake_case variant across v3/v4/v5). The primary import therefore always succeeds and the fallback is dead code; if it ever executed it would raise ImportError again. Drop the try/except and import getSampleStyleSheet directly.

Use the single correct import name and remove the misleading fallback.
from reportlab.lib.styles import getSampleStyleSheet as _gss
💡 Quality: verify() takes pdf_path but never checks the PDF

📄 componentes/md-a-documento.py:208-222 📄 componentes/md-a-documento.py:262-263

verify() accepts pdf_path and its docstring claims to validate the generated document, but it only extracts and compares text from the .docx; the PDF is never verified. This means a corrupt or content-incomplete PDF still yields 'VERIFICACIÓN OK'. Either drop the unused pdf_path parameter or actually extract and diff the PDF text (e.g. via pdfminer/pypdf).

🤖 Prompt for agents
Code Review: Adds a reusable Markdown to Word/PDF converter component, but the PDF build outputs literal markdown markers, the reportlab fallback import references a nonexistent function, and the verification step ignores the PDF output entirely.

1. ⚠️ Bug: PDF output shows literal ** and * instead of bold/italic
   Files: componentes/md-a-documento.py:182-196

   In build_pdf the text is passed through esc() only, which escapes &<> but leaves the Markdown emphasis markers untouched. Unlike build_docx (which parses **/* into runs via add_runs), the PDF path never converts `**texto**` / `*texto*` into reportlab's `<b>`/`<i>` tags, so the generated PDF displays the raw asterisks and no bold/italic formatting. Convert the inline markers to tags before building each Paragraph, e.g. run esc() first then re.sub the marker pairs into <b>/<i>.

   Fix (Escape XML first, then translate ** and * emphasis into reportlab <b>/<i> tags so the PDF renders formatting instead of literal asterisks.):
   def esc(text: str) -> str:
       text = text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
       text = re.sub(r"\*\*(.+?)\*\*", r"<b>\1</b>", text)
       text = re.sub(r"\*(.+?)\*", r"<i>\1</i>", text)
       return text

2. 💡 Quality: reportlab fallback import references nonexistent function
   Files: componentes/md-a-documento.py:165-168

   The except ImportError branch imports `get_sample_stylesheet`, but reportlab has always exported this as `getSampleStyleSheet` (never a snake_case variant across v3/v4/v5). The primary import therefore always succeeds and the fallback is dead code; if it ever executed it would raise ImportError again. Drop the try/except and import getSampleStyleSheet directly.

   Fix (Use the single correct import name and remove the misleading fallback.):
   from reportlab.lib.styles import getSampleStyleSheet as _gss

3. 💡 Quality: verify() takes pdf_path but never checks the PDF
   Files: componentes/md-a-documento.py:208-222, componentes/md-a-documento.py:262-263

   verify() accepts pdf_path and its docstring claims to validate the generated document, but it only extracts and compares text from the .docx; the PDF is never verified. This means a corrupt or content-incomplete PDF still yields 'VERIFICACIÓN OK'. Either drop the unused pdf_path parameter or actually extract and diff the PDF text (e.g. via pdfminer/pypdf).

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Important

Your trial ends in 7 days — upgrade now to keep code review, CI analysis, auto-apply, custom automations, and more.

Was this helpful? React with 👍 / 👎 | Gitar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant