diff --git a/Logic/Tags/And.ts b/Logic/Tags/And.ts index 84b4794b0..3d3d8f83c 100644 --- a/Logic/Tags/And.ts +++ b/Logic/Tags/And.ts @@ -243,7 +243,9 @@ export class And extends TagsFilter { properties[opt.key] = opt.value } } - for (const opt of optimized) { + + for (let i = 0; i < optimized.length; i++){ + const opt = optimized[i]; if (opt instanceof Tag) { const k = opt.key const v = properties[k] @@ -264,7 +266,23 @@ export class And extends TagsFilter { if (v === undefined) { continue } - if (v !== opt.value) { + if(opt.invert){ + // We should _not_ match this value + // If 'v' is given, we already know what value it should be + // If 'v' is the not-expected value, we have a conflict and return false + // Otherwise, we can safely drop this value + + const doesMatch = (typeof opt.value === "string" && v === opt.value) || + (v.match( opt.value) !== null) + + if(doesMatch){ + // We have a conflict as 'opt' is inverted + return false + }else{ + optimized.splice(i, 1) + i-- + } + }else if (v !== opt.value) { // detected an internal conflict return false } diff --git a/Models/ThemeConfig/SourceConfig.ts b/Models/ThemeConfig/SourceConfig.ts index 646eaa1cc..6db3c3b03 100644 --- a/Models/ThemeConfig/SourceConfig.ts +++ b/Models/ThemeConfig/SourceConfig.ts @@ -55,7 +55,9 @@ export default class SourceConfig { throw ( "Error at " + context + - ": the specified tags are conflicting with each other: they will never match anything at all" + ": the specified tags are conflicting with each other: they will never match anything at all.\n" + + "\tThe offending tags are: "+params.osmTags.asHumanString(false, false, {})+ + "\tThey optmize into 'false' " ) } if (optimized === true) { diff --git a/assets/layers/cafe_pub/cafe_pub.json b/assets/layers/cafe_pub/cafe_pub.json index 20b469b9d..2a9591ba1 100644 --- a/assets/layers/cafe_pub/cafe_pub.json +++ b/assets/layers/cafe_pub/cafe_pub.json @@ -233,7 +233,7 @@ { "if": "amenity=cafe", "then": { - "en": "A cafe to drink tea, coffee or an alcoholical bevarage in a quiet environment", + "en": "A cafe to drink tea, coffee or an alcoholic beverage in a quiet environment", "nl": "Dit is een cafe - een plaats waar men rustig kan zitten om een thee, koffie of alcoholische drank te nuttigen.", "de": "Ein Café, um in ruhiger Umgebung Tee, Kaffee oder ein alkoholisches Getränk zu trinken", "da": "En café til at drikke te, kaffe eller en alkoholisk drik i rolige omgivelser", @@ -245,7 +245,7 @@ { "if": "amenity=restaurant", "then": { - "en": "A restuarant where one can get a proper meal", + "en": "A restaurant where one can get a proper meal", "nl": "Dit is een restaurant waar men een maaltijd geserveerd krijgt", "de": "Ein Restaurant, in dem man ordentlich essen kann", "da": "En restaurant, hvor man kan få et ordentligt måltid", @@ -369,4 +369,4 @@ "fr": "Une couche montrants les cafés et pubs où l’on peut prendre un verre. Cette couche pose des questions y afférentes.", "ca": "Una capa que mostra cafeteries i bars on un es pot reunir amb una beguda. La capa demana algunes preguntes rellevants" } -} \ No newline at end of file +} diff --git a/assets/layers/charging_station/charging_station.json b/assets/layers/charging_station/charging_station.json index 905914b38..2711af535 100644 --- a/assets/layers/charging_station/charging_station.json +++ b/assets/layers/charging_station/charging_station.json @@ -4699,12 +4699,12 @@ "socket:typee=1" ], "title": { - "en": "a charging station for electrical bikes with a normal european wall plug (meant to charge electrical bikes)", - "nl": "een oplaadpunt voor elektrische fietsen met een gewoon Europees stopcontact (speciaal bedoeld voor fietsen)", - "ca": "una estació de càrrega per a bicicletes elèctriques amb un endoll de paret europeu normal (destinat a carregar bicicletes elèctriques)", - "da": "en ladestation til elektriske cykler med et normalt europæisk vægstik (beregnet til opladning af elektriske cykler)", - "de": "eine Ladestation für Elektrofahrräder mit einer normalen europäischen Steckdose (zum Laden von Elektrofahrrädern)", - "es": "una estación de carga para bicicletas eléctricas con un enchufe de pared europeo normal (pensado para cargar bicicletas eléctricas)" + "en": "a charging station for electrical bikes with a normal european wall plug ", + "nl": "een oplaadpunt voor elektrische fietsen met een gewoon Europees stopcontact ", + "ca": "una estació de càrrega per a bicicletes elèctriques amb un endoll de paret europeu normal ", + "da": "en ladestation til elektriske cykler med et normalt europæisk vægstik ", + "de": "eine Ladestation für Elektrofahrräder mit einer normalen europäischen Steckdose ", + "es": "una estación de carga para bicicletas eléctricas con un enchufe de pared europeo normal " }, "preciseInput": { "preferredBackground": "map" diff --git a/assets/layers/charging_station/charging_station.protojson b/assets/layers/charging_station/charging_station.protojson index d5ebc7ce1..3e7ab99d7 100644 --- a/assets/layers/charging_station/charging_station.protojson +++ b/assets/layers/charging_station/charging_station.protojson @@ -800,8 +800,8 @@ "socket:typee=1" ], "title": { - "en": "charging station for electrical bikes with a normal european wall plug (meant to charge electrical bikes)", - "nl": "oplaadpunt voor elektrische fietsen" + "en": "charging station for electrical bikes with a normal european wall plug ", + "nl": "oplaadpunt voor elektrische fietsen met een gewone, europese stekker " }, "preciseInput": { "preferredBackground": "map" diff --git a/assets/layers/shops/shops.json b/assets/layers/shops/shops.json index a980ffbb0..22e8b419a 100644 --- a/assets/layers/shops/shops.json +++ b/assets/layers/shops/shops.json @@ -16,7 +16,8 @@ "source": { "osmTags": { "and": [ - "shop~*" + "shop~*", + "shop!=mall" ] } }, diff --git a/assets/layers/surveillance_camera/surveillance_camera.json b/assets/layers/surveillance_camera/surveillance_camera.json index 9f9032938..d22c11951 100644 --- a/assets/layers/surveillance_camera/surveillance_camera.json +++ b/assets/layers/surveillance_camera/surveillance_camera.json @@ -460,7 +460,8 @@ "fr": "Méthode de montage : {camera:mount}", "it": "Metodo di montaggio: {camera:mount}", "de": "Montageart: {camera:mount}", - "da": "Monteringsmetode: {camera:mount}" + "da": "Monteringsmetode: {camera:mount}", + "ca": "Mètode de muntatge: {camera:mount}" }, "freeform": { "key": "camera:mount" diff --git a/langs/layers/ca.json b/langs/layers/ca.json index 22643149c..63064b94f 100644 --- a/langs/layers/ca.json +++ b/langs/layers/ca.json @@ -4964,7 +4964,8 @@ "then": "Aquesta càmera està posicionada a un arbre" } }, - "question": "Com està posicionada aquesta càmera?" + "question": "Com està posicionada aquesta càmera?", + "render": "Mètode de muntatge: {camera:mount}" }, "camera_direction": { "question": "En quina direcció geogràfica apunta aquesta càmera?", diff --git a/package.json b/package.json index 03bb27e42..01e95a72f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mapcomplete", - "version": "0.30.5", + "version": "0.30.6", "repository": "https://github.com/pietervdvn/MapComplete", "description": "A small website to edit OSM easily", "bugs": "https://github.com/pietervdvn/MapComplete/issues", diff --git a/public/css/index-tailwind-output.css b/public/css/index-tailwind-output.css index 4794c42e8..82fe7dd28 100644 --- a/public/css/index-tailwind-output.css +++ b/public/css/index-tailwind-output.css @@ -1117,10 +1117,6 @@ video { width: 2.75rem; } -.w-24 { - width: 6rem; -} - .w-1\/2 { width: 50%; } @@ -1134,6 +1130,10 @@ video { width: 24rem; } +.w-24 { + width: 6rem; +} + .w-10 { width: 2.5rem; } diff --git a/test/CodeQuality.spec.ts b/test/CodeQuality.spec.ts index 4be39f914..dbe177efa 100644 --- a/test/CodeQuality.spec.ts +++ b/test/CodeQuality.spec.ts @@ -7,8 +7,8 @@ import { describe, it } from "vitest" * @param reason * @private */ -function detectInCode(forbidden: string, reason: string): (done: () => void) => void { - return (done: () => void) => { +function detectInCode(forbidden: string, reason: string): Promise { + return new Promise((done) => { const excludedDirs = [ ".git", "node_modules", @@ -49,14 +49,23 @@ function detectInCode(forbidden: string, reason: string): (done: () => void) => console.error(found.length, "issues found") throw msg } - done() } ) - } + }) +} + +function wrap(promise: Promise): ((done: () => void) => void) { + return (done => { + promise.then(done) + }) +} + +function itAsync(name: string, promise: Promise){ + it(name, wrap(promise)) } describe("Code quality", () => { - it( + itAsync( "should not contain reverse", detectInCode( "reverse()", @@ -64,12 +73,12 @@ describe("Code quality", () => { ) ) - it( + itAsync( "should not contain 'constructor.name'", detectInCode("constructor\\.name", "This is not allowed, as minification does erase names.") ) - it( + itAsync( "should not contain 'innerText'", detectInCode( "innerText", @@ -77,7 +86,7 @@ describe("Code quality", () => { ) ) - it( + itAsync( "should not contain 'import * as name from \"xyz.json\"'", detectInCode( 'import \\* as [a-zA-Z0-9_]\\+ from \\"[.-_/a-zA-Z0-9]\\+\\.json\\"', @@ -85,7 +94,7 @@ describe("Code quality", () => { ) ) - it( + itAsync( "should not contain '[\"default\"]'", detectInCode('\\[\\"default\\"\\]', "Possible leftover of faulty default import") ) diff --git a/test/Logic/Tags/OptimizeTags.spec.ts b/test/Logic/Tags/OptimizeTags.spec.ts index ab7127d72..06110eb54 100644 --- a/test/Logic/Tags/OptimizeTags.spec.ts +++ b/test/Logic/Tags/OptimizeTags.spec.ts @@ -1,10 +1,10 @@ -import { TagsFilter } from "../../../Logic/Tags/TagsFilter" -import { And } from "../../../Logic/Tags/And" -import { Tag } from "../../../Logic/Tags/Tag" -import { TagUtils } from "../../../Logic/Tags/TagUtils" -import { Or } from "../../../Logic/Tags/Or" -import { RegexTag } from "../../../Logic/Tags/RegexTag" -import { describe, expect, it } from "vitest" +import {TagsFilter} from "../../../Logic/Tags/TagsFilter" +import {And} from "../../../Logic/Tags/And" +import {Tag} from "../../../Logic/Tags/Tag" +import {TagUtils} from "../../../Logic/Tags/TagUtils" +import {Or} from "../../../Logic/Tags/Or" +import {RegexTag} from "../../../Logic/Tags/RegexTag" +import {describe, expect, it} from "vitest" describe("Tag optimalization", () => { describe("And", () => { @@ -71,6 +71,14 @@ describe("Tag optimalization", () => { expect(TagUtils.toString(opt)).toBe("amenity=binoculars&bicycle=yes") }) + it("should correctly optimize key=A&key!=B into key=A", () => { + const t = new And([new Tag("shop", "sports"), new RegexTag("shop", "mall", true)]) + const opt = t.optimize() + expect(typeof opt !== "boolean").true + expect(TagUtils.toString(opt)).toBe("shop=sports") + + }) + it("should optimize nested ORs", () => { const filter = TagUtils.Tag({ or: [ @@ -263,7 +271,7 @@ describe("Tag optimalization", () => { or: [ "club=climbing", { - and: ["sport=climbing", { or: ["club~*", "office~*"] }], + and: ["sport=climbing", {or: ["club~*", "office~*"]}], }, { and: [ diff --git a/vitest.config.ts b/vitest.config.ts index 396c31d59..0d00fdf48 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -6,6 +6,6 @@ export default defineConfig({ test: { globals: true, setupFiles: ["./test/testhooks.ts"], - include: ["./test", "./*.doctest.ts", "./**/*.doctest.ts"], + include: ["./test/*.spec.ts","./test/**/*.spec.ts", "./*.doctest.ts", "./**/*.doctest.ts"], }, })