🎉 Initial commit
This commit is contained in:
commit
997a387a57
17 changed files with 2302 additions and 0 deletions
0
.github/dependabot.yml
vendored
Normal file
0
.github/dependabot.yml
vendored
Normal file
18
.github/workflows/build.yaml
vendored
Normal file
18
.github/workflows/build.yaml
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
name: Build extension
|
||||||
|
on: [push, pull_request]
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- 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@v2
|
||||||
|
with:
|
||||||
|
name: mapcomplete
|
||||||
|
path: mapcomplete.vsix
|
11
.github/workflows/lint.yaml
vendored
Normal file
11
.github/workflows/lint.yaml
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
name: Linter
|
||||||
|
on: [push, pull_request]
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm install
|
||||||
|
- name: Lint
|
||||||
|
run: npm run lint
|
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
node_modules
|
||||||
|
out
|
||||||
|
*.vsix
|
9
.vscode/extensions.json
vendored
Normal file
9
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
|
||||||
|
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
|
||||||
|
|
||||||
|
// List of extensions which should be recommended for users of this workspace.
|
||||||
|
"recommendations": [
|
||||||
|
"dbaeumer.vscode-eslint"
|
||||||
|
]
|
||||||
|
}
|
22
.vscode/launch.json
vendored
Normal file
22
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// A launch configuration that compiles the extension and then opens it inside a new window
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Run Extension",
|
||||||
|
"type": "extensionHost",
|
||||||
|
"request": "launch",
|
||||||
|
"runtimeExecutable": "${execPath}",
|
||||||
|
"args": [
|
||||||
|
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||||
|
],
|
||||||
|
"outFiles": [
|
||||||
|
"${workspaceFolder}/out/**/*.js"
|
||||||
|
],
|
||||||
|
"preLaunchTask": "npm: watch"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.tabSize": 2
|
||||||
|
}
|
20
.vscode/tasks.json
vendored
Normal file
20
.vscode/tasks.json
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "npm",
|
||||||
|
"script": "watch",
|
||||||
|
"problemMatcher": "$tsc-watch",
|
||||||
|
"isBackground": true,
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "never"
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
9
README.md
Normal file
9
README.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# MapCompleteVScode
|
||||||
|
|
||||||
|
This is a Visual Studio Code extension for [MapComplete](https://github.com/pietervdvn/MapComplete). It adds autocompletion and defintion support for the MapComplete theme and layer configuration files.
|
||||||
|
|
||||||
|
Not everything is supported yet, but currently the following features are supported:
|
||||||
|
|
||||||
|
- Autocompletion for the layer names
|
||||||
|
- Definition support for the layer names
|
||||||
|
- Definintion support for icons
|
44
eslint.config.mjs
Normal file
44
eslint.config.mjs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
* ESLint configuration for the project.
|
||||||
|
*
|
||||||
|
* See https://eslint.style and https://typescript-eslint.io for additional linting options.
|
||||||
|
*/
|
||||||
|
// @ts-check
|
||||||
|
import js from '@eslint/js';
|
||||||
|
import tseslint from 'typescript-eslint';
|
||||||
|
import stylistic from '@stylistic/eslint-plugin';
|
||||||
|
|
||||||
|
export default tseslint.config(
|
||||||
|
{
|
||||||
|
ignores: [
|
||||||
|
'.vscode-test',
|
||||||
|
'out',
|
||||||
|
]
|
||||||
|
},
|
||||||
|
js.configs.recommended,
|
||||||
|
...tseslint.configs.recommended,
|
||||||
|
...tseslint.configs.stylistic,
|
||||||
|
{
|
||||||
|
plugins: {
|
||||||
|
'@stylistic': stylistic
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'curly': 'warn',
|
||||||
|
'@stylistic/semi': ['warn', 'always'],
|
||||||
|
'@typescript-eslint/no-empty-function': 'off',
|
||||||
|
'@typescript-eslint/naming-convention': [
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
'selector': 'import',
|
||||||
|
'format': ['camelCase', 'PascalCase']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'@typescript-eslint/no-unused-vars': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
'argsIgnorePattern': '^_'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
1703
package-lock.json
generated
Normal file
1703
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
47
package.json
Normal file
47
package.json
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
{
|
||||||
|
"name": "mapcompletevscode",
|
||||||
|
"displayName": "MapComplete VScode",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"publisher": "robinvanderlinde",
|
||||||
|
"author": {
|
||||||
|
"name": "Robin van der Linde",
|
||||||
|
"email": "r@rlin.eu",
|
||||||
|
"url": "https://rlin.eu"
|
||||||
|
},
|
||||||
|
"description": "MapComplete extension for Visual Studio Code",
|
||||||
|
"keywords": [
|
||||||
|
"mapcomplete",
|
||||||
|
"vscode",
|
||||||
|
"extension"
|
||||||
|
],
|
||||||
|
"private": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"vscode": "^1.73.0"
|
||||||
|
},
|
||||||
|
"categories": [
|
||||||
|
"Other"
|
||||||
|
],
|
||||||
|
"activationEvents": [
|
||||||
|
"workspaceContains:**/assets/svg/mapcomplete_logo.svg"
|
||||||
|
],
|
||||||
|
"main": "./out/extension.js",
|
||||||
|
"scripts": {
|
||||||
|
"vscode:prepublish": "npm run compile",
|
||||||
|
"compile": "tsc -p ./",
|
||||||
|
"lint": "eslint",
|
||||||
|
"watch": "tsc -watch -p ./"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^9.13.0",
|
||||||
|
"@stylistic/eslint-plugin": "^2.9.0",
|
||||||
|
"@types/node": "^20",
|
||||||
|
"@types/vscode": "^1.73.0",
|
||||||
|
"eslint": "^9.13.0",
|
||||||
|
"typescript": "^5.7.2",
|
||||||
|
"typescript-eslint": "^8.16.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"jsonc-parser": "^3.3.1"
|
||||||
|
}
|
||||||
|
}
|
11
src/extension.ts
Normal file
11
src/extension.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import * as vscode from "vscode";
|
||||||
|
import { layerCompletionProvider, layerDefinitionProvider } from "./theme";
|
||||||
|
import { iconDefinitionProvider } from "./generic";
|
||||||
|
|
||||||
|
export function activate(context: vscode.ExtensionContext) {
|
||||||
|
// Activate all theme related features
|
||||||
|
context.subscriptions.push(layerCompletionProvider, layerDefinitionProvider);
|
||||||
|
|
||||||
|
// Activate all generic features
|
||||||
|
context.subscriptions.push(iconDefinitionProvider);
|
||||||
|
}
|
91
src/generic.ts
Normal file
91
src/generic.ts
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
/**
|
||||||
|
* This file contains some function that are used both in theme files, as well in layer files
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as vscode from "vscode";
|
||||||
|
import {
|
||||||
|
getCursorPath,
|
||||||
|
getRawCursorPath,
|
||||||
|
getStartEnd,
|
||||||
|
getValueFromPath,
|
||||||
|
} from "./utils";
|
||||||
|
import * as path from "path";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Icon definition provider
|
||||||
|
*
|
||||||
|
* This provider will provide a definition for icons, allowing users to jump to the icon file
|
||||||
|
*/
|
||||||
|
export const iconDefinitionProvider =
|
||||||
|
vscode.languages.registerDefinitionProvider(
|
||||||
|
{
|
||||||
|
language: "json",
|
||||||
|
scheme: "file",
|
||||||
|
pattern: "**/assets/**/*.json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provideDefinition(
|
||||||
|
document: vscode.TextDocument,
|
||||||
|
position: vscode.Position
|
||||||
|
) {
|
||||||
|
console.log("iconDefinitionProvider");
|
||||||
|
const text = document.getText();
|
||||||
|
const jsonPath = getCursorPath(text, position);
|
||||||
|
const rawJsonPath = getRawCursorPath(text, position);
|
||||||
|
|
||||||
|
const regexes = [/icon$/, /icon.render/, /icon.mappings.\d+.then$/];
|
||||||
|
|
||||||
|
for (const regex of regexes) {
|
||||||
|
if (regex.exec(jsonPath)) {
|
||||||
|
const iconPath = getValueFromPath(text, rawJsonPath);
|
||||||
|
console.log("Found reference to icon", iconPath);
|
||||||
|
|
||||||
|
let fullIconPath: string;
|
||||||
|
|
||||||
|
// Check if the path starts with a dot, if so, it's a relative path
|
||||||
|
// if not, it's a built-in icon
|
||||||
|
if (!iconPath.startsWith(".")) {
|
||||||
|
fullIconPath = path.join(
|
||||||
|
(vscode.workspace.workspaceFolders
|
||||||
|
? vscode.workspace.workspaceFolders[0].uri.fsPath
|
||||||
|
: "") || "",
|
||||||
|
"assets",
|
||||||
|
"svg",
|
||||||
|
iconPath + ".svg"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
fullIconPath = path.join(
|
||||||
|
(vscode.workspace.workspaceFolders
|
||||||
|
? vscode.workspace.workspaceFolders[0].uri.fsPath
|
||||||
|
: "") || "",
|
||||||
|
iconPath
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const startEnd = getStartEnd(text, rawJsonPath);
|
||||||
|
console.log("fullIconPath", fullIconPath);
|
||||||
|
console.log(
|
||||||
|
"startEndLines",
|
||||||
|
startEnd.start.line,
|
||||||
|
startEnd.end.line
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
"startEndChars",
|
||||||
|
startEnd.start.character,
|
||||||
|
startEnd.end.character
|
||||||
|
);
|
||||||
|
|
||||||
|
const link: vscode.DefinitionLink = {
|
||||||
|
targetUri: vscode.Uri.file(fullIconPath),
|
||||||
|
targetRange: new vscode.Range(0, 0, 0, 0),
|
||||||
|
originSelectionRange: startEnd,
|
||||||
|
};
|
||||||
|
|
||||||
|
return [link];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
141
src/theme.ts
Normal file
141
src/theme.ts
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
/**
|
||||||
|
* This file contains all functions that should be used when editing theme files
|
||||||
|
* Theme files are located in the /assets/themes/{THEME_NAME}/{THEME_NAME}.json file
|
||||||
|
*
|
||||||
|
* This consists of the following functions:
|
||||||
|
* - layerCompletionProvider: Provides a list of existing layers for autocompletion
|
||||||
|
* - layerDefinitionProvider: Provides a definition for layers, allowing users to jump to the layer definition
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as vscode from "vscode";
|
||||||
|
import * as path from "path";
|
||||||
|
import { getAvailableLayers, getCursorPath } from "./utils";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layer completion provider
|
||||||
|
*
|
||||||
|
* This provider will provide a list of available layers for autocompletion
|
||||||
|
*
|
||||||
|
* JSON paths:
|
||||||
|
* - layers.{index} (If this is a string)
|
||||||
|
* - layers.{index}.builtin
|
||||||
|
*/
|
||||||
|
export const layerCompletionProvider =
|
||||||
|
vscode.languages.registerCompletionItemProvider(
|
||||||
|
{
|
||||||
|
language: "json",
|
||||||
|
scheme: "file",
|
||||||
|
pattern: "**/assets/themes/*/*.json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
async provideCompletionItems(
|
||||||
|
document: vscode.TextDocument,
|
||||||
|
position: vscode.Position
|
||||||
|
) {
|
||||||
|
console.log("layerCompletionProvider");
|
||||||
|
// Now we'll need to try and get the current path for the cursor
|
||||||
|
const text = document.getText();
|
||||||
|
|
||||||
|
// Now we need to get the current path
|
||||||
|
const jsonPath = getCursorPath(text, position);
|
||||||
|
|
||||||
|
const regex = /^layers\.\d+(.builtin)*$/;
|
||||||
|
if (regex.exec(jsonPath)) {
|
||||||
|
// We need to get the available layers
|
||||||
|
const layers = await getAvailableLayers();
|
||||||
|
console.log(`Got ${layers.length} layers`);
|
||||||
|
|
||||||
|
const items: vscode.CompletionItem[] = [];
|
||||||
|
|
||||||
|
for (const layer of layers) {
|
||||||
|
const item = new vscode.CompletionItem(layer);
|
||||||
|
item.kind = vscode.CompletionItemKind.Value;
|
||||||
|
items.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we need to return the completion items
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layer definition provider
|
||||||
|
*
|
||||||
|
* This provider will provide a definition for layers, allowing users to jump to the layer definition
|
||||||
|
*
|
||||||
|
* JSON paths:
|
||||||
|
* - layers.{index} (If this is a string)
|
||||||
|
* - layers.{index}.builtin
|
||||||
|
*/
|
||||||
|
export const layerDefinitionProvider =
|
||||||
|
vscode.languages.registerDefinitionProvider(
|
||||||
|
{
|
||||||
|
language: "json",
|
||||||
|
scheme: "file",
|
||||||
|
pattern: "**/assets/themes/*/*.json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provideDefinition(
|
||||||
|
document: vscode.TextDocument,
|
||||||
|
position: vscode.Position
|
||||||
|
) {
|
||||||
|
console.log("layerDefinitionProvider");
|
||||||
|
|
||||||
|
// We don't want to provide definitions for the license_info.json file
|
||||||
|
if (document.fileName.endsWith("license_info.json")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = document.getText();
|
||||||
|
const jsonPath = getCursorPath(text, position);
|
||||||
|
const json = JSON.parse(text);
|
||||||
|
|
||||||
|
const regex = /^layers\.\d+(.builtin)*$/;
|
||||||
|
if (regex.exec(jsonPath)) {
|
||||||
|
const layer = json.layers[parseInt(jsonPath.split(".")[1])];
|
||||||
|
// If an item is a string, it's a reference to a layer, also if it's an object and has a builtin property
|
||||||
|
if (typeof layer === "string") {
|
||||||
|
// We have a reference to a layer
|
||||||
|
const layerPath = path.join(
|
||||||
|
(vscode.workspace.workspaceFolders
|
||||||
|
? vscode.workspace.workspaceFolders[0].uri.fsPath
|
||||||
|
: "") || "",
|
||||||
|
"assets",
|
||||||
|
"layers",
|
||||||
|
layer,
|
||||||
|
layer + ".json"
|
||||||
|
);
|
||||||
|
console.log("Found reference to layer", layerPath);
|
||||||
|
|
||||||
|
return new vscode.Location(
|
||||||
|
vscode.Uri.file(layerPath),
|
||||||
|
new vscode.Position(0, 0)
|
||||||
|
);
|
||||||
|
} else if (typeof layer === "object" && layer.builtin) {
|
||||||
|
// We have a builtin layer
|
||||||
|
const layerPath = path.join(
|
||||||
|
(vscode.workspace.workspaceFolders
|
||||||
|
? vscode.workspace.workspaceFolders[0].uri.fsPath
|
||||||
|
: "") || "",
|
||||||
|
"assets",
|
||||||
|
"layers",
|
||||||
|
layer.builtin,
|
||||||
|
layer.builtin + ".json"
|
||||||
|
);
|
||||||
|
console.log("Found reference to layer (as builtin)", layerPath);
|
||||||
|
|
||||||
|
return new vscode.Location(
|
||||||
|
vscode.Uri.file(layerPath),
|
||||||
|
new vscode.Position(0, 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
154
src/utils.ts
Normal file
154
src/utils.ts
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
import * as vscode from "vscode";
|
||||||
|
import * as path from "path";
|
||||||
|
import {
|
||||||
|
findNodeAtLocation,
|
||||||
|
getLocation,
|
||||||
|
JSONPath,
|
||||||
|
parseTree,
|
||||||
|
} from "jsonc-parser";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function to get the JSON path at the cursor position, separated by dots
|
||||||
|
*
|
||||||
|
* @param jsonText Original unparsed JSON text
|
||||||
|
* @param position VScode cursor position
|
||||||
|
* @returns JSON path as a string, separated by dots
|
||||||
|
*/
|
||||||
|
export function getCursorPath(
|
||||||
|
jsonText: string,
|
||||||
|
position: vscode.Position
|
||||||
|
): string {
|
||||||
|
return getRawCursorPath(jsonText, position).join(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function to get the JSON path at the cursor position
|
||||||
|
*
|
||||||
|
* @param jsonText Original unparsed JSON text
|
||||||
|
* @param position VScode cursor position
|
||||||
|
* @returns JSON path as an array of strings
|
||||||
|
*/
|
||||||
|
export function getRawCursorPath(
|
||||||
|
jsonText: string,
|
||||||
|
position: vscode.Position
|
||||||
|
): JSONPath {
|
||||||
|
const offset = positionToOffset(jsonText, position);
|
||||||
|
const location = getLocation(jsonText, offset);
|
||||||
|
return location.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function to convert a VScode position to a numeric offset
|
||||||
|
*
|
||||||
|
* @param text Original text content
|
||||||
|
* @param position VScode cursor position
|
||||||
|
* @returns Offset
|
||||||
|
*/
|
||||||
|
function positionToOffset(text: string, position: vscode.Position): number {
|
||||||
|
const lines = text.split("\n");
|
||||||
|
let offset = 0;
|
||||||
|
for (let i = 0; i < position.line; i++) {
|
||||||
|
offset += lines[i].length + 1; // +1 for the newline character
|
||||||
|
}
|
||||||
|
offset += position.character;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to get all available layers on disk
|
||||||
|
*
|
||||||
|
* In essence, we look for folders under the assets/layers directory
|
||||||
|
* and return the names of the folders
|
||||||
|
* @returns List of layer names
|
||||||
|
*/
|
||||||
|
export async function getAvailableLayers(): Promise<string[]> {
|
||||||
|
const layers: string[] = [];
|
||||||
|
let files = await vscode.workspace.findFiles(
|
||||||
|
"assets/layers/**/*.json",
|
||||||
|
"**/node_modules/**"
|
||||||
|
);
|
||||||
|
|
||||||
|
files = files.filter((file) => {
|
||||||
|
return !file.fsPath.includes("license_info");
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const layerName = path.basename(path.dirname(file.fsPath));
|
||||||
|
layers.push(layerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return layers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to get a range of a JSON path
|
||||||
|
* Useful for creating document links
|
||||||
|
*
|
||||||
|
* @param json file content
|
||||||
|
* @param path JSON path
|
||||||
|
* @returns Range of the path
|
||||||
|
*/
|
||||||
|
export function getStartEnd(json: string, path: JSONPath): vscode.Range {
|
||||||
|
const rootNode = parseTree(json);
|
||||||
|
if (!rootNode) {
|
||||||
|
return new vscode.Range(0, 0, 0, 0);
|
||||||
|
} else {
|
||||||
|
const node = findNodeAtLocation(rootNode, path);
|
||||||
|
if (!node) {
|
||||||
|
return new vscode.Range(0, 0, 0, 0);
|
||||||
|
} else {
|
||||||
|
return new vscode.Range(
|
||||||
|
offsetToPosition(json, node.offset + 1),
|
||||||
|
offsetToPosition(json, node.offset + node.length - 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function to convert an offset to a position
|
||||||
|
*
|
||||||
|
* @param text Text content
|
||||||
|
* @param offset Offset
|
||||||
|
* @returns Position
|
||||||
|
*/
|
||||||
|
function offsetToPosition(text: string, offset: number): vscode.Position {
|
||||||
|
const lines = text.split("\n");
|
||||||
|
let currentOffset = 0;
|
||||||
|
for (let i = 0; i < lines.length; i++) {
|
||||||
|
if (currentOffset + lines[i].length + 1 >= offset) {
|
||||||
|
return new vscode.Position(i, offset - currentOffset);
|
||||||
|
}
|
||||||
|
currentOffset += lines[i].length + 1;
|
||||||
|
}
|
||||||
|
return new vscode.Position(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function to get the value of a JSON path
|
||||||
|
*
|
||||||
|
* @param json Original JSON content
|
||||||
|
* @param path JSON path
|
||||||
|
* @returns Value of the path
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
export function getValueFromPath(json: string, path: JSONPath): any {
|
||||||
|
console.log("getValueFromPath", path);
|
||||||
|
const rootNode = parseTree(json);
|
||||||
|
if (!rootNode) {
|
||||||
|
console.log("Root node not found");
|
||||||
|
return undefined;
|
||||||
|
} else {
|
||||||
|
console.log("Root node found");
|
||||||
|
const node = findNodeAtLocation(rootNode, path);
|
||||||
|
if (!node) {
|
||||||
|
return undefined;
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
"Substring",
|
||||||
|
json.substring(node.offset, node.offset + node.length)
|
||||||
|
);
|
||||||
|
return JSON.parse(json.substring(node.offset, node.offset + node.length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
tsconfig.json
Normal file
15
tsconfig.json
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es2020",
|
||||||
|
"lib": ["es2020"],
|
||||||
|
"outDir": "out",
|
||||||
|
"sourceMap": true,
|
||||||
|
"strict": true,
|
||||||
|
"rootDir": "src"
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
".vscode-test"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in a new issue