Add kml-to-mif converter (KML/KMZ → MapInfo) - #2
Closed
fedyunin wants to merge 1 commit into
Closed
Conversation
Adds the second converter through the registry contract introduced in PR1.
Produces byte-identical output to the reference Python script
(kml_to_mif.py) on a real 1854-feature dataset (Karaganda 108 KMZ).
What it does
- Resolves per-feature colors by following styleUrl -> StyleMap(normal)
-> Style chains. KML AABBGGRR -> MapInfo decimal RGB int.
- Preserves <name> (label), <description>, and the resolved StyleId as
MID attribute columns. Adds a Folder column with the full slash-joined
KML folder path so the hierarchy is queryable in MapInfo SQL.
- Lays files out either as nested directories matching the KML Folder
tree (default) or one flat directory with `parent__child` prefixes
(`flat: true`) so they can be merged without TAB name collisions.
- Charset option: WindowsCyrillic (cp1251, default) for Russian/Kazakh
data, or Neutral (UTF-8) for MapInfo Pro 15.2+.
- Supports KML and KMZ. KMZ is unzipped in-process via a minimal pure-JS
ZIP reader (stored + deflate) — no native deps.
- Skips placemarks without geometry; reports per-file errors in stats.
New modules
- src/core/common/color.js KML AABBGGRR <-> MapInfo int <-> #RRGGBB
- src/core/common/zip.js minimal ZIP reader (zlib only)
- src/core/converters/kml-to-mif/
parseKml.js KML parsing (fast-xml-parser) +
Style/StyleMap collection + resolution
writeMif.js MIF/MID writer with CRLF normalization
and Unicode-safe filename sanitization
index.js Converter definition + run()
- test/fixtures/sample.kml polygons + line + point + StyleMap
New dependency: fast-xml-parser (zero runtime deps, MIT, popular)
Tests: 75 passing (62 from PR1 + 13 new)
- color: AABBGGRR / BBGGRR / fallback / hex round-trip
- zip: deflate + stored extraction, rejects non-ZIP buffers
- kml-to-mif: schema, full folder dispatch, flat layout, KMZ archive,
Neutral charset, resolved Pen/Brush/Symbol values per feature
Verified end-to-end: `diff -r` of the original Python output against
the JS output on the 1854-feature Karaganda 108 KMZ shows no
differences across all 18 produced files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the second converter to the registry: KML/KMZ → MapInfo MIF/MID. Validates the Converter contract from #1 with a real second implementation. Produces byte-identical output to the reference Python script on a real 1854-feature dataset.
Stacked on top of #1 — review #1 first.
What it does
styleUrlis followed throughStyleMap(normal) → Style. KMLAABBGGRRis converted to MapInfo decimal RGB. Polygons emit matchingPen+Brush(pattern 1 when<fill>0</fill>, pattern 2 otherwise). Lines emitPenwith line width from<LineStyle><width>. Points emitSymbolwithIconStylecolor.Name(from<name>),Description, resolvedStyleId, andFolder(full slash-joined KML folder path — usable for MapInfo SQL filtering).Foldertree. Withflat: true: one directory, parent folders joined asparent__childprefix to avoid TAB name collisions when merging.WindowsCyrillic(cp1251, default — works in any MapInfo Pro version), orNeutral(UTF-8, requires MapInfo Pro 15.2+).New modules
src/core/common/color.js— KMLAABBGGRR↔ MapInfo int ↔#RRGGBBsrc/core/common/zip.js— minimal ZIP reader (zlibonly, ~150 LOC)src/core/converters/kml-to-mif/parseKml.js—fast-xml-parser+ Style/StyleMap resolutionwriteMif.js— MIF/MID writer with CRLF normalization and Unicode-safe filename sanitization (preserves Cyrillic via\p{L})index.js— Converter definition +runtest/fixtures/sample.kml— small synthetic file with polygons, line, point, and aStyleMapNew dependency:
fast-xml-parser(zero runtime deps, MIT, widely used).Tests
75 passing (62 from #1 + 13 new):
Pen/Brush/Symbolvalues per feature, flat layout filename pattern, KMZ end-to-end via a generated in-memory archive, Neutral/UTF-8 charset pathnpm testByte-for-byte parity check
Test plan
npm testis green.miffiles in MapInfo Pro and confirm colors match the source KMLFollow-ups
feat/dispatch-ui— switch the renderer to render its options panel from the converter schema, switch the worker to dispatch byconverterId. Two converters now exist, so we can validate that the UI generalizes.feat/cli—bin/mifkit convert kml-to-mif <input> <output> --flat.feat/mif-to-kml— reverse direction (export MapInfo to Google Earth).🤖 Generated with Claude Code