Skip to content

feat: add KML and KMZ layer export - #1568

Merged
giswqs merged 12 commits into
mainfrom
fix/issue-1566-kml-kmz-export
Jul 30, 2026
Merged

feat: add KML and KMZ layer export#1568
giswqs merged 12 commits into
mainfrom
fix/issue-1566-kml-kmz-export

Conversation

@giswqs

@giswqs giswqs commented Jul 30, 2026

Copy link
Copy Markdown
Member

Summary

  • add KML and KMZ options to layer and attribute table exports
  • preserve GeoJSON geometries, feature attributes, IDs, altitude coordinates, and simplestyle colors
  • package KMZ output with the conventional doc.kml archive entry

Testing

  • npm run build
  • npm run test:frontend
  • pre-commit run --all-files
  • exported us_cities.geojson to KML in light mode and KMZ in dark mode, then imported both files back into GeoLibre

Fixes #1566

Summary by CodeRabbit

  • New Features
    • Added KML and KMZ to the vector export menus (layer export and attribute table export).
    • Desktop exports now support KML 2.2 generation (including multiple geometry types, XML-safe text, styling from available properties, and optional altitude-aware output).
    • KMZ export packages the generated KML with the correct .kmz extension and KMZ MIME type.
  • Bug Fixes
    • Prevents KML/KMZ export when coordinates contain non-finite longitude/latitude values.

Copilot AI review requested due to automatic review settings July 30, 2026 09:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

GeoLibre adds native KML and KMZ layer export. GeoJSON features are serialized with geometry, properties, metadata, and styles; KMZ packages the generated KML as doc.kml. Desktop export menus and automated tests cover both formats.

Changes

KML and KMZ export

Layer / File(s) Summary
KML document serialization
apps/geolibre-desktop/src/lib/kml-writer.ts
GeoJSON geometries, properties, metadata, styles, coordinates, and document names are serialized into escaped KML 2.2 output.
KML and KMZ export pipeline
apps/geolibre-desktop/src/lib/vector-export.ts, apps/geolibre-desktop/src/lib/vector-exporter.ts, tests/kml-writer.test.ts
KML is routed through text export, KMZ is generated with doc.kml, format metadata is added, and serialization, packaging, validation, and browser save-picker behavior are tested.
Desktop export menu entries
apps/geolibre-desktop/src/components/panels/AttributeTable.tsx, apps/geolibre-desktop/src/components/panels/LayerPanel.tsx
Attribute-table and per-layer export menus expose KML and KMZ actions through existing handlers.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant LayerPanel
  participant exportVectorLayer
  participant exportTextLayer
  participant exportBinaryVectorLayer
  participant writeKml
  participant exportKmz
  LayerPanel->>exportVectorLayer: select KML
  exportVectorLayer->>exportTextLayer: route text export
  exportTextLayer->>writeKml: serialize FeatureCollection
  writeKml-->>exportTextLayer: KML document
  LayerPanel->>exportBinaryVectorLayer: select KMZ
  exportBinaryVectorLayer->>exportKmz: create KMZ
  exportKmz->>writeKml: serialize FeatureCollection
  writeKml-->>exportKmz: doc.kml content
  exportKmz-->>exportBinaryVectorLayer: zipped KMZ bytes
Loading

Poem

A rabbit hops through KML bright,
With placemarks tucked in XML light.
KMZ packs doc.kml tight,
Menus bloom with formats right—
Exporting maps is pure delight! 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The AttributeTable KML/KMZ export additions extend the feature beyond #1566's Layers panel scope. Either remove the AttributeTable export menu changes or update the issue scope to explicitly include attribute table export.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding KML/KMZ export.
Linked Issues check ✅ Passed The PR adds native KML/KMZ export options and supporting export logic, matching issue #1566's request.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-1566-kml-kmz-export

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

🔍 Cloudflare PR preview

Item Value
Site https://a20691d1.geolibre-preview.pages.dev
Demo app https://a20691d1.geolibre-preview.pages.dev/demo/
Commit b1464a1

@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

🔍 GitHub Pages PR preview

