confpub-cli 1.7.1__tar.gz → 1.7.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/PKG-INFO +1 -1
  2. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/__init__.py +1 -1
  3. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/reverse_converter.py +15 -7
  4. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_reverse_converter.py +44 -0
  5. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/.github/copilot-instructions.md +0 -0
  6. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/.github/workflows/publish.yml +0 -0
  7. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/.gitignore +0 -0
  8. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/CLAUDE.md +0 -0
  9. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/LICENSE +0 -0
  10. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/PRD.md +0 -0
  11. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/README.md +0 -0
  12. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/applier.py +0 -0
  13. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/assets.py +0 -0
  14. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/cli.py +0 -0
  15. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/config.py +0 -0
  16. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/confluence.py +0 -0
  17. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/converter.py +0 -0
  18. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/envelope.py +0 -0
  19. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/errors.py +0 -0
  20. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/front_matter.py +0 -0
  21. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/guide.py +0 -0
  22. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/lockfile.py +0 -0
  23. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/macro_plugin.py +0 -0
  24. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/manifest.py +0 -0
  25. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/output.py +0 -0
  26. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/planner.py +0 -0
  27. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/publish.py +0 -0
  28. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/puller.py +0 -0
  29. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/py.typed +0 -0
  30. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/validator.py +0 -0
  31. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub/verifier.py +0 -0
  32. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/confpub.lock +0 -0
  33. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/pyproject.toml +0 -0
  34. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/__init__.py +0 -0
  35. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/conftest.py +0 -0
  36. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_applier.py +0 -0
  37. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_assets.py +0 -0
  38. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_config.py +0 -0
  39. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_confluence.py +0 -0
  40. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_converter.py +0 -0
  41. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_envelope.py +0 -0
  42. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_errors.py +0 -0
  43. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_front_matter.py +0 -0
  44. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_guide.py +0 -0
  45. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_integration.py +0 -0
  46. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_lockfile.py +0 -0
  47. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_macro_plugin.py +0 -0
  48. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_manifest.py +0 -0
  49. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_output.py +0 -0
  50. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_planner.py +0 -0
  51. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_publish.py +0 -0
  52. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_puller.py +0 -0
  53. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_validator.py +0 -0
  54. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/tests/test_verifier.py +0 -0
  55. {confpub_cli-1.7.1 → confpub_cli-1.7.2}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: confpub-cli
3
- Version: 1.7.1
3
+ Version: 1.7.2
4
4
  Summary: Agent-first CLI to publish Markdown to Confluence
5
5
  Project-URL: Homepage, https://github.com/ThomasRohde/confpub-cli
6
6
  Project-URL: Repository, https://github.com/ThomasRohde/confpub-cli.git
@@ -1,3 +1,3 @@
1
1
  """confpub — Agent-first CLI to publish Markdown to Confluence."""
2
2
 
3
- __version__ = "1.7.1"
3
+ __version__ = "1.7.2"
@@ -452,14 +452,18 @@ def _preprocess_storage_format(html: str) -> tuple[BeautifulSoup, list[str]]:
452
452
  if next_sib and next_sib.name == "ol":
453
453
  hr.decompose()
454
454
 
455
- # 5. Transform ac:layout → div[data-layout-macro]
455
+ # 5. Transform ac:layout → div[data-layout-macro] per section
456
456
  for layout in soup.find_all("ac:layout"):
457
- layout_div = soup.new_tag("div")
458
- layout_div["data-layout-macro"] = "layout"
459
- section = layout.find("ac:layout-section")
460
- if section:
457
+ sections = layout.find_all("ac:layout-section", recursive=False)
458
+ if not sections:
459
+ layout.decompose()
460
+ continue
461
+ # Build one layout div per section, then replace the ac:layout
462
+ section_divs = []
463
+ for section in sections:
464
+ layout_div = soup.new_tag("div")
465
+ layout_div["data-layout-macro"] = "layout"
461
466
  layout_type = section.get("ac:type", "single")
462
- # Convert underscores back to hyphens
463
467
  layout_type = layout_type.replace("_", "-")
464
468
  layout_div["data-layout-type"] = layout_type
465
469
  for cell in section.find_all("ac:layout-cell", recursive=False):
@@ -468,7 +472,11 @@ def _preprocess_storage_format(html: str) -> tuple[BeautifulSoup, list[str]]:
468
472
  for child in list(cell.children):
469
473
  cell_div.append(child.extract())
470
474
  layout_div.append(cell_div)
471
- layout.replace_with(layout_div)
475
+ section_divs.append(layout_div)
476
+ # Insert all section divs after the layout, then remove it
477
+ for div in reversed(section_divs):
478
+ layout.insert_after(div)
479
+ layout.decompose()
472
480
 
473
481
  # 6. Transform ac:link → a
474
482
  for link in soup.find_all("ac:link"):
@@ -355,6 +355,50 @@ class TestLayoutReverse:
355
355
  assert "Right" in result.markdown
356
356
  assert "::::" in result.markdown
357
357
 
358
+ def test_layout_multiple_sections(self):
359
+ """Multiple ac:layout-section elements must all be converted (bug fix)."""
360
+ html = (
361
+ '<ac:layout>'
362
+ '<ac:layout-section ac:type="single">'
363
+ '<ac:layout-cell><p>Section one</p></ac:layout-cell>'
364
+ '</ac:layout-section>'
365
+ '<ac:layout-section ac:type="single">'
366
+ '<ac:layout-cell>'
367
+ '<h1>Main heading</h1>'
368
+ '<p>Body paragraph with <strong>bold</strong> text.</p>'
369
+ '<ul><li>Item A</li><li>Item B</li></ul>'
370
+ '</ac:layout-cell>'
371
+ '</ac:layout-section>'
372
+ '</ac:layout>'
373
+ )
374
+ result = convert_storage_to_markdown(html)
375
+ assert "Section one" in result.markdown
376
+ assert "# Main heading" in result.markdown
377
+ assert "Body paragraph" in result.markdown
378
+ assert "**bold**" in result.markdown
379
+ assert "Item A" in result.markdown
380
+ assert "Item B" in result.markdown
381
+
382
+ def test_layout_mixed_section_types(self):
383
+ """Sections with different layout types preserve their types."""
384
+ html = (
385
+ '<ac:layout>'
386
+ '<ac:layout-section ac:type="single">'
387
+ '<ac:layout-cell><p>Full width</p></ac:layout-cell>'
388
+ '</ac:layout-section>'
389
+ '<ac:layout-section ac:type="two_left_sidebar">'
390
+ '<ac:layout-cell><p>Sidebar</p></ac:layout-cell>'
391
+ '<ac:layout-cell><p>Main content</p></ac:layout-cell>'
392
+ '</ac:layout-section>'
393
+ '</ac:layout>'
394
+ )
395
+ result = convert_storage_to_markdown(html)
396
+ assert ":::: layout single" in result.markdown
397
+ assert ":::: layout two-left-sidebar" in result.markdown
398
+ assert "Full width" in result.markdown
399
+ assert "Sidebar" in result.markdown
400
+ assert "Main content" in result.markdown
401
+
358
402
 
359
403
  class TestPluginRoundTrips:
360
404
  """Test round-trip conversion for new plugin features."""
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes