chore(deps-dev): Bump typescript from 5.8.3 to 5.9.2 (#1301)

Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.8.3
to 5.9.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/microsoft/TypeScript/releases">typescript's
releases</a>.</em></p>
<blockquote>
<h2>TypeScript 5.9</h2>
<p>Release notes pending.</p>
<!-- raw HTML omitted -->
<ul>
<li><a
href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&amp;q=milestone%3A%22TypeScript+5.9.0%22+is%3Aclosed+">fixed
issues query for Typescript 5.9.0 (Beta)</a>.</li>
<li><a
href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&amp;q=milestone%3A%22TypeScript+5.9.1%22+is%3Aclosed+">fixed
issues query for Typescript 5.9.1 (RC)</a>.</li>
<li>[[No specific changes for TypeScript 5.9.2 (Stable)]]</li>
</ul>
<p>Downloads are available on:</p>
<ul>
<li><a href="https://www.npmjs.com/package/typescript">npm</a></li>
</ul>
<h2>TypeScript 5.9 RC</h2>
<p>For release notes, check out the <a
href="https://devblogs.microsoft.com/typescript/announcing-typescript-5-9-rc/">release
announcement</a></p>
<ul>
<li><a
href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&amp;q=milestone%3A%22TypeScript+5.9.0%22+is%3Aclosed+">fixed
issues query for Typescript 5.9.0 (Beta)</a>.</li>
<li><a
href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&amp;q=milestone%3A%22TypeScript+5.9.1%22+is%3Aclosed+">fixed
issues query for Typescript 5.9.1 (RC)</a>.</li>
</ul>
<p>Downloads are available on:</p>
<ul>
<li><a href="https://www.npmjs.com/package/typescript">npm</a></li>
</ul>
<h2>TypeScript 5.9 Beta</h2>
<p>For release notes, check out the <a
href="https://devblogs.microsoft.com/typescript/announcing-typescript-5-9-beta/">release
announcement</a>.</p>
<ul>
<li><a
href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&amp;q=milestone%3A%22TypeScript+5.9.0%22+is%3Aclosed+">fixed
issues query for Typescript 5.9.0 (Beta)</a>.</li>
</ul>
<p>Downloads are available on:</p>
<ul>
<li><a href="https://www.npmjs.com/package/typescript">npm</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="be86783155"><code>be86783</code></a>
Give more specific errors for <code>verbatimModuleSyntax</code> (<a
href="https://redirect.github.com/microsoft/TypeScript/issues/62113">#62113</a>)</li>
<li><a
href="22ef57786f"><code>22ef577</code></a>
LEGO: Pull request from
lego/hb_5378966c-b857-470a-8675-daebef4a6da1_20250714...</li>
<li><a
href="d5a414cd1d"><code>d5a414c</code></a>
Don't use <code>noErrorTruncation</code> when printing types with
<code>maximumLength</code> set (#...</li>
<li><a
href="f14b5c8a2f"><code>f14b5c8</code></a>
Remove unused and confusing dom.iterable.d.ts file (<a
href="https://redirect.github.com/microsoft/TypeScript/issues/62037">#62037</a>)</li>
<li><a
href="2778e84ed8"><code>2778e84</code></a>
Restore AbortSignal.abort (<a
href="https://redirect.github.com/microsoft/TypeScript/issues/62086">#62086</a>)</li>
<li><a
href="65cb4bd2d5"><code>65cb4bd</code></a>
LEGO: Pull request from
lego/hb_5378966c-b857-470a-8675-daebef4a6da1_20250710...</li>
<li><a
href="9e20e032ef"><code>9e20e03</code></a>
Clear out checker-level stacks on pop (<a
href="https://redirect.github.com/microsoft/TypeScript/issues/62016">#62016</a>)</li>
<li><a
href="87740bc7fe"><code>87740bc</code></a>
Fix for Issue 61081 (<a
href="https://redirect.github.com/microsoft/TypeScript/issues/61221">#61221</a>)</li>
<li><a
href="833a8d492c"><code>833a8d4</code></a>
Fix Symbol completion priority and cursor positioning (<a
href="https://redirect.github.com/microsoft/TypeScript/issues/61945">#61945</a>)</li>
<li><a
href="0018c9ff12"><code>0018c9f</code></a>
LEGO: Pull request from
lego/hb_5378966c-b857-470a-8675-daebef4a6da1_20250702...</li>
<li>Additional commits viewable in <a
href="https://github.com/microsoft/TypeScript/compare/v5.8.3...v5.9.2">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=typescript&package-manager=npm_and_yarn&previous-version=5.8.3&new-version=5.9.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

You can trigger a rebase of this PR by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

> **Note**
> Automatic rebases have been disabled on this pull request as it has
been open for over 30 days.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Harel M <harel.mazor@gmail.com>
This commit is contained in:
dependabot[bot]
2025-09-13 18:45:03 +00:00
committed by GitHub
parent 51d063ca5a
commit 5fe38bb6ff
115 changed files with 2111 additions and 2053 deletions

View File

@@ -1,8 +1,8 @@
import throttle from 'lodash.throttle'
import throttle from "lodash.throttle";
// Throttle for 3 seconds so when a user enables it they don't have to refresh the page.
const reducedMotionEnabled = throttle(() => {
return window.matchMedia("(prefers-reduced-motion: reduce)").matches
}, 3000)
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
}, 3000);
export { reducedMotionEnabled }
export { reducedMotionEnabled };

View File

@@ -1,7 +1,7 @@
import {parse} from '@prantlf/jsonlint';
import CodeMirror, { MarkerRange } from 'codemirror';
import jsonToAst from 'json-to-ast';
import {expression, validateStyleMin} from '@maplibre/maplibre-gl-style-spec';
import {parse} from "@prantlf/jsonlint";
import CodeMirror, { type MarkerRange } from "codemirror";
import jsonToAst from "json-to-ast";
import {expression, validateStyleMin} from "@maplibre/maplibre-gl-style-spec";
type MarkerRangeWithMessage = MarkerRange & {message: string};
@@ -90,7 +90,7 @@ CodeMirror.registerHelper("lint", "mgl", (text: string, opts: any, doc: any) =>
newNode = newNode.value;
}
}
return getArrayPositionalFromAst(newNode, path.slice(1))
return getArrayPositionalFromAst(newNode, path.slice(1));
}
}
@@ -121,12 +121,12 @@ CodeMirror.registerHelper("lint", "mgl", (text: string, opts: any, doc: any) =>
// Remove the 'layers[0].' as we're validating the layer only here
const errMessageParts = err.message.replace(/^layers\[0\]./, "").split(":");
return {
name: '',
name: "",
key: errMessageParts[0],
message: errMessageParts[1],
};
})
}
};
}
}
else if (context === "expression") {
@@ -147,11 +147,11 @@ CodeMirror.registerHelper("lint", "mgl", (text: string, opts: any, doc: any) =>
from: CodeMirror.Pos(doc.firstLine(), 0),
to: CodeMirror.Pos(doc.lastLine(), lastLineHandle.text.length),
message: message,
}
};
found.push(err);
}
else if (key) {
const path = key.replace(/^\[|\]$/g, "").split(/\.|[[\]]+/).filter(Boolean)
const path = key.replace(/^\[|\]$/g, "").split(/\.|[[\]]+/).filter(Boolean);
const parsedError = getArrayPositionalFromAst(ast, path);
if (!parsedError) {
console.warn("Something went wrong parsing error:", error);
@@ -167,7 +167,7 @@ CodeMirror.registerHelper("lint", "mgl", (text: string, opts: any, doc: any) =>
message: message,
});
}
})
});
}
return found;

