+}
+
+L.OSM.JSONParser = {
+ getChangesets(json) {
+ const changesets = json.changeset ? [json.changeset] : [];
+
+ return changesets.map(cs => ({
+ id: String(cs.id),
+ type: "changeset",
+ latLngBounds: L.latLngBounds(
+ [cs.min_lat, cs.min_lon],
+ [cs.max_lat, cs.max_lon]
+ ),
+ tags: this.getTags(cs)
+ }));
+ },
+
+ getNodes(json) {
+ const nodes = json.elements?.filter(el => el.type === "node") ?? [];
+ let result = {};
+
+ for (const node of nodes) {
+ result[node.id] = {
+ id: String(node.id),
+ type: "node",
+ latLng: L.latLng(node.lat, node.lon, true),
+ tags: this.getTags(node)
+ };
+ }
+
+ return result;
+ },
+
+ getWays(json, nodes) {
+ const ways = json.elements?.filter(el => el.type === "way") ?? [];
+
+ return ways.map(way => ({
+ id: String(way.id),
+ type: "way",
+ nodes: way.nodes.map(nodeId => nodes[nodeId]),
+ tags: this.getTags(way)
+ }));
+ },
+
+ getRelations(json, nodes, ways) {
+ const relations = json.elements?.filter(el => el.type === "relation") ?? [];
+
+ return relations.map(rel => ({
+ id: String(rel.id),
+ type: "relation",
+ members: (rel.members ?? []) // relation-way and relation-relation membership not implemented
+ .map(member => member.type === "node" ? nodes[member.ref] : null)
+ .filter(Boolean), // filter out null and undefined
+ tags: this.getTags(rel)
+ }));
+ },
+
+ getTags(json) {
+ return json.tags ?? {};
+ }
+};