First version of automatic dependency injection

This commit is contained in:
Pieter Vander Vennet 2021-12-04 21:49:17 +01:00
parent 2dc6d4658f
commit 62f280feae
3 changed files with 81 additions and 32 deletions

View file

@ -1,7 +1,7 @@
import {Translation} from "../../UI/i18n/Translation"; import {Translation} from "../../UI/i18n/Translation";
import SourceConfig from "./SourceConfig"; import SourceConfig from "./SourceConfig";
import TagRenderingConfig from "./TagRenderingConfig"; import TagRenderingConfig from "./TagRenderingConfig";
import PresetConfig from "./PresetConfig"; import PresetConfig, {PreciseInput} from "./PresetConfig";
import {LayerConfigJson} from "./Json/LayerConfigJson"; import {LayerConfigJson} from "./Json/LayerConfigJson";
import Translations from "../../UI/i18n/Translations"; import Translations from "../../UI/i18n/Translations";
import {TagUtils} from "../../Logic/Tags/TagUtils"; import {TagUtils} from "../../Logic/Tags/TagUtils";
@ -26,19 +26,19 @@ import * as icons from "../../assets/tagRenderings/icons.json"
export default class LayerConfig extends WithContextLoader { export default class LayerConfig extends WithContextLoader {
id: string; public readonly id: string;
name: Translation; public readonly name: Translation;
description: Translation; public readonly description: Translation;
source: SourceConfig; public readonly source: SourceConfig;
calculatedTags: [string, string][]; public readonly calculatedTags: [string, string][];
doNotDownload: boolean; public readonly doNotDownload: boolean;
passAllFeatures: boolean; public readonly passAllFeatures: boolean;
isShown: TagRenderingConfig; public readonly isShown: TagRenderingConfig;
minzoom: number; public readonly minzoom: number;
minzoomVisible: number; public readonly minzoomVisible: number;
maxzoom: number; public readonly maxzoom: number;
title?: TagRenderingConfig; public readonly title?: TagRenderingConfig;
titleIcons: TagRenderingConfig[]; public readonly titleIcons: TagRenderingConfig[];
public readonly mapRendering: PointRenderingConfig[] public readonly mapRendering: PointRenderingConfig[]
public readonly lineRendering: LineRenderingConfig[] public readonly lineRendering: LineRenderingConfig[]
@ -52,10 +52,10 @@ export default class LayerConfig extends WithContextLoader {
*/ */
public readonly maxAgeOfCache: number public readonly maxAgeOfCache: number
presets: PresetConfig[]; public readonly presets: PresetConfig[];
tagRenderings: TagRenderingConfig[]; public readonly tagRenderings: TagRenderingConfig[];
filters: FilterConfig[]; public readonly filters: FilterConfig[];
constructor( constructor(
json: LayerConfigJson, json: LayerConfigJson,
@ -151,8 +151,7 @@ export default class LayerConfig extends WithContextLoader {
throw "Presets should be a list of items (at " + context + ")" throw "Presets should be a list of items (at " + context + ")"
} }
this.presets = (json.presets ?? []).map((pr, i) => { this.presets = (json.presets ?? []).map((pr, i) => {
let preciseInput: PreciseInput = {
let preciseInput: any = {
preferredBackground: ["photo"], preferredBackground: ["photo"],
snapToLayers: undefined, snapToLayers: undefined,
maxSnapDistance: undefined maxSnapDistance: undefined
@ -163,6 +162,7 @@ export default class LayerConfig extends WithContextLoader {
preferredBackground: undefined preferredBackground: undefined
} }
} }
let snapToLayers: string[]; let snapToLayers: string[];
if (typeof pr.preciseInput.snapToLayer === "string") { if (typeof pr.preciseInput.snapToLayer === "string") {
snapToLayers = [pr.preciseInput.snapToLayer] snapToLayers = [pr.preciseInput.snapToLayer]
@ -178,7 +178,7 @@ export default class LayerConfig extends WithContextLoader {
} }
preciseInput = { preciseInput = {
preferredBackground: preferredBackground, preferredBackground: preferredBackground,
snapToLayers: snapToLayers, snapToLayers,
maxSnapDistance: pr.preciseInput.maxSnapDistance ?? 10 maxSnapDistance: pr.preciseInput.maxSnapDistance ?? 10
} }
} }
@ -439,6 +439,10 @@ export default class LayerConfig extends WithContextLoader {
] ]
} }
for (const dep of Array.from(this.getDependencies())) {
extraProps.push(new Combine(["This layer will automatically load ", new Link(dep, "#"+dep)," into the layout as it depends on it."]))
}
return new Combine([ return new Combine([
new Title(this.id, 3), new Title(this.id, 3),
this.description, this.description,
@ -478,4 +482,23 @@ export default class LayerConfig extends WithContextLoader {
public isLeftRightSensitive(): boolean { public isLeftRightSensitive(): boolean {
return this.lineRendering.some(lr => lr.leftRightSensitive) return this.lineRendering.some(lr => lr.leftRightSensitive)
} }
/**
* Returns a set of all other layer-ids that this layer needs to function.
* E.g. if this layers does snap to another layer in the preset, this other layer id will be mentioned
*/
public getDependencies(): Set<string>{
const deps = new Set<string>()
for (const preset of this.presets ?? []) {
if(preset.preciseInput?.snapToLayers === undefined){
continue
}
preset.preciseInput?.snapToLayers?.forEach(id => {
deps.add(id);
})
}
return deps
}
} }

View file

@ -166,7 +166,7 @@ export default class LayoutConfig {
return return
} else { } else {
const shared = AllKnownLayers.sharedLayers.get(layer) const shared = AllKnownLayers.sharedLayers.get(layer)
if(shared === undefined){ if (shared === undefined) {
throw `Shared layer ${layer} not found (at ${context}.layers[${i}])` throw `Shared layer ${layer} not found (at ${context}.layers[${i}])`
} }
result.push(shared) result.push(shared)
@ -212,15 +212,39 @@ export default class LayoutConfig {
}) })
}); });
// Some special layers which are always included by default // Some special layers which are always included by default
for (const defaultLayer of AllKnownLayers.added_by_default) { for (const defaultLayer of AllKnownLayers.added_by_default) {
if(result.some(l => l?.id === defaultLayer)){ if (result.some(l => l?.id === defaultLayer)) {
continue; // Already added continue; // Already added
} }
result.push(AllKnownLayers.sharedLayers.get(defaultLayer)) const sharedLayer = AllKnownLayers.sharedLayers.get(defaultLayer)
if (sharedLayer !== undefined) {
result.push(sharedLayer)
}
} }
let unmetDependencies: { dependency: string, layer: string }[] = []
do {
const dependencies: { dependency: string, layer: string }[] = [].concat(...result.map(l => Array.from(l.getDependencies()).map(d => ({
dependency: d,
layer: l.id
}))))
const loadedLayers = new Set(result.map(r => r.id))
unmetDependencies = dependencies.filter(dep => !loadedLayers.has(dep.dependency))
for (const unmetDependency of unmetDependencies) {
console.log("Recursively loading unmet dependency ", unmetDependency.dependency, "(needed by " + unmetDependency.layer + ")")
const dep = AllKnownLayers.sharedLayers.get(unmetDependency.dependency)
if (dep === undefined) {
throw "The layer '" + unmetDependency.layer + "' needs '" + unmetDependency.dependency + "' to be loaded, but it could not be found as builtin layer (at " + context + ")"
}
result.unshift(dep)
unmetDependencies = unmetDependencies.filter(d => d.dependency !== unmetDependency.dependency)
}
} while (unmetDependencies.length > 0)
return {layers: result, extractAllNodes: exportAllNodes} return {layers: result, extractAllNodes: exportAllNodes}
} }
@ -300,9 +324,9 @@ export default class LayoutConfig {
public isLeftRightSensitive() { public isLeftRightSensitive() {
return this.layers.some(l => l.isLeftRightSensitive()) return this.layers.some(l => l.isLeftRightSensitive())
} }
public getMatchingLayer(tags: any) : LayerConfig | undefined{ public getMatchingLayer(tags: any): LayerConfig | undefined {
if(tags === undefined){ if (tags === undefined) {
return undefined return undefined
} }
for (const layer of this.layers) { for (const layer of this.layers) {

View file

@ -1,6 +1,12 @@
import {Translation} from "../../UI/i18n/Translation"; import {Translation} from "../../UI/i18n/Translation";
import {Tag} from "../../Logic/Tags/Tag"; import {Tag} from "../../Logic/Tags/Tag";
export interface PreciseInput {
preferredBackground?: string[],
snapToLayers?: string[],
maxSnapDistance?: number
}
export default interface PresetConfig { export default interface PresetConfig {
title: Translation, title: Translation,
tags: Tag[], tags: Tag[],
@ -8,9 +14,5 @@ export default interface PresetConfig {
/** /**
* If precise input is set, then an extra map is shown in which the user can drag the map to the precise location * If precise input is set, then an extra map is shown in which the user can drag the map to the precise location
*/ */
preciseInput?: { preciseInput?: PreciseInput
preferredBackground?: string[],
snapToLayers?: string[],
maxSnapDistance?: number
}
} }