From ab46f465a2948a3eaeb84ed28dc9ac44dab5edca Mon Sep 17 00:00:00 2001 From: Tawera Manaena Date: Tue, 3 Jun 2025 10:27:24 +1200 Subject: [PATCH 01/15] feat(cli-vector): initialise cli-vector docs command --- packages/cli-vector/src/cli/cli.docs.ts | 150 ++++++++++++++++++ packages/cli-vector/src/index.ts | 6 +- .../src/templates/vector-tile-schema.md | 51 ++++++ 3 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 packages/cli-vector/src/cli/cli.docs.ts create mode 100644 packages/cli-vector/src/templates/vector-tile-schema.md diff --git a/packages/cli-vector/src/cli/cli.docs.ts b/packages/cli-vector/src/cli/cli.docs.ts new file mode 100644 index 0000000000..ad396aee0d --- /dev/null +++ b/packages/cli-vector/src/cli/cli.docs.ts @@ -0,0 +1,150 @@ +import { fsa, Url, UrlFolder } from '@basemaps/shared'; +import { CliInfo } from '@basemaps/shared/build/cli/info.js'; +import { getLogger, logArguments } from '@basemaps/shared/build/cli/log.js'; +import { command, option } from 'cmd-ts'; +import { readFileSync } from 'fs'; +import Mustache from 'mustache'; +import { z } from 'zod'; + +import { zSchema } from '../schema-loader/parser.js'; +import { Schema } from '../schema-loader/schema.js'; + +interface Property { + name: string; + type: string; + description: string; +} + +interface Feature { + name: string; + kind: string; + geometry: string; + minZoom: number; + maxZoom: number; +} + +interface Layer { + name: string; + description: string; + properties: Property[]; + features: Feature[]; +} + +function pathToURLFolder(path: string): URL { + const url = fsa.toUrl(path); + url.search = ''; + url.hash = ''; + if (!url.pathname.endsWith('/')) url.pathname += '/'; + return url; +} + +export const DocsArgs = { + ...logArguments, + schema: option({ + type: UrlFolder, + long: 'schema', + defaultValue: () => pathToURLFolder('schema'), + description: 'Path to the directory containing the schema files from which to generate markdown docs', + }), + template: option({ + type: Url, + long: 'template', + description: 'Template file', + }), + target: option({ + type: Url, + long: 'target', + description: 'Target location for the result file', + }), +}; + +export const DocsCommand = command({ + name: 'docs', + version: CliInfo.version, + description: 'Generate markdown docs from a directory of schema files.', + args: DocsArgs, + async handler(args) { + const logger = getLogger(this, args, 'cli-vector'); + logger.info('GenerateMarkdownDocs: Start'); + + // parse schema files + const schemas: Schema[] = []; + const files = await fsa.toArray(fsa.list(args.schema)); + + for (const file of files) { + if (file.href.endsWith('.json')) { + const json = await fsa.readJson(file); + // Validate the json + try { + const parsed = zSchema.parse(json); + schemas.push(parsed); + } catch (e) { + if (e instanceof z.ZodError) { + throw new Error(`Schema ${file.href} is invalid: ${e.message}`); + } + } + } + } + + const layers: Layer[] = []; + + for (const schema of schemas) { + const properties = schema.metadata.attributes.map((attribute) => ({ + name: attribute, + type: 'TBC', + description: 'TBC', + })); + + const features = schema.layers.reduce( + (obj, layer) => { + const kind = layer.tags['kind']; + if (typeof kind !== 'string') return obj; + + // const zoom = + // layer.style.minZoom === layer.style.maxZoom + // ? layer.style.minZoom.toString() + // : `${layer.style.minZoom}-${layer.style.maxZoom}`; + + const entry = obj[kind]; + + if (entry == null) { + return { + ...obj, + [kind]: { + name: kind, + kind, + geometry: 'TBC', + minZoom: layer.style.minZoom, + maxZoom: layer.style.maxZoom, + } as Feature, + }; + } + + if (layer.style.minZoom < entry.minZoom) { + entry.minZoom = layer.style.minZoom; + } + + if (layer.style.maxZoom > entry.maxZoom) { + entry.maxZoom = layer.style.maxZoom; + } + + return obj; + }, + {} as { [key: string]: Feature }, + ); + + layers.push({ + name: schema.name, + description: 'TBC', + properties, + features: Object.values(features), + }); + } + + const template = readFileSync(args.template).toString(); + const output = Mustache.render(template, { layers }); + await fsa.write(new URL('result.md', args.target), output); + + logger.info('GenerateMarkdownDocs: End'); + }, +}); diff --git a/packages/cli-vector/src/index.ts b/packages/cli-vector/src/index.ts index a4eb55c497..63e6a522bd 100644 --- a/packages/cli-vector/src/index.ts +++ b/packages/cli-vector/src/index.ts @@ -1,7 +1,8 @@ -// eslint-disable-next-line simple-import-sort/imports import { subcommands } from 'cmd-ts'; -import { ExtractCommand } from './cli/cli.extract.js'; + import { CreateCommand } from './cli/cli.create.js'; +import { DocsCommand } from './cli/cli.docs.js'; +import { ExtractCommand } from './cli/cli.extract.js'; import { JoinCommand } from './cli/cli.join.js'; export const VectorCli = subcommands({ @@ -10,5 +11,6 @@ export const VectorCli = subcommands({ extract: ExtractCommand, create: CreateCommand, join: JoinCommand, + docs: DocsCommand, }, }); diff --git a/packages/cli-vector/src/templates/vector-tile-schema.md b/packages/cli-vector/src/templates/vector-tile-schema.md new file mode 100644 index 0000000000..cedcd471ed --- /dev/null +++ b/packages/cli-vector/src/templates/vector-tile-schema.md @@ -0,0 +1,51 @@ +{{#layers}} + +## Layer "{{name}}" + +{{description}} + +### Properties + + + + + + + + + + + {{#properties}} + + + + + + {{/properties}} + +
NameTypeDescription
{{name}}{{type}}{{description}}
+ +### Features + + + + + + + + + + + + {{#features}} + + + + + + + {{/features}} + +
Name`kind`GeometryZoom
{{name}}{{kind}}{{geometry}}{{zoom}}
+ +{{/layers}} From 99158042a2289321c834ade193ec235a9e42912f Mon Sep 17 00:00:00 2001 From: Tawera Manaena Date: Thu, 5 Jun 2025 10:03:50 +1200 Subject: [PATCH 02/15] feat(cli-vector): add documentation metadata to the JSON schema files --- packages/cli-vector/schema/addresses.json | 16 +- packages/cli-vector/schema/aerialways.json | 26 +- packages/cli-vector/schema/boundaries.json | 14 +- packages/cli-vector/schema/buildings.json | 28 +- packages/cli-vector/schema/contours.json | 37 ++- packages/cli-vector/schema/dam_lines.json | 22 +- packages/cli-vector/schema/ferries.json | 12 +- packages/cli-vector/schema/land.json | 294 ++++++++++++++++++ .../cli-vector/schema/parcel_boundaries.json | 14 +- packages/cli-vector/schema/pier_lines.json | 12 +- packages/cli-vector/schema/place_labels.json | 29 +- .../cli-vector/schema/public_transport.json | 28 +- packages/cli-vector/schema/sites.json | 54 +++- packages/cli-vector/schema/street_labels.json | 31 +- .../cli-vector/schema/street_polygons.json | 22 +- packages/cli-vector/schema/streets.json | 144 +++++++++ packages/cli-vector/schema/water_lines.json | 80 ++++- .../cli-vector/schema/water_polygons.json | 72 ++++- 18 files changed, 918 insertions(+), 17 deletions(-) diff --git a/packages/cli-vector/schema/addresses.json b/packages/cli-vector/schema/addresses.json index 1429d81b88..d5ce9412f6 100644 --- a/packages/cli-vector/schema/addresses.json +++ b/packages/cli-vector/schema/addresses.json @@ -1,13 +1,25 @@ { "name": "addresses", - "metadata": { "attributes": ["housenumber", "name", "id"] }, + "metadata": { + "attributes": ["housenumber"], + "schema": [ + { + "filter": ["all"], + "properties": { + "housenumber": { "guaranteed": true, "type": "string" } + }, + "geometry": "Point", + "zoom_levels": { "min": 15, "max": 15 } + } + ] + }, "layers": [ { "id": "105689", "name": "105689-nz-addresses-pilot", "source": "s3://linz-lds-cache/105689/", "tags": {}, - "attributes": { "address_id": "id", "full_address_number": "housenumber" }, + "attributes": { "full_address_number": "housenumber" }, "style": { "minZoom": 15, "maxZoom": 15 } } ] diff --git a/packages/cli-vector/schema/aerialways.json b/packages/cli-vector/schema/aerialways.json index fa29381c0c..8520367d34 100644 --- a/packages/cli-vector/schema/aerialways.json +++ b/packages/cli-vector/schema/aerialways.json @@ -1,6 +1,30 @@ { "name": "aerialways", - "metadata": { "attributes": ["kind", "feature", "name"] }, + "metadata": { + "attributes": ["kind", "feature"], + "schema": [ + { + "filter": ["all", ["==", "kind", "cable_car"]], + "properties": { + "feature": { "guaranteed": true, "type": "string", "values": ["people", "industrial"] } + }, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "ski_lift"]], + "properties": {}, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "ski_tow"]], + "properties": {}, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + } + ] + }, "layers": [ { "id": "50248", diff --git a/packages/cli-vector/schema/boundaries.json b/packages/cli-vector/schema/boundaries.json index cb0e9a18ad..011b81336a 100644 --- a/packages/cli-vector/schema/boundaries.json +++ b/packages/cli-vector/schema/boundaries.json @@ -1,6 +1,18 @@ { "name": "boundaries", - "metadata": { "attributes": ["name"] }, + "metadata": { + "attributes": ["name"], + "schema": [ + { + "filter": ["all"], + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 0, "max": 15 } + } + ] + }, "simplify": [ { "style": { "minZoom": 0, "maxZoom": 0 }, "tolerance": 0.1 }, { "style": { "minZoom": 1, "maxZoom": 1 }, "tolerance": 0.09 }, diff --git a/packages/cli-vector/schema/buildings.json b/packages/cli-vector/schema/buildings.json index 0778919ab4..0bf2b0996e 100644 --- a/packages/cli-vector/schema/buildings.json +++ b/packages/cli-vector/schema/buildings.json @@ -1,6 +1,32 @@ { "name": "buildings", - "metadata": { "attributes": ["building", "store_item", "kind", "name", "use"] }, + "metadata": { + "attributes": ["building", "store_item", "kind", "name", "use"], + "schema": [ + { + "filter": ["all", ["!has", "kind"]], + "properties": { + "building": { "guaranteed": true, "type": "string", "values": ["storage_tank"] }, + "store_item": { "guaranteed": false, "type": "string", "values": ["fuel", "water"] } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 9, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "building"]], + "properties": { + "name": { "guaranteed": true, "type": "string" }, + "use": { + "guaranteed": true, + "type": "string", + "values": ["Unknown", "Supermarket", "School", "Hospital", "Hut", "Shelter"] + } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 14, "max": 15 } + } + ] + }, "layers": [ { "id": "101290", diff --git a/packages/cli-vector/schema/contours.json b/packages/cli-vector/schema/contours.json index 817f6a35d1..f52399cbec 100644 --- a/packages/cli-vector/schema/contours.json +++ b/packages/cli-vector/schema/contours.json @@ -1,6 +1,41 @@ { "name": "contours", - "metadata": { "attributes": ["designated", "type", "nat_form", "elevation", "kind", "name", "rank"] }, + "metadata": { + "attributes": ["designated", "type", "nat_form", "elevation", "kind", "name", "rank"], + "schema": [ + { + "filter": ["all", ["==", "kind", "contours"]], + "properties": { + "designated": { + "guaranteed": false, + "type": "string", + "values": ["supplementary"] + }, + "elevation": { + "guaranteed": true, + "type": "number" + }, + "nat_form": { "guaranteed": false, "type": "string", "values": ["depression"] }, + "type": { + "guaranteed": ["all", ["modulo_100", "elevation", 0]], + "type": "string", + "values": ["index"] + } + }, + "geometry": "LineString", + "zoom_levels": { "min": 9, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "peak"]], + "properties": { + "elevation": { "guaranteed": false, "type": "number" }, + "rank": { "guaranteed": false, "type": "number", "values": [5, 4, 3, 2, 1] } + }, + "geometry": "Point", + "zoom_levels": { "min": 9, "max": 15 } + } + ] + }, "layers": [ { "id": "50768", diff --git a/packages/cli-vector/schema/dam_lines.json b/packages/cli-vector/schema/dam_lines.json index b96904e066..9b83133d74 100644 --- a/packages/cli-vector/schema/dam_lines.json +++ b/packages/cli-vector/schema/dam_lines.json @@ -1,6 +1,26 @@ { "name": "dam_lines", - "metadata": { "attributes": ["kind", "name", "dam_status"] }, + "metadata": { + "attributes": ["kind", "name", "dam_status"], + "schema": [ + { + "filter": ["all", ["==", "kind", "dam"]], + "properties": { + "dam_status": { + "guaranteed": false, + "type": "string", + "values": ["old", "ruins", "disused"] + }, + "name": { + "guaranteed": false, + "type": "string" + } + }, + "geometry": "LineString", + "zoom_levels": { "min": 4, "max": 15 } + } + ] + }, "layers": [ { "id": "50075", diff --git a/packages/cli-vector/schema/ferries.json b/packages/cli-vector/schema/ferries.json index d4449f422c..57c927982b 100644 --- a/packages/cli-vector/schema/ferries.json +++ b/packages/cli-vector/schema/ferries.json @@ -1,6 +1,16 @@ { "name": "ferries", - "metadata": { "attributes": ["kind", "name"] }, + "metadata": { + "attributes": ["kind"], + "schema": [ + { + "filter": ["all", ["==", "kind", "ferry"]], + "properties": {}, + "geometry": "LineString", + "zoom_levels": { "min": 10, "max": 15 } + } + ] + }, "layers": [ { "id": "50269", diff --git a/packages/cli-vector/schema/land.json b/packages/cli-vector/schema/land.json index 535f31350c..3bcb774ba6 100644 --- a/packages/cli-vector/schema/land.json +++ b/packages/cli-vector/schema/land.json @@ -13,6 +13,300 @@ "substance", "visibility", "status" + ], + "schema": [ + { + "filter": ["all", ["==", "kind", "bare_rock"]], + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 14, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "boatramp"]], + "properties": { + "name": { + "guaranteed": false, + "type": "string", + "values": ["boatramp", "Te Onepoto Boat Ramp", "Namukulu Boat Ramp"] + } + }, + "geometry": "LineString", + "zoom_levels": { "min": 10, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "cemetery"]], + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 10, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "cliff"]], + "properties": {}, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "cutting"]], + "properties": {}, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "dredge_tailing"]], + "properties": {}, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "dry_dock"]], + "properties": {}, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "embankment"]], + "properties": { + "embkmt_use": { + "guaranteed": false, + "type": "string", + "values": ["stopbank", "causeway", "seawall"] + }, + "name": { "guaranteed": false, "type": "string", "values": ["Tamehanas Dam"] } + }, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "fence"]], + "properties": {}, + "geometry": "LineString", + "zoom_levels": { "min": 13, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "forest"]], + "properties": { + "landuse": { "guaranteed": false, "type": "string", "values": ["forest", "wood"] }, + "species": { "guaranteed": false, "type": "string", "values": ["non-coniferous"] }, + "tree": { "guaranteed": true, "type": "string", "values": ["native", "exotic"] } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 0, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "golf_course"]], + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 6, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "ice"]], + "properties": {}, + "geometry": "Polygon", + "zoom_levels": { "min": 2, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "ladder"]], + "properties": {}, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "landfill"]], + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "mangrove"]], + "properties": {}, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "mine"]], + "properties": { + "name": { "guaranteed": false, "type": "string" }, + "status": { + "guaranteed": false, + "type": "string", + "values": ["historic", "disused", "old"] + }, + "substance": { + "guaranteed": false, + "type": "string", + "values": ["coal", "gold", "ironsand"] + }, + "visibility": { + "guaranteed": true, + "type": "string", + "values": ["opencast"] + } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "moraine"]], + "properties": {}, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "moraine_wall"]], + "properties": {}, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "mud"]], + "properties": {}, + "geometry": "Polygon", + "zoom_levels": { "min": 1, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "orchard"]], + "properties": {}, + "geometry": "Polygon", + "zoom_levels": { "min": 10, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "pipeline"]], + "properties": { + "visibility": { "guaranteed": false, "type": "string", "values": ["underground"] } + }, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "pond"]], + "properties": { + "name": { + "guaranteed": false, + "type": "string", + "values": ["Lake Crichton", "pond", "ponds"] + } + }, + "geometry": "Polygon", + "zoom_levels": { "max": 15, "min": 9 } + }, + { + "filter": ["all", ["==", "kind", "powerline"]], + "properties": { + "support_ty": { "guaranteed": false, "type": "string", "values": ["pole", "pylon"] } + }, + "geometry": "LineString", + "zoom_levels": { "min": 0, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "quarry"]], + "properties": { + "name": { "guaranteed": false, "type": "string" }, + "status": { "guaranteed": false, "type": "string", "values": ["disused"] }, + "substance": { + "guaranteed": false, + "type": "string", + "values": ["lime", "limestone", "silica sand", "stone", "clay", "gravel", "shingle", "metal", "zeolite"] + } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "residential"]], + "properties": { + "name": { + "guaranteed": false, + "type": "string" + } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 0, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "sand"]], + "properties": {}, + "geometry": "Polygon", + "zoom_levels": { "min": 8, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "scree"]], + "properties": {}, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "scrub"]], + "properties": { + "distribution": { "guaranteed": false, "type": "string", "values": ["scattered"] } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 0, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "shingle"]], + "properties": {}, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "siphon"]], + "properties": {}, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "slip"]], + "properties": {}, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "slipway"]], + "properties": {}, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "swamp"]], + + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 2, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "telephone"]], + "properties": {}, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "tree_row"]], + "properties": {}, + "geometry": "LineString", + "zoom_levels": { "min": 8, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "vineyard"]], + "properties": {}, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "walkwire"]], + "properties": {}, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + } ] }, "layers": [ diff --git a/packages/cli-vector/schema/parcel_boundaries.json b/packages/cli-vector/schema/parcel_boundaries.json index f007e949b1..b4b3fcfe1b 100644 --- a/packages/cli-vector/schema/parcel_boundaries.json +++ b/packages/cli-vector/schema/parcel_boundaries.json @@ -1,6 +1,18 @@ { "name": "parcel_boundaries", - "metadata": { "attributes": ["parcel_intent", "name", "id"] }, + "metadata": { + "attributes": ["parcel_intent", "name", "id"], + "schema": [ + { + "filter": ["all"], + "properties": { + "parcel_intent": { "guaranteed": true, "type": "string" } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 14, "max": 15 } + } + ] + }, "layers": [ { "id": "50772", diff --git a/packages/cli-vector/schema/pier_lines.json b/packages/cli-vector/schema/pier_lines.json index 8e153b6b0b..148acc5dc1 100644 --- a/packages/cli-vector/schema/pier_lines.json +++ b/packages/cli-vector/schema/pier_lines.json @@ -1,6 +1,16 @@ { "name": "pier_lines", - "metadata": { "attributes": ["kind", "name"] }, + "metadata": { + "attributes": ["kind", "name"], + "schema": [ + { + "filter": ["all", ["==", "kind", "breakwater"]], + "properties": {}, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + } + ] + }, "layers": [ { "id": "50243", diff --git a/packages/cli-vector/schema/place_labels.json b/packages/cli-vector/schema/place_labels.json index 59853dac8f..8ca338e55f 100644 --- a/packages/cli-vector/schema/place_labels.json +++ b/packages/cli-vector/schema/place_labels.json @@ -1,6 +1,33 @@ { "name": "place_labels", - "metadata": { "attributes": ["water", "name", "natural", "place"] }, + "metadata": { + "attributes": ["water", "name", "natural", "place"], + "schema": [ + { + "filter": ["all"], + "properties": { + "name": { "guaranteed": true, "type": "string" }, + "natural": { + "guaranteed": true, + "type": "string", + "values": ["0", "cape", "peninsula", "peak"] + }, + "place": { + "guaranteed": true, + "type": "string", + "values": ["0", "island", "archipelago", "city", "town", "lake", "village", "suburb", "Island"] + }, + "water": { + "guaranteed": true, + "type": "string", + "values": ["sea", "0", "ocean", "searidge", "seachannel", "seamount", "seacanyon", "bay", "lagoon"] + } + }, + "geometry": "Point", + "zoom_levels": { "min": 3, "max": 14 } + } + ] + }, "layers": [ { "id": "51154", diff --git a/packages/cli-vector/schema/public_transport.json b/packages/cli-vector/schema/public_transport.json index ceaea5f8e3..4531ec057f 100644 --- a/packages/cli-vector/schema/public_transport.json +++ b/packages/cli-vector/schema/public_transport.json @@ -1,6 +1,32 @@ { "name": "public_transport", - "metadata": { "attributes": ["kind", "name"] }, + "metadata": { + "attributes": ["kind", "name"], + "schema": [ + { + "filter": ["all", ["==", "kind", "aerodrome"]], + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "Point", + "zoom_levels": { "min": 0, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "helipad"]], + "properties": {}, + "geometry": "Point", + "zoom_levels": { "min": 10, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "station"]], + "properties": { + "name": { "guaranteed": true, "type": "string" } + }, + "geometry": "Point", + "zoom_levels": { "min": 12, "max": 15 } + } + ] + }, "layers": [ { "id": "50237", diff --git a/packages/cli-vector/schema/sites.json b/packages/cli-vector/schema/sites.json index ea9cd92c05..32ad338dee 100644 --- a/packages/cli-vector/schema/sites.json +++ b/packages/cli-vector/schema/sites.json @@ -1,6 +1,58 @@ { "name": "sites", - "metadata": { "attributes": ["kind", "species", "name", "type", "track_type", "track_use"] }, + "metadata": { + "attributes": ["kind", "species", "name", "type", "track_type", "track_use"], + "schema": [ + { + "filter": ["all", ["==", "kind", "fish_farm"]], + "properties": { + "species": { "guaranteed": false, "type": "string", "values": ["salmon"] } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "gravel_pit"]], + "properties": {}, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "pumice_pit"]], + "properties": {}, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "raceway"]], + "properties": { + "name": { "guaranteed": false, "type": "string" }, + "track_type": { "guaranteed": false, "type": "string", "values": ["training"] }, + "track_use": { + "guaranteed": false, + "type": "string", + "values": ["horse", "vehicle"] + } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "showground"]], + "properties": {}, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "sports_field"]], + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 7, "max": 15 } + } + ] + }, "layers": [ { "id": "50283", diff --git a/packages/cli-vector/schema/street_labels.json b/packages/cli-vector/schema/street_labels.json index a9ed8f949c..73a658dbc8 100644 --- a/packages/cli-vector/schema/street_labels.json +++ b/packages/cli-vector/schema/street_labels.json @@ -1,6 +1,35 @@ { "name": "street_labels", - "metadata": { "attributes": ["kind", "ref", "name"] }, + "metadata": { + "attributes": ["kind", "ref", "name"], + "schema": [ + { + "filter": ["all", ["==", "kind", "motorway"]], + "properties": { + "name": { "guaranteed": false, "type": "string" }, + "ref": { "guaranteed": true, "type": "string" } + }, + "geometry": "LineString", + "zoom_levels": { "min": 8, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "primary"]], + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "LineString", + "zoom_levels": { "min": 8, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "secondary"]], + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "LineString", + "zoom_levels": { "min": 8, "max": 15 } + } + ] + }, "layers": [ { "id": "50329", diff --git a/packages/cli-vector/schema/street_polygons.json b/packages/cli-vector/schema/street_polygons.json index 8461bf27d3..451ab80f85 100644 --- a/packages/cli-vector/schema/street_polygons.json +++ b/packages/cli-vector/schema/street_polygons.json @@ -1,6 +1,26 @@ { "name": "street_polygons", - "metadata": { "attributes": ["kind", "surface", "name"] }, + "metadata": { + "attributes": ["kind", "surface", "name"], + "schema": [ + { + "filter": ["all", ["==", "kind", "aerodrome"]], + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 5, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "runway"]], + "properties": { + "surface": { "guaranteed": false, "type": "string", "values": ["sealed"] } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 10, "max": 15 } + } + ] + }, "layers": [ { "id": "50237", diff --git a/packages/cli-vector/schema/streets.json b/packages/cli-vector/schema/streets.json index dbeaea167a..c0b5564131 100644 --- a/packages/cli-vector/schema/streets.json +++ b/packages/cli-vector/schema/streets.json @@ -19,6 +19,150 @@ "use_2", "ref", "subclass" + ], + "schema": [ + { + "filter": ["all", ["==", "kind", "aerodrome"]], + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 5, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "motorway"]], + "properties": { + "hway_num": { "guaranteed": true, "type": "string" }, + "lane_count": { + "guaranteed": true, + "type": "number", + "values": [1, 2, 3, 4, 5, 6, 7] + }, + "name": { "guaranteed": false, "type": "string" }, + "ref": { "guaranteed": true, "type": "string" }, + "surface": { "guaranteed": true, "type": "string", "values": ["sealed", "metalled"] } + }, + "geometry": "LineString", + "zoom_levels": { "min": 8, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "primary"]], + "properties": { + "lane_count": { "guaranteed": true, "type": "number", "values": [4, 5, 6] }, + "name": { "guaranteed": false, "type": "string" }, + "status": { "guaranteed": false, "type": "string", "values": ["under construction"] }, + "surface": { "guaranteed": true, "type": "string", "values": ["sealed", "unmetalled"] } + }, + "geometry": "LineString", + "zoom_levels": { "min": 8, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "raceway"]], + + "properties": { + "name": { "guaranteed": false, "type": "string" }, + "track_type": { "guaranteed": false, "type": "string", "values": ["training"] }, + "track_use": { + "guaranteed": false, + "type": "string", + "values": ["horse", "vehicle", "cycle", "dog"] + } + }, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "rail"]], + + "properties": { + "name": { "guaranteed": false, "type": "string" }, + "rway_use": { "guaranteed": false, "type": "string", "values": ["siding"] }, + "status": { "guaranteed": false, "type": "string", "values": ["disused"] }, + "track_type": { + "guaranteed": true, + "type": "string", + "values": ["single", "multiple"] + } + }, + "geometry": "LineString", + "zoom_levels": { "min": 0, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "runway"]], + "properties": { + "status": { "guaranteed": false, "type": "string", "values": ["disused"] }, + "surface": { "guaranteed": false, "type": "string", "values": ["sealed"] } + }, + "geometry": "Polygon", + "zoom_levels": { "max": 15, "min": 10 } + }, + { + "filter": ["all", ["==", "kind", "secondary"]], + "geometry": "LineString, Point", + "properties": { + "bridge": { "guaranteed": false, "type": "boolean", "values": [true] }, + "ford": { "guaranteed": false, "type": "boolean", "values": [true] }, + "lane_count": { "guaranteed": false, "type": "number", "values": [1, 2, 3] }, + "name": { "guaranteed": false, "type": "string" }, + "status": { + "guaranteed": false, + "type": "string", + "values": ["under construction", "closed", "derelict", "disused", "historic"] + }, + "surface": { + "guaranteed": false, + "type": "string", + "values": ["metalled", "unmetalled", "sealed"] + }, + "tunnel": { "guaranteed": false, "type": "boolean", "values": [true] }, + "use_1": { + "guaranteed": false, + "type": "string", + "values": ["vehicle", "foot traffic", "farm", "train", "cablecar"] + }, + "use_2": { "guaranteed": false, "type": "string", "values": ["train"] } + }, + "zoom_levels": { "min": 8, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "track"]], + "properties": { + "name": { "guaranteed": false, "type": "string" }, + "status": { + "guaranteed": false, + "type": "string", + "values": ["closed", "unmaintained"] + }, + "subclass": { + "guaranteed": false, + "type": "string", + "values": [ + "foot", + "foot_route", + "foot_closed", + "vehicle", + "cycle only", + "vehicle_closed", + "foot_connector", + "foot_routeroute", + "foot_route_closed", + "vehicle_unmaintained" + ] + }, + "track_type": { + "guaranteed": false, + "type": "string", + "values": ["route", "connector", "routeroute"] + }, + "track_use": { + "guaranteed": false, + "type": "string", + "values": ["foot", "vehicle", "cycle only"] + } + }, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + } ] }, "layers": [ diff --git a/packages/cli-vector/schema/water_lines.json b/packages/cli-vector/schema/water_lines.json index 252514239f..0e8faec495 100644 --- a/packages/cli-vector/schema/water_lines.json +++ b/packages/cli-vector/schema/water_lines.json @@ -1,6 +1,84 @@ { "name": "water_lines", - "metadata": { "attributes": ["kind", "name", "feature", "species", "height"] }, + "metadata": { + "attributes": ["kind", "name", "feature", "species", "height"], + "schema": [ + { + "filter": ["all", ["==", "kind", "boom"]], + "properties": {}, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "drain"]], + "properties": {}, + "geometry": "LineString", + "zoom_levels": { "min": 10, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "flume"]], + "properties": {}, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "marine_farm"]], + "properties": { + "geometry": "LineString", + "species": { "guaranteed": false, "type": "string", "values": ["salmon"] } + }, + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "river"]], + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "LineString", + "zoom_levels": { "min": 8, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "stream"]], + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "water_race"]], + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "waterfall"]], + "properties": { + "feature": { "guaranteed": false, "type": "string", "values": ["edge"] }, + "height": { "guaranteed": true, "type": "number" }, + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "LineString", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "wharf"]], + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "LineString", + "zoom_levels": { "min": 10, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "wharf_edge"]], + "properties": {}, + "geometry": "LineString", + "zoom_levels": { "min": 10, "max": 15 } + } + ] + }, "layers": [ { "id": "103632", diff --git a/packages/cli-vector/schema/water_polygons.json b/packages/cli-vector/schema/water_polygons.json index b1226ea641..3e4ba806fc 100644 --- a/packages/cli-vector/schema/water_polygons.json +++ b/packages/cli-vector/schema/water_polygons.json @@ -1,6 +1,76 @@ { "name": "water_polygons", - "metadata": { "attributes": ["water", "kind", "name", "lid_type", "species", "height", "direction"] }, + "metadata": { + "attributes": ["water", "kind", "name", "lid_type", "species", "height", "direction"], + "schema": [ + { + "filter": ["all", ["==", "kind", "marine_farm"]], + "properties": { + "species": { "guaranteed": false, "type": "string", "values": ["mussels"] } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "reef"]], + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 1, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "reservoir"]], + "properties": { + "lid_type": { "guaranteed": false, "type": "string", "values": ["covered"] } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 10, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "river"]], + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 9, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "shoal"]], + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "stream"]], + "properties": { + "name": { "guaranteed": false, "type": "string" } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "water"]], + "properties": { + "name": { "guaranteed": false, "type": "string" }, + "water": { "guaranteed": true, "type": "string", "values": ["lagoon", "lake"] } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 1, "max": 15 } + }, + { + "filter": ["all", ["==", "kind", "waterfall"]], + "properties": { + "height": { "guaranteed": true, "type": "number", "values": [56] }, + "name": { "guaranteed": true, "type": "string", "values": ["Alice Falls"] } + }, + "geometry": "Polygon", + "zoom_levels": { "min": 12, "max": 15 } + } + ] + }, "layers": [ { "id": "103631", From 2d7820398f55faa12f38ca657fb5238ab4b1c1e0 Mon Sep 17 00:00:00 2001 From: Tawera Manaena Date: Fri, 6 Jun 2025 11:11:53 +1200 Subject: [PATCH 03/15] fix(cli-vector): install mustache dependency --- package-lock.json | 18 ++++++++++++++++++ packages/cli-vector/package.json | 2 ++ 2 files changed, 20 insertions(+) diff --git a/package-lock.json b/package-lock.json index 01758acb86..600f9bef8a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5400,6 +5400,13 @@ "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", "dev": true }, + "node_modules/@types/mustache": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/@types/mustache/-/mustache-4.2.6.tgz", + "integrity": "sha512-t+8/QWTAhOFlrF1IVZqKnMRJi84EgkIK5Kh0p2JV4OLywUvCwJPFxbJAl7XAow7DVIHsF+xW9f1MVzg0L6Szjw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "22.15.24", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.24.tgz", @@ -13950,6 +13957,15 @@ "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==", "dev": true }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "license": "MIT", + "bin": { + "mustache": "bin/mustache" + } + }, "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -19598,6 +19614,7 @@ "@linzjs/docker-command": "^7.5.0", "@linzjs/geojson": "^8.0.0", "cmd-ts": "^0.12.1", + "mustache": "^4.2.0", "p-limit": "^6.2.0", "polylabel": "^2.0.1", "stac-ts": "^1.0.0", @@ -19609,6 +19626,7 @@ }, "devDependencies": { "@types/geojson": "^7946.0.7", + "@types/mustache": "^4.2.6", "@types/polylabel": "^1.1.3", "@types/tar-stream": "^2.2.2" }, diff --git a/packages/cli-vector/package.json b/packages/cli-vector/package.json index cc27195f20..cad12347ea 100644 --- a/packages/cli-vector/package.json +++ b/packages/cli-vector/package.json @@ -37,6 +37,7 @@ }, "devDependencies": { "@types/geojson": "^7946.0.7", + "@types/mustache": "^4.2.6", "@types/polylabel": "^1.1.3", "@types/tar-stream": "^2.2.2" }, @@ -56,6 +57,7 @@ "@linzjs/docker-command": "^7.5.0", "@linzjs/geojson": "^8.0.0", "cmd-ts": "^0.12.1", + "mustache": "^4.2.0", "p-limit": "^6.2.0", "polylabel": "^2.0.1", "stac-ts": "^1.0.0", From eb7c3c094064efd213603cab5b6b0e02bcce9e6c Mon Sep 17 00:00:00 2001 From: Tawera Manaena Date: Wed, 11 Jun 2025 14:10:34 +1200 Subject: [PATCH 04/15] feat(cli-vector): implement cli-vector reports command --- packages/cli-vector/src/cli/cli.reports.ts | 178 +++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 packages/cli-vector/src/cli/cli.reports.ts diff --git a/packages/cli-vector/src/cli/cli.reports.ts b/packages/cli-vector/src/cli/cli.reports.ts new file mode 100644 index 0000000000..2521dca97c --- /dev/null +++ b/packages/cli-vector/src/cli/cli.reports.ts @@ -0,0 +1,178 @@ +import { DatabaseSync } from 'node:sqlite'; + +import { Url, UrlFolder } from '@basemaps/shared'; +import { CliInfo } from '@basemaps/shared/build/cli/info.js'; +import { getLogger, logArguments } from '@basemaps/shared/build/cli/log.js'; +import { VectorTile, VectorTileFeature } from '@mapbox/vector-tile'; +import { command, oneOf, option } from 'cmd-ts'; +import { existsSync, mkdirSync, writeFileSync } from 'fs'; +import Protobuf from 'pbf'; +import { gunzipSync } from 'zlib'; + +import { Report } from '../schema-loader/schema.js'; + +export const MaxValues = 24; +const MaxZoom = 15; + +export const ReportsArgs = { + ...logArguments, + mbtiles: option({ + type: Url, + long: 'mbtiles', + description: + 'Path to the mbtiles or config containing path to mbtiles from which to generate reports. (based on file extension)', + }), + target: option({ + type: UrlFolder, + long: 'target', + description: 'Target directory into which to save the generated reports.', + }), + mode: option({ + type: oneOf(['none', 'limited', 'full']), + defaultValue: () => 'limited', + defaultValueIsSerializable: true, + long: 'mode', + description: + 'For each attribute: ' + + 'none - do not output any values (fast). ' + + `limited - only output the first ${MaxValues} unique values. ` + + 'full - output all unique values (slow).', + }), +}; + +export const ReportsCommand = command({ + name: 'reports', + version: CliInfo.version, + description: + 'Parses an MBTiles file to extract and report detailed information about its contents. ' + + 'Identifies the layers, features within those layers, and attributes for each feature.', + args: ReportsArgs, + handler(args) { + const logger = getLogger(this, args, 'cli-vector'); + logger.info('Reports: Start'); + + const targetExists = existsSync(args.target); + if (!targetExists) mkdirSync(args.target, { recursive: true }); + + const layerReports: Record = {}; + + const db = new DatabaseSync(args.mbtiles); + for (let zoomLevel = 0; zoomLevel <= MaxZoom; zoomLevel++) { + logger.info({ zoomLevel }, 'Start'); + + const rows = db + .prepare( + 'SELECT tile_column AS x, tile_row AS y, zoom_level AS z, tile_data AS data ' + + 'FROM tiles ' + + 'WHERE zoom_level = ?', + ) + .all(zoomLevel) as { x: number; y: number; z: number; data: Buffer }[]; + + for (const row of rows) { + logger.info({ x: row.x, y: row.y, z: row.z }, 'Start'); + + const buffer = gunzipSync(row.data); + const tile = new VectorTile(new Protobuf(buffer)); + + // Prepare layer information + for (const [name, layer] of Object.entries(tile.layers)) { + if (layerReports[name] == null) { + layerReports[name] = { + name, + all: { attributes: {}, geometries: [], zoom_levels: [] }, + }; + } + + const layerReport = layerReports[name]; + + // for each the layer's features + for (let i = 0; i < layer.length; i++) { + const feature = layer.feature(i); + const properties = feature.properties; + const geometry = VectorTileFeature.types[feature.type]; + const kind = properties['kind']; + + const reports = [layerReport.all]; + + if (typeof kind === 'string') { + if (layerReport.kinds == null) { + layerReport.kinds = {}; + } + + if (layerReport.kinds[kind] == null) { + layerReport.kinds[kind] = { attributes: {}, geometries: [], zoom_levels: [] }; + } + + reports.push(layerReport.kinds[kind]); + } + + for (const report of reports) { + // append attribute + for (const [name, value] of Object.entries(properties)) { + if (report.attributes[name] == null) { + report.attributes[name] = { + guaranteed: true, + num_unique_values: 0, + values: [], + types: [], + }; + } + + const attributeReport = report.attributes[name]; + + // append type + const type = typeof value; + + if (!attributeReport.types.includes(type)) { + attributeReport.types.push(type); + } + + // handle value + if (!attributeReport.values.includes(value)) { + attributeReport.num_unique_values++; + + // append value based on the mode + if (args.mode === 'limited') { + if (attributeReport.num_unique_values < MaxValues) { + attributeReport.values.push(value); + } + } else if (args.mode === 'full') { + attributeReport.values.push(value); + } + } + + // append geometry + if (!report.geometries.includes(geometry)) { + report.geometries.push(geometry); + } + + // append zoom level + if (!report.zoom_levels.includes(row.z)) { + report.zoom_levels.push(row.z); + } + } + + // check the current feature's properties against the already captured attributes + for (const [name, attribute] of Object.entries(report.attributes)) { + if (attribute.guaranteed === true) { + if (properties[name] == null) { + attribute.guaranteed = false; + } + } + } + } + } + } + } + + logger.info({ zoomLevel }, 'End'); + } + + db.close(); + + for (const [name, report] of Object.entries(layerReports)) { + writeFileSync(new URL(`${name}.json`, args.target), JSON.stringify(report, null, 2)); + } + logger.info('Reports: Done'); + }, +}); From b80ab4411c5fd3e23dcf0afd539a4d41dd72be79 Mon Sep 17 00:00:00 2001 From: Tawera Manaena Date: Wed, 11 Jun 2025 14:10:53 +1200 Subject: [PATCH 05/15] feat(cli-vector): refine cli-vector docs command --- packages/cli-vector/src/cli/cli.docs.ts | 226 +++++++++++++++--------- 1 file changed, 144 insertions(+), 82 deletions(-) diff --git a/packages/cli-vector/src/cli/cli.docs.ts b/packages/cli-vector/src/cli/cli.docs.ts index ad396aee0d..1dd599edce 100644 --- a/packages/cli-vector/src/cli/cli.docs.ts +++ b/packages/cli-vector/src/cli/cli.docs.ts @@ -2,76 +2,83 @@ import { fsa, Url, UrlFolder } from '@basemaps/shared'; import { CliInfo } from '@basemaps/shared/build/cli/info.js'; import { getLogger, logArguments } from '@basemaps/shared/build/cli/log.js'; import { command, option } from 'cmd-ts'; -import { readFileSync } from 'fs'; +import { existsSync, mkdirSync, readFileSync } from 'fs'; import Mustache from 'mustache'; import { z } from 'zod'; -import { zSchema } from '../schema-loader/parser.js'; -import { Schema } from '../schema-loader/schema.js'; +import { zReport, zSchema } from '../schema-loader/parser.js'; +import { Report, ReportAttribute, Schema } from '../schema-loader/schema.js'; +import { MaxValues } from './cli.reports.js'; -interface Property { +interface Doc { name: string; - type: string; - description: string; + description?: string; + isCustom: boolean; + all: DocEntry; + kinds?: DocEntry[]; } -interface Feature { +interface DocEntry { name: string; - kind: string; - geometry: string; - minZoom: number; - maxZoom: number; + filter: string; + attributes: DocAttribute[]; + hasAttributes: boolean; + geometries: string; + zoom_levels: { + min: number; + max: number; + }; } -interface Layer { +interface DocAttribute { name: string; - description: string; - properties: Property[]; - features: Feature[]; -} - -function pathToURLFolder(path: string): URL { - const url = fsa.toUrl(path); - url.search = ''; - url.hash = ''; - if (!url.pathname.endsWith('/')) url.pathname += '/'; - return url; + types: string; + values: string; } export const DocsArgs = { ...logArguments, - schema: option({ + schemas: option({ type: UrlFolder, - long: 'schema', - defaultValue: () => pathToURLFolder('schema'), - description: 'Path to the directory containing the schema files from which to generate markdown docs', + long: 'schemas', + description: 'Path to the directory containing schemas from which to extract layer-specific information.', + }), + reports: option({ + type: UrlFolder, + long: 'reports', + description: + 'Path to the directory containing reports from which to extract layer, feature, and attribute information.', }), template: option({ type: Url, long: 'template', - description: 'Template file', + description: 'Path to the Mustache template markdown file.', }), target: option({ type: Url, long: 'target', - description: 'Target location for the result file', + description: 'Target directory into which to save the generated markdown documentation.', }), }; export const DocsCommand = command({ name: 'docs', version: CliInfo.version, - description: 'Generate markdown docs from a directory of schema files.', + description: + 'Parses a directory of JSON report files and a Mustache template file to generate a collection of vector tile schema markdown files.', args: DocsArgs, async handler(args) { const logger = getLogger(this, args, 'cli-vector'); - logger.info('GenerateMarkdownDocs: Start'); + logger.info('Docs: Start'); + + const targetExists = existsSync(args.target); + if (!targetExists) mkdirSync(args.target, { recursive: true }); // parse schema files const schemas: Schema[] = []; - const files = await fsa.toArray(fsa.list(args.schema)); + const schemaFiles = await fsa.toArray(fsa.list(args.schemas)); - for (const file of files) { + for (const file of schemaFiles) { if (file.href.endsWith('.json')) { const json = await fsa.readJson(file); // Validate the json @@ -86,65 +93,120 @@ export const DocsCommand = command({ } } - const layers: Layer[] = []; - - for (const schema of schemas) { - const properties = schema.metadata.attributes.map((attribute) => ({ - name: attribute, - type: 'TBC', - description: 'TBC', - })); - - const features = schema.layers.reduce( - (obj, layer) => { - const kind = layer.tags['kind']; - if (typeof kind !== 'string') return obj; - - // const zoom = - // layer.style.minZoom === layer.style.maxZoom - // ? layer.style.minZoom.toString() - // : `${layer.style.minZoom}-${layer.style.maxZoom}`; - - const entry = obj[kind]; - - if (entry == null) { - return { - ...obj, - [kind]: { - name: kind, - kind, - geometry: 'TBC', - minZoom: layer.style.minZoom, - maxZoom: layer.style.maxZoom, - } as Feature, - }; - } + // parse report files + const reports: Report[] = []; + const reportFiles = await fsa.toArray(fsa.list(args.reports)); - if (layer.style.minZoom < entry.minZoom) { - entry.minZoom = layer.style.minZoom; + for (const file of reportFiles) { + if (file.href.endsWith('.json')) { + const json = await fsa.readJson(file); + // Validate the json + try { + const parsed = zReport.parse(json); + reports.push(parsed); + } catch (e) { + if (e instanceof z.ZodError) { + throw new Error(`Report ${file.href} is invalid: ${e.message}`); } + } + } + } - if (layer.style.maxZoom > entry.maxZoom) { - entry.maxZoom = layer.style.maxZoom; - } + const docs: Doc[] = []; + + for (const report of reports) { + const schema = schemas.find((schema) => schema.name === report.name); + if (schema == null) throw new Error(`Could not locate schema to pair with report: ${report.name}`); + + const attributes = flattenAttributes(report.all.attributes); + const zoom_levels = flattenZoomLevels(report.all.zoom_levels); + + const all: DocEntry = { + name: 'all', + filter: '["all"]', + attributes, + hasAttributes: attributes.length > 0, + geometries: report.all.geometries.join(', '), + zoom_levels, + }; + + if (report.kinds == null) { + docs.push({ + name: report.name, + description: schema.description, + isCustom: schema.custom ?? false, + all, + }); + continue; + } - return obj; - }, - {} as { [key: string]: Feature }, - ); + const kinds: DocEntry[] = []; - layers.push({ - name: schema.name, - description: 'TBC', - properties, - features: Object.values(features), + for (const [name, kind] of Object.entries(report.kinds)) { + const attributes = flattenAttributes(kind.attributes); + const zoom_levels = flattenZoomLevels(kind.zoom_levels); + + kinds.push({ + name, + filter: `["all", ["==", "kind", ${name}]]`, + attributes, + hasAttributes: attributes.length > 0, + geometries: kind.geometries.join(', '), + zoom_levels, + }); + } + + kinds.sort((a, b) => a.name.localeCompare(b.name)); + + docs.push({ + name: report.name, + description: schema.description, + isCustom: schema.custom ?? false, + all, + kinds, }); } + const layersDir = new URL('layers/', args.target); const template = readFileSync(args.template).toString(); - const output = Mustache.render(template, { layers }); - await fsa.write(new URL('result.md', args.target), output); + + for (const layer of docs) { + const markdown = Mustache.render(template, layer); + await fsa.write(new URL(`${layer.name}.md`, layersDir), markdown); + } logger.info('GenerateMarkdownDocs: End'); }, }); + +function flattenAttributes(attributes: Record): DocAttribute[] { + return Object.entries(attributes) + .map(([name, attribute]) => { + // handle types + const types = attribute.types.join(', '); + + // handle values + let values: string; + + if (attribute.num_unique_values > MaxValues) { + values = `${attribute.num_unique_values} unique values`; + } else { + values = attribute.values.sort().map(String).join(', '); + } + + if (!attribute.guaranteed) { + values = ['{empty}', values].join(', '); + } + + // return attribute + return { name, types, values }; + }) + .sort((a, b) => a.name.localeCompare(b.name)); +} + +function flattenZoomLevels(zoom_levels: number[]): { min: number; max: number } { + const min = Math.min(...zoom_levels); + const max = Math.max(...zoom_levels); + + return { min, max }; +} From 11f790640c962da8255c958c75ebf8aaabcef57a Mon Sep 17 00:00:00 2001 From: Tawera Manaena Date: Wed, 11 Jun 2025 14:11:46 +1200 Subject: [PATCH 06/15] feat(cli-vector): add new and refine existing interface and zod definitions --- .../cli-vector/src/schema-loader/parser.ts | 50 +++++++++++-- .../cli-vector/src/schema-loader/schema.ts | 70 ++++++++++++++++++- 2 files changed, 112 insertions(+), 8 deletions(-) diff --git a/packages/cli-vector/src/schema-loader/parser.ts b/packages/cli-vector/src/schema-loader/parser.ts index f10c34cfdf..080406bca8 100644 --- a/packages/cli-vector/src/schema-loader/parser.ts +++ b/packages/cli-vector/src/schema-loader/parser.ts @@ -1,24 +1,37 @@ import { z } from 'zod'; +import { + Attributes, + Layer, + Report, + ReportAttribute, + ReportEntry, + Schema, + Simplify, + SpecialTag, + Styling, + Tags, +} from './schema.js'; + export const zStyling = z.object({ minZoom: z.number(), maxZoom: z.number(), detail: z.number().optional(), -}); +}) satisfies z.ZodType; -export const zTags = z.record(z.string().or(z.boolean())); +export const zTags = z.record(z.string().or(z.boolean())) satisfies z.ZodType; -export const zAttributes = z.record(z.string()); +export const zAttributes = z.record(z.string()) satisfies z.ZodType; export const zSpecialTag = z.object({ condition: z.string(), tags: zTags, -}); +}) satisfies z.ZodType; export const zSimplify = z.object({ style: zStyling, tolerance: z.number().optional(), -}); +}) satisfies z.ZodType; export const zLayer = z.object({ id: z.string(), @@ -30,16 +43,39 @@ export const zLayer = z.object({ style: zStyling, simplify: z.array(zSimplify).optional(), tippecanoe: z.array(z.string()).optional(), -}); +}) satisfies z.ZodType; export const zSchema = z.object({ name: z.string(), + description: z.string().optional(), + custom: z.boolean().optional(), metadata: z.object({ attributes: z.array(z.string()), }), simplify: z.array(zSimplify).optional(), layers: z.array(zLayer), -}); +}) satisfies z.ZodType; export type zTypeLayer = z.infer; export type zTypeSchema = z.infer; + +const zReportAttribute = z.object({ + guaranteed: z.boolean(), + num_unique_values: z.number(), + types: z.array(z.string()), + values: z.array(z.union([z.boolean(), z.number(), z.string()])), +}) satisfies z.ZodType; + +const zEntry = z.object({ + attributes: z.record(z.string(), zReportAttribute), + geometries: z.array( + z.union([z.literal('LineString'), z.literal('Point'), z.literal('Polygon'), z.literal('Unknown')]), + ), + zoom_levels: z.array(z.number()), +}) satisfies z.ZodType; + +export const zReport = z.object({ + name: z.string(), + all: zEntry, + kinds: z.record(z.string(), zEntry).optional(), +}) satisfies z.ZodType; diff --git a/packages/cli-vector/src/schema-loader/schema.ts b/packages/cli-vector/src/schema-loader/schema.ts index 3fa744cb24..a38b3d4ea6 100644 --- a/packages/cli-vector/src/schema-loader/schema.ts +++ b/packages/cli-vector/src/schema-loader/schema.ts @@ -113,7 +113,6 @@ export interface Layer { /** * Schema metadata for vector layer - * */ export interface SchemaMetadata { /** All the attributes that is available for this layer, could be mapped from different attribute from source layer */ @@ -128,6 +127,12 @@ export interface Schema { /** Schema name */ name: string; + /** Schema description */ + description?: string; + + /** True, if the Schema describes a non-default Shortbread layer */ + custom?: boolean; + /** Schema metadata */ metadata: SchemaMetadata; @@ -137,3 +142,66 @@ export interface Schema { /** All individual layers that combined for the Schema */ layers: Layer[]; } + +/** + * Interface describing a Report object as created and exported by the vector-cli 'reports' command. + */ +export interface Report { + /** + * Name of the Shortbread layer for which the report derives. + * + * @example "addresses" + * @example "boundaries" + * @example "contours" + */ + name: string; + + /** + * Entry object containing information from all features, regardless of `kind` attribute value. + */ + all: ReportEntry; + + /** + * Entry objects deriving information from all features with the same `kind` attribute value. + * + * @example { "contours": ReportEntry, "peaks": ReportEntry } + */ + kinds?: Record; +} + +export interface ReportEntry { + /** + * @example { "feature": { "guaranteed": true, "type": "string", "values": ["people", "industrial"] } } + */ + attributes: Record; + + /** + * @example ["LineString"] + */ + geometries: ('LineString' | 'Point' | 'Polygon' | 'Unknown')[]; + + /** + * @example { "min": 12, "max": 15 } + */ + zoom_levels: number[]; +} + +export interface ReportAttribute { + /** + * `true`, if all features of the parent `ReportEntry` define this attribute. Otherwise, `false`. + */ + guaranteed: boolean; + + /** + * The number of unique values across all features of the parent `ReportEntry` that define this attribute. + */ + num_unique_values: number; + /** + * @example ["boolean", "string"] + */ + types: string[]; + /** + * @example ["people", "industrial"] + */ + values: unknown[]; +} From e0a8e1d5613759e415556367c61de97449e37649 Mon Sep 17 00:00:00 2001 From: Tawera Manaena Date: Wed, 11 Jun 2025 14:12:56 +1200 Subject: [PATCH 07/15] feat(cli-vector): refine vector tile schema mustache template --- .../src/templates/vector-tile-schema.md | 136 +++++++++++++++--- 1 file changed, 117 insertions(+), 19 deletions(-) diff --git a/packages/cli-vector/src/templates/vector-tile-schema.md b/packages/cli-vector/src/templates/vector-tile-schema.md index cedcd471ed..081ba04561 100644 --- a/packages/cli-vector/src/templates/vector-tile-schema.md +++ b/packages/cli-vector/src/templates/vector-tile-schema.md @@ -1,51 +1,149 @@ -{{#layers}} +# {{name}} -## Layer "{{name}}" +{{#description}} +{{{description}}} +{{/description}} -{{description}} +{{^description}} +_No description._ +{{/description}} -### Properties +{{#isCustom}} +!!! example "Custom" + + This is a custom Shortbread layer. + +{{/isCustom}} + +{{^isCustom}} +!!! Default + + This is a default [Shortbread](https://shortbread-tiles.org/schema/1.0/#layer-{{name}}) layer. + +{{/isCustom}} + +## all + +{{#all}} + +#### Filter + +`{{{filter}}}` + +#### Attributes + +{{#hasAttributes}} - + - {{#properties}} + {{#attributes}} - - + + - {{/properties}} + {{/attributes}}
Name TypeDescriptionValue(s)
{{name}}{{type}}{{description}}{{types}}{{{values}}}
+{{/hasAttributes}} + +{{^hasAttributes}} + +_Features under this filter have no targetable attributes._ + +{{/hasAttributes}} + +#### Properties + + + + + + + + + + + + + + + + +
GeometriesMin ZoomMax Zoom
{{geometries}}{{zoom_levels.min}}{{zoom_levels.max}}
-### Features +{{/all}} + +## kinds + +{{#kinds}} + +### {{name}} + +#### Filter + +`{{{filter}}}` + +#### Attributes + +{{#hasAttributes}} - - - + + - {{#features}} + {{#attributes}} - - - + + - {{/features}} + {{/attributes}}
Name`kind`GeometryZoomTypeValue(s)
{{name}}{{kind}}{{geometry}}{{zoom}}{{types}}{{{values}}}
+{{/hasAttributes}} + +{{^hasAttributes}} + +_Features under this filter have no targetable attributes._ + +{{/hasAttributes}} + +#### Properties + + + + + + + + + + + + + + + + +
GeometriesMin ZoomMax Zoom
{{geometries}}{{zoom_levels.min}}{{zoom_levels.max}}
+ +{{/kinds}} + +{{^kinds}} + +_This layer has no kinds._ -{{/layers}} +{{/kinds}} From ab2c063f874024c2ea0eb405b4cfe90920535c96 Mon Sep 17 00:00:00 2001 From: Tawera Manaena Date: Wed, 11 Jun 2025 14:14:13 +1200 Subject: [PATCH 08/15] feat(cli-vector): add the cli-vector reports command to the parent cli command --- packages/cli-vector/src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/cli-vector/src/index.ts b/packages/cli-vector/src/index.ts index 63e6a522bd..d5387bede5 100644 --- a/packages/cli-vector/src/index.ts +++ b/packages/cli-vector/src/index.ts @@ -4,6 +4,7 @@ import { CreateCommand } from './cli/cli.create.js'; import { DocsCommand } from './cli/cli.docs.js'; import { ExtractCommand } from './cli/cli.extract.js'; import { JoinCommand } from './cli/cli.join.js'; +import { ReportsCommand } from './cli/cli.reports.js'; export const VectorCli = subcommands({ name: 'vector', @@ -11,6 +12,7 @@ export const VectorCli = subcommands({ extract: ExtractCommand, create: CreateCommand, join: JoinCommand, + reports: ReportsCommand, docs: DocsCommand, }, }); From 6defc2f381ed70d904381b9e030b32e78216d28c Mon Sep 17 00:00:00 2001 From: Tawera Manaena Date: Wed, 11 Jun 2025 14:16:48 +1200 Subject: [PATCH 09/15] feat(cli-vector): update the JSON schema files documentation metadata --- packages/cli-vector/schema/addresses.json | 5 +- packages/cli-vector/schema/aerialways.json | 9 +- packages/cli-vector/schema/boundaries.json | 5 +- packages/cli-vector/schema/buildings.json | 6 +- packages/cli-vector/schema/contours.json | 10 +- packages/cli-vector/schema/dam_lines.json | 4 +- packages/cli-vector/schema/ferries.json | 4 +- packages/cli-vector/schema/land.json | 77 +++--- .../cli-vector/schema/parcel_boundaries.json | 4 +- packages/cli-vector/schema/pier_lines.json | 4 +- packages/cli-vector/schema/place_labels.json | 6 +- packages/cli-vector/schema/pois.json | 91 ++++++- .../cli-vector/schema/public_transport.json | 8 +- packages/cli-vector/schema/sites.json | 14 +- packages/cli-vector/schema/street_labels.json | 8 +- .../cli-vector/schema/street_polygons.json | 6 +- packages/cli-vector/schema/streets.json | 236 +----------------- packages/cli-vector/schema/water_lines.json | 24 +- .../cli-vector/schema/water_polygons.json | 18 +- 19 files changed, 199 insertions(+), 340 deletions(-) diff --git a/packages/cli-vector/schema/addresses.json b/packages/cli-vector/schema/addresses.json index d5ce9412f6..3f35d9400d 100644 --- a/packages/cli-vector/schema/addresses.json +++ b/packages/cli-vector/schema/addresses.json @@ -1,11 +1,12 @@ { "name": "addresses", + "description": "This layer contains address features represented as `Point` geometries. Each feature includes a `housenumber` property.", "metadata": { "attributes": ["housenumber"], - "schema": [ + "report": [ { "filter": ["all"], - "properties": { + "attributes": { "housenumber": { "guaranteed": true, "type": "string" } }, "geometry": "Point", diff --git a/packages/cli-vector/schema/aerialways.json b/packages/cli-vector/schema/aerialways.json index 8520367d34..df870e1b48 100644 --- a/packages/cli-vector/schema/aerialways.json +++ b/packages/cli-vector/schema/aerialways.json @@ -1,11 +1,12 @@ { "name": "aerialways", + "description": "This layer holds aerialways as `LineString` geometries.", "metadata": { "attributes": ["kind", "feature"], - "schema": [ + "report": [ { "filter": ["all", ["==", "kind", "cable_car"]], - "properties": { + "attributes": { "feature": { "guaranteed": true, "type": "string", "values": ["people", "industrial"] } }, "geometry": "LineString", @@ -13,13 +14,13 @@ }, { "filter": ["all", ["==", "kind", "ski_lift"]], - "properties": {}, + "attributes": {}, "geometry": "LineString", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "ski_tow"]], - "properties": {}, + "attributes": {}, "geometry": "LineString", "zoom_levels": { "min": 12, "max": 15 } } diff --git a/packages/cli-vector/schema/boundaries.json b/packages/cli-vector/schema/boundaries.json index 011b81336a..4a1559d40e 100644 --- a/packages/cli-vector/schema/boundaries.json +++ b/packages/cli-vector/schema/boundaries.json @@ -1,11 +1,12 @@ { "name": "boundaries", + "description": "This layer contains coastline features represented as `Polygon` geometries, indicating land-sea boundaries. Most features include a `name` property.", "metadata": { "attributes": ["name"], - "schema": [ + "report": [ { "filter": ["all"], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" } }, "geometry": "Polygon", diff --git a/packages/cli-vector/schema/buildings.json b/packages/cli-vector/schema/buildings.json index 0bf2b0996e..0c4dd79daf 100644 --- a/packages/cli-vector/schema/buildings.json +++ b/packages/cli-vector/schema/buildings.json @@ -2,10 +2,10 @@ "name": "buildings", "metadata": { "attributes": ["building", "store_item", "kind", "name", "use"], - "schema": [ + "report": [ { "filter": ["all", ["!has", "kind"]], - "properties": { + "attributes": { "building": { "guaranteed": true, "type": "string", "values": ["storage_tank"] }, "store_item": { "guaranteed": false, "type": "string", "values": ["fuel", "water"] } }, @@ -14,7 +14,7 @@ }, { "filter": ["all", ["==", "kind", "building"]], - "properties": { + "attributes": { "name": { "guaranteed": true, "type": "string" }, "use": { "guaranteed": true, diff --git a/packages/cli-vector/schema/contours.json b/packages/cli-vector/schema/contours.json index f52399cbec..135aedf1d8 100644 --- a/packages/cli-vector/schema/contours.json +++ b/packages/cli-vector/schema/contours.json @@ -1,11 +1,13 @@ { "name": "contours", + "description": "This layer contains contour line interval features represented as `LineString` geometries, and height peak features represents as 'Point' geometries.", + "custom": true, "metadata": { "attributes": ["designated", "type", "nat_form", "elevation", "kind", "name", "rank"], - "schema": [ + "report": [ { "filter": ["all", ["==", "kind", "contours"]], - "properties": { + "attributes": { "designated": { "guaranteed": false, "type": "string", @@ -17,7 +19,7 @@ }, "nat_form": { "guaranteed": false, "type": "string", "values": ["depression"] }, "type": { - "guaranteed": ["all", ["modulo_100", "elevation", 0]], + "guaranteed": false, "type": "string", "values": ["index"] } @@ -27,7 +29,7 @@ }, { "filter": ["all", ["==", "kind", "peak"]], - "properties": { + "attributes": { "elevation": { "guaranteed": false, "type": "number" }, "rank": { "guaranteed": false, "type": "number", "values": [5, 4, 3, 2, 1] } }, diff --git a/packages/cli-vector/schema/dam_lines.json b/packages/cli-vector/schema/dam_lines.json index 9b83133d74..53a445f43e 100644 --- a/packages/cli-vector/schema/dam_lines.json +++ b/packages/cli-vector/schema/dam_lines.json @@ -2,10 +2,10 @@ "name": "dam_lines", "metadata": { "attributes": ["kind", "name", "dam_status"], - "schema": [ + "report": [ { "filter": ["all", ["==", "kind", "dam"]], - "properties": { + "attributes": { "dam_status": { "guaranteed": false, "type": "string", diff --git a/packages/cli-vector/schema/ferries.json b/packages/cli-vector/schema/ferries.json index 57c927982b..5e9d265ce1 100644 --- a/packages/cli-vector/schema/ferries.json +++ b/packages/cli-vector/schema/ferries.json @@ -2,10 +2,10 @@ "name": "ferries", "metadata": { "attributes": ["kind"], - "schema": [ + "report": [ { "filter": ["all", ["==", "kind", "ferry"]], - "properties": {}, + "attributes": {}, "geometry": "LineString", "zoom_levels": { "min": 10, "max": 15 } } diff --git a/packages/cli-vector/schema/land.json b/packages/cli-vector/schema/land.json index 3bcb774ba6..03c2c26214 100644 --- a/packages/cli-vector/schema/land.json +++ b/packages/cli-vector/schema/land.json @@ -1,5 +1,6 @@ { "name": "land", + "description": "This layer contains various land-related features represented as `LineString` and `Polygon` geometries. `Polygon` features represent areas, such as forests or mangroves, while `LineString` features delineate vectors such as cliffs or embankments.", "metadata": { "attributes": [ "kind", @@ -14,10 +15,10 @@ "visibility", "status" ], - "schema": [ + "report": [ { "filter": ["all", ["==", "kind", "bare_rock"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" } }, "geometry": "Polygon", @@ -25,7 +26,7 @@ }, { "filter": ["all", ["==", "kind", "boatramp"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string", @@ -37,7 +38,7 @@ }, { "filter": ["all", ["==", "kind", "cemetery"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" } }, "geometry": "Polygon", @@ -45,31 +46,31 @@ }, { "filter": ["all", ["==", "kind", "cliff"]], - "properties": {}, + "attributes": {}, "geometry": "LineString", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "cutting"]], - "properties": {}, + "attributes": {}, "geometry": "LineString", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "dredge_tailing"]], - "properties": {}, + "attributes": {}, "geometry": "LineString", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "dry_dock"]], - "properties": {}, + "attributes": {}, "geometry": "Polygon", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "embankment"]], - "properties": { + "attributes": { "embkmt_use": { "guaranteed": false, "type": "string", @@ -82,13 +83,13 @@ }, { "filter": ["all", ["==", "kind", "fence"]], - "properties": {}, + "attributes": {}, "geometry": "LineString", "zoom_levels": { "min": 13, "max": 15 } }, { "filter": ["all", ["==", "kind", "forest"]], - "properties": { + "attributes": { "landuse": { "guaranteed": false, "type": "string", "values": ["forest", "wood"] }, "species": { "guaranteed": false, "type": "string", "values": ["non-coniferous"] }, "tree": { "guaranteed": true, "type": "string", "values": ["native", "exotic"] } @@ -98,7 +99,7 @@ }, { "filter": ["all", ["==", "kind", "golf_course"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" } }, "geometry": "Polygon", @@ -106,19 +107,19 @@ }, { "filter": ["all", ["==", "kind", "ice"]], - "properties": {}, + "attributes": {}, "geometry": "Polygon", "zoom_levels": { "min": 2, "max": 15 } }, { "filter": ["all", ["==", "kind", "ladder"]], - "properties": {}, + "attributes": {}, "geometry": "LineString", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "landfill"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" } }, "geometry": "Polygon", @@ -126,13 +127,13 @@ }, { "filter": ["all", ["==", "kind", "mangrove"]], - "properties": {}, + "attributes": {}, "geometry": "Polygon", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "mine"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" }, "status": { "guaranteed": false, @@ -155,31 +156,31 @@ }, { "filter": ["all", ["==", "kind", "moraine"]], - "properties": {}, + "attributes": {}, "geometry": "Polygon", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "moraine_wall"]], - "properties": {}, + "attributes": {}, "geometry": "Polygon", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "mud"]], - "properties": {}, + "attributes": {}, "geometry": "Polygon", "zoom_levels": { "min": 1, "max": 15 } }, { "filter": ["all", ["==", "kind", "orchard"]], - "properties": {}, + "attributes": {}, "geometry": "Polygon", "zoom_levels": { "min": 10, "max": 15 } }, { "filter": ["all", ["==", "kind", "pipeline"]], - "properties": { + "attributes": { "visibility": { "guaranteed": false, "type": "string", "values": ["underground"] } }, "geometry": "LineString", @@ -187,7 +188,7 @@ }, { "filter": ["all", ["==", "kind", "pond"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string", @@ -199,7 +200,7 @@ }, { "filter": ["all", ["==", "kind", "powerline"]], - "properties": { + "attributes": { "support_ty": { "guaranteed": false, "type": "string", "values": ["pole", "pylon"] } }, "geometry": "LineString", @@ -207,7 +208,7 @@ }, { "filter": ["all", ["==", "kind", "quarry"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" }, "status": { "guaranteed": false, "type": "string", "values": ["disused"] }, "substance": { @@ -221,7 +222,7 @@ }, { "filter": ["all", ["==", "kind", "residential"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" @@ -232,19 +233,19 @@ }, { "filter": ["all", ["==", "kind", "sand"]], - "properties": {}, + "attributes": {}, "geometry": "Polygon", "zoom_levels": { "min": 8, "max": 15 } }, { "filter": ["all", ["==", "kind", "scree"]], - "properties": {}, + "attributes": {}, "geometry": "Polygon", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "scrub"]], - "properties": { + "attributes": { "distribution": { "guaranteed": false, "type": "string", "values": ["scattered"] } }, "geometry": "Polygon", @@ -252,32 +253,32 @@ }, { "filter": ["all", ["==", "kind", "shingle"]], - "properties": {}, + "attributes": {}, "geometry": "Polygon", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "siphon"]], - "properties": {}, + "attributes": {}, "geometry": "Polygon", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "slip"]], - "properties": {}, + "attributes": {}, "geometry": "LineString", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "slipway"]], - "properties": {}, + "attributes": {}, "geometry": "LineString", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "swamp"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" } }, "geometry": "Polygon", @@ -285,25 +286,25 @@ }, { "filter": ["all", ["==", "kind", "telephone"]], - "properties": {}, + "attributes": {}, "geometry": "LineString", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "tree_row"]], - "properties": {}, + "attributes": {}, "geometry": "LineString", "zoom_levels": { "min": 8, "max": 15 } }, { "filter": ["all", ["==", "kind", "vineyard"]], - "properties": {}, + "attributes": {}, "geometry": "Polygon", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "walkwire"]], - "properties": {}, + "attributes": {}, "geometry": "LineString", "zoom_levels": { "min": 12, "max": 15 } } diff --git a/packages/cli-vector/schema/parcel_boundaries.json b/packages/cli-vector/schema/parcel_boundaries.json index b4b3fcfe1b..bd1e779a77 100644 --- a/packages/cli-vector/schema/parcel_boundaries.json +++ b/packages/cli-vector/schema/parcel_boundaries.json @@ -2,10 +2,10 @@ "name": "parcel_boundaries", "metadata": { "attributes": ["parcel_intent", "name", "id"], - "schema": [ + "report": [ { "filter": ["all"], - "properties": { + "attributes": { "parcel_intent": { "guaranteed": true, "type": "string" } }, "geometry": "Polygon", diff --git a/packages/cli-vector/schema/pier_lines.json b/packages/cli-vector/schema/pier_lines.json index 148acc5dc1..87f6669c19 100644 --- a/packages/cli-vector/schema/pier_lines.json +++ b/packages/cli-vector/schema/pier_lines.json @@ -2,10 +2,10 @@ "name": "pier_lines", "metadata": { "attributes": ["kind", "name"], - "schema": [ + "report": [ { "filter": ["all", ["==", "kind", "breakwater"]], - "properties": {}, + "attributes": {}, "geometry": "LineString", "zoom_levels": { "min": 12, "max": 15 } } diff --git a/packages/cli-vector/schema/place_labels.json b/packages/cli-vector/schema/place_labels.json index 8ca338e55f..79908d0d46 100644 --- a/packages/cli-vector/schema/place_labels.json +++ b/packages/cli-vector/schema/place_labels.json @@ -1,11 +1,11 @@ { "name": "place_labels", "metadata": { - "attributes": ["water", "name", "natural", "place"], - "schema": [ + "attributes": ["kind", "water", "name", "natural", "place"], + "report": [ { "filter": ["all"], - "properties": { + "attributes": { "name": { "guaranteed": true, "type": "string" }, "natural": { "guaranteed": true, diff --git a/packages/cli-vector/schema/pois.json b/packages/cli-vector/schema/pois.json index e322b88e87..de2e9ca4a6 100644 --- a/packages/cli-vector/schema/pois.json +++ b/packages/cli-vector/schema/pois.json @@ -1,5 +1,6 @@ { "name": "pois", + "description": "This layer contains features with `Point` geometries.", "metadata": { "attributes": [ "leisure", @@ -18,7 +19,6 @@ "barrier", "historic", "ref", - "ladder", "fortification_type", "power", "farmyard", @@ -32,6 +32,79 @@ "orientation", "substance", "visibility" + ], + "report": [ + { + "filter": ["all"], + "attributes": { + "building": { "guaranteed": false, "type": "string", "values": ["storage_tank"] }, + "store_item": { "guaranteed": false, "type": "string", "values": ["water", "fuel"] }, + "wetland": { "guaranteed": false, "type": "string", "values": ["swamp"] }, + "natural": { + "guaranteed": false, + "type": "string", + "values": ["tree", "cave_entrance", "spring", "sinkhole", "rock", "fumarole"] + }, + "power": { "guaranteed": false, "type": "string", "values": ["pole"] }, + "name": { "guaranteed": false, "type": "string" }, + "man_made": { + "guaranteed": false, + "type": "string", + "values": [ + "kiln", + "beacon", + "mast", + "water_well", + "trig_point", + "tower", + "wind_turbine", + "chimney", + "dredge", + "radar_dome", + "mineshaft", + "telescope", + "flare", + "ladder", + "geo_bore" + ] + }, + "historic": { "guaranteed": false, "type": "string", "values": ["wreck", "monument", "yes", "redoubt"] }, + "temp": { "guaranteed": false, "type": "string", "values": ["cold", "hot"] }, + "waterway": { + "guaranteed": false, + "type": "string", + "values": ["soakhole", "ford", "waterfall", "siphon", "sluice_gate"] + }, + "type": { "guaranteed": false, "type": "string", "values": ["lighthouse"] }, + "height": { "guaranteed": false, "type": "number" }, + "barrier": { "guaranteed": false, "type": "string", "values": ["gate"] }, + "farmyard": { "guaranteed": false, "type": "string", "values": ["stockyard"] }, + "landuse": { "guaranteed": false, "type": "string", "values": ["cemetery", "mine"] }, + "amenity": { "guaranteed": false, "type": "string", "values": ["grave_yard", "bivouac"] }, + "direction": { "guaranteed": false, "type": "number" }, + "elevation": { "guaranteed": false, "type": "number" }, + "materials": { "guaranteed": false, "type": "string", "values": ["rock"] }, + "status": { + "guaranteed": false, + "type": "string", + "values": ["disused", "old", "derelict", "dangerous", "historic", "closed", "remains"] + }, + "visibility": { "guaranteed": false, "type": "string", "values": ["underground", "opencast"] }, + "ref": { "guaranteed": false, "type": "string" }, + "leisure": { "guaranteed": false, "type": "string", "values": ["shooting_ground"] }, + "substance": { + "guaranteed": false, + "type": "string", + "values": ["scheelite", "gold", "quartz", "coal", "silver", "bentonite"] + }, + "fortification_type": { "guaranteed": false, "type": "string", "values": ["pa"] }, + "pipeline": { "guaranteed": false, "type": "string", "values": ["valve"] }, + "seamark": { "guaranteed": false, "type": "string", "values": ["buoy"] }, + "geological": { "guaranteed": false, "type": "string", "values": ["outcrop"] } + }, + "geometry": "Point", + "zoom_levels": { "min": 0, "max": 15 } + } ] }, "layers": [ @@ -580,7 +653,7 @@ "id": "50291", "name": "50291-nz-ladder-points-topo-150k", "source": "s3://linz-lds-cache/50291/", - "tags": { "ladder": "yes" }, + "tags": { "man_made": "ladder" }, "style": { "minZoom": 12, "maxZoom": 15 } }, { @@ -792,6 +865,20 @@ "source": "s3://linz-lds-cache/103476/", "tags": { "man_made": "trig_point" }, "style": { "minZoom": 12, "maxZoom": 15 } + }, + { + "id": "50275", + "name": "50275-nz-ford-points-topo-150k", + "source": "s3://linz-lds-cache/50275/", + "tags": { "waterway": "ford" }, + "style": { "minZoom": 12, "maxZoom": 15 } + }, + { + "id": "50080", + "name": "50080-nz-chatham-island-ford-points-topo-150k", + "source": "s3://linz-lds-cache/50080/", + "tags": { "waterway": "ford" }, + "style": { "minZoom": 12, "maxZoom": 15 } } ] } diff --git a/packages/cli-vector/schema/public_transport.json b/packages/cli-vector/schema/public_transport.json index 4531ec057f..35796954fd 100644 --- a/packages/cli-vector/schema/public_transport.json +++ b/packages/cli-vector/schema/public_transport.json @@ -2,10 +2,10 @@ "name": "public_transport", "metadata": { "attributes": ["kind", "name"], - "schema": [ + "report": [ { "filter": ["all", ["==", "kind", "aerodrome"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" } }, "geometry": "Point", @@ -13,13 +13,13 @@ }, { "filter": ["all", ["==", "kind", "helipad"]], - "properties": {}, + "attributes": {}, "geometry": "Point", "zoom_levels": { "min": 10, "max": 15 } }, { "filter": ["all", ["==", "kind", "station"]], - "properties": { + "attributes": { "name": { "guaranteed": true, "type": "string" } }, "geometry": "Point", diff --git a/packages/cli-vector/schema/sites.json b/packages/cli-vector/schema/sites.json index 32ad338dee..c1f6ac5cf9 100644 --- a/packages/cli-vector/schema/sites.json +++ b/packages/cli-vector/schema/sites.json @@ -2,10 +2,10 @@ "name": "sites", "metadata": { "attributes": ["kind", "species", "name", "type", "track_type", "track_use"], - "schema": [ + "report": [ { "filter": ["all", ["==", "kind", "fish_farm"]], - "properties": { + "attributes": { "species": { "guaranteed": false, "type": "string", "values": ["salmon"] } }, "geometry": "Polygon", @@ -13,19 +13,19 @@ }, { "filter": ["all", ["==", "kind", "gravel_pit"]], - "properties": {}, + "attributes": {}, "geometry": "Polygon", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "pumice_pit"]], - "properties": {}, + "attributes": {}, "geometry": "Polygon", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "raceway"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" }, "track_type": { "guaranteed": false, "type": "string", "values": ["training"] }, "track_use": { @@ -39,13 +39,13 @@ }, { "filter": ["all", ["==", "kind", "showground"]], - "properties": {}, + "attributes": {}, "geometry": "Polygon", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "sports_field"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" } }, "geometry": "Polygon", diff --git a/packages/cli-vector/schema/street_labels.json b/packages/cli-vector/schema/street_labels.json index 73a658dbc8..063c4e2b1d 100644 --- a/packages/cli-vector/schema/street_labels.json +++ b/packages/cli-vector/schema/street_labels.json @@ -2,10 +2,10 @@ "name": "street_labels", "metadata": { "attributes": ["kind", "ref", "name"], - "schema": [ + "report": [ { "filter": ["all", ["==", "kind", "motorway"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" }, "ref": { "guaranteed": true, "type": "string" } }, @@ -14,7 +14,7 @@ }, { "filter": ["all", ["==", "kind", "primary"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" } }, "geometry": "LineString", @@ -22,7 +22,7 @@ }, { "filter": ["all", ["==", "kind", "secondary"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" } }, "geometry": "LineString", diff --git a/packages/cli-vector/schema/street_polygons.json b/packages/cli-vector/schema/street_polygons.json index 451ab80f85..17e0039b84 100644 --- a/packages/cli-vector/schema/street_polygons.json +++ b/packages/cli-vector/schema/street_polygons.json @@ -2,10 +2,10 @@ "name": "street_polygons", "metadata": { "attributes": ["kind", "surface", "name"], - "schema": [ + "report": [ { "filter": ["all", ["==", "kind", "aerodrome"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" } }, "geometry": "Polygon", @@ -13,7 +13,7 @@ }, { "filter": ["all", ["==", "kind", "runway"]], - "properties": { + "attributes": { "surface": { "guaranteed": false, "type": "string", "values": ["sealed"] } }, "geometry": "Polygon", diff --git a/packages/cli-vector/schema/streets.json b/packages/cli-vector/schema/streets.json index c0b5564131..4be0cbf7a5 100644 --- a/packages/cli-vector/schema/streets.json +++ b/packages/cli-vector/schema/streets.json @@ -20,150 +20,7 @@ "ref", "subclass" ], - "schema": [ - { - "filter": ["all", ["==", "kind", "aerodrome"]], - "properties": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 5, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "motorway"]], - "properties": { - "hway_num": { "guaranteed": true, "type": "string" }, - "lane_count": { - "guaranteed": true, - "type": "number", - "values": [1, 2, 3, 4, 5, 6, 7] - }, - "name": { "guaranteed": false, "type": "string" }, - "ref": { "guaranteed": true, "type": "string" }, - "surface": { "guaranteed": true, "type": "string", "values": ["sealed", "metalled"] } - }, - "geometry": "LineString", - "zoom_levels": { "min": 8, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "primary"]], - "properties": { - "lane_count": { "guaranteed": true, "type": "number", "values": [4, 5, 6] }, - "name": { "guaranteed": false, "type": "string" }, - "status": { "guaranteed": false, "type": "string", "values": ["under construction"] }, - "surface": { "guaranteed": true, "type": "string", "values": ["sealed", "unmetalled"] } - }, - "geometry": "LineString", - "zoom_levels": { "min": 8, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "raceway"]], - - "properties": { - "name": { "guaranteed": false, "type": "string" }, - "track_type": { "guaranteed": false, "type": "string", "values": ["training"] }, - "track_use": { - "guaranteed": false, - "type": "string", - "values": ["horse", "vehicle", "cycle", "dog"] - } - }, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "rail"]], - - "properties": { - "name": { "guaranteed": false, "type": "string" }, - "rway_use": { "guaranteed": false, "type": "string", "values": ["siding"] }, - "status": { "guaranteed": false, "type": "string", "values": ["disused"] }, - "track_type": { - "guaranteed": true, - "type": "string", - "values": ["single", "multiple"] - } - }, - "geometry": "LineString", - "zoom_levels": { "min": 0, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "runway"]], - "properties": { - "status": { "guaranteed": false, "type": "string", "values": ["disused"] }, - "surface": { "guaranteed": false, "type": "string", "values": ["sealed"] } - }, - "geometry": "Polygon", - "zoom_levels": { "max": 15, "min": 10 } - }, - { - "filter": ["all", ["==", "kind", "secondary"]], - "geometry": "LineString, Point", - "properties": { - "bridge": { "guaranteed": false, "type": "boolean", "values": [true] }, - "ford": { "guaranteed": false, "type": "boolean", "values": [true] }, - "lane_count": { "guaranteed": false, "type": "number", "values": [1, 2, 3] }, - "name": { "guaranteed": false, "type": "string" }, - "status": { - "guaranteed": false, - "type": "string", - "values": ["under construction", "closed", "derelict", "disused", "historic"] - }, - "surface": { - "guaranteed": false, - "type": "string", - "values": ["metalled", "unmetalled", "sealed"] - }, - "tunnel": { "guaranteed": false, "type": "boolean", "values": [true] }, - "use_1": { - "guaranteed": false, - "type": "string", - "values": ["vehicle", "foot traffic", "farm", "train", "cablecar"] - }, - "use_2": { "guaranteed": false, "type": "string", "values": ["train"] } - }, - "zoom_levels": { "min": 8, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "track"]], - "properties": { - "name": { "guaranteed": false, "type": "string" }, - "status": { - "guaranteed": false, - "type": "string", - "values": ["closed", "unmaintained"] - }, - "subclass": { - "guaranteed": false, - "type": "string", - "values": [ - "foot", - "foot_route", - "foot_closed", - "vehicle", - "cycle only", - "vehicle_closed", - "foot_connector", - "foot_routeroute", - "foot_route_closed", - "vehicle_unmaintained" - ] - }, - "track_type": { - "guaranteed": false, - "type": "string", - "values": ["route", "connector", "routeroute"] - }, - "track_use": { - "guaranteed": false, - "type": "string", - "values": ["foot", "vehicle", "cycle only"] - } - }, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - } - ] + "report": [] }, "layers": [ { @@ -320,83 +177,6 @@ { "style": { "minZoom": 11, "maxZoom": 15 } } ] }, - { - "id": "50237", - "name": "50237-nz-airport-polygons-topo-150k", - "source": "s3://linz-lds-cache/50237/", - "tags": { "kind": "aerodrome" }, - "style": { "minZoom": 10, "maxZoom": 15 } - }, - { - "id": "50063", - "name": "50063-nz-chatham-island-airport-polygons-topo-150k", - "source": "s3://linz-lds-cache/50063/", - "tags": { "kind": "aerodrome" }, - "style": { "minZoom": 10, "maxZoom": 15 } - }, - { - "id": "52231", - "name": "52231-cook-islands-airport-polygons-topo-125k-zone4", - "source": "s3://linz-lds-cache/52231/", - "tags": { "kind": "aerodrome" }, - "style": { "minZoom": 0, "maxZoom": 15 } - }, - { - "id": "52168", - "name": "52168-niue-airport-polygons-topo-150k", - "source": "s3://linz-lds-cache/52168/", - "tags": { "kind": "aerodrome" }, - "style": { "minZoom": 0, "maxZoom": 15 } - }, - { - "id": "50333", - "name": "50333-nz-runway-polygons-topo-150k", - "source": "s3://linz-lds-cache/50333/", - "tags": { "kind": "runway" }, - "style": { "minZoom": 10, "maxZoom": 15 } - }, - { - "id": "50914", - "name": "50914-nz-kermadec-is-runway-polygons-topo-125k", - "source": "s3://linz-lds-cache/50914/", - "tags": { "kind": "runway" }, - "style": { "minZoom": 12, "maxZoom": 15 } - }, - { - "id": "52302", - "name": "52302-cook-islands-runway-polygons-topo-125k-zone3", - "source": "s3://linz-lds-cache/52302/", - "tags": { "kind": "runway" }, - "style": { "minZoom": 13, "maxZoom": 15 } - }, - { - "id": "52268", - "name": "52268-cook-islands-runway-polygons-topo-125k-zone4", - "source": "s3://linz-lds-cache/52268/", - "tags": { "kind": "runway" }, - "style": { "minZoom": 13, "maxZoom": 15 } - }, - { - "id": "52211", - "name": "52211-cook-islands-runway-polygons-topo-150k-zone4", - "source": "s3://linz-lds-cache/52211/", - "tags": { "kind": "runway" }, - "style": { "minZoom": 13, "maxZoom": 15 } - }, - { - "id": "52190", - "name": "52190-niue-runway-polygons-topo-150k", - "source": "s3://linz-lds-cache/52190/", - "tags": { "kind": "runway" }, - "style": { "minZoom": 13, "maxZoom": 15 } - }, - { - "id": "50103", - "name": "50103-nz-chatham-island-runway-polygons-topo-150k", - "source": "s3://linz-lds-cache/50103/", - "tags": { "kind": "runway" }, - "style": { "minZoom": 10, "maxZoom": 15 } - }, { "id": "50244", "name": "50244-nz-bridge-centrelines-topo-150k", @@ -425,20 +205,6 @@ "tags": { "kind": "secondary", "bridge": "true" }, "style": { "minZoom": 10, "maxZoom": 15 } }, - { - "id": "50275", - "name": "50275-nz-ford-points-topo-150k", - "source": "s3://linz-lds-cache/50275/", - "tags": { "kind": "secondary", "ford": "true" }, - "style": { "minZoom": 12, "maxZoom": 15 } - }, - { - "id": "50080", - "name": "50080-nz-chatham-island-ford-points-topo-150k", - "source": "s3://linz-lds-cache/50080/", - "tags": { "kind": "secondary", "ford": "true" }, - "style": { "minZoom": 12, "maxZoom": 15 } - }, { "id": "50366", "name": "50366-nz-tunnel-centrelines-topo-150k", diff --git a/packages/cli-vector/schema/water_lines.json b/packages/cli-vector/schema/water_lines.json index 0e8faec495..342f2d07aa 100644 --- a/packages/cli-vector/schema/water_lines.json +++ b/packages/cli-vector/schema/water_lines.json @@ -2,36 +2,36 @@ "name": "water_lines", "metadata": { "attributes": ["kind", "name", "feature", "species", "height"], - "schema": [ + "report": [ { "filter": ["all", ["==", "kind", "boom"]], - "properties": {}, + "attributes": {}, "geometry": "LineString", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "drain"]], - "properties": {}, + "attributes": {}, "geometry": "LineString", "zoom_levels": { "min": 10, "max": 15 } }, { "filter": ["all", ["==", "kind", "flume"]], - "properties": {}, + "attributes": {}, "geometry": "LineString", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "marine_farm"]], - "properties": { - "geometry": "LineString", + "attributes": { "species": { "guaranteed": false, "type": "string", "values": ["salmon"] } }, + "geometry": "LineString", "zoom_levels": { "min": 12, "max": 15 } }, { "filter": ["all", ["==", "kind", "river"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" } }, "geometry": "LineString", @@ -39,7 +39,7 @@ }, { "filter": ["all", ["==", "kind", "stream"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" } }, "geometry": "LineString", @@ -47,7 +47,7 @@ }, { "filter": ["all", ["==", "kind", "water_race"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" } }, "geometry": "LineString", @@ -55,7 +55,7 @@ }, { "filter": ["all", ["==", "kind", "waterfall"]], - "properties": { + "attributes": { "feature": { "guaranteed": false, "type": "string", "values": ["edge"] }, "height": { "guaranteed": true, "type": "number" }, "name": { "guaranteed": false, "type": "string" } @@ -65,7 +65,7 @@ }, { "filter": ["all", ["==", "kind", "wharf"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" } }, "geometry": "LineString", @@ -73,7 +73,7 @@ }, { "filter": ["all", ["==", "kind", "wharf_edge"]], - "properties": {}, + "attributes": {}, "geometry": "LineString", "zoom_levels": { "min": 10, "max": 15 } } diff --git a/packages/cli-vector/schema/water_polygons.json b/packages/cli-vector/schema/water_polygons.json index 3e4ba806fc..db62bc9bb8 100644 --- a/packages/cli-vector/schema/water_polygons.json +++ b/packages/cli-vector/schema/water_polygons.json @@ -2,10 +2,10 @@ "name": "water_polygons", "metadata": { "attributes": ["water", "kind", "name", "lid_type", "species", "height", "direction"], - "schema": [ + "report": [ { "filter": ["all", ["==", "kind", "marine_farm"]], - "properties": { + "attributes": { "species": { "guaranteed": false, "type": "string", "values": ["mussels"] } }, "geometry": "Polygon", @@ -13,7 +13,7 @@ }, { "filter": ["all", ["==", "kind", "reef"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" } }, "geometry": "Polygon", @@ -21,7 +21,7 @@ }, { "filter": ["all", ["==", "kind", "reservoir"]], - "properties": { + "attributes": { "lid_type": { "guaranteed": false, "type": "string", "values": ["covered"] } }, "geometry": "Polygon", @@ -29,7 +29,7 @@ }, { "filter": ["all", ["==", "kind", "river"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" } }, "geometry": "Polygon", @@ -37,7 +37,7 @@ }, { "filter": ["all", ["==", "kind", "shoal"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" } }, "geometry": "Polygon", @@ -45,7 +45,7 @@ }, { "filter": ["all", ["==", "kind", "stream"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" } }, "geometry": "Polygon", @@ -53,7 +53,7 @@ }, { "filter": ["all", ["==", "kind", "water"]], - "properties": { + "attributes": { "name": { "guaranteed": false, "type": "string" }, "water": { "guaranteed": true, "type": "string", "values": ["lagoon", "lake"] } }, @@ -62,7 +62,7 @@ }, { "filter": ["all", ["==", "kind", "waterfall"]], - "properties": { + "attributes": { "height": { "guaranteed": true, "type": "number", "values": [56] }, "name": { "guaranteed": true, "type": "string", "values": ["Alice Falls"] } }, From 7ba67300e7d6bf6759dcdacf37a4136272564bb5 Mon Sep 17 00:00:00 2001 From: Tawera Manaena Date: Fri, 13 Jun 2025 07:42:09 +1200 Subject: [PATCH 10/15] fix(cli-vector): fix string interpolation mistyping --- packages/cli-vector/src/cli/cli.docs.ts | 2 +- packages/cli-vector/src/cli/cli.reports.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/cli-vector/src/cli/cli.docs.ts b/packages/cli-vector/src/cli/cli.docs.ts index 1dd599edce..09ead4232f 100644 --- a/packages/cli-vector/src/cli/cli.docs.ts +++ b/packages/cli-vector/src/cli/cli.docs.ts @@ -148,7 +148,7 @@ export const DocsCommand = command({ kinds.push({ name, - filter: `["all", ["==", "kind", ${name}]]`, + filter: `["all", ["==", "kind", "${name}"]]`, attributes, hasAttributes: attributes.length > 0, geometries: kind.geometries.join(', '), diff --git a/packages/cli-vector/src/cli/cli.reports.ts b/packages/cli-vector/src/cli/cli.reports.ts index 2521dca97c..1de6eb53a4 100644 --- a/packages/cli-vector/src/cli/cli.reports.ts +++ b/packages/cli-vector/src/cli/cli.reports.ts @@ -19,8 +19,7 @@ export const ReportsArgs = { mbtiles: option({ type: Url, long: 'mbtiles', - description: - 'Path to the mbtiles or config containing path to mbtiles from which to generate reports. (based on file extension)', + description: 'Path to the mbtiles from which to generate reports.', }), target: option({ type: UrlFolder, From 9716ff1749aeea224a0d5051534ee7ce35684720 Mon Sep 17 00:00:00 2001 From: Tawera Manaena Date: Fri, 13 Jun 2025 09:22:18 +1200 Subject: [PATCH 11/15] refactor(cli-vector): add comments and refine report terminology --- packages/cli-vector/src/cli/cli.docs.ts | 10 +-- packages/cli-vector/src/cli/cli.reports.ts | 86 ++++++++++++------- .../cli-vector/src/schema-loader/parser.ts | 24 +++--- .../cli-vector/src/schema-loader/schema.ts | 12 +-- 4 files changed, 79 insertions(+), 53 deletions(-) diff --git a/packages/cli-vector/src/cli/cli.docs.ts b/packages/cli-vector/src/cli/cli.docs.ts index 09ead4232f..20a0436085 100644 --- a/packages/cli-vector/src/cli/cli.docs.ts +++ b/packages/cli-vector/src/cli/cli.docs.ts @@ -6,8 +6,8 @@ import { existsSync, mkdirSync, readFileSync } from 'fs'; import Mustache from 'mustache'; import { z } from 'zod'; -import { zReport, zSchema } from '../schema-loader/parser.js'; -import { Report, ReportAttribute, Schema } from '../schema-loader/schema.js'; +import { zLayerReport, zSchema } from '../schema-loader/parser.js'; +import { AttributeReport, LayerReport, Schema } from '../schema-loader/schema.js'; import { MaxValues } from './cli.reports.js'; interface Doc { @@ -94,7 +94,7 @@ export const DocsCommand = command({ } // parse report files - const reports: Report[] = []; + const reports: LayerReport[] = []; const reportFiles = await fsa.toArray(fsa.list(args.reports)); for (const file of reportFiles) { @@ -102,7 +102,7 @@ export const DocsCommand = command({ const json = await fsa.readJson(file); // Validate the json try { - const parsed = zReport.parse(json); + const parsed = zLayerReport.parse(json); reports.push(parsed); } catch (e) { if (e instanceof z.ZodError) { @@ -179,7 +179,7 @@ export const DocsCommand = command({ }, }); -function flattenAttributes(attributes: Record): DocAttribute[] { +function flattenAttributes(attributes: Record): DocAttribute[] { return Object.entries(attributes) .map(([name, attribute]) => { // handle types diff --git a/packages/cli-vector/src/cli/cli.reports.ts b/packages/cli-vector/src/cli/cli.reports.ts index 1de6eb53a4..6865e6a217 100644 --- a/packages/cli-vector/src/cli/cli.reports.ts +++ b/packages/cli-vector/src/cli/cli.reports.ts @@ -9,7 +9,7 @@ import { existsSync, mkdirSync, writeFileSync } from 'fs'; import Protobuf from 'pbf'; import { gunzipSync } from 'zlib'; -import { Report } from '../schema-loader/schema.js'; +import { AttributeReport, FeaturesReport, LayerReport } from '../schema-loader/schema.js'; export const MaxValues = 24; const MaxZoom = 15; @@ -26,6 +26,14 @@ export const ReportsArgs = { long: 'target', description: 'Target directory into which to save the generated reports.', }), + /** + * The `mode` argument can be useful, depending on what you want to check. + * + * For example, if you're generating reports to check an mbtiles file's contents, + * you can control how many values for each attribute to include in the generated + * reports. If you don't intend to check the values themselves, you can skip the + * 'value capturing' process entirely to speed up the command's execution time. + */ mode: option({ type: oneOf(['none', 'limited', 'full']), defaultValue: () => 'limited', @@ -53,13 +61,16 @@ export const ReportsCommand = command({ const targetExists = existsSync(args.target); if (!targetExists) mkdirSync(args.target, { recursive: true }); - const layerReports: Record = {}; - const db = new DatabaseSync(args.mbtiles); + const layerReports: Record = {}; + + /** + * for each zoom level + */ for (let zoomLevel = 0; zoomLevel <= MaxZoom; zoomLevel++) { logger.info({ zoomLevel }, 'Start'); - const rows = db + const tiles = db .prepare( 'SELECT tile_column AS x, tile_row AS y, zoom_level AS z, tile_data AS data ' + 'FROM tiles ' + @@ -67,31 +78,40 @@ export const ReportsCommand = command({ ) .all(zoomLevel) as { x: number; y: number; z: number; data: Buffer }[]; - for (const row of rows) { - logger.info({ x: row.x, y: row.y, z: row.z }, 'Start'); + /** + * for each of the zoom level's tiles + */ + for (const { x, y, z, data } of tiles) { + logger.info({ x, y, z }, 'Start'); - const buffer = gunzipSync(row.data); + const buffer = gunzipSync(data); const tile = new VectorTile(new Protobuf(buffer)); - // Prepare layer information + /** + * for each of the tile's layers + */ for (const [name, layer] of Object.entries(tile.layers)) { if (layerReports[name] == null) { + // init a report for the current layer layerReports[name] = { name, all: { attributes: {}, geometries: [], zoom_levels: [] }, - }; + } as LayerReport; } const layerReport = layerReports[name]; - // for each the layer's features + /** + * for each of the layer's features + */ for (let i = 0; i < layer.length; i++) { const feature = layer.feature(i); const properties = feature.properties; const geometry = VectorTileFeature.types[feature.type]; const kind = properties['kind']; - const reports = [layerReport.all]; + // the list of reports for which to capture the current feature's details + const featureReports: FeaturesReport[] = [layerReport.all]; if (typeof kind === 'string') { if (layerReport.kinds == null) { @@ -99,38 +119,42 @@ export const ReportsCommand = command({ } if (layerReport.kinds[kind] == null) { - layerReport.kinds[kind] = { attributes: {}, geometries: [], zoom_levels: [] }; + // init a report for the current kind + layerReport.kinds[kind] = { attributes: {}, geometries: [], zoom_levels: [] } as FeaturesReport; } - reports.push(layerReport.kinds[kind]); + // we also want to capture the feature's details against the corresponding 'kind' report + featureReports.push(layerReport.kinds[kind]); } - for (const report of reports) { - // append attribute + for (const featureReport of featureReports) { + /** + * for each of the feature's attributes (a.k.a. properties) + */ for (const [name, value] of Object.entries(properties)) { - if (report.attributes[name] == null) { - report.attributes[name] = { + if (featureReport.attributes[name] == null) { + // init a report for the current attribute + featureReport.attributes[name] = { guaranteed: true, num_unique_values: 0, values: [], types: [], - }; + } as AttributeReport; } - const attributeReport = report.attributes[name]; + const attributeReport = featureReport.attributes[name]; - // append type + // capture the feature's type const type = typeof value; if (!attributeReport.types.includes(type)) { attributeReport.types.push(type); } - // handle value + // capture the feature's value if (!attributeReport.values.includes(value)) { attributeReport.num_unique_values++; - // append value based on the mode if (args.mode === 'limited') { if (attributeReport.num_unique_values < MaxValues) { attributeReport.values.push(value); @@ -140,19 +164,20 @@ export const ReportsCommand = command({ } } - // append geometry - if (!report.geometries.includes(geometry)) { - report.geometries.push(geometry); + // capture the feature's geometry + if (!featureReport.geometries.includes(geometry)) { + featureReport.geometries.push(geometry); } - // append zoom level - if (!report.zoom_levels.includes(row.z)) { - report.zoom_levels.push(row.z); + // capture the feature's zoom level + if (!featureReport.zoom_levels.includes(z)) { + featureReport.zoom_levels.push(z); } } - // check the current feature's properties against the already captured attributes - for (const [name, attribute] of Object.entries(report.attributes)) { + // check the current feature's properties against the attributes already captured in the current report. + // an attribute is only 'guaranteed' if all features describe it + for (const [name, attribute] of Object.entries(featureReport.attributes)) { if (attribute.guaranteed === true) { if (properties[name] == null) { attribute.guaranteed = false; @@ -169,6 +194,7 @@ export const ReportsCommand = command({ db.close(); + // write each report to the target directory for (const [name, report] of Object.entries(layerReports)) { writeFileSync(new URL(`${name}.json`, args.target), JSON.stringify(report, null, 2)); } diff --git a/packages/cli-vector/src/schema-loader/parser.ts b/packages/cli-vector/src/schema-loader/parser.ts index 080406bca8..caa8737560 100644 --- a/packages/cli-vector/src/schema-loader/parser.ts +++ b/packages/cli-vector/src/schema-loader/parser.ts @@ -1,11 +1,11 @@ import { z } from 'zod'; import { + AttributeReport, Attributes, + FeaturesReport, Layer, - Report, - ReportAttribute, - ReportEntry, + LayerReport, Schema, Simplify, SpecialTag, @@ -59,23 +59,23 @@ export const zSchema = z.object({ export type zTypeLayer = z.infer; export type zTypeSchema = z.infer; -const zReportAttribute = z.object({ +const zAttributeReport = z.object({ guaranteed: z.boolean(), num_unique_values: z.number(), types: z.array(z.string()), values: z.array(z.union([z.boolean(), z.number(), z.string()])), -}) satisfies z.ZodType; +}) satisfies z.ZodType; -const zEntry = z.object({ - attributes: z.record(z.string(), zReportAttribute), +const zFeaturesReport = z.object({ + attributes: z.record(z.string(), zAttributeReport), geometries: z.array( z.union([z.literal('LineString'), z.literal('Point'), z.literal('Polygon'), z.literal('Unknown')]), ), zoom_levels: z.array(z.number()), -}) satisfies z.ZodType; +}) satisfies z.ZodType; -export const zReport = z.object({ +export const zLayerReport = z.object({ name: z.string(), - all: zEntry, - kinds: z.record(z.string(), zEntry).optional(), -}) satisfies z.ZodType; + all: zFeaturesReport, + kinds: z.record(z.string(), zFeaturesReport).optional(), +}) satisfies z.ZodType; diff --git a/packages/cli-vector/src/schema-loader/schema.ts b/packages/cli-vector/src/schema-loader/schema.ts index a38b3d4ea6..125fe293e1 100644 --- a/packages/cli-vector/src/schema-loader/schema.ts +++ b/packages/cli-vector/src/schema-loader/schema.ts @@ -146,7 +146,7 @@ export interface Schema { /** * Interface describing a Report object as created and exported by the vector-cli 'reports' command. */ -export interface Report { +export interface LayerReport { /** * Name of the Shortbread layer for which the report derives. * @@ -159,21 +159,21 @@ export interface Report { /** * Entry object containing information from all features, regardless of `kind` attribute value. */ - all: ReportEntry; + all: FeaturesReport; /** * Entry objects deriving information from all features with the same `kind` attribute value. * * @example { "contours": ReportEntry, "peaks": ReportEntry } */ - kinds?: Record; + kinds?: Record; } -export interface ReportEntry { +export interface FeaturesReport { /** * @example { "feature": { "guaranteed": true, "type": "string", "values": ["people", "industrial"] } } */ - attributes: Record; + attributes: Record; /** * @example ["LineString"] @@ -186,7 +186,7 @@ export interface ReportEntry { zoom_levels: number[]; } -export interface ReportAttribute { +export interface AttributeReport { /** * `true`, if all features of the parent `ReportEntry` define this attribute. Otherwise, `false`. */ From b2b5ab7260ee0ebb22d6d06b767725d4e3dfb45c Mon Sep 17 00:00:00 2001 From: Tawera Manaena Date: Fri, 13 Jun 2025 10:33:35 +1200 Subject: [PATCH 12/15] refactor(cli-vector): move the docs and reports types into standalone files --- packages/cli-vector/src/cli/cli.docs.ts | 40 ++----- packages/cli-vector/src/cli/cli.reports.ts | 2 +- .../cli-vector/src/schema-loader/parser.ts | 34 +----- .../cli-vector/src/schema-loader/schema.ts | 63 ---------- packages/cli-vector/src/types/doc.ts | 113 ++++++++++++++++++ packages/cli-vector/src/types/report.ts | 85 +++++++++++++ 6 files changed, 208 insertions(+), 129 deletions(-) create mode 100644 packages/cli-vector/src/types/doc.ts create mode 100644 packages/cli-vector/src/types/report.ts diff --git a/packages/cli-vector/src/cli/cli.docs.ts b/packages/cli-vector/src/cli/cli.docs.ts index 20a0436085..ea22d7819f 100644 --- a/packages/cli-vector/src/cli/cli.docs.ts +++ b/packages/cli-vector/src/cli/cli.docs.ts @@ -6,36 +6,12 @@ import { existsSync, mkdirSync, readFileSync } from 'fs'; import Mustache from 'mustache'; import { z } from 'zod'; -import { zLayerReport, zSchema } from '../schema-loader/parser.js'; -import { AttributeReport, LayerReport, Schema } from '../schema-loader/schema.js'; +import { zSchema } from '../schema-loader/parser.js'; +import { Schema } from '../schema-loader/schema.js'; +import { AttributeDoc, FeaturesDoc, LayerDoc } from '../types/doc.js'; +import { AttributeReport, LayerReport, zLayerReport } from '../types/report.js'; import { MaxValues } from './cli.reports.js'; -interface Doc { - name: string; - description?: string; - isCustom: boolean; - all: DocEntry; - kinds?: DocEntry[]; -} - -interface DocEntry { - name: string; - filter: string; - attributes: DocAttribute[]; - hasAttributes: boolean; - geometries: string; - zoom_levels: { - min: number; - max: number; - }; -} - -interface DocAttribute { - name: string; - types: string; - values: string; -} - export const DocsArgs = { ...logArguments, schemas: option({ @@ -112,7 +88,7 @@ export const DocsCommand = command({ } } - const docs: Doc[] = []; + const docs: LayerDoc[] = []; for (const report of reports) { const schema = schemas.find((schema) => schema.name === report.name); @@ -121,7 +97,7 @@ export const DocsCommand = command({ const attributes = flattenAttributes(report.all.attributes); const zoom_levels = flattenZoomLevels(report.all.zoom_levels); - const all: DocEntry = { + const all: FeaturesDoc = { name: 'all', filter: '["all"]', attributes, @@ -140,7 +116,7 @@ export const DocsCommand = command({ continue; } - const kinds: DocEntry[] = []; + const kinds: FeaturesDoc[] = []; for (const [name, kind] of Object.entries(report.kinds)) { const attributes = flattenAttributes(kind.attributes); @@ -179,7 +155,7 @@ export const DocsCommand = command({ }, }); -function flattenAttributes(attributes: Record): DocAttribute[] { +function flattenAttributes(attributes: Record): AttributeDoc[] { return Object.entries(attributes) .map(([name, attribute]) => { // handle types diff --git a/packages/cli-vector/src/cli/cli.reports.ts b/packages/cli-vector/src/cli/cli.reports.ts index 6865e6a217..d43efa4b7f 100644 --- a/packages/cli-vector/src/cli/cli.reports.ts +++ b/packages/cli-vector/src/cli/cli.reports.ts @@ -9,7 +9,7 @@ import { existsSync, mkdirSync, writeFileSync } from 'fs'; import Protobuf from 'pbf'; import { gunzipSync } from 'zlib'; -import { AttributeReport, FeaturesReport, LayerReport } from '../schema-loader/schema.js'; +import { AttributeReport, FeaturesReport, LayerReport } from '../types/report.js'; export const MaxValues = 24; const MaxZoom = 15; diff --git a/packages/cli-vector/src/schema-loader/parser.ts b/packages/cli-vector/src/schema-loader/parser.ts index caa8737560..c87fae7806 100644 --- a/packages/cli-vector/src/schema-loader/parser.ts +++ b/packages/cli-vector/src/schema-loader/parser.ts @@ -1,17 +1,6 @@ import { z } from 'zod'; -import { - AttributeReport, - Attributes, - FeaturesReport, - Layer, - LayerReport, - Schema, - Simplify, - SpecialTag, - Styling, - Tags, -} from './schema.js'; +import { Attributes, Layer, Schema, Simplify, SpecialTag, Styling, Tags } from './schema.js'; export const zStyling = z.object({ minZoom: z.number(), @@ -58,24 +47,3 @@ export const zSchema = z.object({ export type zTypeLayer = z.infer; export type zTypeSchema = z.infer; - -const zAttributeReport = z.object({ - guaranteed: z.boolean(), - num_unique_values: z.number(), - types: z.array(z.string()), - values: z.array(z.union([z.boolean(), z.number(), z.string()])), -}) satisfies z.ZodType; - -const zFeaturesReport = z.object({ - attributes: z.record(z.string(), zAttributeReport), - geometries: z.array( - z.union([z.literal('LineString'), z.literal('Point'), z.literal('Polygon'), z.literal('Unknown')]), - ), - zoom_levels: z.array(z.number()), -}) satisfies z.ZodType; - -export const zLayerReport = z.object({ - name: z.string(), - all: zFeaturesReport, - kinds: z.record(z.string(), zFeaturesReport).optional(), -}) satisfies z.ZodType; diff --git a/packages/cli-vector/src/schema-loader/schema.ts b/packages/cli-vector/src/schema-loader/schema.ts index 125fe293e1..c102a88419 100644 --- a/packages/cli-vector/src/schema-loader/schema.ts +++ b/packages/cli-vector/src/schema-loader/schema.ts @@ -142,66 +142,3 @@ export interface Schema { /** All individual layers that combined for the Schema */ layers: Layer[]; } - -/** - * Interface describing a Report object as created and exported by the vector-cli 'reports' command. - */ -export interface LayerReport { - /** - * Name of the Shortbread layer for which the report derives. - * - * @example "addresses" - * @example "boundaries" - * @example "contours" - */ - name: string; - - /** - * Entry object containing information from all features, regardless of `kind` attribute value. - */ - all: FeaturesReport; - - /** - * Entry objects deriving information from all features with the same `kind` attribute value. - * - * @example { "contours": ReportEntry, "peaks": ReportEntry } - */ - kinds?: Record; -} - -export interface FeaturesReport { - /** - * @example { "feature": { "guaranteed": true, "type": "string", "values": ["people", "industrial"] } } - */ - attributes: Record; - - /** - * @example ["LineString"] - */ - geometries: ('LineString' | 'Point' | 'Polygon' | 'Unknown')[]; - - /** - * @example { "min": 12, "max": 15 } - */ - zoom_levels: number[]; -} - -export interface AttributeReport { - /** - * `true`, if all features of the parent `ReportEntry` define this attribute. Otherwise, `false`. - */ - guaranteed: boolean; - - /** - * The number of unique values across all features of the parent `ReportEntry` that define this attribute. - */ - num_unique_values: number; - /** - * @example ["boolean", "string"] - */ - types: string[]; - /** - * @example ["people", "industrial"] - */ - values: unknown[]; -} diff --git a/packages/cli-vector/src/types/doc.ts b/packages/cli-vector/src/types/doc.ts new file mode 100644 index 0000000000..dc8c3473a1 --- /dev/null +++ b/packages/cli-vector/src/types/doc.ts @@ -0,0 +1,113 @@ +/** + * Interface describing a LayerDoc object as created by the vector-cli 'docs' command. Interpolated by Mustache to generate a Markdown a document. + */ +export interface LayerDoc { + /** + * The Shortbread layer's name. + * + * @example "addresses" + * @example "boundaries" + * @example "contours" + */ + name: string; + + /** + * The Shortbread layer's description. + * + * @example "addresses" + * @example "boundaries" + * @example "contours" + */ + description?: string; + + /** + * A flag for whether the layer is natively supported by Shortbread (used exclusively by Mustache). + * + * @example "addresses" + * @example "boundaries" + * @example "contours" + */ + isCustom: boolean; + + /** + * FeaturesDoc object containing information from all features, regardless of `kind` attribute value. + */ + all: FeaturesDoc; + + /** + * FeaturesDoc objects deriving information from all features with the same `kind` attribute value. + */ + kinds?: FeaturesDoc[]; +} + +export interface FeaturesDoc { + /** + * The name for this group of features. Typically, the `kind` attribute value for targeting this group of features. + * + * @example "all" + * @example "motorway" + * @example "peaks" + */ + name: string; + + /** + * The filter expression for targeting this group of features. + * + * @example `["all"]` + * @example `["all", ["==", "kind", "motorway"]]`, + */ + filter: string; + + /** + * AttributeDoc objects containing attribute information across this group of features. + */ + attributes: AttributeDoc[]; + + /** + * A flag for whether this FeaturesDoc object describes any attributes (used exclusively by Mustache). + */ + hasAttributes: boolean; + + /** + * A comma-separated list of all geometries across this group of features. Typically, only one geometry. + * + * @example "LineString" + * @example "Point, Polygon" + */ + geometries: string; + + /** + * An object describing the min and max zoom levels for which features within this group appear. + * + * @example { "min": 12, "max": 15 } + */ + zoom_levels: { + min: number; + max: number; + }; +} + +export interface AttributeDoc { + /** + * The attribute's name. + */ + name: string; + + /** + * A comma-separated list of the attribute's types. Typically, only one type. + * + * @example "boolean" + * @example "number, string" + */ + types: string; + + /** + * A comma-separated list of the attribute's values. Sometimes only a snippet of the attribute's values. Sometimes minified. + * + * @example "1, 2, 3, 4, 5" + * @example "cable_car, ski_lift, ski_tow" + * @example "{empty}, industrial, people" + * @example "12448 unique values"" + */ + values: string; +} diff --git a/packages/cli-vector/src/types/report.ts b/packages/cli-vector/src/types/report.ts new file mode 100644 index 0000000000..835001da02 --- /dev/null +++ b/packages/cli-vector/src/types/report.ts @@ -0,0 +1,85 @@ +import { z } from 'zod'; + +/** + * Interface describing a LayerReport object as created and exported by the vector-cli 'reports' command. + */ +export interface LayerReport { + /** + * Name of the Shortbread layer for which the report derives. + * + * @example "addresses" + * @example "boundaries" + * @example "contours" + */ + name: string; + + /** + * FeaturesReport object containing information from all features, regardless of `kind` attribute value. + */ + all: FeaturesReport; + + /** + * FeaturesReport objects deriving information from all features with the same `kind` attribute value. + * + * @example { "contours": FeaturesReport, "peaks": FeaturesReport } + */ + kinds?: Record; +} + +export interface FeaturesReport { + /** + * @example { "feature": { "guaranteed": true, "type": "string", "values": ["people", "industrial"] } } + */ + attributes: Record; + + /** + * @example ["LineString"] + */ + geometries: ('LineString' | 'Point' | 'Polygon' | 'Unknown')[]; + + /** + * @example [12, 13, 14, 15] + */ + zoom_levels: number[]; +} + +export interface AttributeReport { + /** + * `true`, if all features of the parent `FeaturesReport` define this attribute. Otherwise, `false`. + */ + guaranteed: boolean; + + /** + * The number of unique values across all features of the parent `FeaturesReport` that define this attribute. + */ + num_unique_values: number; + /** + * @example ["boolean", "string"] + */ + types: string[]; + /** + * @example ["people", "industrial"] + */ + values: unknown[]; +} + +const zAttributeReport = z.object({ + guaranteed: z.boolean(), + num_unique_values: z.number(), + types: z.array(z.string()), + values: z.array(z.union([z.boolean(), z.number(), z.string()])), +}) satisfies z.ZodType; + +const zFeaturesReport = z.object({ + attributes: z.record(z.string(), zAttributeReport), + geometries: z.array( + z.union([z.literal('LineString'), z.literal('Point'), z.literal('Polygon'), z.literal('Unknown')]), + ), + zoom_levels: z.array(z.number()), +}) satisfies z.ZodType; + +export const zLayerReport = z.object({ + name: z.string(), + all: zFeaturesReport, + kinds: z.record(z.string(), zFeaturesReport).optional(), +}) satisfies z.ZodType; From 97b6f7213a2cc3a88d752157b8b2214329492a95 Mon Sep 17 00:00:00 2001 From: Tawera Manaena Date: Mon, 16 Jun 2025 09:28:55 +1200 Subject: [PATCH 13/15] refactor(cli-vector): refine the docs and reports commands --- packages/cli-vector/src/cli/cli.docs.ts | 53 ++++++++++++---------- packages/cli-vector/src/cli/cli.reports.ts | 50 +++++++------------- packages/cli-vector/src/types/report.ts | 12 +++-- 3 files changed, 51 insertions(+), 64 deletions(-) diff --git a/packages/cli-vector/src/cli/cli.docs.ts b/packages/cli-vector/src/cli/cli.docs.ts index ea22d7819f..7e0363230e 100644 --- a/packages/cli-vector/src/cli/cli.docs.ts +++ b/packages/cli-vector/src/cli/cli.docs.ts @@ -10,7 +10,6 @@ import { zSchema } from '../schema-loader/parser.js'; import { Schema } from '../schema-loader/schema.js'; import { AttributeDoc, FeaturesDoc, LayerDoc } from '../types/doc.js'; import { AttributeReport, LayerReport, zLayerReport } from '../types/report.js'; -import { MaxValues } from './cli.reports.js'; export const DocsArgs = { ...logArguments, @@ -31,7 +30,7 @@ export const DocsArgs = { description: 'Path to the Mustache template markdown file.', }), target: option({ - type: Url, + type: UrlFolder, long: 'target', description: 'Target directory into which to save the generated markdown documentation.', }), @@ -143,41 +142,45 @@ export const DocsCommand = command({ }); } - const layersDir = new URL('layers/', args.target); const template = readFileSync(args.template).toString(); for (const layer of docs) { const markdown = Mustache.render(template, layer); - await fsa.write(new URL(`${layer.name}.md`, layersDir), markdown); + const url = new URL(`${layer.name}.md`, args.target); + + await fsa.write(url, markdown); + logger.info({ url }, 'File created'); } - logger.info('GenerateMarkdownDocs: End'); + logger.info('Generate Markdown Docs: End'); }, }); function flattenAttributes(attributes: Record): AttributeDoc[] { - return Object.entries(attributes) - .map(([name, attribute]) => { - // handle types - const types = attribute.types.join(', '); - - // handle values - let values: string; - - if (attribute.num_unique_values > MaxValues) { - values = `${attribute.num_unique_values} unique values`; - } else { - values = attribute.values.sort().map(String).join(', '); - } + const attributeDocs: AttributeDoc[] = []; - if (!attribute.guaranteed) { - values = ['{empty}', values].join(', '); - } + for (const [name, attribute] of Object.entries(attributes)) { + // flatten types + const types = attribute.types.join(', '); + + // flatten values + const values: string[] = []; + + if (!attribute.guaranteed) { + values.push('{empty}'); + } + + if (attribute.has_more_values === true) { + values.push(`Too many values to list`); + } else { + values.push(...attribute.values.sort().map(String)); + } + + // push attribute + attributeDocs.push({ name, types, values: values.join(', ') }); + } - // return attribute - return { name, types, values }; - }) - .sort((a, b) => a.name.localeCompare(b.name)); + return attributeDocs.toSorted((a, b) => a.name.localeCompare(b.name)); } function flattenZoomLevels(zoom_levels: number[]): { min: number; max: number } { diff --git a/packages/cli-vector/src/cli/cli.reports.ts b/packages/cli-vector/src/cli/cli.reports.ts index d43efa4b7f..f8cbb2f86e 100644 --- a/packages/cli-vector/src/cli/cli.reports.ts +++ b/packages/cli-vector/src/cli/cli.reports.ts @@ -4,14 +4,14 @@ import { Url, UrlFolder } from '@basemaps/shared'; import { CliInfo } from '@basemaps/shared/build/cli/info.js'; import { getLogger, logArguments } from '@basemaps/shared/build/cli/log.js'; import { VectorTile, VectorTileFeature } from '@mapbox/vector-tile'; -import { command, oneOf, option } from 'cmd-ts'; +import { command, option } from 'cmd-ts'; import { existsSync, mkdirSync, writeFileSync } from 'fs'; import Protobuf from 'pbf'; import { gunzipSync } from 'zlib'; import { AttributeReport, FeaturesReport, LayerReport } from '../types/report.js'; -export const MaxValues = 24; +export const MaxUniqueValues = 20; const MaxZoom = 15; export const ReportsArgs = { @@ -26,25 +26,6 @@ export const ReportsArgs = { long: 'target', description: 'Target directory into which to save the generated reports.', }), - /** - * The `mode` argument can be useful, depending on what you want to check. - * - * For example, if you're generating reports to check an mbtiles file's contents, - * you can control how many values for each attribute to include in the generated - * reports. If you don't intend to check the values themselves, you can skip the - * 'value capturing' process entirely to speed up the command's execution time. - */ - mode: option({ - type: oneOf(['none', 'limited', 'full']), - defaultValue: () => 'limited', - defaultValueIsSerializable: true, - long: 'mode', - description: - 'For each attribute: ' + - 'none - do not output any values (fast). ' + - `limited - only output the first ${MaxValues} unique values. ` + - 'full - output all unique values (slow).', - }), }; export const ReportsCommand = command({ @@ -56,7 +37,7 @@ export const ReportsCommand = command({ args: ReportsArgs, handler(args) { const logger = getLogger(this, args, 'cli-vector'); - logger.info('Reports: Start'); + logger.info('Generate JSON Reports: Start'); const targetExists = existsSync(args.target); if (!targetExists) mkdirSync(args.target, { recursive: true }); @@ -136,9 +117,9 @@ export const ReportsCommand = command({ // init a report for the current attribute featureReport.attributes[name] = { guaranteed: true, - num_unique_values: 0, - values: [], types: [], + values: [], + has_more_values: false, } as AttributeReport; } @@ -151,16 +132,14 @@ export const ReportsCommand = command({ attributeReport.types.push(type); } - // capture the feature's value - if (!attributeReport.values.includes(value)) { - attributeReport.num_unique_values++; - - if (args.mode === 'limited') { - if (attributeReport.num_unique_values < MaxValues) { + // capture the feature's first 20 unique values + if (attributeReport.has_more_values === false) { + if (!attributeReport.values.includes(value)) { + if (attributeReport.values.length < MaxUniqueValues) { attributeReport.values.push(value); + } else { + attributeReport.has_more_values = true; } - } else if (args.mode === 'full') { - attributeReport.values.push(value); } } @@ -196,8 +175,11 @@ export const ReportsCommand = command({ // write each report to the target directory for (const [name, report] of Object.entries(layerReports)) { - writeFileSync(new URL(`${name}.json`, args.target), JSON.stringify(report, null, 2)); + const url = new URL(`${name}.json`, args.target); + + writeFileSync(url, JSON.stringify(report, null, 2)); + logger.info({ url }, 'File created'); } - logger.info('Reports: Done'); + logger.info('Generate JSON Reports: Done'); }, }); diff --git a/packages/cli-vector/src/types/report.ts b/packages/cli-vector/src/types/report.ts index 835001da02..9cb8b16ad0 100644 --- a/packages/cli-vector/src/types/report.ts +++ b/packages/cli-vector/src/types/report.ts @@ -49,25 +49,27 @@ export interface AttributeReport { */ guaranteed: boolean; - /** - * The number of unique values across all features of the parent `FeaturesReport` that define this attribute. - */ - num_unique_values: number; /** * @example ["boolean", "string"] */ types: string[]; + /** * @example ["people", "industrial"] */ values: unknown[]; + + /** + * A flag of whether has this attribute has more than `MaxValues` (i.e. 20) unique values. + */ + has_more_values: boolean; } const zAttributeReport = z.object({ guaranteed: z.boolean(), - num_unique_values: z.number(), types: z.array(z.string()), values: z.array(z.union([z.boolean(), z.number(), z.string()])), + has_more_values: z.boolean(), }) satisfies z.ZodType; const zFeaturesReport = z.object({ From ff1e99aa01728f0dec9b1e73d476f2f9a0ba0ca5 Mon Sep 17 00:00:00 2001 From: Tawera Manaena Date: Mon, 16 Jun 2025 09:32:16 +1200 Subject: [PATCH 14/15] fix(cli-vector): remove report-like metadata from the JSON schema files --- packages/cli-vector/schema/addresses.json | 14 +- packages/cli-vector/schema/aerialways.json | 26 +- packages/cli-vector/schema/boundaries.json | 14 +- packages/cli-vector/schema/buildings.json | 28 +- packages/cli-vector/schema/contours.json | 39 +-- packages/cli-vector/schema/dam_lines.json | 22 +- packages/cli-vector/schema/ferries.json | 12 +- packages/cli-vector/schema/land.json | 294 ------------------ .../cli-vector/schema/parcel_boundaries.json | 14 +- packages/cli-vector/schema/pier_lines.json | 12 +- packages/cli-vector/schema/place_labels.json | 29 +- packages/cli-vector/schema/pois.json | 73 ----- .../cli-vector/schema/public_transport.json | 28 +- packages/cli-vector/schema/sites.json | 54 +--- packages/cli-vector/schema/street_labels.json | 31 +- .../cli-vector/schema/street_polygons.json | 22 +- packages/cli-vector/schema/streets.json | 3 +- packages/cli-vector/schema/water_lines.json | 80 +---- .../cli-vector/schema/water_polygons.json | 72 +---- 19 files changed, 18 insertions(+), 849 deletions(-) diff --git a/packages/cli-vector/schema/addresses.json b/packages/cli-vector/schema/addresses.json index 3f35d9400d..15f62bbaf5 100644 --- a/packages/cli-vector/schema/addresses.json +++ b/packages/cli-vector/schema/addresses.json @@ -1,19 +1,7 @@ { "name": "addresses", "description": "This layer contains address features represented as `Point` geometries. Each feature includes a `housenumber` property.", - "metadata": { - "attributes": ["housenumber"], - "report": [ - { - "filter": ["all"], - "attributes": { - "housenumber": { "guaranteed": true, "type": "string" } - }, - "geometry": "Point", - "zoom_levels": { "min": 15, "max": 15 } - } - ] - }, + "metadata": { "attributes": ["housenumber"] }, "layers": [ { "id": "105689", diff --git a/packages/cli-vector/schema/aerialways.json b/packages/cli-vector/schema/aerialways.json index df870e1b48..8512bd2d57 100644 --- a/packages/cli-vector/schema/aerialways.json +++ b/packages/cli-vector/schema/aerialways.json @@ -1,31 +1,7 @@ { "name": "aerialways", "description": "This layer holds aerialways as `LineString` geometries.", - "metadata": { - "attributes": ["kind", "feature"], - "report": [ - { - "filter": ["all", ["==", "kind", "cable_car"]], - "attributes": { - "feature": { "guaranteed": true, "type": "string", "values": ["people", "industrial"] } - }, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "ski_lift"]], - "attributes": {}, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "ski_tow"]], - "attributes": {}, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - } - ] - }, + "metadata": { "attributes": ["kind", "feature"] }, "layers": [ { "id": "50248", diff --git a/packages/cli-vector/schema/boundaries.json b/packages/cli-vector/schema/boundaries.json index 4a1559d40e..e949cb2bdf 100644 --- a/packages/cli-vector/schema/boundaries.json +++ b/packages/cli-vector/schema/boundaries.json @@ -1,19 +1,7 @@ { "name": "boundaries", "description": "This layer contains coastline features represented as `Polygon` geometries, indicating land-sea boundaries. Most features include a `name` property.", - "metadata": { - "attributes": ["name"], - "report": [ - { - "filter": ["all"], - "attributes": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 0, "max": 15 } - } - ] - }, + "metadata": { "attributes": ["name"] }, "simplify": [ { "style": { "minZoom": 0, "maxZoom": 0 }, "tolerance": 0.1 }, { "style": { "minZoom": 1, "maxZoom": 1 }, "tolerance": 0.09 }, diff --git a/packages/cli-vector/schema/buildings.json b/packages/cli-vector/schema/buildings.json index 0c4dd79daf..0778919ab4 100644 --- a/packages/cli-vector/schema/buildings.json +++ b/packages/cli-vector/schema/buildings.json @@ -1,32 +1,6 @@ { "name": "buildings", - "metadata": { - "attributes": ["building", "store_item", "kind", "name", "use"], - "report": [ - { - "filter": ["all", ["!has", "kind"]], - "attributes": { - "building": { "guaranteed": true, "type": "string", "values": ["storage_tank"] }, - "store_item": { "guaranteed": false, "type": "string", "values": ["fuel", "water"] } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 9, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "building"]], - "attributes": { - "name": { "guaranteed": true, "type": "string" }, - "use": { - "guaranteed": true, - "type": "string", - "values": ["Unknown", "Supermarket", "School", "Hospital", "Hut", "Shelter"] - } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 14, "max": 15 } - } - ] - }, + "metadata": { "attributes": ["building", "store_item", "kind", "name", "use"] }, "layers": [ { "id": "101290", diff --git a/packages/cli-vector/schema/contours.json b/packages/cli-vector/schema/contours.json index 135aedf1d8..8c164b289d 100644 --- a/packages/cli-vector/schema/contours.json +++ b/packages/cli-vector/schema/contours.json @@ -1,43 +1,8 @@ { "name": "contours", - "description": "This layer contains contour line interval features represented as `LineString` geometries, and height peak features represents as 'Point' geometries.", + "description": "This layer contains contour line interval features represented as `LineString` geometries, and height peak features represents as `Point` geometries.", "custom": true, - "metadata": { - "attributes": ["designated", "type", "nat_form", "elevation", "kind", "name", "rank"], - "report": [ - { - "filter": ["all", ["==", "kind", "contours"]], - "attributes": { - "designated": { - "guaranteed": false, - "type": "string", - "values": ["supplementary"] - }, - "elevation": { - "guaranteed": true, - "type": "number" - }, - "nat_form": { "guaranteed": false, "type": "string", "values": ["depression"] }, - "type": { - "guaranteed": false, - "type": "string", - "values": ["index"] - } - }, - "geometry": "LineString", - "zoom_levels": { "min": 9, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "peak"]], - "attributes": { - "elevation": { "guaranteed": false, "type": "number" }, - "rank": { "guaranteed": false, "type": "number", "values": [5, 4, 3, 2, 1] } - }, - "geometry": "Point", - "zoom_levels": { "min": 9, "max": 15 } - } - ] - }, + "metadata": { "attributes": ["designated", "type", "nat_form", "elevation", "kind", "name", "rank"] }, "layers": [ { "id": "50768", diff --git a/packages/cli-vector/schema/dam_lines.json b/packages/cli-vector/schema/dam_lines.json index 53a445f43e..b96904e066 100644 --- a/packages/cli-vector/schema/dam_lines.json +++ b/packages/cli-vector/schema/dam_lines.json @@ -1,26 +1,6 @@ { "name": "dam_lines", - "metadata": { - "attributes": ["kind", "name", "dam_status"], - "report": [ - { - "filter": ["all", ["==", "kind", "dam"]], - "attributes": { - "dam_status": { - "guaranteed": false, - "type": "string", - "values": ["old", "ruins", "disused"] - }, - "name": { - "guaranteed": false, - "type": "string" - } - }, - "geometry": "LineString", - "zoom_levels": { "min": 4, "max": 15 } - } - ] - }, + "metadata": { "attributes": ["kind", "name", "dam_status"] }, "layers": [ { "id": "50075", diff --git a/packages/cli-vector/schema/ferries.json b/packages/cli-vector/schema/ferries.json index 5e9d265ce1..399c2de377 100644 --- a/packages/cli-vector/schema/ferries.json +++ b/packages/cli-vector/schema/ferries.json @@ -1,16 +1,6 @@ { "name": "ferries", - "metadata": { - "attributes": ["kind"], - "report": [ - { - "filter": ["all", ["==", "kind", "ferry"]], - "attributes": {}, - "geometry": "LineString", - "zoom_levels": { "min": 10, "max": 15 } - } - ] - }, + "metadata": { "attributes": ["kind"] }, "layers": [ { "id": "50269", diff --git a/packages/cli-vector/schema/land.json b/packages/cli-vector/schema/land.json index 03c2c26214..124c209a41 100644 --- a/packages/cli-vector/schema/land.json +++ b/packages/cli-vector/schema/land.json @@ -14,300 +14,6 @@ "substance", "visibility", "status" - ], - "report": [ - { - "filter": ["all", ["==", "kind", "bare_rock"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 14, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "boatramp"]], - "attributes": { - "name": { - "guaranteed": false, - "type": "string", - "values": ["boatramp", "Te Onepoto Boat Ramp", "Namukulu Boat Ramp"] - } - }, - "geometry": "LineString", - "zoom_levels": { "min": 10, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "cemetery"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 10, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "cliff"]], - "attributes": {}, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "cutting"]], - "attributes": {}, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "dredge_tailing"]], - "attributes": {}, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "dry_dock"]], - "attributes": {}, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "embankment"]], - "attributes": { - "embkmt_use": { - "guaranteed": false, - "type": "string", - "values": ["stopbank", "causeway", "seawall"] - }, - "name": { "guaranteed": false, "type": "string", "values": ["Tamehanas Dam"] } - }, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "fence"]], - "attributes": {}, - "geometry": "LineString", - "zoom_levels": { "min": 13, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "forest"]], - "attributes": { - "landuse": { "guaranteed": false, "type": "string", "values": ["forest", "wood"] }, - "species": { "guaranteed": false, "type": "string", "values": ["non-coniferous"] }, - "tree": { "guaranteed": true, "type": "string", "values": ["native", "exotic"] } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 0, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "golf_course"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 6, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "ice"]], - "attributes": {}, - "geometry": "Polygon", - "zoom_levels": { "min": 2, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "ladder"]], - "attributes": {}, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "landfill"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "mangrove"]], - "attributes": {}, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "mine"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" }, - "status": { - "guaranteed": false, - "type": "string", - "values": ["historic", "disused", "old"] - }, - "substance": { - "guaranteed": false, - "type": "string", - "values": ["coal", "gold", "ironsand"] - }, - "visibility": { - "guaranteed": true, - "type": "string", - "values": ["opencast"] - } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "moraine"]], - "attributes": {}, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "moraine_wall"]], - "attributes": {}, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "mud"]], - "attributes": {}, - "geometry": "Polygon", - "zoom_levels": { "min": 1, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "orchard"]], - "attributes": {}, - "geometry": "Polygon", - "zoom_levels": { "min": 10, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "pipeline"]], - "attributes": { - "visibility": { "guaranteed": false, "type": "string", "values": ["underground"] } - }, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "pond"]], - "attributes": { - "name": { - "guaranteed": false, - "type": "string", - "values": ["Lake Crichton", "pond", "ponds"] - } - }, - "geometry": "Polygon", - "zoom_levels": { "max": 15, "min": 9 } - }, - { - "filter": ["all", ["==", "kind", "powerline"]], - "attributes": { - "support_ty": { "guaranteed": false, "type": "string", "values": ["pole", "pylon"] } - }, - "geometry": "LineString", - "zoom_levels": { "min": 0, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "quarry"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" }, - "status": { "guaranteed": false, "type": "string", "values": ["disused"] }, - "substance": { - "guaranteed": false, - "type": "string", - "values": ["lime", "limestone", "silica sand", "stone", "clay", "gravel", "shingle", "metal", "zeolite"] - } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "residential"]], - "attributes": { - "name": { - "guaranteed": false, - "type": "string" - } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 0, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "sand"]], - "attributes": {}, - "geometry": "Polygon", - "zoom_levels": { "min": 8, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "scree"]], - "attributes": {}, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "scrub"]], - "attributes": { - "distribution": { "guaranteed": false, "type": "string", "values": ["scattered"] } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 0, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "shingle"]], - "attributes": {}, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "siphon"]], - "attributes": {}, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "slip"]], - "attributes": {}, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "slipway"]], - "attributes": {}, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "swamp"]], - - "attributes": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 2, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "telephone"]], - "attributes": {}, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "tree_row"]], - "attributes": {}, - "geometry": "LineString", - "zoom_levels": { "min": 8, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "vineyard"]], - "attributes": {}, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "walkwire"]], - "attributes": {}, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - } ] }, "layers": [ diff --git a/packages/cli-vector/schema/parcel_boundaries.json b/packages/cli-vector/schema/parcel_boundaries.json index bd1e779a77..f007e949b1 100644 --- a/packages/cli-vector/schema/parcel_boundaries.json +++ b/packages/cli-vector/schema/parcel_boundaries.json @@ -1,18 +1,6 @@ { "name": "parcel_boundaries", - "metadata": { - "attributes": ["parcel_intent", "name", "id"], - "report": [ - { - "filter": ["all"], - "attributes": { - "parcel_intent": { "guaranteed": true, "type": "string" } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 14, "max": 15 } - } - ] - }, + "metadata": { "attributes": ["parcel_intent", "name", "id"] }, "layers": [ { "id": "50772", diff --git a/packages/cli-vector/schema/pier_lines.json b/packages/cli-vector/schema/pier_lines.json index 87f6669c19..8e153b6b0b 100644 --- a/packages/cli-vector/schema/pier_lines.json +++ b/packages/cli-vector/schema/pier_lines.json @@ -1,16 +1,6 @@ { "name": "pier_lines", - "metadata": { - "attributes": ["kind", "name"], - "report": [ - { - "filter": ["all", ["==", "kind", "breakwater"]], - "attributes": {}, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - } - ] - }, + "metadata": { "attributes": ["kind", "name"] }, "layers": [ { "id": "50243", diff --git a/packages/cli-vector/schema/place_labels.json b/packages/cli-vector/schema/place_labels.json index 79908d0d46..83e2bc362d 100644 --- a/packages/cli-vector/schema/place_labels.json +++ b/packages/cli-vector/schema/place_labels.json @@ -1,33 +1,6 @@ { "name": "place_labels", - "metadata": { - "attributes": ["kind", "water", "name", "natural", "place"], - "report": [ - { - "filter": ["all"], - "attributes": { - "name": { "guaranteed": true, "type": "string" }, - "natural": { - "guaranteed": true, - "type": "string", - "values": ["0", "cape", "peninsula", "peak"] - }, - "place": { - "guaranteed": true, - "type": "string", - "values": ["0", "island", "archipelago", "city", "town", "lake", "village", "suburb", "Island"] - }, - "water": { - "guaranteed": true, - "type": "string", - "values": ["sea", "0", "ocean", "searidge", "seachannel", "seamount", "seacanyon", "bay", "lagoon"] - } - }, - "geometry": "Point", - "zoom_levels": { "min": 3, "max": 14 } - } - ] - }, + "metadata": { "attributes": ["kind", "water", "name", "natural", "place"] }, "layers": [ { "id": "51154", diff --git a/packages/cli-vector/schema/pois.json b/packages/cli-vector/schema/pois.json index de2e9ca4a6..2c76a399fa 100644 --- a/packages/cli-vector/schema/pois.json +++ b/packages/cli-vector/schema/pois.json @@ -32,79 +32,6 @@ "orientation", "substance", "visibility" - ], - "report": [ - { - "filter": ["all"], - "attributes": { - "building": { "guaranteed": false, "type": "string", "values": ["storage_tank"] }, - "store_item": { "guaranteed": false, "type": "string", "values": ["water", "fuel"] }, - "wetland": { "guaranteed": false, "type": "string", "values": ["swamp"] }, - "natural": { - "guaranteed": false, - "type": "string", - "values": ["tree", "cave_entrance", "spring", "sinkhole", "rock", "fumarole"] - }, - "power": { "guaranteed": false, "type": "string", "values": ["pole"] }, - "name": { "guaranteed": false, "type": "string" }, - "man_made": { - "guaranteed": false, - "type": "string", - "values": [ - "kiln", - "beacon", - "mast", - "water_well", - "trig_point", - "tower", - "wind_turbine", - "chimney", - "dredge", - "radar_dome", - "mineshaft", - "telescope", - "flare", - "ladder", - "geo_bore" - ] - }, - "historic": { "guaranteed": false, "type": "string", "values": ["wreck", "monument", "yes", "redoubt"] }, - "temp": { "guaranteed": false, "type": "string", "values": ["cold", "hot"] }, - "waterway": { - "guaranteed": false, - "type": "string", - "values": ["soakhole", "ford", "waterfall", "siphon", "sluice_gate"] - }, - "type": { "guaranteed": false, "type": "string", "values": ["lighthouse"] }, - "height": { "guaranteed": false, "type": "number" }, - "barrier": { "guaranteed": false, "type": "string", "values": ["gate"] }, - "farmyard": { "guaranteed": false, "type": "string", "values": ["stockyard"] }, - "landuse": { "guaranteed": false, "type": "string", "values": ["cemetery", "mine"] }, - "amenity": { "guaranteed": false, "type": "string", "values": ["grave_yard", "bivouac"] }, - "direction": { "guaranteed": false, "type": "number" }, - "elevation": { "guaranteed": false, "type": "number" }, - "materials": { "guaranteed": false, "type": "string", "values": ["rock"] }, - "status": { - "guaranteed": false, - "type": "string", - "values": ["disused", "old", "derelict", "dangerous", "historic", "closed", "remains"] - }, - "visibility": { "guaranteed": false, "type": "string", "values": ["underground", "opencast"] }, - "ref": { "guaranteed": false, "type": "string" }, - "leisure": { "guaranteed": false, "type": "string", "values": ["shooting_ground"] }, - "substance": { - "guaranteed": false, - "type": "string", - "values": ["scheelite", "gold", "quartz", "coal", "silver", "bentonite"] - }, - "fortification_type": { "guaranteed": false, "type": "string", "values": ["pa"] }, - "pipeline": { "guaranteed": false, "type": "string", "values": ["valve"] }, - "seamark": { "guaranteed": false, "type": "string", "values": ["buoy"] }, - "geological": { "guaranteed": false, "type": "string", "values": ["outcrop"] } - }, - "geometry": "Point", - "zoom_levels": { "min": 0, "max": 15 } - } ] }, "layers": [ diff --git a/packages/cli-vector/schema/public_transport.json b/packages/cli-vector/schema/public_transport.json index 35796954fd..ceaea5f8e3 100644 --- a/packages/cli-vector/schema/public_transport.json +++ b/packages/cli-vector/schema/public_transport.json @@ -1,32 +1,6 @@ { "name": "public_transport", - "metadata": { - "attributes": ["kind", "name"], - "report": [ - { - "filter": ["all", ["==", "kind", "aerodrome"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "Point", - "zoom_levels": { "min": 0, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "helipad"]], - "attributes": {}, - "geometry": "Point", - "zoom_levels": { "min": 10, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "station"]], - "attributes": { - "name": { "guaranteed": true, "type": "string" } - }, - "geometry": "Point", - "zoom_levels": { "min": 12, "max": 15 } - } - ] - }, + "metadata": { "attributes": ["kind", "name"] }, "layers": [ { "id": "50237", diff --git a/packages/cli-vector/schema/sites.json b/packages/cli-vector/schema/sites.json index c1f6ac5cf9..ea9cd92c05 100644 --- a/packages/cli-vector/schema/sites.json +++ b/packages/cli-vector/schema/sites.json @@ -1,58 +1,6 @@ { "name": "sites", - "metadata": { - "attributes": ["kind", "species", "name", "type", "track_type", "track_use"], - "report": [ - { - "filter": ["all", ["==", "kind", "fish_farm"]], - "attributes": { - "species": { "guaranteed": false, "type": "string", "values": ["salmon"] } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "gravel_pit"]], - "attributes": {}, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "pumice_pit"]], - "attributes": {}, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "raceway"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" }, - "track_type": { "guaranteed": false, "type": "string", "values": ["training"] }, - "track_use": { - "guaranteed": false, - "type": "string", - "values": ["horse", "vehicle"] - } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "showground"]], - "attributes": {}, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "sports_field"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 7, "max": 15 } - } - ] - }, + "metadata": { "attributes": ["kind", "species", "name", "type", "track_type", "track_use"] }, "layers": [ { "id": "50283", diff --git a/packages/cli-vector/schema/street_labels.json b/packages/cli-vector/schema/street_labels.json index 063c4e2b1d..a9ed8f949c 100644 --- a/packages/cli-vector/schema/street_labels.json +++ b/packages/cli-vector/schema/street_labels.json @@ -1,35 +1,6 @@ { "name": "street_labels", - "metadata": { - "attributes": ["kind", "ref", "name"], - "report": [ - { - "filter": ["all", ["==", "kind", "motorway"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" }, - "ref": { "guaranteed": true, "type": "string" } - }, - "geometry": "LineString", - "zoom_levels": { "min": 8, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "primary"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "LineString", - "zoom_levels": { "min": 8, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "secondary"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "LineString", - "zoom_levels": { "min": 8, "max": 15 } - } - ] - }, + "metadata": { "attributes": ["kind", "ref", "name"] }, "layers": [ { "id": "50329", diff --git a/packages/cli-vector/schema/street_polygons.json b/packages/cli-vector/schema/street_polygons.json index 17e0039b84..8461bf27d3 100644 --- a/packages/cli-vector/schema/street_polygons.json +++ b/packages/cli-vector/schema/street_polygons.json @@ -1,26 +1,6 @@ { "name": "street_polygons", - "metadata": { - "attributes": ["kind", "surface", "name"], - "report": [ - { - "filter": ["all", ["==", "kind", "aerodrome"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 5, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "runway"]], - "attributes": { - "surface": { "guaranteed": false, "type": "string", "values": ["sealed"] } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 10, "max": 15 } - } - ] - }, + "metadata": { "attributes": ["kind", "surface", "name"] }, "layers": [ { "id": "50237", diff --git a/packages/cli-vector/schema/streets.json b/packages/cli-vector/schema/streets.json index 4be0cbf7a5..1b89ce97ef 100644 --- a/packages/cli-vector/schema/streets.json +++ b/packages/cli-vector/schema/streets.json @@ -19,8 +19,7 @@ "use_2", "ref", "subclass" - ], - "report": [] + ] }, "layers": [ { diff --git a/packages/cli-vector/schema/water_lines.json b/packages/cli-vector/schema/water_lines.json index 342f2d07aa..252514239f 100644 --- a/packages/cli-vector/schema/water_lines.json +++ b/packages/cli-vector/schema/water_lines.json @@ -1,84 +1,6 @@ { "name": "water_lines", - "metadata": { - "attributes": ["kind", "name", "feature", "species", "height"], - "report": [ - { - "filter": ["all", ["==", "kind", "boom"]], - "attributes": {}, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "drain"]], - "attributes": {}, - "geometry": "LineString", - "zoom_levels": { "min": 10, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "flume"]], - "attributes": {}, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "marine_farm"]], - "attributes": { - "species": { "guaranteed": false, "type": "string", "values": ["salmon"] } - }, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "river"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "LineString", - "zoom_levels": { "min": 8, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "stream"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "water_race"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "waterfall"]], - "attributes": { - "feature": { "guaranteed": false, "type": "string", "values": ["edge"] }, - "height": { "guaranteed": true, "type": "number" }, - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "LineString", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "wharf"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "LineString", - "zoom_levels": { "min": 10, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "wharf_edge"]], - "attributes": {}, - "geometry": "LineString", - "zoom_levels": { "min": 10, "max": 15 } - } - ] - }, + "metadata": { "attributes": ["kind", "name", "feature", "species", "height"] }, "layers": [ { "id": "103632", diff --git a/packages/cli-vector/schema/water_polygons.json b/packages/cli-vector/schema/water_polygons.json index db62bc9bb8..b1226ea641 100644 --- a/packages/cli-vector/schema/water_polygons.json +++ b/packages/cli-vector/schema/water_polygons.json @@ -1,76 +1,6 @@ { "name": "water_polygons", - "metadata": { - "attributes": ["water", "kind", "name", "lid_type", "species", "height", "direction"], - "report": [ - { - "filter": ["all", ["==", "kind", "marine_farm"]], - "attributes": { - "species": { "guaranteed": false, "type": "string", "values": ["mussels"] } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "reef"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 1, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "reservoir"]], - "attributes": { - "lid_type": { "guaranteed": false, "type": "string", "values": ["covered"] } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 10, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "river"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 9, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "shoal"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "stream"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "water"]], - "attributes": { - "name": { "guaranteed": false, "type": "string" }, - "water": { "guaranteed": true, "type": "string", "values": ["lagoon", "lake"] } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 1, "max": 15 } - }, - { - "filter": ["all", ["==", "kind", "waterfall"]], - "attributes": { - "height": { "guaranteed": true, "type": "number", "values": [56] }, - "name": { "guaranteed": true, "type": "string", "values": ["Alice Falls"] } - }, - "geometry": "Polygon", - "zoom_levels": { "min": 12, "max": 15 } - } - ] - }, + "metadata": { "attributes": ["water", "kind", "name", "lid_type", "species", "height", "direction"] }, "layers": [ { "id": "103631", From 80260f065c3613e3f3731e9622f5387374a34e4d Mon Sep 17 00:00:00 2001 From: Tawera Manaena Date: Mon, 16 Jun 2025 09:44:51 +1200 Subject: [PATCH 15/15] fix(cli-vector): minor adjustments --- packages/cli-vector/src/cli/cli.docs.ts | 2 +- packages/cli-vector/src/types/report.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/cli-vector/src/cli/cli.docs.ts b/packages/cli-vector/src/cli/cli.docs.ts index 7e0363230e..59d4150073 100644 --- a/packages/cli-vector/src/cli/cli.docs.ts +++ b/packages/cli-vector/src/cli/cli.docs.ts @@ -44,7 +44,7 @@ export const DocsCommand = command({ args: DocsArgs, async handler(args) { const logger = getLogger(this, args, 'cli-vector'); - logger.info('Docs: Start'); + logger.info('Generate Markdown Docs: Start'); const targetExists = existsSync(args.target); if (!targetExists) mkdirSync(args.target, { recursive: true }); diff --git a/packages/cli-vector/src/types/report.ts b/packages/cli-vector/src/types/report.ts index 9cb8b16ad0..b820333f4b 100644 --- a/packages/cli-vector/src/types/report.ts +++ b/packages/cli-vector/src/types/report.ts @@ -60,7 +60,8 @@ export interface AttributeReport { values: unknown[]; /** - * A flag of whether has this attribute has more than `MaxValues` (i.e. 20) unique values. + * `true`, if all features of the parent `FeaturesReport` define this attribute with more than `MaxValues` (i.e. 20) unique values. Otherwise, `false`. + * Capturing all unique values at runtime demands too much memory. Useful for determining if an attribute is likely to describe a limited set of options (i.e an Enum). */ has_more_values: boolean; }