@uipath/guardrails-tool 1.202.1-preview.220 → 1.202.1-preview.239

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.
Files changed (2) hide show
  1. package/dist/tool.js +225 -8
  2. package/package.json +2 -2
package/dist/tool.js CHANGED
@@ -2100,7 +2100,7 @@ var require_commander = __commonJS(function(exports) {
2100
2100
  var package_default = {
2101
2101
  name: "@uipath/guardrails-tool",
2102
2102
  license: "SEE LICENSE IN LICENSE.txt",
2103
- version: "1.202.1-preview.220",
2103
+ version: "1.202.1-preview.239",
2104
2104
  description: "CLI plugin for UiPath AI Trust Layer guardrail configurations.",
2105
2105
  private: false,
2106
2106
  repository: {
@@ -4433,7 +4433,165 @@ class FilterImplicitLimitError extends Error {
4433
4433
  this.instructions = "Pass --limit <n> to choose how many records the filter applies to. " + "To filter over all records, pass the command's maximum accepted --limit (see the option's description in --help).";
4434
4434
  }
4435
4435
  }
4436
- function applyFilter(data, filter) {
4436
+ function countRecords(data) {
4437
+ if (Array.isArray(data))
4438
+ return data.length;
4439
+ return data == null ? 0 : 1;
4440
+ }
4441
+ function availableFields(data) {
4442
+ const records = Array.isArray(data) ? data : [data];
4443
+ const keys = new Set;
4444
+ for (const record of records) {
4445
+ if (record && typeof record === "object" && !Array.isArray(record)) {
4446
+ for (const key of Object.keys(record))
4447
+ keys.add(key);
4448
+ }
4449
+ }
4450
+ return [...keys];
4451
+ }
4452
+ function decodeQuotedIdentifier(whole, inner) {
4453
+ const [error, decoded] = catchError(() => JSON.parse(whole));
4454
+ if (!error && typeof decoded === "string")
4455
+ return decoded;
4456
+ return inner.replace(/\\(.)/g, "$1");
4457
+ }
4458
+ function referencedFields(filter) {
4459
+ const top = new Set;
4460
+ const nested = new Set;
4461
+ const withoutValueLiterals = filter.replace(/'(?:\\.|[^'\\])*'/g, " ").replace(/`(?:\\.|[^`\\])*`/g, " ");
4462
+ const isPathTail = (text, index) => text[index - 1] === "." && /[A-Za-z0-9_"]/.test(text[index - 2] ?? "");
4463
+ const quoted = [];
4464
+ const withoutLiterals = withoutValueLiterals.replace(/"((?:\\.|[^"\\])*)"/g, (whole, name, index) => {
4465
+ const isAlias = /^\s*:/.test(withoutValueLiterals.slice(index + whole.length));
4466
+ if (!isAlias) {
4467
+ quoted.push({
4468
+ name: decodeQuotedIdentifier(whole, name),
4469
+ index,
4470
+ tail: isPathTail(withoutValueLiterals, index)
4471
+ });
4472
+ }
4473
+ return `"${" ".repeat(whole.length - 2)}"`;
4474
+ });
4475
+ const descent = /[A-Za-z0-9_"]\s*[.[]/.exec(withoutLiterals);
4476
+ const rootEnd = descent ? descent.index + 1 : Number.POSITIVE_INFINITY;
4477
+ const place = (name, index, tail) => {
4478
+ if (tail || index >= rootEnd)
4479
+ nested.add(name);
4480
+ else
4481
+ top.add(name);
4482
+ };
4483
+ for (const entry of quoted)
4484
+ place(entry.name, entry.index, entry.tail);
4485
+ const identifiers = withoutLiterals.matchAll(/([A-Za-z_][A-Za-z0-9_]*)(\s*[:(])?/g);
4486
+ const reserved = new Set(["true", "false", "null", "and", "or", "not"]);
4487
+ for (const match of identifiers) {
4488
+ const [, name, trailing] = match;
4489
+ if (trailing || reserved.has(name))
4490
+ continue;
4491
+ place(name, match.index, isPathTail(withoutLiterals, match.index));
4492
+ }
4493
+ return {
4494
+ top: [...top],
4495
+ nested: [...nested].filter((name) => !top.has(name)),
4496
+ hasPredicate: /\[\s*\?/.test(withoutValueLiterals)
4497
+ };
4498
+ }
4499
+ function appearsBelowTopLevel(data, name) {
4500
+ let budget = 2000;
4501
+ const visit = (value, depth) => {
4502
+ if (budget-- <= 0 || depth > 4)
4503
+ return false;
4504
+ if (value === null || typeof value !== "object")
4505
+ return false;
4506
+ if (Array.isArray(value))
4507
+ return value.some((entry) => visit(entry, depth));
4508
+ const record = value;
4509
+ if (depth > 0 && Object.hasOwn(record, name))
4510
+ return true;
4511
+ return Object.values(record).some((entry) => visit(entry, depth + 1));
4512
+ };
4513
+ return visit(data, 0);
4514
+ }
4515
+ function alwaysNullKeys(records) {
4516
+ const objects = records.filter((r) => r != null && typeof r === "object" && !Array.isArray(r));
4517
+ if (objects.length === 0 || objects.length !== records.length)
4518
+ return [];
4519
+ const keys = [...new Set(objects.flatMap((o) => Object.keys(o)))];
4520
+ if (keys.length === 0)
4521
+ return [];
4522
+ const nullKeys = keys.filter((key) => objects.every((record) => record[key] === null));
4523
+ return nullKeys.length === keys.length ? nullKeys : [];
4524
+ }
4525
+ function carriesOnlyNulls(value) {
4526
+ if (value === null)
4527
+ return true;
4528
+ if (Array.isArray(value)) {
4529
+ return value.length > 0 && value.every(carriesOnlyNulls);
4530
+ }
4531
+ if (typeof value === "object" && value !== undefined) {
4532
+ const values = Object.values(value);
4533
+ return values.length > 0 && values.every(carriesOnlyNulls);
4534
+ }
4535
+ return false;
4536
+ }
4537
+ function nameList(names, cap2 = 12) {
4538
+ const shown = names.slice(0, cap2).map((n) => `\`${n}\``);
4539
+ const rest = names.length - shown.length;
4540
+ return shown.join(", ") + (rest > 0 ? `, and ${rest} more` : "");
4541
+ }
4542
+ function buildFilterWarning(filter, data, outcome) {
4543
+ const present = availableFields(data);
4544
+ const refs = referencedFields(filter);
4545
+ const unknown = refs.top.filter((name) => !present.includes(name) && !appearsBelowTopLevel(data, name));
4546
+ const unchecked = refs.nested.filter((name) => !present.includes(name));
4547
+ const count = countRecords(data);
4548
+ const scope = `${count} record(s)`;
4549
+ const isNotAField = (names) => `${nameList(names)} ${names.length === 1 ? "is not a field" : "are not fields"} on the ${scope} it read`;
4550
+ 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" : "";
4551
+ const withSoundness = (base) => soundness ? `${base}, and ${soundness}` : base;
4552
+ let detail;
4553
+ let lede;
4554
+ if (outcome.kind === "null-elements") {
4555
+ lede = "returned only null values";
4556
+ const projected = `all ${outcome.count} of the elements it projected are null`;
4557
+ if (unknown.length > 0) {
4558
+ detail = `${projected}, because ${isNotAField(unknown)}`;
4559
+ } else if (unchecked.length > 0) {
4560
+ detail = withSoundness(projected);
4561
+ } else {
4562
+ 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`;
4563
+ }
4564
+ } else if (outcome.kind === "null-rows") {
4565
+ lede = "returned only null values";
4566
+ const projected = `every value it projected is null on all ${outcome.count} row(s)`;
4567
+ detail = unknown.length > 0 ? `${projected}, because ${isNotAField(unknown)}` : withSoundness(projected);
4568
+ } else if (outcome.kind === "null-values") {
4569
+ lede = "returned only null values";
4570
+ const projected = `every key it projected (${nameList(outcome.keys)}) is null`;
4571
+ const sameSet = unknown.length === outcome.keys.length && outcome.keys.every((k) => unknown.includes(k));
4572
+ if (sameSet) {
4573
+ detail = `${isNotAField(outcome.keys)}, so every key it projected is null`;
4574
+ } else if (unknown.length > 0) {
4575
+ detail = `${projected}, because ${isNotAField(unknown)}`;
4576
+ } else {
4577
+ detail = withSoundness(`${projected} on all ${scope}`);
4578
+ }
4579
+ } else {
4580
+ lede = "returned nothing";
4581
+ if (unknown.length > 0) {
4582
+ detail = isNotAField(unknown);
4583
+ } else {
4584
+ const selection = refs.hasPredicate ? "no record matched" : "the expression resolved to no value";
4585
+ detail = withSoundness(`${selection} — it read ${scope}`);
4586
+ }
4587
+ }
4588
+ const fields = present.length > 0 ? ` Available fields: ${nameList(present)}.` : "";
4589
+ return `--output-filter ${JSON.stringify(filter)} ${lede}: ${detail}.${fields}`;
4590
+ }
4591
+ function appendWarning(existing, note) {
4592
+ return existing ? `${existing} ${note}` : note;
4593
+ }
4594
+ function applyFilter(data, filter, onWarning) {
4437
4595
  const codec = requireJmespath();
4438
4596
  let result;
4439
4597
  try {
@@ -4441,9 +4599,34 @@ function applyFilter(data, filter) {
4441
4599
  } catch (err) {
4442
4600
  throw new FilterEvaluationError(filter, err);
4443
4601
  }
4444
- if (result == null)
4602
+ const inputCount = countRecords(data);
4603
+ const warn = (outcome) => {
4604
+ if (inputCount === 0)
4605
+ return;
4606
+ const note = buildFilterWarning(filter, data, outcome);
4607
+ getOutputSink().writeErr(`[WARN] ${note}
4608
+ `);
4609
+ onWarning?.(note);
4610
+ };
4611
+ const warnIfAllNull = (records) => {
4612
+ const keys = alwaysNullKeys(records);
4613
+ if (keys.length > 0)
4614
+ warn({ kind: "null-values", keys });
4615
+ };
4616
+ if (result == null) {
4617
+ warn({ kind: "empty" });
4445
4618
  return [];
4619
+ }
4446
4620
  if (Array.isArray(result)) {
4621
+ if (result.length === 0) {
4622
+ warn({ kind: "empty" });
4623
+ } else if (result.every((entry) => entry === null)) {
4624
+ warn({ kind: "null-elements", count: result.length });
4625
+ } else if (result.every((entry) => Array.isArray(entry)) && carriesOnlyNulls(result)) {
4626
+ warn({ kind: "null-rows", count: result.length });
4627
+ } else {
4628
+ warnIfAllNull(result);
4629
+ }
4447
4630
  if (result.length > 0 && typeof result[0] !== "object") {
4448
4631
  const fieldMatch = filter.match(/\.(\w+)$/);
4449
4632
  const key = fieldMatch ? fieldMatch[1] : "Value";
@@ -4451,10 +4634,30 @@ function applyFilter(data, filter) {
4451
4634
  }
4452
4635
  return result;
4453
4636
  }
4454
- if (typeof result === "object")
4637
+ if (typeof result === "object") {
4638
+ warnIfAllNull([result]);
4455
4639
  return result;
4640
+ }
4456
4641
  return { Value: result };
4457
4642
  }
4643
+ function filterFailureData(envelope) {
4644
+ const filter = getOutputFilter();
4645
+ const data = envelope.Data;
4646
+ if (!filter || data == null)
4647
+ return;
4648
+ let note;
4649
+ const [filterError, filtered] = catchError(() => applyFilter(data, filter, (n) => {
4650
+ note = n;
4651
+ }));
4652
+ if (filterError) {
4653
+ envelope.Warning = appendWarning(envelope.Warning, `--output-filter was not applied, so Data is shown in full: ${filterError.message}`);
4654
+ return;
4655
+ }
4656
+ envelope.Data = filtered;
4657
+ if (note) {
4658
+ envelope.Warning = appendWarning(envelope.Warning, note);
4659
+ }
4660
+ }
4458
4661
  function defaultErrorCodeForResult(result) {
4459
4662
  switch (result) {
4460
4663
  case RESULTS.AuthenticationError:
@@ -4537,8 +4740,14 @@ var OutputFormatter;
4537
4740
  }
4538
4741
  const filter = getOutputFilter();
4539
4742
  if (filter) {
4540
- const filtered = applyFilter(data.Data, filter);
4743
+ let note;
4744
+ const filtered = applyFilter(data.Data, filter, (n) => {
4745
+ note = n;
4746
+ });
4541
4747
  data.Data = normalize ? normalizeDataKeys(filtered, verbatim, subtrees && { refs: subtrees.refs, mode: "skip" }) : filtered;
4748
+ if (note) {
4749
+ data.Warning = appendWarning(data.Warning, note);
4750
+ }
4542
4751
  }
4543
4752
  logOutput(normalizeOutputKeys(data), getOutputFormat(), options?.tableRowStyle);
4544
4753
  }
@@ -4566,6 +4775,7 @@ var OutputFormatter;
4566
4775
  delete envelope.TelemetryErrorClass;
4567
4776
  delete envelope.TelemetryTerminalOutcome;
4568
4777
  delete envelope.TelemetryTerminalSignal;
4778
+ filterFailureData(envelope);
4569
4779
  if (!suppressTelemetry) {
4570
4780
  telemetry.trackEvent(CommonTelemetryEvents.Error, {
4571
4781
  result: data.Result,
@@ -4614,13 +4824,20 @@ var OutputFormatter;
4614
4824
  OutputFormatter.log = log;
4615
4825
  function formatToString(data) {
4616
4826
  const filter = getOutputFilter();
4827
+ const envelope = data;
4617
4828
  if ("Data" in data && data.Data != null) {
4618
4829
  data.Data = normalizeDataKeys(data.Data);
4619
4830
  if (filter) {
4620
- data.Data = normalizeDataKeys(applyFilter(data.Data, filter));
4831
+ let note;
4832
+ data.Data = normalizeDataKeys(applyFilter(data.Data, filter, (n) => {
4833
+ note = n;
4834
+ }));
4835
+ if (note) {
4836
+ envelope.Warning = appendWarning(envelope.Warning, note);
4837
+ }
4621
4838
  }
4622
4839
  }
4623
- const output = normalizeOutputKeys(data);
4840
+ const output = normalizeOutputKeys(envelope);
4624
4841
  const lines = [];
4625
4842
  const sink = getOutputSink();
4626
4843
  printOutput(output, getOutputFormat(), (msg) => {
@@ -7218,4 +7435,4 @@ export {
7218
7435
  registerCommands
7219
7436
  };
7220
7437
 
7221
- //# debugId=2729F8E9D128CAF564756E2164756E21
7438
+ //# debugId=3806B014A4E8360364756E2164756E21
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@uipath/guardrails-tool",
3
3
  "license": "SEE LICENSE IN LICENSE.txt",
4
- "version": "1.202.1-preview.220",
4
+ "version": "1.202.1-preview.239",
5
5
  "description": "CLI plugin for UiPath AI Trust Layer guardrail configurations.",
6
6
  "private": false,
7
7
  "repository": {
@@ -23,5 +23,5 @@
23
23
  "files": [
24
24
  "dist"
25
25
  ],
26
- "gitHead": "a09041733b628c3f6b658a1f58349ea0f40bb492"
26
+ "gitHead": "97545a7857bdff7e6db62bbe13c6097607cf38f1"
27
27
  }