View File

@@ -6,7 +6,7 @@ export type OnStyleChangedOpts = {
save?: boolean;
addRevision?: boolean;
initialLoad?: boolean;
}
};
export type OnStyleChangedCallback = (newStyle: StyleSpecificationWithId, opts: OnStyleChangedOpts={}) => void;

View File

@@ -1,14 +1,14 @@
import {diff} from '@maplibre/maplibre-gl-style-spec'
import type {StyleSpecification} from 'maplibre-gl'
import {diff} from "@maplibre/maplibre-gl-style-spec";
import type {StyleSpecification} from "maplibre-gl";
function diffMessages(beforeStyle: StyleSpecification, afterStyle: StyleSpecification) {
const changes = diff(beforeStyle, afterStyle)
return changes.map(cmd => cmd.command + ' ' + cmd.args.join(' '))
const changes = diff(beforeStyle, afterStyle);
return changes.map(cmd => cmd.command + " " + cmd.args.join(" "));
}
export function undoMessages(beforeStyle: StyleSpecification, afterStyle: StyleSpecification) {
return diffMessages(beforeStyle, afterStyle).map(m => 'Undo ' + m)
return diffMessages(beforeStyle, afterStyle).map(m => "Undo " + m);
}
export function redoMessages(beforeStyle: StyleSpecification, afterStyle: StyleSpecification) {
return diffMessages(beforeStyle, afterStyle).map(m => 'Redo ' + m)
return diffMessages(beforeStyle, afterStyle).map(m => "Redo " + m);
}

View File

@@ -1,4 +1,4 @@
import { TFunction } from "i18next";
import { type TFunction } from "i18next";
const spec = (t: TFunction) => ({
maputnik: {
@@ -31,6 +31,6 @@ const spec = (t: TFunction) => ({
doc: t("Choose the default Maputnik renderer for this style.")
},
}
})
});
export default spec;

View File

@@ -1,7 +1,7 @@
import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json'
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
export const combiningFilterOps = ['all', 'any', 'none'];
export const setFilterOps = ['in', '!in'];
export const combiningFilterOps = ["all", "any", "none"];
export const setFilterOps = ["in", "!in"];
export const otherFilterOps = Object
.keys(latest.filter_operator.values)
.filter(op => combiningFilterOps.indexOf(op) < 0);

View File

