forked from MapComplete/MapComplete
Fix bug: override preserves null's again
This commit is contained in:
parent
2f4ccae39e
commit
b43d976058
6 changed files with 205 additions and 87 deletions
|
@ -38,16 +38,43 @@ export class AddContextToTranslations<T> extends DesugaringStep<T> {
|
||||||
* ]
|
* ]
|
||||||
* }
|
* }
|
||||||
* rewritten // => expected
|
* rewritten // => expected
|
||||||
|
*
|
||||||
|
* // should preserve nulls
|
||||||
|
* const theme = {
|
||||||
|
* layers: [
|
||||||
|
* {
|
||||||
|
* builtin: ["abc"],
|
||||||
|
* override: {
|
||||||
|
* name:null
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ]
|
||||||
|
* }
|
||||||
|
* const rewritten = new AddContextToTranslations<any>("prefix:").convert(theme, "context").result
|
||||||
|
* const expected = {
|
||||||
|
* layers: [
|
||||||
|
* {
|
||||||
|
* builtin: ["abc"],
|
||||||
|
* override: {
|
||||||
|
* name: null
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ]
|
||||||
|
* }
|
||||||
|
* rewritten // => expected
|
||||||
*/
|
*/
|
||||||
convert(json: T, context: string): { result: T; errors?: string[]; warnings?: string[]; information?: string[] } {
|
convert(json: T, context: string): { result: T; errors?: string[]; warnings?: string[]; information?: string[] } {
|
||||||
|
|
||||||
const result = Utils.WalkJson(json, (leaf, path) => {
|
const result = Utils.WalkJson(json, (leaf, path) => {
|
||||||
|
if(leaf === undefined || leaf === null){
|
||||||
|
return leaf
|
||||||
|
}
|
||||||
if (typeof leaf === "object") {
|
if (typeof leaf === "object") {
|
||||||
return {...leaf, _context: this._prefix + context + "." + path.join(".")}
|
return {...leaf, _context: this._prefix + context + "." + path.join(".")}
|
||||||
} else {
|
} else {
|
||||||
return leaf
|
return leaf
|
||||||
}
|
}
|
||||||
}, obj => obj !== undefined && obj !== null && Translations.isProbablyATranslation(obj))
|
}, obj => obj === undefined || obj === null || Translations.isProbablyATranslation(obj))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
result
|
result
|
||||||
|
|
|
@ -158,6 +158,20 @@ export class On<P, T> extends DesugaringStep<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class Pass<T> extends Conversion<T, T> {
|
||||||
|
constructor(message?: string) {
|
||||||
|
super(message??"Does nothing, often to swap out steps in testing", [], "Pass");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
convert(json: T, context: string): { result: T; errors?: string[]; warnings?: string[]; information?: string[] } {
|
||||||
|
return {
|
||||||
|
result: json
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export class Concat<X, T> extends Conversion<X[], T[]> {
|
export class Concat<X, T> extends Conversion<X[], T[]> {
|
||||||
private readonly _step: Conversion<X, T[]>;
|
private readonly _step: Conversion<X, T[]>;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {Concat, Conversion, DesugaringContext, DesugaringStep, Each, Fuse, On, SetDefault} from "./Conversion";
|
import {Concat, Conversion, DesugaringContext, DesugaringStep, Each, Fuse, On, Pass, SetDefault} from "./Conversion";
|
||||||
import {LayoutConfigJson} from "../Json/LayoutConfigJson";
|
import {LayoutConfigJson} from "../Json/LayoutConfigJson";
|
||||||
import {PrepareLayer} from "./PrepareLayer";
|
import {PrepareLayer} from "./PrepareLayer";
|
||||||
import {LayerConfigJson} from "../Json/LayerConfigJson";
|
import {LayerConfigJson} from "../Json/LayerConfigJson";
|
||||||
|
@ -13,23 +13,25 @@ import {AddContextToTranslations} from "./AddContextToTranslations";
|
||||||
|
|
||||||
class SubstituteLayer extends Conversion<(string | LayerConfigJson), LayerConfigJson[]> {
|
class SubstituteLayer extends Conversion<(string | LayerConfigJson), LayerConfigJson[]> {
|
||||||
private readonly _state: DesugaringContext;
|
private readonly _state: DesugaringContext;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
state: DesugaringContext,
|
state: DesugaringContext,
|
||||||
) {
|
) {
|
||||||
super("Converts the identifier of a builtin layer into the actual layer, or converts a 'builtin' syntax with override in the fully expanded form", [],"SubstituteLayer");
|
super("Converts the identifier of a builtin layer into the actual layer, or converts a 'builtin' syntax with override in the fully expanded form", [], "SubstituteLayer");
|
||||||
this._state = state;
|
this._state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: string | LayerConfigJson, context: string): { result: LayerConfigJson[]; errors: string[], information?: string[] } {
|
convert(json: string | LayerConfigJson, context: string): { result: LayerConfigJson[]; errors: string[], information?: string[] } {
|
||||||
const errors = []
|
const errors = []
|
||||||
const information = []
|
const information = []
|
||||||
const state= this._state
|
const state = this._state
|
||||||
function reportNotFound(name: string){
|
|
||||||
|
function reportNotFound(name: string) {
|
||||||
const knownLayers = Array.from(state.sharedLayers.keys())
|
const knownLayers = Array.from(state.sharedLayers.keys())
|
||||||
const withDistance = knownLayers.map(lname => [lname, Utils.levenshteinDistance(name, lname)])
|
const withDistance = knownLayers.map(lname => [lname, Utils.levenshteinDistance(name, lname)])
|
||||||
withDistance.sort((a, b) => a[1] - b[1])
|
withDistance.sort((a, b) => a[1] - b[1])
|
||||||
const ids = withDistance.map(n => n[0])
|
const ids = withDistance.map(n => n[0])
|
||||||
// Known builtin layers are "+.join(",")+"\n For more information, see "
|
// Known builtin layers are "+.join(",")+"\n For more information, see "
|
||||||
errors.push(`${context}: The layer with name ${name} was not found as a builtin layer. Perhaps you meant ${ids[0]}, ${ids[1]} or ${ids[2]}?
|
errors.push(`${context}: The layer with name ${name} was not found as a builtin layer. Perhaps you meant ${ids[0]}, ${ids[1]} or ${ids[2]}?
|
||||||
For an overview of all available layers, refer to https://github.com/pietervdvn/MapComplete/blob/develop/Docs/BuiltinLayers.md`)
|
For an overview of all available layers, refer to https://github.com/pietervdvn/MapComplete/blob/develop/Docs/BuiltinLayers.md`)
|
||||||
}
|
}
|
||||||
|
@ -73,39 +75,39 @@ class SubstituteLayer extends Conversion<(string | LayerConfigJson), LayerConfig
|
||||||
errors.push(`At ${context}: could not apply an override due to: ${e}.\nThe override is: ${JSON.stringify(json["override"],)}`)
|
errors.push(`At ${context}: could not apply an override due to: ${e}.\nThe override is: ${JSON.stringify(json["override"],)}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(json["hideTagRenderingsWithLabels"]){
|
if (json["hideTagRenderingsWithLabels"]) {
|
||||||
const hideLabels: Set<string> = new Set(json["hideTagRenderingsWithLabels"])
|
const hideLabels: Set<string> = new Set(json["hideTagRenderingsWithLabels"])
|
||||||
// These labels caused at least one deletion
|
// These labels caused at least one deletion
|
||||||
const usedLabels : Set<string> = new Set<string>();
|
const usedLabels: Set<string> = new Set<string>();
|
||||||
const filtered = []
|
const filtered = []
|
||||||
for (const tr of found.tagRenderings) {
|
for (const tr of found.tagRenderings) {
|
||||||
const labels = tr["labels"]
|
const labels = tr["labels"]
|
||||||
if(labels !== undefined){
|
if (labels !== undefined) {
|
||||||
const forbiddenLabel = labels.findIndex(l => hideLabels.has(l))
|
const forbiddenLabel = labels.findIndex(l => hideLabels.has(l))
|
||||||
if(forbiddenLabel >= 0){
|
if (forbiddenLabel >= 0) {
|
||||||
usedLabels.add(labels[forbiddenLabel])
|
usedLabels.add(labels[forbiddenLabel])
|
||||||
information.push(context+": Dropping tagRendering "+tr["id"]+" as it has a forbidden label: "+labels[forbiddenLabel])
|
information.push(context + ": Dropping tagRendering " + tr["id"] + " as it has a forbidden label: " + labels[forbiddenLabel])
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(hideLabels.has(tr["id"])){
|
if (hideLabels.has(tr["id"])) {
|
||||||
usedLabels.add(tr["id"])
|
usedLabels.add(tr["id"])
|
||||||
information.push(context+": Dropping tagRendering "+tr["id"]+" as its id is a forbidden label")
|
information.push(context + ": Dropping tagRendering " + tr["id"] + " as its id is a forbidden label")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if(hideLabels.has(tr["group"])){
|
if (hideLabels.has(tr["group"])) {
|
||||||
usedLabels.add(tr["group"])
|
usedLabels.add(tr["group"])
|
||||||
information.push(context+": Dropping tagRendering "+tr["id"]+" as its group `"+tr["group"]+"` is a forbidden label")
|
information.push(context + ": Dropping tagRendering " + tr["id"] + " as its group `" + tr["group"] + "` is a forbidden label")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
filtered.push(tr)
|
filtered.push(tr)
|
||||||
}
|
}
|
||||||
const unused = Array.from(hideLabels).filter(l => !usedLabels.has(l))
|
const unused = Array.from(hideLabels).filter(l => !usedLabels.has(l))
|
||||||
if(unused.length > 0){
|
if (unused.length > 0) {
|
||||||
errors.push("This theme specifies that certain tagrenderings have to be removed based on forbidden layers. One or more of these layers did not match any tagRenderings and caused no deletions: "+unused.join(", ")+"\n This means that this label can be removed or that the original tagRendering that should be deleted does not have this label anymore")
|
errors.push("This theme specifies that certain tagrenderings have to be removed based on forbidden layers. One or more of these layers did not match any tagRenderings and caused no deletions: " + unused.join(", ") + "\n This means that this label can be removed or that the original tagRendering that should be deleted does not have this label anymore")
|
||||||
}
|
}
|
||||||
found.tagRenderings = filtered
|
found.tagRenderings = filtered
|
||||||
}
|
}
|
||||||
|
@ -130,7 +132,7 @@ class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> {
|
||||||
private _state: DesugaringContext;
|
private _state: DesugaringContext;
|
||||||
|
|
||||||
constructor(state: DesugaringContext) {
|
constructor(state: DesugaringContext) {
|
||||||
super("Adds the default layers, namely: " + Constants.added_by_default.join(", "), ["layers"],"AddDefaultLayers");
|
super("Adds the default layers, namely: " + Constants.added_by_default.join(", "), ["layers"], "AddDefaultLayers");
|
||||||
this._state = state;
|
this._state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,8 +149,8 @@ class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> {
|
||||||
errors.push("Default layer " + layerName + " not found")
|
errors.push("Default layer " + layerName + " not found")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if(alreadyLoaded.has(v.id)){
|
if (alreadyLoaded.has(v.id)) {
|
||||||
warnings.push("Layout "+context+" already has a layer with name "+v.id+"; skipping inclusion of this builtin layer")
|
warnings.push("Layout " + context + " already has a layer with name " + v.id + "; skipping inclusion of this builtin layer")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
json.layers.push(v)
|
json.layers.push(v)
|
||||||
|
@ -165,7 +167,7 @@ class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> {
|
||||||
|
|
||||||
class AddImportLayers extends DesugaringStep<LayoutConfigJson> {
|
class AddImportLayers extends DesugaringStep<LayoutConfigJson> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("For every layer in the 'layers'-list, create a new layer which'll import notes. (Note that priviliged layers and layers which have a geojson-source set are ignored)", ["layers"],"AddImportLayers");
|
super("For every layer in the 'layers'-list, create a new layer which'll import notes. (Note that priviliged layers and layers which have a geojson-source set are ignored)", ["layers"], "AddImportLayers");
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: LayoutConfigJson, context: string): { result: LayoutConfigJson; errors: string[] } {
|
convert(json: LayoutConfigJson, context: string): { result: LayoutConfigJson; errors: string[] } {
|
||||||
|
@ -176,7 +178,7 @@ class AddImportLayers extends DesugaringStep<LayoutConfigJson> {
|
||||||
json.layers = [...json.layers]
|
json.layers = [...json.layers]
|
||||||
|
|
||||||
|
|
||||||
if(json.enableNoteImports ?? true) {
|
if (json.enableNoteImports ?? true) {
|
||||||
const creator = new CreateNoteImportLayer()
|
const creator = new CreateNoteImportLayer()
|
||||||
for (let i1 = 0; i1 < allLayers.length; i1++) {
|
for (let i1 = 0; i1 < allLayers.length; i1++) {
|
||||||
const layer = allLayers[i1];
|
const layer = allLayers[i1];
|
||||||
|
@ -222,8 +224,9 @@ class AddImportLayers extends DesugaringStep<LayoutConfigJson> {
|
||||||
|
|
||||||
export class AddMiniMap extends DesugaringStep<LayerConfigJson> {
|
export class AddMiniMap extends DesugaringStep<LayerConfigJson> {
|
||||||
private readonly _state: DesugaringContext;
|
private readonly _state: DesugaringContext;
|
||||||
constructor(state: DesugaringContext, ) {
|
|
||||||
super("Adds a default 'minimap'-element to the tagrenderings if none of the elements define such a minimap", ["tagRenderings"],"AddMiniMap");
|
constructor(state: DesugaringContext,) {
|
||||||
|
super("Adds a default 'minimap'-element to the tagrenderings if none of the elements define such a minimap", ["tagRenderings"], "AddMiniMap");
|
||||||
this._state = state;
|
this._state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,10 +283,10 @@ export class AddMiniMap extends DesugaringStep<LayerConfigJson> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AddContextToTransltionsInLayout extends DesugaringStep <LayoutConfigJson>{
|
class AddContextToTransltionsInLayout extends DesugaringStep <LayoutConfigJson> {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super("Adds context to translations, including the prefix 'themes:json.id'; this is to make sure terms in an 'overrides' or inline layer are linkable too",["_context"], "AddContextToTranlationsInLayout");
|
super("Adds context to translations, including the prefix 'themes:json.id'; this is to make sure terms in an 'overrides' or inline layer are linkable too", ["_context"], "AddContextToTranlationsInLayout");
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: LayoutConfigJson, context: string): { result: LayoutConfigJson; errors?: string[]; warnings?: string[]; information?: string[] } {
|
convert(json: LayoutConfigJson, context: string): { result: LayoutConfigJson; errors?: string[]; warnings?: string[]; information?: string[] } {
|
||||||
|
@ -296,7 +299,7 @@ class AddContextToTransltionsInLayout extends DesugaringStep <LayoutConfigJson>{
|
||||||
class ApplyOverrideAll extends DesugaringStep<LayoutConfigJson> {
|
class ApplyOverrideAll extends DesugaringStep<LayoutConfigJson> {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super("Applies 'overrideAll' onto every 'layer'. The 'overrideAll'-field is removed afterwards", ["overrideAll", "layers"],"ApplyOverrideAll");
|
super("Applies 'overrideAll' onto every 'layer'. The 'overrideAll'-field is removed afterwards", ["overrideAll", "layers"], "ApplyOverrideAll");
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: LayoutConfigJson, context: string): { result: LayoutConfigJson; errors: string[]; warnings: string[] } {
|
convert(json: LayoutConfigJson, context: string): { result: LayoutConfigJson; errors: string[]; warnings: string[] } {
|
||||||
|
@ -325,8 +328,9 @@ class ApplyOverrideAll extends DesugaringStep<LayoutConfigJson> {
|
||||||
|
|
||||||
class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
|
class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
private readonly _state: DesugaringContext;
|
private readonly _state: DesugaringContext;
|
||||||
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)", ["layers"],"AddDependencyLayersToTheme");
|
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)", ["layers"], "AddDependencyLayersToTheme");
|
||||||
this._state = state;
|
this._state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,17 +344,17 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
const dependencies: { neededLayer: string, reason: string, context?: string, neededBy: string }[] = []
|
const dependencies: { neededLayer: string, reason: string, context?: string, neededBy: string }[] = []
|
||||||
|
|
||||||
for (const layerConfig of alreadyLoaded) {
|
for (const layerConfig of alreadyLoaded) {
|
||||||
try{
|
try {
|
||||||
const layerDeps = DependencyCalculator.getLayerDependencies(new LayerConfig(layerConfig))
|
const layerDeps = DependencyCalculator.getLayerDependencies(new LayerConfig(layerConfig))
|
||||||
dependencies.push(...layerDeps)
|
dependencies.push(...layerDeps)
|
||||||
}catch(e){
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
throw "Detecting layer dependencies for "+layerConfig.id+" failed due to "+e
|
throw "Detecting layer dependencies for " + layerConfig.id + " failed due to " + e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const dependency of dependencies) {
|
for (const dependency of dependencies) {
|
||||||
if(loadedLayerIds.has(dependency.neededLayer)){
|
if (loadedLayerIds.has(dependency.neededLayer)) {
|
||||||
// We mark the needed layer as 'mustLoad'
|
// We mark the needed layer as 'mustLoad'
|
||||||
alreadyLoaded.find(l => l.id === dependency.neededLayer).forceLoad = true
|
alreadyLoaded.find(l => l.id === dependency.neededLayer).forceLoad = true
|
||||||
}
|
}
|
||||||
|
@ -418,13 +422,14 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
|
|
||||||
class PreparePersonalTheme extends DesugaringStep<LayoutConfigJson> {
|
class PreparePersonalTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
private readonly _state: DesugaringContext;
|
private readonly _state: DesugaringContext;
|
||||||
|
|
||||||
constructor(state: DesugaringContext) {
|
constructor(state: DesugaringContext) {
|
||||||
super("Adds every public layer to the personal theme",["layers"],"PreparePersonalTheme");
|
super("Adds every public layer to the personal theme", ["layers"], "PreparePersonalTheme");
|
||||||
this._state = state;
|
this._state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: LayoutConfigJson, context: string): { result: LayoutConfigJson; errors?: string[]; warnings?: string[]; information?: string[] } {
|
convert(json: LayoutConfigJson, context: string): { result: LayoutConfigJson; errors?: string[]; warnings?: string[]; information?: string[] } {
|
||||||
if(json.id !== "personal"){
|
if (json.id !== "personal") {
|
||||||
return {result: json}
|
return {result: json}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,30 +439,30 @@ class PreparePersonalTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>{
|
class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson> {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super("Generates a warning if a theme uses an unsubstituted layer", ["layers"],"WarnForUnsubstitutedLayersInTheme");
|
super("Generates a warning if a theme uses an unsubstituted layer", ["layers"], "WarnForUnsubstitutedLayersInTheme");
|
||||||
}
|
}
|
||||||
|
|
||||||
convert(json: LayoutConfigJson, context: string): { result: LayoutConfigJson; errors?: string[]; warnings?: string[]; information?: string[] } {
|
convert(json: LayoutConfigJson, context: string): { result: LayoutConfigJson; errors?: string[]; warnings?: string[]; information?: string[] } {
|
||||||
if(json.hideFromOverview === true){
|
if (json.hideFromOverview === true) {
|
||||||
return {result: json}
|
return {result: json}
|
||||||
}
|
}
|
||||||
const warnings = []
|
const warnings = []
|
||||||
for (const layer of json.layers) {
|
for (const layer of json.layers) {
|
||||||
if(typeof layer === "string"){
|
if (typeof layer === "string") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if(layer["builtin"] !== undefined){
|
if (layer["builtin"] !== undefined) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if(layer["source"]["geojson"] !== undefined){
|
if (layer["source"]["geojson"] !== undefined) {
|
||||||
// We turn a blind eye for import layers
|
// We turn a blind eye for import layers
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
const wrn = "The theme "+json.id+" has an inline layer: "+layer["id"]+". This is discouraged."
|
const wrn = "The theme " + json.id + " has an inline layer: " + layer["id"] + ". This is discouraged."
|
||||||
warnings.push(wrn)
|
warnings.push(wrn)
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
@ -469,7 +474,9 @@ class WarnForUnsubstitutedLayersInTheme extends DesugaringStep<LayoutConfigJson>
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PrepareTheme extends Fuse<LayoutConfigJson> {
|
export class PrepareTheme extends Fuse<LayoutConfigJson> {
|
||||||
constructor(state: DesugaringContext) {
|
constructor(state: DesugaringContext, options?: {
|
||||||
|
skipDefaultLayers: false | boolean
|
||||||
|
}) {
|
||||||
super(
|
super(
|
||||||
"Fully prepares and expands a theme",
|
"Fully prepares and expands a theme",
|
||||||
new AddContextToTransltionsInLayout(),
|
new AddContextToTransltionsInLayout(),
|
||||||
|
@ -483,7 +490,7 @@ export class PrepareTheme extends Fuse<LayoutConfigJson> {
|
||||||
new ApplyOverrideAll(),
|
new ApplyOverrideAll(),
|
||||||
// And then we prepare all the layers _again_ in case that an override all contained unexpanded tagrenderings!
|
// And then we prepare all the layers _again_ in case that an override all contained unexpanded tagrenderings!
|
||||||
new On("layers", new Each(new PrepareLayer(state))),
|
new On("layers", new Each(new PrepareLayer(state))),
|
||||||
new AddDefaultLayers(state),
|
options?.skipDefaultLayers ? new Pass("AddDefaultLayers is disabled due to the set flag") : new AddDefaultLayers(state),
|
||||||
new AddDependencyLayersToTheme(state),
|
new AddDependencyLayersToTheme(state),
|
||||||
new AddImportLayers(),
|
new AddImportLayers(),
|
||||||
new On("layers", new Each(new AddMiniMap(state)))
|
new On("layers", new Each(new AddMiniMap(state)))
|
||||||
|
|
28
Utils.ts
28
Utils.ts
|
@ -518,11 +518,35 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
||||||
* Apply a function on every leaf of the JSON; used to rewrite parts of the JSON.
|
* Apply a function on every leaf of the JSON; used to rewrite parts of the JSON.
|
||||||
* Returns a modified copy of the original object.
|
* Returns a modified copy of the original object.
|
||||||
*
|
*
|
||||||
|
* 'null' and 'undefined' are _always_ considered a leaf, even if 'isLeaf' says it isn't
|
||||||
|
*
|
||||||
* Hangs if the object contains a loop
|
* Hangs if the object contains a loop
|
||||||
|
*
|
||||||
|
* // should walk a json
|
||||||
|
* const walked = Utils.WalkJson({
|
||||||
|
* key: "value"
|
||||||
|
* }, (x: string) => x + "!")
|
||||||
|
* walked // => {key: "value!"}
|
||||||
|
*
|
||||||
|
* // should preserve undefined and null:
|
||||||
|
* const walked = Utils.WalkJson({
|
||||||
|
* u: undefined,
|
||||||
|
* n: null,
|
||||||
|
* v: "value"
|
||||||
|
* }, (x) => {if(x !== undefined && x !== null){return x+"!}; return x})
|
||||||
|
* walked // => {v: "value!", u: undefined, n: null}
|
||||||
|
*
|
||||||
|
* // should preserve undefined and null, also with a negative isLeaf:
|
||||||
|
* const walked = Utils.WalkJson({
|
||||||
|
* u: undefined,
|
||||||
|
* n: null,
|
||||||
|
* v: "value"
|
||||||
|
* }, (x) => return x}, _ => false)
|
||||||
|
* walked // => {v: "value", u: undefined, n: null}
|
||||||
*/
|
*/
|
||||||
static WalkJson(json: any, f: (v: object | number | string | boolean | undefined, path: string[]) => any, isLeaf: (object) => boolean = undefined, path: string[] = []) {
|
static WalkJson(json: any, f: (v: object | number | string | boolean | undefined, path: string[]) => any, isLeaf: (object) => boolean = undefined, path: string[] = []) {
|
||||||
if (json === undefined) {
|
if (json === undefined || json === null) {
|
||||||
return f(undefined, path)
|
return f(json, path)
|
||||||
}
|
}
|
||||||
const jtp = typeof json
|
const jtp = typeof json
|
||||||
if (isLeaf !== undefined) {
|
if (isLeaf !== undefined) {
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
{
|
{
|
||||||
"id": "mapcomplete-changes",
|
"id": "mapcomplete-changes",
|
||||||
"title": {
|
"title": {
|
||||||
"en": "Changes made with MapComplete",
|
"en": "Changes made with MapComplete"
|
||||||
"de": "Änderungen mit MapComplete"
|
|
||||||
},
|
},
|
||||||
"shortDescription": {
|
"shortDescription": {
|
||||||
"en": "Shows changes made by MapComplete",
|
"en": "Shows changes made by MapComplete"
|
||||||
"de": "Zeigt Änderungen von MapComplete"
|
|
||||||
},
|
},
|
||||||
"description": {
|
"description": {
|
||||||
"en": "This maps shows all the changes made with MapComplete",
|
"en": "This maps shows all the changes made with MapComplete"
|
||||||
"de": "Diese Karte zeigt alle Änderungen die mit MapComplete gemacht wurden"
|
|
||||||
},
|
},
|
||||||
"maintainer": "",
|
"maintainer": "",
|
||||||
"icon": "./assets/svg/logo.svg",
|
"icon": "./assets/svg/logo.svg",
|
||||||
|
@ -39,27 +36,23 @@
|
||||||
],
|
],
|
||||||
"title": {
|
"title": {
|
||||||
"render": {
|
"render": {
|
||||||
"en": "Changeset for {theme}",
|
"en": "Changeset for {theme}"
|
||||||
"de": "Änderungen für {theme}"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": {
|
"description": {
|
||||||
"en": "Shows all MapComplete changes",
|
"en": "Shows all MapComplete changes"
|
||||||
"de": "Zeigt alle MapComplete Änderungen"
|
|
||||||
},
|
},
|
||||||
"tagRenderings": [
|
"tagRenderings": [
|
||||||
{
|
{
|
||||||
"id": "render_id",
|
"id": "render_id",
|
||||||
"render": {
|
"render": {
|
||||||
"en": "Changeset <a href='https://openstreetmap.org/changeset/{id}' target='_blank'>{id}</a>",
|
"en": "Changeset <a href='https://openstreetmap.org/changeset/{id}' target='_blank'>{id}</a>"
|
||||||
"de": "Änderung <a href='https://openstreetmap.org/changeset/{id}' target='_blank'>{id}</a>"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "contributor",
|
"id": "contributor",
|
||||||
"render": {
|
"render": {
|
||||||
"en": "Change made by <a href='https://openstreetmap.org/user/{_last_edit:contributor}' target='_blank'>{_last_edit:contributor}</a>",
|
"en": "Change made by <a href='https://openstreetmap.org/user/{_last_edit:contributor}' target='_blank'>{_last_edit:contributor}</a>"
|
||||||
"de": "Änderung wurde von <a href='https://openstreetmap.org/user/{_last_edit:contributor}' target='_blank'>{_last_edit:contributor}</a> gemacht"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -335,8 +328,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"question": {
|
"question": {
|
||||||
"en": "Themename contains {search}",
|
"en": "Themename contains {search}"
|
||||||
"de": "Themenname enthält {search}"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -352,8 +344,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"question": {
|
"question": {
|
||||||
"en": "Made by contributor {search}",
|
"en": "Made by contributor {search}"
|
||||||
"de": "Erstellt von {search}"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -369,8 +360,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"question": {
|
"question": {
|
||||||
"en": "<b>Not</b> made by contributor {search}",
|
"en": "<b>Not</b> made by contributor {search}"
|
||||||
"de": "<b>Nicht</b> erstellt von {search}"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -385,8 +375,7 @@
|
||||||
{
|
{
|
||||||
"id": "link_to_more",
|
"id": "link_to_more",
|
||||||
"render": {
|
"render": {
|
||||||
"en": "More statistics can be found <a href='https://github.com/pietervdvn/MapComplete/tree/develop/Docs/Tools/graphs' target='_blank'>here</a>",
|
"en": "More statistics can be found <a href='https://github.com/pietervdvn/MapComplete/tree/develop/Docs/Tools/graphs' target='_blank'>here</a>"
|
||||||
"de": "Weitere Statistiken finden Sie <a href='https://github.com/pietervdvn/MapComplete/tree/develop/Docs/Tools/graphs' target='_blank'>hier</a>"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,6 +10,7 @@ import LayerConfig from "../../../../Models/ThemeConfig/LayerConfig";
|
||||||
import {ExtractImages} from "../../../../Models/ThemeConfig/Conversion/FixImages";
|
import {ExtractImages} from "../../../../Models/ThemeConfig/Conversion/FixImages";
|
||||||
import * as cyclofix from "../../../../assets/generated/themes/cyclofix.json"
|
import * as cyclofix from "../../../../assets/generated/themes/cyclofix.json"
|
||||||
import {Tag} from "../../../../Logic/Tags/Tag";
|
import {Tag} from "../../../../Logic/Tags/Tag";
|
||||||
|
import {DesugaringContext} from "../../../../Models/ThemeConfig/Conversion/Conversion";
|
||||||
|
|
||||||
|
|
||||||
const themeConfigJson: LayoutConfigJson = {
|
const themeConfigJson: LayoutConfigJson = {
|
||||||
|
@ -69,7 +70,6 @@ describe("PrepareTheme", () => {
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
it("should apply override", () => {
|
it("should apply override", () => {
|
||||||
|
|
||||||
const sharedLayers = new Map<string, LayerConfigJson>()
|
const sharedLayers = new Map<string, LayerConfigJson>()
|
||||||
|
@ -82,8 +82,65 @@ describe("PrepareTheme", () => {
|
||||||
const layerUnderTest = <LayerConfig> themeConfig.layers.find(l => l.id === "public_bookcase")
|
const layerUnderTest = <LayerConfig> themeConfig.layers.find(l => l.id === "public_bookcase")
|
||||||
expect(layerUnderTest.source.geojsonSource).eq("https://example.com/data.geojson")
|
expect(layerUnderTest.source.geojsonSource).eq("https://example.com/data.geojson")
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
|
it("should remove names which are overriden with null", () => {
|
||||||
|
const testLayer: LayerConfigJson = {
|
||||||
|
source: {
|
||||||
|
osmTags: "x=y"
|
||||||
|
},
|
||||||
|
id: "layer-example",
|
||||||
|
name: {
|
||||||
|
en: "Test layer - please ignore"
|
||||||
|
},
|
||||||
|
titleIcons : [],
|
||||||
|
mapRendering: null
|
||||||
|
}
|
||||||
|
const ctx: DesugaringContext = {
|
||||||
|
sharedLayers: new Map<string, LayerConfigJson>([[
|
||||||
|
"layer-example", testLayer
|
||||||
|
]]),
|
||||||
|
tagRenderings: new Map<string, TagRenderingConfigJson>()
|
||||||
|
|
||||||
|
}
|
||||||
|
const layout : LayoutConfigJson=
|
||||||
|
{
|
||||||
|
description: "A testing theme",
|
||||||
|
icon: "",
|
||||||
|
id: "",
|
||||||
|
layers: [
|
||||||
|
"layer-example",
|
||||||
|
{
|
||||||
|
"builtin": "layer-example",
|
||||||
|
"override": {
|
||||||
|
"name": null,
|
||||||
|
"minzoom": 18
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
maintainer: "Me",
|
||||||
|
startLat: 0,
|
||||||
|
startLon: 0,
|
||||||
|
startZoom: 0,
|
||||||
|
title: "Test theme",
|
||||||
|
version: ""
|
||||||
|
|
||||||
|
}
|
||||||
|
const rewritten = new PrepareTheme(ctx, {
|
||||||
|
skipDefaultLayers: true
|
||||||
|
}).convertStrict(layout, "test")
|
||||||
|
expect(rewritten.layers[0]).deep.eq(testLayer)
|
||||||
|
expect(rewritten.layers[1]).deep.eq({
|
||||||
|
source: {
|
||||||
|
osmTags: "x=y"
|
||||||
|
},
|
||||||
|
id: "layer-example",
|
||||||
|
name:null,
|
||||||
|
minzoom: 18,
|
||||||
|
mapRendering: null,
|
||||||
|
titleIcons: []
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("ExtractImages", () => {
|
describe("ExtractImages", () => {
|
||||||
it("should find all images in a themefile", () => {
|
it("should find all images in a themefile", () => {
|
||||||
|
|
Loading…
Add table
Reference in a new issue