@uipath/common 1.202.1-preview.220 → 1.202.1-preview.238

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.
@@ -102,6 +102,13 @@ export declare class SuccessOutput {
102
102
  Data: DataRecord | DataRecord[];
103
103
  Pagination?: Pagination;
104
104
  Instructions?: string;
105
+ /**
106
+ * A note for the caller that does not change the `Data` contract — e.g.
107
+ * why `--output-filter` returned nothing. Declared here because agents
108
+ * read the envelope and nothing else; `emitList` and the filter paths
109
+ * both set it.
110
+ */
111
+ Warning?: string;
105
112
  Log?: string;
106
113
  constructor(code: string, data: DataRecord | DataRecord[]);
107
114
  }
@@ -303,6 +310,9 @@ export declare namespace OutputFormatter {
303
310
  *
304
311
  * **Side-effect:** records the exit code through {@link setExitCode}, so a
305
312
  * printed failure exits non-zero even when no `context.exit()` follows.
313
+ *
314
+ * `--output-filter` projects `Data` here as it does in {@link success};
315
+ * see {@link filterFailureData}.
306
316
  */
307
317
  function error(data: FailureOutput): void;
308
318
  /** Emit a list result. Always uses `Result: "Success"` — an empty list is not an error. */
@@ -319,6 +329,11 @@ export declare namespace OutputFormatter {
319
329
  /**
320
330
  * Format structured output to a string without writing to console.
321
331
  * Useful when the caller needs the formatted string (e.g., Commander's formatHelp).
332
+ *
333
+ * This is the structured-help path, so it carries the filter note on the
334
+ * envelope like {@link success} does: a mistyped filter against `--help`
335
+ * is the same ambiguity as one against a list, and stdout is the only
336
+ * channel its reader has.
322
337
  */
323
338
  function formatToString(data: StructuredOutput): string;
324
339
  }
package/dist/index.js CHANGED
@@ -10871,6 +10871,7 @@ class SuccessOutput {
10871
10871
  Data;
10872
10872
  Pagination;
10873
10873
  Instructions;
10874
+ Warning;
10874
10875
  Log;
10875
10876
  constructor(code, data) {
10876
10877
  this.Code = code;
@@ -11287,7 +11288,165 @@ class ConfigurationError extends Error {
11287
11288
  function isConfigurationError(error) {
11288
11289
  return typeof error === "object" && error !== null && "__brand" in error && error.__brand === "ConfigurationError";
11289
11290
  }
11290
- function applyFilter(data, filter) {
11291
+ function countRecords(data) {
11292
+ if (Array.isArray(data))
11293
+ return data.length;
11294
+ return data == null ? 0 : 1;
11295
+ }
11296
+ function availableFields(data) {
11297
+ const records = Array.isArray(data) ? data : [data];
11298
+ const keys = new Set;
11299
+ for (const record of records) {
11300
+ if (record && typeof record === "object" && !Array.isArray(record)) {
11301
+ for (const key of Object.keys(record))
11302
+ keys.add(key);
11303
+ }
11304
+ }
11305
+ return [...keys];
11306
+ }
11307
+ function decodeQuotedIdentifier(whole, inner) {
11308
+ const [error, decoded] = catchError(() => JSON.parse(whole));
11309
+ if (!error && typeof decoded === "string")
11310
+ return decoded;
11311
+ return inner.replace(/\\(.)/g, "$1");
11312
+ }
11313
+ function referencedFields(filter) {
11314
+ const top = new Set;
11315
+ const nested = new Set;
11316
+ const withoutValueLiterals = filter.replace(/'(?:\\.|[^'\\])*'/g, " ").replace(/`(?:\\.|[^`\\])*`/g, " ");
11317
+ const isPathTail = (text, index) => text[index - 1] === "." && /[A-Za-z0-9_"]/.test(text[index - 2] ?? "");
11318
+ const quoted = [];
11319
+ const withoutLiterals = withoutValueLiterals.replace(/"((?:\\.|[^"\\])*)"/g, (whole, name, index) => {
11320
+ const isAlias = /^\s*:/.test(withoutValueLiterals.slice(index + whole.length));
11321
+ if (!isAlias) {
11322
+ quoted.push({
11323
+ name: decodeQuotedIdentifier(whole, name),
11324
+ index,
11325
+ tail: isPathTail(withoutValueLiterals, index)
11326
+ });
11327
+ }
11328
+ return `"${" ".repeat(whole.length - 2)}"`;
11329
+ });
11330
+ const descent = /[A-Za-z0-9_"]\s*[.[]/.exec(withoutLiterals);
11331
+ const rootEnd = descent ? descent.index + 1 : Number.POSITIVE_INFINITY;
11332
+ const place = (name, index, tail) => {
11333
+ if (tail || index >= rootEnd)
11334
+ nested.add(name);
11335
+ else
11336
+ top.add(name);
11337
+ };
11338
+ for (const entry of quoted)
11339
+ place(entry.name, entry.index, entry.tail);
11340
+ const identifiers = withoutLiterals.matchAll(/([A-Za-z_][A-Za-z0-9_]*)(\s*[:(])?/g);
11341
+ const reserved = new Set(["true", "false", "null", "and", "or", "not"]);
11342
+ for (const match of identifiers) {
11343
+ const [, name, trailing] = match;
11344
+ if (trailing || reserved.has(name))
11345
+ continue;
11346
+ place(name, match.index, isPathTail(withoutLiterals, match.index));
11347
+ }
11348
+ return {
11349
+ top: [...top],
11350
+ nested: [...nested].filter((name) => !top.has(name)),
11351
+ hasPredicate: /\[\s*\?/.test(withoutValueLiterals)
11352
+ };
11353
+ }
11354
+ function appearsBelowTopLevel(data, name) {
11355
+ let budget = 2000;
11356
+ const visit = (value, depth) => {
11357
+ if (budget-- <= 0 || depth > 4)
11358
+ return false;
11359
+ if (value === null || typeof value !== "object")
11360
+ return false;
11361
+ if (Array.isArray(value))
11362
+ return value.some((entry) => visit(entry, depth));
11363
+ const record = value;
11364
+ if (depth > 0 && Object.hasOwn(record, name))
11365
+ return true;
11366
+ return Object.values(record).some((entry) => visit(entry, depth + 1));
11367
+ };
11368
+ return visit(data, 0);
11369
+ }
11370
+ function alwaysNullKeys(records) {
11371
+ const objects = records.filter((r) => r != null && typeof r === "object" && !Array.isArray(r));
11372
+ if (objects.length === 0 || objects.length !== records.length)
11373
+ return [];
11374
+ const keys = [...new Set(objects.flatMap((o) => Object.keys(o)))];
11375
+ if (keys.length === 0)
11376
+ return [];
11377
+ const nullKeys = keys.filter((key) => objects.every((record) => record[key] === null));
11378
+ return nullKeys.length === keys.length ? nullKeys : [];
11379
+ }
11380
+ function carriesOnlyNulls(value) {
11381
+ if (value === null)
11382
+ return true;
11383
+ if (Array.isArray(value)) {
11384
+ return value.length > 0 && value.every(carriesOnlyNulls);
11385
+ }
11386
+ if (typeof value === "object" && value !== undefined) {
11387
+ const values = Object.values(value);
11388
+ return values.length > 0 && values.every(carriesOnlyNulls);
11389
+ }
11390
+ return false;
11391
+ }
11392
+ function nameList(names, cap2 = 12) {
11393
+ const shown = names.slice(0, cap2).map((n) => `\`${n}\``);
11394
+ const rest = names.length - shown.length;
11395
+ return shown.join(", ") + (rest > 0 ? `, and ${rest} more` : "");
11396
+ }
11397
+ function buildFilterWarning(filter, data, outcome) {
11398
+ const present = availableFields(data);
11399
+ const refs = referencedFields(filter);
11400
+ const unknown = refs.top.filter((name) => !present.includes(name) && !appearsBelowTopLevel(data, name));
11401
+ const unchecked = refs.nested.filter((name) => !present.includes(name));
11402
+ const count = countRecords(data);
11403
+ const scope = `${count} record(s)`;
11404
+ const isNotAField = (names) => `${nameList(names)} ${names.length === 1 ? "is not a field" : "are not fields"} on the ${scope} it read`;
11405
+ const soundness = unchecked.length > 0 ? `${nameList(unchecked)} ${unchecked.length === 1 ? "reads" : "read"} below the top level, so ${unchecked.length === 1 ? "it was" : "they were"} not checked against the record keys` : refs.top.length > 0 ? "every field it names exists" : "";
11406
+ const withSoundness = (base) => soundness ? `${base}, and ${soundness}` : base;
11407
+ let detail;
11408
+ let lede;
11409
+ if (outcome.kind === "null-elements") {
11410
+ lede = "returned only null values";
11411
+ const projected = `all ${outcome.count} of the elements it projected are null`;
11412
+ if (unknown.length > 0) {
11413
+ detail = `${projected}, because ${isNotAField(unknown)}`;
11414
+ } else if (unchecked.length > 0) {
11415
+ detail = withSoundness(projected);
11416
+ } else {
11417
+ detail = `${projected}, and every field it names exists — a multi-select list ` + `(\`[A, B]\`) reads each entry against \`Data\` itself, so on a list ` + `result use \`[].[A, B]\` or \`[].{a: A, b: B}\` to read the records`;
11418
+ }
11419
+ } else if (outcome.kind === "null-rows") {
11420
+ lede = "returned only null values";
11421
+ const projected = `every value it projected is null on all ${outcome.count} row(s)`;
11422
+ detail = unknown.length > 0 ? `${projected}, because ${isNotAField(unknown)}` : withSoundness(projected);
11423
+ } else if (outcome.kind === "null-values") {
11424
+ lede = "returned only null values";
11425
+ const projected = `every key it projected (${nameList(outcome.keys)}) is null`;
11426
+ const sameSet = unknown.length === outcome.keys.length && outcome.keys.every((k) => unknown.includes(k));
11427
+ if (sameSet) {
11428
+ detail = `${isNotAField(outcome.keys)}, so every key it projected is null`;
11429
+ } else if (unknown.length > 0) {
11430
+ detail = `${projected}, because ${isNotAField(unknown)}`;
11431
+ } else {
11432
+ detail = withSoundness(`${projected} on all ${scope}`);
11433
+ }
11434
+ } else {
11435
+ lede = "returned nothing";
11436
+ if (unknown.length > 0) {
11437
+ detail = isNotAField(unknown);
11438
+ } else {
11439
+ const selection = refs.hasPredicate ? "no record matched" : "the expression resolved to no value";
11440
+ detail = withSoundness(`${selection} — it read ${scope}`);
11441
+ }
11442
+ }
11443
+ const fields = present.length > 0 ? ` Available fields: ${nameList(present)}.` : "";
11444
+ return `--output-filter ${JSON.stringify(filter)} ${lede}: ${detail}.${fields}`;
11445
+ }
11446
+ function appendWarning(existing, note) {
11447
+ return existing ? `${existing} ${note}` : note;
11448
+ }
11449
+ function applyFilter(data, filter, onWarning) {
11291
11450
  const codec = requireJmespath();
11292
11451
  let result;
11293
11452
  try {
@@ -11295,9 +11454,34 @@ function applyFilter(data, filter) {
11295
11454
  } catch (err) {
11296
11455
  throw new FilterEvaluationError(filter, err);
11297
11456
  }
11298
- if (result == null)
11457
+ const inputCount = countRecords(data);
11458
+ const warn = (outcome) => {
11459
+ if (inputCount === 0)
11460
+ return;
11461
+ const note = buildFilterWarning(filter, data, outcome);
11462
+ getOutputSink().writeErr(`[WARN] ${note}
11463
+ `);
11464
+ onWarning?.(note);
11465
+ };
11466
+ const warnIfAllNull = (records) => {
11467
+ const keys = alwaysNullKeys(records);
11468
+ if (keys.length > 0)
11469
+ warn({ kind: "null-values", keys });
11470
+ };
11471
+ if (result == null) {
11472
+ warn({ kind: "empty" });
11299
11473
  return [];
11474
+ }
11300
11475
  if (Array.isArray(result)) {
11476
+ if (result.length === 0) {
11477
+ warn({ kind: "empty" });
11478
+ } else if (result.every((entry) => entry === null)) {
11479
+ warn({ kind: "null-elements", count: result.length });
11480
+ } else if (result.every((entry) => Array.isArray(entry)) && carriesOnlyNulls(result)) {
11481
+ warn({ kind: "null-rows", count: result.length });
11482
+ } else {
11483
+ warnIfAllNull(result);
11484
+ }
11301
11485
  if (result.length > 0 && typeof result[0] !== "object") {
11302
11486
  const fieldMatch = filter.match(/\.(\w+)$/);
11303
11487
  const key = fieldMatch ? fieldMatch[1] : "Value";
@@ -11305,10 +11489,30 @@ function applyFilter(data, filter) {
11305
11489
  }
11306
11490
  return result;
11307
11491
  }
11308
- if (typeof result === "object")
11492
+ if (typeof result === "object") {
11493
+ warnIfAllNull([result]);
11309
11494
  return result;
11495
+ }
11310
11496
  return { Value: result };
11311
11497
  }
11498
+ function filterFailureData(envelope) {
11499
+ const filter = getOutputFilter();
11500
+ const data = envelope.Data;
11501
+ if (!filter || data == null)
11502
+ return;
11503
+ let note;
11504
+ const [filterError, filtered] = catchError(() => applyFilter(data, filter, (n) => {
11505
+ note = n;
11506
+ }));
11507
+ if (filterError) {
11508
+ envelope.Warning = appendWarning(envelope.Warning, `--output-filter was not applied, so Data is shown in full: ${filterError.message}`);
11509
+ return;
11510
+ }
11511
+ envelope.Data = filtered;
11512
+ if (note) {
11513
+ envelope.Warning = appendWarning(envelope.Warning, note);
11514
+ }
11515
+ }
11312
11516
  function defaultErrorCodeForResult(result) {
11313
11517
  switch (result) {
11314
11518
  case RESULTS.AuthenticationError:
@@ -11391,8 +11595,14 @@ var OutputFormatter;
11391
11595
  }
11392
11596
  const filter = getOutputFilter();
11393
11597
  if (filter) {
11394
- const filtered = applyFilter(data.Data, filter);
11598
+ let note;
11599
+ const filtered = applyFilter(data.Data, filter, (n) => {
11600
+ note = n;
11601
+ });
11395
11602
  data.Data = normalize ? normalizeDataKeys(filtered, verbatim, subtrees && { refs: subtrees.refs, mode: "skip" }) : filtered;
11603
+ if (note) {
11604
+ data.Warning = appendWarning(data.Warning, note);
11605
+ }
11396
11606
  }
11397
11607
  logOutput(normalizeOutputKeys(data), getOutputFormat(), options?.tableRowStyle);
11398
11608
  }
@@ -11420,6 +11630,7 @@ var OutputFormatter;
11420
11630
  delete envelope.TelemetryErrorClass;
11421
11631
  delete envelope.TelemetryTerminalOutcome;
11422
11632
  delete envelope.TelemetryTerminalSignal;
11633
+ filterFailureData(envelope);
11423
11634
  if (!suppressTelemetry) {
11424
11635
  telemetry.trackEvent(CommonTelemetryEvents.Error, {
11425
11636
  result: data.Result,
@@ -11468,13 +11679,20 @@ var OutputFormatter;
11468
11679
  OutputFormatter.log = log;
11469
11680
  function formatToString(data) {
11470
11681
  const filter = getOutputFilter();
11682
+ const envelope = data;
11471
11683
  if ("Data" in data && data.Data != null) {
11472
11684
  data.Data = normalizeDataKeys(data.Data);
11473
11685
  if (filter) {
11474
- data.Data = normalizeDataKeys(applyFilter(data.Data, filter));
11686
+ let note;
11687
+ data.Data = normalizeDataKeys(applyFilter(data.Data, filter, (n) => {
11688
+ note = n;
11689
+ }));
11690
+ if (note) {
11691
+ envelope.Warning = appendWarning(envelope.Warning, note);
11692
+ }
11475
11693
  }
11476
11694
  }
11477
- const output = normalizeOutputKeys(data);
11695
+ const output = normalizeOutputKeys(envelope);
11478
11696
  const lines = [];
11479
11697
  const sink = getOutputSink();
11480
11698
  printOutput(output, getOutputFormat(), (msg) => {
@@ -13752,4 +13970,4 @@ export {
13752
13970
  writeTelemetrySpoolFile
13753
13971
  };
13754
13972
 
13755
- //# debugId=4D6104E1FF2E565764756E2164756E21
13973
+ //# debugId=03A35D12FEEB5F8864756E2164756E21
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@uipath/common",
3
3
  "license": "SEE LICENSE IN LICENSE.txt",
4
- "version": "1.202.1-preview.220",
4
+ "version": "1.202.1-preview.238",
5
5
  "description": "Common infrastructure needed by uip tools.",
6
6
  "repository": {
7
7
  "type": "git",
@@ -75,5 +75,5 @@
75
75
  "mihaigirleanu",
76
76
  "vlad-uipath"
77
77
  ],
78
- "gitHead": "a09041733b628c3f6b658a1f58349ea0f40bb492"
78
+ "gitHead": "537e43df1d3583633cfd3a0b88634f9ce3ba9d6b"
79
79
  }