@cqa-lib/cqa-ui 1.1.482 → 1.1.483
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/esm2020/lib/execution-screen/api-step/api-step.component.mjs +78 -54
- package/fesm2015/cqa-lib-cqa-ui.mjs +78 -55
- package/fesm2015/cqa-lib-cqa-ui.mjs.map +1 -1
- package/fesm2020/cqa-lib-cqa-ui.mjs +78 -54
- package/fesm2020/cqa-lib-cqa-ui.mjs.map +1 -1
- package/lib/execution-screen/api-step/api-step.component.d.ts +9 -1
- package/package.json +1 -1
|
@@ -14174,18 +14174,56 @@ class ApiStepComponent extends BaseStepComponent {
|
|
|
14174
14174
|
}
|
|
14175
14175
|
}
|
|
14176
14176
|
/**
|
|
14177
|
-
*
|
|
14177
|
+
* Walks jsonData and builds a map from each line number (in the output of
|
|
14178
|
+
* JSON.stringify(jsonData, null, 2)) to the segment path that line represents.
|
|
14179
|
+
* Segments are strings for object keys and numbers for array indices.
|
|
14180
|
+
*/
|
|
14181
|
+
buildLinePathMap(obj) {
|
|
14182
|
+
const map = new Map();
|
|
14183
|
+
const state = { line: 0 };
|
|
14184
|
+
const walk = (value, path) => {
|
|
14185
|
+
if (Array.isArray(value)) {
|
|
14186
|
+
if (value.length === 0)
|
|
14187
|
+
return;
|
|
14188
|
+
for (let i = 0; i < value.length; i++) {
|
|
14189
|
+
state.line += 1; // newline before element
|
|
14190
|
+
const elementPath = [...path, i];
|
|
14191
|
+
map.set(state.line, elementPath);
|
|
14192
|
+
walk(value[i], elementPath);
|
|
14193
|
+
}
|
|
14194
|
+
state.line += 1; // newline before closing ]
|
|
14195
|
+
return;
|
|
14196
|
+
}
|
|
14197
|
+
if (value && typeof value === 'object') {
|
|
14198
|
+
const keys = Object.keys(value);
|
|
14199
|
+
if (keys.length === 0)
|
|
14200
|
+
return;
|
|
14201
|
+
for (const key of keys) {
|
|
14202
|
+
state.line += 1; // newline before "key":
|
|
14203
|
+
const keyPath = [...path, key];
|
|
14204
|
+
map.set(state.line, keyPath);
|
|
14205
|
+
walk(value[key], keyPath);
|
|
14206
|
+
}
|
|
14207
|
+
state.line += 1; // newline before closing }
|
|
14208
|
+
return;
|
|
14209
|
+
}
|
|
14210
|
+
// primitive — no additional lines
|
|
14211
|
+
};
|
|
14212
|
+
// Root line (line 0) is the opening { or [ or primitive.
|
|
14213
|
+
walk(obj, []);
|
|
14214
|
+
return map;
|
|
14215
|
+
}
|
|
14216
|
+
/**
|
|
14217
|
+
* Extracts JSON path from the clicked position in a formatted JSON string.
|
|
14218
|
+
* Returns an array of segments (string keys or numeric array indices), or null.
|
|
14178
14219
|
*/
|
|
14179
14220
|
getJsonPathFromClick(event, jsonData, prefix = '') {
|
|
14180
14221
|
const target = event.target;
|
|
14181
|
-
if (!target ||
|
|
14222
|
+
if (!target || jsonData == null)
|
|
14182
14223
|
return null;
|
|
14183
14224
|
const preElement = target.closest('pre');
|
|
14184
14225
|
if (!preElement)
|
|
14185
14226
|
return null;
|
|
14186
|
-
// Get the formatted JSON text
|
|
14187
|
-
const formattedJson = this.formatJson(jsonData);
|
|
14188
|
-
const lines = formattedJson.split('\n');
|
|
14189
14227
|
// Create a range at the click position
|
|
14190
14228
|
let range = null;
|
|
14191
14229
|
if (document.caretRangeFromPoint) {
|
|
@@ -14208,58 +14246,44 @@ class ApiStepComponent extends BaseStepComponent {
|
|
|
14208
14246
|
const textBeforeClick = preRange.toString();
|
|
14209
14247
|
// Count newlines to find which line we're on
|
|
14210
14248
|
const lineIndex = (textBeforeClick.match(/\n/g) || []).length;
|
|
14211
|
-
|
|
14212
|
-
|
|
14213
|
-
//
|
|
14214
|
-
|
|
14215
|
-
if (!
|
|
14216
|
-
|
|
14217
|
-
|
|
14218
|
-
|
|
14219
|
-
|
|
14220
|
-
|
|
14221
|
-
|
|
14222
|
-
|
|
14223
|
-
|
|
14224
|
-
|
|
14225
|
-
const lineKeyMatch = line.match(/^(\s+)"([^"]+)":/);
|
|
14226
|
-
if (lineKeyMatch) {
|
|
14227
|
-
const lineIndent = lineKeyMatch[1].length / 2; // Divide by 2 for 2-space indentation
|
|
14228
|
-
const lineKey = lineKeyMatch[2];
|
|
14229
|
-
// If this line has less indentation, it's a parent
|
|
14230
|
-
if (lineIndent < currentIndent) {
|
|
14231
|
-
path.unshift(lineKey);
|
|
14232
|
-
currentIndent = lineIndent;
|
|
14233
|
-
// Stop if we've reached the root level
|
|
14234
|
-
if (lineIndent === 0)
|
|
14235
|
-
break;
|
|
14236
|
-
}
|
|
14237
|
-
}
|
|
14238
|
-
}
|
|
14239
|
-
// Add the clicked key
|
|
14240
|
-
path.push(clickedKey);
|
|
14241
|
-
// Build the full path string
|
|
14242
|
-
if (path.length === 0)
|
|
14249
|
+
const linePathMap = this.buildLinePathMap(jsonData);
|
|
14250
|
+
// Exact match first; otherwise fall back to the nearest preceding mapped line
|
|
14251
|
+
// (handles clicks on closing brackets or blank columns).
|
|
14252
|
+
let segments = linePathMap.get(lineIndex);
|
|
14253
|
+
if (!segments) {
|
|
14254
|
+
for (let i = lineIndex - 1; i >= 0; i--) {
|
|
14255
|
+
const candidate = linePathMap.get(i);
|
|
14256
|
+
if (candidate) {
|
|
14257
|
+
segments = candidate;
|
|
14258
|
+
break;
|
|
14259
|
+
}
|
|
14260
|
+
}
|
|
14261
|
+
}
|
|
14262
|
+
if (!segments || segments.length === 0)
|
|
14243
14263
|
return null;
|
|
14244
|
-
|
|
14245
|
-
return fullPath;
|
|
14264
|
+
return prefix ? [prefix, ...segments] : [...segments];
|
|
14246
14265
|
}
|
|
14247
|
-
|
|
14248
|
-
|
|
14249
|
-
|
|
14250
|
-
|
|
14251
|
-
|
|
14252
|
-
|
|
14253
|
-
|
|
14266
|
+
formatSegmentsPath(segments) {
|
|
14267
|
+
return segments.reduce((acc, seg) => {
|
|
14268
|
+
if (typeof seg === 'number')
|
|
14269
|
+
return `${acc}[${seg}]`;
|
|
14270
|
+
return acc ? `${acc}.${seg}` : String(seg);
|
|
14271
|
+
}, '');
|
|
14272
|
+
}
|
|
14273
|
+
normalizeJsonPath(segments, prefix) {
|
|
14274
|
+
if (!segments || segments.length === 0)
|
|
14275
|
+
return '';
|
|
14276
|
+
if (!prefix || segments.length < 2) {
|
|
14277
|
+
return this.formatSegmentsPath(segments);
|
|
14254
14278
|
}
|
|
14255
|
-
const [, ...rest] =
|
|
14279
|
+
const [, ...rest] = segments;
|
|
14256
14280
|
if (prefix === 'requestHeaders' || prefix === 'responseHeaders') {
|
|
14257
|
-
return rest.length ? `headers
|
|
14281
|
+
return rest.length ? `headers${this.formatSegmentsPath(rest).startsWith('[') ? '' : '.'}${this.formatSegmentsPath(rest)}` : 'headers';
|
|
14258
14282
|
}
|
|
14259
14283
|
if (prefix === 'requestBody' || prefix === 'responseBody') {
|
|
14260
|
-
return rest.length ? `body
|
|
14284
|
+
return rest.length ? `body${this.formatSegmentsPath(rest).startsWith('[') ? '' : '.'}${this.formatSegmentsPath(rest)}` : 'body';
|
|
14261
14285
|
}
|
|
14262
|
-
return
|
|
14286
|
+
return this.formatSegmentsPath(segments);
|
|
14263
14287
|
}
|
|
14264
14288
|
/**
|
|
14265
14289
|
* Copy JSON path on double-click
|
|
@@ -14267,12 +14291,12 @@ class ApiStepComponent extends BaseStepComponent {
|
|
|
14267
14291
|
copyJsonPath(event, jsonData, prefix = '') {
|
|
14268
14292
|
if (!jsonData)
|
|
14269
14293
|
return;
|
|
14270
|
-
const
|
|
14271
|
-
if (
|
|
14294
|
+
const segments = this.getJsonPathFromClick(event, jsonData, prefix);
|
|
14295
|
+
if (segments && segments.length > 0) {
|
|
14272
14296
|
const source = prefix;
|
|
14273
|
-
const normalizedPath = this.normalizeJsonPath(
|
|
14297
|
+
const normalizedPath = this.normalizeJsonPath(segments, prefix);
|
|
14274
14298
|
navigator.clipboard.writeText(normalizedPath).then(() => {
|
|
14275
|
-
console.log('Copied to clipboard:',
|
|
14299
|
+
console.log('Copied to clipboard:', normalizedPath);
|
|
14276
14300
|
// Call the handler on every double-click (even on success, for now showing error as per requirement)
|
|
14277
14301
|
if (this.onJsonPathCopiedHandler) {
|
|
14278
14302
|
console.log('Calling onJsonPathCopiedHandler on success with:', { path: normalizedPath, source });
|