Compare commits

...

18 commits
v1.2.0 ... main

Author SHA1 Message Date
7a9581fc54 🚧Move to local versions 2025-04-10 13:20:56 +02:00
1e1888c733
♻️ Move over to implementations 2025-04-08 09:08:22 +02:00
5b884387a6
🔖 Version 1.2.2 2025-03-01 00:33:46 +01:00
46d15f59e4
♻️ Slightly clean up caching 2025-03-01 00:20:05 +01:00
3a4d721a7e
🚧 Add labels for implementation 2025-02-28 23:44:50 +01:00
7dc524edbf
⬇️ Change version 2025-02-28 21:35:22 +01:00
5ec799e4b3
💚 Add path back (oops) 2025-02-28 21:33:34 +01:00
0bcda3bc24
💚 Add base URL to workflow 2025-02-28 21:32:05 +01:00
6e8480cd1c
👷 Move workflows 2025-02-28 21:29:31 +01:00
e60fd45214
🚚 Update URLS, add publish scripts 2025-02-28 21:13:07 +01:00
3ac1f33971
⬇️ Downgrade @types/vscode 2025-02-28 20:52:23 +01:00
2bcb259a9b
🐛 Fix missing implementations with asterisk 2025-02-21 01:28:48 +01:00
d575c4fc6c
⬆️ Update dependencies 2025-02-21 01:23:29 +01:00
3d54501219
🐛 Fix incorrect command id 2025-02-21 01:21:56 +01:00
3519438094
🔖 Version 1.2.1 2025-02-20 23:57:52 +01:00
7e73d21e34
🐛 Fix layer definition for lists 2025-02-20 23:55:20 +01:00
24abec9c6d
Also recognize socialImage 2025-02-20 23:55:07 +01:00
4f049d2ce9
✏️ Fix typo 2025-01-15 22:39:16 +01:00
14 changed files with 388 additions and 257 deletions

View file

@ -0,0 +1,23 @@
on:
push:
paths-ignore:
- "**.md"
pull_request:
paths-ignore:
- "**.md"
jobs:
build:
runs-on: docker
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: npm install
- name: Install VSCE
run: npm install -g vsce
- name: Build
run: vsce package -o mapcomplete.vsix --baseContentUrl https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/src/branch/main/ --baseImagesUrl https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/media/branch/main/
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: mapcomplete
path: mapcomplete.vsix

View file

@ -8,9 +8,13 @@ on:
- "**.md"
jobs:
lint:
runs-on: ubuntu-latest
runs-on: docker
steps:
- uses: actions/checkout@v4
- uses: https://source.mapcomplete.org/actions/checkout@v4
- name: Set up Node.js
uses: https://source.mapcomplete.org/actions/setup-node@v4
with:
node-version: "20"
- name: Install dependencies
run: npm install
- name: Lint

View file

@ -1,16 +0,0 @@
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule:
interval: weekly
commit-message:
prefix: "⬆️"
open-pull-requests-limit: 10
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
commit-message:
prefix: "⬆️"
open-pull-requests-limit: 10

View file

@ -1,24 +0,0 @@
name: Build extension
on:
push:
paths-ignore:
- "**.md"
pull_request:
paths-ignore:
- "**.md"
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: npm install
- name: Instal VSCE
run: npm install -g vsce
- name: Build
run: vsce package -o mapcomplete.vsix
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: mapcomplete
path: mapcomplete.vsix

View file

