First version of automatic dependency injection

This commit is contained in:
pietervdvn 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 SourceConfig from "./SourceConfig";
import TagRenderingConfig from "./TagRenderingConfig";
import PresetConfig from "./PresetConfig";
import PresetConfig, {PreciseInput} from "./PresetConfig";
import {LayerConfigJson} from "./Json/LayerConfigJson";
import Translations from "../../UI/i18n/Translations";
import {TagUtils} from "../../Logic/Tags/TagUtils";
@ -26,19 +26,19 @@ import * as icons from "../../assets/tagRenderings/icons.json"
export default class LayerConfig extends WithContextLoader {
id: string;
name: Translation;
description: Translation;
source: SourceConfig;
calculatedTags: [string, string][];
doNotDownload: boolean;
passAllFeatures: boolean;
isShown: TagRenderingConfig;
minzoom: number;
minzoomVisible: number;
maxzoom: number;
title?: TagRenderingConfig;
titleIcons: TagRenderingConfig[];
public readonly id: string;
public readonly name: Translation;
public readonly description: Translation;
public readonly source: SourceConfig;
public readonly calculatedTags: [string, string][];
public readonly doNotDownload: boolean;
public readonly passAllFeatures: boolean;
public readonly isShown: TagRenderingConfig;
public readonly minzoom: number;
public readonly minzoomVisible: number;
public readonly maxzoom: number;
public readonly title?: TagRenderingConfig;
public readonly titleIcons: TagRenderingConfig[];
public readonly mapRendering: PointRenderingConfig[]
public readonly lineRendering: LineRenderingConfig[]
@ -52,10 +52,10 @@ export default class LayerConfig extends WithContextLoader {
*/
public readonly maxAgeOfCache: number
presets: PresetConfig[];
public readonly presets: PresetConfig[];
tagRenderings: TagRenderingConfig[];
filters: FilterConfig[];
public readonly tagRenderings: TagRenderingConfig[];
public readonly filters: FilterConfig[];
constructor(
json: LayerConfigJson,
@ -151,8 +151,7 @@ export default class LayerConfig extends WithContextLoader {
throw "Presets should be a list of items (at " + context + ")"
}
this.presets = (json.presets ?? []).map((pr, i) => {
let preciseInput: any = {
let preciseInput: PreciseInput = {
preferredBackground: ["photo"],
snapToLayers: undefined,
maxSnapDistance: undefined
@ -163,6 +162,7 @@ export default class LayerConfig extends WithContextLoader {
preferredBackground: undefined
}
}
let snapToLayers: string[];
if (typeof pr.preciseInput.snapToLayer === "string") {
snapToLayers = [pr.preciseInput.snapToLayer]
@ -178,7 +178,7 @@ export default class LayerConfig extends WithContextLoader {
}
preciseInput = {
preferredBackground: preferredBackground,
snapToLayers: snapToLayers,
snapToLayers,
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([
new Title(this.id, 3),
this.description,
@ -478,4 +482,23 @@ export default class LayerConfig extends WithContextLoader {
public isLeftRightSensitive(): boolean {
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
} else {
const shared = AllKnownLayers.sharedLayers.get(layer)
if(shared === undefined){
if (shared === undefined) {
throw `Shared layer ${layer} not found (at ${context}.layers[${i}])`
}
result.push(shared)
@ -212,15 +212,39 @@ export default class LayoutConfig {
})
});
// Some special layers which are always included 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
}
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}
}
@ -300,9 +324,9 @@ export default class LayoutConfig {
public isLeftRightSensitive() {
return this.layers.some(l => l.isLeftRightSensitive())
}
public getMatchingLayer(tags: any) : LayerConfig | undefined{
if(tags === undefined){
public getMatchingLayer(tags: any): LayerConfig | undefined {
if (tags === undefined) {
return undefined
}
for (const layer of this.layers) {

View file

@ -1,6 +1,12 @@
import {Translation} from "../../UI/i18n/Translation";
import {Tag} from "../../Logic/Tags/Tag";
export interface PreciseInput {
preferredBackground?: string[],
snapToLayers?: string[],
maxSnapDistance?: number
}
export default interface PresetConfig {
title: Translation,
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
*/
preciseInput?: {
preferredBackground?: string[],
snapToLayers?: string[],
maxSnapDistance?: number
}
preciseInput?: PreciseInput
}