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