@@ -1,42 +1,42 @@
import stylegen from '@maplibre/maplibre-gl-inspect/lib/stylegen'
import colors from '@maplibre/maplibre-gl-inspect/lib/colors'
import type {FilterSpecification,LayerSpecification } from 'maplibre-gl'
import stylegen from "@maplibre/maplibre-gl-inspect/lib/stylegen";
import colors from "@maplibre/maplibre-gl-inspect/lib/colors";
import type {FilterSpecification,LayerSpecification } from "maplibre-gl";
export type HighlightedLayer = LayerSpecification & {filter?: FilterSpecification};
function changeLayer(l: HighlightedLayer, layer: LayerSpecification) {
if(l.type === 'circle') {
l.paint!['circle-radius'] = 3
} else if(l.type === 'line') {
l.paint!['line-width'] = 2
if(l.type === "circle") {
l.paint!["circle-radius"] = 3;
} else if(l.type === "line") {
l.paint!["line-width"] = 2;
}
if("filter" in layer) {
l.filter = layer.filter
l.filter = layer.filter;
} else {
delete l['filter']
delete l["filter"];
}
l.id = l.id + '_highlight'
return l
l.id = l.id + "_highlight";
return l;
}
export function colorHighlightedLayer(layer?: LayerSpecification): HighlightedLayer | null {
if(!layer || layer.type === 'background' || layer.type === 'raster') return null
if(!layer || layer.type === "background" || layer.type === "raster") return null;
const sourceLayerId = layer['source-layer'] || ''
const sourceLayerId = layer["source-layer"] || "";
const color = colors.brightColor(sourceLayerId, 1);
if(layer.type === "fill" || layer.type === 'fill-extrusion') {
return changeLayer(stylegen.polygonLayer(color, color, layer.source, layer['source-layer']), layer)
if(layer.type === "fill" || layer.type === "fill-extrusion") {
return changeLayer(stylegen.polygonLayer(color, color, layer.source, layer["source-layer"]), layer);
}
if(layer.type === "symbol" || layer.type === 'circle') {
return changeLayer(stylegen.circleLayer(color, layer.source, layer['source-layer']), layer)
if(layer.type === "symbol" || layer.type === "circle") {
return changeLayer(stylegen.circleLayer(color, layer.source, layer["source-layer"]), layer);
}
if(layer.type === 'line') {
return changeLayer(stylegen.lineLayer(color, layer.source, layer['source-layer']), layer)
if(layer.type === "line") {
return changeLayer(stylegen.lineLayer(color, layer.source, layer["source-layer"]), layer);
}
return null
return null;
}

View File

@@ -1,10 +1,10 @@
import capitalize from 'lodash.capitalize'
import capitalize from "lodash.capitalize";
export default function labelFromFieldName(fieldName: string) {
let label;
const parts = fieldName.split('-');
const parts = fieldName.split("-");
if (parts.length > 1) {
label = fieldName.split('-').slice(1).join(' ');
label = fieldName.split("-").slice(1).join(" ");
}
else {
label = fieldName;

View File

@@ -1,27 +1,27 @@
import {latest} from '@maplibre/maplibre-gl-style-spec'
import { LayerSpecification } from 'maplibre-gl'
import {latest} from "@maplibre/maplibre-gl-style-spec";
import { type LayerSpecification } from "maplibre-gl";
export function changeType(layer: LayerSpecification, newType: string) {
const changedPaintProps: LayerSpecification["paint"] = { ...layer.paint }
const changedPaintProps: LayerSpecification["paint"] = { ...layer.paint };
Object.keys(changedPaintProps).forEach(propertyName => {
if(!(propertyName in latest['paint_' + newType])) {
delete changedPaintProps[propertyName as keyof LayerSpecification["paint"]]
if(!(propertyName in latest["paint_" + newType])) {
delete changedPaintProps[propertyName as keyof LayerSpecification["paint"]];
}
})
});
const changedLayoutProps: LayerSpecification["layout"] = { ...layer.layout }
const changedLayoutProps: LayerSpecification["layout"] = { ...layer.layout };
Object.keys(changedLayoutProps).forEach(propertyName => {
if(!(propertyName in latest['layout_' + newType])) {
delete changedLayoutProps[propertyName as keyof LayerSpecification["layout"]]
if(!(propertyName in latest["layout_" + newType])) {
delete changedLayoutProps[propertyName as keyof LayerSpecification["layout"]];
}
})
});
return {
...layer,
paint: changedPaintProps,
layout: changedLayoutProps,
type: newType,
}
};
}
/** A {@property} in either the paint our layout {@group} has changed
@@ -61,30 +61,30 @@ export function changeProperty(layer: LayerSpecification, group: keyof LayerSpec
...layer[group] as any,
[property]: newValue
}
}
};
} else {
return {
...layer,
[property]: newValue
}
};
}
}
}
export function layerPrefix(name: string) {
return name.replace(' ', '-').replace('_', '-').split('-')[0]
return name.replace(" ", "-").replace("_", "-").split("-")[0];
}
export function findClosestCommonPrefix(layers: LayerSpecification[], idx: number) {
const currentLayerPrefix = layerPrefix(layers[idx].id)
let closestIdx = idx
const currentLayerPrefix = layerPrefix(layers[idx].id);
let closestIdx = idx;
for (let i = idx; i > 0; i--) {
const previousLayerPrefix = layerPrefix(layers[i-1].id)
const previousLayerPrefix = layerPrefix(layers[i-1].id);
if(previousLayerPrefix === currentLayerPrefix) {
closestIdx = i - 1
closestIdx = i - 1;
} else {
return closestIdx
return closestIdx;
}
}
return closestIdx
return closestIdx;
}

View File

@@ -1,11 +1,11 @@
import throttle from 'lodash.throttle'
import isEqual from 'lodash.isequal'
import { Map } from 'maplibre-gl';
import throttle from "lodash.throttle";
import isEqual from "lodash.isequal";
import { type Map } from "maplibre-gl";
export type LayerWatcherOptions = {
onSourcesChange?: (sources: { [sourceId: string]: string[] }) => void;
onVectorLayersChange?: (vectorLayers: { [vectorLayerId: string]: { [propertyName: string]: { [propertyValue: string]: {} } } }) => void;
}
};
/** Listens to map events to build up a store of available vector
* layers contained in the tiles */
@@ -17,65 +17,65 @@ export default class LayerWatcher {
_vectorLayers: { [vectorLayerId: string]: { [propertyName: string]: { [propertyValue: string]: {} } } };
constructor(opts: LayerWatcherOptions = {}) {
this.onSourcesChange = opts.onSourcesChange || (() => {})
this.onVectorLayersChange = opts.onVectorLayersChange || (() => {})
this.onSourcesChange = opts.onSourcesChange || (() => {});
this.onVectorLayersChange = opts.onVectorLayersChange || (() => {});
this._sources = {}
this._vectorLayers = {}
this._sources = {};
this._vectorLayers = {};
// Since we scan over all features we want to avoid this as much as
// possible and only do it after a batch of data has loaded because
// we only care eventuall about knowing the fields in the vector layers
this.throttledAnalyzeVectorLayerFields = throttle(this.analyzeVectorLayerFields, 5000)
this.throttledAnalyzeVectorLayerFields = throttle(this.analyzeVectorLayerFields, 5000);
}
analyzeMap(map: Map) {
const previousSources = { ...this._sources }
const previousSources = { ...this._sources };
Object.keys(map.style.sourceCaches).forEach(sourceId => {
//NOTE: This heavily depends on the internal API of Maplibre GL
//so this breaks between Maplibre GL JS releases
this._sources[sourceId] = map.style.sourceCaches[sourceId]._source.vectorLayerIds as string[];
})
});
if(!isEqual(previousSources, this._sources)) {
this.onSourcesChange(this._sources)
this.onSourcesChange(this._sources);
}
this.throttledAnalyzeVectorLayerFields(map)
this.throttledAnalyzeVectorLayerFields(map);
}
analyzeVectorLayerFields(map: Map) {
const previousVectorLayers = { ...this._vectorLayers }
const previousVectorLayers = { ...this._vectorLayers };
Object.keys(this._sources).forEach(sourceId => {
(this._sources[sourceId] || []).forEach(vectorLayerId => {
const knownProperties = this._vectorLayers[vectorLayerId] || {}
const params = { sourceLayer: vectorLayerId }
const knownProperties = this._vectorLayers[vectorLayerId] || {};
const params = { sourceLayer: vectorLayerId };
map.querySourceFeatures(sourceId, params as any).forEach(feature => {
Object.keys(feature.properties).forEach(propertyName => {
const knownPropertyValues = knownProperties[propertyName] || {}
knownPropertyValues[feature.properties[propertyName]] = {}
knownProperties[propertyName] = knownPropertyValues
})
})
const knownPropertyValues = knownProperties[propertyName] || {};
knownPropertyValues[feature.properties[propertyName]] = {};
knownProperties[propertyName] = knownPropertyValues;
});
});
this._vectorLayers[vectorLayerId] = knownProperties
})
})
this._vectorLayers[vectorLayerId] = knownProperties;
});
});
if(!isEqual(previousVectorLayers, this._vectorLayers)) {
this.onVectorLayersChange(this._vectorLayers)
this.onVectorLayersChange(this._vectorLayers);
}
}
/** Access all known sources and their vector tile ids */
get sources() {
return this._sources
return this._sources;
}
get vectorLayers() {
return this._vectorLayers
return this._vectorLayers;
}
}

