├── .vscode
├── settings.json
└── launch.json
├── bun.lockb
├── .commitlintrc.cjs
├── renovate.json
├── .github
├── FUNDING.yml
├── workflows
│ ├── commitlint.yml
│ ├── notify-discord.yml
│ ├── on-pull-request.yml
│ ├── on-push-master.yml
│ └── release.yml
└── ISSUE_TEMPLATE
│ ├── question.md
│ ├── feature_request.md
│ └── bug_report.md
├── vitest.config.ts
├── .gitignore
├── data
├── mapbox
│ ├── text_placement.ts
│ ├── text_placement_point.ts
│ ├── fill_simplefill.ts
│ ├── text_placement_line_center.ts
│ ├── icon_simpleicon_mapboxapi.ts
│ ├── line_simpleline_zoom.ts
│ ├── icon_simpleicon.ts
│ ├── point_simpletext.ts
│ ├── fill_patternfill.ts
│ ├── point_placeholderText_simple.ts
│ ├── line_simpleline_expression.ts
│ ├── line_simpleline.ts
│ ├── color_rgba.ts
│ ├── fill_graphic_fill_mark.ts
│ ├── circle_simplecircle.ts
│ ├── point_placeholderText.ts
│ ├── icontext_symbolizer.ts
│ ├── line_patternline.ts
│ ├── expression_get.ts
│ ├── fill_simple_outline.ts
│ ├── expression_interpolate.ts
│ ├── line_simpleline_basefilter.ts
│ ├── multi_rule_line_fill.ts
│ ├── multi_simpleline_simplefill.ts
│ ├── expression_case.ts
│ ├── source_layer_mapping.ts
│ └── source_mapping.ts
├── styles
│ ├── text_placement_line.ts
│ ├── text_placement_point.ts
│ ├── fill_simplefill.ts
│ ├── text_placement_line_center.ts
│ ├── point_simpletext.ts
│ ├── point_placeholderText.ts
│ ├── point_placeholderText_simple.ts
│ ├── line_simpleline.ts
│ ├── line_simpleline_zoom.ts
│ ├── line_simpleline_expression.ts
│ ├── circle_simplecircle.ts
│ ├── fill_simple_outline.ts
│ ├── multi_rule_line_fill.ts
│ ├── multi_simpleline_simplefill.ts
│ ├── fill_graphic_fill_mark.ts
│ ├── gs_expression_lookup.ts
│ ├── icon_simpleicon_mapboxapi.ts
│ ├── color_rgba.ts
│ ├── icon_simpleicon.ts
│ ├── gs_expression_property.ts
│ ├── line_simpleline_basefilter.ts
│ ├── fill_patternfill.ts
│ ├── source_layer_mapping.ts
│ ├── gs_expression_string.ts
│ ├── line_patternline.ts
│ ├── source_mapping.ts
│ ├── gs_expression_interpolate.ts
│ ├── gs_expression_case.ts
│ ├── gs_expression_math.ts
│ └── gs_expression_decisions.ts
├── mapbox_metadata
│ ├── text_placement_line.ts
│ ├── text_placement_point.ts
│ ├── fill_simplefill.ts
│ ├── text_placement_line_center.ts
│ ├── icon_simpleicon_mapboxapi.ts
│ ├── line_simpleline_zoom.ts
│ ├── icon_simpleicon.ts
│ ├── point_simpletext.ts
│ ├── fill_patternfill.ts
│ ├── point_placeholderText_simple.ts
│ ├── line_simpleline_expression.ts
│ ├── line_simpleline.ts
│ ├── circle_simplecircle.ts
│ ├── point_placeholderText.ts
│ ├── line_patternline.ts
│ ├── icontext_symbolizer.ts
│ ├── expression_get.ts
│ ├── expression_interpolate.ts
│ ├── line_simpleline_basefilter.ts
│ ├── fill_simple_outline.ts
│ ├── expression_lookup.ts
│ ├── expression_case.ts
│ ├── multi_rule_line_fill.ts
│ ├── multi_simpleline_simplefill.ts
│ ├── source_layer_mapping.ts
│ ├── source_mapping.ts
│ ├── expression_string.ts
│ ├── expression_decisions.ts
│ └── expression_math.ts
└── styles_metadata
│ └── icontext_symbolizer.ts
├── vite.config.ts
├── tsconfig.test.json
├── tsconfig.json
├── .releaserc
├── eslint.config.mjs
├── LICENSE
├── package.json
├── README.md
├── src
├── Expressions.spec.ts
├── Util
│ └── MapboxStyleUtil.ts
├── Expressions.ts
└── MapboxStyleParser.spec.ts
└── CHANGELOG.md
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.tsdk": "node_modules/typescript/lib"
3 | }
4 |
--------------------------------------------------------------------------------
/bun.lockb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geostyler/geostyler-mapbox-parser/HEAD/bun.lockb
--------------------------------------------------------------------------------
/.commitlintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ['@commitlint/config-conventional']
3 | };
4 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": [
4 | "config:base"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/displaying-a-sponsor-button-in-your-repository#about-funding-files
2 | open_collective: geostyler
3 |
4 |
--------------------------------------------------------------------------------
/vitest.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vitest/config';
2 |
3 | export default defineConfig({
4 | test: {
5 | coverage: {
6 | provider: 'istanbul',
7 | reporter: ['text', 'html', 'clover', 'json', 'lcov']
8 | }
9 | },
10 | });
11 |
--------------------------------------------------------------------------------
/.github/workflows/commitlint.yml:
--------------------------------------------------------------------------------
1 | name: Lint Commit Messages
2 | on: [pull_request, push]
3 |
4 | jobs:
5 | commitlint:
6 | runs-on: ubuntu-latest
7 | steps:
8 | - uses: actions/checkout@v4
9 | - uses: wagoid/commitlint-github-action@v5
10 | with:
11 | configFile: .commitlintrc.js
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 | /browser
12 | /dist
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 |
23 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/question.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Question
3 | about: Ask a question related to this project
4 | title: ''
5 | labels: question
6 | assignees: jansule, KaiVolland
7 |
8 | ---
9 |
10 | # Question
11 |
12 |
13 |
14 |
19 |
--------------------------------------------------------------------------------
/.github/workflows/notify-discord.yml:
--------------------------------------------------------------------------------
1 | name: Discord notification
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | discord-notification:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: Discord notification 📯
12 | env:
13 | DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
14 | uses: Ilshidur/action-discord@0.3.2
15 | with:
16 | args: '${{ github.event.repository.name }} [${{ github.event.release.tag_name }}](${{ github.event.release.html_url }}) has been released. 🚀'
17 |
--------------------------------------------------------------------------------
/data/mapbox/text_placement.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const textPlacement: MbStyle = {
4 | version: 8,
5 | name: 'symbol placement',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'Simple Text',
14 | type: 'symbol',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | layout: {
18 | 'symbol-placement': 'line'
19 | }
20 | }
21 | ]
22 | };
23 |
24 | export default textPlacement;
25 |
--------------------------------------------------------------------------------
/data/mapbox/text_placement_point.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const textPlacementPoint: MbStyle = {
4 | version: 8,
5 | name: 'symbol placement',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'Simple Text',
14 | source: 'testsource',
15 | type: 'symbol',
16 | 'source-layer': 'foo',
17 | layout: {
18 | 'symbol-placement': 'point'
19 | }
20 | }
21 | ]
22 | };
23 |
24 | export default textPlacementPoint;
25 |
--------------------------------------------------------------------------------
/data/mapbox/fill_simplefill.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const fillSimpleFill: MbStyle = {
4 | version: 8,
5 | name: 'Simple Fill',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'Simple Fill',
14 | type: 'fill',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | paint: {
18 | 'fill-color': '#000000',
19 | 'fill-opacity': 1
20 | }
21 | }
22 | ]
23 | };
24 |
25 | export default fillSimpleFill;
26 |
--------------------------------------------------------------------------------
/data/mapbox/text_placement_line_center.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const textPlacementLineCenter: MbStyle = {
4 | version: 8,
5 | name: 'symbol placement',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'Simple Text',
14 | type: 'symbol',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | layout: {
18 | 'symbol-placement': 'line-center'
19 | }
20 | }
21 | ]
22 | };
23 |
24 | export default textPlacementLineCenter;
25 |
--------------------------------------------------------------------------------
/data/mapbox/icon_simpleicon_mapboxapi.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const iconSimpleIcon: MbStyle = {
4 | version: 8,
5 | name: 'Simple Icon',
6 | sprite: 'mapbox://sprites/mapbox/streets-v8',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | id: 'Simple Icon',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | type: 'symbol',
18 | layout: {
19 | 'icon-image': 'poi'
20 | }
21 | }
22 | ]
23 | };
24 |
25 | export default iconSimpleIcon;
26 |
--------------------------------------------------------------------------------
/data/mapbox/line_simpleline_zoom.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const lineSimpleLine: MbStyle = {
4 | version: 8,
5 | name: 'Simple Line Filter',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [{
12 | id: 'Small populated New Yorks',
13 | source: 'testsource',
14 | 'source-layer': 'foo',
15 | type: 'line',
16 | minzoom: 5.5,
17 | maxzoom: 10,
18 | paint: {
19 | 'line-color': '#FF0000',
20 | 'line-width': 5
21 | }
22 | }]
23 | };
24 |
25 | export default lineSimpleLine;
26 |
--------------------------------------------------------------------------------
/data/mapbox/icon_simpleicon.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const iconSimpleIcon: MbStyle = {
4 | version: 8,
5 | name: 'Simple Icon',
6 | sprite: 'https://testurl.com/sprites/mysprite',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | id: 'Simple Icon',
15 | type: 'symbol',
16 | source: 'testsource',
17 | 'source-layer': 'foo',
18 | layout: {
19 | 'icon-image': 'poi',
20 | 'icon-size': 2
21 | }
22 | }
23 | ]
24 | };
25 |
26 | export default iconSimpleIcon;
27 |
--------------------------------------------------------------------------------
/data/mapbox/point_simpletext.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const pointSimpleText: MbStyle = {
4 | version: 8,
5 | name: 'Simple Text',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'Simple Text',
14 | type: 'symbol',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | layout: {
18 | 'text-field': 'River'
19 | },
20 | paint: {
21 | 'text-color': '#000000',
22 | 'text-opacity': 1
23 | }
24 | }
25 | ]
26 | };
27 |
28 | export default pointSimpleText;
29 |
--------------------------------------------------------------------------------
/data/styles/text_placement_line.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const textPlacement: Style = {
4 | name: 'symbol placement',
5 | rules: [{
6 | name: 'Simple Text',
7 | symbolizers: [{
8 | kind: 'Text',
9 | placement: 'line'
10 | }]
11 | }],
12 | metadata: {
13 | 'mapbox:ref': {
14 | sources: {
15 | testsource: {
16 | type: 'vector'
17 | }
18 | },
19 | sourceMapping: {
20 | testsource: [0]
21 | },
22 | sourceLayerMapping: {
23 | foo: [0]
24 | }
25 | }
26 | }
27 | };
28 |
29 | export default textPlacement;
30 |
--------------------------------------------------------------------------------
/data/styles/text_placement_point.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const textPlacementPoint: Style = {
4 | name: 'symbol placement',
5 | rules: [{
6 | name: 'Simple Text',
7 | symbolizers: [{
8 | kind: 'Text',
9 | placement: 'point'
10 | }]
11 | }],
12 | metadata: {
13 | 'mapbox:ref': {
14 | sources: {
15 | testsource: {
16 | type: 'vector'
17 | }
18 | },
19 | sourceMapping: {
20 | testsource: [0]
21 | },
22 | sourceLayerMapping: {
23 | foo: [0]
24 | }
25 | }
26 | }
27 | };
28 |
29 | export default textPlacementPoint;
30 |
--------------------------------------------------------------------------------
/data/styles/fill_simplefill.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const fillSimpleFill: Style = {
4 | name: 'Simple Fill',
5 | rules: [{
6 | name: 'Simple Fill',
7 | symbolizers: [{
8 | kind: 'Fill',
9 | color: '#000000',
10 | opacity: 1
11 | }]
12 | }],
13 | metadata: {
14 | 'mapbox:ref': {
15 | sources: {
16 | testsource: {
17 | type: 'vector'
18 | }
19 | },
20 | sourceMapping: {
21 | testsource: [0]
22 | },
23 | sourceLayerMapping: {
24 | foo: [0]
25 | }
26 | }
27 | }
28 | };
29 |
30 | export default fillSimpleFill;
31 |
--------------------------------------------------------------------------------
/data/mapbox/fill_patternfill.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const fillSimpleFill: MbStyle = {
4 | version: 8,
5 | name: 'Pattern Fill',
6 | sprite: 'https://testurl.com/sprites/mysprite',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | id: 'Pattern Fill',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | type: 'fill',
18 | paint: {
19 | 'fill-color': '#000000',
20 | 'fill-opacity': 1,
21 | 'fill-pattern': 'poi'
22 | }
23 | }
24 | ]
25 | };
26 |
27 | export default fillSimpleFill;
28 |
--------------------------------------------------------------------------------
/data/mapbox/point_placeholderText_simple.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const pointPlaceholderText: MbStyle = {
4 | version: 8,
5 | name: 'Placeholder Text',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'Placeholder Text',
14 | source: 'testsource',
15 | 'source-layer': 'foo',
16 | type: 'symbol',
17 | layout: {
18 | 'text-field': '{River}'
19 | },
20 | paint: {
21 | 'text-color': '#000000',
22 | 'text-opacity': 1
23 | }
24 | }
25 | ]
26 | };
27 |
28 | export default pointPlaceholderText;
29 |
--------------------------------------------------------------------------------
/data/styles/text_placement_line_center.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const textPlacementLineCenter: Style = {
4 | name: 'symbol placement',
5 | rules: [{
6 | name: 'Simple Text',
7 | symbolizers: [{
8 | kind: 'Text',
9 | placement: 'line-center'
10 | }]
11 | }],
12 | metadata: {
13 | 'mapbox:ref': {
14 | sources: {
15 | testsource: {
16 | type: 'vector'
17 | }
18 | },
19 | sourceMapping: {
20 | testsource: [0]
21 | },
22 | sourceLayerMapping: {
23 | foo: [0]
24 | }
25 | }
26 | }
27 | };
28 |
29 | export default textPlacementLineCenter;
30 |
--------------------------------------------------------------------------------
/data/mapbox/line_simpleline_expression.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const lineSimpleLine: MbStyle = {
4 | version: 8,
5 | name: 'Simple Line Filter',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [{
12 | id: 'Small populated New Yorks',
13 | source: 'testsource',
14 | 'source-layer': 'foo',
15 | type: 'line',
16 | paint: {
17 | 'line-color': '#FF0000',
18 | 'line-width': ['case',
19 | ['==', 'DENSITY', 20],
20 | 3,
21 | ['!=', 'DENSITY', 20],
22 | 5
23 | ]
24 | }
25 | }]
26 | };
27 |
28 | export default lineSimpleLine;
29 |
--------------------------------------------------------------------------------
/data/styles/point_simpletext.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const pointSimpleText: Style = {
4 | name: 'Simple Text',
5 | rules: [{
6 | name: 'Simple Text',
7 | symbolizers: [{
8 | kind: 'Text',
9 | label: 'River',
10 | color: '#000000',
11 | opacity: 1
12 | }]
13 | }],
14 | metadata: {
15 | 'mapbox:ref': {
16 | sources: {
17 | testsource: {
18 | type: 'vector'
19 | }
20 | },
21 | sourceMapping: {
22 | testsource: [0]
23 | },
24 | sourceLayerMapping: {
25 | foo: [0]
26 | }
27 | }
28 | }
29 | };
30 |
31 | export default pointSimpleText;
32 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite';
2 |
3 | // https://vitejs.dev/config/
4 | export default defineConfig({
5 | plugins: [],
6 | build: {
7 | manifest: true,
8 | lib: {
9 | entry: './src/MapboxStyleParser.ts',
10 | name: 'MapboxStyleParser',
11 | formats: ['iife'],
12 | fileName: 'mapboxStyleParser',
13 | },
14 | rollupOptions: {
15 | output: {
16 | dir: 'dist',
17 | exports: 'named',
18 | generatedCode: 'es5',
19 | format: 'iife',
20 | sourcemap: true
21 | },
22 | }
23 | },
24 | define: {
25 | appName: 'GeoStyler'
26 | },
27 | server: {
28 | host: '0.0.0.0'
29 | }
30 | });
31 |
--------------------------------------------------------------------------------
/data/mapbox/line_simpleline.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const lineSimpleLine: MbStyle = {
4 | version: 8,
5 | name: 'Simple Line',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'Simple Line',
14 | source: 'testsource',
15 | 'source-layer': 'foo',
16 | type: 'line',
17 | paint: {
18 | 'line-color': '#000000',
19 | 'line-width': 3,
20 | 'line-dasharray': [13, 37]
21 | },
22 | layout: {
23 | 'line-cap': 'round',
24 | 'line-join': 'miter'
25 | }
26 | }
27 | ]
28 | };
29 |
30 | export default lineSimpleLine;
31 |
--------------------------------------------------------------------------------
/data/mapbox/color_rgba.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const colorRgba: MbStyle = {
4 | version: 8,
5 | name: 'Color RGBA',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'Color RGBA',
14 | source: 'testsource',
15 | 'source-layer': 'foo',
16 | type: 'circle',
17 | paint: {
18 | 'circle-color': 'rgba(0, 0, 0, 1)',
19 | 'circle-stroke-color': [
20 | 'case',
21 | ['<', ['get', 'mag'], 2],
22 | 'rgba(255, 0, 0, 1)',
23 | 'rgba(0, 255, 0, 1)'
24 | ]
25 | }
26 | }
27 | ]
28 | };
29 |
30 | export default colorRgba;
31 |
--------------------------------------------------------------------------------
/data/mapbox/fill_graphic_fill_mark.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const fillGraphicFillMark: MbStyle = {
4 | version: 8,
5 | name: 'Graphic Fill Mark',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | type: 'fill',
14 | paint: {
15 | 'fill-opacity': 0.5,
16 | 'fill-color': '#006C2B'
17 | },
18 | source: 'testsource',
19 | 'source-layer': 'foo',
20 | id: 'r0_sy0_st0'
21 | }
22 | ],
23 | metadata: {
24 | 'geostyler:ref': { rules: [{name: 'Graphic Fill Mark', symbolizers: [['r0_sy0_st0']]}] },
25 | }
26 | };
27 |
28 | export default fillGraphicFillMark;
29 |
--------------------------------------------------------------------------------
/data/styles/point_placeholderText.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const pointPlaceholderText: Style = {
4 | name: 'Placeholder Text',
5 | rules: [{
6 | name: 'Placeholder Text',
7 | symbolizers: [{
8 | kind: 'Text',
9 | label: 'Area: {{area}}km2',
10 | color: '#000000',
11 | opacity: 1
12 | }]
13 | }],
14 | metadata: {
15 | 'mapbox:ref': {
16 | sources: {
17 | testsource: {
18 | type: 'vector'
19 | }
20 | },
21 | sourceMapping: {
22 | testsource: [0]
23 | },
24 | sourceLayerMapping: {
25 | foo: [0]
26 | }
27 | }
28 | }
29 | };
30 |
31 | export default pointPlaceholderText;
32 |
--------------------------------------------------------------------------------
/data/styles/point_placeholderText_simple.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const pointPlaceholderText: Style = {
4 | name: 'Placeholder Text',
5 | rules: [{
6 | name: 'Placeholder Text',
7 | symbolizers: [{
8 | kind: 'Text',
9 | label: '{{River}}',
10 | color: '#000000',
11 | opacity: 1
12 | }]
13 | }],
14 | metadata: {
15 | 'mapbox:ref': {
16 | sources: {
17 | testsource: {
18 | type: 'vector'
19 | }
20 | },
21 | sourceMapping: {
22 | testsource: [0]
23 | },
24 | sourceLayerMapping: {
25 | foo: [0]
26 | }
27 | }
28 | }
29 | };
30 |
31 | export default pointPlaceholderText;
32 |
--------------------------------------------------------------------------------
/data/styles/line_simpleline.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const lineSimpleLine: Style = {
4 | name: 'Simple Line',
5 | rules: [{
6 | name: 'Simple Line',
7 | symbolizers: [{
8 | kind: 'Line',
9 | color: '#000000',
10 | width: 3,
11 | dasharray: [13, 37],
12 | cap: 'round',
13 | join: 'miter'
14 | }]
15 | }],
16 | metadata: {
17 | 'mapbox:ref': {
18 | sources: {
19 | testsource: {
20 | type: 'vector'
21 | }
22 | },
23 | sourceMapping: {
24 | testsource: [0]
25 | },
26 | sourceLayerMapping: {
27 | foo: [0]
28 | }
29 | }
30 | }
31 | };
32 |
33 | export default lineSimpleLine;
34 |
--------------------------------------------------------------------------------
/data/mapbox/circle_simplecircle.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const circleSimpleCircle: MbStyle = {
4 | version: 8,
5 | name: 'Simple Circle',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'Simple Circle',
14 | source: 'testsource',
15 | 'source-layer': 'foo',
16 | type: 'circle',
17 | paint: {
18 | 'circle-color': '#000000',
19 | 'circle-radius': 5,
20 | 'circle-opacity': 1,
21 | 'circle-stroke-width': 2,
22 | 'circle-stroke-color': '#FF0000',
23 | 'circle-stroke-opacity': 0.5
24 | }
25 | }
26 | ]
27 | };
28 |
29 | export default circleSimpleCircle;
30 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: jansule, KaiVolland
7 |
8 | ---
9 |
10 | # Feature Request
11 |
12 | **Is your feature request related to a problem? Please describe.**
13 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
14 |
15 | **Describe the solution you'd like**
16 | A clear and concise description of what you want to happen.
17 |
18 | **Describe alternatives you've considered**
19 | A clear and concise description of any alternative solutions or features you've considered.
20 |
21 | **Additional context**
22 | Add any other context or screenshots about the feature request here.
23 |
--------------------------------------------------------------------------------
/data/mapbox/point_placeholderText.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const pointPlaceholderText: MbStyle = {
4 | version: 8,
5 | name: 'Placeholder Text',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'Placeholder Text',
14 | type: 'symbol',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | layout: {
18 | 'text-field': ['format',
19 | 'Area: ', {},
20 | ['get', 'area'], {},
21 | 'km2', {}
22 | ]
23 | },
24 | paint: {
25 | 'text-color': '#000000',
26 | 'text-opacity': 1
27 | }
28 | }
29 | ]
30 | };
31 |
32 | export default pointPlaceholderText;
33 |
--------------------------------------------------------------------------------
/data/styles/line_simpleline_zoom.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const lineSimpleLine: Style = {
4 | name: 'Simple Line Filter',
5 | rules: [{
6 | name: 'Small populated New Yorks',
7 | scaleDenominator: {
8 | min: 545978.7909368654,
9 | max: 12354089.774575673,
10 | },
11 | symbolizers: [{
12 | kind: 'Line',
13 | color: '#FF0000',
14 | width: 5
15 | }]
16 | }],
17 | metadata: {
18 | 'mapbox:ref': {
19 | sources: {
20 | testsource: {
21 | type: 'vector'
22 | }
23 | },
24 | sourceMapping: {
25 | testsource: [0]
26 | },
27 | sourceLayerMapping: {
28 | foo: [0]
29 | }
30 | }
31 | }
32 | };
33 |
34 | export default lineSimpleLine;
35 |
--------------------------------------------------------------------------------
/data/styles/line_simpleline_expression.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | // TODO: this includes some expressions and should fail for now
4 | const lineSimpleLine: Style = {
5 | name: 'Simple Line Filter',
6 | rules: [{
7 | name: 'Small populated New Yorks',
8 | symbolizers: [{
9 | kind: 'Line',
10 | color: '#FF0000',
11 | width: {
12 | name: 'random'
13 | }
14 | }]
15 | }],
16 | metadata: {
17 | 'mapbox:ref': {
18 | sources: {
19 | testsource: {
20 | type: 'vector'
21 | }
22 | },
23 | sourceMapping: {
24 | testsource: [0]
25 | },
26 | sourceLayerMapping: {
27 | foo: [0]
28 | }
29 | }
30 | }
31 | };
32 |
33 | export default lineSimpleLine;
34 |
--------------------------------------------------------------------------------
/data/mapbox/icontext_symbolizer.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const iconTextSymbolizer: MbStyle = {
4 | version: 8,
5 | name: 'icontext symbolizer',
6 | sprite: 'https://testurl.com/sprites/mysprite',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | type: 'symbol',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | paint: {
18 | 'text-color': 'rgba(45, 45, 45, 1)',
19 | },
20 | layout: {
21 | 'text-field': '{name}',
22 | 'text-size': 12,
23 | 'icon-image': 'poi',
24 | visibility: 'visible',
25 | },
26 | id: 'label and icon',
27 | }
28 | ]
29 | };
30 |
31 |
32 | export default iconTextSymbolizer;
33 |
--------------------------------------------------------------------------------
/data/mapbox/line_patternline.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const linePatternLine: MbStyle = {
4 | version: 8,
5 | name: 'Pattern Line',
6 | sprite: 'https://testurl.com/sprites/mysprite',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | id: 'Pattern Line',
15 | type: 'line',
16 | source: 'testsource',
17 | 'source-layer': 'foo',
18 | paint: {
19 | 'line-color': '#000000',
20 | 'line-width': 3,
21 | 'line-dasharray': [13, 37],
22 | 'line-pattern': 'poi'
23 | },
24 | layout: {
25 | 'line-cap': 'round',
26 | 'line-join': 'miter'
27 | }
28 | }
29 | ]
30 | };
31 |
32 | export default linePatternLine;
33 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/text_placement_line.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const textPlacementLine: MbStyle = {
4 | version: 8,
5 | name: 'symbol placement',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'r0_sy0_st0',
14 | source: 'testsource',
15 | 'source-layer': 'foo',
16 | type: 'symbol',
17 | layout: {
18 | 'symbol-placement': 'line'
19 | }
20 | }
21 | ],
22 | metadata: {
23 | 'geostyler:ref': {
24 | rules: [{
25 | name: 'Simple Text',
26 | symbolizers: [
27 | [
28 | 'r0_sy0_st0'
29 | ]
30 | ]
31 | }]
32 | }
33 | }
34 | };
35 |
36 | export default textPlacementLine;
37 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/text_placement_point.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const textPlacementPoint: MbStyle = {
4 | version: 8,
5 | name: 'symbol placement',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'r0_sy0_st0',
14 | source: 'testsource',
15 | 'source-layer': 'foo',
16 | type: 'symbol',
17 | layout: {
18 | 'symbol-placement': 'point'
19 | }
20 | }
21 | ],
22 | metadata: {
23 | 'geostyler:ref': {
24 | rules: [{
25 | name: 'Simple Text',
26 | symbolizers: [
27 | [
28 | 'r0_sy0_st0'
29 | ]
30 | ]
31 | }]
32 | }
33 | }
34 | };
35 |
36 | export default textPlacementPoint;
37 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/fill_simplefill.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const fillSimpleFill: MbStyle = {
4 | version: 8,
5 | name: 'Simple Fill',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'r0_sy0_st0',
14 | source: 'testsource',
15 | 'source-layer': 'foo',
16 | type: 'fill',
17 | paint: {
18 | 'fill-color': '#000000',
19 | 'fill-opacity': 1
20 | }
21 | }
22 | ],
23 | metadata: {
24 | 'geostyler:ref': {
25 | rules: [{
26 | name: 'Simple Fill',
27 | symbolizers: [
28 | [
29 | 'r0_sy0_st0'
30 | ]
31 | ]
32 | }]
33 | }
34 | }
35 | };
36 |
37 | export default fillSimpleFill;
38 |
--------------------------------------------------------------------------------
/data/styles/circle_simplecircle.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const circleSimpleCircle: Style = {
4 | name: 'Simple Circle',
5 | rules: [{
6 | name: 'Simple Circle',
7 | symbolizers: [{
8 | kind: 'Mark',
9 | wellKnownName: 'circle',
10 | color: '#000000',
11 | radius: 5,
12 | fillOpacity: 1,
13 | strokeWidth: 2,
14 | strokeColor: '#FF0000',
15 | strokeOpacity: 0.5
16 | }]
17 | }],
18 | metadata: {
19 | 'mapbox:ref': {
20 | sources: {
21 | testsource: {
22 | type: 'vector'
23 | }
24 | },
25 | sourceMapping: {
26 | testsource: [0]
27 | },
28 | sourceLayerMapping: {
29 | foo: [0]
30 | }
31 | }
32 | }
33 | };
34 |
35 | export default circleSimpleCircle;
36 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/text_placement_line_center.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const textPlacementLineCenter: MbStyle = {
4 | version: 8,
5 | name: 'symbol placement',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'r0_sy0_st0',
14 | source: 'testsource',
15 | 'source-layer': 'foo',
16 | type: 'symbol',
17 | layout: {
18 | 'symbol-placement': 'line-center'
19 | }
20 | }
21 | ],
22 | metadata: {
23 | 'geostyler:ref': {
24 | rules: [{
25 | name: 'Simple Text',
26 | symbolizers: [
27 | [
28 | 'r0_sy0_st0'
29 | ]
30 | ]
31 | }]
32 | }
33 | }
34 | };
35 |
36 | export default textPlacementLineCenter;
37 |
--------------------------------------------------------------------------------
/data/mapbox/expression_get.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/naming-convention */
2 | import { MbStyle } from '../../src/MapboxStyleParser';
3 |
4 | const expression_get: MbStyle = {
5 | version: 8,
6 | name: 'Expression Get',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | id: 'Expression Get',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | type: 'circle',
18 | paint: {
19 | 'circle-color': '#000000',
20 | 'circle-radius': ['get', 'population'],
21 | 'circle-opacity': ['get', 'population_density'],
22 | 'circle-stroke-width': 2,
23 | 'circle-stroke-color': '#FF0000',
24 | 'circle-stroke-opacity': 0.5
25 | }
26 | }
27 | ]
28 | };
29 |
30 | export default expression_get;
31 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/icon_simpleicon_mapboxapi.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const iconSimpleIcon: MbStyle = {
4 | version: 8,
5 | name: 'Simple Icon',
6 | sprite: 'mapbox://sprites/mapbox/streets-v8',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | id: 'r0_sy0_st0',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | type: 'symbol',
18 | layout: {
19 | 'icon-image': 'poi'
20 | }
21 | }
22 | ],
23 | metadata: {
24 | 'geostyler:ref': {
25 | rules: [{
26 | name: 'Simple Icon',
27 | symbolizers: [
28 | [
29 | 'r0_sy0_st0'
30 | ]
31 | ]
32 | }]
33 | }
34 | }
35 | };
36 |
37 | export default iconSimpleIcon;
38 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/line_simpleline_zoom.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const lineSimpleLine: MbStyle = {
4 | version: 8,
5 | name: 'Simple Line Filter',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [{
12 | id: 'r0_sy0_st0',
13 | source: 'testsource',
14 | 'source-layer': 'foo',
15 | type: 'line',
16 | minzoom: 5.5,
17 | maxzoom: 10,
18 | paint: {
19 | 'line-color': '#FF0000',
20 | 'line-width': 5
21 | }
22 | }],
23 | metadata: {
24 | 'geostyler:ref': {
25 | rules: [{
26 | name: 'Small populated New Yorks',
27 | symbolizers: [
28 | [
29 | 'r0_sy0_st0'
30 | ]
31 | ]
32 | }]
33 | }
34 | }
35 | };
36 |
37 | export default lineSimpleLine;
38 |
--------------------------------------------------------------------------------
/.github/workflows/on-pull-request.yml:
--------------------------------------------------------------------------------
1 | name: Test Pull Request
2 |
3 | on: pull_request
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 |
9 | steps:
10 | - name: Checkout sources
11 | uses: actions/checkout@v4
12 |
13 | - name: Set up bun
14 | uses: oven-sh/setup-bun@v2
15 |
16 | - name: Install dependencies ⏬
17 | run: bun install
18 |
19 | - name: Lint code 💄
20 | run: bun run lint
21 |
22 | - name: Test code ✅
23 | run: bun test --coverage --coverage-reporter=lcov
24 |
25 | - name: Build artifacts 🏗️
26 | run: bun run build
27 |
28 | - name: Publish to coveralls ⭐
29 | # coverage/lcov.info was generated in the previous npm run build step
30 | uses: coverallsapp/github-action@master
31 | with:
32 | github-token: ${{ secrets.GITHUB_TOKEN }}
33 |
--------------------------------------------------------------------------------
/tsconfig.test.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": false,
4 | "baseUrl": ".",
5 | "declaration": true,
6 | "esModuleInterop": true,
7 | "forceConsistentCasingInFileNames": true,
8 | "inlineSources": true,
9 | "lib": ["ES2022", "es6", "dom"],
10 | "module": "Preserve",
11 | "moduleResolution": "Bundler",
12 | "noImplicitAny": true,
13 | "noImplicitReturns": true,
14 | "noImplicitThis": true,
15 | "noUnusedLocals": true,
16 | "outDir": "dist",
17 | "rootDir": ".",
18 | "sourceMap": true,
19 | "strictNullChecks": true,
20 | "target": "ES2022",
21 | },
22 | "exclude": [
23 | "acceptance-tests",
24 | "browser-build.config.js",
25 | "browser",
26 | "dist",
27 | "coverage",
28 | "data",
29 | "jest",
30 | "node_modules",
31 | "scripts"
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/icon_simpleicon.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const iconSimpleIcon: MbStyle = {
4 | version: 8,
5 | name: 'Simple Icon',
6 | sprite: 'https://testurl.com/sprites/mysprite',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | id: 'r0_sy0_st0',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | type: 'symbol',
18 | layout: {
19 | 'icon-image': 'poi',
20 | 'icon-size': 2
21 | }
22 | }
23 | ],
24 | metadata: {
25 | 'geostyler:ref': {
26 | rules: [{
27 | name: 'Simple Icon',
28 | symbolizers: [
29 | [
30 | 'r0_sy0_st0'
31 | ]
32 | ]
33 | }]
34 | }
35 | }
36 | };
37 |
38 | export default iconSimpleIcon;
39 |
--------------------------------------------------------------------------------
/data/styles/fill_simple_outline.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const fillSimpleFillOutline: Style = {
4 | name: 'Simple Fill With outline',
5 | rules: [{
6 | name: 'The name of my rule',
7 | symbolizers: [{
8 | kind: 'Fill',
9 | color: '#ff0000',
10 | outlineColor: '#00ff00',
11 | outlineWidth: 2,
12 | outlineOpacity: 0.5,
13 | outlineCap: 'butt',
14 | outlineJoin: 'round',
15 | outlineDasharray: [13, 37]
16 | }]
17 | }],
18 | metadata: {
19 | 'mapbox:ref': {
20 | sources: {
21 | testsource: {
22 | type: 'vector'
23 | }
24 | },
25 | sourceMapping: {
26 | testsource: [0]
27 | },
28 | sourceLayerMapping: {
29 | foo: [0]
30 | }
31 | }
32 | }
33 | };
34 |
35 | export default fillSimpleFillOutline;
36 |
--------------------------------------------------------------------------------
/.github/workflows/on-push-master.yml:
--------------------------------------------------------------------------------
1 | name: Test Push to Master
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - name: Checkout sources
14 | uses: actions/checkout@v4
15 |
16 | - name: Set up bun
17 | uses: oven-sh/setup-bun@v2
18 |
19 | - name: Install dependencies ⏬
20 | run: bun install
21 |
22 | - name: Lint code 💄
23 | run: bun run lint
24 |
25 | - name: Test code ✅
26 | run: bun test --coverage --coverage-reporter=lcov
27 |
28 | - name: Build artifacts 🏗️
29 | run: bun run build
30 |
31 | - name: Publish to coveralls ⭐
32 | # coverage/lcov.info was generated in the previous npm run build step
33 | uses: coverallsapp/github-action@master
34 | with:
35 | github-token: ${{ secrets.GITHUB_TOKEN }}
36 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/point_simpletext.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const pointSimpleText: MbStyle = {
4 | version: 8,
5 | name: 'Simple Text',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'r0_sy0_st0',
14 | source: 'testsource',
15 | 'source-layer': 'foo',
16 | type: 'symbol',
17 | layout: {
18 | 'text-field': 'River'
19 | },
20 | paint: {
21 | 'text-color': '#000000',
22 | 'text-opacity': 1
23 | }
24 | }
25 | ],
26 | metadata: {
27 | 'geostyler:ref': {
28 | rules: [{
29 | name: 'Simple Text',
30 | symbolizers: [
31 | [
32 | 'r0_sy0_st0'
33 | ]
34 | ]
35 | }]
36 | }
37 | }
38 | };
39 |
40 | export default pointSimpleText;
41 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | branches:
7 | - next
8 |
9 | jobs:
10 | release:
11 | permissions:
12 | contents: write
13 | issues: write
14 | pull-requests: write
15 | id-token: write
16 | runs-on: ubuntu-latest
17 | steps:
18 | - name: Checkout sources 🔰
19 | uses: actions/checkout@v4
20 |
21 | - name: Set up node
22 | uses: actions/setup-node@v6
23 | with:
24 | node-version: '24'
25 |
26 | - name: Install dependencies ⏬
27 | run: npm install --force
28 |
29 | - name: Build artifacts 🏗️
30 | run: npm run build
31 |
32 | - id: semantic-release-step
33 | name: Release with Semantic Release
34 | env:
35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36 | run: npx semantic-release
--------------------------------------------------------------------------------
/data/mapbox_metadata/fill_patternfill.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const fillSimpleFill: MbStyle = {
4 | version: 8,
5 | name: 'Pattern Fill',
6 | sprite: 'https://testurl.com/sprites/mysprite',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | id: 'r0_sy0_st0',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | type: 'fill',
18 | paint: {
19 | 'fill-color': '#000000',
20 | 'fill-opacity': 1,
21 | 'fill-pattern': 'poi'
22 | }
23 | }
24 | ],
25 | metadata: {
26 | 'geostyler:ref': {
27 | rules: [{
28 | name: 'Pattern Fill',
29 | symbolizers: [
30 | [
31 | 'r0_sy0_st0'
32 | ]
33 | ]
34 | }]
35 | }
36 | }
37 | };
38 |
39 | export default fillSimpleFill;
40 |
--------------------------------------------------------------------------------
/data/mapbox/fill_simple_outline.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const fillSimpleFillOutline: MbStyle = {
4 | version: 8,
5 | name: 'Simple Fill With outline',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [{
12 | id: 'r0_sy0_st0',
13 | type: 'fill',
14 | source: 'testsource',
15 | 'source-layer': 'foo',
16 | paint: {
17 | 'fill-color': '#ff0000'
18 | }
19 | },
20 | {
21 | id: 'r0_sy0_st1',
22 | type: 'line',
23 | source: 'testsource',
24 | 'source-layer': 'foo',
25 | paint: {
26 | 'line-opacity': 0.5,
27 | 'line-color': '#00ff00',
28 | 'line-width': 2,
29 | 'line-dasharray': [13, 37]
30 | },
31 | layout: {
32 | 'line-cap': 'butt',
33 | 'line-join': 'round'
34 | }
35 | }]
36 | };
37 |
38 | export default fillSimpleFillOutline;
39 |
--------------------------------------------------------------------------------
/data/mapbox/expression_interpolate.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/naming-convention */
2 | import { MbStyle } from '../../src/MapboxStyleParser';
3 |
4 | const expressionInterpolate: MbStyle = {
5 | version: 8,
6 | name: 'Expression Interpolate',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | id: 'earthquake_circle',
15 | type: 'circle',
16 | source: 'testsource',
17 | 'source-layer': 'foo',
18 | paint: {
19 | 'circle-color': '#000000',
20 | 'circle-opacity': 0.6,
21 | 'circle-radius': [
22 | 'interpolate',
23 | ['linear'],
24 | ['get', 'population'],
25 | 12,
26 | 2,
27 | 15,
28 | 4,
29 | 19,
30 | 35
31 | ]
32 | }
33 | }
34 | ]
35 | };
36 |
37 | export default expressionInterpolate;
38 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/point_placeholderText_simple.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const pointPlaceholderText: MbStyle = {
4 | version: 8,
5 | name: 'Placeholder Text',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'r0_sy0_st0',
14 | source: 'testsource',
15 | 'source-layer': 'foo',
16 | type: 'symbol',
17 | layout: {
18 | 'text-field': '{River}'
19 | },
20 | paint: {
21 | 'text-color': '#000000',
22 | 'text-opacity': 1
23 | }
24 | }
25 | ],
26 | metadata: {
27 | 'geostyler:ref': {
28 | rules: [{
29 | name: 'Placeholder Text',
30 | symbolizers: [
31 | [
32 | 'r0_sy0_st0'
33 | ]
34 | ]
35 | }]
36 | }
37 | }
38 | };
39 |
40 | export default pointPlaceholderText;
41 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/line_simpleline_expression.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const lineSimpleLine: MbStyle = {
4 | version: 8,
5 | name: 'Simple Line Filter',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [{
12 | id: 'r0_sy0_st0',
13 | source: 'testsource',
14 | 'source-layer': 'foo',
15 | type: 'line',
16 | paint: {
17 | 'line-color': '#FF0000',
18 | 'line-width': ['case',
19 | ['==', 'DENSITY', 20],
20 | 3,
21 | ['!=', 'DENSITY', 20],
22 | 5
23 | ]
24 | }
25 | }],
26 | metadata: {
27 | 'geostyler:ref': {
28 | rules: [{
29 | name: 'Small populated New Yorks',
30 | symbolizers: [
31 | [
32 | 'r0_sy0_st0'
33 | ]
34 | ]
35 | }]
36 | }
37 | }
38 | };
39 |
40 | export default lineSimpleLine;
41 |
--------------------------------------------------------------------------------
/data/styles/multi_rule_line_fill.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const multiRuleLineFill: Style = {
4 | name: 'Rule Line Fill',
5 | rules: [{
6 | name: 'Line Rule',
7 | symbolizers: [{
8 | kind: 'Line',
9 | color: '#000000',
10 | width: 3,
11 | dasharray: [13, 37],
12 | cap: 'round',
13 | join: 'miter',
14 | dashOffset: 10
15 | }]
16 | }, {
17 | name: 'Fill Rule',
18 | symbolizers: [{
19 | kind: 'Fill',
20 | color: '#000000',
21 | opacity: 1
22 | }]
23 | }],
24 | metadata: {
25 | 'mapbox:ref': {
26 | sources: {
27 | testsource: {
28 | type: 'vector'
29 | }
30 | },
31 | sourceMapping: {
32 | testsource: [0, 1]
33 | },
34 | sourceLayerMapping: {
35 | foo: [0, 1]
36 | }
37 | }
38 | }
39 | };
40 |
41 | export default multiRuleLineFill;
42 |
--------------------------------------------------------------------------------
/data/mapbox/line_simpleline_basefilter.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const lineSimpleLine: MbStyle = {
4 | version: 8,
5 | name: 'Small populated New Yorks',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [{
12 | id: 'Small populated New Yorks',
13 | source: 'testsource',
14 | 'source-layer': 'foo',
15 | type: 'line',
16 | filter: ['all',
17 | ['==', 'NAME', 'New York'],
18 | ['==', 'TEST_BOOL', 'true'],
19 | ['==', 'TEST', null],
20 | ['*=', 'TEST2', '*York*'],
21 | ['*=', 'TEST1', '*New*'],
22 | ['!', ['>', 'POPULATION', '100000']],
23 | ['any',
24 | ['==', 'TEST2', '1'],
25 | ['==', 'TEST2', '2']
26 | ]
27 | ],
28 | paint: {
29 | 'line-color': '#FF0000',
30 | 'line-width': 3
31 | }
32 | }]
33 | };
34 |
35 | export default lineSimpleLine;
36 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Debug Jest Tests",
6 | "type": "node",
7 | "request": "launch",
8 | "port": 9230,
9 | "runtimeArgs": [
10 | "--inspect-brk=9230",
11 | "${workspaceRoot}/node_modules/.bin/jest",
12 | "--runInBand",
13 | "--watch"
14 | ],
15 | "runtimeExecutable": null,
16 | "console": "integratedTerminal"
17 | },
18 | {
19 | "type": "node",
20 | "request": "launch",
21 | "name": "Debug Jest Tests Windows",
22 | "program": "${workspaceRoot}/node_modules/jest/bin/jest",
23 | "args": [
24 | "-i",
25 | "--watch"
26 | ],
27 | "internalConsoleOptions": "openOnSessionStart",
28 | "console": "integratedTerminal",
29 | "outFiles": [
30 | "${workspaceRoot}/build/dist/**/*"
31 | ]
32 | }
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": false,
4 | "baseUrl": ".",
5 | "declaration": true,
6 | "esModuleInterop": true,
7 | "forceConsistentCasingInFileNames": true,
8 | "inlineSources": true,
9 | "lib": ["ES2022", "es6", "dom"],
10 | "module": "Preserve",
11 | "moduleResolution": "Bundler",
12 | "noImplicitAny": true,
13 | "noImplicitReturns": true,
14 | "noImplicitThis": true,
15 | "noUnusedLocals": true,
16 | "outDir": "dist",
17 | "rootDir": "src",
18 | "sourceMap": true,
19 | "strictNullChecks": true,
20 | "target": "ES2022",
21 | },
22 | "exclude": [
23 | "acceptance-tests",
24 | "browser-build.config.js",
25 | "browser",
26 | "dist",
27 | "coverage",
28 | "data",
29 | "jest",
30 | "node_modules",
31 | "scripts",
32 | "src/**.spec.ts",
33 | "vite.config.ts",
34 | "vitest.config.ts"
35 | ]
36 | }
37 |
--------------------------------------------------------------------------------
/data/mapbox/multi_rule_line_fill.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const multiRuleLineFill: MbStyle = {
4 | version: 8,
5 | name: 'Rule Line Fill',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'Line Rule',
14 | type: 'line',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | paint: {
18 | 'line-color': '#000000',
19 | 'line-width': 3,
20 | 'line-dasharray': [13, 37]
21 | },
22 | layout: {
23 | 'line-cap': 'round',
24 | 'line-join': 'miter'
25 | }
26 | }, {
27 | id: 'Fill Rule',
28 | type: 'fill',
29 | source: 'testsource',
30 | 'source-layer': 'foo',
31 | paint: {
32 | 'fill-color': '#000000',
33 | 'fill-opacity': 1
34 | }
35 | }
36 | ]
37 | };
38 |
39 | export default multiRuleLineFill;
40 |
--------------------------------------------------------------------------------
/.releaserc:
--------------------------------------------------------------------------------
1 | {
2 | "branches": [
3 | "main",
4 | {
5 | "name": "next",
6 | "prerelease": true
7 | }
8 | ],
9 | "plugins": [
10 | [
11 | "@semantic-release/commit-analyzer",
12 | {
13 | "preset": "conventionalcommits"
14 | }
15 | ],
16 | [
17 | "@semantic-release/release-notes-generator",
18 | {
19 | "preset": "conventionalcommits",
20 | "presetConfig": {
21 | "header": "Changelog of GeoStyler Mapbox Parser"
22 | }
23 | }
24 | ],
25 | "@semantic-release/changelog",
26 | "@semantic-release/npm",
27 | [
28 | "@semantic-release/git",
29 | {
30 | "assets": [
31 | "CHANGELOG.md", "package.json", "package-lock.json"
32 | ],
33 | "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
34 | }
35 | ],
36 | "@semantic-release/github"
37 | ]
38 | }
39 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/line_simpleline.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const lineSimpleLine: MbStyle = {
4 | version: 8,
5 | name: 'Simple Line',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'r0_sy0_st0',
14 | type: 'line',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | paint: {
18 | 'line-color': '#000000',
19 | 'line-width': 3,
20 | 'line-dasharray': [13, 37]
21 | },
22 | layout: {
23 | 'line-cap': 'round',
24 | 'line-join': 'miter'
25 | }
26 | }
27 | ],
28 | metadata: {
29 | 'geostyler:ref': {
30 | rules: [{
31 | name: 'Simple Line',
32 | symbolizers: [
33 | [
34 | 'r0_sy0_st0'
35 | ]
36 | ]
37 | }]
38 | }
39 | }
40 | };
41 |
42 | export default lineSimpleLine;
43 |
--------------------------------------------------------------------------------
/data/styles/multi_simpleline_simplefill.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const multiSimpleLineSimpleFill: Style = {
4 | name: 'Simple Line Simple Fill',
5 | rules: [{
6 | name: 'Simple Line Simple Fill',
7 | symbolizers: [{
8 | kind: 'Line',
9 | color: '#000000',
10 | width: 3,
11 | dasharray: [13, 37],
12 | cap: 'round',
13 | join: 'miter'
14 | }]
15 | },{
16 | name: 'Simple Line Simple Fill',
17 | symbolizers: [{
18 | kind: 'Fill',
19 | color: '#000000',
20 | opacity: 1
21 | }]
22 | }],
23 | metadata: {
24 | 'mapbox:ref': {
25 | sources: {
26 | testsource: {
27 | type: 'vector'
28 | }
29 | },
30 | sourceMapping: {
31 | testsource: [0, 1]
32 | },
33 | sourceLayerMapping: {
34 | foo: [0, 1]
35 | }
36 | }
37 | }
38 | };
39 |
40 | export default multiSimpleLineSimpleFill;
41 |
--------------------------------------------------------------------------------
/data/styles/fill_graphic_fill_mark.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const fillGraphicFillMark: Style = {
4 | name: 'Graphic Fill Mark',
5 | rules: [
6 | {
7 | name: 'Graphic Fill Mark',
8 | symbolizers: [{
9 | kind: 'Fill',
10 | graphicFill: {
11 | kind: 'Mark',
12 | wellKnownName: 'circle',
13 | opacity: 1,
14 | color: '#006C2B',
15 | rotate: 0,
16 | radius: 0.3,
17 | strokeOpacity: 1,
18 | strokeColor: '#000000',
19 | strokeWidth: 0.2
20 | }
21 | }
22 | ]
23 | }],
24 | metadata: {
25 | 'mapbox:ref': {
26 | sources: {
27 | testsource: {
28 | type: 'vector'
29 | }
30 | },
31 | sourceMapping: {
32 | testsource: [0]
33 | },
34 | sourceLayerMapping: {
35 | foo: [0]
36 | }
37 | }
38 | }
39 | };
40 |
41 | export default fillGraphicFillMark;
42 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/circle_simplecircle.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const circleSimpleCircle: MbStyle = {
4 | version: 8,
5 | name: 'Simple Circle',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'r0_sy0_st0',
14 | source: 'testsource',
15 | 'source-layer': 'foo',
16 | type: 'circle',
17 | paint: {
18 | 'circle-color': '#000000',
19 | 'circle-radius': 5,
20 | 'circle-opacity': 1,
21 | 'circle-stroke-width': 2,
22 | 'circle-stroke-color': '#FF0000',
23 | 'circle-stroke-opacity': 0.5
24 | }
25 | }
26 | ],
27 | metadata: {
28 | 'geostyler:ref': {
29 | rules: [{
30 | name: 'Simple Circle',
31 | symbolizers: [
32 | [
33 | 'r0_sy0_st0'
34 | ]
35 | ]
36 | }]
37 | }
38 | }
39 | };
40 |
41 | export default circleSimpleCircle;
42 |
--------------------------------------------------------------------------------
/data/mapbox/multi_simpleline_simplefill.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const multiSimpleLineSimpleFill: MbStyle = {
4 | version: 8,
5 | name: 'Simple Line Simple Fill',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'Simple Line Simple Fill',
14 | source: 'testsource',
15 | 'source-layer': 'foo',
16 | type: 'line',
17 | paint: {
18 | 'line-color': '#000000',
19 | 'line-width': 3,
20 | 'line-dasharray': [13, 37]
21 | },
22 | layout: {
23 | 'line-cap': 'round',
24 | 'line-join': 'miter'
25 | }
26 | }, {
27 | id: 'Simple Line Simple Fill',
28 | source: 'testsource',
29 | 'source-layer': 'foo',
30 | type: 'fill',
31 | paint: {
32 | 'fill-color': '#000000',
33 | 'fill-opacity': 1
34 | }
35 | }
36 | ]
37 | };
38 |
39 | export default multiSimpleLineSimpleFill;
40 |
--------------------------------------------------------------------------------
/data/styles/gs_expression_lookup.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/naming-convention */
2 | import { Style } from 'geostyler-style';
3 |
4 | const gs_expression_lookup: Style = {
5 | name: 'Expression Lookup',
6 | rules: [{
7 | name: 'length',
8 | symbolizers: [{
9 | kind: 'Mark',
10 | wellKnownName: 'circle',
11 | radius: {
12 | name: 'strLength',
13 | args: ['peter']
14 | }
15 | }]
16 | }, {
17 | name: 'slice',
18 | symbolizers: [{
19 | kind: 'Text',
20 | label: {
21 | name: 'strSubstring',
22 | args: ['peter', 0, 2]
23 | }
24 | }]
25 | }],
26 | metadata: {
27 | 'mapbox:ref': {
28 | sources: {
29 | testsource: {
30 | type: 'vector'
31 | }
32 | },
33 | sourceMapping: {
34 | testsource: [0, 1]
35 | },
36 | sourceLayerMapping: {
37 | foo: [0, 1]
38 | }
39 | }
40 | }
41 | };
42 |
43 | export default gs_expression_lookup;
44 |
--------------------------------------------------------------------------------
/data/styles/icon_simpleicon_mapboxapi.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const iconSimpleIcon: Style = {
4 | name: 'Simple Icon',
5 | rules: [{
6 | name: 'Simple Icon',
7 | symbolizers: [{
8 | kind: 'Icon',
9 | image: {
10 | source: 'https://api.mapbox.com/sprites/mapbox/streets-v8.png',
11 | position: [0, 0],
12 | size: [12, 12]
13 | }
14 | }]
15 | }],
16 | metadata: {
17 | 'mapbox:ref': {
18 | sources: {
19 | testsource: {
20 | type: 'vector'
21 | }
22 | },
23 | sourceMapping: {
24 | testsource: [0]
25 | },
26 | sourceLayerMapping: {
27 | foo: [0]
28 | },
29 | sprite: {
30 | poi: {
31 | position: [
32 | 0,
33 | 0,
34 | ],
35 | size: [
36 | 12,
37 | 12,
38 | ],
39 | },
40 | },
41 | }
42 | }
43 | };
44 |
45 | export default iconSimpleIcon;
46 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/point_placeholderText.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const pointPlaceholderText: MbStyle = {
4 | version: 8,
5 | name: 'Placeholder Text',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'r0_sy0_st0',
14 | type: 'symbol',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | layout: {
18 | 'text-field': ['format',
19 | 'Area: ', {},
20 | ['get', 'area'], {},
21 | 'km2', {}
22 | ]
23 | },
24 | paint: {
25 | 'text-color': '#000000',
26 | 'text-opacity': 1
27 | }
28 | }
29 | ],
30 | metadata: {
31 | 'geostyler:ref': {
32 | rules: [{
33 | name: 'Placeholder Text',
34 | symbolizers: [
35 | [
36 | 'r0_sy0_st0'
37 | ]
38 | ]
39 | }]
40 | }
41 | }
42 | };
43 |
44 | export default pointPlaceholderText;
45 |
--------------------------------------------------------------------------------
/data/styles/color_rgba.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const colorRgba: Style = {
4 | name: 'Color RGBA',
5 | rules: [{
6 | name: 'Color RGBA',
7 | symbolizers: [{
8 | kind: 'Mark',
9 | wellKnownName: 'circle',
10 | color: '#000000',
11 | strokeColor: {
12 | name: 'case',
13 | args: [
14 | '#00ff00', {
15 | case: {
16 | name: 'lessThan',
17 | args: [{
18 | name: 'property',
19 | args: ['mag']
20 | }, 2]
21 | },
22 | value: '#ff0000'
23 | }
24 | ]
25 | }
26 | }]
27 | }],
28 | metadata: {
29 | 'mapbox:ref': {
30 | sources: {
31 | testsource: {
32 | type: 'vector'
33 | }
34 | },
35 | sourceMapping: {
36 | testsource: [0]
37 | },
38 | sourceLayerMapping: {
39 | foo: [0]
40 | }
41 | }
42 | }
43 | };
44 |
45 | export default colorRgba;
46 |
--------------------------------------------------------------------------------
/data/styles/icon_simpleicon.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const iconSimpleIcon: Style = {
4 | name: 'Simple Icon',
5 | rules: [{
6 | name: 'Simple Icon',
7 | symbolizers: [{
8 | kind: 'Icon',
9 | image: {
10 | source: 'https://testurl.com/sprites/mysprite.png',
11 | position: [0, 0],
12 | size: [12, 12]
13 | },
14 | size: 24
15 | }]
16 | }],
17 | metadata: {
18 | 'mapbox:ref': {
19 | sources: {
20 | testsource: {
21 | type: 'vector'
22 | }
23 | },
24 | sourceMapping: {
25 | testsource: [0]
26 | },
27 | sourceLayerMapping: {
28 | foo: [0]
29 | },
30 | sprite: {
31 | poi: {
32 | 'icon-size': 2,
33 | position: [
34 | 0,
35 | 0,
36 | ],
37 | size: [
38 | 12,
39 | 12,
40 | ],
41 | },
42 | },
43 | }
44 | }
45 | };
46 |
47 | export default iconSimpleIcon;
48 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/line_patternline.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const linePatternLine: MbStyle = {
4 | version: 8,
5 | name: 'Pattern Line',
6 | sprite: 'https://testurl.com/sprites/mysprite',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | id: 'r0_sy0_st0',
15 | type: 'line',
16 | source: 'testsource',
17 | 'source-layer': 'foo',
18 | paint: {
19 | 'line-color': '#000000',
20 | 'line-width': 3,
21 | 'line-dasharray': [13, 37],
22 | 'line-pattern': 'poi'
23 | },
24 | layout: {
25 | 'line-cap': 'round',
26 | 'line-join': 'miter'
27 | }
28 | }
29 | ],
30 | metadata: {
31 | 'geostyler:ref': {
32 | rules: [{
33 | name: 'Pattern Line',
34 | symbolizers: [
35 | [
36 | 'r0_sy0_st0'
37 | ]
38 | ]
39 | }]
40 | }
41 | }
42 | };
43 |
44 | export default linePatternLine;
45 |
--------------------------------------------------------------------------------
/data/styles/gs_expression_property.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/naming-convention */
2 | import { Style } from 'geostyler-style';
3 |
4 | const gs_expression_property: Style = {
5 | name: 'Expression Get',
6 | rules: [{
7 | name: 'Expression Get',
8 | symbolizers: [{
9 | kind: 'Mark',
10 | wellKnownName: 'circle',
11 | color: '#000000',
12 | radius: {
13 | name: 'property',
14 | args: ['population']
15 | },
16 | fillOpacity: {
17 | name: 'property',
18 | args: ['population_density']
19 | },
20 | strokeWidth: 2,
21 | strokeColor: '#FF0000',
22 | strokeOpacity: 0.5
23 | }]
24 | }],
25 | metadata: {
26 | 'mapbox:ref': {
27 | sources: {
28 | testsource: {
29 | type: 'vector'
30 | }
31 | },
32 | sourceMapping: {
33 | testsource: [0]
34 | },
35 | sourceLayerMapping: {
36 | foo: [0]
37 | }
38 | }
39 | }
40 | };
41 |
42 | export default gs_expression_property;
43 |
--------------------------------------------------------------------------------
/data/styles/line_simpleline_basefilter.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const lineSimpleLine: Style = {
4 | name: 'Small populated New Yorks',
5 | rules: [{
6 | filter: ['&&',
7 | ['==', 'NAME', 'New York'],
8 | ['==', 'TEST_BOOL', 'true'],
9 | ['==', 'TEST', null],
10 | ['*=', 'TEST2', '*York*'],
11 | ['*=', 'TEST1', '*New*'],
12 | ['!', ['>', 'POPULATION', '100000']],
13 | ['||',
14 | ['==', 'TEST2', '1'],
15 | ['==', 'TEST2', '2']
16 | ]
17 | ],
18 | name: 'Small populated New Yorks',
19 | symbolizers: [{
20 | kind: 'Line',
21 | color: '#FF0000',
22 | width: 3
23 | }]
24 | }],
25 | metadata: {
26 | 'mapbox:ref': {
27 | sources: {
28 | testsource: {
29 | type: 'vector'
30 | }
31 | },
32 | sourceMapping: {
33 | testsource: [0]
34 | },
35 | sourceLayerMapping: {
36 | foo: [0]
37 | }
38 | }
39 | }
40 | };
41 |
42 | export default lineSimpleLine;
43 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: jansule, KaiVolland
7 |
8 | ---
9 |
10 | # Bug
11 |
12 | **Describe the bug**
13 | A clear and concise description of what the bug is.
14 |
15 | **To Reproduce**
16 | Steps to reproduce the behavior:
17 | 1. Go to '...'
18 | 2. Click on '....'
19 | 3. Scroll down to '....'
20 | 4. See error
21 |
22 | **Expected behavior**
23 | A clear and concise description of what you expected to happen.
24 |
25 | **Screenshots**
26 | If applicable, add screenshots to help explain your problem.
27 |
28 | **Desktop (please complete the following information):**
29 | - OS: [e.g. iOS]
30 | - Browser [e.g. chrome, safari]
31 | - Version [e.g. 22]
32 |
33 | **Smartphone (please complete the following information):**
34 | - Device: [e.g. iPhone6]
35 | - OS: [e.g. iOS8.1]
36 | - Browser [e.g. stock browser, safari]
37 | - Version [e.g. 22]
38 |
39 | **Additional context**
40 | Add any other context about the problem here.
41 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/icontext_symbolizer.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const iconTextSymbolizer: MbStyle = {
4 | version: 8,
5 | name: 'icontext symbolizer',
6 | sprite: 'https://testurl.com/sprites/mysprite',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | type: 'symbol',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | paint: {
18 | 'text-color': '#2d2d2d',
19 | },
20 | layout: {
21 | 'text-field': '{name}',
22 | 'text-size': 12,
23 | 'icon-image': 'poi',
24 | visibility: 'visible',
25 | },
26 | id: 'r0_sy0_st0',
27 | }
28 | ],
29 | metadata: {
30 | 'geostyler:ref': {
31 | rules: [
32 | {
33 | name: 'label and icon',
34 | symbolizers: [
35 | [
36 | 'r0_sy0_st0',
37 | ]
38 | ],
39 | },
40 | ],
41 | },
42 | },
43 | };
44 |
45 | export default iconTextSymbolizer;
46 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/expression_get.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/naming-convention */
2 | import { MbStyle } from '../../src/MapboxStyleParser';
3 |
4 | const expression_get: MbStyle = {
5 | version: 8,
6 | name: 'Expression Get',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | id: 'r0_sy0_st0',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | type: 'circle',
18 | paint: {
19 | 'circle-color': '#000000',
20 | 'circle-radius': ['get', 'population'],
21 | 'circle-opacity': ['get', 'population_density'],
22 | 'circle-stroke-width': 2,
23 | 'circle-stroke-color': '#FF0000',
24 | 'circle-stroke-opacity': 0.5
25 | }
26 | }
27 | ],
28 | metadata: {
29 | 'geostyler:ref': {
30 | rules: [{
31 | name: 'Expression Get',
32 | symbolizers: [
33 | [
34 | 'r0_sy0_st0'
35 | ]
36 | ]
37 | }]
38 | }
39 | }
40 | };
41 |
42 | export default expression_get;
43 |
--------------------------------------------------------------------------------
/data/mapbox/expression_case.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/naming-convention */
2 | import { MbStyle } from '../../src/MapboxStyleParser';
3 |
4 | const expression_case: MbStyle = {
5 | version: 8,
6 | name: 'Expression Case',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | id: 'earthquake_circle',
15 | type: 'circle',
16 | source: 'testsource',
17 | 'source-layer': 'foo',
18 | paint: {
19 | 'circle-color': [
20 | 'case',
21 | ['<', ['get', 'mag'], 2],
22 | '#fed976',
23 | ['all', ['>=', ['get', 'mag'], 2], ['<', ['get', 'mag'], 3]],
24 | '#feb24c',
25 | ['all', ['>=', ['get', 'mag'], 3], ['<', ['get', 'mag'], 4]],
26 | '#fd8d3c',
27 | ['all', ['>=', ['get', 'mag'], 4], ['<', ['get', 'mag'], 5]],
28 | '#fc4e2a',
29 | '#e31a1c'
30 | ],
31 | 'circle-opacity': 0.6,
32 | 'circle-radius': 12
33 | }
34 | }
35 | ]
36 | };
37 |
38 | export default expression_case;
39 |
--------------------------------------------------------------------------------
/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import tsParser from '@typescript-eslint/parser';
2 | import path from 'node:path';
3 | import { fileURLToPath } from 'node:url';
4 | import js from '@eslint/js';
5 | import { FlatCompat } from '@eslint/eslintrc';
6 |
7 | const filename = fileURLToPath(import.meta.url);
8 | const dirname = path.dirname(filename);
9 | const compat = new FlatCompat({
10 | baseDirectory: dirname,
11 | recommendedConfig: js.configs.recommended,
12 | allConfig: js.configs.all
13 | });
14 |
15 | export default [
16 | {
17 | ignores: ['eslint.config.mjs', 'dist/**', 'data/**', '.commitlintrc.cjs']
18 | },
19 | ...compat.extends('@terrestris/eslint-config-typescript'),
20 | {
21 | files: ['**/*.ts', '**/*.tsx', '*.mjs'],
22 | languageOptions: {
23 | parser: tsParser,
24 | parserOptions: {
25 | project: [
26 | 'tsconfig.json',
27 | 'tsconfig.test.json',
28 | ],
29 | tsconfigRootDir: dirname,
30 | }
31 | },
32 | },
33 | {
34 | rules: {
35 | '@typescript-eslint/switch-exhaustiveness-check': 'off'
36 | }
37 | }
38 | ];
39 |
--------------------------------------------------------------------------------
/data/styles/fill_patternfill.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const fillPatternFill: Style = {
4 | name: 'Pattern Fill',
5 | rules: [{
6 | name: 'Pattern Fill',
7 | symbolizers: [{
8 | kind: 'Fill',
9 | color: '#000000',
10 | opacity: 1,
11 | graphicFill: {
12 | kind: 'Icon',
13 | image: {
14 | source: 'https://testurl.com/sprites/mysprite.png',
15 | position: [0, 0],
16 | size: [12, 12]
17 | }
18 | }
19 | }]
20 | }],
21 | metadata: {
22 | 'mapbox:ref': {
23 | sources: {
24 | testsource: {
25 | type: 'vector'
26 | }
27 | },
28 | sourceMapping: {
29 | testsource: [0]
30 | },
31 | sourceLayerMapping: {
32 | foo: [0]
33 | },
34 | sprite: {
35 | poi: {
36 | position: [
37 | 0,
38 | 0,
39 | ],
40 | size: [
41 | 12,
42 | 12,
43 | ],
44 | },
45 | },
46 | }
47 | }
48 | };
49 |
50 | export default fillPatternFill;
51 |
--------------------------------------------------------------------------------
/data/mapbox/source_layer_mapping.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const sourceLayerMapping: MbStyle = {
4 | version: 8,
5 | name: 'SourceLayerMapping',
6 | sources: {
7 | first: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'Simple Circle 1',
14 | source: 'first',
15 | 'source-layer': 'foo',
16 | type: 'circle',
17 | paint: {
18 | 'circle-color': '#000000',
19 | 'circle-radius': 5,
20 | 'circle-opacity': 1,
21 | 'circle-stroke-width': 2,
22 | 'circle-stroke-color': '#FF0000',
23 | 'circle-stroke-opacity': 0.5
24 | }
25 | },
26 | {
27 | id: 'Simple Circle 2',
28 | source: 'first',
29 | 'source-layer': 'bar',
30 | type: 'circle',
31 | paint: {
32 | 'circle-color': '#000000',
33 | 'circle-radius': 5,
34 | 'circle-opacity': 1,
35 | 'circle-stroke-width': 2,
36 | 'circle-stroke-color': '#FF0000',
37 | 'circle-stroke-opacity': 0.5
38 | }
39 | }
40 | ]
41 | };
42 |
43 | export default sourceLayerMapping;
44 |
--------------------------------------------------------------------------------
/data/styles/source_layer_mapping.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const sourceLayerMapping: Style = {
4 | name: 'SourceLayerMapping',
5 | rules: [{
6 | name: 'Simple Circle 1',
7 | symbolizers: [{
8 | kind: 'Mark',
9 | wellKnownName: 'circle',
10 | color: '#000000',
11 | radius: 5,
12 | fillOpacity: 1,
13 | strokeWidth: 2,
14 | strokeColor: '#FF0000',
15 | strokeOpacity: 0.5
16 | }]
17 | }, {
18 | name: 'Simple Circle 2',
19 | symbolizers: [{
20 | kind: 'Mark',
21 | wellKnownName: 'circle',
22 | color: '#000000',
23 | radius: 5,
24 | fillOpacity: 1,
25 | strokeWidth: 2,
26 | strokeColor: '#FF0000',
27 | strokeOpacity: 0.5
28 | }]
29 | }],
30 | metadata: {
31 | 'mapbox:ref': {
32 | sources: {
33 | first: {
34 | type: 'vector'
35 | }
36 | },
37 | sourceMapping: {
38 | first: [0, 1]
39 | },
40 | sourceLayerMapping: {
41 | foo: [0],
42 | bar: [1]
43 | }
44 | }
45 | }
46 | };
47 |
48 | export default sourceLayerMapping;
49 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/expression_interpolate.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/naming-convention */
2 | import { MbStyle } from '../../src/MapboxStyleParser';
3 |
4 | const expression_case: MbStyle = {
5 | version: 8,
6 | name: 'Expression Interpolate',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | id: 'r0_sy0_st0',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | type: 'circle',
18 | paint: {
19 | 'circle-color': '#000000',
20 | 'circle-opacity': 0.6,
21 | 'circle-radius': [
22 | 'interpolate',
23 | ['linear'],
24 | ['get', 'population'],
25 | 12,
26 | 2,
27 | 15,
28 | 4,
29 | 19,
30 | 35
31 | ]
32 | }
33 | }
34 | ],
35 | metadata: {
36 | 'geostyler:ref': {
37 | rules: [{
38 | name: 'earthquake_circle',
39 | symbolizers: [
40 | [
41 | 'r0_sy0_st0'
42 | ]
43 | ]
44 | }]
45 | }
46 | }
47 | };
48 |
49 | export default expression_case;
50 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/line_simpleline_basefilter.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const lineSimpleLine: MbStyle = {
4 | version: 8,
5 | name: 'Small populated New Yorks',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [{
12 | id: 'r0_sy0_st0',
13 | source: 'testsource',
14 | 'source-layer': 'foo',
15 | type: 'line',
16 | filter: ['all',
17 | ['==', 'NAME', 'New York'],
18 | ['==', 'TEST_BOOL', 'true'],
19 | ['==', 'TEST', null],
20 | ['*=', 'TEST2', '*York*'],
21 | ['*=', 'TEST1', '*New*'],
22 | ['!', ['>', 'POPULATION', '100000']],
23 | ['any',
24 | ['==', 'TEST2', '1'],
25 | ['==', 'TEST2', '2']
26 | ]
27 | ],
28 | paint: {
29 | 'line-color': '#FF0000',
30 | 'line-width': 3
31 | }
32 | }],
33 | metadata: {
34 | 'geostyler:ref': {
35 | rules: [{
36 | name: 'Small populated New Yorks',
37 | symbolizers: [
38 | [
39 | 'r0_sy0_st0'
40 | ]
41 | ]
42 | }]
43 | }
44 | }
45 | };
46 |
47 | export default lineSimpleLine;
48 |
--------------------------------------------------------------------------------
/data/mapbox/source_mapping.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const sourceMapping: MbStyle = {
4 | version: 8,
5 | name: 'SourceMapping',
6 | sources: {
7 | first: {
8 | type: 'vector'
9 | },
10 | second: {
11 | type: 'vector'
12 | }
13 | },
14 | layers: [
15 | {
16 | id: 'Simple Circle 1',
17 | source: 'first',
18 | 'source-layer': 'foo',
19 | type: 'circle',
20 | paint: {
21 | 'circle-color': '#000000',
22 | 'circle-radius': 5,
23 | 'circle-opacity': 1,
24 | 'circle-stroke-width': 2,
25 | 'circle-stroke-color': '#FF0000',
26 | 'circle-stroke-opacity': 0.5
27 | }
28 | },
29 | {
30 | id: 'Simple Circle 2',
31 | source: 'second',
32 | 'source-layer': 'foo',
33 | type: 'circle',
34 | paint: {
35 | 'circle-color': '#000000',
36 | 'circle-radius': 5,
37 | 'circle-opacity': 1,
38 | 'circle-stroke-width': 2,
39 | 'circle-stroke-color': '#FF0000',
40 | 'circle-stroke-opacity': 0.5
41 | }
42 | }
43 | ]
44 | };
45 |
46 | export default sourceMapping;
47 |
--------------------------------------------------------------------------------
/data/styles/gs_expression_string.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/naming-convention */
2 | import { Style } from 'geostyler-style';
3 |
4 | const gs_expression_string: Style = {
5 | name: 'Expression String',
6 | rules: [{
7 | name: 'concat',
8 | symbolizers: [{
9 | kind: 'Text',
10 | label: {
11 | name: 'strConcat',
12 | args: ['Lukas', ' ', 'Podolski']
13 | }
14 | }]
15 | }, {
16 | name: 'downcase',
17 | symbolizers: [{
18 | kind: 'Text',
19 | label: {
20 | name: 'strToLowerCase',
21 | args: ['Peter']
22 | }
23 | }]
24 | }, {
25 | name: 'upcase',
26 | symbolizers: [{
27 | kind: 'Text',
28 | label: {
29 | name: 'strToUpperCase',
30 | args: ['peter']
31 | }
32 | }]
33 | }],
34 | metadata: {
35 | 'mapbox:ref': {
36 | sources: {
37 | testsource: {
38 | type: 'vector'
39 | }
40 | },
41 | sourceMapping: {
42 | testsource: [0, 1, 2]
43 | },
44 | sourceLayerMapping: {
45 | foo: [0, 1, 2]
46 | }
47 | }
48 | }
49 | };
50 |
51 | export default gs_expression_string;
52 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/fill_simple_outline.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const fillSimpleFillOutline: MbStyle = {
4 | version: 8,
5 | name: 'Simple Fill With outline',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [{
12 | id: 'r0_sy0_st0',
13 | source: 'testsource',
14 | 'source-layer': 'foo',
15 | type: 'fill',
16 | paint: {
17 | 'fill-color': '#ff0000'
18 | }
19 | },
20 | {
21 | id: 'r0_sy0_st1',
22 | source: 'testsource',
23 | 'source-layer': 'foo',
24 | type: 'line',
25 | paint: {
26 | 'line-opacity': 0.5,
27 | 'line-color': '#00ff00',
28 | 'line-width': 2,
29 | 'line-dasharray': [13, 37]
30 | },
31 | layout: {
32 | 'line-cap': 'butt',
33 | 'line-join': 'round'
34 | }
35 | }],
36 | metadata: {
37 | 'geostyler:ref': {
38 | rules: [{
39 | name: 'The name of my rule',
40 | symbolizers: [
41 | [
42 | 'r0_sy0_st0',
43 | 'r0_sy0_st1'
44 | ]
45 | ]
46 | }]
47 | }
48 | }
49 | };
50 |
51 | export default fillSimpleFillOutline;
52 |
--------------------------------------------------------------------------------
/data/styles/line_patternline.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const linePatternLine: Style = {
4 | name: 'Pattern Line',
5 | rules: [{
6 | name: 'Pattern Line',
7 | symbolizers: [{
8 | kind: 'Line',
9 | color: '#000000',
10 | width: 3,
11 | dasharray: [13, 37],
12 | cap: 'round',
13 | join: 'miter',
14 | graphicFill: {
15 | kind: 'Icon',
16 | image: {
17 | source: 'https://testurl.com/sprites/mysprite.png',
18 | position: [0, 0],
19 | size: [12, 12]
20 | }
21 | }
22 | }]
23 | }],
24 | metadata: {
25 | 'mapbox:ref': {
26 | sources: {
27 | testsource: {
28 | type: 'vector'
29 | }
30 | },
31 | sourceMapping: {
32 | testsource: [0]
33 | },
34 | sourceLayerMapping: {
35 | foo: [0]
36 | },
37 | sprite: {
38 | poi: {
39 | position: [
40 | 0,
41 | 0,
42 | ],
43 | size: [
44 | 12,
45 | 12,
46 | ],
47 | },
48 | },
49 | }
50 | }
51 | };
52 |
53 | export default linePatternLine;
54 |
--------------------------------------------------------------------------------
/data/styles/source_mapping.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const sourceMapping: Style = {
4 | name: 'SourceMapping',
5 | rules: [{
6 | name: 'Simple Circle 1',
7 | symbolizers: [{
8 | kind: 'Mark',
9 | wellKnownName: 'circle',
10 | color: '#000000',
11 | radius: 5,
12 | fillOpacity: 1,
13 | strokeWidth: 2,
14 | strokeColor: '#FF0000',
15 | strokeOpacity: 0.5
16 | }]
17 | }, {
18 | name: 'Simple Circle 2',
19 | symbolizers: [{
20 | kind: 'Mark',
21 | wellKnownName: 'circle',
22 | color: '#000000',
23 | radius: 5,
24 | fillOpacity: 1,
25 | strokeWidth: 2,
26 | strokeColor: '#FF0000',
27 | strokeOpacity: 0.5
28 | }]
29 | }],
30 | metadata: {
31 | 'mapbox:ref': {
32 | sources: {
33 | first: {
34 | type: 'vector'
35 | },
36 | second: {
37 | type: 'vector'
38 | }
39 | },
40 | sourceMapping: {
41 | first: [0],
42 | second: [1]
43 | },
44 | sourceLayerMapping: {
45 | foo: [0, 1]
46 | }
47 | }
48 | }
49 | };
50 |
51 | export default sourceMapping;
52 |
--------------------------------------------------------------------------------
/data/styles/gs_expression_interpolate.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/naming-convention */
2 | import { Style } from 'geostyler-style';
3 |
4 | const gsExpressionInterpolate: Style = {
5 | name: 'Expression Interpolate',
6 | rules: [{
7 | name: 'earthquake_circle',
8 | symbolizers: [{
9 | kind: 'Mark',
10 | wellKnownName: 'circle',
11 | color: '#000000',
12 | fillOpacity: 0.6,
13 | radius: {
14 | name: 'interpolate',
15 | args: [{
16 | name: 'linear'
17 | }, {
18 | name: 'property',
19 | args: ['population']
20 | }, {
21 | stop: 12,
22 | value: 2
23 | }, {
24 | stop: 15,
25 | value: 4
26 | }, {
27 | stop: 19,
28 | value: 35
29 | }]
30 | }
31 | }]
32 | }],
33 | metadata: {
34 | 'mapbox:ref': {
35 | sources: {
36 | testsource: {
37 | type: 'vector'
38 | }
39 | },
40 | sourceMapping: {
41 | testsource: [0]
42 | },
43 | sourceLayerMapping: {
44 | foo: [0]
45 | }
46 | }
47 | }
48 | };
49 |
50 | export default gsExpressionInterpolate;
51 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/expression_lookup.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/naming-convention */
2 | import { MbStyle } from '../../src/MapboxStyleParser';
3 |
4 | const expression_lookup: MbStyle = {
5 | version: 8,
6 | name: 'Expression Lookup',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | id: 'r0_sy0_st0',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | type: 'circle',
18 | paint: {
19 | 'circle-radius': ['length', 'peter']
20 | }
21 | },
22 | {
23 | id: 'r1_sy0_st0',
24 | source: 'testsource',
25 | 'source-layer': 'foo',
26 | type: 'symbol',
27 | layout: {
28 | 'text-field': ['slice', 'peter', 0, 2]
29 | }
30 | }
31 | ],
32 | metadata: {
33 | 'geostyler:ref': {
34 | rules: [{
35 | name: 'length',
36 | symbolizers: [
37 | [
38 | 'r0_sy0_st0'
39 | ]
40 | ]
41 | }, {
42 | name: 'slice',
43 | symbolizers: [
44 | [
45 | 'r1_sy0_st0'
46 | ]
47 | ]
48 | }]
49 | }
50 | }
51 | };
52 |
53 | export default expression_lookup;
54 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/expression_case.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/naming-convention */
2 | import { MbStyle } from '../../src/MapboxStyleParser';
3 |
4 | const expression_case: MbStyle = {
5 | version: 8,
6 | name: 'Expression Case',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | id: 'r0_sy0_st0',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | type: 'circle',
18 | paint: {
19 | 'circle-color': [
20 | 'case',
21 | ['<', ['get', 'mag'], 2],
22 | '#fed976',
23 | ['all', ['>=', ['get', 'mag'], 2], ['<', ['get', 'mag'], 3]],
24 | '#feb24c',
25 | ['all', ['>=', ['get', 'mag'], 3], ['<', ['get', 'mag'], 4]],
26 | '#fd8d3c',
27 | ['all', ['>=', ['get', 'mag'], 4], ['<', ['get', 'mag'], 5]],
28 | '#fc4e2a',
29 | '#e31a1c'
30 | ],
31 | 'circle-opacity': 0.6,
32 | 'circle-radius': 12
33 | }
34 | }
35 | ],
36 | metadata: {
37 | 'geostyler:ref': {
38 | rules: [{
39 | name: 'earthquake_circle',
40 | symbolizers: [
41 | [
42 | 'r0_sy0_st0'
43 | ]
44 | ]
45 | }]
46 | }
47 | }
48 | };
49 |
50 | export default expression_case;
51 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/multi_rule_line_fill.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const multiRuleLineFill: MbStyle = {
4 | version: 8,
5 | name: 'Rule Line Fill',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'r0_sy0_st0',
14 | source: 'testsource',
15 | 'source-layer': 'foo',
16 | type: 'line',
17 | paint: {
18 | 'line-color': '#000000',
19 | 'line-width': 3,
20 | 'line-dasharray': [13, 37]
21 | },
22 | layout: {
23 | 'line-cap': 'round',
24 | 'line-join': 'miter'
25 | }
26 | }, {
27 | id: 'r1_sy0_st0',
28 | source: 'testsource',
29 | 'source-layer': 'foo',
30 | type: 'fill',
31 | paint: {
32 | 'fill-color': '#000000',
33 | 'fill-opacity': 1
34 | }
35 | }
36 | ],
37 | metadata: {
38 | 'geostyler:ref': {
39 | rules: [{
40 | name: 'Line Rule',
41 | symbolizers: [
42 | [
43 | 'r0_sy0_st0'
44 | ]
45 | ]
46 | },{
47 | name: 'Fill Rule',
48 | symbolizers: [
49 | [
50 | 'r1_sy0_st0'
51 | ]
52 | ]
53 | }]
54 | }
55 | }
56 | };
57 |
58 | export default multiRuleLineFill;
59 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/multi_simpleline_simplefill.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const multiSimpleLineSimpleFill: MbStyle = {
4 | version: 8,
5 | name: 'Simple Line Simple Fill',
6 | sources: {
7 | testsource: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'r0_sy0_st0',
14 | source: 'testsource',
15 | 'source-layer': 'foo',
16 | type: 'line',
17 | paint: {
18 | 'line-color': '#000000',
19 | 'line-width': 3,
20 | 'line-dasharray': [13, 37]
21 | },
22 | layout: {
23 | 'line-cap': 'round',
24 | 'line-join': 'miter'
25 | }
26 | }, {
27 | id: 'r1_sy0_st0',
28 | source: 'testsource',
29 | 'source-layer': 'foo',
30 | type: 'fill',
31 | paint: {
32 | 'fill-color': '#000000',
33 | 'fill-opacity': 1
34 | }
35 | }
36 | ],
37 | metadata: {
38 | 'geostyler:ref': {
39 | rules: [{
40 | name: 'Simple Line Simple Fill',
41 | symbolizers: [
42 | [
43 | 'r0_sy0_st0'
44 | ]
45 | ]
46 | },{
47 | name: 'Simple Line Simple Fill',
48 | symbolizers: [
49 | [
50 | 'r1_sy0_st0'
51 | ]
52 | ]
53 | }]
54 | }
55 | }
56 | };
57 |
58 | export default multiSimpleLineSimpleFill;
59 |
--------------------------------------------------------------------------------
/data/styles_metadata/icontext_symbolizer.ts:
--------------------------------------------------------------------------------
1 | import { Style } from 'geostyler-style';
2 |
3 | const iconTextSymbolizer: Style = {
4 | name: 'icontext symbolizer',
5 | rules: [
6 | {
7 | name: 'label and icon',
8 | symbolizers: [
9 | {
10 | kind: 'Text',
11 | color: '#2d2d2d',
12 | label: '{{name}}',
13 | size: 12,
14 | visibility: true
15 | },
16 | {
17 | kind: 'Icon',
18 | visibility: true,
19 | image: {
20 | source: 'https://testurl.com/sprites/mysprite.png',
21 | position: [0, 0],
22 | size: [12, 12]
23 | }
24 | }
25 | ]
26 | }
27 | ],
28 | metadata: {
29 | 'mapbox:ref': {
30 | sources: {
31 | testsource: {
32 | type: 'vector'
33 | }
34 | },
35 | splitSymbolizers: [{
36 | rule: 0,
37 | symbolizers: [0, 1]
38 | }],
39 | sourceMapping: {
40 | testsource: [0]
41 | },
42 | sourceLayerMapping: {
43 | foo: [0]
44 | },
45 | sprite: {
46 | poi: {
47 | position: [
48 | 0,
49 | 0,
50 | ],
51 | size: [
52 | 12,
53 | 12,
54 | ],
55 | },
56 | },
57 | }
58 | }
59 | };
60 |
61 | export default iconTextSymbolizer;
62 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 2-Clause License
2 |
3 | Copyright (c) 2018, terrestris GmbH & Co. KG
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/source_layer_mapping.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const sourceLayerMapping: MbStyle = {
4 | version: 8,
5 | name: 'SourceLayerMapping',
6 | sources: {
7 | first: {
8 | type: 'vector'
9 | }
10 | },
11 | layers: [
12 | {
13 | id: 'r0_sy0_st0',
14 | source: 'first',
15 | 'source-layer': 'foo',
16 | type: 'circle',
17 | paint: {
18 | 'circle-color': '#000000',
19 | 'circle-radius': 5,
20 | 'circle-opacity': 1,
21 | 'circle-stroke-width': 2,
22 | 'circle-stroke-color': '#FF0000',
23 | 'circle-stroke-opacity': 0.5
24 | }
25 | },
26 | {
27 | id: 'r1_sy0_st0',
28 | source: 'first',
29 | 'source-layer': 'bar',
30 | type: 'circle',
31 | paint: {
32 | 'circle-color': '#000000',
33 | 'circle-radius': 5,
34 | 'circle-opacity': 1,
35 | 'circle-stroke-width': 2,
36 | 'circle-stroke-color': '#FF0000',
37 | 'circle-stroke-opacity': 0.5
38 | }
39 | }
40 | ],
41 | metadata: {
42 | 'geostyler:ref': {
43 | rules: [{
44 | name: 'Simple Circle 1',
45 | symbolizers: [[
46 | 'r0_sy0_st0'
47 | ]]
48 | }, {
49 | name: 'Simple Circle 2',
50 | symbolizers: [[
51 | 'r1_sy0_st0'
52 | ]]
53 | }]
54 | }
55 | }
56 | };
57 |
58 | export default sourceLayerMapping;
59 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/source_mapping.ts:
--------------------------------------------------------------------------------
1 | import { MbStyle } from '../../src/MapboxStyleParser';
2 |
3 | const sourceMapping: MbStyle = {
4 | version: 8,
5 | name: 'SourceMapping',
6 | sources: {
7 | first: {
8 | type: 'vector'
9 | },
10 | second: {
11 | type: 'vector'
12 | }
13 | },
14 | layers: [
15 | {
16 | id: 'r0_sy0_st0',
17 | source: 'first',
18 | 'source-layer': 'foo',
19 | type: 'circle',
20 | paint: {
21 | 'circle-color': '#000000',
22 | 'circle-radius': 5,
23 | 'circle-opacity': 1,
24 | 'circle-stroke-width': 2,
25 | 'circle-stroke-color': '#FF0000',
26 | 'circle-stroke-opacity': 0.5
27 | }
28 | },
29 | {
30 | id: 'r1_sy0_st0',
31 | source: 'second',
32 | 'source-layer': 'foo',
33 | type: 'circle',
34 | paint: {
35 | 'circle-color': '#000000',
36 | 'circle-radius': 5,
37 | 'circle-opacity': 1,
38 | 'circle-stroke-width': 2,
39 | 'circle-stroke-color': '#FF0000',
40 | 'circle-stroke-opacity': 0.5
41 | }
42 | }
43 | ],
44 | metadata: {
45 | 'geostyler:ref': {
46 | rules: [{
47 | name: 'Simple Circle 1',
48 | symbolizers: [[
49 | 'r0_sy0_st0'
50 | ]]
51 | }, {
52 | name: 'Simple Circle 2',
53 | symbolizers: [[
54 | 'r1_sy0_st0'
55 | ]]
56 | }]
57 | }
58 | }
59 | };
60 |
61 | export default sourceMapping;
62 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/expression_string.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/naming-convention */
2 | import { MbStyle } from '../../src/MapboxStyleParser';
3 |
4 | const expression_string: MbStyle = {
5 | version: 8,
6 | name: 'Expression String',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | id: 'r0_sy0_st0',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | type: 'symbol',
18 | layout: {
19 | 'text-field': [
20 | 'concat',
21 | 'Lukas',
22 | ' ',
23 | 'Podolski'
24 | ]
25 | }
26 | }, {
27 | id: 'r1_sy0_st0',
28 | source: 'testsource',
29 | 'source-layer': 'foo',
30 | type: 'symbol',
31 | layout: {
32 | 'text-field': [
33 | 'downcase',
34 | 'Peter'
35 | ]
36 | }
37 | }, {
38 | id: 'r2_sy0_st0',
39 | source: 'testsource',
40 | 'source-layer': 'foo',
41 | type: 'symbol',
42 | layout: {
43 | 'text-field': [
44 | 'upcase',
45 | 'peter'
46 | ]
47 | }
48 | }
49 | ],
50 | metadata: {
51 | 'geostyler:ref': {
52 | rules: [{
53 | name: 'concat',
54 | symbolizers: [
55 | [
56 | 'r0_sy0_st0'
57 | ]
58 | ]
59 | }, {
60 | name: 'downcase',
61 | symbolizers: [
62 | [
63 | 'r1_sy0_st0'
64 | ]
65 | ]
66 | }, {
67 | name: 'upcase',
68 | symbolizers: [
69 | [
70 | 'r2_sy0_st0'
71 | ]
72 | ]
73 | }]
74 | }
75 | }
76 | };
77 |
78 | export default expression_string;
79 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "geostyler-mapbox-parser",
3 | "version": "6.2.0",
4 | "description": "GeoStyler-Style-Parser implementation for Mapbox",
5 | "type": "module",
6 | "main": "dist/MapboxStyleParser.js",
7 | "repository": {
8 | "type": "git",
9 | "url": "git+https://github.com/geostyler/geostyler-mapbox-parser.git"
10 | },
11 | "files": [
12 | "dist"
13 | ],
14 | "keywords": [
15 | "mapbox",
16 | "geostyler"
17 | ],
18 | "author": "",
19 | "license": "BSD-2-Clause",
20 | "bugs": {
21 | "url": "https://github.com/geostyler/geostyler-mapbox-parser/issues"
22 | },
23 | "homepage": "https://github.com/geostyler/geostyler-mapbox-parser#readme",
24 | "engines": {
25 | "node": ">=18",
26 | "npm": ">=9"
27 | },
28 | "dependencies": {
29 | "@types/mapbox-gl": "^3.4.1",
30 | "geostyler-style": "^10.5.0"
31 | },
32 | "scripts": {
33 | "build-browser": "vite build",
34 | "build-dist": "tsc",
35 | "build": "npm run build-browser && npm run build-dist",
36 | "lint:test:build": "npm run lint && npm run test && npm run build",
37 | "lint:test": "npm run lint && npm run test",
38 | "lint": "eslint -c eslint.config.mjs --ext .ts . && tsc --noEmit",
39 | "prepublishOnly": "npm run build",
40 | "prepare": "npm run build",
41 | "test-watch": "NODE_OPTIONS=--import=extensionless/register vitest",
42 | "test": "NODE_OPTIONS=--import=extensionless/register vitest --coverage run"
43 | },
44 | "devDependencies": {
45 | "@babel/polyfill": "^7.12.1",
46 | "@commitlint/cli": "^19.8.1",
47 | "@commitlint/config-conventional": "^19.8.1",
48 | "@semantic-release/changelog": "^6.0.3",
49 | "@semantic-release/git": "^10.0.1",
50 | "@stylistic/eslint-plugin": "^4.4.1",
51 | "@terrestris/eslint-config-typescript": "^9.0.0",
52 | "@types/lodash": "^4.17.17",
53 | "@types/node": "^22.15.29",
54 | "@typescript-eslint/eslint-plugin": "^8.33.1",
55 | "@typescript-eslint/eslint-plugin-tslint": "^7.0.2",
56 | "@typescript-eslint/parser": "^8.33.1",
57 | "@vitest/coverage-istanbul": "^3.2.1",
58 | "conventional-changelog-conventionalcommits": "^9.0.0",
59 | "eslint": "^9.28.0",
60 | "extensionless": "^1.9.9",
61 | "jest": "^29.7.0",
62 | "lodash": "^4.17.21",
63 | "semantic-release": "^25.0.2",
64 | "typescript": "^5.8.3",
65 | "vite": "^6.3.5",
66 | "vitest": "^3.2.1"
67 | },
68 | "funding": "https://opencollective.com/geostyler"
69 | }
70 |
--------------------------------------------------------------------------------
/data/styles/gs_expression_case.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/naming-convention */
2 | import { Style } from 'geostyler-style';
3 |
4 | const gs_expression_case: Style = {
5 | name: 'Expression Case',
6 | rules: [{
7 | name: 'earthquake_circle',
8 | symbolizers: [{
9 | kind: 'Mark',
10 | wellKnownName: 'circle',
11 | color: {
12 | name: 'case',
13 | args: ['#e31a1c', {
14 | case: {
15 | name: 'lessThan',
16 | args: [{
17 | name: 'property',
18 | args: ['mag']
19 | },
20 | 2]
21 | },
22 | value: '#fed976'
23 | }, {
24 | case: {
25 | name: 'all',
26 | args: [{
27 | name: 'greaterThanOrEqualTo',
28 | args: [{
29 | name: 'property',
30 | args: ['mag']
31 | },
32 | 2]
33 | }, {
34 | name: 'lessThan',
35 | args: [{
36 | name: 'property',
37 | args: ['mag']
38 | },
39 | 3]
40 | }]
41 | },
42 | value:'#feb24c'
43 | }, {
44 | case: {
45 | name: 'all',
46 | args: [{
47 | name: 'greaterThanOrEqualTo',
48 | args: [{
49 | name: 'property',
50 | args: ['mag']
51 | },
52 | 3]
53 | }, {
54 | name: 'lessThan',
55 | args: [{
56 | name: 'property',
57 | args: ['mag']
58 | },
59 | 4]
60 | }]
61 | },
62 | value:'#fd8d3c'
63 | }, {
64 | case: {
65 | name: 'all',
66 | args: [{
67 | name: 'greaterThanOrEqualTo',
68 | args: [{
69 | name: 'property',
70 | args: ['mag']
71 | },
72 | 4]
73 | }, {
74 | name: 'lessThan',
75 | args: [{
76 | name: 'property',
77 | args: ['mag']
78 | },
79 | 5]
80 | }]
81 | },
82 | value:'#fc4e2a'
83 | }]
84 | },
85 | radius: 12,
86 | fillOpacity: 0.6
87 | }]
88 | }],
89 | metadata: {
90 | 'mapbox:ref': {
91 | sources: {
92 | testsource: {
93 | type: 'vector'
94 | }
95 | },
96 | sourceMapping: {
97 | testsource: [0]
98 | },
99 | sourceLayerMapping: {
100 | foo: [0]
101 | }
102 | }
103 | }
104 | };
105 |
106 | export default gs_expression_case;
107 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # geostyler-mapbox-parser
2 |
3 | [](https://coveralls.io/github/geostyler/geostyler-mapbox-parser?branch=master)
4 | [](https://github.com/geostyler/geostyler-mapbox-parser/blob/master/LICENSE)
5 | [](https://www.npmjs.com/package/geostyler-mapbox-parser)
6 |
7 | GeoStyler-Style-Parser implementation for Mapbox
8 |
9 | ## :rocket: GeoStyler Code Sprint 2025
10 |
11 | We are happy to announce the next GeoStyler Code Sprint from **02.-06.06.2025** in Switzerland. Be part of it! More infos on https://geostyler.org/.
12 |
13 | ### Important Notes
14 | Since mapbox works with [spritesheets](https://docs.mapbox.com/api/maps/#sprites), geostyler-mapbox-parser is only capable of handling sprites/icons if the application that is using the parser implements following API:
15 |
16 | `GET /sprites/?name&baseurl`
17 | - `name` - name of the sprite in the spritesheet corresponding json
18 | - `baseurl` - baseurl for retrieving spritesheet and sprite json
19 |
20 | The endpoint MUST return a reference to a single image.
21 |
22 | ---
23 |
24 | Mapbox styles require the properties [`sources`](https://docs.mapbox.com/mapbox-gl-js/style-spec/#root-sources) (root property)
25 | and [`source`](https://docs.mapbox.com/mapbox-gl-js/style-spec/#layer-source) (layers property).
26 | In order to keep a clear separation between style and data, geostyler-mapbox-parser puts the source-related attributes into the metadata block of
27 | a geostyler-style under `mapbox:ref`. There, the original sources object, as well as the mappings between layers and sources will be stored
28 | (properties `sources`, `sourceMapping` and `layerSourceMapping`). Applications can then use these mappings for re-creating the same layer structure
29 | using their map library of choice (e.g. OpenLayers, etc.).
30 |
31 | ### How to use
32 |
33 | ES6:
34 | ```js
35 | import MapboxParser from "geostyler-mapbox-parser";
36 |
37 | const pointSimplePoint = {
38 | name: "My Style",
39 | rules: [
40 | {
41 | name: "My Rule",
42 | symbolizers: [
43 | {
44 | kind: "Mark",
45 | wellKnownName: "circle",
46 | color: "#FF0000",
47 | radius: 6
48 | }
49 | ]
50 | }
51 | ]
52 | };
53 |
54 | const parser = new MapboxParser();
55 |
56 | const { output: mbStyle } = await parser.writeStyle(pointSimplePoint);
57 | console.log(mbStyle);
58 | ```
59 |
60 | Browser:
61 |
62 | ```js
63 | const pointSimplePoint = {
64 | name: "My Style",
65 | rules: [
66 | {
67 | name: "My Rule",
68 | symbolizers: [
69 | {
70 | kind: "Mark",
71 | wellKnownName: "Circle",
72 | color: "#FF0000",
73 | radius: 6
74 | }
75 | ]
76 | }
77 | ]
78 | };
79 | var parser = new GeoStylerMapboxParser.MapboxStyleParser();
80 | parser
81 | .writeStyle(pointSimplePoint)
82 | .then(function(res) {
83 | var mbStyle = res.output;
84 | console.log(mbStyle);
85 | });
86 | ```
87 |
88 | ## Funding & financial sponsorship
89 |
90 | Maintenance and further development of this code can be funded through the
91 | [GeoStyler Open Collective](https://opencollective.com/geostyler). All contributions and
92 | expenses can transparently be reviewed by anyone; you see what we use the donated money for.
93 | Thank you for any financial support you give the GeoStyler project 💞
94 |
95 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/expression_decisions.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/naming-convention */
2 | import { MbStyle } from '../../src/MapboxStyleParser';
3 |
4 | const expression_decisions: MbStyle = {
5 | version: 8,
6 | name: 'Expression Decisions',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | id: 'r0_sy0_st0',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | type: 'circle',
18 | paint: {
19 | 'circle-color': [
20 | 'case',
21 | ['!', ['==', ['get', 'mag'], 1]],
22 | '#FFFFFF',
23 | '#000000'
24 | ]
25 | }
26 | },
27 | {
28 | id: 'r1_sy0_st0',
29 | source: 'testsource',
30 | 'source-layer': 'foo',
31 | type: 'circle',
32 | paint: {
33 | 'circle-color': [
34 | 'case',
35 | ['!=', ['get', 'mag'], 1],
36 | '#FFFFFF',
37 | '#000000'
38 | ]
39 | }
40 | },
41 | {
42 | id: 'r2_sy0_st0',
43 | source: 'testsource',
44 | 'source-layer': 'foo',
45 | type: 'circle',
46 | paint: {
47 | 'circle-color': [
48 | 'case',
49 | ['<', ['get', 'mag'], 1],
50 | '#FFFFFF',
51 | '#000000'
52 | ]
53 | }
54 | },
55 | {
56 | id: 'r3_sy0_st0',
57 | source: 'testsource',
58 | 'source-layer': 'foo',
59 | type: 'circle',
60 | paint: {
61 | 'circle-color': [
62 | 'case',
63 | ['<=', ['get', 'mag'], 1],
64 | '#FFFFFF',
65 | '#000000'
66 | ]
67 | }
68 | },
69 | {
70 | id: 'r4_sy0_st0',
71 | source: 'testsource',
72 | 'source-layer': 'foo',
73 | type: 'circle',
74 | paint: {
75 | 'circle-color': [
76 | 'case',
77 | ['==', ['get', 'mag'], 1],
78 | '#FFFFFF',
79 | '#000000'
80 | ]
81 | }
82 | },
83 | {
84 | id: 'r5_sy0_st0',
85 | source: 'testsource',
86 | 'source-layer': 'foo',
87 | type: 'circle',
88 | paint: {
89 | 'circle-color': [
90 | 'case',
91 | ['>', ['get', 'mag'], 1],
92 | '#FFFFFF',
93 | '#000000'
94 | ]
95 | }
96 | },
97 | {
98 | id: 'r6_sy0_st0',
99 | source: 'testsource',
100 | 'source-layer': 'foo',
101 | type: 'circle',
102 | paint: {
103 | 'circle-color': [
104 | 'case',
105 | ['>=', ['get', 'mag'], 1],
106 | '#FFFFFF',
107 | '#000000'
108 | ]
109 | }
110 | },
111 | {
112 | id: 'r7_sy0_st0',
113 | source: 'testsource',
114 | 'source-layer': 'foo',
115 | type: 'circle',
116 | paint: {
117 | 'circle-color': [
118 | 'case',
119 | ['all',
120 | ['>=', ['get', 'mag'], 1],
121 | ['<=', ['get', 'mag'], 2]
122 | ],
123 | '#FFFFFF',
124 | '#000000'
125 | ]
126 | }
127 | },
128 | {
129 | id: 'r8_sy0_st0',
130 | source: 'testsource',
131 | 'source-layer': 'foo',
132 | type: 'circle',
133 | paint: {
134 | 'circle-color': [
135 | 'case',
136 | ['any',
137 | ['==', ['get', 'mag'], 'a'],
138 | ['==', ['get', 'mag'], 'b']
139 | ],
140 | '#FFFFFF',
141 | '#000000'
142 | ]
143 | }
144 | }
145 | ],
146 | metadata: {
147 | 'geostyler:ref': {
148 | rules: [{
149 | name: 'negation',
150 | symbolizers: [
151 | [
152 | 'r0_sy0_st0'
153 | ]
154 | ]
155 | }, {
156 | name: 'not equal to',
157 | symbolizers: [
158 | [
159 | 'r1_sy0_st0'
160 | ]
161 | ]
162 | }, {
163 | name: 'less than',
164 | symbolizers: [
165 | [
166 | 'r2_sy0_st0'
167 | ]
168 | ]
169 | }, {
170 | name: 'less than or equal to',
171 | symbolizers: [
172 | [
173 | 'r3_sy0_st0'
174 | ]
175 | ]
176 | }, {
177 | name: 'equal to',
178 | symbolizers: [
179 | [
180 | 'r4_sy0_st0'
181 | ]
182 | ]
183 | }, {
184 | name: 'greater than',
185 | symbolizers: [
186 | [
187 | 'r5_sy0_st0'
188 | ]
189 | ]
190 | }, {
191 | name: 'greater than or equal to',
192 | symbolizers: [
193 | [
194 | 'r6_sy0_st0'
195 | ]
196 | ]
197 | }, {
198 | name: 'all',
199 | symbolizers: [
200 | [
201 | 'r7_sy0_st0'
202 | ]
203 | ]
204 | }, {
205 | name: 'any',
206 | symbolizers: [
207 | [
208 | 'r8_sy0_st0'
209 | ]
210 | ]
211 | }]
212 | }
213 | }
214 | };
215 |
216 | export default expression_decisions;
217 |
--------------------------------------------------------------------------------
/data/styles/gs_expression_math.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/naming-convention */
2 | import { Style } from 'geostyler-style';
3 |
4 | const gs_expression_math: Style = {
5 | name: 'Expression Math',
6 | rules: [{
7 | name: 'add',
8 | symbolizers: [{
9 | kind: 'Mark',
10 | wellKnownName: 'circle',
11 | radius: {
12 | name: 'add',
13 | args: [13, 3, 7]
14 | }
15 | }]
16 | }, {
17 | name: 'abs',
18 | symbolizers: [{
19 | kind: 'Mark',
20 | wellKnownName: 'circle',
21 | radius: {
22 | name: 'abs',
23 | args: [-12]
24 | }
25 | }]
26 | }, {
27 | name: 'acos',
28 | symbolizers: [{
29 | kind: 'Mark',
30 | wellKnownName: 'circle',
31 | radius: {
32 | name: 'acos',
33 | args: [4]
34 | }
35 | }]
36 | }, {
37 | name: 'asin',
38 | symbolizers: [{
39 | kind: 'Mark',
40 | wellKnownName: 'circle',
41 | radius: {
42 | name: 'asin',
43 | args: [4]
44 | }
45 | }]
46 | }, {
47 | name: 'atan',
48 | symbolizers: [{
49 | kind: 'Mark',
50 | wellKnownName: 'circle',
51 | radius: {
52 | name: 'atan',
53 | args: [4]
54 | }
55 | }]
56 | }, {
57 | name: 'ceil',
58 | symbolizers: [{
59 | kind: 'Mark',
60 | wellKnownName: 'circle',
61 | radius: {
62 | name: 'ceil',
63 | args: [3.4]
64 | }
65 | }]
66 | }, {
67 | name: 'cos',
68 | symbolizers: [{
69 | kind: 'Mark',
70 | wellKnownName: 'circle',
71 | radius: {
72 | name: 'cos',
73 | args: [3.4]
74 | }
75 | }]
76 | }, {
77 | name: 'div',
78 | symbolizers: [{
79 | kind: 'Mark',
80 | wellKnownName: 'circle',
81 | radius: {
82 | name: 'div',
83 | args: [100, 2]
84 | }
85 | }]
86 | }, {
87 | name: 'exp',
88 | symbolizers: [{
89 | kind: 'Mark',
90 | wellKnownName: 'circle',
91 | radius: {
92 | name: 'exp',
93 | args: [1]
94 | }
95 | }]
96 | }, {
97 | name: 'floor',
98 | symbolizers: [{
99 | kind: 'Mark',
100 | wellKnownName: 'circle',
101 | radius: {
102 | name: 'floor',
103 | args: [3.5]
104 | }
105 | }]
106 | }, {
107 | name: 'log',
108 | symbolizers: [{
109 | kind: 'Mark',
110 | wellKnownName: 'circle',
111 | radius: {
112 | name: 'log',
113 | args: [4.6]
114 | }
115 | }]
116 | }, {
117 | name: 'max',
118 | symbolizers: [{
119 | kind: 'Mark',
120 | wellKnownName: 'circle',
121 | radius: {
122 | name: 'max',
123 | args: [13, 37, 0, 8, 15]
124 | }
125 | }]
126 | }, {
127 | name: 'min',
128 | symbolizers: [{
129 | kind: 'Mark',
130 | wellKnownName: 'circle',
131 | radius: {
132 | name: 'min',
133 | args: [13, 37, 0, 8, 15]
134 | }
135 | }]
136 | }, {
137 | name: 'modulo',
138 | symbolizers: [{
139 | kind: 'Mark',
140 | wellKnownName: 'circle',
141 | radius: {
142 | name: 'modulo',
143 | args: [3, 2]
144 | }
145 | }]
146 | }, {
147 | name: 'mul',
148 | symbolizers: [{
149 | kind: 'Mark',
150 | wellKnownName: 'circle',
151 | radius: {
152 | name: 'mul',
153 | args: [2, 2.5, 10]
154 | }
155 | }]
156 | }, {
157 | name: 'pi',
158 | symbolizers: [{
159 | kind: 'Mark',
160 | wellKnownName: 'circle',
161 | radius: {
162 | name: 'pi'
163 | }
164 | }]
165 | }, {
166 | name: 'pow',
167 | symbolizers: [{
168 | kind: 'Mark',
169 | wellKnownName: 'circle',
170 | radius: {
171 | name: 'pow',
172 | args: [2, 4]
173 | }
174 | }]
175 | }, {
176 | name: 'round',
177 | symbolizers: [{
178 | kind: 'Mark',
179 | wellKnownName: 'circle',
180 | radius: {
181 | name: 'round',
182 | args: [13.37]
183 | }
184 | }]
185 | }, {
186 | name: 'sin',
187 | symbolizers: [{
188 | kind: 'Mark',
189 | wellKnownName: 'circle',
190 | radius: {
191 | name: 'sin',
192 | args: [1]
193 | }
194 | }]
195 | }, {
196 | name: 'sqrt',
197 | symbolizers: [{
198 | kind: 'Mark',
199 | wellKnownName: 'circle',
200 | radius: {
201 | name: 'sqrt',
202 | args: [1]
203 | }
204 | }]
205 | }, {
206 | name: 'sub',
207 | symbolizers: [{
208 | kind: 'Mark',
209 | wellKnownName: 'circle',
210 | radius: {
211 | name: 'sub',
212 | args: [5, 6]
213 | }
214 | }]
215 | }, {
216 | name: 'tan',
217 | symbolizers: [{
218 | kind: 'Mark',
219 | wellKnownName: 'circle',
220 | radius: {
221 | name: 'tan',
222 | args: [1]
223 | }
224 | }]
225 | }],
226 | metadata: {
227 | 'mapbox:ref': {
228 | sources: {
229 | testsource: {
230 | type: 'vector'
231 | }
232 | },
233 | sourceMapping: {
234 | testsource: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]
235 | },
236 | sourceLayerMapping: {
237 | foo: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]
238 | }
239 | }
240 | }
241 | };
242 |
243 | export default gs_expression_math;
244 |
--------------------------------------------------------------------------------
/src/Expressions.spec.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable camelcase */
2 | import { beforeEach, expect, it, describe } from 'vitest';
3 |
4 | import expression_case from '../data/mapbox/expression_case';
5 | import expression_case_metadata from '../data/mapbox_metadata/expression_case';
6 | import expression_get from '../data/mapbox/expression_get';
7 | import expression_get_metadata from '../data/mapbox_metadata/expression_get';
8 | import gs_expression_case from '../data/styles/gs_expression_case';
9 | import gs_expression_property from '../data/styles/gs_expression_property';
10 | import MapboxStyleParser from './MapboxStyleParser';
11 | import expression_decisions_metadata from '../data/mapbox_metadata/expression_decisions';
12 | import gs_expression_decisions from '../data/styles/gs_expression_decisions';
13 | import gs_expression_math from '../data/styles/gs_expression_math';
14 | import expression_math_metadata from '../data/mapbox_metadata/expression_math';
15 | import gs_expression_string from '../data/styles/gs_expression_string';
16 | import expression_string_metadata from '../data/mapbox_metadata/expression_string';
17 | import expression_lookup_metadata from '../data/mapbox_metadata/expression_lookup';
18 | import gs_expression_lookup from '../data/styles/gs_expression_lookup';
19 | import gs_expression_interpolate from '../data/styles/gs_expression_interpolate';
20 | import expression_interpolate from '../data/mapbox/expression_interpolate';
21 | import expression_interpolate_metadata from '../data/mapbox_metadata/expression_interpolate';
22 |
23 | describe('MapboxStyleParser can parse Expressions', () => {
24 | let styleParser: MapboxStyleParser;
25 |
26 | beforeEach(() => {
27 | styleParser = new MapboxStyleParser();
28 | });
29 |
30 | describe('#readStyle', () => {
31 | it('can read the "case" expression', async () => {
32 | const { output: geoStylerStyle } = await styleParser.readStyle(expression_case);
33 | expect(geoStylerStyle).toBeDefined();
34 | expect(geoStylerStyle).toEqual(gs_expression_case);
35 | return;
36 | });
37 | it('can read the "decision" expressions', async () => {
38 | const { output: geoStylerStyle } = await styleParser.readStyle(expression_decisions_metadata);
39 | expect(geoStylerStyle).toBeDefined();
40 | expect(geoStylerStyle).toEqual(gs_expression_decisions);
41 | return;
42 | });
43 | it('can read the "get" expression', async () => {
44 | const { output: geoStylerStyle } = await styleParser.readStyle(expression_get);
45 | expect(geoStylerStyle).toBeDefined();
46 | expect(geoStylerStyle).toEqual(gs_expression_property);
47 | return;
48 | });
49 | it('can read the "lookup" expressions', async () => {
50 | const { output: geoStylerStyle } = await styleParser.readStyle(expression_lookup_metadata);
51 | expect(geoStylerStyle).toBeDefined();
52 | expect(geoStylerStyle).toEqual(gs_expression_lookup);
53 | return;
54 | });
55 | it('can read the "math" expressions', async () => {
56 | const { output: geoStylerStyle } = await styleParser.readStyle(expression_math_metadata);
57 | expect(geoStylerStyle).toBeDefined();
58 | expect(geoStylerStyle).toEqual(gs_expression_math);
59 | return;
60 | });
61 | it('can read the "string" expressions', async () => {
62 | const { output: geoStylerStyle } = await styleParser.readStyle(expression_math_metadata);
63 | expect(geoStylerStyle).toBeDefined();
64 | expect(geoStylerStyle).toEqual(gs_expression_math);
65 | return;
66 | });
67 |
68 | it('can read the "interpolate" expressions', async () => {
69 | const { output: geostylerStyle } = await styleParser.readStyle(expression_interpolate);
70 | expect(geostylerStyle).toBeDefined();
71 | expect(geostylerStyle).toEqual(gs_expression_interpolate);
72 | });
73 | });
74 |
75 | describe('#writeStyle', () => {
76 | it('can write the "case" expression', async () => {
77 | const { output: mbStyle } = await styleParser.writeStyle(gs_expression_case);
78 | expect(mbStyle).toBeDefined();
79 | expect(mbStyle).toEqual(expression_case_metadata);
80 | return;
81 | });
82 | it('can write the "decision" expressions', async () => {
83 | const { output: mbStyle } = await styleParser.writeStyle(gs_expression_decisions);
84 | expect(mbStyle).toBeDefined();
85 | expect(mbStyle).toEqual(expression_decisions_metadata);
86 | return;
87 | });
88 | it('can write the "lookup" expressions', async () => {
89 | const { output: mbStyle } = await styleParser.writeStyle(gs_expression_lookup);
90 | expect(mbStyle).toBeDefined();
91 | expect(mbStyle).toEqual(expression_lookup_metadata);
92 | return;
93 | });
94 | it('can write the "math" expressions', async () => {
95 | const { output: mbStyle } = await styleParser.writeStyle(gs_expression_math);
96 | expect(mbStyle).toBeDefined();
97 | expect(mbStyle).toEqual(expression_math_metadata);
98 | return;
99 | });
100 | it('can write the "property" expression', async () => {
101 | const { output: mbStyle } = await styleParser.writeStyle(gs_expression_property);
102 | expect(mbStyle).toBeDefined();
103 | expect(mbStyle).toEqual(expression_get_metadata);
104 | return;
105 | });
106 | it('can write the "string" expression', async () => {
107 | const { output: mbStyle } = await styleParser.writeStyle(gs_expression_string);
108 | expect(mbStyle).toBeDefined();
109 | expect(mbStyle).toEqual(expression_string_metadata);
110 | return;
111 | });
112 | it('can write the "interpolate" expression', async () => {
113 | const { output: mbStyle } = await styleParser.writeStyle(gs_expression_interpolate);
114 | expect(mbStyle).toBeDefined();
115 | expect(mbStyle).toEqual(expression_interpolate_metadata);
116 | });
117 | });
118 | });
119 |
--------------------------------------------------------------------------------
/data/styles/gs_expression_decisions.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/naming-convention */
2 | import { Style } from 'geostyler-style';
3 |
4 | const gs_expression_decisions: Style = {
5 | name: 'Expression Decisions',
6 | rules: [{
7 | name: 'negation',
8 | symbolizers: [{
9 | kind: 'Mark',
10 | wellKnownName: 'circle',
11 | color: {
12 | name: 'case',
13 | args: [
14 | '#000000',
15 | {
16 | case: {
17 | name: 'not',
18 | args: [{
19 | name: 'equalTo',
20 | args: [{
21 | name: 'property',
22 | args: ['mag']
23 | }, 1]
24 | }]
25 | },
26 | value: '#FFFFFF'
27 | }
28 | ]
29 | }
30 | }]
31 | }, {
32 | name: 'not equal to',
33 | symbolizers: [{
34 | kind: 'Mark',
35 | wellKnownName: 'circle',
36 | color: {
37 | name: 'case',
38 | args: [
39 | '#000000',
40 | {
41 | case: {
42 | name: 'notEqualTo',
43 | args: [{
44 | name: 'property',
45 | args: ['mag']
46 | }, 1]
47 | },
48 | value: '#FFFFFF'
49 | }
50 | ]
51 | }
52 | }]
53 | }, {
54 | name: 'less than',
55 | symbolizers: [{
56 | kind: 'Mark',
57 | wellKnownName: 'circle',
58 | color: {
59 | name: 'case',
60 | args: [
61 | '#000000',
62 | {
63 | case: {
64 | name: 'lessThan',
65 | args: [{
66 | name: 'property',
67 | args: ['mag']
68 | }, 1]
69 | },
70 | value: '#FFFFFF'
71 | }
72 | ]
73 | }
74 | }]
75 | }, {
76 | name: 'less than or equal to',
77 | symbolizers: [{
78 | kind: 'Mark',
79 | wellKnownName: 'circle',
80 | color: {
81 | name: 'case',
82 | args: [
83 | '#000000',
84 | {
85 | case: {
86 | name: 'lessThanOrEqualTo',
87 | args: [{
88 | name: 'property',
89 | args: ['mag']
90 | }, 1]
91 | },
92 | value: '#FFFFFF'
93 | }
94 | ]
95 | }
96 | }]
97 | }, {
98 | name: 'equal to',
99 | symbolizers: [{
100 | kind: 'Mark',
101 | wellKnownName: 'circle',
102 | color: {
103 | name: 'case',
104 | args: [
105 | '#000000',
106 | {
107 | case: {
108 | name: 'equalTo',
109 | args: [{
110 | name: 'property',
111 | args: ['mag']
112 | }, 1]
113 | },
114 | value: '#FFFFFF'
115 | }
116 | ]
117 | }
118 | }]
119 | }, {
120 | name: 'greater than',
121 | symbolizers: [{
122 | kind: 'Mark',
123 | wellKnownName: 'circle',
124 | color: {
125 | name: 'case',
126 | args: [
127 | '#000000',
128 | {
129 | case: {
130 | name: 'greaterThan',
131 | args: [{
132 | name: 'property',
133 | args: ['mag']
134 | }, 1]
135 | },
136 | value: '#FFFFFF'
137 | }
138 | ]
139 | }
140 | }]
141 | }, {
142 | name: 'greater than or equal to',
143 | symbolizers: [{
144 | kind: 'Mark',
145 | wellKnownName: 'circle',
146 | color: {
147 | name: 'case',
148 | args: [
149 | '#000000',
150 | {
151 | case: {
152 | name: 'greaterThanOrEqualTo',
153 | args: [{
154 | name: 'property',
155 | args: ['mag']
156 | }, 1]
157 | },
158 | value: '#FFFFFF'
159 | }
160 | ]
161 | }
162 | }]
163 | }, {
164 | name: 'all',
165 | symbolizers: [{
166 | kind: 'Mark',
167 | wellKnownName: 'circle',
168 | color: {
169 | name: 'case',
170 | args: [
171 | '#000000',
172 | {
173 | case: {
174 | name: 'all',
175 | args: [
176 | {
177 | name: 'greaterThanOrEqualTo',
178 | args: [{
179 | name: 'property',
180 | args: ['mag']
181 | }, 1]
182 | },
183 | {
184 | name: 'lessThanOrEqualTo',
185 | args: [{
186 | name: 'property',
187 | args: ['mag']
188 | }, 2]
189 | }
190 | ]
191 | },
192 | value: '#FFFFFF'
193 | }
194 | ]
195 | }
196 | }]
197 | }, {
198 | name: 'any',
199 | symbolizers: [{
200 | kind: 'Mark',
201 | wellKnownName: 'circle',
202 | color: {
203 | name: 'case',
204 | args: [
205 | '#000000',
206 | {
207 | case: {
208 | name: 'any',
209 | args: [
210 | {
211 | name: 'equalTo',
212 | args: [{
213 | name: 'property',
214 | args: ['mag']
215 | }, 'a']
216 | },
217 | {
218 | name: 'equalTo',
219 | args: [{
220 | name: 'property',
221 | args: ['mag']
222 | }, 'b']
223 | }
224 | ]
225 | },
226 | value: '#FFFFFF'
227 | }
228 | ]
229 | }
230 | }]
231 | }],
232 | metadata: {
233 | 'mapbox:ref': {
234 | sources: {
235 | testsource: {
236 | type: 'vector'
237 | }
238 | },
239 | sourceMapping: {
240 | testsource: [0, 1, 2, 3, 4, 5, 6, 7, 8]
241 | },
242 | sourceLayerMapping: {
243 | foo: [0, 1, 2, 3, 4, 5, 6, 7, 8]
244 | }
245 | }
246 | }
247 | };
248 |
249 | export default gs_expression_decisions;
250 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [6.2.0](https://github.com/geostyler/geostyler-mapbox-parser/compare/v6.1.1...v6.2.0) (2025-12-16)
2 |
3 | ### Features
4 |
5 | * add option to replace markers with solid color ([7fe7467](https://github.com/geostyler/geostyler-mapbox-parser/commit/7fe7467ee015da5298d01980bd9fffce76dd95f0))
6 | * add prepare script to allow installing a git reference ([10689b8](https://github.com/geostyler/geostyler-mapbox-parser/commit/10689b8a1ef2290709af96dadfe6a5b4bb24941a))
7 | * update dependencies and switch to bun ([70e8ade](https://github.com/geostyler/geostyler-mapbox-parser/commit/70e8adea3931b0914598dc6be6fc5bac989ad9f1))
8 |
9 | ### Bug Fixes
10 |
11 | * add imported indirect dependency to devDependencies ([970b788](https://github.com/geostyler/geostyler-mapbox-parser/commit/970b7889eb4ebd83e5021fcbab49b5a4da1a7d74))
12 | * add test for graphicFill fallback ([1fbd8a0](https://github.com/geostyler/geostyler-mapbox-parser/commit/1fbd8a066306ebf244c669a9e9a4c0ccc13fd4e1))
13 | * fix workflow ([046c2ac](https://github.com/geostyler/geostyler-mapbox-parser/commit/046c2ac14d9ec2669165b0094db566668c26f53e))
14 | * fix workflow ([41b35f4](https://github.com/geostyler/geostyler-mapbox-parser/commit/41b35f459c2cfe6e1ae0c17f8e4537437cb5184c))
15 | * fix workflow ([14b0226](https://github.com/geostyler/geostyler-mapbox-parser/commit/14b02268fadc0ca6ab8e8347de495ae0fe13c57c))
16 | * fix workflow ([b0b344e](https://github.com/geostyler/geostyler-mapbox-parser/commit/b0b344ec793139eee37a9af2478a5a885a29110e))
17 | * fix workflow ([f76a1f1](https://github.com/geostyler/geostyler-mapbox-parser/commit/f76a1f1d314b7a4b4ee3bad2ef069cef48017ea7))
18 | * fix workflow ([f8c0a26](https://github.com/geostyler/geostyler-mapbox-parser/commit/f8c0a268be00fd748bddccb8717c1265d05bba37))
19 | * fix workflow ([85aa519](https://github.com/geostyler/geostyler-mapbox-parser/commit/85aa5194ba668f4c4067d502cb0412e3e40daf91))
20 | * fix workflow ([2073066](https://github.com/geostyler/geostyler-mapbox-parser/commit/2073066eadd8086cb866f273780b794d81443b1c))
21 | * fix workflow ([719f72c](https://github.com/geostyler/geostyler-mapbox-parser/commit/719f72cdf0166fe606c2fcaf8e4a1fb0bb81b812))
22 | * fix workflow ([1ffe937](https://github.com/geostyler/geostyler-mapbox-parser/commit/1ffe937e2f1453fd46883b04d355651c82b5811f))
23 | * update dependency, fix workflow ([c5f64be](https://github.com/geostyler/geostyler-mapbox-parser/commit/c5f64be1d1c85492b89e780f8068bc6e66a2b980))
24 |
25 | ## [6.1.1](https://github.com/geostyler/geostyler-mapbox-parser/compare/v6.1.0...v6.1.1) (2025-03-12)
26 |
27 | ### Bug Fixes
28 |
29 | * **deps:** update dependency geostyler-style to v10 ([7661add](https://github.com/geostyler/geostyler-mapbox-parser/commit/7661add5aa0c8d2c44f6cc28142aaf90e6645ae7))
30 |
31 | ## [6.1.0](https://github.com/geostyler/geostyler-mapbox-parser/compare/v6.0.1...v6.1.0) (2024-12-02)
32 |
33 |
34 | ### Features
35 |
36 | * add interpolate function ([#325](https://github.com/geostyler/geostyler-mapbox-parser/issues/325)) ([6567d8b](https://github.com/geostyler/geostyler-mapbox-parser/commit/6567d8b14c0158f96856de8786081d4fd0f554ff))
37 |
38 |
39 | ### Bug Fixes
40 |
41 | * **deps:** update dependency @types/mapbox-gl to v2.7.21 ([d7cf5ea](https://github.com/geostyler/geostyler-mapbox-parser/commit/d7cf5ea2d80a4baae9b5990f9b90ac7c5fa5b330))
42 | * preserve outline dash array ([77edffb](https://github.com/geostyler/geostyler-mapbox-parser/commit/77edffbf967d31c668e6b4a2e8c3a8d90b9517a4))
43 |
44 | ## [6.0.1](https://github.com/geostyler/geostyler-mapbox-parser/compare/v6.0.0...v6.0.1) (2024-11-11)
45 |
46 |
47 | ### Bug Fixes
48 |
49 | * preserve visibility in line symbolizer during cloning ([dfda998](https://github.com/geostyler/geostyler-mapbox-parser/commit/dfda9982199eb1769d3b1a103d26940517949874))
50 |
51 | ## [6.0.0](https://github.com/geostyler/geostyler-mapbox-parser/compare/v5.0.1...v6.0.0) (2024-06-25)
52 |
53 |
54 | ### ⚠ BREAKING CHANGES
55 |
56 | * Switches to esm build and to vite. Users possibly
57 | need to adapt their imports and their bundler.
58 |
59 | ### Features
60 |
61 | * prepare next release ([f110eec](https://github.com/geostyler/geostyler-mapbox-parser/commit/f110eecbdedd3830a03be0b31cb13615fbc03027))
62 | * read rgba color values into hex ([#323](https://github.com/geostyler/geostyler-mapbox-parser/issues/323)) ([e47192d](https://github.com/geostyler/geostyler-mapbox-parser/commit/e47192d7a62b9e70f9e1d2fd36e8f74f1abe6dcd))
63 |
64 |
65 | ### Bug Fixes
66 |
67 | * update dependencies ([5926b1b](https://github.com/geostyler/geostyler-mapbox-parser/commit/5926b1b087ca05ac3825b9fb262756f27510112f))
68 | * update resolutions to levels 0-24 ([#320](https://github.com/geostyler/geostyler-mapbox-parser/issues/320)) ([b02d9a5](https://github.com/geostyler/geostyler-mapbox-parser/commit/b02d9a5bbafba4d544f935c3ac40a785cbb7ecec))
69 |
70 | ## [6.0.0-next.2](https://github.com/geostyler/geostyler-mapbox-parser/compare/v6.0.0-next.1...v6.0.0-next.2) (2024-06-25)
71 |
72 |
73 | ### Bug Fixes
74 |
75 | * update dependencies ([5926b1b](https://github.com/geostyler/geostyler-mapbox-parser/commit/5926b1b087ca05ac3825b9fb262756f27510112f))
76 |
77 | ## [6.0.0-next.1](https://github.com/geostyler/geostyler-mapbox-parser/compare/v5.0.1...v6.0.0-next.1) (2024-06-21)
78 |
79 |
80 | ### ⚠ BREAKING CHANGES
81 |
82 | * Switches to esm build and to vite. Users possibly
83 | need to adapt their imports and their bundler.
84 |
85 | ### Features
86 |
87 | * prepare next release ([f110eec](https://github.com/geostyler/geostyler-mapbox-parser/commit/f110eecbdedd3830a03be0b31cb13615fbc03027))
88 | * read rgba color values into hex ([#323](https://github.com/geostyler/geostyler-mapbox-parser/issues/323)) ([e47192d](https://github.com/geostyler/geostyler-mapbox-parser/commit/e47192d7a62b9e70f9e1d2fd36e8f74f1abe6dcd))
89 |
90 |
91 | ### Bug Fixes
92 |
93 | * update resolutions to levels 0-24 ([#320](https://github.com/geostyler/geostyler-mapbox-parser/issues/320)) ([b02d9a5](https://github.com/geostyler/geostyler-mapbox-parser/commit/b02d9a5bbafba4d544f935c3ac40a785cbb7ecec))
94 |
95 | ## [5.0.1](https://github.com/geostyler/geostyler-mapbox-parser/compare/v5.0.0...v5.0.1) (2023-12-05)
96 |
97 |
98 | ### Bug Fixes
99 |
100 | * allow scale to be a GeoStylerFunction ([73d2271](https://github.com/geostyler/geostyler-mapbox-parser/commit/73d2271e536b14604ca222aaa9af6972014930aa))
101 | * treat ison-size as scale ([ebc9434](https://github.com/geostyler/geostyler-mapbox-parser/commit/ebc9434443ffa4ead4d0bf0296b3422cc73aa2c4))
102 | * use width and multiply directly ([113ef5e](https://github.com/geostyler/geostyler-mapbox-parser/commit/113ef5e8c051e4433971fd3034ff102922f74adf))
103 |
104 | ## [5.0.0](https://github.com/geostyler/geostyler-mapbox-parser/compare/v4.0.0...v5.0.0) (2023-12-04)
105 |
106 |
107 | ### ⚠ BREAKING CHANGES
108 |
109 | * use geostyler-style Sprite instead of string syntax
110 | * This changes the typing of the MbStyle by making
111 | the property 'source' required. Through this, we actually follow
112 | the MapBox Style Specification. MbStyles that previously omitted the
113 | 'source' property, will now have to add it.
114 |
115 | ### Features
116 |
117 | * add sprite support ([9d883be](https://github.com/geostyler/geostyler-mapbox-parser/commit/9d883be90463480fc1cd71e3bce48aaf43d88405))
118 | * add spriteCache ([9043e10](https://github.com/geostyler/geostyler-mapbox-parser/commit/9043e10a93a0394cdda2e4fcb575abefbc3e9c1e))
119 | * keep track of mapbox sources and source layers in layers ([a8f5d7c](https://github.com/geostyler/geostyler-mapbox-parser/commit/a8f5d7c787a78dc9d59d91ac14e52ef8686c4822))
120 | * parse placement of TextSymbolizer ([#292](https://github.com/geostyler/geostyler-mapbox-parser/issues/292)) ([9acb43f](https://github.com/geostyler/geostyler-mapbox-parser/commit/9acb43f377bca6c376155e0b6b0b9d09d9c4cc4c))
121 |
122 |
123 | ### Bug Fixes
124 |
125 | * address comments and add docs ([eca7607](https://github.com/geostyler/geostyler-mapbox-parser/commit/eca760769e3e7c4a1b6869de7050f99c0ba97fab))
126 | * **lint:** remove test util ([9a01114](https://github.com/geostyler/geostyler-mapbox-parser/commit/9a01114f3be74aae80c46ba622d3dfecde73851b))
127 | * merge icontext symbol from separate symbolizers when needed ([a02a565](https://github.com/geostyler/geostyler-mapbox-parser/commit/a02a5650311723cb2d741c5a890a3b3c6b59e23e))
128 | * mutate only clones of arguments ([36a76d0](https://github.com/geostyler/geostyler-mapbox-parser/commit/36a76d0af0560ef8fce43e63144f06d61565cf9f))
129 | * typos ([2de63cc](https://github.com/geostyler/geostyler-mapbox-parser/commit/2de63cc64d3b7c7ad81efc6308c5fa372d6f5196))
130 |
--------------------------------------------------------------------------------
/data/mapbox_metadata/expression_math.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/naming-convention */
2 | import { MbStyle } from '../../src/MapboxStyleParser';
3 |
4 | const expression_math: MbStyle = {
5 | version: 8,
6 | name: 'Expression Math',
7 | sources: {
8 | testsource: {
9 | type: 'vector'
10 | }
11 | },
12 | layers: [
13 | {
14 | id: 'r0_sy0_st0',
15 | source: 'testsource',
16 | 'source-layer': 'foo',
17 | type: 'circle',
18 | paint: {
19 | 'circle-radius': ['+', 13, 3, 7]
20 | }
21 | },
22 | {
23 | id: 'r1_sy0_st0',
24 | source: 'testsource',
25 | 'source-layer': 'foo',
26 | type: 'circle',
27 | paint: {
28 | 'circle-radius': ['abs', -12]
29 | }
30 | },
31 | {
32 | id: 'r2_sy0_st0',
33 | source: 'testsource',
34 | 'source-layer': 'foo',
35 | type: 'circle',
36 | paint: {
37 | 'circle-radius': ['acos', 4]
38 | }
39 | },
40 | {
41 | id: 'r3_sy0_st0',
42 | source: 'testsource',
43 | 'source-layer': 'foo',
44 | type: 'circle',
45 | paint: {
46 | 'circle-radius': ['asin', 4]
47 | }
48 | },
49 | {
50 | id: 'r4_sy0_st0',
51 | source: 'testsource',
52 | 'source-layer': 'foo',
53 | type: 'circle',
54 | paint: {
55 | 'circle-radius': ['atan', 4]
56 | }
57 | },
58 | {
59 | id: 'r5_sy0_st0',
60 | source: 'testsource',
61 | 'source-layer': 'foo',
62 | type: 'circle',
63 | paint: {
64 | 'circle-radius': ['ceil', 3.4]
65 | }
66 | },
67 | {
68 | id: 'r6_sy0_st0',
69 | source: 'testsource',
70 | 'source-layer': 'foo',
71 | type: 'circle',
72 | paint: {
73 | 'circle-radius': ['cos', 3.4]
74 | }
75 | },
76 | {
77 | id: 'r7_sy0_st0',
78 | source: 'testsource',
79 | 'source-layer': 'foo',
80 | type: 'circle',
81 | paint: {
82 | 'circle-radius': ['/', 100, 2]
83 | }
84 | },
85 | {
86 | id: 'r8_sy0_st0',
87 | source: 'testsource',
88 | 'source-layer': 'foo',
89 | type: 'circle',
90 | paint: {
91 | 'circle-radius': ['e']
92 | }
93 | },
94 | {
95 | id: 'r9_sy0_st0',
96 | source: 'testsource',
97 | 'source-layer': 'foo',
98 | type: 'circle',
99 | paint: {
100 | 'circle-radius': ['floor', 3.5]
101 | }
102 | },
103 | {
104 | id: 'r10_sy0_st0',
105 | source: 'testsource',
106 | 'source-layer': 'foo',
107 | type: 'circle',
108 | paint: {
109 | 'circle-radius': ['ln', 4.6]
110 | }
111 | },
112 | {
113 | id: 'r11_sy0_st0',
114 | source: 'testsource',
115 | 'source-layer': 'foo',
116 | type: 'circle',
117 | paint: {
118 | 'circle-radius': ['max', 13, 37, 0, 8, 15]
119 | }
120 | },
121 | {
122 | id: 'r12_sy0_st0',
123 | source: 'testsource',
124 | 'source-layer': 'foo',
125 | type: 'circle',
126 | paint: {
127 | 'circle-radius': ['min', 13, 37, 0, 8, 15]
128 | }
129 | },
130 | {
131 | id: 'r13_sy0_st0',
132 | source: 'testsource',
133 | 'source-layer': 'foo',
134 | type: 'circle',
135 | paint: {
136 | 'circle-radius': ['%', 3, 2]
137 | }
138 | },
139 | {
140 | id: 'r14_sy0_st0',
141 | source: 'testsource',
142 | 'source-layer': 'foo',
143 | type: 'circle',
144 | paint: {
145 | 'circle-radius': ['*', 2, 2.5, 10]
146 | }
147 | },
148 | {
149 | id: 'r15_sy0_st0',
150 | source: 'testsource',
151 | 'source-layer': 'foo',
152 | type: 'circle',
153 | paint: {
154 | 'circle-radius': ['pi']
155 | }
156 | },
157 | {
158 | id: 'r16_sy0_st0',
159 | source: 'testsource',
160 | 'source-layer': 'foo',
161 | type: 'circle',
162 | paint: {
163 | 'circle-radius': ['^', 2, 4]
164 | }
165 | },
166 | {
167 | id: 'r17_sy0_st0',
168 | source: 'testsource',
169 | 'source-layer': 'foo',
170 | type: 'circle',
171 | paint: {
172 | 'circle-radius': ['round', 13.37]
173 | }
174 | },
175 | {
176 | id: 'r18_sy0_st0',
177 | source: 'testsource',
178 | 'source-layer': 'foo',
179 | type: 'circle',
180 | paint: {
181 | 'circle-radius': ['sin', 1]
182 | }
183 | },
184 | {
185 | id: 'r19_sy0_st0',
186 | source: 'testsource',
187 | 'source-layer': 'foo',
188 | type: 'circle',
189 | paint: {
190 | 'circle-radius': ['sqrt', 1]
191 | }
192 | },
193 | {
194 | id: 'r20_sy0_st0',
195 | source: 'testsource',
196 | 'source-layer': 'foo',
197 | type: 'circle',
198 | paint: {
199 | 'circle-radius': ['-', 5, 6]
200 | }
201 | },
202 | {
203 | id: 'r21_sy0_st0',
204 | source: 'testsource',
205 | 'source-layer': 'foo',
206 | type: 'circle',
207 | paint: {
208 | 'circle-radius': ['tan', 1]
209 | }
210 | }
211 | ],
212 | metadata: {
213 | 'geostyler:ref': {
214 | rules: [{
215 | name: 'add',
216 | symbolizers: [
217 | [
218 | 'r0_sy0_st0'
219 | ]
220 | ]
221 | }, {
222 | name: 'abs',
223 | symbolizers: [
224 | [
225 | 'r1_sy0_st0'
226 | ]
227 | ]
228 | }, {
229 | name: 'acos',
230 | symbolizers: [
231 | [
232 | 'r2_sy0_st0'
233 | ]
234 | ]
235 | }, {
236 | name: 'asin',
237 | symbolizers: [
238 | [
239 | 'r3_sy0_st0'
240 | ]
241 | ]
242 | }, {
243 | name: 'atan',
244 | symbolizers: [
245 | [
246 | 'r4_sy0_st0'
247 | ]
248 | ]
249 | }, {
250 | name: 'ceil',
251 | symbolizers: [
252 | [
253 | 'r5_sy0_st0'
254 | ]
255 | ]
256 | }, {
257 | name: 'cos',
258 | symbolizers: [
259 | [
260 | 'r6_sy0_st0'
261 | ]
262 | ]
263 | }, {
264 | name: 'div',
265 | symbolizers: [
266 | [
267 | 'r7_sy0_st0'
268 | ]
269 | ]
270 | }, {
271 | name: 'exp',
272 | symbolizers: [
273 | [
274 | 'r8_sy0_st0'
275 | ]
276 | ]
277 | }, {
278 | name: 'floor',
279 | symbolizers: [
280 | [
281 | 'r9_sy0_st0'
282 | ]
283 | ]
284 | }, {
285 | name: 'log',
286 | symbolizers: [
287 | [
288 | 'r10_sy0_st0'
289 | ]
290 | ]
291 | }, {
292 | name: 'max',
293 | symbolizers: [
294 | [
295 | 'r11_sy0_st0'
296 | ]
297 | ]
298 | }, {
299 | name: 'min',
300 | symbolizers: [
301 | [
302 | 'r12_sy0_st0'
303 | ]
304 | ]
305 | }, {
306 | name: 'modulo',
307 | symbolizers: [
308 | [
309 | 'r13_sy0_st0'
310 | ]
311 | ]
312 | }, {
313 | name: 'mul',
314 | symbolizers: [
315 | [
316 | 'r14_sy0_st0'
317 | ]
318 | ]
319 | }, {
320 | name: 'pi',
321 | symbolizers: [
322 | [
323 | 'r15_sy0_st0'
324 | ]
325 | ]
326 | }, {
327 | name: 'pow',
328 | symbolizers: [
329 | [
330 | 'r16_sy0_st0'
331 | ]
332 | ]
333 | }, {
334 | name: 'round',
335 | symbolizers: [
336 | [
337 | 'r17_sy0_st0'
338 | ]
339 | ]
340 | }, {
341 | name: 'sin',
342 | symbolizers: [
343 | [
344 | 'r18_sy0_st0'
345 | ]
346 | ]
347 | }, {
348 | name: 'sqrt',
349 | symbolizers: [
350 | [
351 | 'r19_sy0_st0'
352 | ]
353 | ]
354 | }, {
355 | name: 'sub',
356 | symbolizers: [
357 | [
358 | 'r20_sy0_st0'
359 | ]
360 | ]
361 | }, {
362 | name: 'tan',
363 | symbolizers: [
364 | [
365 | 'r21_sy0_st0'
366 | ]
367 | ]
368 | }]
369 | }
370 | }
371 | };
372 |
373 | export default expression_math;
374 |
--------------------------------------------------------------------------------
/src/Util/MapboxStyleUtil.ts:
--------------------------------------------------------------------------------
1 | import { Sprite, Symbolizer, TextSymbolizer } from 'geostyler-style';
2 | import { MapboxRef } from '../MapboxStyleParser';
3 |
4 | class MapboxStyleUtil {
5 |
6 | public static getResolutions(): number[] {
7 | const resolutions = [];
8 | let res = 78271.51696402048;
9 | // adding resolution for arbitrary zoom level 0
10 | // This simplyfies working with zoom levels but might lead to unexpected
11 | // behaviour.
12 | resolutions.push(res * 2);
13 | for (res; resolutions.length <= 24; res /= 2) {
14 | resolutions.push(res);
15 | }
16 | return resolutions;
17 | }
18 | // credits to
19 | // https://github.com/terrestris/ol-util/blob/de1b580c63454c8110806a3d73a5f6e972b2f2b0/src/MapUtil/MapUtil.js#L104
20 | public static getScaleForResolution(resolution: number): number {
21 | var dpi = 25.4 / 0.28;
22 | var mpu = 1;
23 | var inchesPerMeter = 39.37008;
24 |
25 | return resolution * mpu * inchesPerMeter * dpi;
26 | }
27 |
28 | // credits to
29 | // https://github.com/openlayers/ol-mapbox-style/blob/e632c935e7e34bd27079b7fc234202a9ac3b73ee/util.js
30 | public static getZoomForResolution(resolution: number): number {
31 | let i = 0;
32 | const resolutions = MapboxStyleUtil.getResolutions();
33 | const ii = resolutions.length;
34 | for (; i < ii; ++i) {
35 | const candidate = resolutions[i];
36 | if (candidate < resolution && i + 1 < ii) {
37 | const zoomFactor = resolutions[i] / resolutions[i + 1];
38 | return i + Math.log(resolutions[i] / resolution) / Math.log(zoomFactor);
39 | }
40 | }
41 | return ii - 1;
42 | }
43 |
44 | /**
45 | * Calculates the appropriate map resolution for a given scale in the given
46 | * units.
47 | *
48 | * See: https://gis.stackexchange.com/questions/158435/
49 | * how-to-get-current-scale-in-openlayers-3
50 | *
51 | * @method
52 | * @param {number} scale The input scale to calculate the appropriate
53 | * resolution for.
54 | * @return {number} The calculated resolution.
55 | */
56 | static getResolutionForScale(scale: number): number {
57 | let dpi = 25.4 / 0.28;
58 | let mpu = 1;
59 | let inchesPerMeter = 39.37008;
60 |
61 | return scale / (mpu * inchesPerMeter * dpi);
62 | }
63 |
64 | public static zoomToScale(zoom: number): number {
65 | const resolutions = MapboxStyleUtil.getResolutions();
66 | // if zoom is integer
67 | if (zoom >= resolutions.length) {
68 | throw new Error('Cannot parse scaleDenominator. ZoomLevel does not exist.');
69 | }
70 | let resolution: number;
71 | if (Number.isInteger(zoom)) {
72 | resolution = resolutions[zoom];
73 | } else {
74 | // interpolate values
75 | const pre = Math.floor(zoom);
76 | const preVal = resolutions[pre];
77 | // after carefully rearranging
78 | // zoom = i + Math.log(resolutions[i] / resolution) / Math.log(zoomFactor)
79 | // with the zoomFactor being 2 I've arrived at this formula to properly
80 | // calculate the resolution:
81 | resolution = Math.pow(2, pre) * preVal / Math.pow(2, zoom);
82 | // this still gives some smallish rounding errors, but at the 8th digit after
83 | // the dot this is ok
84 | }
85 | return this.getScaleForResolution(resolution);
86 | }
87 |
88 | /**
89 | * Checks if all keys of an object are undefined.
90 | * Returns true if so.
91 | *
92 | * @param obj The object to be checked
93 | */
94 | public static allUndefined(obj: any): boolean {
95 | if (!obj) {
96 | return true;
97 | }
98 | const keys = Object.keys(obj);
99 | return !keys.some((k: string) => {
100 | return typeof obj[k] !== 'undefined';
101 | });
102 | }
103 |
104 | /**
105 | * Checks if all keys of a Symbolizer are undefined except 'kind'.
106 | *
107 | * @param symbolizer A GeoStylerStyle Symbolizer
108 | */
109 | // TODO: TextSymbolizer can be removed once it is fixed in the geostyler-style
110 | public static symbolizerAllUndefined(symbolizer: Symbolizer | TextSymbolizer): boolean {
111 | return !Object.keys(symbolizer)
112 | .filter(val => val !== 'kind' && val !== 'visibility')
113 | .some((val: keyof Symbolizer) => typeof symbolizer[val] !== 'undefined');
114 | }
115 |
116 | /**
117 | * Replaces the mapbox api placeholder with its actual url.
118 | *
119 | * @param url URL
120 | */
121 | public static getUrlForMbPlaceholder(url: string): string {
122 | const mbPlaceholder = 'mapbox://';
123 | const mbUrl = 'https://api.mapbox.com/';
124 | if (url && url.startsWith(mbPlaceholder)) {
125 | return url.replace(mbPlaceholder, mbUrl);
126 | }
127 | return url;
128 | }
129 |
130 | /**
131 | * Replaces the actual mapbox url with its api placeholder.
132 | *
133 | * @param url URL
134 | */
135 | public static getMbPlaceholderForUrl(url: string): string {
136 | const mbPlaceholder = 'mapbox://';
137 | const mbUrl = 'https://api.mapbox.com/';
138 | if (url && url.startsWith(mbUrl)) {
139 | return url.replace(mbUrl, mbPlaceholder);
140 | }
141 | return url;
142 | }
143 |
144 | /**
145 | * Resolves a mapbox text-field placeholder string to a geostyler-style
146 | * placeholder string. I.e. replaces {varname} with {{varname}}.
147 | *
148 | * @param template Template string that should be resolved
149 | */
150 | public static resolveMbTextPlaceholder(template: string): string {
151 | // prefix indicating that a template is being used
152 | const prefix: string = '\\{';
153 | // suffix indicating that a template is being used
154 | const suffix: string = '\\}';
155 |
156 | let regExp: RegExp = new RegExp(prefix + '.*?' + suffix, 'g');
157 | const gsLabel = template.replace(regExp, (match: string) => {
158 | return `{${match}}`;
159 | });
160 | return gsLabel;
161 | }
162 |
163 | public static getSpriteName(sprite: Sprite, metadata: MapboxRef): string {
164 | if (!metadata?.sprite || !sprite) {
165 | throw new Error('Cannot retrieve sprite name. Sprite or metadata missing.');
166 | }
167 | const name = Object.keys(metadata.sprite)
168 | .find(key => {
169 | const value = metadata.sprite![key];
170 | return value.position[0] === sprite.position[0] &&
171 | value.position[1] === sprite.position[1] &&
172 | value.size[0] === sprite.size[0] &&
173 | value.size[1] === sprite.size[1];
174 | });
175 | if (!name) {
176 | throw new Error('Cannot retrieve sprite name. No matching sprite in metadata.');
177 | }
178 | return name || '';
179 | }
180 |
181 | /**
182 | * Splits a RGBA encoded color into its color values.
183 | *
184 | * @param {string} rgbaColor RGB(A) encoded color
185 | * @return {number[]} Numeric color values as array
186 | */
187 | public static splitRgbaColor(rgbaColor: string): number[] {
188 | const colorsOnly = rgbaColor.substring(rgbaColor.indexOf('(') + 1, rgbaColor.lastIndexOf(')')).split(/,\s*/);
189 | const red = parseInt(colorsOnly[0], 10);
190 | const green = parseInt(colorsOnly[1], 10);
191 | const blue = parseInt(colorsOnly[2], 10);
192 | const opacity = parseFloat(colorsOnly[3]);
193 |
194 | return [red, green, blue, opacity];
195 | }
196 |
197 | /**
198 | * Returns the hex code for a given RGB(A) array.
199 | *
200 | * @param colorArr RGB(A) array. e.g. [255,0,0]
201 | * @return {string} The HEX color representation of the given color
202 | */
203 | public static getHexCodeFromRgbArray(colorArr: number[]): string {
204 | return '#' + colorArr.map((x, idx) => {
205 | const hex = x.toString(16);
206 | // skip opacity if passed as fourth entry
207 | if (idx < 3) {
208 | return hex.length === 1 ? '0' + hex : hex;
209 | }
210 | return '';
211 | }).join('');
212 | }
213 |
214 | /**
215 | * Transforms a RGB(A) or named color value to a HEX encoded notation.
216 | * If a HEX color is provided it will be returned untransformed.
217 | *
218 | * @param {string} inColor The color to transform
219 | * @return {string | undefined} The HEX color representation of the given color
220 | */
221 | public static getHexColor(inColor: string): string | undefined {
222 | // if passing in a hex code we just return it
223 | if (inColor.startsWith('#')) {
224 | return inColor;
225 | } else if (inColor.startsWith('rgb')) {
226 | const colorArr = this.splitRgbaColor(inColor);
227 | return this.getHexCodeFromRgbArray(colorArr);
228 | } else {
229 | return;
230 | }
231 | }
232 |
233 | }
234 |
235 | export default MapboxStyleUtil;
236 |
--------------------------------------------------------------------------------
/src/Expressions.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Expression,
3 | Fcase,
4 | Finterpolate,
5 | Expression as GeoStylerExpression,
6 | GeoStylerFunction,
7 | PropertyType,
8 | isGeoStylerFunction
9 | } from 'geostyler-style';
10 | import { invert } from 'lodash';
11 | import {
12 | ExpressionName,
13 | Expression as MapboxExpression,
14 | StyleFunction
15 | } from 'mapbox-gl';
16 |
17 | import MapboxStyleUtil from './Util/MapboxStyleUtil';
18 |
19 | const expressionNames: ExpressionName[] = ['array',
20 | 'boolean',
21 | 'collator',
22 | 'format',
23 | 'literal',
24 | 'number',
25 | 'number-format',
26 | 'object',
27 | 'string',
28 | 'image',
29 | 'to-boolean',
30 | 'to-color',
31 | 'to-number',
32 | 'to-string',
33 | 'typeof',
34 | 'feature-state',
35 | 'geometry-type',
36 | 'id',
37 | 'line-progress',
38 | 'properties',
39 | 'at',
40 | 'get',
41 | 'has',
42 | 'in',
43 | 'index-of',
44 | 'length',
45 | 'slice',
46 | '!',
47 | '!=',
48 | '<',
49 | '<=',
50 | '==',
51 | '>',
52 | '>=',
53 | 'all',
54 | 'any',
55 | 'case',
56 | 'match',
57 | 'coalesce',
58 | 'within',
59 | 'interpolate',
60 | 'interpolate-hcl',
61 | 'interpolate-lab',
62 | 'step',
63 | 'let',
64 | 'var',
65 | 'concat',
66 | 'downcase',
67 | 'is-supported-script',
68 | 'resolved-locale',
69 | 'upcase',
70 | 'rgb',
71 | 'rgba',
72 | 'to-rgba',
73 | '-',
74 | '*',
75 | '/',
76 | '%',
77 | '^',
78 | '+',
79 | 'abs',
80 | 'acos',
81 | 'asin',
82 | 'atan',
83 | 'ceil',
84 | 'cos',
85 | 'e',
86 | 'floor',
87 | 'ln',
88 | 'ln2',
89 | 'log10',
90 | 'log2',
91 | 'max',
92 | 'min',
93 | 'pi',
94 | 'round',
95 | 'sin',
96 | 'sqrt',
97 | 'tan',
98 | 'zoom',
99 | 'heatmap-density'];
100 |
101 | const functionNameMap: Record = {
102 | // ---- string ----
103 | numberFormat: null,
104 | // numberFormat: 'number-format', // TODO: this could be done in theory but gs and mb use different format approaches
105 | strAbbreviate: null,
106 | strCapitalize: null,
107 | strConcat: 'concat',
108 | strDefaultIfBlank: null,
109 | strEndsWith: null,
110 | strEqualsIgnoreCase: null,
111 | strIndexOf: null,
112 | strLastIndexOf: null,
113 | strLength: 'length',
114 | strMatches: null,
115 | strReplace: null,
116 | strStartsWith: null,
117 | strStripAccents: null,
118 | strSubstring: 'slice',
119 | strSubstringStart: null,
120 | strToLowerCase: 'downcase',
121 | strToUpperCase: 'upcase',
122 | strToString: null,
123 | strTrim: null,
124 | // ---- number ----
125 | add: '+',
126 | abs: 'abs',
127 | acos: 'acos',
128 | asin: 'asin',
129 | atan: 'atan',
130 | atan2: null,
131 | ceil: 'ceil',
132 | cos: 'cos',
133 | div: '/',
134 | exp: 'e',
135 | floor: 'floor',
136 | interpolate: 'interpolate',
137 | log: 'ln',
138 | // – : 'ln2'
139 | // – : 'log10'
140 | // – : 'log2'
141 | max: 'max',
142 | min: 'min',
143 | modulo: '%',
144 | mul: '*',
145 | pi: 'pi',
146 | // - : 'e',
147 | pow: '^',
148 | random: null,
149 | rint: null,
150 | round: 'round',
151 | sin: 'sin',
152 | sqrt: 'sqrt',
153 | sub: '-',
154 | tan: 'tan',
155 | toDegrees: null,
156 | toNumber: null,
157 | toRadians: null,
158 | // ---- boolean ----
159 | all: 'all',
160 | // eslint-disable-next-line id-blacklist
161 | any: 'any',
162 | between: 'within',
163 | double2bool: null,
164 | equalTo: '==',
165 | greaterThan: '>',
166 | greaterThanOrEqualTo: '>=',
167 | in: 'in',
168 | lessThan: '<',
169 | lessThanOrEqualTo: '<=',
170 | not: '!',
171 | notEqualTo: '!=',
172 | parseBoolean: 'to-boolean',
173 | // ---- unknown ----
174 | case: 'case',
175 | property: 'get',
176 | step: null
177 | };
178 |
179 | const invertedFunctionNameMap: Partial> =
180 | invert(functionNameMap);
181 |
182 | export function gs2mbExpression(gsExpression?: GeoStylerExpression):
183 | MapboxExpression | T | undefined {
184 | if (!isGeoStylerFunction(gsExpression)) {
185 | return gsExpression as T;
186 | }
187 |
188 | const args = 'args' in gsExpression ? gsExpression.args : [];
189 |
190 | // special handling
191 | switch (gsExpression.name) {
192 | case 'case': {
193 | const mbArgs: any = [];
194 | let fallback: any;
195 | args.forEach((arg: any, index: number) => {
196 | if (index === 0) {
197 | fallback = gs2mbExpression(arg);
198 | return;
199 | }
200 | if (arg.case === null || arg.case === undefined || arg.value === null || arg.value === undefined) {
201 | throw new Error('Could not translate GeoStyler Expression: ' + gsExpression);
202 | }
203 | mbArgs.push(gs2mbExpression(arg.case));
204 | mbArgs.push(gs2mbExpression(arg.value));
205 | });
206 | return ['case', ...mbArgs, fallback];
207 | }
208 | case 'interpolate': {
209 | const mbArgs: any = [];
210 | args.forEach((arg: any, index: number) => {
211 | if (index === 0) {
212 | mbArgs.push([arg.name]);
213 | return;
214 | }
215 | if (index === 1) {
216 | mbArgs.push(gs2mbExpression(arg));
217 | return;
218 | }
219 | if (arg.stop === null || arg.stop === undefined || arg.value === null || arg.value === undefined) {
220 | throw new Error('Could not translate GeoStyler Expression: ' + gsExpression);
221 | }
222 | mbArgs.push(gs2mbExpression(arg.stop));
223 | mbArgs.push(gs2mbExpression(arg.value));
224 | });
225 | return ['interpolate', ...mbArgs];
226 | }
227 | case 'exp':
228 | if (args[0] === 1) {
229 | return ['e'];
230 | }
231 | break;
232 | case 'pi':
233 | return ['pi'];
234 | default:
235 | const mapboxFunctionName = functionNameMap[gsExpression.name];
236 | if (!mapboxFunctionName) {
237 | throw new Error('Could not translate GeoStyler Expression: ' + gsExpression);
238 | }
239 | return [mapboxFunctionName, ...args.map(arg => gs2mbExpression(arg))] as MapboxExpression;
240 | }
241 |
242 | throw new Error('Could not translate GeoStyler Expression: ' + gsExpression);
243 |
244 | }
245 |
246 | type MbInput = MapboxExpression | PropertyType | StyleFunction;
247 |
248 | export function mb2gsExpression(mbExpression?: MbInput, isColor?: boolean):
249 | GeoStylerExpression | undefined {
250 |
251 | // TODO: is this check valid ?
252 | // fails for arrays like offset = [10, 20]
253 | if (!(Array.isArray(mbExpression) && expressionNames.includes(mbExpression[0]))) {
254 | if (typeof mbExpression === 'string' && isColor) {
255 | return MapboxStyleUtil.getHexColor(mbExpression) as GeoStylerExpression;
256 | }
257 | return mbExpression as GeoStylerExpression | undefined;
258 | }
259 |
260 | const mapboxExpressionName: ExpressionName = mbExpression[0];
261 | const args: Expression[] = mbExpression.slice(1);
262 | let func: GeoStylerFunction;
263 |
264 | // special handling
265 | switch (mapboxExpressionName) {
266 | case 'e':
267 | func = {
268 | name: 'exp',
269 | args: [1]
270 | };
271 | break;
272 | case 'case': {
273 | const gsArgs: any[] = [];
274 | const fallback = mb2gsExpression(args.pop(), isColor);
275 | args.forEach((a, index) => {
276 | var gsIndex = Math.floor(index / 2);
277 | if (index % 2 === 0) {
278 | gsArgs[gsIndex] = {
279 | case: mb2gsExpression(a)
280 | };
281 | } else {
282 | gsArgs[gsIndex] = {
283 | ...gsArgs[gsIndex] as any,
284 | value: mb2gsExpression(a, isColor)
285 | };
286 | }
287 | });
288 | // adding the fallback as the first arg
289 | gsArgs.unshift(fallback);
290 | func = {
291 | name: 'case',
292 | args: gsArgs as Fcase['args']
293 | };
294 | break;
295 | }
296 | case 'interpolate': {
297 | const interpolationType = (args.shift() as [string])[0];
298 | const input = mb2gsExpression(args.shift());
299 | const gsArgs: any[] = [];
300 |
301 | args.forEach((a, index) => {
302 | const gsIndex = Math.floor(index / 2);
303 | if (index % 2 === 0) {
304 | gsArgs[gsIndex] = {
305 | stop: mb2gsExpression(a)
306 | };
307 | } else {
308 | gsArgs[gsIndex] = {
309 | ...gsArgs[gsIndex] as any,
310 | value: mb2gsExpression(a)
311 | };
312 | }
313 | });
314 | // adding the interpolation type and the input as the first args
315 | gsArgs.unshift({name: interpolationType}, input);
316 | func = {
317 | name: 'interpolate',
318 | args: gsArgs as Finterpolate['args']
319 | };
320 | break;
321 | }
322 | case 'pi':
323 | func = {
324 | name: 'pi'
325 | };
326 | break;
327 | default:
328 | const gsFunctionName = invertedFunctionNameMap[mapboxExpressionName];
329 | if (!gsFunctionName) {
330 | throw new Error('Could not translate Mapbox Expression: ' + mbExpression);
331 | }
332 | func = {
333 | name: gsFunctionName,
334 | args: args.map(arg => mb2gsExpression(arg))
335 | } as GeoStylerFunction;
336 | break;
337 | }
338 |
339 | return func as GeoStylerExpression;
340 | }
341 |
--------------------------------------------------------------------------------
/src/MapboxStyleParser.spec.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable camelcase */
2 | import MapboxStyleParser from './MapboxStyleParser';
3 |
4 | import { beforeEach, expect, it, describe, vi } from 'vitest';
5 |
6 | import line_simpleline from '../data/styles/line_simpleline';
7 | import mb_line_simpleline from '../data/mapbox/line_simpleline';
8 | import mb_line_simpleline_metadata from '../data/mapbox_metadata/line_simpleline';
9 | import fill_simplefill from '../data/styles/fill_simplefill';
10 | import mb_fill_simplefill from '../data/mapbox/fill_simplefill';
11 | import mb_fill_simplefill_metadata from '../data/mapbox_metadata/fill_simplefill';
12 | import fill_simplefill_outline from '../data/styles/fill_simple_outline';
13 | import mb_fill_simplefill_outline_metadata from '../data/mapbox_metadata/fill_simple_outline';
14 | import point_simpletext from '../data/styles/point_simpletext';
15 | import mb_point_simpletext from '../data/mapbox/point_simpletext';
16 | import mb_point_simpletext_metadata from '../data/mapbox_metadata/point_simpletext';
17 | import point_placeholdertext from '../data/styles/point_placeholderText';
18 | import mb_point_placeholdertext from '../data/mapbox/point_placeholderText';
19 | import fill_graphic_fill_mark from '../data/styles/fill_graphic_fill_mark';
20 | import mb_fill_graphic_fill_mark from '../data/mapbox/fill_graphic_fill_mark';
21 | // import mb_point_placeholdertext_metadata from '../data/mapbox_metadata/point_placeholderText';
22 | import multi_simpleline_simplefill from '../data/styles/multi_simpleline_simplefill';
23 | import mb_multi_simpleline_simplefill from '../data/mapbox/multi_simpleline_simplefill';
24 | import mb_multi_simpleline_simplefill_metadata from '../data/mapbox_metadata/multi_simpleline_simplefill';
25 | import multi_rule_line_fill from '../data/styles/multi_rule_line_fill';
26 | // import mb_multi_rule_line_fill from '../data/mapbox/multi_rule_line_fill';
27 | import mb_multi_rule_line_fill_metadata from '../data/mapbox_metadata/multi_rule_line_fill';
28 | import line_simpleline_basefilter from '../data/styles/line_simpleline_basefilter';
29 | import mb_line_simpleline_basefilter from '../data/mapbox/line_simpleline_basefilter';
30 | import mb_line_simpleline_basefilter_metadata from '../data/mapbox_metadata/line_simpleline_basefilter';
31 | // import line_simpleline_expression from '../data/styles/line_simpleline_expression';
32 | // import mb_line_simpleline_expression from '../data/mapbox/line_simpleline_expression';
33 | // import mb_line_simpleline_expression_metadata from '../data/mapbox_metadata/line_simpleline_expression';
34 | import line_simpleline_zoom from '../data/styles/line_simpleline_zoom';
35 | import mb_line_simpleline_zoom from '../data/mapbox/line_simpleline_zoom';
36 | import mb_line_simpleline_zoom_metadata from '../data/mapbox_metadata/line_simpleline_zoom';
37 | import icon_simpleicon from '../data/styles/icon_simpleicon';
38 | import mb_icon_simpleicon from '../data/mapbox/icon_simpleicon';
39 | import mb_icon_simpleicon_metadata from '../data/mapbox_metadata/icon_simpleicon';
40 | import icon_simpleicon_mapboxapi from '../data/styles/icon_simpleicon_mapboxapi';
41 | import mb_icon_simpleicon_mapboxapi from '../data/mapbox/icon_simpleicon_mapboxapi';
42 | import mb_icon_simpleicon_mapboxapi_metadata from '../data/mapbox_metadata/icon_simpleicon_mapboxapi';
43 | import circle_simplecircle from '../data/styles/circle_simplecircle';
44 | import mb_circle_simplecircle from '../data/mapbox/circle_simplecircle';
45 | import mb_circle_simplecircle_metadata from '../data/mapbox_metadata/circle_simplecircle';
46 | import fill_patternfill from '../data/styles/fill_patternfill';
47 | import mb_fill_patternfill from '../data/mapbox/fill_patternfill';
48 | import mb_fill_patternfill_metadata from '../data/mapbox_metadata/fill_patternfill';
49 | import line_patternline from '../data/styles/line_patternline';
50 | import mb_line_patternline from '../data/mapbox/line_patternline';
51 | import mb_line_patternline_metadata from '../data/mapbox_metadata/line_patternline';
52 | import point_placeholdertext_simple from '../data/styles/point_placeholderText_simple';
53 | import mb_point_placeholdertext_simple from '../data/mapbox/point_placeholderText_simple';
54 | import mb_point_placeholdertext_simple_metadata from '../data/mapbox_metadata/point_placeholderText_simple';
55 | import icontext_symbolizer_metadata from '../data/styles_metadata/icontext_symbolizer';
56 | import mb_icontext_symbolizer from '../data/mapbox/icontext_symbolizer';
57 | import mb_icontext_symbolizer_metadata from '../data/mapbox_metadata/icontext_symbolizer';
58 | import source_mapping from '../data/styles/source_mapping';
59 | import mb_source_mapping from '../data/mapbox/source_mapping';
60 | import mb_source_mapping_metadata from '../data/mapbox_metadata/source_mapping';
61 | import source_layer_mapping from '../data/styles/source_layer_mapping';
62 | import mb_source_layer_mapping from '../data/mapbox/source_layer_mapping';
63 | import mb_source_layer_mapping_metadata from '../data/mapbox_metadata/source_layer_mapping';
64 | import { CustomLayerInterface } from 'mapbox-gl';
65 | import { AnyLayer } from 'mapbox-gl';
66 | import text_placement_line_center from '../data/styles/text_placement_line_center';
67 | import mb_placement_line_center from '../data/mapbox/text_placement_line_center';
68 | import mb_text_placement_line_center_metadata from '../data/mapbox_metadata/text_placement_line_center';
69 | import mb_text_placement_line from '../data/mapbox/text_placement';
70 | import text_placement_line from '../data/styles/text_placement_line';
71 | import mb_text_placement_line_metadata from '../data/mapbox_metadata/text_placement_line';
72 | import mb_text_placement_point from '../data/mapbox/text_placement_point';
73 | import text_placement_point from '../data/styles/text_placement_point';
74 | import mb_text_placement_point_metadata from '../data/mapbox_metadata/text_placement_point';
75 | import color_rgba from '../data/styles/color_rgba';
76 | import mb_color_rgba from '../data/mapbox/color_rgba';
77 |
78 | const mockFetchResult = (data: any) => {
79 | vi.spyOn(global, 'fetch')
80 | .mockImplementationOnce(() => {
81 | const response = {
82 | ok: true,
83 | status: 200,
84 | json: () => Promise.resolve(data),
85 | } as Response;
86 | return Promise.resolve(response);
87 | });
88 | };
89 |
90 | it('MapboxStyleParser is defined', () => {
91 | expect(MapboxStyleParser).toBeDefined();
92 | });
93 |
94 | it('MapboxStyleParser can interpret Mark graphicFill with a fallback', async () => {
95 | expect.assertions(2);
96 | const styleParser = new MapboxStyleParser({replaceGraphicFillWithColor: true});
97 | const { output: mbStyle } = await styleParser.writeStyle(fill_graphic_fill_mark);
98 | expect(mbStyle).toBeDefined();
99 | expect(mbStyle).toEqual(mb_fill_graphic_fill_mark);
100 | });
101 |
102 | describe('MapboxStyleParser implements StyleParser', () => {
103 | let styleParser: MapboxStyleParser;
104 | beforeEach(() => {
105 | styleParser = new MapboxStyleParser();
106 | });
107 | describe('#readStyle', () => {
108 | it('can read a mapbox Line style', async () => {
109 | const { output: geoStylerStyle } = await styleParser.readStyle(mb_line_simpleline);
110 | expect(geoStylerStyle).toBeDefined();
111 | expect(geoStylerStyle).toEqual(line_simpleline);
112 | });
113 |
114 | it('can read a mapbox Line style with fill pattern', async () => {
115 | mockFetchResult({
116 | poi: {
117 | width: 12,
118 | height: 12,
119 | x: 0,
120 | y: 0
121 | }
122 | });
123 | const { output: geoStylerStyle } = await styleParser.readStyle(mb_line_patternline);
124 | expect(geoStylerStyle).toBeDefined();
125 | expect(geoStylerStyle).toEqual(line_patternline);
126 | });
127 | it('can read a mapbox text placement line value', async () => {
128 | expect.assertions(2);
129 | const { output: geoStylerStyle } = await styleParser.readStyle(mb_text_placement_line);
130 | expect(geoStylerStyle).toBeDefined();
131 | expect(geoStylerStyle).toEqual(text_placement_line);
132 | });
133 |
134 | it('can read a mapbox text placement point value', async () => {
135 | expect.assertions(2);
136 | const { output: geoStylerStyle } = await styleParser.readStyle(mb_text_placement_point);
137 | expect(geoStylerStyle).toBeDefined();
138 | expect(geoStylerStyle).toEqual(text_placement_point);
139 | });
140 |
141 | it('can read a mapbox text placement line center value', async () => {
142 | expect.assertions(2);
143 | const { output: geoStylerStyle } = await styleParser.readStyle(mb_placement_line_center);
144 | expect(geoStylerStyle).toBeDefined();
145 | expect(geoStylerStyle).toEqual(text_placement_line_center);
146 | });
147 |
148 | it('can read a mapbox Fill style with outline', async () => {
149 | expect.assertions(2);
150 | const { output: geoStylerStyle } = await styleParser.readStyle(mb_fill_simplefill_outline_metadata);
151 | expect(geoStylerStyle).toBeDefined();
152 | expect(geoStylerStyle).toEqual(fill_simplefill_outline);
153 | });
154 |
155 | it('can read a mapbox Fill style', async () => {
156 | expect.assertions(2);
157 | const { output: geoStylerStyle } = await styleParser.readStyle(mb_fill_simplefill);
158 | expect(geoStylerStyle).toBeDefined();
159 | expect(geoStylerStyle).toEqual(fill_simplefill);
160 | });
161 |
162 | it('can read a mapbox Fill style with fill pattern', async () => {
163 | mockFetchResult({
164 | poi: {
165 | width: 12,
166 | height: 12,
167 | x: 0,
168 | y: 0
169 | }
170 | });
171 | const { output: geoStylerStyle } = await styleParser.readStyle(mb_fill_patternfill);
172 | expect(geoStylerStyle).toBeDefined();
173 | expect(geoStylerStyle).toEqual(fill_patternfill);
174 | });
175 |
176 | it('can read a mapbox style with a basefilter', async () => {
177 | expect.assertions(2);
178 | const { output: geoStylerStyle } = await styleParser.readStyle(mb_line_simpleline_basefilter);
179 | expect(geoStylerStyle).toBeDefined();
180 | expect(geoStylerStyle).toEqual(line_simpleline_basefilter);
181 | });
182 |
183 | // TODO: readd this test once the expressions do work
184 | // it('can read a mapbox style with an expression', async () => {
185 | // expect.assertions(2);
186 | // const { output: geoStylerStyle } = await styleParser.readStyle(mb_line_simpleline_expression);
187 | // expect(geoStylerStyle).toBeDefined();
188 | // expect(geoStylerStyle).toEqual(line_simpleline_expression);
189 | // });
190 |
191 | it('can read a mapbox style with min and max zoom', async () => {
192 | // bun does not fully support this yet
193 | // expect.assertions(3);
194 | const { output: geoStylerStyle } = await styleParser.readStyle(mb_line_simpleline_zoom);
195 | expect(geoStylerStyle).toBeDefined();
196 | const min = geoStylerStyle?.rules[0].scaleDenominator?.min;
197 | const max = geoStylerStyle?.rules[0].scaleDenominator?.max;
198 | const gotMin = line_simpleline_zoom.rules[0].scaleDenominator?.min as number;
199 | const gotMax = line_simpleline_zoom.rules[0].scaleDenominator?.max as number;
200 | expect(min).toBeCloseTo(gotMin, 4);
201 | expect(max).toBeCloseTo(gotMax, 4);
202 | });
203 |
204 | it('can write and read a mapbox style with min and max zoom', async () => {
205 | // bun does not fully support this yet
206 | // expect.assertions(3);
207 | const { output: mbStyle } = await styleParser.writeStyle(line_simpleline_zoom);
208 | const { output: geoStylerStyle } = await styleParser.readStyle(mbStyle!);
209 | expect(geoStylerStyle).toBeDefined();
210 | const min = geoStylerStyle?.rules[0].scaleDenominator?.min;
211 | const max = geoStylerStyle?.rules[0].scaleDenominator?.max;
212 | const gotMin = line_simpleline_zoom.rules[0].scaleDenominator?.min as number;
213 | const gotMax = line_simpleline_zoom.rules[0].scaleDenominator?.max as number;
214 | expect(min).toBeCloseTo(gotMin, 4);
215 | expect(max).toBeCloseTo(gotMax, 4);
216 | });
217 |
218 | it('can read a mapbox Text style', async () => {
219 | expect.assertions(2);
220 | const { output: geoStylerStyle } = await styleParser.readStyle(mb_point_simpletext);
221 | expect(geoStylerStyle).toBeDefined();
222 | expect(geoStylerStyle).toEqual(point_simpletext);
223 | });
224 |
225 | it('can read a mapbox Text style with placeholder Text', async () => {
226 | expect.assertions(2);
227 | const { output: geoStylerStyle } = await styleParser.readStyle(mb_point_placeholdertext);
228 | expect(geoStylerStyle).toBeDefined();
229 | expect(geoStylerStyle).toEqual(point_placeholdertext);
230 | });
231 |
232 | it('can read a mapbox Text style with formatted Text', async () => {
233 | expect.assertions(2);
234 | const { output: geoStylerStyle } = await styleParser.readStyle(mb_point_placeholdertext_simple);
235 | expect(geoStylerStyle).toBeDefined();
236 | expect(geoStylerStyle).toEqual(point_placeholdertext_simple);
237 | });
238 |
239 | it('can read a mapbox Circle style', async () => {
240 | expect.assertions(2);
241 | const { output: geoStylerStyle } = await styleParser.readStyle(mb_circle_simplecircle);
242 | expect(geoStylerStyle).toBeDefined();
243 | expect(geoStylerStyle).toEqual(circle_simplecircle);
244 | });
245 |
246 | it('can read a mapbox style with multiple layers', async () => {
247 | expect.assertions(2);
248 | const { output: geoStylerStyle } = await styleParser.readStyle(mb_multi_simpleline_simplefill);
249 | expect(geoStylerStyle).toBeDefined();
250 | expect(geoStylerStyle).toEqual(multi_simpleline_simplefill);
251 | });
252 |
253 | it('can read a mapbox style with an icon', async () => {
254 | mockFetchResult({
255 | poi: {
256 | width: 12,
257 | height: 12,
258 | x: 0,
259 | y: 0
260 | }
261 | });
262 | const { output: geoStylerStyle } = await styleParser.readStyle(mb_icon_simpleicon);
263 | expect(geoStylerStyle).toBeDefined();
264 | expect(geoStylerStyle).toEqual(icon_simpleicon);
265 | });
266 |
267 | it('can read a mapbox style with an icon and resolves mapbox api', async () => {
268 | mockFetchResult({
269 | poi: {
270 | width: 12,
271 | height: 12,
272 | x: 0,
273 | y: 0
274 | }
275 | });
276 | const { output: geoStylerStyle } = await styleParser.readStyle(mb_icon_simpleicon_mapboxapi);
277 | expect(geoStylerStyle).toBeDefined();
278 | expect(geoStylerStyle).toEqual(icon_simpleicon_mapboxapi);
279 | });
280 |
281 | it('can read a mapbox style with icontext symbolizer', async () => {
282 | mockFetchResult({
283 | poi: {
284 | width: 12,
285 | height: 12,
286 | x: 0,
287 | y: 0
288 | }
289 | });
290 | const { output: geoStylerStyle } = await styleParser.readStyle(mb_icontext_symbolizer);
291 | expect(geoStylerStyle).toBeDefined();
292 | expect(geoStylerStyle).toEqual(icontext_symbolizer_metadata);
293 | });
294 |
295 | it('can keep track of a mapbox style sources', async () => {
296 | const { output: geoStylerStyle } = await styleParser.readStyle(mb_source_mapping);
297 | expect(geoStylerStyle).toBeDefined();
298 | expect(geoStylerStyle).toEqual(source_mapping);
299 | });
300 |
301 | it('can keep track of a mapbox style layer source', async () => {
302 | const { output: geostylerStyle } = await styleParser.readStyle(mb_source_layer_mapping);
303 | expect(geostylerStyle).toBeDefined();
304 | expect(geostylerStyle).toEqual(source_layer_mapping);
305 | });
306 |
307 | it('can read a style with rgba color values', async () => {
308 | const { output: geostylerStyle } = await styleParser.readStyle(mb_color_rgba);
309 | expect(geostylerStyle).toBeDefined();
310 | expect(geostylerStyle).toEqual(color_rgba);
311 | });
312 | });
313 |
314 | describe('#writeStyle', () => {
315 | it('can write a mapbox Line style', async () => {
316 | expect.assertions(2);
317 | const { output: mbStyle } = await styleParser.writeStyle(line_simpleline);
318 | expect(mbStyle).toBeDefined();
319 | expect(mbStyle).toEqual(mb_line_simpleline_metadata);
320 | });
321 |
322 | it('can write a mapbox Line style with fill pattern', async () => {
323 | expect.assertions(2);
324 | const { output: mbStyle } = await styleParser.writeStyle(line_patternline);
325 | expect(mbStyle).toBeDefined();
326 | expect(mbStyle).toEqual(mb_line_patternline_metadata);
327 | });
328 |
329 | it('can write a mapbox Fill style', async () => {
330 | expect.assertions(2);
331 | const { output: mbStyle } = await styleParser.writeStyle(fill_simplefill);
332 | expect(mbStyle).toBeDefined();
333 | expect(mbStyle).toEqual(mb_fill_simplefill_metadata);
334 | });
335 |
336 | it('can write a mapbox Fill style with fill pattern', async () => {
337 | expect.assertions(2);
338 | const { output: mbStyle } = await styleParser.writeStyle(fill_patternfill);
339 | expect(mbStyle).toBeDefined();
340 | expect(mbStyle).toEqual(mb_fill_patternfill_metadata);
341 | });
342 |
343 | it('can write a mapbox Fill style with outline', async () => {
344 | expect.assertions(2);
345 | const { output: mbStyle } = await styleParser.writeStyle(fill_simplefill_outline);
346 | expect(mbStyle).toBeDefined();
347 | expect(mbStyle).toEqual(mb_fill_simplefill_outline_metadata);
348 | });
349 |
350 | it('can write a mapbox Text style', async () => {
351 | expect.assertions(2);
352 | const { output: mbStyle } = await styleParser.writeStyle(point_simpletext);
353 | expect(mbStyle).toBeDefined();
354 | expect(mbStyle).toEqual(mb_point_simpletext_metadata);
355 | });
356 |
357 | it('can write a mapbox Text style with a placeholder Text', async () => {
358 | expect.assertions(2);
359 | const { output: mbStyle } = await styleParser.writeStyle(point_placeholdertext_simple);
360 | expect(mbStyle).toBeDefined();
361 | expect(mbStyle).toEqual(mb_point_placeholdertext_simple_metadata);
362 | });
363 |
364 | it('can write a mapbox Circle style', async () => {
365 | expect.assertions(2);
366 | const { output: mbStyle } = await styleParser.writeStyle(circle_simplecircle);
367 | expect(mbStyle).toBeDefined();
368 | expect(mbStyle).toEqual(mb_circle_simplecircle_metadata);
369 | });
370 |
371 | it('can write a mapbox style with multiple symbolizers', async () => {
372 | expect.assertions(2);
373 | const { output: mbStyle } = await styleParser.writeStyle(multi_simpleline_simplefill);
374 | expect(mbStyle).toBeDefined();
375 | expect(mbStyle).toEqual(mb_multi_simpleline_simplefill_metadata);
376 | });
377 |
378 | it('can write a mapbox style with multiple rules', async () => {
379 | expect.assertions(2);
380 | const { output: mbStyle } = await styleParser.writeStyle(multi_rule_line_fill);
381 | expect(mbStyle).toBeDefined();
382 | expect(mbStyle).toEqual(mb_multi_rule_line_fill_metadata);
383 | });
384 |
385 | it('can write a mapbox text line placement', async() => {
386 | expect.assertions(2);
387 | const {output: mbStyle} = await styleParser.writeStyle(text_placement_line);
388 | expect(mbStyle).toBeDefined();
389 | expect(mbStyle).toEqual(mb_text_placement_line_metadata);
390 | });
391 | it('can write a mapbox text line center placement', async() => {
392 | expect.assertions(2);
393 | const {output: mbStyle} = await styleParser.writeStyle(text_placement_line_center);
394 | expect(mbStyle).toBeDefined();
395 | expect(mbStyle).toEqual(mb_text_placement_line_center_metadata);
396 | });
397 | it('can write a mapbox text point placement', async() => {
398 | expect.assertions(2);
399 | const {output: mbStyle} = await styleParser.writeStyle(text_placement_point);
400 | expect(mbStyle).toBeDefined();
401 | expect(mbStyle).toEqual(mb_text_placement_point_metadata);
402 | });
403 | it('can write a mapbox style with a complex filter', async () => {
404 | expect.assertions(2);
405 | const { output: mbStyle } = await styleParser.writeStyle(line_simpleline_basefilter);
406 | expect(mbStyle).toBeDefined();
407 | expect(mbStyle).toEqual(mb_line_simpleline_basefilter_metadata);
408 | });
409 |
410 | it('can write a mapbox style with min and max zoom', async () => {
411 | // bun does not fully support this yet
412 | // expect.assertions(3);
413 | const { output: mbStyle } = await styleParser.writeStyle(line_simpleline_zoom);
414 | expect(mbStyle).toBeDefined();
415 | const layer = mbStyle?.layers?.[0] as Exclude;
416 | const mbLayers = mb_line_simpleline_zoom_metadata.layers as (Exclude)[];
417 | expect(layer.minzoom).toBeCloseTo(mbLayers[0].minzoom!, 0);
418 | expect(layer.maxzoom).toBeCloseTo(mbLayers[0].maxzoom!, 0);
419 | });
420 |
421 | it('can write a mapbox style with an icon', async () => {
422 | expect.assertions(2);
423 | const { output: mbStyle } = await styleParser.writeStyle(icon_simpleicon);
424 | expect(mbStyle).toBeDefined();
425 | expect(mbStyle).toEqual(mb_icon_simpleicon_metadata);
426 | });
427 |
428 | it('can write a mapbox style with an icon and resolves mapbox api', async () => {
429 | expect.assertions(2);
430 | const { output: mbStyle } = await styleParser.writeStyle(icon_simpleicon_mapboxapi);
431 | expect(mbStyle).toBeDefined();
432 | expect(mbStyle).toEqual(mb_icon_simpleicon_mapboxapi_metadata);
433 | });
434 |
435 | it('can write a mapbox style with icontext symbolizer', async () => {
436 | const { output: mbStyle } = await styleParser.writeStyle(icontext_symbolizer_metadata);
437 | expect(mbStyle).toBeDefined();
438 | expect(mbStyle).toEqual(mb_icontext_symbolizer_metadata);
439 | });
440 |
441 | it('can properly resolve the source mapping', async () => {
442 | const { output: mbStyle } = await styleParser.writeStyle(source_mapping);
443 | expect(mbStyle).toBeDefined();
444 | expect(mbStyle).toEqual(mb_source_mapping_metadata);
445 | });
446 |
447 | it('can properly resolve the source layer mapping', async () => {
448 | const { output: mbStyle } = await styleParser.writeStyle(source_layer_mapping);
449 | expect(mbStyle).toBeDefined();
450 | expect(mbStyle).toEqual(mb_source_layer_mapping_metadata);
451 | });
452 | });
453 | });
454 |
--------------------------------------------------------------------------------