refactoring(maplibre): WIP

This commit is contained in:
Pieter Vander Vennet 2023-03-24 19:21:15 +01:00
parent 231d67361e
commit 4d48b1cf2b
89 changed files with 1166 additions and 3973 deletions

View file

@ -23,8 +23,6 @@ import predifined_filters from "../../../assets/layers/filters/filters.json"
import { TagConfigJson } from "../Json/TagConfigJson"
import PointRenderingConfigJson from "../Json/PointRenderingConfigJson"
import LineRenderingConfigJson from "../Json/LineRenderingConfigJson"
import { type } from "os"
import exp from "constants"
class ExpandFilter extends DesugaringStep<LayerConfigJson> {
private static readonly predefinedFilters = ExpandFilter.load_filters()

View file

@ -175,7 +175,7 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
}
class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> {
private _state: DesugaringContext
private readonly _state: DesugaringContext
constructor(state: DesugaringContext) {
super(
@ -430,7 +430,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
constructor(state: DesugaringContext) {
super(
`If a layer has a dependency on another layer, these layers are added automatically on the theme. (For example: defibrillator depends on 'walls_and_buildings' to snap onto. This layer is added automatically)
Note that these layers are added _at the start_ of the layer list, meaning that they will see _every_ feature.
Furthermore, \`passAllFeatures\` will be set, so that they won't steal away features from further layers.
Some layers (e.g. \`all_buildings_and_walls\' or \'streets_with_a_name\') are invisible, so by default, \'force_load\' is set too.

View file

@ -15,6 +15,7 @@ import Svg from "../../../Svg"
import FilterConfigJson from "../Json/FilterConfigJson"
import DeleteConfig from "../DeleteConfig"
import { QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson"
import ValidatedTextField from "../../../UI/Input/ValidatedTextField"
class ValidateLanguageCompleteness extends DesugaringStep<any> {
private readonly _languages: string[]
@ -594,6 +595,7 @@ export class DetectMappingsWithImages extends DesugaringStep<TagRenderingConfigJ
class MiscTagRenderingChecks extends DesugaringStep<TagRenderingConfigJson> {
private _options: { noQuestionHintCheck: boolean }
constructor(options: { noQuestionHintCheck: boolean }) {
super("Miscellaneous checks on the tagrendering", ["special"], "MiscTagRenderingChecks")
this._options = options
@ -637,6 +639,19 @@ class MiscTagRenderingChecks extends DesugaringStep<TagRenderingConfigJson> {
}
}
}
const freeformType = json["freeform"]?.["type"]
if (freeformType) {
if (ValidatedTextField.AvailableTypes().indexOf(freeformType) < 0) {
throw (
"At " +
context +
".freeform.type is an unknown type: " +
freeformType +
"; try one of " +
ValidatedTextField.AvailableTypes().join(", ")
)
}
}
return {
result: json,
errors,
@ -905,6 +920,38 @@ export class ValidateLayer extends DesugaringStep<LayerConfigJson> {
}
}
export class ValidateFilter extends DesugaringStep<FilterConfigJson> {
constructor() {
super("Detect common errors in the filters", [], "ValidateFilter")
}
convert(
filter: FilterConfigJson,
context: string
): {
result: FilterConfigJson
errors?: string[]
warnings?: string[]
information?: string[]
} {
const errors = []
for (const option of filter.options) {
for (let i = 0; i < option.fields.length; i++) {
const field = option.fields[i]
const type = field.type ?? "string"
if (!ValidatedTextField.ForType(type) !== undefined) {
continue
}
const err = `Invalid filter: ${type} is not a valid validated textfield type (at ${context}.fields[${i}])\n\tTry one of ${Array.from(
ValidatedTextField.AvailableTypes()
).join(",")}`
errors.push(err)
}
}
return { result: filter, errors }
}
}
export class DetectDuplicateFilters extends DesugaringStep<{
layers: LayerConfigJson[]
themes: LayoutConfigJson[]

View file

@ -3,7 +3,6 @@ import { TagsFilter } from "../../Logic/Tags/TagsFilter"
import FilterConfigJson from "./Json/FilterConfigJson"
import Translations from "../../UI/i18n/Translations"
import { TagUtils } from "../../Logic/Tags/TagUtils"
import ValidatedTextField from "../../UI/Input/ValidatedTextField"
import { TagConfigJson } from "./Json/TagConfigJson"
import { UIEventSource } from "../../Logic/UIEventSource"
import { FilterState } from "../FilteredLayer"
@ -54,11 +53,7 @@ export default class FilterConfig {
const fields: { name: string; type: string }[] = (option.fields ?? []).map((f, i) => {
const type = f.type ?? "string"
if (!ValidatedTextField.ForType(type) === undefined) {
throw `Invalid filter: ${type} is not a valid validated textfield type (at ${ctx}.fields[${i}])\n\tTry one of ${Array.from(
ValidatedTextField.AvailableTypes()
).join(",")}`
}
// Type is validated against 'ValidatedTextField' in Validation.ts, in ValidateFilterConfig
if (f.name === undefined || f.name === "" || f.name.match(/[a-z0-9_-]+/) == null) {
throw `Invalid filter: a variable name should match [a-z0-9_-]+ at ${ctx}.fields[${i}]`
}

View file

@ -40,8 +40,9 @@ export interface LayerConfigJson {
*
* Every source _must_ define which tags _must_ be present in order to be picked up.
*
* Note: a source must always be defined. 'special' is only allowed if this is a builtin-layer
*/
source: {
source: "special" | "special:library" | ({
/**
* Every source must set which tags have to be present in order to load the given layer.
*/
@ -102,7 +103,7 @@ export interface LayerConfigJson {
* Setting this key will rename this field into 'id'
*/
idKey?: string
}
})
)
/**

View file

@ -12,8 +12,11 @@ import { TagConfigJson } from "./TagConfigJson"
export default interface PointRenderingConfigJson {
/**
* All the locations that this point should be rendered at.
* Using `location: ["point", "centroid"] will always render centerpoint.
* 'projected_centerpoint' will show an item on the line itself, near the middle of the line. (LineStrings only)
* Possible values are:
* - `point`: only renders points at their location
* - `centroid`: show a symbol at the centerpoint of a (multi)Linestring and (multi)polygon. Points will _not_ be rendered with this
* - `projected_centerpoint`: Only on (multi)linestrings: calculate the centerpoint and snap it to the way
* - `start` and `end`: only on linestrings: add a point to the first/last coordinate of the LineString
*/
location: ("point" | "centroid" | "start" | "end" | "projected_centerpoint" | string)[]

View file

@ -29,7 +29,7 @@ import { Overpass } from "../../Logic/Osm/Overpass"
import Constants from "../Constants"
import { FixedUiElement } from "../../UI/Base/FixedUiElement"
import Svg from "../../Svg"
import { UIEventSource } from "../../Logic/UIEventSource"
import { ImmutableStore } from "../../Logic/UIEventSource"
import { OsmTags } from "../OsmFeature"
export default class LayerConfig extends WithContextLoader {
@ -37,7 +37,10 @@ export default class LayerConfig extends WithContextLoader {
public readonly id: string
public readonly name: Translation
public readonly description: Translation
public readonly source: SourceConfig
/**
* Only 'null' for special, privileged layers
*/
public readonly source: SourceConfig | null
public readonly calculatedTags: [string, string, boolean][]
public readonly doNotDownload: boolean
public readonly passAllFeatures: boolean
@ -83,7 +86,9 @@ export default class LayerConfig extends WithContextLoader {
throw "Layer " + this.id + " does not define a source section (" + context + ")"
}
if (json.source.osmTags === undefined) {
if(json.source === "special" || json.source === "special:library"){
this.source = null
}else if (json.source.osmTags === undefined) {
throw (
"Layer " +
this.id +
@ -584,11 +589,9 @@ export default class LayerConfig extends WithContextLoader {
.filter((mr) => mr.location.has("point"))
.map(
(mr) =>
mr.GenerateLeafletStyle(
new UIEventSource<OsmTags>({ id: "node/-1" }),
false,
{ includeBadges: false }
).html
mr.RenderIcon(new ImmutableStore<OsmTags>({ id: "node/-1" }), false, {
includeBadges: false,
}).html
)
.find((i) => i !== undefined)
}

View file

@ -8,7 +8,6 @@ import { ExtractImages } from "./Conversion/FixImages"
import ExtraLinkConfig from "./ExtraLinkConfig"
import { Utils } from "../../Utils"
import LanguageUtils from "../../Utils/LanguageUtils"
/**
* Minimal information about a theme
**/

View file

@ -175,7 +175,7 @@ export default class PointRenderingConfig extends WithContextLoader {
)
}
public GenerateLeafletStyle(
public RenderIcon(
tags: Store<OsmTags>,
clickable: boolean,
options?: {
@ -210,7 +210,7 @@ export default class PointRenderingConfig extends WithContextLoader {
// in MapLibre, the offset is relative to the _center_ of the object, with left = [-x, 0] and up = [0,-y]
let anchorW = 0
let anchorH = iconH / 2
let anchorH = 0
if (mode === "left") {
anchorW = -iconW / 2
}

View file

@ -3,7 +3,6 @@ import { TagsFilter } from "../../Logic/Tags/TagsFilter"
import Translations from "../../UI/i18n/Translations"
import { TagUtils, UploadableTag } from "../../Logic/Tags/TagUtils"
import { And } from "../../Logic/Tags/And"
import ValidatedTextField from "../../UI/Input/ValidatedTextField"
import { Utils } from "../../Utils"
import { Tag } from "../../Logic/Tags/Tag"
import BaseUIElement from "../../UI/BaseUIElement"
@ -132,17 +131,6 @@ export default class TagRenderingConfig {
}
const type = json.freeform.type ?? "string"
if (ValidatedTextField.AvailableTypes().indexOf(type) < 0) {
throw (
"At " +
context +
".freeform.type is an unknown type: " +
type +
"; try one of " +
ValidatedTextField.AvailableTypes().join(", ")
)
}
let placeholder: Translation = Translations.T(json.freeform.placeholder)
if (placeholder === undefined) {
const typeDescription = <Translation>Translations.t.validation[type]?.description
@ -182,13 +170,7 @@ export default class TagRenderingConfig {
}
}
if (
this.freeform.type !== undefined &&
ValidatedTextField.AvailableTypes().indexOf(this.freeform.type) < 0
) {
const knownKeys = ValidatedTextField.AvailableTypes().join(", ")
throw `Freeform.key ${this.freeform.key} is an invalid type. Known keys are ${knownKeys}`
}
// freeform.type is validated in Validation.ts so that we don't need ValidatedTextFields here
if (this.freeform.addExtraTags) {
const usedKeys = new And(this.freeform.addExtraTags).usedKeys()
if (usedKeys.indexOf(this.freeform.key) >= 0) {