Item Value
Site Deploy failed. See the job log.
Demo app Unavailable
Commit b1464a1

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/geolibre-desktop/src/lib/vector-export.ts`:
- Around line 181-221: Refactor exportTextLayer to derive the format-specific
extension, label, MIME type, file filters, and browser accept mapping from one
lookup table keyed by format, instead of repeating isCsv/isKml ternary chains.
Reuse the table’s MIME and extension values for both mimeType and
browserTypes[0].accept so each format’s metadata has a single source of truth.

In `@tests/kml-writer.test.ts`:
- Around line 15-26: Extend the KML writer test fixture and assertions around
SAMPLE to cover stroke, stroke-width, and fill properties. Verify that styleKml
emits the expected LineStyle width and PolyStyle color values, while preserving
the existing IconStyle coverage.
- Around line 128-138: Add a test in the KML export suite covering
exportVectorLayer/exportTextLayer with the "kml" format, asserting the generated
text, extension, label, MIME type, filters, and browser-save accept
configuration used by vector-export.ts. Reuse the existing SAMPLE fixture and
expected writeKml output, and keep the existing KMZ coverage unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1d815f92-5bf5-423a-9a91-bb63945fd6a0

📥 Commits

Reviewing files that changed from the base of the PR and between 37014d3 and 55c3ed7.

📒 Files selected for processing (6)
  • apps/geolibre-desktop/src/components/panels/AttributeTable.tsx
  • apps/geolibre-desktop/src/components/panels/LayerPanel.tsx
  • apps/geolibre-desktop/src/lib/kml-writer.ts
  • apps/geolibre-desktop/src/lib/vector-export.ts
  • apps/geolibre-desktop/src/lib/vector-exporter.ts
  • tests/kml-writer.test.ts

Comment thread apps/geolibre-desktop/src/lib/vector-export.ts
Comment thread tests/kml-writer.test.ts
Comment thread tests/kml-writer.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/kml-writer.test.ts`:
- Around line 150-169: Restore the original globalThis.self value in the
browser-picker test’s cleanup alongside globalThis.window. Capture whether self
existed and its prior value before assigning it, then have the finally block
remove self when it was originally absent or restore the saved value when it
existed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f7fafd8d-40b6-4233-9683-36e1d9941629

📥 Commits

Reviewing files that changed from the base of the PR and between 55c3ed7 and 6b00f78.

📒 Files selected for processing (2)
  • apps/geolibre-desktop/src/lib/vector-export.ts
  • tests/kml-writer.test.ts

Comment thread tests/kml-writer.test.ts
Comment thread apps/geolibre-desktop/src/lib/kml-writer.ts
Comment thread apps/geolibre-desktop/src/lib/kml-writer.ts
@github-actions

Copy link
Copy Markdown
Contributor

Code review

Bugs

  • writeKml never emits an <altitudeMode> element, so per the KML 2.2 spec the default clampToGround applies and compliant viewers (Google Earth, etc.) will visually ignore the altitude values it does write into <coordinates> — contradicting the PR's stated goal of preserving altitude. Medium confidence. (apps/geolibre-desktop/src/lib/kml-writer.ts:23-28)
  • positionText throws a generic error with no feature id/index on the first invalid coordinate, aborting the entire export with little diagnostic value for large layers. Low-medium confidence, minor. (apps/geolibre-desktop/src/lib/kml-writer.ts:23-28)

