@health-samurai/react-components 0.0.0-alpha.18 → 0.0.0-alpha.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/bundle.css +51 -33
- package/dist/src/components/code-editor/fhir-autocomplete.d.ts +70 -0
- package/dist/src/components/code-editor/fhir-autocomplete.d.ts.map +1 -0
- package/dist/src/components/code-editor/fhir-autocomplete.js +1849 -0
- package/dist/src/components/code-editor/fhir-autocomplete.js.map +1 -0
- package/dist/src/components/code-editor/fhir-autocomplete.test.js +1099 -0
- package/dist/src/components/code-editor/fhir-autocomplete.test.js.map +1 -0
- package/dist/src/components/code-editor/http/index.d.ts +9 -1
- package/dist/src/components/code-editor/http/index.d.ts.map +1 -1
- package/dist/src/components/code-editor/http/index.js +423 -3
- package/dist/src/components/code-editor/http/index.js.map +1 -1
- package/dist/src/components/code-editor/index.d.ts +13 -4
- package/dist/src/components/code-editor/index.d.ts.map +1 -1
- package/dist/src/components/code-editor/index.js +505 -96
- package/dist/src/components/code-editor/index.js.map +1 -1
- package/dist/src/components/code-editor/json-ast.d.ts +46 -0
- package/dist/src/components/code-editor/json-ast.d.ts.map +1 -0
- package/dist/src/components/code-editor/json-ast.js +465 -0
- package/dist/src/components/code-editor/json-ast.js.map +1 -0
- package/dist/src/components/code-editor/json-ast.test.js +206 -0
- package/dist/src/components/code-editor/json-ast.test.js.map +1 -0
- package/dist/src/components/code-editor/sql-completion.d.ts +22 -0
- package/dist/src/components/code-editor/sql-completion.d.ts.map +1 -0
- package/dist/src/components/code-editor/sql-completion.js +895 -0
- package/dist/src/components/code-editor/sql-completion.js.map +1 -0
- package/dist/src/components/date-picker-input.d.ts +10 -0
- package/dist/src/components/date-picker-input.d.ts.map +1 -0
- package/dist/src/components/date-picker-input.js +90 -0
- package/dist/src/components/date-picker-input.js.map +1 -0
- package/dist/src/components/date-picker-input.stories.js +76 -0
- package/dist/src/components/date-picker-input.stories.js.map +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/shadcn/components/ui/alert-dialog.d.ts +1 -1
- package/dist/src/shadcn/components/ui/calendar.d.ts +1 -1
- package/dist/src/shadcn/components/ui/carousel.d.ts +1 -1
- package/dist/src/shadcn/components/ui/chart.d.ts +3 -3
- package/dist/src/shadcn/components/ui/chart.d.ts.map +1 -1
- package/dist/src/shadcn/components/ui/chart.js +1 -1
- package/dist/src/shadcn/components/ui/chart.js.map +1 -1
- package/dist/src/shadcn/components/ui/command.d.ts +1 -1
- package/dist/src/shadcn/components/ui/pagination.d.ts +1 -1
- package/dist/src/shadcn/components/ui/resizable.stories.js +2 -2
- package/dist/src/shadcn/components/ui/resizable.stories.js.map +1 -1
- package/dist/src/shadcn/components/ui/sidebar.d.ts +4 -4
- package/dist/src/shadcn/components/ui/tabs.d.ts +3 -1
- package/dist/src/shadcn/components/ui/tabs.d.ts.map +1 -1
- package/dist/src/shadcn/components/ui/tabs.js +129 -2
- package/dist/src/shadcn/components/ui/tabs.js.map +1 -1
- package/dist/src/shadcn/components/ui/tabs.stories.js +1 -1
- package/dist/src/shadcn/components/ui/tabs.stories.js.map +1 -1
- package/dist/src/shadcn/components/ui/toggle-group.d.ts +1 -1
- package/dist/src/typography.css +1 -1
- package/package.json +24 -19
- package/src/components/code-editor/fhir-autocomplete.test.ts +993 -0
- package/src/components/code-editor/fhir-autocomplete.ts +2321 -0
- package/src/components/code-editor/http/index.ts +339 -2
- package/src/components/code-editor/index.tsx +593 -102
- package/src/components/code-editor/json-ast.test.ts +230 -0
- package/src/components/code-editor/json-ast.ts +590 -0
- package/src/components/code-editor/sql-completion.ts +1105 -0
- package/src/components/date-picker-input.stories.tsx +79 -0
- package/src/components/date-picker-input.tsx +104 -0
- package/src/index.tsx +1 -0
- package/src/shadcn/components/ui/chart.tsx +6 -3
- package/src/shadcn/components/ui/resizable.stories.tsx +2 -2
- package/src/shadcn/components/ui/tabs.stories.tsx +1 -1
- package/src/shadcn/components/ui/tabs.tsx +160 -2
- package/src/typography.css +1 -1
- package/dist/src/components/code-editor/http/grammar/http.test.d.ts +0 -2
- package/dist/src/components/code-editor/http/grammar/http.test.d.ts.map +0 -1
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
// ── HTTP mode helper ───────────────────────────────────────────────────
|
|
2
|
+
const HTTP_METHOD_RE = /^(GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD)\s/;
|
|
3
|
+
function detectJsonStart(doc) {
|
|
4
|
+
const firstLine = doc.slice(0, doc.indexOf("\n") >>> 0).trimStart();
|
|
5
|
+
if (HTTP_METHOD_RE.test(firstLine)) {
|
|
6
|
+
const bodyStart = doc.indexOf("\n\n");
|
|
7
|
+
if (bodyStart === -1) return 0;
|
|
8
|
+
return bodyStart + 2;
|
|
9
|
+
}
|
|
10
|
+
return 0;
|
|
11
|
+
}
|
|
12
|
+
// ── JSON path at cursor ────────────────────────────────────────────────
|
|
13
|
+
function getJsonPathAtCursor(doc, pos) {
|
|
14
|
+
const path = [];
|
|
15
|
+
const arrayKeyStack = [];
|
|
16
|
+
let inString = false;
|
|
17
|
+
let isEscaped = false;
|
|
18
|
+
let currentKey = "";
|
|
19
|
+
let collectingKey = false;
|
|
20
|
+
let lastKey = "";
|
|
21
|
+
for(let i = 0; i < pos; i++){
|
|
22
|
+
const ch = doc[i];
|
|
23
|
+
if (isEscaped) {
|
|
24
|
+
if (collectingKey) currentKey += ch;
|
|
25
|
+
isEscaped = false;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (ch === "\\") {
|
|
29
|
+
isEscaped = true;
|
|
30
|
+
if (collectingKey) currentKey += ch;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (ch === '"') {
|
|
34
|
+
if (!inString) {
|
|
35
|
+
inString = true;
|
|
36
|
+
collectingKey = true;
|
|
37
|
+
currentKey = "";
|
|
38
|
+
} else {
|
|
39
|
+
inString = false;
|
|
40
|
+
if (collectingKey) {
|
|
41
|
+
lastKey = currentKey;
|
|
42
|
+
collectingKey = false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (inString) {
|
|
48
|
+
if (collectingKey) currentKey += ch;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (ch === "[") {
|
|
52
|
+
arrayKeyStack.push(lastKey);
|
|
53
|
+
lastKey = "";
|
|
54
|
+
} else if (ch === "]") {
|
|
55
|
+
arrayKeyStack.pop();
|
|
56
|
+
lastKey = "";
|
|
57
|
+
} else if (ch === "{") {
|
|
58
|
+
const key = lastKey || (arrayKeyStack.length > 0 ? arrayKeyStack[arrayKeyStack.length - 1] ?? "" : "");
|
|
59
|
+
if (key) path.push(key);
|
|
60
|
+
lastKey = "";
|
|
61
|
+
} else if (ch === "}") {
|
|
62
|
+
path.pop();
|
|
63
|
+
lastKey = "";
|
|
64
|
+
} else if (ch === ",") {
|
|
65
|
+
lastKey = "";
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return path;
|
|
69
|
+
}
|
|
70
|
+
// ── Cursor position detection ──────────────────────────────────────────
|
|
71
|
+
function isJsonValuePosition(beforeCursor) {
|
|
72
|
+
// Don't match if a comma follows the value (value is complete)
|
|
73
|
+
if (/,\s*$/.test(beforeCursor)) return null;
|
|
74
|
+
const match = beforeCursor.match(/"?(\w+)"?\s*:\s*"?([^"]*)?$/);
|
|
75
|
+
if (match) return match[1] ?? null;
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
function isJsonPropertyPosition(beforeCursor) {
|
|
79
|
+
if (beforeCursor === "" || beforeCursor === '"') return true;
|
|
80
|
+
if (/^"?[\w]*$/.test(beforeCursor)) return true;
|
|
81
|
+
if (/[{,]\s*"?[\w]*$/.test(beforeCursor)) return true;
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
function isInsideJsonArray(doc, pos) {
|
|
85
|
+
let depth = 0;
|
|
86
|
+
let inStr = false;
|
|
87
|
+
let escaped = false;
|
|
88
|
+
for(let i = pos - 1; i >= 0; i--){
|
|
89
|
+
const ch = doc[i];
|
|
90
|
+
if (escaped) {
|
|
91
|
+
escaped = false;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (ch === "\\") {
|
|
95
|
+
escaped = true;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (ch === '"') {
|
|
99
|
+
inStr = !inStr;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (inStr) continue;
|
|
103
|
+
if (ch === "}" || ch === "]") {
|
|
104
|
+
depth++;
|
|
105
|
+
} else if (ch === "{") {
|
|
106
|
+
if (depth === 0) return false;
|
|
107
|
+
depth--;
|
|
108
|
+
} else if (ch === "[") {
|
|
109
|
+
if (depth === 0) return true;
|
|
110
|
+
depth--;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
// ── Array-item detection ───────────────────────────────────────────────
|
|
116
|
+
function detectArrayItemContext(doc, pos) {
|
|
117
|
+
const textBefore = doc.slice(0, pos);
|
|
118
|
+
const arrayMatch = textBefore.match(/"(\w+)"\s*:\s*\[\s*(?:"[^"]*"\s*,\s*)*"?([^"]*)$/s);
|
|
119
|
+
if (!arrayMatch) return null;
|
|
120
|
+
// If there are unmatched { after [, cursor is inside a nested object, not directly in array
|
|
121
|
+
const afterBracket = arrayMatch[2] ?? "";
|
|
122
|
+
let braceDepth = 0;
|
|
123
|
+
for (const ch of afterBracket){
|
|
124
|
+
if (ch === "{") braceDepth++;
|
|
125
|
+
else if (ch === "}") braceDepth--;
|
|
126
|
+
}
|
|
127
|
+
if (braceDepth > 0) return null;
|
|
128
|
+
return {
|
|
129
|
+
parentKey: arrayMatch[1],
|
|
130
|
+
prefix: afterBracket
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
// ── Scope view (find values in ancestor objects) ───────────────────────
|
|
134
|
+
function findStringValueInObject(doc, objStart, limit, targetKey) {
|
|
135
|
+
let fd = 0;
|
|
136
|
+
let fs = false;
|
|
137
|
+
let fe = false;
|
|
138
|
+
let lastKey = "";
|
|
139
|
+
let collecting = false;
|
|
140
|
+
let current = "";
|
|
141
|
+
let afterColon = false;
|
|
142
|
+
for(let i = objStart + 1; i < limit; i++){
|
|
143
|
+
const ch = doc[i];
|
|
144
|
+
if (fe) {
|
|
145
|
+
if (collecting) current += ch;
|
|
146
|
+
fe = false;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (ch === "\\") {
|
|
150
|
+
fe = true;
|
|
151
|
+
if (collecting) current += ch;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (ch === '"') {
|
|
155
|
+
if (!fs) {
|
|
156
|
+
fs = true;
|
|
157
|
+
if (fd === 0) {
|
|
158
|
+
collecting = true;
|
|
159
|
+
current = "";
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
fs = false;
|
|
163
|
+
if (collecting) {
|
|
164
|
+
if (afterColon) {
|
|
165
|
+
if (lastKey === targetKey) return current;
|
|
166
|
+
afterColon = false;
|
|
167
|
+
} else {
|
|
168
|
+
lastKey = current;
|
|
169
|
+
}
|
|
170
|
+
collecting = false;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (fs) {
|
|
176
|
+
if (collecting) current += ch;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (ch === "{" || ch === "[") fd++;
|
|
180
|
+
else if (ch === "}" || ch === "]") fd--;
|
|
181
|
+
else if (ch === ":" && fd === 0) afterColon = true;
|
|
182
|
+
else if (ch === "," && fd === 0) {
|
|
183
|
+
afterColon = false;
|
|
184
|
+
lastKey = "";
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
function findStringArrayInObject(doc, objStart, limit, parentKey, arrayKey) {
|
|
190
|
+
// Find "parentKey": { ... "arrayKey": ["v1", "v2"] ... }
|
|
191
|
+
// or if parentKey is empty, find "arrayKey": [...] at top level
|
|
192
|
+
const searchDoc = doc.slice(objStart, limit);
|
|
193
|
+
let pattern;
|
|
194
|
+
if (parentKey) {
|
|
195
|
+
pattern = new RegExp(`"${parentKey}"\\s*:\\s*\\{[\\s\\S]*?"${arrayKey}"\\s*:\\s*\\[([\\s\\S]*?)\\]`);
|
|
196
|
+
} else {
|
|
197
|
+
pattern = new RegExp(`"${arrayKey}"\\s*:\\s*\\[([\\s\\S]*?)\\]`);
|
|
198
|
+
}
|
|
199
|
+
const match = searchDoc.match(pattern);
|
|
200
|
+
if (!match?.[1]) return [];
|
|
201
|
+
const urls = [];
|
|
202
|
+
const re = /"([^"]+)"/g;
|
|
203
|
+
let m;
|
|
204
|
+
// biome-ignore lint/suspicious/noAssignInExpressions: standard regex exec loop
|
|
205
|
+
while((m = re.exec(match[1])) !== null){
|
|
206
|
+
if (m[1]) urls.push(m[1]);
|
|
207
|
+
}
|
|
208
|
+
return urls;
|
|
209
|
+
}
|
|
210
|
+
function findKeysInObject(doc, objStart, limit) {
|
|
211
|
+
const keys = [];
|
|
212
|
+
let fd = 0;
|
|
213
|
+
let fs = false;
|
|
214
|
+
let fe = false;
|
|
215
|
+
let collecting = false;
|
|
216
|
+
let current = "";
|
|
217
|
+
let afterColon = false;
|
|
218
|
+
for(let i = objStart + 1; i < limit; i++){
|
|
219
|
+
const ch = doc[i];
|
|
220
|
+
if (fe) {
|
|
221
|
+
if (collecting) current += ch;
|
|
222
|
+
fe = false;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (ch === "\\") {
|
|
226
|
+
fe = true;
|
|
227
|
+
if (collecting) current += ch;
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
if (ch === '"') {
|
|
231
|
+
if (!fs) {
|
|
232
|
+
fs = true;
|
|
233
|
+
if (fd === 0) {
|
|
234
|
+
collecting = true;
|
|
235
|
+
current = "";
|
|
236
|
+
}
|
|
237
|
+
} else {
|
|
238
|
+
fs = false;
|
|
239
|
+
if (collecting) {
|
|
240
|
+
if (!afterColon) {
|
|
241
|
+
keys.push(current);
|
|
242
|
+
}
|
|
243
|
+
collecting = false;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
if (fs) {
|
|
249
|
+
if (collecting) current += ch;
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (ch === "{" || ch === "[") fd++;
|
|
253
|
+
else if (ch === "}" || ch === "]") fd--;
|
|
254
|
+
else if (ch === ":" && fd === 0) afterColon = true;
|
|
255
|
+
else if (ch === "," && fd === 0) {
|
|
256
|
+
afterColon = false;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return keys;
|
|
260
|
+
}
|
|
261
|
+
function buildScopeView(doc, pos, levelsUp) {
|
|
262
|
+
// Forward scan to find enclosing objects — avoids string-tracking bugs
|
|
263
|
+
// from backward scanning when cursor is inside an unclosed string.
|
|
264
|
+
const objectStack = [];
|
|
265
|
+
let inString = false;
|
|
266
|
+
let isEscaped = false;
|
|
267
|
+
for(let i = 0; i < pos; i++){
|
|
268
|
+
const ch = doc[i];
|
|
269
|
+
if (isEscaped) {
|
|
270
|
+
isEscaped = false;
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
if (ch === "\\") {
|
|
274
|
+
isEscaped = true;
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
if (ch === '"') {
|
|
278
|
+
inString = !inString;
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
if (inString) continue;
|
|
282
|
+
if (ch === "{") {
|
|
283
|
+
objectStack.push(i);
|
|
284
|
+
} else if (ch === "}") {
|
|
285
|
+
objectStack.pop();
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
// objectStack[last] is innermost, objectStack[last - levelsUp] is target
|
|
289
|
+
const targetIdx = objectStack.length - 1 - levelsUp;
|
|
290
|
+
if (targetIdx < 0) {
|
|
291
|
+
return {
|
|
292
|
+
getString () {
|
|
293
|
+
return null;
|
|
294
|
+
},
|
|
295
|
+
getStringArray () {
|
|
296
|
+
return [];
|
|
297
|
+
},
|
|
298
|
+
getKeys () {
|
|
299
|
+
return [];
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
const objStart = objectStack[targetIdx];
|
|
304
|
+
const scopeEnd = doc.length;
|
|
305
|
+
return {
|
|
306
|
+
getString (key) {
|
|
307
|
+
return findStringValueInObject(doc, objStart, scopeEnd, key);
|
|
308
|
+
},
|
|
309
|
+
getStringArray (parentKey, arrayKey) {
|
|
310
|
+
return findStringArrayInObject(doc, objStart, scopeEnd, parentKey, arrayKey);
|
|
311
|
+
},
|
|
312
|
+
getKeys () {
|
|
313
|
+
return findKeysInObject(doc, objStart, scopeEnd);
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
// ── buildJsonDocumentContext ────────────────────────────────────────────
|
|
318
|
+
export function buildJsonDocumentContext(doc, pos) {
|
|
319
|
+
const jsonStart = detectJsonStart(doc);
|
|
320
|
+
const jsonBody = doc.slice(jsonStart);
|
|
321
|
+
const posInBody = pos - jsonStart;
|
|
322
|
+
const fullPath = getJsonPathAtCursor(jsonBody, posInBody);
|
|
323
|
+
// Determine cursor position kind
|
|
324
|
+
const lineStart = doc.lastIndexOf("\n", pos - 1) + 1;
|
|
325
|
+
const beforeCursor = doc.slice(lineStart, pos).trimStart();
|
|
326
|
+
let cursorPosition;
|
|
327
|
+
const valueKey = isJsonValuePosition(beforeCursor);
|
|
328
|
+
if (valueKey) {
|
|
329
|
+
cursorPosition = {
|
|
330
|
+
kind: "value",
|
|
331
|
+
key: valueKey,
|
|
332
|
+
prefix: ""
|
|
333
|
+
};
|
|
334
|
+
const wordMatch = beforeCursor.match(/"?(\w+)"?\s*:\s*"?([^"]*)?$/);
|
|
335
|
+
if (wordMatch?.[2] != null) {
|
|
336
|
+
cursorPosition.prefix = wordMatch[2];
|
|
337
|
+
}
|
|
338
|
+
} else {
|
|
339
|
+
const arrayItem = detectArrayItemContext(doc.slice(jsonStart), posInBody);
|
|
340
|
+
if (arrayItem) {
|
|
341
|
+
cursorPosition = {
|
|
342
|
+
kind: "array-item",
|
|
343
|
+
parentKey: arrayItem.parentKey,
|
|
344
|
+
prefix: arrayItem.prefix
|
|
345
|
+
};
|
|
346
|
+
} else if (isJsonPropertyPosition(beforeCursor)) {
|
|
347
|
+
const wordMatch = beforeCursor.match(/"?(\w*)$/);
|
|
348
|
+
cursorPosition = {
|
|
349
|
+
kind: "property",
|
|
350
|
+
prefix: wordMatch?.[1] ?? ""
|
|
351
|
+
};
|
|
352
|
+
} else {
|
|
353
|
+
cursorPosition = {
|
|
354
|
+
kind: "none"
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return {
|
|
359
|
+
fullPath,
|
|
360
|
+
pos,
|
|
361
|
+
doc,
|
|
362
|
+
cursorPosition,
|
|
363
|
+
getScope (levelsUp) {
|
|
364
|
+
return buildScopeView(jsonBody, posInBody, levelsUp);
|
|
365
|
+
},
|
|
366
|
+
isInsideArray () {
|
|
367
|
+
return isInsideJsonArray(jsonBody, posInBody);
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
// ── Validation helpers ─────────────────────────────────────────────────
|
|
372
|
+
export function walkJsonProperties(doc, tree, resourceTypeHint) {
|
|
373
|
+
const properties = [];
|
|
374
|
+
const emptyStrings = [];
|
|
375
|
+
const rootObj = findRootJsonObject(doc, tree);
|
|
376
|
+
if (rootObj) {
|
|
377
|
+
walkJsonObject(rootObj, [], resourceTypeHint, doc, properties, emptyStrings);
|
|
378
|
+
}
|
|
379
|
+
return {
|
|
380
|
+
properties,
|
|
381
|
+
emptyStrings
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
export function findRootJsonObject(doc, tree) {
|
|
385
|
+
const direct = tree.topNode.getChild("Object");
|
|
386
|
+
if (direct) return direct;
|
|
387
|
+
const bodyStart = doc.indexOf("\n\n");
|
|
388
|
+
if (bodyStart === -1) return null;
|
|
389
|
+
const jsonStart = bodyStart + 2;
|
|
390
|
+
if (jsonStart >= doc.length) return null;
|
|
391
|
+
const innerNode = tree.resolveInner(jsonStart, 1);
|
|
392
|
+
if (!innerNode) return null;
|
|
393
|
+
let node = innerNode;
|
|
394
|
+
while(node){
|
|
395
|
+
if (node.name === "Object") return node;
|
|
396
|
+
if (node.name === "JsonText") {
|
|
397
|
+
return node.getChild("Object");
|
|
398
|
+
}
|
|
399
|
+
node = node.parent;
|
|
400
|
+
}
|
|
401
|
+
return null;
|
|
402
|
+
}
|
|
403
|
+
function walkJsonObject(node, parentPath, parentResourceType, doc, result, emptyStrings) {
|
|
404
|
+
let ownResourceType = null;
|
|
405
|
+
for(let child = node.firstChild; child; child = child.nextSibling){
|
|
406
|
+
if (child.name !== "Property") continue;
|
|
407
|
+
const nameNode = child.getChild("PropertyName");
|
|
408
|
+
if (!nameNode) continue;
|
|
409
|
+
const keyName = doc.slice(nameNode.from, nameNode.to).replace(/^"|"$/g, "");
|
|
410
|
+
if (keyName === "resourceType") {
|
|
411
|
+
for(let v = child.firstChild; v; v = v.nextSibling){
|
|
412
|
+
if (v.name === "String") {
|
|
413
|
+
ownResourceType = doc.slice(v.from, v.to).replace(/^"|"$/g, "");
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
const resourceType = ownResourceType ?? parentResourceType;
|
|
421
|
+
const path = ownResourceType ? [] : parentPath;
|
|
422
|
+
if (!resourceType) return;
|
|
423
|
+
for(let child = node.firstChild; child; child = child.nextSibling){
|
|
424
|
+
if (child.name !== "Property") continue;
|
|
425
|
+
const nameNode = child.getChild("PropertyName");
|
|
426
|
+
if (!nameNode) continue;
|
|
427
|
+
const name = doc.slice(nameNode.from, nameNode.to).replace(/^"|"$/g, "");
|
|
428
|
+
result.push({
|
|
429
|
+
name,
|
|
430
|
+
path: [
|
|
431
|
+
...path
|
|
432
|
+
],
|
|
433
|
+
resourceType,
|
|
434
|
+
from: nameNode.from,
|
|
435
|
+
to: nameNode.to
|
|
436
|
+
});
|
|
437
|
+
for(let v = child.firstChild; v; v = v.nextSibling){
|
|
438
|
+
if (v.name === "Object") {
|
|
439
|
+
walkJsonObject(v, [
|
|
440
|
+
...path,
|
|
441
|
+
name
|
|
442
|
+
], resourceType, doc, result, emptyStrings);
|
|
443
|
+
} else if (v.name === "Array") {
|
|
444
|
+
for(let item = v.firstChild; item; item = item.nextSibling){
|
|
445
|
+
if (item.name === "Object") {
|
|
446
|
+
walkJsonObject(item, [
|
|
447
|
+
...path,
|
|
448
|
+
name
|
|
449
|
+
], resourceType, doc, result, emptyStrings);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
} else if (v.name === "String" && emptyStrings) {
|
|
453
|
+
const raw = doc.slice(v.from, v.to);
|
|
454
|
+
if (raw === '""') {
|
|
455
|
+
emptyStrings.push({
|
|
456
|
+
from: v.from,
|
|
457
|
+
to: v.to
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
//# sourceMappingURL=json-ast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/code-editor/json-ast.ts"],"sourcesContent":["import type { syntaxTree } from \"@codemirror/language\";\nimport type { SyntaxNode } from \"@lezer/common\";\n\n// ── Types ──────────────────────────────────────────────────────────────\n\nexport interface ScopeView {\n\tgetString(key: string): string | null;\n\tgetStringArray(parentKey: string, arrayKey: string): string[];\n\tgetKeys(): string[];\n}\n\nexport interface DocumentContext {\n\tfullPath: string[];\n\tpos: number;\n\tdoc: string;\n\tcursorPosition:\n\t\t| { kind: \"property\"; prefix: string }\n\t\t| { kind: \"value\"; key: string; prefix: string }\n\t\t| { kind: \"array-item\"; parentKey: string; prefix: string }\n\t\t| { kind: \"none\" };\n\tgetScope(levelsUp: number): ScopeView;\n\tisInsideArray(): boolean;\n}\n\nexport interface PropertyInfo {\n\tname: string;\n\tpath: string[];\n\tresourceType: string;\n\tfrom: number;\n\tto: number;\n}\n\nexport interface EmptyStringInfo {\n\tfrom: number;\n\tto: number;\n}\n\n// ── HTTP mode helper ───────────────────────────────────────────────────\n\nconst HTTP_METHOD_RE = /^(GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD)\\s/;\n\nfunction detectJsonStart(doc: string): number {\n\tconst firstLine = doc.slice(0, doc.indexOf(\"\\n\") >>> 0).trimStart();\n\tif (HTTP_METHOD_RE.test(firstLine)) {\n\t\tconst bodyStart = doc.indexOf(\"\\n\\n\");\n\t\tif (bodyStart === -1) return 0;\n\t\treturn bodyStart + 2;\n\t}\n\treturn 0;\n}\n\n// ── JSON path at cursor ────────────────────────────────────────────────\n\nfunction getJsonPathAtCursor(doc: string, pos: number): string[] {\n\tconst path: string[] = [];\n\tconst arrayKeyStack: string[] = [];\n\tlet inString = false;\n\tlet isEscaped = false;\n\tlet currentKey = \"\";\n\tlet collectingKey = false;\n\tlet lastKey = \"\";\n\n\tfor (let i = 0; i < pos; i++) {\n\t\tconst ch = doc[i];\n\n\t\tif (isEscaped) {\n\t\t\tif (collectingKey) currentKey += ch;\n\t\t\tisEscaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\") {\n\t\t\tisEscaped = true;\n\t\t\tif (collectingKey) currentKey += ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === '\"') {\n\t\t\tif (!inString) {\n\t\t\t\tinString = true;\n\t\t\t\tcollectingKey = true;\n\t\t\t\tcurrentKey = \"\";\n\t\t\t} else {\n\t\t\t\tinString = false;\n\t\t\t\tif (collectingKey) {\n\t\t\t\t\tlastKey = currentKey;\n\t\t\t\t\tcollectingKey = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (inString) {\n\t\t\tif (collectingKey) currentKey += ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"[\") {\n\t\t\tarrayKeyStack.push(lastKey);\n\t\t\tlastKey = \"\";\n\t\t} else if (ch === \"]\") {\n\t\t\tarrayKeyStack.pop();\n\t\t\tlastKey = \"\";\n\t\t} else if (ch === \"{\") {\n\t\t\tconst key =\n\t\t\t\tlastKey ||\n\t\t\t\t(arrayKeyStack.length > 0\n\t\t\t\t\t? (arrayKeyStack[arrayKeyStack.length - 1] ?? \"\")\n\t\t\t\t\t: \"\");\n\t\t\tif (key) path.push(key);\n\t\t\tlastKey = \"\";\n\t\t} else if (ch === \"}\") {\n\t\t\tpath.pop();\n\t\t\tlastKey = \"\";\n\t\t} else if (ch === \",\") {\n\t\t\tlastKey = \"\";\n\t\t}\n\t}\n\treturn path;\n}\n\n// ── Cursor position detection ──────────────────────────────────────────\n\nfunction isJsonValuePosition(beforeCursor: string): string | null {\n\t// Don't match if a comma follows the value (value is complete)\n\tif (/,\\s*$/.test(beforeCursor)) return null;\n\tconst match = beforeCursor.match(/\"?(\\w+)\"?\\s*:\\s*\"?([^\"]*)?$/);\n\tif (match) return match[1] ?? null;\n\treturn null;\n}\n\nfunction isJsonPropertyPosition(beforeCursor: string): boolean {\n\tif (beforeCursor === \"\" || beforeCursor === '\"') return true;\n\tif (/^\"?[\\w]*$/.test(beforeCursor)) return true;\n\tif (/[{,]\\s*\"?[\\w]*$/.test(beforeCursor)) return true;\n\treturn false;\n}\n\nfunction isInsideJsonArray(doc: string, pos: number): boolean {\n\tlet depth = 0;\n\tlet inStr = false;\n\tlet escaped = false;\n\tfor (let i = pos - 1; i >= 0; i--) {\n\t\tconst ch = doc[i];\n\t\tif (escaped) {\n\t\t\tescaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\") {\n\t\t\tescaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === '\"') {\n\t\t\tinStr = !inStr;\n\t\t\tcontinue;\n\t\t}\n\t\tif (inStr) continue;\n\t\tif (ch === \"}\" || ch === \"]\") {\n\t\t\tdepth++;\n\t\t} else if (ch === \"{\") {\n\t\t\tif (depth === 0) return false;\n\t\t\tdepth--;\n\t\t} else if (ch === \"[\") {\n\t\t\tif (depth === 0) return true;\n\t\t\tdepth--;\n\t\t}\n\t}\n\treturn false;\n}\n\n// ── Array-item detection ───────────────────────────────────────────────\n\nfunction detectArrayItemContext(\n\tdoc: string,\n\tpos: number,\n): { parentKey: string; prefix: string } | null {\n\tconst textBefore = doc.slice(0, pos);\n\tconst arrayMatch = textBefore.match(\n\t\t/\"(\\w+)\"\\s*:\\s*\\[\\s*(?:\"[^\"]*\"\\s*,\\s*)*\"?([^\"]*)$/s,\n\t);\n\tif (!arrayMatch) return null;\n\t// If there are unmatched { after [, cursor is inside a nested object, not directly in array\n\tconst afterBracket = arrayMatch[2] ?? \"\";\n\tlet braceDepth = 0;\n\tfor (const ch of afterBracket) {\n\t\tif (ch === \"{\") braceDepth++;\n\t\telse if (ch === \"}\") braceDepth--;\n\t}\n\tif (braceDepth > 0) return null;\n\treturn { parentKey: arrayMatch[1]!, prefix: afterBracket };\n}\n\n// ── Scope view (find values in ancestor objects) ───────────────────────\n\nfunction findStringValueInObject(\n\tdoc: string,\n\tobjStart: number,\n\tlimit: number,\n\ttargetKey: string,\n): string | null {\n\tlet fd = 0;\n\tlet fs = false;\n\tlet fe = false;\n\tlet lastKey = \"\";\n\tlet collecting = false;\n\tlet current = \"\";\n\tlet afterColon = false;\n\n\tfor (let i = objStart + 1; i < limit; i++) {\n\t\tconst ch = doc[i];\n\t\tif (fe) {\n\t\t\tif (collecting) current += ch;\n\t\t\tfe = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\") {\n\t\t\tfe = true;\n\t\t\tif (collecting) current += ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === '\"') {\n\t\t\tif (!fs) {\n\t\t\t\tfs = true;\n\t\t\t\tif (fd === 0) {\n\t\t\t\t\tcollecting = true;\n\t\t\t\t\tcurrent = \"\";\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfs = false;\n\t\t\t\tif (collecting) {\n\t\t\t\t\tif (afterColon) {\n\t\t\t\t\t\tif (lastKey === targetKey) return current;\n\t\t\t\t\t\tafterColon = false;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlastKey = current;\n\t\t\t\t\t}\n\t\t\t\t\tcollecting = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (fs) {\n\t\t\tif (collecting) current += ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"{\" || ch === \"[\") fd++;\n\t\telse if (ch === \"}\" || ch === \"]\") fd--;\n\t\telse if (ch === \":\" && fd === 0) afterColon = true;\n\t\telse if (ch === \",\" && fd === 0) {\n\t\t\tafterColon = false;\n\t\t\tlastKey = \"\";\n\t\t}\n\t}\n\treturn null;\n}\n\nfunction findStringArrayInObject(\n\tdoc: string,\n\tobjStart: number,\n\tlimit: number,\n\tparentKey: string,\n\tarrayKey: string,\n): string[] {\n\t// Find \"parentKey\": { ... \"arrayKey\": [\"v1\", \"v2\"] ... }\n\t// or if parentKey is empty, find \"arrayKey\": [...] at top level\n\tconst searchDoc = doc.slice(objStart, limit);\n\tlet pattern: RegExp;\n\tif (parentKey) {\n\t\tpattern = new RegExp(\n\t\t\t`\"${parentKey}\"\\\\s*:\\\\s*\\\\{[\\\\s\\\\S]*?\"${arrayKey}\"\\\\s*:\\\\s*\\\\[([\\\\s\\\\S]*?)\\\\]`,\n\t\t);\n\t} else {\n\t\tpattern = new RegExp(`\"${arrayKey}\"\\\\s*:\\\\s*\\\\[([\\\\s\\\\S]*?)\\\\]`);\n\t}\n\tconst match = searchDoc.match(pattern);\n\tif (!match?.[1]) return [];\n\tconst urls: string[] = [];\n\tconst re = /\"([^\"]+)\"/g;\n\tlet m: RegExpExecArray | null;\n\t// biome-ignore lint/suspicious/noAssignInExpressions: standard regex exec loop\n\twhile ((m = re.exec(match[1])) !== null) {\n\t\tif (m[1]) urls.push(m[1]);\n\t}\n\treturn urls;\n}\n\nfunction findKeysInObject(\n\tdoc: string,\n\tobjStart: number,\n\tlimit: number,\n): string[] {\n\tconst keys: string[] = [];\n\tlet fd = 0;\n\tlet fs = false;\n\tlet fe = false;\n\tlet collecting = false;\n\tlet current = \"\";\n\tlet afterColon = false;\n\n\tfor (let i = objStart + 1; i < limit; i++) {\n\t\tconst ch = doc[i];\n\t\tif (fe) {\n\t\t\tif (collecting) current += ch;\n\t\t\tfe = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\") {\n\t\t\tfe = true;\n\t\t\tif (collecting) current += ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === '\"') {\n\t\t\tif (!fs) {\n\t\t\t\tfs = true;\n\t\t\t\tif (fd === 0) {\n\t\t\t\t\tcollecting = true;\n\t\t\t\t\tcurrent = \"\";\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfs = false;\n\t\t\t\tif (collecting) {\n\t\t\t\t\tif (!afterColon) {\n\t\t\t\t\t\tkeys.push(current);\n\t\t\t\t\t}\n\t\t\t\t\tcollecting = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (fs) {\n\t\t\tif (collecting) current += ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"{\" || ch === \"[\") fd++;\n\t\telse if (ch === \"}\" || ch === \"]\") fd--;\n\t\telse if (ch === \":\" && fd === 0) afterColon = true;\n\t\telse if (ch === \",\" && fd === 0) {\n\t\t\tafterColon = false;\n\t\t}\n\t}\n\treturn keys;\n}\n\nfunction buildScopeView(doc: string, pos: number, levelsUp: number): ScopeView {\n\t// Forward scan to find enclosing objects — avoids string-tracking bugs\n\t// from backward scanning when cursor is inside an unclosed string.\n\tconst objectStack: number[] = [];\n\tlet inString = false;\n\tlet isEscaped = false;\n\n\tfor (let i = 0; i < pos; i++) {\n\t\tconst ch = doc[i];\n\t\tif (isEscaped) {\n\t\t\tisEscaped = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === \"\\\\\") {\n\t\t\tisEscaped = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === '\"') {\n\t\t\tinString = !inString;\n\t\t\tcontinue;\n\t\t}\n\t\tif (inString) continue;\n\t\tif (ch === \"{\") {\n\t\t\tobjectStack.push(i);\n\t\t} else if (ch === \"}\") {\n\t\t\tobjectStack.pop();\n\t\t}\n\t}\n\n\t// objectStack[last] is innermost, objectStack[last - levelsUp] is target\n\tconst targetIdx = objectStack.length - 1 - levelsUp;\n\tif (targetIdx < 0) {\n\t\treturn {\n\t\t\tgetString() {\n\t\t\t\treturn null;\n\t\t\t},\n\t\t\tgetStringArray() {\n\t\t\t\treturn [];\n\t\t\t},\n\t\t\tgetKeys() {\n\t\t\t\treturn [];\n\t\t\t},\n\t\t};\n\t}\n\n\tconst objStart = objectStack[targetIdx]!;\n\tconst scopeEnd = doc.length;\n\n\treturn {\n\t\tgetString(key: string): string | null {\n\t\t\treturn findStringValueInObject(doc, objStart, scopeEnd, key);\n\t\t},\n\t\tgetStringArray(parentKey: string, arrayKey: string): string[] {\n\t\t\treturn findStringArrayInObject(\n\t\t\t\tdoc,\n\t\t\t\tobjStart,\n\t\t\t\tscopeEnd,\n\t\t\t\tparentKey,\n\t\t\t\tarrayKey,\n\t\t\t);\n\t\t},\n\t\tgetKeys(): string[] {\n\t\t\treturn findKeysInObject(doc, objStart, scopeEnd);\n\t\t},\n\t};\n}\n\n// ── buildJsonDocumentContext ────────────────────────────────────────────\n\nexport function buildJsonDocumentContext(\n\tdoc: string,\n\tpos: number,\n): DocumentContext {\n\tconst jsonStart = detectJsonStart(doc);\n\tconst jsonBody = doc.slice(jsonStart);\n\tconst posInBody = pos - jsonStart;\n\n\tconst fullPath = getJsonPathAtCursor(jsonBody, posInBody);\n\n\t// Determine cursor position kind\n\tconst lineStart = doc.lastIndexOf(\"\\n\", pos - 1) + 1;\n\tconst beforeCursor = doc.slice(lineStart, pos).trimStart();\n\n\tlet cursorPosition: DocumentContext[\"cursorPosition\"];\n\n\tconst valueKey = isJsonValuePosition(beforeCursor);\n\tif (valueKey) {\n\t\tcursorPosition = { kind: \"value\", key: valueKey, prefix: \"\" };\n\t\tconst wordMatch = beforeCursor.match(/\"?(\\w+)\"?\\s*:\\s*\"?([^\"]*)?$/);\n\t\tif (wordMatch?.[2] != null) {\n\t\t\tcursorPosition.prefix = wordMatch[2];\n\t\t}\n\t} else {\n\t\tconst arrayItem = detectArrayItemContext(doc.slice(jsonStart), posInBody);\n\t\tif (arrayItem) {\n\t\t\tcursorPosition = {\n\t\t\t\tkind: \"array-item\",\n\t\t\t\tparentKey: arrayItem.parentKey,\n\t\t\t\tprefix: arrayItem.prefix,\n\t\t\t};\n\t\t} else if (isJsonPropertyPosition(beforeCursor)) {\n\t\t\tconst wordMatch = beforeCursor.match(/\"?(\\w*)$/);\n\t\t\tcursorPosition = { kind: \"property\", prefix: wordMatch?.[1] ?? \"\" };\n\t\t} else {\n\t\t\tcursorPosition = { kind: \"none\" };\n\t\t}\n\t}\n\n\treturn {\n\t\tfullPath,\n\t\tpos,\n\t\tdoc,\n\t\tcursorPosition,\n\t\tgetScope(levelsUp: number): ScopeView {\n\t\t\treturn buildScopeView(jsonBody, posInBody, levelsUp);\n\t\t},\n\t\tisInsideArray(): boolean {\n\t\t\treturn isInsideJsonArray(jsonBody, posInBody);\n\t\t},\n\t};\n}\n\n// ── Validation helpers ─────────────────────────────────────────────────\n\nexport function walkJsonProperties(\n\tdoc: string,\n\ttree: ReturnType<typeof syntaxTree>,\n\tresourceTypeHint: string | null,\n): { properties: PropertyInfo[]; emptyStrings: EmptyStringInfo[] } {\n\tconst properties: PropertyInfo[] = [];\n\tconst emptyStrings: EmptyStringInfo[] = [];\n\n\tconst rootObj = findRootJsonObject(doc, tree);\n\tif (rootObj) {\n\t\twalkJsonObject(\n\t\t\trootObj,\n\t\t\t[],\n\t\t\tresourceTypeHint,\n\t\t\tdoc,\n\t\t\tproperties,\n\t\t\temptyStrings,\n\t\t);\n\t}\n\n\treturn { properties, emptyStrings };\n}\n\nexport function findRootJsonObject(\n\tdoc: string,\n\ttree: ReturnType<typeof syntaxTree>,\n): SyntaxNode | null {\n\tconst direct = tree.topNode.getChild(\"Object\");\n\tif (direct) return direct;\n\n\tconst bodyStart = doc.indexOf(\"\\n\\n\");\n\tif (bodyStart === -1) return null;\n\n\tconst jsonStart = bodyStart + 2;\n\tif (jsonStart >= doc.length) return null;\n\n\tconst innerNode = tree.resolveInner(jsonStart, 1);\n\tif (!innerNode) return null;\n\n\tlet node: SyntaxNode | null = innerNode;\n\twhile (node) {\n\t\tif (node.name === \"Object\") return node;\n\t\tif (node.name === \"JsonText\") {\n\t\t\treturn node.getChild(\"Object\");\n\t\t}\n\t\tnode = node.parent;\n\t}\n\n\treturn null;\n}\n\nfunction walkJsonObject(\n\tnode: SyntaxNode,\n\tparentPath: string[],\n\tparentResourceType: string | null,\n\tdoc: string,\n\tresult: PropertyInfo[],\n\temptyStrings?: EmptyStringInfo[],\n): void {\n\tlet ownResourceType: string | null = null;\n\tfor (let child = node.firstChild; child; child = child.nextSibling) {\n\t\tif (child.name !== \"Property\") continue;\n\t\tconst nameNode = child.getChild(\"PropertyName\");\n\t\tif (!nameNode) continue;\n\t\tconst keyName = doc.slice(nameNode.from, nameNode.to).replace(/^\"|\"$/g, \"\");\n\t\tif (keyName === \"resourceType\") {\n\t\t\tfor (let v = child.firstChild; v; v = v.nextSibling) {\n\t\t\t\tif (v.name === \"String\") {\n\t\t\t\t\townResourceType = doc.slice(v.from, v.to).replace(/^\"|\"$/g, \"\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tconst resourceType = ownResourceType ?? parentResourceType;\n\tconst path = ownResourceType ? [] : parentPath;\n\n\tif (!resourceType) return;\n\n\tfor (let child = node.firstChild; child; child = child.nextSibling) {\n\t\tif (child.name !== \"Property\") continue;\n\t\tconst nameNode = child.getChild(\"PropertyName\");\n\t\tif (!nameNode) continue;\n\t\tconst name = doc.slice(nameNode.from, nameNode.to).replace(/^\"|\"$/g, \"\");\n\n\t\tresult.push({\n\t\t\tname,\n\t\t\tpath: [...path],\n\t\t\tresourceType,\n\t\t\tfrom: nameNode.from,\n\t\t\tto: nameNode.to,\n\t\t});\n\n\t\tfor (let v = child.firstChild; v; v = v.nextSibling) {\n\t\t\tif (v.name === \"Object\") {\n\t\t\t\twalkJsonObject(\n\t\t\t\t\tv,\n\t\t\t\t\t[...path, name],\n\t\t\t\t\tresourceType,\n\t\t\t\t\tdoc,\n\t\t\t\t\tresult,\n\t\t\t\t\temptyStrings,\n\t\t\t\t);\n\t\t\t} else if (v.name === \"Array\") {\n\t\t\t\tfor (let item = v.firstChild; item; item = item.nextSibling) {\n\t\t\t\t\tif (item.name === \"Object\") {\n\t\t\t\t\t\twalkJsonObject(\n\t\t\t\t\t\t\titem,\n\t\t\t\t\t\t\t[...path, name],\n\t\t\t\t\t\t\tresourceType,\n\t\t\t\t\t\t\tdoc,\n\t\t\t\t\t\t\tresult,\n\t\t\t\t\t\t\temptyStrings,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (v.name === \"String\" && emptyStrings) {\n\t\t\t\tconst raw = doc.slice(v.from, v.to);\n\t\t\t\tif (raw === '\"\"') {\n\t\t\t\t\temptyStrings.push({ from: v.from, to: v.to });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"],"names":["HTTP_METHOD_RE","detectJsonStart","doc","firstLine","slice","indexOf","trimStart","test","bodyStart","getJsonPathAtCursor","pos","path","arrayKeyStack","inString","isEscaped","currentKey","collectingKey","lastKey","i","ch","push","pop","key","length","isJsonValuePosition","beforeCursor","match","isJsonPropertyPosition","isInsideJsonArray","depth","inStr","escaped","detectArrayItemContext","textBefore","arrayMatch","afterBracket","braceDepth","parentKey","prefix","findStringValueInObject","objStart","limit","targetKey","fd","fs","fe","collecting","current","afterColon","findStringArrayInObject","arrayKey","searchDoc","pattern","RegExp","urls","re","m","exec","findKeysInObject","keys","buildScopeView","levelsUp","objectStack","targetIdx","getString","getStringArray","getKeys","scopeEnd","buildJsonDocumentContext","jsonStart","jsonBody","posInBody","fullPath","lineStart","lastIndexOf","cursorPosition","valueKey","kind","wordMatch","arrayItem","getScope","isInsideArray","walkJsonProperties","tree","resourceTypeHint","properties","emptyStrings","rootObj","findRootJsonObject","walkJsonObject","direct","topNode","getChild","innerNode","resolveInner","node","name","parent","parentPath","parentResourceType","result","ownResourceType","child","firstChild","nextSibling","nameNode","keyName","from","to","replace","v","resourceType","item","raw"],"mappings":"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"}
|