View File

@@ -1,3 +1,3 @@
import MapLibreGl from "maplibre-gl"
import MapLibreGl from "maplibre-gl";
MapLibreGl.setRTLTextPlugin('https://unpkg.com/@mapbox/mapbox-gl-rtl-text@0.2.3/mapbox-gl-rtl-text.min.js', false);
MapLibreGl.setRTLTextPlugin("https://unpkg.com/@mapbox/mapbox-gl-rtl-text@0.2.3/mapbox-gl-rtl-text.min.js", false);

View File

@@ -1,44 +1,44 @@
import npmurl from 'url'
import npmurl from "url";
function loadJSON(url: string, defaultValue: any, cb: (...args: any[]) => void) {
fetch(url, {
mode: 'cors',
mode: "cors",
credentials: "same-origin"
})
.then((response) => {
if (!response.ok) {
throw new Error('Failed to load metadata for ' + url);
throw new Error("Failed to load metadata for " + url);
}
return response.json();
})
.then((body) => {
cb(body)
cb(body);
})
.catch(() => {
console.warn('Can not load metadata for ' + url + ', using default value ' + defaultValue);
cb(defaultValue)
})
console.warn("Can not load metadata for " + url + ", using default value " + defaultValue);
cb(defaultValue);
});
}
export function downloadGlyphsMetadata(urlTemplate: string, cb: (...args: any[]) => void) {
if(!urlTemplate) return cb([])
if(!urlTemplate) return cb([]);
// Special handling because Tileserver GL serves the fontstacks metadata differently
// https://github.com/klokantech/tileserver-gl/pull/104#issuecomment-274444087
const urlObj = npmurl.parse(urlTemplate);
const normPathPart = '/%7Bfontstack%7D/%7Brange%7D.pbf';
const normPathPart = "/%7Bfontstack%7D/%7Brange%7D.pbf";
if(urlObj.pathname === normPathPart) {
urlObj.pathname = '/fontstacks.json';
urlObj.pathname = "/fontstacks.json";
} else {
urlObj.pathname = urlObj.pathname!.replace(normPathPart, '.json');
urlObj.pathname = urlObj.pathname!.replace(normPathPart, ".json");
}
const url = npmurl.format(urlObj);
loadJSON(url, [], cb)
loadJSON(url, [], cb);
}
export function downloadSpriteMetadata(baseUrl: string, cb: (...args: any[]) => void) {
if(!baseUrl) return cb([])
const url = baseUrl + '.json'
loadJSON(url, {}, glyphs => cb(Object.keys(glyphs)))
if(!baseUrl) return cb([]);
const url = baseUrl + ".json";
loadJSON(url, {}, glyphs => cb(Object.keys(glyphs)));
}