Security

  • None found. xmlSafeText escapes control characters and XML metacharacters in the correct order (control chars → &</>/"/'), and all user-controlled property/attribute values pass through it before being embedded in the document.

Performance

  • No notable issues. String building via array-join is consistent with the other exporters (Shapefile/GeoPackage writers) in this codebase.

Quality

  • name, description, and simplestyle keys are promoted to native KML elements/<Style> and duplicated inside <ExtendedData>, bloating file size. This is functionally harmless for round-tripping through GeoLibre's own kml.ts importer (the <Style>-derived values take precedence over the ExtendedData copies on re-import), but is redundant for other KML consumers. Low confidence, informational. (apps/geolibre-desktop/src/lib/kml-writer.ts:117-128)
  • vector-export.ts/vector-exporter.ts cleanly generalize the existing text/binary export plumbing (TEXT_EXPORT_FORMATS table, exhaustive switches) to add kml/kmz without touching unrelated code paths. New UI menu items in AttributeTable.tsx/LayerPanel.tsx follow the existing (unlocalized) label pattern used by the other export formats, so no regression there.

CLAUDE.md

  • No violations found. The change doesn't touch any of the mirrored-constant/version-sync areas called out in CLAUDE.md, and doesn't introduce new external tile/map hosts.

Overall this is a well-scoped, well-tested addition (geometry types, escaping, invalid-coordinate handling, KMZ packaging, and the browser save picker are all covered in tests/kml-writer.test.ts); the findings above are minor/edge-case concerns rather than blockers.

Comment thread apps/geolibre-desktop/src/lib/kml-writer.ts Outdated
Comment thread apps/geolibre-desktop/src/lib/kml-writer.ts Outdated
Comment thread apps/geolibre-desktop/src/lib/vector-export.ts Outdated
@github-actions

Copy link
Copy Markdown
Contributor

Code review

Bugs

  • kml-writer.ts:27positionText joins coordinates via default Number.toString(), which switches to exponential notation for magnitudes below 1e-6 (e.g. 5e-7,36.17). A longitude/latitude value that close to 0° would produce invalid, unparseable <coordinates> content. Medium confidence — no test currently covers this range.

Security

  • None found. XML text, attribute names (ExtendedData's Data name="..."), and the document/placemark name/description are all escaped via xmlSafeText; property keys and values are attacker-influenced (arbitrary GeoJSON attributes) but properly encoded before being embedded in the XML/attribute context. No path traversal risk — output filenames go through sanitizeExportFileName.

Performance

  • kml-writer.ts:188styleKml is inlined as a full <Style> block on every <Placemark> rather than defined once at the Document level and referenced via styleUrl. For large layers where most features share the same simplestyle colors, this needlessly bloats KML/KMZ output size. Medium confidence — a real cost for big exports, not a correctness issue.

Quality

  • vector-export.ts:223 (and the corresponding KMZ path through exportBinaryVectorLayer) — the filesystem-sanitized baseName (spaces → -) is used both as the output filename and as the visible <name> of the KML Document, so a layer named "My Cities" shows up as "My-Cities" in Google Earth's Places panel. Other binary writers (GeoPackage/Shapefile) use the sanitized name only internally, where it's far less visible to the end user. Low-medium confidence — worth passing the original layer.name as the document title while keeping the sanitized name for the file.

CLAUDE.md

  • No violations found. The new "KML"/"KMZ" menu labels follow the same (pre-existing) untranslated-format-label convention already used by sibling entries ("GeoPackage", "CSV (attributes only)", etc.), Tauri CSP/tile-host allowlists are unaffected (no new external hosts), and no generated catalogs (whitebox-menu-catalog.ts) needed regeneration.

Also checked and found no issues: XML escaping order/control-character handling, KML color byte ordering (verified against the added unit tests), polygon ring closing, GeometryCollection/Multi* recursion, error handling around writeKml's thrown validation error (caught by both AttributeTable's exportLayer and LayerPanel's handleExportLayer), and the new format wiring across vector-export.ts/vector-exporter.ts switch statements (all exhaustive, no missed cases for the new kml/kmz variants).

Comment thread apps/geolibre-desktop/src/lib/kml-writer.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/kml-writer.test.ts (1)

163-181: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the feature-ID error path.

The new writer branch at Line 216 uses feature.id when present, but this test only exercises the index fallback. Add a malformed feature with an ID and assert the error contains feature with id ... so this new diagnostic cannot regress unnoticed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/kml-writer.test.ts` around lines 163 - 181, The invalid-coordinate test
in the KML writer should also cover the feature-ID diagnostic path. Add a
malformed feature with a defined ID to the test suite and assert that writeKml
throws an error containing the expected “feature with id …” context, while
preserving the existing index-based assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@tests/kml-writer.test.ts`:
- Around line 163-181: The invalid-coordinate test in the KML writer should also
cover the feature-ID diagnostic path. Add a malformed feature with a defined ID
to the test suite and assert that writeKml throws an error containing the
expected “feature with id …” context, while preserving the existing index-based
assertion.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 12e28595-3e97-43fc-8799-14bc614b37f6

📥 Commits

Reviewing files that changed from the base of the PR and between 612da75 and e505bad.

📒 Files selected for processing (2)
  • apps/geolibre-desktop/src/lib/kml-writer.ts
  • tests/kml-writer.test.ts

Comment thread apps/geolibre-desktop/src/lib/kml-writer.ts
@github-actions

Copy link
Copy Markdown
Contributor

Code review

Bugs

  • extendedDataKml silently drops the real GeoJSON feature.id when the feature's own properties already contain an (unrelated) feature_id key, instead of preserving it under another name — low-medium confidence, edge case for real-world attribute data (kml-writer.ts:170).

Security

  • None found. XML escaping (xmlSafeText) correctly escapes & before the other entities, strips disallowed control characters, and attribute values (Data name=) are escaped so arbitrary property keys can't break out of the XML structure.

Performance

  • None found beyond pre-existing patterns (synchronous zipSync for KMZ mirrors the existing Shapefile export path, not a new regression).

Quality

  • ExtendedData includes every property verbatim, so name/description (and simplestyle keys) are duplicated: once as native KML elements/style, once again as <Data> entries — likely to produce duplicate/confusing attribute columns on re-import — medium confidence (kml-writer.ts:168-179, suggestion posted inline).
  • The new "KML"/"KMZ" dropdown labels are hardcoded strings rather than run through t(), though this matches the existing (also untranslated) "GeoPackage"/"Shapefile (zipped)"/"CSV" siblings in the same menus, so it's consistent with current convention rather than a new deviation — very low confidence.
  • docs/user-guide/attribute-table.md's export-formats sentence ("GeoJSON, GeoParquet, GeoPackage, a zipped Shapefile, or CSV") wasn't updated to mention KML/KMZ — minor doc-completeness gap, not part of the diff so no inline comment was possible.

CLAUDE.md

  • No violations of the export-menu/i18n/mirrored-constant guidelines beyond the very-low-confidence i18n nit above; this feature is pure client-side JS and doesn't touch any of the mirrored WASM/plugin constants CLAUDE.md calls out.

Overall the KML/KMZ writer is careful and well-tested (escaping, altitude handling, ring closing, per-feature error isolation with clear messages, KMZ packaging), and the export wiring reuses existing patterns cleanly.

@giswqs

giswqs commented Jul 30, 2026

Copy link
Copy Markdown
Member Author

Addressed the latest CodeRabbit follow-up in f5f1491. The invalid-coordinate test now covers both the index fallback and the feature-ID diagnostic path.

Comment thread apps/geolibre-desktop/src/lib/kml-writer.ts
@github-actions

Copy link
Copy Markdown
Contributor

Code review

Bugs: None found. Traced the full data path (kml-writer.tsvector-exporter.tsvector-export.tsAttributeTable.tsx/LayerPanel.tsx) including coordinate/altitude handling, ring closing, shared-style dedup, feature-id/property-name collision resolution, scientific-notation-to-decimal formatting, and KMZ zip packaging. Parameter wiring for the new documentName argument is consistent and correctly ordered at every call site. Non-finite coordinates are validated and rejected before any partial/corrupt output can be written, and the test suite (tests/kml-writer.test.ts) exercises these paths well, including the geometry types, altitude modes, style sharing, and id-collision logic (verified against the implementation, not just skimmed).

Security: None found. All text (names, descriptions, property keys/values, document name) is passed through xmlSafeText, which correctly escapes &/</>/"/' in the right order and strips invalid XML control characters while preserving valid whitespace (tab/LF/CR). No injection vector into the generated XML. Confidence: high.

Performance: None found. KML/KMZ writer modules are lazy-loaded via dynamic import(), consistent with the existing Shapefile/GeoPackage export pattern. String building is linear in feature count.

Quality: Low-confidence nit posted inline — the new coordinate-validation error message and its feature-context wrapper (kml-writer.ts:104) are new user-facing strings that bypass t()/react-i18next and surface directly to the user via error.message in both export call sites. This mirrors a pre-existing pattern for other export formats, so it's not a regression, but it's new text worth a look given the project's i18n convention.

CLAUDE.md: No other adherence issues found. The new "KML"/"KMZ" menu labels are hardcoded like their sibling format labels ("GeoJSON", "GeoPackage", "Shapefile (zipped)") in the same dropdowns, so they're consistent with existing (untranslated) file convention rather than a new violation.

Comment thread apps/geolibre-desktop/src/components/processing/ConversionDialog.tsx Outdated
Comment thread apps/geolibre-desktop/src/components/panels/AttributeTable.tsx Outdated
Comment thread apps/geolibre-desktop/src/i18n/locales/en.json Outdated
@github-actions

Copy link
Copy Markdown
Contributor

Code review

Bugs

  • None found. The KML/KMZ writer was cross-checked against the test suite line-by-line (coordinate formatting, altitude modes, polygon ring closing, style color byte order aabbggrr, style dedup, feature-ID collision handling) and all behave correctly; invalid (non-finite) coordinates are caught per-feature and surfaced as a typed KmlCoordinateError rather than corrupting the output file.

Security

  • None found. All user-controlled text (names, descriptions, property keys/values, document name) is passed through xmlSafeText, which escapes control characters and XML metacharacters before being interpolated into the document. No injection vectors identified.

Performance

  • None significant. The writer builds the KML document as an in-memory string, same order of cost as the existing GeoJSON export; no obvious inefficiency beyond what the format requires.

Quality

  • The error instanceof KmlCoordinateError ? … : error instanceof Error ? … : … message-selection logic is duplicated verbatim in AttributeTable.tsx, LayerPanel.tsx, and ConversionDialog.tsx. Worth extracting into a shared helper to avoid drift (confidence: high).
  • In ConversionDialog.tsx's runBrowserVectorExport, the new KmlCoordinateError branch appears unreachable: the format argument there can only be a BROWSER_OUTPUT_FORMATS value (geojson|csv|geoparquet|geopackage|shapefile), and this PR doesn't add kml/kmz to that map — KML output continues to route to the desktop sidecar per the existing code comment. Likely dead code, low risk but potentially misleading (confidence: medium-high).
  • The "invalid coordinates at index" message uses a 0-based featureIndex, which may read oddly to end users expecting 1-based row/feature numbering (confidence: low-medium, UX nit).
  • Minor: exportVectorLayer(..., layer.name) passes the raw, unsanitized layer name as the KML document name; if a layer name is blank, the exported <name> element would be empty even though the saved filename still falls back to "layer" via sanitizeExportFileName. Very low-severity edge case.

CLAUDE.md

  • No violations found. No new external tile/map hosts, no RTL-sensitive UI layout added (only text strings and dropdown items), translation strings correctly added via t()/i18next, and fflate was already a dependency so no lockfile/package.json changes were needed.

Comment thread apps/geolibre-desktop/src/lib/kml-writer.ts Outdated
@github-actions

Copy link
Copy Markdown
Contributor

Code review

Bugs: None found. kml-writer.ts's coordinate validation, ring-closing, scientific-notation-to-decimal conversion, feature-ID/attribute-name collision handling, and style-sharing/dedup logic were traced through the accompanying test cases and check out correctly, including edge cases (NaN coordinates, empty rings/geometries, 2D vs 3D altitude mode, ID/attribute-name collisions).

Security: None found. Property values and keys are XML-escaped via xmlSafeText before being written into elements/attributes, feature name/description are only ever emitted through the fixed, hardcoded element names (no user-controlled element names), and the KMZ zip entry name (doc.kml) is a fixed string, so there's no injection or zip-slip surface. (Low confidence, minor: xmlSafeText's control-character strip doesn't cover 0x7F or lone UTF-16 surrogates, which are technically invalid in XML 1.0 — unlikely to occur in real GeoJSON properties.)

Performance: None found. Building the KML document in memory mirrors the existing GeoJSON/CSV exporters' approach; no new regression introduced.

Quality:

  • (medium confidence) opacityByte/kmlColor default a missing opacity to 1 (fully opaque) for marker-opacity, stroke-opacity, and fill-opacity alike. The simplestyle-spec defines fill-opacity's default as 0.6, so a feature with fill but no fill-opacity will export as fully opaque KML instead of translucent, diverging from how the same GeoJSON renders elsewhere — flagged inline on kml-writer.ts.
  • (low confidence) propertyText's JSON.stringify(value) ?? String(value) fallback is effectively dead code for ordinary GeoJSON properties parsed from JSON — not worth changing, just noting it's over-defensive.

CLAUDE.md: No violations. New i18n keys were correctly added only to en.json (the source of truth); per docs/i18n.md, other locale catalogs are expected to be partial and fall back to English, so this is standard practice, not a gap.

Overall this is a well-implemented, well-tested feature (291 new lines in kml-writer.ts backed by 358 lines of tests covering geometry types, altitude, escaping, style sharing, ID collisions, and error propagation). Only one inline suggestion was posted, at medium confidence.

Comment thread apps/geolibre-desktop/src/lib/kml-writer.ts
Comment thread apps/geolibre-desktop/src/lib/kml-writer.ts
@github-actions

Copy link
Copy Markdown
Contributor

Code review

Bugs

  • None found with high confidence. The core kml-writer.ts logic (coordinate validation, ring-closing, style dedup, feature-ID collision handling, scientific-notation-to-decimal conversion) is correct and well covered by tests/kml-writer.test.ts.
  • Low confidence: geometries with mixed 2D/3D vertices get a uniform altitudeMode=absolute when any vertex has a third coordinate, implicitly placing the 2D vertices at altitude 0 — could look like dropped points in Google Earth for unusual (but valid) mixed-dimensionality GeoJSON. (inline comment on kml-writer.ts:211-213)

Security

  • No issues found. All user-controlled text (layer/document name, feature properties, ExtendedData keys/values) is routed through xmlSafeText, which escapes &, <, >, ", ' before being placed into XML text or attribute positions — no XML injection vector. No use of raw user data as XML tag names. kmlColor validates hex input via regex before use, so no arbitrary string ends up in <color>.

Performance

  • No concerns; export work happens on already-existing patterns (dynamic import of kml-writer/fflate, same lazy-loading style as the existing Shapefile/GeoPackage exporters), and document generation is linear in feature count.

Quality

  • Minor nit: propertyText's JSON.stringify(value) ?? String(value) fallback is effectively unreachable for plain objects/arrays. (inline comment on kml-writer.ts:252)
  • The refactor of vector-export.ts into a TEXT_EXPORT_FORMATS table is a clean generalization of the previous CSV/GeoJSON-only branching, with no behavioral regression for the existing formats.

CLAUDE.md

  • No violations found. New user-facing strings (vectorExport.invalidKmlCoordinatesByPosition/ById) were added to en.json only, consistent with the documented convention that other locale catalogs may lag behind the English source of truth. Format names ("KML"/"KMZ") are left untranslated in the menus, consistent with how "GeoJSON"/"GeoPackage"/etc. are already handled nearby.

Comment thread apps/geolibre-desktop/src/lib/kml-writer.ts
@github-actions

Copy link
Copy Markdown
Contributor

Code review

Bugs: None found. Coordinate/geometry construction (positionText, hasAltitude, ring-closing, decimalText scientific-notation handling), the invalid-coordinate error path (InvalidCoordinateErrorKmlCoordinateError, feature index/id plumbing into the UI via kmlExportErrorMessage), and the KML/KMZ plumbing through vector-export.ts/vector-exporter.ts (including the documentName default parameter and its other, unaffected call sites in ConversionDialog.tsx, SqlWorkspacePanel.tsx, etc.) all check out. Confidence: high.

Security: No injection issues. All XML-facing content (name, description, ExtendedData keys/values, document name) goes through xmlSafeText, which correctly escapes & before </>/quotes and covers exactly the C0 control-character range XML 1.0 disallows. Confidence: high.

Performance: No concerns; string building is linear in feature/geometry count and consistent with the existing GeoJSON/CSV writers. Confidence: high.

Quality:

  • Left an inline note on kml-writer.ts (hasAltitude, lines 57–61): using absolute altitudeMode whenever any vertex in a geometry has a 3rd coordinate, while sibling 2D vertices fall back to KML's implicit 0, is a reasonable and documented tradeoff, but mixed-dimensionality <coordinates> blocks may not round-trip cleanly through stricter consumers like GDAL's OGR KML driver, and absolute assumes the altitude is true elevation rather than a relative/DEM value. Not blocking — worth a quick gut-check against the project's usual QGIS/ArcGIS-compatibility bar. Confidence: low-medium.
  • Style deduplication, simplestyle→KML color conversion (correct aabbggrr byte order), and feature-id/attribute-name collision handling in ExtendedData are all correct and well covered by tests/kml-writer.test.ts.
  • Escaping description as plain text rather than CDATA-wrapping potential HTML is consistent with this codebase's existing convention (see the comment in georss.ts about rendering all property values as plain text), so not flagged as an issue.

CLAUDE.md: No violations. New user-facing strings go through t()/en.json (other locales are intentionally allowed to lag per tests/i18n-catalogs.test.ts), no RTL-sensitive layout was touched, and none of the mirrored-constant or generated-catalog conventions (whitebox menu, PMTiles zoom cap, remote file size cap, sidecar lockfile) apply to this change.

@giswqs
giswqs merged commit a6b280b into main Jul 30, 2026
28 checks passed
@giswqs
giswqs deleted the fix/issue-1566-kml-kmz-export branch July 30, 2026 13:15
@giswqs giswqs mentioned this pull request Jul 30, 2026
1 task
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.

[Feature]: Export KMZ or KML files

2 participants