Skip to content

Commit

Permalink
feat: implement a function findSelectionFromTextLocation (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
josdejong committed Feb 13, 2025
1 parent 2eb88f2 commit 8aef55c
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 3 deletions.
35 changes: 34 additions & 1 deletion src/lib/utils/jsonUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ import {
toJSONContent,
toTextContent,
validateContentType,
parseAndRepairOrUndefined
parseAndRepairOrUndefined,
findTextLocation,
findSelectionFromTextLocation
} from './jsonUtils.js'
import { createMultiSelection } from 'svelte-jsoneditor'

const LosslessJSONParser = { parse, stringify }

Expand Down Expand Up @@ -439,4 +442,34 @@ describe('jsonUtils', () => {
// expect(parseAndRepairOrUndefined('0123', JSON)).toEqual('0123') // FIXME
})
})

describe('findTextLocation', () => {
// TODO: write more unit tests for findTextLocation
test('find a text location', () => {
const text = `{\n "object": {\n "a":2 \n}\n}`
const path = ['object', 'a']
expect(findTextLocation(text, path)).toEqual({
path,
line: 2,
column: 4,
from: 20,
to: 23
})
})
})

describe('findSelectionFromTextLocation', () => {
// TODO: write more unit tests for findSelectionFromTextLocation
test('find the path', () => {
const text = `{\n "object": {\n "a":2 \n}\n}`

expect(findSelectionFromTextLocation(text, 20, 20)).toEqual(
createMultiSelection(['object', 'a'], ['object', 'a'])
)

expect(findSelectionFromTextLocation(text, 23, 24)).toEqual(
createMultiSelection(['object', 'a'], ['object', 'a'])
)
})
})
})
43 changes: 41 additions & 2 deletions src/lib/utils/jsonUtils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { JSONPath } from 'immutable-json-patch'
import { type JSONPath, parseJSONPointer } from 'immutable-json-patch'
import { compileJSONPointer } from 'immutable-json-patch'
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
Expand All @@ -10,11 +10,14 @@ import type {
Content,
JSONContent,
JSONParser,
JSONSelection,
MultiSelection,

Check failure on line 14 in src/lib/utils/jsonUtils.ts

View workflow job for this annotation

GitHub Actions / lint

'MultiSelection' is defined but never used
ParseError,
TextContent,
TextLocation
} from '../types'
import { int } from './numberUtils.js'
import { createMultiSelection } from '$lib/logic/selection'

/**
* Parse the JSON. if this fails, try to repair and parse.
Expand Down Expand Up @@ -201,7 +204,6 @@ export function countCharacterOccurrences(
/**
* Find the text location of a JSON path
*/
// TODO: write unit tests
export function findTextLocation(text: string, path: JSONPath): TextLocation {
try {
const jsmap = jsonSourceMap.parse(text)
Expand Down Expand Up @@ -230,6 +232,43 @@ export function findTextLocation(text: string, path: JSONPath): TextLocation {
}
}

/**
* Find the text location from a JSON path
* Returns null when not found (either not exists, or the document cannot be parsed)
*/
export function findSelectionFromTextLocation(
text: string,
anchor: number,
head: number
): JSONSelection | null {
try {
const jsmap = jsonSourceMap.parse(text)
const pointers = Object.keys(jsmap.pointers)

let anchorPath: JSONPath = []
let focusPath: JSONPath = []

for (const pointer of pointers) {
const state = jsmap.pointers[pointer]

// TODO: work out creating a KeySelection, ValueSelection,
// AfterSelection, InsideSelection, and MultiSelection

if (state?.key?.pos <= anchor && state?.valueEnd?.pos >= anchor) {
anchorPath = parseJSONPointer(pointer)
}

if (state?.key?.pos <= head && state?.valueEnd?.pos >= head) {
focusPath = parseJSONPointer(pointer)
}
}

return createMultiSelection(anchorPath, focusPath)
} catch {
return null
}
}

/**
* Convert a JSON object, array, or value to another type
* If it cannot be converted, an error is thrown
Expand Down

0 comments on commit 8aef55c

Please sign in to comment.