newOutline.ts 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import {
  2. JSONArrayValue,
  3. JSONObjectMember,
  4. JSONObjectValue,
  5. JSONValue,
  6. } from "./jsonParse"
  7. type RootEntry =
  8. | {
  9. kind: "RootObject"
  10. astValue: JSONObjectValue
  11. }
  12. | {
  13. kind: "RootArray"
  14. astValue: JSONArrayValue
  15. }
  16. type ObjectMemberEntry = {
  17. kind: "ObjectMember"
  18. name: string
  19. astValue: JSONObjectMember
  20. astParent: JSONObjectValue
  21. }
  22. type ArrayMemberEntry = {
  23. kind: "ArrayMember"
  24. index: number
  25. astValue: JSONValue
  26. astParent: JSONArrayValue
  27. }
  28. type PathEntry = RootEntry | ObjectMemberEntry | ArrayMemberEntry
  29. export function getJSONOutlineAtPos(
  30. jsonRootAst: JSONObjectValue | JSONArrayValue,
  31. posIndex: number
  32. ): PathEntry[] | null {
  33. try {
  34. const rootObj = jsonRootAst
  35. if (posIndex > rootObj.end || posIndex < rootObj.start)
  36. throw new Error("Invalid position")
  37. let current: JSONValue = rootObj
  38. const path: PathEntry[] = []
  39. if (rootObj.kind === "Object") {
  40. path.push({
  41. kind: "RootObject",
  42. astValue: rootObj,
  43. })
  44. } else {
  45. path.push({
  46. kind: "RootArray",
  47. astValue: rootObj,
  48. })
  49. }
  50. while (current.kind === "Object" || current.kind === "Array") {
  51. if (current.kind === "Object") {
  52. const next: JSONObjectMember | undefined = current.members.find(
  53. (member) => member.start <= posIndex && member.end >= posIndex
  54. )
  55. if (!next) throw new Error("Couldn't find child")
  56. path.push({
  57. kind: "ObjectMember",
  58. name: next.key.value,
  59. astValue: next,
  60. astParent: current,
  61. })
  62. current = next.value
  63. } else {
  64. const nextIndex = current.values.findIndex(
  65. (value) => value.start <= posIndex && value.end >= posIndex
  66. )
  67. if (nextIndex < 0) throw new Error("Couldn't find child")
  68. const next: JSONValue = current.values[nextIndex]
  69. path.push({
  70. kind: "ArrayMember",
  71. index: nextIndex,
  72. astValue: next,
  73. astParent: current,
  74. })
  75. current = next
  76. }
  77. }
  78. return path
  79. } catch (e: any) {
  80. return null
  81. }
  82. }