View File

@@ -1 +1 @@
export const NON_SOURCE_LAYERS = ['background', 'raster', 'hillshade', 'heatmap', 'color-relief']
export const NON_SOURCE_LAYERS = ["background", "raster", "hillshade", "heatmap", "color-relief"];

View File

@@ -1,4 +1,4 @@
import { StyleSpecificationWithId } from "./definitions";
import { type StyleSpecificationWithId } from "./definitions";
export class RevisionStore {
revisions: StyleSpecificationWithId[];
@@ -6,16 +6,16 @@ export class RevisionStore {
constructor(initialRevisions=[]) {
this.revisions = initialRevisions
this.currentIdx = initialRevisions.length - 1
this.revisions = initialRevisions;
this.currentIdx = initialRevisions.length - 1;
}
get latest() {
return this.revisions[this.revisions.length - 1]
return this.revisions[this.revisions.length - 1];
}
get current() {
return this.revisions[this.currentIdx]
return this.revisions[this.currentIdx];
}
addRevision(revision: StyleSpecificationWithId) {
@@ -23,8 +23,8 @@ export class RevisionStore {
// and ensure current index is at end of list
this.revisions = this.revisions.slice(0, this.currentIdx + 1);
this.revisions.push(revision)
this.currentIdx++
this.revisions.push(revision);
this.currentIdx++;
//}
}
@@ -37,7 +37,7 @@ export class RevisionStore {
redo() {
if(this.currentIdx < this.revisions.length - 1) {
this.currentIdx++
this.currentIdx++;
}
return this.current;
}

View File

@@ -3,10 +3,10 @@ export default function(num1: string | number, num2: string| number) {
const b = +num2;
if(a < b) {
return -1
return -1;
}
else if(a > b) {
return 1
return 1;
}
else {
return 0;

View File

@@ -2,26 +2,26 @@ import type {SourceSpecification} from "maplibre-gl";
import type {StyleSpecificationWithId} from "./definitions";
export function deleteSource(mapStyle: StyleSpecificationWithId, sourceId: string) {
const remainingSources = { ...mapStyle.sources}
delete remainingSources[sourceId]
const remainingSources = { ...mapStyle.sources};
delete remainingSources[sourceId];
return {
...mapStyle,
sources: remainingSources
}
};
}
export function addSource(mapStyle: StyleSpecificationWithId, sourceId: string, source: SourceSpecification) {
return changeSource(mapStyle, sourceId, source)
return changeSource(mapStyle, sourceId, source);
}
export function changeSource(mapStyle: StyleSpecificationWithId, sourceId: string, source: SourceSpecification) {
const changedSources = {
...mapStyle.sources,
[sourceId]: source
}
};
return {
...mapStyle,
sources: changedSources
}
};
}

View File

@@ -1,18 +1,18 @@
/**
* If we don't have a default value just make one up
*/
export function findDefaultFromSpec(spec: { type: 'string' | 'color' | 'boolean' | 'array', default?: any }) {
if (Object.prototype.hasOwnProperty.call(spec, 'default')) {
export function findDefaultFromSpec(spec: { type: "string" | "color" | "boolean" | "array", default?: any }) {
if (Object.prototype.hasOwnProperty.call(spec, "default")) {
return spec.default;
}
const defaults = {
'color': '#000000',
'string': '',
'boolean': false,
'number': 0,
'array': [],
}
"color": "#000000",
"string": "",
"boolean": false,
"number": 0,
"array": [],
};
return defaults[spec.type] || '';
return defaults[spec.type] || "";
}

View File

@@ -1,11 +1,11 @@
import style from '../style'
import {format} from '@maplibre/maplibre-gl-style-spec'
import ReconnectingWebSocket from 'reconnecting-websocket'
import type {IStyleStore, OnStyleChangedCallback, StyleSpecificationWithId} from '../definitions'
import style from "../style";
import {format} from "@maplibre/maplibre-gl-style-spec";
import ReconnectingWebSocket from "reconnecting-websocket";
import type {IStyleStore, OnStyleChangedCallback, StyleSpecificationWithId} from "../definitions";
export type ApiStyleStoreOptions = {
onLocalStyleChange?: OnStyleChangedCallback
}
};
export class ApiStyleStore implements IStyleStore {
@@ -15,51 +15,51 @@ export class ApiStyleStore implements IStyleStore {
onLocalStyleChange: OnStyleChangedCallback;
constructor(opts: ApiStyleStoreOptions) {
this.onLocalStyleChange = opts.onLocalStyleChange || (() => {})
const port = window.location.port
const host = 'localhost'
this.localUrl = `http://${host}:${port}`
this.websocketUrl = `ws://${host}:${port}/ws`
this.init = this.init.bind(this)
this.onLocalStyleChange = opts.onLocalStyleChange || (() => {});
const port = window.location.port;
const host = "localhost";
this.localUrl = `http://${host}:${port}`;
this.websocketUrl = `ws://${host}:${port}/ws`;
this.init = this.init.bind(this);
}
async init(): Promise<void> {
try {
const response = await fetch(this.localUrl + '/styles', {mode: 'cors'});
const response = await fetch(this.localUrl + "/styles", {mode: "cors"});
const body = await response.json();
const styleIds = body;
this.latestStyleId = styleIds[0]
this.latestStyleId = styleIds[0];
this.notifyLocalChanges();
} catch {
throw new Error('Can not connect to style API');
throw new Error("Can not connect to style API");
}
}
notifyLocalChanges() {
const connection = new ReconnectingWebSocket(this.websocketUrl)
const connection = new ReconnectingWebSocket(this.websocketUrl);
connection.onmessage = e => {
if(!e.data) return
console.log('Received style update from API')
let parsedStyle = style.emptyStyle
if(!e.data) return;
console.log("Received style update from API");
let parsedStyle = style.emptyStyle;
try {
parsedStyle = JSON.parse(e.data)
parsedStyle = JSON.parse(e.data);
} catch(err) {
console.error(err)
console.error(err);
}
const updatedStyle = style.ensureStyleValidity(parsedStyle)
this.onLocalStyleChange(updatedStyle)
}
const updatedStyle = style.ensureStyleValidity(parsedStyle);
this.onLocalStyleChange(updatedStyle);
};
}
async getLatestStyle(): Promise<StyleSpecificationWithId> {
if(this.latestStyleId) {
const response = await fetch(this.localUrl + '/styles/' + this.latestStyleId, {
mode: 'cors',
const response = await fetch(this.localUrl + "/styles/" + this.latestStyleId, {
mode: "cors",
});
const body = await response.json();
return style.ensureStyleValidity(body);
} else {
throw new Error('No latest style available. You need to init the api backend first.')
throw new Error("No latest style available. You need to init the api backend first.");
}
}
@@ -71,18 +71,18 @@ export class ApiStyleStore implements IStyleStore {
)
);
const id = mapStyle.id
fetch(this.localUrl + '/styles/' + id, {
const id = mapStyle.id;
fetch(this.localUrl + "/styles/" + id, {
method: "PUT",
mode: 'cors',
mode: "cors",
headers: {
"Content-Type": "application/json; charset=utf-8",
},
body: styleJSON
})
.catch(function(error) {
if(error) console.error(error)
})
return mapStyle
if(error) console.error(error);
});
return mapStyle;
}
}

View File

@@ -1,5 +1,5 @@
/// <reference types="vite/client" />
import { IStyleStore, OnStyleChangedCallback } from "../definitions";
import { type IStyleStore, type OnStyleChangedCallback } from "../definitions";
import { getStyleUrlFromAddressbarAndRemoveItIfNeeded, loadStyleUrl } from "../urlopen";
import { ApiStyleStore } from "./apistore";
import { StyleStore } from "./stylestore";
@@ -8,7 +8,7 @@ export async function createStyleStore(onStyleChanged: OnStyleChangedCallback):
const styleUrl = getStyleUrlFromAddressbarAndRemoveItIfNeeded();
const useStyleUrl = styleUrl && window.confirm("Load style from URL: " + styleUrl + " and discard current changes?");
let styleStore: IStyleStore;
if (import.meta.env.MODE === 'desktop' && !useStyleUrl) {
if (import.meta.env.MODE === "desktop" && !useStyleUrl) {
const apiStyleStore = new ApiStyleStore({
onLocalStyleChange: mapStyle => onStyleChanged(mapStyle, {save: false}),
});

View File

@@ -1,16 +1,16 @@
import style from '../style'
import {loadStyleUrl} from '../urlopen'
import publicSources from '../../config/styles.json'
import type {IStyleStore, StyleSpecificationWithId} from '../definitions'
import style from "../style";
import {loadStyleUrl} from "../urlopen";
import publicSources from "../../config/styles.json";
import type {IStyleStore, StyleSpecificationWithId} from "../definitions";
const storagePrefix = "maputnik"
const stylePrefix = 'style'
const storagePrefix = "maputnik";
const stylePrefix = "style";
const storageKeys = {
latest: [storagePrefix, 'latest_style'].join(':'),
accessToken: [storagePrefix, 'access_token'].join(':')
}
latest: [storagePrefix, "latest_style"].join(":"),
accessToken: [storagePrefix, "access_token"].join(":")
};
const defaultStyleUrl = publicSources[0].url
const defaultStyleUrl = publicSources[0].url;
// Fetch a default style via URL and return it or a fallback style via callback
export function loadDefaultStyle(): Promise<StyleSpecificationWithId> {
@@ -19,35 +19,35 @@ export function loadDefaultStyle(): Promise<StyleSpecificationWithId> {
// Return style ids and dates of all styles stored in local storage
function loadStoredStyles() {
const styles = []
const styles = [];
for (let i = 0; i < window.localStorage.length; i++) {
const key = window.localStorage.key(i)
const key = window.localStorage.key(i);
if(isStyleKey(key!)) {
styles.push(fromKey(key!))
styles.push(fromKey(key!));
}
}
return styles
return styles;
}
function isStyleKey(key: string) {
const parts = key.split(":")
return parts.length === 3 && parts[0] === storagePrefix && parts[1] === stylePrefix
const parts = key.split(":");
return parts.length === 3 && parts[0] === storagePrefix && parts[1] === stylePrefix;
}
// Load style id from key
function fromKey(key: string) {
if(!isStyleKey(key)) {
throw "Key is not a valid style key"
throw "Key is not a valid style key";
}
const parts = key.split(":")
const styleId = parts[2]
return styleId
const parts = key.split(":");
const styleId = parts[2];
return styleId;
}
// Calculate key that identifies the style with a version
function styleKey(styleId: string) {
return [storagePrefix, stylePrefix, styleId].join(":")
return [storagePrefix, stylePrefix, styleId].join(":");
}
// Manages many possible styles that are stored in the local storage
@@ -68,7 +68,7 @@ export class StyleStore implements IStyleStore {
for (let i = 0; i < window.localStorage.length; i++) {
const key = window.localStorage.key(i) as string;
if(key.startsWith(storagePrefix)) {
window.localStorage.removeItem(key)
window.localStorage.removeItem(key);
}
}
}
@@ -79,7 +79,7 @@ export class StyleStore implements IStyleStore {
return loadDefaultStyle();
}
const styleId = window.localStorage.getItem(storageKeys.latest) as string;
const styleItem = window.localStorage.getItem(styleKey(styleId))
const styleItem = window.localStorage.getItem(styleKey(styleId));
if (styleItem) {
return JSON.parse(styleItem) as StyleSpecificationWithId;
@@ -89,30 +89,30 @@ export class StyleStore implements IStyleStore {
// Save current style replacing previous version
save(mapStyle: StyleSpecificationWithId) {
mapStyle = style.ensureStyleValidity(mapStyle)
const key = styleKey(mapStyle.id)
mapStyle = style.ensureStyleValidity(mapStyle);
const key = styleKey(mapStyle.id);
const saveFn = () => {
window.localStorage.setItem(key, JSON.stringify(mapStyle))
window.localStorage.setItem(storageKeys.latest, mapStyle.id)
}
window.localStorage.setItem(key, JSON.stringify(mapStyle));
window.localStorage.setItem(storageKeys.latest, mapStyle.id);
};
try {
saveFn()
saveFn();
} catch (e) {
// Handle quota exceeded error
if (e instanceof DOMException && (
e.code === 22 || // Firefox
e.code === 1014 || // Firefox
e.name === 'QuotaExceededError' ||
e.name === 'NS_ERROR_DOM_QUOTA_REACHED'
e.name === "QuotaExceededError" ||
e.name === "NS_ERROR_DOM_QUOTA_REACHED"
)) {
this.purge()
saveFn() // Retry after clearing
this.purge();
saveFn(); // Retry after clearing
} else {
throw e
throw e;
}
}
return mapStyle
return mapStyle;
}
}

View File

@@ -1,21 +1,21 @@
import {derefLayers} from '@maplibre/maplibre-gl-style-spec'
import type {StyleSpecification, LayerSpecification} from 'maplibre-gl'
import tokens from '../config/tokens.json'
import type {StyleSpecificationWithId} from './definitions'
import {derefLayers} from "@maplibre/maplibre-gl-style-spec";
import type {StyleSpecification, LayerSpecification} from "maplibre-gl";
import tokens from "../config/tokens.json";
import type {StyleSpecificationWithId} from "./definitions";
// Empty style is always used if no style could be restored or fetched
const emptyStyle = ensureStyleValidity({
version: 8,
sources: {},
layers: [],
})
});
function generateId() {
return Math.random().toString(36).substring(2, 9)
return Math.random().toString(36).substring(2, 9);
}
function ensureHasId(style: StyleSpecification & { id?: string }): StyleSpecificationWithId {
if(!('id' in style) || !style.id) {
if(!("id" in style) || !style.id) {
style.id = generateId();
}
return style as StyleSpecificationWithId;
@@ -23,81 +23,81 @@ function ensureHasId(style: StyleSpecification & { id?: string }): StyleSpecific
function ensureHasNoInteractive(style: StyleSpecificationWithId) {
const changedLayers = style.layers.map(layer => {
const changedLayer: LayerSpecification & { interactive?: any } = { ...layer }
delete changedLayer.interactive
return changedLayer
})
const changedLayer: LayerSpecification & { interactive?: any } = { ...layer };
delete changedLayer.interactive;
return changedLayer;
});
return {
...style,
layers: changedLayers
}
};
}
function ensureHasNoRefs(style: StyleSpecificationWithId) {
return {
...style,
layers: derefLayers(style.layers)
}
};
}
function ensureStyleValidity(style: StyleSpecification): StyleSpecificationWithId {
return ensureHasNoInteractive(ensureHasNoRefs(ensureHasId(style)))
return ensureHasNoInteractive(ensureHasNoRefs(ensureHasId(style)));
}
function indexOfLayer(layers: LayerSpecification[], layerId: string) {
for (let i = 0; i < layers.length; i++) {
if(layers[i].id === layerId) {
return i
return i;
}
}
return null
return null;
}
function getAccessToken(sourceName: string, mapStyle: StyleSpecification, opts: {allowFallback?: boolean}) {
const metadata = mapStyle.metadata || {} as any;
let accessToken = metadata[`maputnik:${sourceName}_access_token`]
let accessToken = metadata[`maputnik:${sourceName}_access_token`];
if(opts.allowFallback && !accessToken) {
accessToken = tokens[sourceName as keyof typeof tokens]
accessToken = tokens[sourceName as keyof typeof tokens];
}
return accessToken;
}
function replaceSourceAccessToken(mapStyle: StyleSpecification, sourceName: string, opts={}) {
const source = mapStyle.sources[sourceName]
if(!source) return mapStyle
if(!("url" in source) || !source.url) return mapStyle
const source = mapStyle.sources[sourceName];
if(!source) return mapStyle;
if(!("url" in source) || !source.url) return mapStyle;
let authSourceName = sourceName
let authSourceName = sourceName;
if(sourceName === "thunderforest_transport" || sourceName === "thunderforest_outdoors") {
authSourceName = "thunderforest"
authSourceName = "thunderforest";
}
else if (("url" in source) && source.url?.match(/\.stadiamaps\.com/)) {
// The code currently usually assumes openmaptiles == MapTiler,
// so we need to check the source URL.
authSourceName = "stadia"
authSourceName = "stadia";
}
else if (("url" in source) && source.url?.match(/\.locationiq\.com/)) {
authSourceName = "locationiq"
authSourceName = "locationiq";
}
const accessToken = getAccessToken(authSourceName, mapStyle, opts)
const accessToken = getAccessToken(authSourceName, mapStyle, opts);
if(!accessToken) {
// Early exit.
return mapStyle;
}
let sourceUrl: string
let sourceUrl: string;
if (authSourceName == "stadia") {
// Stadia Maps does not always require an API key,
// so there is no placeholder in our styles.
// We append it at the end of the URL when exporting if necessary.
sourceUrl = `${source.url}?api_key=${accessToken}`
sourceUrl = `${source.url}?api_key=${accessToken}`;
} else {
sourceUrl = source.url.replace('{key}', accessToken)
sourceUrl = source.url.replace("{key}", accessToken);
}
const changedSources = {
@@ -106,42 +106,42 @@ function replaceSourceAccessToken(mapStyle: StyleSpecification, sourceName: stri
...source,
url: sourceUrl
}
}
};
const changedStyle = {
...mapStyle,
sources: changedSources
}
return changedStyle
};
return changedStyle;
}
function replaceAccessTokens(mapStyle: StyleSpecification, opts={}) {
let changedStyle = mapStyle
let changedStyle = mapStyle;
Object.keys(mapStyle.sources).forEach((sourceName) => {
changedStyle = replaceSourceAccessToken(changedStyle, sourceName, opts);
})
});
if (mapStyle.glyphs && (mapStyle.glyphs.match(/\.tilehosting\.com/) || mapStyle.glyphs.match(/\.maptiler\.com/))) {
const newAccessToken = getAccessToken("openmaptiles", mapStyle, opts);
if (newAccessToken) {
changedStyle = {
...changedStyle,
glyphs: mapStyle.glyphs.replace('{key}', newAccessToken)
}
glyphs: mapStyle.glyphs.replace("{key}", newAccessToken)
};
}
}
return changedStyle
return changedStyle;
}
function stripAccessTokens(mapStyle: StyleSpecification) {
const changedMetadata = {
...mapStyle.metadata as any
};
delete changedMetadata['maputnik:openmaptiles_access_token'];
delete changedMetadata['maputnik:thunderforest_access_token'];
delete changedMetadata['maputnik:stadia_access_token'];
delete changedMetadata['maputnik:locationiq_access_token'];
delete changedMetadata["maputnik:openmaptiles_access_token"];
delete changedMetadata["maputnik:thunderforest_access_token"];
delete changedMetadata["maputnik:stadia_access_token"];
delete changedMetadata["maputnik:locationiq_access_token"];
return {
...mapStyle,
metadata: changedMetadata
@@ -156,4 +156,4 @@ export default {
getAccessToken,
replaceAccessTokens,
stripAccessTokens,
}
};

View File

@@ -1,27 +1,27 @@
import style from './style'
import { StyleSpecificationWithId } from './definitions';
import style from "./style";
import { type StyleSpecificationWithId } from "./definitions";
export function getStyleUrlFromAddressbarAndRemoveItIfNeeded(): string | null {
const initialUrl = new URL(window.location.href);
const styleUrl = initialUrl.searchParams.get('style');
const styleUrl = initialUrl.searchParams.get("style");
if (styleUrl) {
initialUrl.searchParams.delete('style');
window.history.replaceState({}, document.title, initialUrl.toString())
initialUrl.searchParams.delete("style");
window.history.replaceState({}, document.title, initialUrl.toString());
}
return styleUrl;
}
export async function loadStyleUrl(styleUrl: string): Promise<StyleSpecificationWithId> {
console.log('Loading style', styleUrl)
console.log("Loading style", styleUrl);
try {
const response = await fetch(styleUrl, {
mode: 'cors',
mode: "cors",
credentials: "same-origin"
});
const body = await response.json();
return style.ensureStyleValidity(body);
} catch {
console.warn('Could not fetch default style: ' + styleUrl)
return style.emptyStyle
console.warn("Could not fetch default style: " + styleUrl);
return style.emptyStyle;
}
}

View File

@@ -1,4 +1,4 @@
import {Map} from 'maplibre-gl';
import {type Map} from "maplibre-gl";
export default class ZoomControl {
_map: Map| undefined = undefined;
@@ -9,8 +9,8 @@ export default class ZoomControl {
onAdd(map: Map) {
this._map = map;
this._container = document.createElement('div');
this._container.className = 'maplibregl-ctrl maplibregl-ctrl-group maplibregl-ctrl-zoom';
this._container = document.createElement("div");
this._container.className = "maplibregl-ctrl maplibregl-ctrl-group maplibregl-ctrl-zoom";
this._container.setAttribute("data-wd-key", "maplibre:ctrl-zoom");
this.setLabel("Zoom:");
this.addEventListeners();
@@ -31,9 +31,9 @@ export default class ZoomControl {
}
addEventListeners (){
this._map!.on('render', () => this.updateZoomLevel());
this._map!.on('zoomIn', () => this.updateZoomLevel());
this._map!.on('zoomOut', () => this.updateZoomLevel());
this._map!.on("render", () => this.updateZoomLevel());
this._map!.on("zoomIn", () => this.updateZoomLevel());
this._map!.on("zoomOut", () => this.updateZoomLevel());
}
onRemove() {