@ -2,6 +2,29 @@
All notable changes to this project will be documented in this file.
## Version 1.2.3 (2025-04-XX)
### Fixed
- Instead of using implementations the extension now correctly used references.
## Version 1.2.2 (2025-03-01)
This is the last release of the extension on GitHub, from now on you'll be able to find the source code on the [MapComplete Forgejo](https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode). Releases will still be available on the VScode Marketplace and Open VSX as well.
### Fixed
- When a tagRendering is re-used by `layer.*`, it's also picked up by the implementation support ([#34](https://github.com/RobinLinde/MapCompleteVScode/issues/34)).
- Fix a wrong ID for the refresh command.
- Handle labels (mostly) correctly in the implementation support. ([#35](https://github.com/RobinLinde/MapCompleteVScode/issues/35))
## Version 1.2.1 (2025-02-20)
### Fixed
- Layer definition also works for lists in the `builtin` property.
- The `socialImage` is now also clickable.
## Version 1.2.0 (2025-01-15)
### Added
@ -20,7 +43,7 @@ All notable changes to this project will be documented in this file.
### Fixed
- TagsRenderings, filters and colours with in override or overrideAll were not working correctly.
- TagRenderings, filters and colours with in override or overrideAll were not working correctly.
- Colours were not correctly parsed when using hex colours (oops).
- All files were included in the extension, not just the compiled ones. This made the extension about 50kb larger than it needed to be.

View file

@ -1,6 +1,6 @@
# MapCompleteVScode
This is a Visual Studio Code extension for [MapComplete](https://github.com/pietervdvn/MapComplete).
This is a Visual Studio Code extension for [MapComplete](https://source.mapcomplete.org/MapComplete/MapComplete).
It adds autocompletion and defintion support for the MapComplete theme and layer configuration files.
Currently the following features are supported:
@ -50,12 +50,12 @@ ext install robin-van-der-linde.mapcompletevscode
### From the .vsix file
You can also install the extension from the .vsix file. You can download the latest version from the [releases page](https://github.com/RobinLinde/MapCompleteVScode/releases). After downloading the .vsix file, you should be able to install it by going to extensions in Visual Studio Code and clicking on the three dots in the top right corner. Then click on "Install from VSIX..." and select the downloaded .vsix file.
You can also install the extension from the .vsix file. You can download the latest version from the [releases page](https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/releases). After downloading the .vsix file, you should be able to install it by going to extensions in Visual Studio Code and clicking on the three dots in the top right corner. Then click on "Install from VSIX..." and select the downloaded .vsix file.
It's also possible to install builds for any commit in any branch by checking out the workflow run for the commit you want to install, and downloading the .vsix file from the artifacts.
## Usage
Most of the features should be pretty self-explanatory. As for the implementation support, the 'anchor' for this is the id property of the layer, tagRendering or filter. This means that if you want to see where a layer is used, you should be able to see all uses by using `CTRL+F12` on the id property of the layer, or by right-clicking on the id property and selecting "Go to Implementations".
Most of the features should be pretty self-explanatory. As for references support, the 'anchor' for this is the id property of the layer, tagRendering or filter. This means that if you want to see where a layer is used, you should be able to see all uses by using `SHIFT+F12` on the id property of the layer, or by right-clicking on the id property and selecting "Go to References".
![Demo showing implementation support for tagRenderings](images/implementation.gif)

View file

@ -7,4 +7,4 @@ For convenience, this license is also available in the [`LICENSE.txt`](LICENSE.t
## Files
- [`demo.gif`](demo.gif): A demo of the extension in action.
- [`icon.png`](icon.png): The icon of the extension. Originally created by [pietervdvn](https://github.com/pietervdvn).
- [`icon.png`](icon.png): The icon of the extension. Originally created by [pietervdvn](https://source.mapcomplete.org/pietervdvn).

178
package-lock.json generated
View file

@ -1,24 +1,24 @@
{
"name": "mapcompletevscode",
"version": "1.2.0",
"version": "1.2.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "mapcompletevscode",
"version": "1.2.0",
"version": "1.2.2",
"license": "MIT",
"dependencies": {
"jsonc-parser": "^3.3.1"
},
"devDependencies": {
"@eslint/js": "^9.18.0",
"@stylistic/eslint-plugin": "^2.13.0",
"@eslint/js": "^9.20.0",
"@stylistic/eslint-plugin": "^4.0.1",
"@types/node": "^22",
"@types/vscode": "^1.73.0",
"eslint": "^9.18.0",
"eslint": "^9.20.1",
"typescript": "^5.7.3",
"typescript-eslint": "^8.20.0"
"typescript-eslint": "^8.24.1"
},
"engines": {
"vscode": "^1.73.0"
@ -167,9 +167,9 @@
}
},
"node_modules/@eslint/js": {
"version": "9.18.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.18.0.tgz",
"integrity": "sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==",
"version": "9.20.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.20.0.tgz",
"integrity": "sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==",
"dev": true,
"license": "MIT",
"engines": {
@ -305,13 +305,13 @@
}
},
"node_modules/@stylistic/eslint-plugin": {
"version": "2.13.0",
"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.13.0.tgz",
"integrity": "sha512-RnO1SaiCFHn666wNz2QfZEFxvmiNRqhzaMXHXxXXKt+MEP7aajlPxUSMIQpKAaJfverpovEYqjBOXDq6dDcaOQ==",
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-4.0.1.tgz",
"integrity": "sha512-RwKkRKiDrF4ptiur54ckDhOByQYKYZ1dEmI5K8BJCmuGpauFJXzVL1UQYTA2zq702CqMFdYiJcVFJWfokIgFxw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/utils": "^8.13.0",
"@typescript-eslint/utils": "^8.23.0",
"eslint-visitor-keys": "^4.2.0",
"espree": "^10.3.0",
"estraverse": "^5.3.0",
@ -321,7 +321,7 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"peerDependencies": {
"eslint": ">=8.40.0"
"eslint": ">=9.0.0"
}
},
"node_modules/@types/estree": {
@ -348,28 +348,28 @@
}
},
"node_modules/@types/vscode": {
"version": "1.96.0",
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.96.0.tgz",
"integrity": "sha512-qvZbSZo+K4ZYmmDuaodMbAa67Pl6VDQzLKFka6rq+3WUTY4Kro7Bwoi0CuZLO/wema0ygcmpwow7zZfPJTs5jg==",
"version": "1.97.0",
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.97.0.tgz",
"integrity": "sha512-ueE73loeOTe7olaVyqP9mrRI54kVPJifUPjblZo9fYcv1CuVLPOEKEkqW0GkqPC454+nCEoigLWnC2Pp7prZ9w==",
"dev": true,
"license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.20.0.tgz",
"integrity": "sha512-naduuphVw5StFfqp4Gq4WhIBE2gN1GEmMUExpJYknZJdRnc+2gDzB8Z3+5+/Kv33hPQRDGzQO/0opHE72lZZ6A==",
"version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.1.tgz",
"integrity": "sha512-ll1StnKtBigWIGqvYDVuDmXJHVH4zLVot1yQ4fJtLpL7qacwkxJc1T0bptqw+miBQ/QfUbhl1TcQ4accW5KUyA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "8.20.0",
"@typescript-eslint/type-utils": "8.20.0",
"@typescript-eslint/utils": "8.20.0",
"@typescript-eslint/visitor-keys": "8.20.0",
"@typescript-eslint/scope-manager": "8.24.1",
"@typescript-eslint/type-utils": "8.24.1",
"@typescript-eslint/utils": "8.24.1",
"@typescript-eslint/visitor-keys": "8.24.1",
"graphemer": "^1.4.0",
"ignore": "^5.3.1",
"natural-compare": "^1.4.0",
"ts-api-utils": "^2.0.0"
"ts-api-utils": "^2.0.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -385,16 +385,16 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.20.0.tgz",
"integrity": "sha512-gKXG7A5HMyjDIedBi6bUrDcun8GIjnI8qOwVLiY3rx6T/sHP/19XLJOnIq/FgQvWLHja5JN/LSE7eklNBr612g==",
"version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.24.1.tgz",
"integrity": "sha512-Tqoa05bu+t5s8CTZFaGpCH2ub3QeT9YDkXbPd3uQ4SfsLoh1/vv2GEYAioPoxCWJJNsenXlC88tRjwoHNts1oQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/scope-manager": "8.20.0",
"@typescript-eslint/types": "8.20.0",
"@typescript-eslint/typescript-estree": "8.20.0",
"@typescript-eslint/visitor-keys": "8.20.0",
"@typescript-eslint/scope-manager": "8.24.1",
"@typescript-eslint/types": "8.24.1",
"@typescript-eslint/typescript-estree": "8.24.1",
"@typescript-eslint/visitor-keys": "8.24.1",
"debug": "^4.3.4"
},
"engines": {
@ -410,14 +410,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.20.0.tgz",
"integrity": "sha512-J7+VkpeGzhOt3FeG1+SzhiMj9NzGD/M6KoGn9f4dbz3YzK9hvbhVTmLj/HiTp9DazIzJ8B4XcM80LrR9Dm1rJw==",
"version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.24.1.tgz",
"integrity": "sha512-OdQr6BNBzwRjNEXMQyaGyZzgg7wzjYKfX2ZBV3E04hUCBDv3GQCHiz9RpqdUIiVrMgJGkXm3tcEh4vFSHreS2Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.20.0",
"@typescript-eslint/visitor-keys": "8.20.0"
"@typescript-eslint/types": "8.24.1",
"@typescript-eslint/visitor-keys": "8.24.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -428,16 +428,16 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.20.0.tgz",
"integrity": "sha512-bPC+j71GGvA7rVNAHAtOjbVXbLN5PkwqMvy1cwGeaxUoRQXVuKCebRoLzm+IPW/NtFFpstn1ummSIasD5t60GA==",
"version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.24.1.tgz",
"integrity": "sha512-/Do9fmNgCsQ+K4rCz0STI7lYB4phTtEXqqCAs3gZW0pnK7lWNkvWd5iW545GSmApm4AzmQXmSqXPO565B4WVrw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/typescript-estree": "8.20.0",
"@typescript-eslint/utils": "8.20.0",
"@typescript-eslint/typescript-estree": "8.24.1",
"@typescript-eslint/utils": "8.24.1",
"debug": "^4.3.4",
"ts-api-utils": "^2.0.0"
"ts-api-utils": "^2.0.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -452,9 +452,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.20.0.tgz",
"integrity": "sha512-cqaMiY72CkP+2xZRrFt3ExRBu0WmVitN/rYPZErA80mHjHx/Svgp8yfbzkJmDoQ/whcytOPO9/IZXnOc+wigRA==",
"version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.24.1.tgz",
"integrity": "sha512-9kqJ+2DkUXiuhoiYIUvIYjGcwle8pcPpdlfkemGvTObzgmYfJ5d0Qm6jwb4NBXP9W1I5tss0VIAnWFumz3mC5A==",
"dev": true,
"license": "MIT",
"engines": {
@ -466,20 +466,20 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.20.0.tgz",
"integrity": "sha512-Y7ncuy78bJqHI35NwzWol8E0X7XkRVS4K4P4TCyzWkOJih5NDvtoRDW4Ba9YJJoB2igm9yXDdYI/+fkiiAxPzA==",
"version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.1.tgz",
"integrity": "sha512-UPyy4MJ/0RE648DSKQe9g0VDSehPINiejjA6ElqnFaFIhI6ZEiZAkUI0D5MCk0bQcTf/LVqZStvQ6K4lPn/BRg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.20.0",
"@typescript-eslint/visitor-keys": "8.20.0",
"@typescript-eslint/types": "8.24.1",
"@typescript-eslint/visitor-keys": "8.24.1",
"debug": "^4.3.4",
"fast-glob": "^3.3.2",
"is-glob": "^4.0.3",
"minimatch": "^9.0.4",
"semver": "^7.6.0",
"ts-api-utils": "^2.0.0"
"ts-api-utils": "^2.0.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -493,16 +493,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.20.0.tgz",
"integrity": "sha512-dq70RUw6UK9ei7vxc4KQtBRk7qkHZv447OUZ6RPQMQl71I3NZxQJX/f32Smr+iqWrB02pHKn2yAdHBb0KNrRMA==",
"version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.24.1.tgz",
"integrity": "sha512-OOcg3PMMQx9EXspId5iktsI3eMaXVwlhC8BvNnX6B5w9a4dVgpkQZuU8Hy67TolKcl+iFWq0XX+jbDGN4xWxjQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
"@typescript-eslint/scope-manager": "8.20.0",
"@typescript-eslint/types": "8.20.0",
"@typescript-eslint/typescript-estree": "8.20.0"
"@typescript-eslint/scope-manager": "8.24.1",
"@typescript-eslint/types": "8.24.1",
"@typescript-eslint/typescript-estree": "8.24.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -517,13 +517,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.20.0.tgz",
"integrity": "sha512-v/BpkeeYAsPkKCkR8BDwcno0llhzWVqPOamQrAEMdpZav2Y9OVjd9dwJyBLJWwf335B5DmlifECIkZRJCaGaHA==",
"version": "8.24.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.1.tgz",
"integrity": "sha512-EwVHlp5l+2vp8CoqJm9KikPZgi3gbdZAtabKT9KPShGeOcJhsv4Zdo3oc8T8I0uKEmYoU4ItyxbptjF08enaxg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.20.0",
"@typescript-eslint/types": "8.24.1",
"eslint-visitor-keys": "^4.2.0"
},
"engines": {
@ -735,18 +735,18 @@
}
},
"node_modules/eslint": {
"version": "9.18.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.18.0.tgz",
"integrity": "sha512-+waTfRWQlSbpt3KWE+CjrPPYnbq9kfZIYUqapc0uBXyjTp8aYXZDsUH16m39Ryq3NjAVP4tjuF7KaukeqoCoaA==",
"version": "9.20.1",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.20.1.tgz",
"integrity": "sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1",
"@eslint/config-array": "^0.19.0",
"@eslint/core": "^0.10.0",
"@eslint/core": "^0.11.0",
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "9.18.0",
"@eslint/js": "9.20.0",
"@eslint/plugin-kit": "^0.2.5",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
@ -824,6 +824,19 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint/node_modules/@eslint/core": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.11.0.tgz",
"integrity": "sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@types/json-schema": "^7.0.15"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/eslint/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -964,9 +977,9 @@
"license": "MIT"
},
"node_modules/fastq": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz",
"integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==",
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz",
"integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==",
"dev": true,
"license": "ISC",
"dependencies": {
@ -1506,9 +1519,9 @@
}
},
"node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"version": "7.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
"dev": true,
"license": "ISC",
"bin": {
@ -1581,10 +1594,11 @@
}
},
"node_modules/ts-api-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz",
"integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz",
"integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18.12"
},
@ -1620,15 +1634,15 @@
}
},
"node_modules/typescript-eslint": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.20.0.tgz",
"integrity": "sha512-Kxz2QRFsgbWj6Xcftlw3Dd154b3cEPFqQC+qMZrMypSijPd4UanKKvoKDrJ4o8AIfZFKAF+7sMaEIR8mTElozA==",
"version": "8.24.1",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.24.1.tgz",
"integrity": "sha512-cw3rEdzDqBs70TIcb0Gdzbt6h11BSs2pS0yaq7hDWDBtCCSei1pPSUXE9qUdQ/Wm9NgFg8mKtMt1b8fTHIl1jA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/eslint-plugin": "8.20.0",
"@typescript-eslint/parser": "8.20.0",
"@typescript-eslint/utils": "8.20.0"
"@typescript-eslint/eslint-plugin": "8.24.1",
"@typescript-eslint/parser": "8.24.1",
"@typescript-eslint/utils": "8.24.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"

View file

@ -1,7 +1,7 @@
{
"name": "mapcompletevscode",
"displayName": "MapComplete VScode",
"version": "1.2.0",
"version": "1.2.2",
"publisher": "robin-van-der-linde",
"author": {
"name": "Robin van der Linde",
@ -11,7 +11,11 @@
"icon": "images/icon.png",
"repository": {
"type": "git",
"url": "https://github.com/RobinLinde/MapCompleteVSCode.git"
"url": "https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode.git"
},
"homepage": "https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode",
"bugs": {
"url": "https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/issues"
},
"description": "Extension providing autocompletion and definition supoort for MapComplete themes and layers.",
"keywords": [
@ -36,16 +40,20 @@
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
"lint": "eslint",
"watch": "tsc -watch -p ./"
"watch": "tsc -watch -p ./",
"package": "vsce package --baseContentUrl https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/src/branch/main/ --baseImagesUrl https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/media/branch/main/",
"publish:vsc": "vsce publish --baseContentUrl https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/src/branch/main/ --baseImagesUrl https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/media/branch/main/",
"publish:ovsx": "ovsx publish --baseContentUrl https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/src/branch/main/ --baseImagesUrl https://source.mapcomplete.org/Robin-van-der-Linde/MapCompleteVScode/media/branch/main/",
"publish": "npm run publish:vsc && npm run publish:ovsx"
},
"devDependencies": {
"@eslint/js": "^9.18.0",
"@stylistic/eslint-plugin": "^2.13.0",
"@eslint/js": "^9.20.0",
"@stylistic/eslint-plugin": "^4.0.1",
"@types/node": "^22",
"@types/vscode": "^1.73.0",
"eslint": "^9.18.0",
"eslint": "^9.20.1",
"typescript": "^5.7.3",
"typescript-eslint": "^8.20.0"
"typescript-eslint": "^8.24.1"
},
"dependencies": {
"jsonc-parser": "^3.3.1"

View file

@ -4,11 +4,11 @@ import { colorProvider, iconDefinitionProvider } from "./generic";
import {
filterCompletionProvider,
filterDefinitionProvider,
filterImplementationProvider,
layerImplementationProvider,
filterReferenceProvider,
layerReferenceProvider,
tagRenderingCompletionProvider,
tagRenderingDefinitionProvider,
tagRenderingImplementationProvider,
tagRenderingReferenceProvider,
} from "./layers";
import { pathDefinitionProvider } from "./license_info";
import { CacheWorker } from "./utils/cache";
@ -29,7 +29,7 @@ export async function activate(context: vscode.ExtensionContext) {
});
// Listen for refreshCache command
vscode.commands.registerCommand("mapcomplete.refreshCache", async () => {
vscode.commands.registerCommand("mapcomplete.refresh", async () => {
if (cacheWorker) {
await cacheWorker.refreshCache();
}
@ -44,9 +44,9 @@ export async function activate(context: vscode.ExtensionContext) {
tagRenderingDefinitionProvider,
filterCompletionProvider,
filterDefinitionProvider,
tagRenderingImplementationProvider,
filterImplementationProvider,
layerImplementationProvider
tagRenderingReferenceProvider,
filterReferenceProvider,
layerReferenceProvider
);
// Activate all license info related features

View file

@ -14,6 +14,11 @@ import {
/**
* This provider will provide completions for icons, based on the files in the assets/svg folder
*
* JSON paths:
* - icon
* - icon.render
* - icon.mappings.{index}.then
*/
export const iconCompletionProvider =
vscode.languages.registerCompletionItemProvider(
@ -72,6 +77,12 @@ export const iconCompletionProvider =
* Icon definition provider
*
* This provider will provide a definition for icons, allowing users to jump to the icon file
*
* JSON paths:
* - icon
* - icon.render
* - icon.mappings.{index}.then
* - socialImage
*/
export const iconDefinitionProvider =
vscode.languages.registerDefinitionProvider(
@ -90,7 +101,14 @@ export const iconDefinitionProvider =
const jsonPath = getCursorPath(text, position);
const rawJsonPath = getRawCursorPath(text, position);
const regexes = [/icon$/, /icon.render/, /icon.mappings.\d+.then$/];
console.log("Icon path:", jsonPath);
const regexes = [
/icon$/,
/icon.render/,
/icon.mappings.\d+.then$/,
/socialImage/,
];
if (regexes.some((regex) => regex.exec(jsonPath))) {
const iconPath = getValueFromPath(text, rawJsonPath);

View file

@ -173,20 +173,20 @@ export const tagRenderingDefinitionProvider =
}
);
export const tagRenderingImplementationProvider =
vscode.languages.registerImplementationProvider(
export const tagRenderingReferenceProvider =
vscode.languages.registerReferenceProvider(
{
language: "json",
scheme: "file",
pattern: "**/assets/*/*/*.json",
},
{
async provideImplementation(
async provideReferences(
document: vscode.TextDocument,
position: vscode.Position
) {
if (vscode.workspace.getConfiguration("mapcomplete").get("caching")) {
console.log("tagRenderingImplementationProvider");
console.log("tagRenderingReferenceProvider");
const text = document.getText();
const jsonPath = getCursorPath(text, position);
const rawJsonPath = getRawCursorPath(text, position);
@ -207,7 +207,7 @@ export const tagRenderingImplementationProvider =
} else {
console.log(`Found ${references.length} references to ${to}`);
const links: vscode.DefinitionLink[] = [];
const links: vscode.Location[] = [];
for (const reference of references) {
console.log(
`Pushing link from ${document.fileName} to ${reference.reference?.from.uri?.fsPath} at ${reference.reference?.to.range?.[0]?.line}:${reference.reference?.to.range?.[0]?.character}`,
@ -217,19 +217,13 @@ export const tagRenderingImplementationProvider =
// Check if we have a targetUri
if (reference.reference?.from.uri) {
links.push({
originSelectionRange: new vscode.Range(
reference.reference?.to?.range?.[0]?.line ?? 0,
reference.reference?.to?.range?.[0]?.character ?? 0,
reference.reference?.to?.range?.[1]?.line ?? 0,
reference.reference?.to?.range?.[1]?.character ?? 0
),
targetRange: new vscode.Range(
range: new vscode.Range(
reference.reference?.from?.range?.[0]?.line ?? 0,
reference.reference?.from?.range?.[0]?.character ?? 0,
reference.reference?.from?.range?.[1]?.line ?? 0,
reference.reference?.from?.range?.[1]?.character ?? 0
),
targetUri: reference.reference?.from?.uri,
uri: reference.reference?.from?.uri,
});
} else {
console.error("Incomplete reference", reference);
@ -407,20 +401,20 @@ export const filterDefinitionProvider =
}
);
export const filterImplementationProvider =
vscode.languages.registerImplementationProvider(
export const filterReferenceProvider =
vscode.languages.registerReferenceProvider(
{
language: "json",
scheme: "file",
pattern: "**/assets/*/*/*.json",
},
{
async provideImplementation(
async provideReferences(
document: vscode.TextDocument,
position: vscode.Position
) {
if (vscode.workspace.getConfiguration("mapcomplete").get("caching")) {
console.log("filterImplementationProvider");
console.log("filterReferenceProvider");
const text = document.getText();
const jsonPath = getCursorPath(text, position);
const rawJsonPath = getRawCursorPath(text, position);
@ -442,7 +436,7 @@ export const filterImplementationProvider =
} else {
console.log(`Found ${references.length} references to ${to}`);
const links: vscode.DefinitionLink[] = [];
const links: vscode.Location[] = [];
for (const reference of references) {
console.log(
`Pushing link from ${document.fileName} to ${reference.reference?.from.uri?.fsPath} at ${reference.reference?.to.range?.[0]?.line}:${reference.reference?.to.range?.[0]?.character}`,
@ -452,19 +446,13 @@ export const filterImplementationProvider =
// Check if we have a targetUri
if (reference.reference?.from.uri) {
links.push({
originSelectionRange: new vscode.Range(
reference.reference?.to?.range?.[0]?.line ?? 0,
reference.reference?.to?.range?.[0]?.character ?? 0,
reference.reference?.to?.range?.[1]?.line ?? 0,
reference.reference?.to?.range?.[1]?.character ?? 0
),
targetRange: new vscode.Range(
range: new vscode.Range(
reference.reference?.from?.range?.[0]?.line ?? 0,
reference.reference?.from?.range?.[0]?.character ?? 0,
reference.reference?.from?.range?.[1]?.line ?? 0,
reference.reference?.from?.range?.[1]?.character ?? 0
),
targetUri: reference.reference?.from?.uri,
uri: reference.reference?.from?.uri,
});
} else {
console.error("Incomplete reference", reference);
@ -484,20 +472,20 @@ export const filterImplementationProvider =
}
);
export const layerImplementationProvider =
vscode.languages.registerImplementationProvider(
export const layerReferenceProvider =
vscode.languages.registerReferenceProvider(
{
language: "json",
scheme: "file",
pattern: "**/assets/layers/*/*.json",
},
{
async provideImplementation(
async provideReferences(
document: vscode.TextDocument,
position: vscode.Position
) {
if (vscode.workspace.getConfiguration("mapcomplete").get("caching")) {
console.log("layerImplementationProvider");
console.log("layerReferenceProvider");
const text = document.getText();
const jsonPath = getCursorPath(text, position);
const rawJsonPath = getRawCursorPath(text, position);
@ -519,7 +507,7 @@ export const layerImplementationProvider =
} else {
console.log(`Found ${references.length} references to ${to}`);
const links: vscode.DefinitionLink[] = [];
const links: vscode.Location[] = [];
for (const reference of references) {
console.log(
`Pushing link from ${document.fileName} to ${reference.reference?.from.uri?.fsPath} at ${reference.reference?.to.range?.[0]?.line}:${reference.reference?.to.range?.[0]?.character}`,
@ -529,19 +517,13 @@ export const layerImplementationProvider =
// Check if we have a targetUri
if (reference.reference?.from.uri) {
links.push({
originSelectionRange: new vscode.Range(
reference.reference?.to?.range?.[0]?.line ?? 0,
reference.reference?.to?.range?.[0]?.character ?? 0,
reference.reference?.to?.range?.[1]?.line ?? 0,
reference.reference?.to?.range?.[1]?.character ?? 0
),
targetRange: new vscode.Range(
range: new vscode.Range(
reference.reference?.from?.range?.[0]?.line ?? 0,
reference.reference?.from?.range?.[0]?.character ?? 0,
reference.reference?.from?.range?.[1]?.line ?? 0,
reference.reference?.from?.range?.[1]?.character ?? 0
),
targetUri: reference.reference?.from?.uri,
uri: reference.reference?.from?.uri,
});
} else {
console.error("Incomplete reference", reference);

View file

@ -78,6 +78,7 @@ export const layerCompletionProvider =
* JSON paths:
* - layers.{index} (If this is a string)
* - layers.{index}.builtin
* - layers.{index}.builtin.{index}
* - (layers.{index}.)presets.{index}.snapToLayer(.{index})
*/
export const layerDefinitionProvider =
@ -104,7 +105,7 @@ export const layerDefinitionProvider =
const rawJsonPath = getRawCursorPath(text, position);
const regexes = [
/^layers\.\d+(.builtin)?$/,
/^layers\.\d+(.builtin(.\d+)?)?$/,
/^(layers.\d+.)?presets.\d+.snapToLayer(.\d)*$/,
];
if (regexes.some((regex) => regex.exec(jsonPath))) {

View file

@ -471,9 +471,85 @@ export class CacheWorker {
}
}
/**
* Find one or more matching tagRenderings in a layer definition text
*
* @param text the text of the layer definition
* @param identifier the identifier of the tagRendering to find, in theory this can be an id, a label or something with a wildcard
* @returns
*/
private findTagRenderingInText(
text: string,
identifier: string
): { paths: JSONPath[]; ids: string[] } {
const json = JSON.parse(text);
const tagRenderings = json.tagRenderings;
const tagRenderingIds: string[] = tagRenderings.map(
(tr: { id: string }) => tr.id
);
const tagRenderingLabels: string[][] = tagRenderings.map(
(tr: { labels: string[] }) => tr.labels
);
if (identifier.includes("*")) {
// This is a wildcard, so we need to handle it differently
const pattern = identifier.split(".")?.pop();
if (pattern) {
const regex = new RegExp(pattern.replace("*", ".*"));
const matchingTagRenderings = tagRenderingIds.filter((tr) =>
regex.test(tr)
);
const labelIndices: number[] = [];
for (let i = 0; i < tagRenderingLabels.length; i++) {
if (tagRenderingLabels[i] !== undefined) {
for (const label of tagRenderingLabels[i]) {
if (regex.test(label)) {
labelIndices.push(i);
}
}
}
}
return {
paths: [
...matchingTagRenderings.map((tr) => ["tagRenderings", tr]),
...labelIndices.map((i) => ["tagRenderings", i]),
],
ids: [
...matchingTagRenderings,
...labelIndices.map((i) => tagRenderingIds[i]),
],
};
}
} else {
// Single identifier, we just need to look through the ids and labels
const idIndex = tagRenderingIds.indexOf(identifier);
if (idIndex !== -1) {
return {
paths: [["tagRenderings", idIndex]],
ids: [identifier],
};
} else {
// Not found by id, so we need to look through the labels, which can match with more than one tagRendering
const labelIndices: number[] = [];
for (let i = 0; i < tagRenderingLabels.length; i++) {
if (tagRenderingLabels[i]?.includes(identifier)) {
labelIndices.push(i);
}
}
return {
paths: labelIndices.map((i) => ["tagRenderings", i]),
ids: labelIndices.map((i) => tagRenderingIds[i]),
};
}
}
return {
ids: [],
paths: [],
};
}
/**
* Save tag renderings to cache
* TODO: references for tagRenderings can also be a label/group, which we don't support yet
*
* @param text Text representation of layer
* @param from The theme or layer where the layer is from, e.g. layers.bicycle_rental or themes.cyclofix.layers.0
@ -528,32 +604,37 @@ export class CacheWorker {
// Read toFile and get the text
const toContent = await vscode.workspace.fs.readFile(toFile[0]);
const toText = new TextDecoder().decode(toContent);
const toJson = JSON.parse(toText);
const trIndex = toJson.tagRenderings.findIndex(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(tr: any) => tr.id === tagRendering.split(".")?.pop()
);
const toRange = getStartEnd(toText, ["tagRenderings", trIndex]);
this.cache.items.push({
id: tagRendering,
filePath: fromUri,
jsonPath: ["tagRenderings"],
type: "reference",
reference: {
from: {
id: from,
uri: fromUri,
range: [fromStartEnd.start, fromStartEnd.end],
const results = this.findTagRenderingInText(toText, tagRendering);
for (let i = 0; i < results.paths.length; i++) {
const toRange = getStartEnd(toText, results.paths[i]);
// Determine the ID of the to of the reference (original to item, but with last part replaced by the tagRendering ID)
const toId = [...to.split(".").slice(0, -1), results.ids[i]].join(
"."
);
this.cache.items.push({
id: tagRendering,
filePath: fromUri,
jsonPath: ["tagRenderings"],
type: "reference",
reference: {
from: {
id: from,
uri: fromUri,
range: [fromStartEnd.start, fromStartEnd.end],
},
to: {
id: toId,
uri: toFile[0],
range: [toRange.start, toRange.end],
},
type: "tagRendering",
},
to: {
id: to,
uri: toFile[0],
range: [toRange.start, toRange.end],
},
type: "tagRendering",
},
});
});
}
} else if (typeof tagRendering === "object") {
// This is a tagRendering, or a reference to one, but with an override
if (tagRendering.builtin) {
@ -591,32 +672,40 @@ export class CacheWorker {
// Read toFile and get the text
const toContent = await vscode.workspace.fs.readFile(toFile[0]);
const toText = new TextDecoder().decode(toContent);
const toJson = JSON.parse(toText);
const trIndex = toJson.tagRenderings.findIndex(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(tr: any) => tr.id === tagRendering.builtin.split(".")?.pop()
);
const toRange = getStartEnd(toText, ["tagRenderings", trIndex]);
this.cache.items.push({
id: tagRendering.builtin,
filePath: fromUri,
jsonPath: ["tagRenderings"],
type: "reference",
reference: {
from: {
id: from,
uri: fromUri,
range: [fromStartEnd.start, fromStartEnd.end],
const results = this.findTagRenderingInText(
toText,
tagRendering.builtin
);
for (let i = 0; i < results.paths.length; i++) {
const toRange = getStartEnd(toText, results.paths[i]);
// Determine the ID of the to of the reference (original to item, but with last part replaced by the tagRendering ID)
const toId = [...to.split(".").slice(0, -1), results.ids[i]].join(
"."
);
this.cache.items.push({
id: tagRendering.builtin,
filePath: fromUri,
jsonPath: ["tagRenderings"],
type: "reference",
reference: {
from: {
id: from,
uri: fromUri,
range: [fromStartEnd.start, fromStartEnd.end],
},
to: {
id: toId,
uri: toFile[0],
range: [toRange.start, toRange.end],
},
type: "tagRendering",
},
to: {
id: to,
uri: toFile[0],
range: [toRange.start, toRange.end],
},
type: "tagRendering",
},
});
});
}
} else {
// Multiple tagRenderings
for (const builtinTagRendering of tagRendering.builtin) {
@ -649,32 +738,41 @@ export class CacheWorker {
// Read toFile and get the text
const toContent = await vscode.workspace.fs.readFile(toFile[0]);
const toText = new TextDecoder().decode(toContent);
const toJson = JSON.parse(toText);
const trIndex = toJson.tagRenderings.findIndex(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(tr: any) => tr.id === builtinTagRendering.split(".")?.pop()
);
const toRange = getStartEnd(toText, ["tagRenderings", trIndex]);
this.cache.items.push({
id: builtinTagRendering,
filePath: fromUri,
jsonPath: ["tagRenderings"],
type: "reference",
reference: {
from: {
id: from,
uri: fromUri,
range: [fromStartEnd.start, fromStartEnd.end],
const results = this.findTagRenderingInText(
toText,
builtinTagRendering
);
for (let i = 0; i < results.paths.length; i++) {
const toRange = getStartEnd(toText, results.paths[i]);
// Determine the ID of the to of the reference (original to item, but with last part replaced by the tagRendering ID)
const toId = [
...to.split(".").slice(0, -1),
results.ids[i],
].join(".");
this.cache.items.push({
id: builtinTagRendering,
filePath: fromUri,
jsonPath: ["tagRenderings"],
type: "reference",
reference: {
from: {
id: from,
uri: fromUri,
range: [fromStartEnd.start, fromStartEnd.end],
},
to: {
id: toId,
uri: toFile[0],
range: [toRange.start, toRange.end],
},
type: "tagRendering",
},
to: {
id: to,
uri: toFile[0],
range: [toRange.start, toRange.end],
},
type: "tagRendering",
},
});
});
}
}
}
} else if (!referencesOnly) {