101 lines
2.1 KiB
TypeScript
101 lines
2.1 KiB
TypeScript
import {
|
|
JSONArrayValue,
|
|
JSONObjectMember,
|
|
JSONObjectValue,
|
|
JSONValue,
|
|
} from "./jsonParse"
|
|
|
|
type RootEntry =
|
|
| {
|
|
kind: "RootObject"
|
|
astValue: JSONObjectValue
|
|
}
|
|
| {
|
|
kind: "RootArray"
|
|
astValue: JSONArrayValue
|
|
}
|
|
|
|
type ObjectMemberEntry = {
|
|
kind: "ObjectMember"
|
|
name: string
|
|
astValue: JSONObjectMember
|
|
astParent: JSONObjectValue
|
|
}
|
|
|
|
type ArrayMemberEntry = {
|
|
kind: "ArrayMember"
|
|
index: number
|
|
astValue: JSONValue
|
|
astParent: JSONArrayValue
|
|
}
|
|
|
|
type PathEntry = RootEntry | ObjectMemberEntry | ArrayMemberEntry
|
|
|
|
export function getJSONOutlineAtPos(
|
|
jsonRootAst: JSONObjectValue | JSONArrayValue,
|
|
posIndex: number
|
|
): PathEntry[] | null {
|
|
try {
|
|
const rootObj = jsonRootAst
|
|
|
|
if (posIndex > rootObj.end || posIndex < rootObj.start)
|
|
throw new Error("Invalid position")
|
|
|
|
let current: JSONValue = rootObj
|
|
|
|
const path: PathEntry[] = []
|
|
|
|
if (rootObj.kind === "Object") {
|
|
path.push({
|
|
kind: "RootObject",
|
|
astValue: rootObj,
|
|
})
|
|
} else {
|
|
path.push({
|
|
kind: "RootArray",
|
|
astValue: rootObj,
|
|
})
|
|
}
|
|
|
|
while (current.kind === "Object" || current.kind === "Array") {
|
|
if (current.kind === "Object") {
|
|
const next: JSONObjectMember | undefined = current.members.find(
|
|
(member) => member.start <= posIndex && member.end >= posIndex
|
|
)
|
|
|
|
if (!next) throw new Error("Couldn't find child")
|
|
|
|
path.push({
|
|
kind: "ObjectMember",
|
|
name: next.key.value,
|
|
astValue: next,
|
|
astParent: current,
|
|
})
|
|
|
|
current = next.value
|
|
} else {
|
|
const nextIndex = current.values.findIndex(
|
|
(value) => value.start <= posIndex && value.end >= posIndex
|
|
)
|
|
|
|
if (nextIndex < 0) throw new Error("Couldn't find child")
|
|
|
|
const next: JSONValue = current.values[nextIndex]
|
|
|
|
path.push({
|
|
kind: "ArrayMember",
|
|
index: nextIndex,
|
|
astValue: next,
|
|
astParent: current,
|
|
})
|
|
|
|
current = next
|
|
}
|
|
}
|
|
|
|
return path
|
|
} catch (e: any) {
|
|
return null
|
|
}
|
|
}
|