Refactoring: fix small errors, simplify 'sortedByLevehnstein'-function, improve error messgae

This commit is contained in:
Pieter Vander Vennet 2025-07-03 17:33:29 +02:00
parent 97b8202b14
commit 8a0023377a
13 changed files with 27 additions and 19 deletions

View file

@ -565,6 +565,10 @@
"if": "theme=rainbow_crossings", "if": "theme=rainbow_crossings",
"then": "./assets/themes/rainbow_crossings/logo.svg" "then": "./assets/themes/rainbow_crossings/logo.svg"
}, },
{
"if": "theme=sauna",
"then": "./assets/layers/sauna/sauna.svg"
},
{ {
"if": "theme=scouting", "if": "theme=scouting",
"then": "./assets/layers/scouting_group/scouting.svg" "then": "./assets/layers/scouting_group/scouting.svg"

View file

@ -108,8 +108,7 @@ export default class DetermineTheme {
if (themeInfo === undefined) { if (themeInfo === undefined) {
const alternatives = Utils.sortedByLevenshteinDistance( const alternatives = Utils.sortedByLevenshteinDistance(
id, id,
themes.map((th) => th.id), themes.map((th) => th.id)
(i) => i
).slice(0, 3) ).slice(0, 3)
const msg = `No builtin map theme with name ${layoutId} exists. Perhaps you meant one of ${alternatives.join( const msg = `No builtin map theme with name ${layoutId} exists. Perhaps you meant one of ${alternatives.join(
", " ", "

View file

@ -111,8 +111,7 @@ export class MenuState {
"No tagRendering with id '" + highlightTagRendering + "'; maybe you meant:", "No tagRendering with id '" + highlightTagRendering + "'; maybe you meant:",
Utils.sortedByLevenshteinDistance( Utils.sortedByLevenshteinDistance(
highlightTagRendering, highlightTagRendering,
UserRelatedState.availableUserSettingsIds, UserRelatedState.availableUserSettingsIds
(x) => x
) )
) )
} }

View file

@ -259,8 +259,7 @@ export class ExpandFilter extends DesugaringStep<LayerConfigJson> {
if (found === undefined) { if (found === undefined) {
const suggestions = Utils.sortedByLevenshteinDistance( const suggestions = Utils.sortedByLevenshteinDistance(
filter, filter,
Array.from(ExpandFilter.predefinedFilters.keys()), Array.from(ExpandFilter.predefinedFilters.keys())
(t) => t
) )
context context
.enter(filter) .enter(filter)

View file

@ -387,8 +387,7 @@ export class ExpandTagRendering extends Conversion<
if (layer === undefined) { if (layer === undefined) {
const candidates = Utils.sortedByLevenshteinDistance( const candidates = Utils.sortedByLevenshteinDistance(
layerName, layerName,
Utils.NoNull(Array.from(state.sharedLayers.keys())), Utils.NoNull(Array.from(state.sharedLayers.keys()))
(s) => s
) )
if (candidates.length === 0) { if (candidates.length === 0) {
ctx.err( ctx.err(
@ -419,7 +418,7 @@ export class ExpandTagRendering extends Conversion<
) )
} }
candidates = Utils.sortedByLevenshteinDistance(name, candidates, (i) => i) candidates = Utils.sortedByLevenshteinDistance(name, candidates)
ctx.err( ctx.err(
"The tagRendering with identifier " + "The tagRendering with identifier " +
name + name +

View file

@ -71,7 +71,8 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
for (const name of names) { for (const name of names) {
const found = Utils.Clone(state.sharedLayers.get(name)) const found = Utils.Clone(state.sharedLayers.get(name))
if (found === undefined) { if (found === undefined) {
context.err("Layer with name " + name + " not found") const nearbyNames = Utils.sortedByLevenshteinDistance(name, Array.from(state.sharedLayers.keys()))
context.err("Layer with name " + name + " not found. Dit you mean one of "+nearbyNames.slice(0, 3))
continue continue
} }
found["_basedOn"] = name found["_basedOn"] = name

View file

@ -167,7 +167,7 @@ export class ValidateTheme extends DesugaringStep<ThemeConfigJson> {
) )
const available = new Set(knownIds) const available = new Set(knownIds)
if (!isCategory && !available.has(backgroundId)) { if (!isCategory && !available.has(backgroundId)) {
const nearby = Utils.sortedByLevenshteinDistance(backgroundId, knownIds, (t) => t) const nearby = Utils.sortedByLevenshteinDistance(backgroundId, knownIds)
context context
.enter("defaultBackgroundId") .enter("defaultBackgroundId")
.err( .err(

View file

@ -65,8 +65,7 @@ export default class FilterConfig {
if (Validators.availableTypes.indexOf(type) < 0) { if (Validators.availableTypes.indexOf(type) < 0) {
throw `Invalid filter: type is not a valid validator. Did you mean one of ${Utils.sortedByLevenshteinDistance( throw `Invalid filter: type is not a valid validator. Did you mean one of ${Utils.sortedByLevenshteinDistance(
type, type,
<ReadonlyArray<string>>Validators.availableTypes, <ReadonlyArray<string>>Validators.availableTypes
(x) => x
).slice(0, 3)}` ).slice(0, 3)}`
} }
// Type is validated against 'ValidatedTextField' in Validation.ts, in ValidateFilterConfig // Type is validated against 'ValidatedTextField' in Validation.ts, in ValidateFilterConfig

View file

@ -212,8 +212,7 @@ export default class TagRenderingConfig {
json.freeform.type json.freeform.type
}, perhaps you meant ${Utils.sortedByLevenshteinDistance( }, perhaps you meant ${Utils.sortedByLevenshteinDistance(
json.freeform.key, json.freeform.key,
<any>Validators.availableTypes, Validators.availableTypes
(s) => <any>s
)}. See https://source.mapcomplete.org/MapComplete/MapComplete/src/branch/develop/Docs/SpecialInputElements.md for more information` )}. See https://source.mapcomplete.org/MapComplete/MapComplete/src/branch/develop/Docs/SpecialInputElements.md for more information`
} }
const type: ValidatorType = <any>json.freeform.type ?? "string" const type: ValidatorType = <any>json.freeform.type ?? "string"

View file

@ -166,8 +166,7 @@
"'; did you perhaps mean one of: " + "'; did you perhaps mean one of: " +
Utils.sortedByLevenshteinDistance( Utils.sortedByLevenshteinDistance(
type, type,
Validators.AllValidators.map((v) => v.name), Validators.AllValidators.map((v) => v.name)
(v) => v
) )
.slice(0, 5) .slice(0, 5)
.join(", ") .join(", ")

View file

@ -47,7 +47,7 @@ export default class DistanceValidator extends Validator {
if (bg && eliCategory.indexOf(bg) < 0) { if (bg && eliCategory.indexOf(bg) < 0) {
return ( return (
"The given background layer is not a recognized ELI-type. Perhaps you meant one of " + "The given background layer is not a recognized ELI-type. Perhaps you meant one of " +
Utils.sortedByLevenshteinDistance(bg, eliCategory, (x) => x).slice(0, 5) Utils.sortedByLevenshteinDistance(bg, eliCategory).slice(0, 5)
) )
} }
if (typeof args["zoom"] !== "number") { if (typeof args["zoom"] !== "number") {

View file

@ -198,7 +198,7 @@ class QrLogin extends SpecialVisualizationSvelte {
class Logout extends SpecialVisualizationSvelte { class Logout extends SpecialVisualizationSvelte {
funcName = "logout" funcName = "logout"
args = [] args = []
needsUrls = [Constants.osmAuthConfig.url] needsUrls = [Constants.osmAuthConfig]
docs = "Shows a button where the user can log out" docs = "Shows a button where the user can log out"
group = "settings" group = "settings"

View file

@ -1259,11 +1259,21 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
} }
} }
public static sortedByLevenshteinDistance(
reference: string,
ts: ReadonlyArray<string>
): string[]
public static sortedByLevenshteinDistance<T>( public static sortedByLevenshteinDistance<T>(
reference: string, reference: string,
ts: ReadonlyArray<T>, ts: ReadonlyArray<T>,
getName: (t: T) => string getName: (t: T) => string
): string[]
public static sortedByLevenshteinDistance<T>(
reference: string,
ts: ReadonlyArray<T>,
getName?: (t: T) => string
): T[] { ): T[] {
getName ??= (str) => <string> str;
const withDistance: [T, number][] = ts.map((t) => [ const withDistance: [T, number][] = ts.map((t) => [
t, t,
Utils.levenshteinDistance(getName(t), reference), Utils.levenshteinDistance(getName(t), reference),