Make layers config typesafe.

This commit is contained in:
baldo 2022-08-24 23:47:55 +02:00
parent 00d93c33b4
commit 59ef8256e6
2 changed files with 72 additions and 3 deletions

View file

@ -3,7 +3,15 @@ import commandLineUsage from "command-line-usage";
import fs from "graceful-fs";
import url from "url";
import { parse } from "sparkson";
import { Config, hasOwnProperty, Url, Version } from "./types";
import {
Config,
hasOwnProperty,
isLayerConfig,
isPlainObject,
isString,
Url,
Version,
} from "./types";
export let config: Config = {} as Config;
export let version: Version = "unknown" as Version;
@ -89,6 +97,24 @@ export function parseCommandLine(): void {
config = parse(Config, configJSON);
if (!isPlainObject(config.client.coordsSelector.layers)) {
console.error(
"Error in config.json: client.coordsSelector.layers is not an JSON object."
);
process.exit(1);
}
for (const [id, layerConfig] of Object.entries(
config.client.coordsSelector.layers
)) {
if (!isLayerConfig(layerConfig)) {
console.error(
`Error in config.json: client.coordsSelector.layers[${id}] is not a valid layer config.`
);
process.exit(1);
}
}
function stripTrailingSlash(url: Url): Url {
return url.endsWith("/")
? (url.substring(0, url.length - 1) as Url)

View file

@ -1,4 +1,9 @@
import { ArrayField, Field, RawJsonField } from "sparkson";
import {
ArrayField,
Field,
RawJsonField,
registerStringMapper,
} from "sparkson";
// Types shared with the client.
export type TypeGuard<T> = (arg: unknown) => arg is T;
@ -282,12 +287,50 @@ export function isCoordinatesConfig(arg: unknown): arg is CoordinatesConfig {
return isNumber(coords.lat) && isNumber(coords.lng);
}
export type LayerOptions = {
attribution: string;
subdomains?: string;
maxZoom: number;
};
export function isLayerOptions(arg: unknown): arg is LayerOptions {
if (!isPlainObject(arg)) {
return false;
}
const obj = arg as LayerOptions;
return (
isString(obj.attribution) &&
isOptional(obj.subdomains, isString) &&
isNumber(obj.maxZoom)
);
}
export type LayerConfig = {
name: string;
url: Url;
type: string;
layerOptions: LayerOptions;
};
export function isLayerConfig(arg: unknown): arg is LayerConfig {
if (!isPlainObject(arg)) {
return false;
}
const obj = arg as LayerConfig;
return (
isString(obj.name) &&
isUrl(obj.url) &&
isString(obj.type) &&
isLayerOptions(obj.layerOptions)
);
}
export class CoordinatesSelectorConfig {
constructor(
@Field("lat") public lat: number,
@Field("lng") public lng: number,
@Field("defaultZoom") public defaultZoom: number,
@RawJsonField("layers") public layers: JSONObject
@RawJsonField("layers") public layers: Record<string, LayerConfig>
) {}
}