From c8bc57aa3a5225f8407fe10e139c773b6512a272 Mon Sep 17 00:00:00 2001 From: ingalls Date: Wed, 4 Feb 2026 10:52:16 -0700 Subject: [PATCH 1/5] Add Support for ServerParts --- lib/xml/basemap.ts | 6 ++++-- test/basemaps.test.ts | 23 +++++++++++++++++++++++ test/basemaps/opentopomap.xml | 2 +- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/lib/xml/basemap.ts b/lib/xml/basemap.ts index 01c9ee7..3bcfde1 100644 --- a/lib/xml/basemap.ts +++ b/lib/xml/basemap.ts @@ -33,10 +33,11 @@ export class Basemap extends XMLDocument { tileType: string | undefined; tileUpdate: string | undefined; backgroundColor: string | undefined; + serverParts: string | undefined; } { if (!this.raw.customMapSource) throw new Err(400, null, 'Unknown Basemap Type'); if (!this.raw.customMapSource.url) throw new Err(400, null, 'Unknown Basemap Type - Missing URL'); - + return { name: this.raw.customMapSource.name ? this.raw.customMapSource.name._text : undefined, url: this.raw.customMapSource.url._text, @@ -44,7 +45,8 @@ export class Basemap extends XMLDocument { maxZoom: this.raw.customMapSource.maxZoom ? Number(this.raw.customMapSource.maxZoom._text) : undefined, tileType: this.raw.customMapSource.tileType ? this.raw.customMapSource.tileType._text : undefined, tileUpdate: this.raw.customMapSource.tileUpdate ? this.raw.customMapSource.tileUpdate._text : undefined, - backgroundColor: this.raw.customMapSource.backgroundColor ? this.raw.customMapSource.backgroundColor._text : undefined + backgroundColor: this.raw.customMapSource.backgroundColor ? this.raw.customMapSource.backgroundColor._text : undefined, + serverParts: this.raw.customMapSource.serverParts ? this.raw.customMapSource.serverParts._text : undefined, } } } diff --git a/test/basemaps.test.ts b/test/basemaps.test.ts index 6b9013f..060cd8e 100644 --- a/test/basemaps.test.ts +++ b/test/basemaps.test.ts @@ -9,11 +9,34 @@ for (const fixturename of await fs.readdir(new URL('./basemaps/', import.meta.ur const fixture = String(await fs.readFile(path.join(path.parse(fileURLToPath(import.meta.url)).dir, 'basemaps/', fixturename))); const container = await Basemap.parse(fixture); + // Ensure raw xml name exists t.ok(container.raw.customMapSource.name._text.length) const json = container.to_json(); + // Ensure JSON name exists t.ok(json.name && json.name.length); + // Ensure JSON url exists + t.ok(json.url && json.url.length); + // Ensure JSON minZoom is a number + t.ok(typeof json.minZoom === 'number'); + // Ensure JSON maxZoom is a number + t.ok(typeof json.maxZoom === 'number'); + // Ensure JSON tileType is a string + t.ok(typeof json.tileType === 'string' && json.tileType.length); + + // Ensure JSON keys match expected structure + t.deepEqual(Object.keys(json), [ + 'name', + 'url', + 'minZoom', + 'maxZoom', + 'tileType', + 'tileUpdate', + 'backgroundColor', + 'serverParts' + ]) + // End the test t.end(); }); } diff --git a/test/basemaps/opentopomap.xml b/test/basemaps/opentopomap.xml index 7539c71..5d880f9 100644 --- a/test/basemaps/opentopomap.xml +++ b/test/basemaps/opentopomap.xml @@ -7,4 +7,4 @@ IfNoneMatch a b c https://{$serverpart}.tile.opentopomap.org/{$z}/{$x}/{$y}.png - \ No newline at end of file + From a001e8a7e798e3aa7d2c60af8a1cb3a330ceaad0 Mon Sep 17 00:00:00 2001 From: ingalls Date: Wed, 4 Feb 2026 10:53:27 -0700 Subject: [PATCH 2/5] Update Basemap Test comments --- test/basemaps.test.ts | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/test/basemaps.test.ts b/test/basemaps.test.ts index 060cd8e..e9ca690 100644 --- a/test/basemaps.test.ts +++ b/test/basemaps.test.ts @@ -9,22 +9,15 @@ for (const fixturename of await fs.readdir(new URL('./basemaps/', import.meta.ur const fixture = String(await fs.readFile(path.join(path.parse(fileURLToPath(import.meta.url)).dir, 'basemaps/', fixturename))); const container = await Basemap.parse(fixture); - // Ensure raw xml name exists - t.ok(container.raw.customMapSource.name._text.length) + t.ok(container.raw.customMapSource.name._text.length, 'Ensure raw xml name exists') const json = container.to_json(); - // Ensure JSON name exists - t.ok(json.name && json.name.length); - // Ensure JSON url exists - t.ok(json.url && json.url.length); - // Ensure JSON minZoom is a number - t.ok(typeof json.minZoom === 'number'); - // Ensure JSON maxZoom is a number - t.ok(typeof json.maxZoom === 'number'); - // Ensure JSON tileType is a string - t.ok(typeof json.tileType === 'string' && json.tileType.length); + t.ok(json.name && json.name.length, 'Ensure JSON name exists'); + t.ok(json.url && json.url.length, 'Ensure JSON url exists'); + t.ok(typeof json.minZoom === 'number', 'Ensure JSON minZoom is a number'); + t.ok(typeof json.maxZoom === 'number', 'Ensure JSON maxZoom is a number'); + t.ok(typeof json.tileType === 'string' && json.tileType.length, 'Ensure JSON tileType is a string'); - // Ensure JSON keys match expected structure t.deepEqual(Object.keys(json), [ 'name', 'url', @@ -34,9 +27,8 @@ for (const fixturename of await fs.readdir(new URL('./basemaps/', import.meta.ur 'tileUpdate', 'backgroundColor', 'serverParts' - ]) + ], 'Ensure JSON keys match expected structure') - // End the test t.end(); }); } From 4a82f2a978fe91f3e680b5b554ad8ce5df9f7482 Mon Sep 17 00:00:00 2001 From: ingalls Date: Wed, 4 Feb 2026 10:57:02 -0700 Subject: [PATCH 3/5] Update Basemap Type --- lib/types/basemap.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/types/basemap.ts b/lib/types/basemap.ts index 9de1d01..b018708 100644 --- a/lib/types/basemap.ts +++ b/lib/types/basemap.ts @@ -3,27 +3,30 @@ import { Type } from '@sinclair/typebox'; export const BasemapMapSource = Type.Object({ name: Type.Object({ _text: Type.String() - }), + }, { description: 'Name of the Basemap' }), minZoom: Type.Object({ _text: Type.Integer() - }), + }, { description: 'Minimum Zoom Level' }), maxZoom: Type.Object({ _text: Type.Integer() - }), + }, { description: 'Maximum Zoom Level' }), tileType: Type.Object({ _text: Type.String() - }), + }, { description: 'Tile Format/Type' }), tileUpdate: Type.Optional(Type.Object({ _text: Type.String({ default: 'None' }) - })), + }, { description: 'Tile Update Strategy' })), url: Type.Optional(Type.Object({ _text: Type.String() - })), + }, { description: 'Tile Server URL Template' })), backgroundColor: Type.Optional(Type.Object({ _text: Type.String() - })), + }, { description: 'Map Background Color' })), + serverParts: Type.Optional(Type.Object({ + _text: Type.String() + }, { description: 'A, B, C, prefix used in some tile servers' })) }) export default Type.Object({ From 9ad22fc518466779c7188986a0308f894d196125 Mon Sep 17 00:00:00 2001 From: ingalls Date: Wed, 4 Feb 2026 11:08:35 -0700 Subject: [PATCH 4/5] Update Additional Properties --- lib/types/basemap.ts | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/types/basemap.ts b/lib/types/basemap.ts index b018708..2f6e688 100644 --- a/lib/types/basemap.ts +++ b/lib/types/basemap.ts @@ -1,32 +1,44 @@ import { Type } from '@sinclair/typebox'; +/** + * Type Schema for Basemap Map Source Configuration + * Compatible with Mobile Atlas Creator (MOBAC) Custom XML Map Sources + * @link https://mobac.sourceforge.io/wiki/index.php/Custom_XML_Map_Sources + */ + export const BasemapMapSource = Type.Object({ name: Type.Object({ _text: Type.String() - }, { description: 'Name of the Basemap' }), + }, { description: 'The name of the map source' }), minZoom: Type.Object({ _text: Type.Integer() - }, { description: 'Minimum Zoom Level' }), + }, { description: 'The minimum zoom level provided by the map source' }), maxZoom: Type.Object({ _text: Type.Integer() - }, { description: 'Maximum Zoom Level' }), + }, { description: 'The maximum zoom level provided by the map source' }), tileType: Type.Object({ _text: Type.String() - }, { description: 'Tile Format/Type' }), + }, { description: 'The image type provided by the map source' }), tileUpdate: Type.Optional(Type.Object({ _text: Type.String({ default: 'None' }) - }, { description: 'Tile Update Strategy' })), + }, { description: 'The server capabilities for conditional downloading of new/updated tiles' })), url: Type.Optional(Type.Object({ _text: Type.String() - }, { description: 'Tile Server URL Template' })), + }, { description: 'The URL for the tiles of the map source' })), + invertYCoordinate: Type.Optional(Type.Object({ + _text: Type.String() + }, { description: 'Inverts the y coordinate so that it starts south' })), backgroundColor: Type.Optional(Type.Object({ _text: Type.String() - }, { description: 'Map Background Color' })), + }, { description: 'The background color of a map' })), + ignoreErrors: Type.Optional(Type.Object({ + _text: Type.String() + }, { description: 'Handling of missing tiles' })), serverParts: Type.Optional(Type.Object({ _text: Type.String() - }, { description: 'A, B, C, prefix used in some tile servers' })) + }, { description: 'Use multiple servers for the map source' })) }) export default Type.Object({ From 6dbdfed7a0c98abdfbb5887546e6d259f67858e2 Mon Sep 17 00:00:00 2001 From: ingalls Date: Wed, 4 Feb 2026 11:09:29 -0700 Subject: [PATCH 5/5] Additional Schema Changes --- lib/types/basemap.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/types/basemap.ts b/lib/types/basemap.ts index 2f6e688..9d6fe20 100644 --- a/lib/types/basemap.ts +++ b/lib/types/basemap.ts @@ -34,10 +34,10 @@ export const BasemapMapSource = Type.Object({ _text: Type.String() }, { description: 'The background color of a map' })), ignoreErrors: Type.Optional(Type.Object({ - _text: Type.String() + _text: Type.Boolean() }, { description: 'Handling of missing tiles' })), serverParts: Type.Optional(Type.Object({ - _text: Type.String() + _text: Type.Optional(Type.String()) }, { description: 'Use multiple servers for the map source' })) })