From 4fe2df61fe359f0f3664d7bc2b3c88d14fa8d945 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Fri, 9 Aug 2024 16:58:48 +0200 Subject: [PATCH] Chore: formatting --- package-lock.json | 16 +- scripts/importscripts/cleanRepair.ts | 332 +++++++++++++++++---------- scripts/thieves/readIdPresets.ts | 14 +- test/Logic/Tags/OptimizeTags.spec.ts | 228 ++++++++++-------- 4 files changed, 359 insertions(+), 231 deletions(-) diff --git a/package-lock.json b/package-lock.json index 63e60c038..88a8fb90a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mapcomplete", - "version": "0.44.11", + "version": "0.44.13", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "mapcomplete", - "version": "0.44.11", + "version": "0.44.13", "license": "GPL-3.0-or-later", "dependencies": { "@comunica/core": "^3.0.1", @@ -7893,9 +7893,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001642", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", - "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", + "version": "1.0.30001651", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", + "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", "dev": true, "funding": [ { @@ -25250,9 +25250,9 @@ "version": "2.0.1" }, "caniuse-lite": { - "version": "1.0.30001642", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", - "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", + "version": "1.0.30001651", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", + "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", "dev": true }, "canonicalize": { diff --git a/scripts/importscripts/cleanRepair.ts b/scripts/importscripts/cleanRepair.ts index 4c21abe09..412b0673e 100644 --- a/scripts/importscripts/cleanRepair.ts +++ b/scripts/importscripts/cleanRepair.ts @@ -15,12 +15,10 @@ import { TagUtils } from "../../src/Logic/Tags/TagUtils" import { BBox } from "../../src/Logic/BBox" export default class CleanRepair extends Script { - constructor() { super("Cleans 'repair'-tags for mass retagging") } - async main(args: string[]) { const path = args[0] console.log("Loading", path) @@ -32,141 +30,244 @@ export default class CleanRepair extends Script { "repair!=brand", "repair!=only", "repair!=only_sold", - "repair!=assisted_self_service" - ] + "repair!=assisted_self_service", + ], }) - const overpass = new Overpass(criteria, [], - "https://overpass-api.de/api/interpreter" - ) - const data: Feature> [] = (await overpass.queryGeoJson(BBox.global))[0].features + const overpass = new Overpass(criteria, [], "https://overpass-api.de/api/interpreter") + const data: Feature>[] = ( + await overpass.queryGeoJson(BBox.global) + )[0].features console.log("Got", data.length, "features; sample", data[0]) const changes = new Changes({ dryRun: new ImmutableStore(true), osmConnection: new OsmConnection({ - dryRun: new ImmutableStore(true) - }) + dryRun: new ImmutableStore(true), + }), }) const metakeys = ["id", "version", "changeset", "user", "uid", "timestamp"] const replace = { - "phone": "mobile_phone", - "phones": "mobile_phone", - "mobile": "mobile_phone", - "cellphone": "mobile_phone", - "pc": "computers", - "mobile_phones": "mobile_phone", - "mobilephones": "mobile_phone", - "mobilephone": "mobile_phone", - "clocks": "clock", - "elektronik": "electronics", - "tires": "tyres", - "welcome": "yes", - "tyre": "tyres", - "electronic_products": "electronics", - "shoe": "shoes", - "pc_repairs": "computer", - "computers": "computer", - "body_construction": "body_work", - "body": "body_work", + phone: "mobile_phone", + phones: "mobile_phone", + mobile: "mobile_phone", + cellphone: "mobile_phone", + pc: "computers", + mobile_phones: "mobile_phone", + mobilephones: "mobile_phone", + mobilephone: "mobile_phone", + clocks: "clock", + elektronik: "electronics", + tires: "tyres", + welcome: "yes", + tyre: "tyres", + electronic_products: "electronics", + shoe: "shoes", + pc_repairs: "computer", + computers: "computer", + body_construction: "body_work", + body: "body_work", - "body_repairer": "body_work", - "instruments": "musical_instrument", - "service": "yes", - "punture": "tyres", - "electricity": "electronics", - "self_service": "assisted_self_repair", - "paint": "bodywork", + body_repairer: "body_work", + instruments: "musical_instrument", + service: "yes", + punture: "tyres", + electricity: "electronics", + self_service: "assisted_self_repair", + paint: "bodywork", "paint shop": "bodywork", - "paint_shop": "bodywork", - "lawnmower": "lawn_mower", - "aircon": "air_conditioning", + paint_shop: "bodywork", + lawnmower: "lawn_mower", + aircon: "air_conditioning", "*": "yes", - "ammeublement": "furniture", - "all": "yes", - "appliances": "appliance", - "electronic": "electronics", "escooter": "electric_scooter", + ammeublement: "furniture", + all: "yes", + appliances: "appliance", + electronic: "electronics", + escooter: "electric_scooter", "aviation maintenance, repair, and_overhaul": "airplane", - "aviation_maintenance": "airplanes", - "bags": "bag", - "boats": "boat", - "boilers": "boiler", - "breaks": "brakes", - "car": "cars", - "tv": "television", - "clothing": "clothes", - "coat_of_lacquer": "body_work", - "cycle": "bicycle", - "cars": "car", - "blacharstwo": "tin", "lakiernictwo": "body_work", - "tire": "tyres", "powder_coating": "body_work", - "leather_products": "leather", - "motocycle": "motorcycle", - "motor": "motorcycle", "motoo": "motorcycle", - "motorbike": "motorcycle", "motorcycle_repair": "motorcycle", "motorsports": "motorcycle", - "printers": "printer", - "tyres24": "tyres", - "paintings": "painting", - "paintwork": "body_work", - "pumps": "pump", + aviation_maintenance: "airplanes", + bags: "bag", + boats: "boat", + boilers: "boiler", + breaks: "brakes", + car: "cars", + tv: "television", + clothing: "clothes", + coat_of_lacquer: "body_work", + cycle: "bicycle", + cars: "car", + blacharstwo: "tin", + lakiernictwo: "body_work", + tire: "tyres", + powder_coating: "body_work", + leather_products: "leather", + motocycle: "motorcycle", + motor: "motorcycle", + motoo: "motorcycle", + motorbike: "motorcycle", + motorcycle_repair: "motorcycle", + motorsports: "motorcycle", + printers: "printer", + tyres24: "tyres", + paintings: "painting", + paintwork: "body_work", + pumps: "pump", "shoes:yes": "shoes", - "wheel": "tyres", - "wheels": "tyres", - "vacuum": "vacuum_cleaner", - "glass": "car_glassj" + wheel: "tyres", + wheels: "tyres", + vacuum: "vacuum_cleaner", + glass: "car_glassj", } - const brands = ["garage", "audi", "renault", "apple", "honda", "ducati", "ford", "mazda","garage_renault_aie"] + const brands = [ + "garage", + "audi", + "renault", + "apple", + "honda", + "ducati", + "ford", + "mazda", + "garage_renault_aie", + ] - const valid = ["train", "tv", "jewelry", "scooter", ...Object.values(replace), "watch", "oldtimer", "car", "bicycle", "boat", "windbreaker", - "agricultural", "alternator", "antiques", "atv", "auto", - "aviation maintenance", "bag", "bags", - "battery", "bicyle", "borehole", "building", - "camera", "car_glass", "caravan", - "carpenter", "coffee_machine", "construction machinery", "cycle", - "dentures", "ducati", "electric motor", - "electric_bike", "electric_scooter", "espresso_machines", "exhaust", - "fire_extinguishers", "fountain_pen", "fridge", - "garden_machinery", "gas appliances", "generator", - "glasses", "golfcart", "guitar", - "hammock", "hardware", "heating pumps", - "hifi", "hvac", "installation", "jewellery", "keys", "kick_scooter", - "kitesurfing", "tools", "toys", "tractor", - "trailer", "transformer", "truck", - "typewriter", "sail", "sewing_machine", "ship", "picture", "pillow", "plastic", - "cash_register", "cnc", "laptop", + const valid = [ + "train", + "tv", + "jewelry", + "scooter", + ...Object.values(replace), + "watch", + "oldtimer", + "car", + "bicycle", + "boat", + "windbreaker", + "agricultural", + "alternator", + "antiques", + "atv", + "auto", + "aviation maintenance", + "bag", + "bags", + "battery", + "bicyle", + "borehole", + "building", + "camera", + "car_glass", + "caravan", + "carpenter", + "coffee_machine", + "construction machinery", + "cycle", + "dentures", + "ducati", + "electric motor", + "electric_bike", + "electric_scooter", + "espresso_machines", + "exhaust", + "fire_extinguishers", + "fountain_pen", + "fridge", + "garden_machinery", + "gas appliances", + "generator", + "glasses", + "golfcart", + "guitar", + "hammock", + "hardware", + "heating pumps", + "hifi", + "hvac", + "installation", + "jewellery", + "keys", + "kick_scooter", + "kitesurfing", + "tools", + "toys", + "tractor", + "trailer", + "transformer", + "truck", + "typewriter", + "sail", + "sewing_machine", + "ship", + "picture", + "pillow", + "plastic", + "cash_register", + "cnc", + "laptop", "laundry_machines", - "photo_camera", "photocopier", "piano", - "power_tools", "pressure_gauges", "printer", - , "snowboard", "snowmobile", "starter", "machines", "mainframe", + "photo_camera", + "photocopier", + "piano", + "power_tools", + "pressure_gauges", + "printer", + , + "snowboard", + "snowmobile", + "starter", + "machines", + "mainframe", "outboard_motor", - "video", "washing_machine", "ski", "radiator", - "radio", "refrigerator", - "rv", "ski", "window", "zipper", "weighing_scale", - "small_electric_vehicle" - - ].map(s => s.replace(/ /g, "_")) - + "video", + "washing_machine", + "ski", + "radiator", + "radio", + "refrigerator", + "rv", + "ski", + "window", + "zipper", + "weighing_scale", + "small_electric_vehicle", + ].map((s) => s.replace(/ /g, "_")) const skip = ["yes", "no", "only", "brand", "assisted_self_repair", "only_sold"] const dloader = new OsmObjectDownloader() - const rm = ["50243147100015", "81342677200048", "and overhaul", "repair", "unset", "сервисный_центр", "taller_de_michu", "quitandinha_g_&_a", "mechanika"].map(v => v.replace(/ /g, "_")) + const rm = [ + "50243147100015", + "81342677200048", + "and overhaul", + "repair", + "unset", + "сервисный_центр", + "taller_de_michu", + "quitandinha_g_&_a", + "mechanika", + ].map((v) => v.replace(/ /g, "_")) const objects: OsmObject[] = [] - const changesToMake: ChangeDescription [] = [] + const changesToMake: ChangeDescription[] = [] const first = GeoOperations.centerpointCoordinates(data[0]) for (const f of data) { - if (GeoOperations.distanceBetween(first, GeoOperations.centerpointCoordinates(f)) > 2500000) { + if ( + GeoOperations.distanceBetween(first, GeoOperations.centerpointCoordinates(f)) > + 2500000 + ) { continue } let keyRaw = f.properties.repair keyRaw = replace[keyRaw] ?? keyRaw - if (brands.some(br => keyRaw.toLowerCase().indexOf(br.trim()) >= 0)) { + if (brands.some((br) => keyRaw.toLowerCase().indexOf(br.trim()) >= 0)) { f.properties.repair = "brand" - } if(skip.indexOf(keyRaw) >= 0){ + } + if (skip.indexOf(keyRaw) >= 0) { f.properties.repair = keyRaw } else { - - const r = keyRaw.replace(/\/|,/g, ";").split(";").map(k => k.trim().replace(/ /g, "_").toLowerCase()) + const r = keyRaw + .replace(/\/|,/g, ";") + .split(";") + .map((k) => k.trim().replace(/ /g, "_").toLowerCase()) for (let key of r) { key = replace[key] ?? key @@ -177,9 +278,7 @@ export default class CleanRepair extends Script { f.properties[key + ":repair"] = "yes" delete f.properties.repair - } - } if (f.properties.service === "repair") { delete f.properties.service @@ -198,34 +297,25 @@ export default class CleanRepair extends Script { const value = f.properties[key] const ct = await new ChangeTagAction(id, new Tag(key, value), f.properties, { changeType: "fix", - theme: "script" + theme: "script", }).CreateChangeDescriptions() changesToMake.push(...ct) - console.log(ct.map(cd => cd.tags)) + console.log(ct.map((cd) => cd.tags)) if (f.properties.repair === undefined) { const ct = await new ChangeTagAction(id, new Tag("repair", ""), f.properties, { changeType: "fix", - theme: "script" + theme: "script", }).CreateChangeDescriptions() changesToMake.push(...ct) } } } - const - changedObjects = changes.CreateChangesetObjects(changesToMake, objects) + const changedObjects = changes.CreateChangesetObjects(changesToMake, objects) - const - osc = Changes.createChangesetFor("", changedObjects) - - writeFileSync( - "Cleanup.osc" - , - osc - , - "utf8" - ) + const osc = Changes.createChangesetFor("", changedObjects) + writeFileSync("Cleanup.osc", osc, "utf8") } } diff --git a/scripts/thieves/readIdPresets.ts b/scripts/thieves/readIdPresets.ts index 483dad6af..1a995453f 100644 --- a/scripts/thieves/readIdPresets.ts +++ b/scripts/thieves/readIdPresets.ts @@ -213,7 +213,7 @@ class IdThief { continue } - if(preset.tags["shop"] === "vacant") { + if (preset.tags["shop"] === "vacant") { console.log("Skipping 'vacant'") continue } @@ -282,15 +282,15 @@ class IdThief { } } - -class ReadIdPresets extends Script{ +class ReadIdPresets extends Script { constructor() { - super("Reads the id-tagging-schema repository and steals the presets; which will be written into 'id_presets.json'\n\nArguments: [path-to-repository] [path-to-target]\n" + - "Note that default arguments are used") + super( + "Reads the id-tagging-schema repository and steals the presets; which will be written into 'id_presets.json'\n\nArguments: [path-to-repository] [path-to-target]\n" + + "Note that default arguments are used" + ) } async main(args: string[]): Promise { - const targetDir = args[1] ?? "./assets/layers/id_presets/" const makiThief = new MakiThief( @@ -345,9 +345,7 @@ class ReadIdPresets extends Script{ ] console.log("Writing id presets to", id_presets_path) writeFileSync(id_presets_path, JSON.stringify(idPresets, null, " "), "utf8") - } } - new ReadIdPresets().run() diff --git a/test/Logic/Tags/OptimizeTags.spec.ts b/test/Logic/Tags/OptimizeTags.spec.ts index 94ca11bb9..ab7bf0208 100644 --- a/test/Logic/Tags/OptimizeTags.spec.ts +++ b/test/Logic/Tags/OptimizeTags.spec.ts @@ -31,7 +31,7 @@ describe("Tag optimalization", () => { const t = new And([ new Tag("foo", "bar"), new Or([new Tag("x", "y"), new Tag("a", "b")]), - new Or([new Tag("x", "y"), new Tag("c", "d")]) + new Or([new Tag("x", "y"), new Tag("c", "d")]), ]) const opt = t.optimize() expect(TagUtils.toString(opt)).toBe("foo=bar& (x=y| (a=b&c=d) )") @@ -42,7 +42,7 @@ describe("Tag optimalization", () => { const t = new And([ new Tag("foo", "bar"), new Or([new RegexTag("x", "y"), new RegexTag("a", "b")]), - new Or([new RegexTag("x", "y"), new RegexTag("c", "d")]) + new Or([new RegexTag("x", "y"), new RegexTag("c", "d")]), ]) const opt = t.optimize() expect(TagUtils.toString(opt)).toBe("foo=bar& ( (a=b&c=d) |x=y)") @@ -53,7 +53,7 @@ describe("Tag optimalization", () => { const t = new And([ new Tag("foo", "bar"), new Or([new RegexTag("x", "y"), new RegexTag("a", "b")]), - new Or([new RegexTag("x", "y", true), new RegexTag("c", "d")]) + new Or([new RegexTag("x", "y", true), new RegexTag("c", "d")]), ]) const opt = t.optimize() expect(TagUtils.toString(opt)).toBe("foo=bar& (a=b|x=y) & (c=d|x!=y)") @@ -86,12 +86,12 @@ describe("Tag optimalization", () => { { and: [ { - or: ["X=Y", "FOO=BAR"] + or: ["X=Y", "FOO=BAR"], }, - "bicycle=yes" - ] - } - ] + "bicycle=yes", + ], + }, + ], }) // (X=Y | FOO=BAR | (bicycle=yes & (X=Y | FOO=BAR)) ) // This is equivalent to (X=Y | FOO=BAR) @@ -109,11 +109,11 @@ describe("Tag optimalization", () => { "amenity=charging_station", "disused:amenity=charging_station", "planned:amenity=charging_station", - "construction:amenity=charging_station" - ] + "construction:amenity=charging_station", + ], }, - "bicycle=yes" - ] + "bicycle=yes", + ], }, { and: [ @@ -122,19 +122,19 @@ describe("Tag optimalization", () => { "amenity=charging_station", "disused:amenity=charging_station", "planned:amenity=charging_station", - "construction:amenity=charging_station" - ] - } - ] + "construction:amenity=charging_station", + ], + }, + ], }, "amenity=toilets", "amenity=bench", "leisure=picnic_table", { - and: ["tower:type=observation"] + and: ["tower:type=observation"], }, { - and: ["amenity=bicycle_repair_station"] + and: ["amenity=bicycle_repair_station"], }, { and: [ @@ -143,16 +143,16 @@ describe("Tag optimalization", () => { "amenity=bicycle_rental", "bicycle_rental~*", "service:bicycle:rental=yes", - "rental~.*bicycle.*" - ] + "rental~.*bicycle.*", + ], }, - "bicycle_rental!=docking_station" - ] + "bicycle_rental!=docking_station", + ], }, { - and: ["leisure=playground", "playground!=forest"] - } - ] + and: ["leisure=playground", "playground!=forest"], + }, + ], }) const opt = filter.optimize() const expected = [ @@ -166,7 +166,7 @@ describe("Tag optimalization", () => { "planned:amenity=charging_station", "tower:type=observation", "(amenity=bicycle_rental|service:bicycle:rental=yes|bicycle_rental~.+|rental~^(.*bicycle.*)$) &bicycle_rental!=docking_station", - "leisure=playground&playground!=forest" + "leisure=playground&playground!=forest", ] expect((opt).or.map((f) => TagUtils.toString(f))).toEqual(expected) @@ -184,22 +184,16 @@ describe("Tag optimalization", () => { it("should optimize comparing tags", () => { const spec = TagUtils.Tag({ - and:[ - "x=5", - "x>5" - ] + and: ["x=5", "x>5"], }) const opt = spec.optimize() expect(opt).to.eq(false) }) it("should optimize regexes in the key", () => { const spec = TagUtils.Tag({ - and: [ - "service:bicycle:retail=yes", - "service:bicycle:.+~~yes" - ] + and: ["service:bicycle:retail=yes", "service:bicycle:.+~~yes"], }) - const tag = spec.optimize() + const tag = spec.optimize() expect(tag.asJson()).to.eq("service:bicycle:retail=yes") }) }) @@ -208,7 +202,7 @@ describe("Tag optimalization", () => { it("with nested And which has a common property should be dropped", () => { const t = new Or([ new Tag("foo", "bar"), - new And([new Tag("foo", "bar"), new Tag("x", "y")]) + new And([new Tag("foo", "bar"), new Tag("x", "y")]), ]) const opt = t.optimize() expect(TagUtils.toString(opt)).toBe("foo=bar") @@ -233,14 +227,14 @@ describe("Tag optimalization", () => { and: [ "sport=climbing", { - or: ["office~*", "club~*"] - } - ] - } - ] + or: ["office~*", "club~*"], + }, + ], + }, + ], }) const gym_tags = TagUtils.Tag({ - and: ["sport=climbing", "leisure=sports_centre"] + and: ["sport=climbing", "leisure=sports_centre"], }) const other_climbing = TagUtils.Tag({ and: [ @@ -248,8 +242,8 @@ describe("Tag optimalization", () => { "climbing!~route", "leisure!~sports_centre", "climbing!=route_top", - "climbing!=route_bottom" - ] + "climbing!=route_bottom", + ], }) const together = new Or([club_tags, gym_tags, other_climbing]) const opt = together.optimize() @@ -291,7 +285,7 @@ describe("Tag optimalization", () => { or: [ "club=climbing", { - and: ["sport=climbing", { or: ["club~*", "office~*"] }] + and: ["sport=climbing", { or: ["club~*", "office~*"] }], }, { and: [ @@ -304,63 +298,109 @@ describe("Tag optimalization", () => { "climbing!~route", "climbing!=route_top", "climbing!=route_bottom", - "leisure!~sports_centre" - ] - } - ] - } - ] - } - ] + "leisure!~sports_centre", + ], + }, + ], + }, + ], + }, + ], }) ) }) it("should optimize a complicated nested case", () => { const spec = { - "and": - ["service:bicycle:retail=yes", - { - "or": [ - { - "and": [ - { "or": ["shop=outdoor", "shop=sport", "shop=diy", "shop=doityourself"] }, - { - "or": ["service:bicycle:repair=yes", "shop=bicycle", - { - "and": ["shop=sports", - { "or": ["sport=bicycle", "sport=cycling", "sport="] }, - "service:bicycle:retail!=no", - "service:bicycle:repair!=no"] - }] - }] - }, { - "and": - [ + and: [ + "service:bicycle:retail=yes", + { + or: [ + { + and: [ + { + or: [ + "shop=outdoor", + "shop=sport", + "shop=diy", + "shop=doityourself", + ], + }, + { + or: [ + "service:bicycle:repair=yes", + "shop=bicycle", { - "or": - ["shop=outdoor", "shop=sport", "shop=diy", "shop=doityourself"] - }, - { - "or": ["service:bicycle:repair=yes", "shop=bicycle", + and: [ + "shop=sports", { - "and": ["shop=sports", - { "or": ["sport=bicycle", "sport=cycling", "sport="] }, - "service:bicycle:retail!=no", "service:bicycle:repair!=no"] - }] - }] - }, { - "and": - [{ - "or": - ["craft=shoe_repair", "craft=key_cutter", "shop~.+"] - }, - { "or": ["shop=outdoor", "shop=sport", "shop=diy", "shop=doityourself"] }, - "shop!=mall"] - }, - "service:bicycle:retail~.+", - "service:bicycle:retail~.+"] - }] + or: [ + "sport=bicycle", + "sport=cycling", + "sport=", + ], + }, + "service:bicycle:retail!=no", + "service:bicycle:repair!=no", + ], + }, + ], + }, + ], + }, + { + and: [ + { + or: [ + "shop=outdoor", + "shop=sport", + "shop=diy", + "shop=doityourself", + ], + }, + { + or: [ + "service:bicycle:repair=yes", + "shop=bicycle", + { + and: [ + "shop=sports", + { + or: [ + "sport=bicycle", + "sport=cycling", + "sport=", + ], + }, + "service:bicycle:retail!=no", + "service:bicycle:repair!=no", + ], + }, + ], + }, + ], + }, + { + and: [ + { + or: ["craft=shoe_repair", "craft=key_cutter", "shop~.+"], + }, + { + or: [ + "shop=outdoor", + "shop=sport", + "shop=diy", + "shop=doityourself", + ], + }, + "shop!=mall", + ], + }, + "service:bicycle:retail~.+", + "service:bicycle:retail~.+", + ], + }, + ], } const tag = TagUtils.Tag(spec)