@uipath/guardrails-tool 1.203.0-preview.233 → 1.203.0-preview.237

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
@@ -2101,7 +2101,7 @@ var package_default = {
2101
2101
  name: "@uipath/guardrails-tool",
2102
2102
  author: "UiPath",
2103
2103
  license: "SEE LICENSE IN LICENSE.txt",
2104
- version: "1.203.0-preview.233",
2104
+ version: "1.203.0-preview.237",
2105
2105
  description: "CLI plugin for UiPath AI Trust Layer guardrail configurations.",
2106
2106
  private: false,
2107
2107
  repository: {
@@ -4663,7 +4663,165 @@ class FilterImplicitLimitError extends Error {
4663
4663
  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).";
4664
4664
  }
4665
4665
  }
4666
- function applyFilter(data, filter) {
4666
+ function countRecords(data) {
4667
+ if (Array.isArray(data))
4668
+ return data.length;
4669
+ return data == null ? 0 : 1;
4670
+ }
4671
+ function availableFields(data) {
4672
+ const records = Array.isArray(data) ? data : [data];
4673
+ const keys = new Set;
4674
+ for (const record of records) {
4675
+ if (record && typeof record === "object" && !Array.isArray(record)) {
4676
+ for (const key of Object.keys(record))
4677
+ keys.add(key);
4678
+ }
4679
+ }
4680
+ return [...keys];
4681
+ }
4682
+ function decodeQuotedIdentifier(whole, inner) {
4683
+ const [error, decoded] = catchError(() => JSON.parse(whole));
4684
+ if (!error && typeof decoded === "string")
4685
+ return decoded;
4686
+ return inner.replace(/\\(.)/g, "$1");
4687
+ }
4688
+ function referencedFields(filter) {
4689
+ const top = new Set;
4690
+ const nested = new Set;
4691
+ const withoutValueLiterals = filter.replace(/'(?:\\.|[^'\\])*'/g, " ").replace(/`(?:\\.|[^`\\])*`/g, " ");
4692
+ const isPathTail = (text, index) => text[index - 1] === "." && /[A-Za-z0-9_"]/.test(text[index - 2] ?? "");
4693
+ const quoted = [];
4694
+ const withoutLiterals = withoutValueLiterals.replace(/"((?:\\.|[^"\\])*)"/g, (whole, name, index) => {
4695
+ const isAlias = /^\s*:/.test(withoutValueLiterals.slice(index + whole.length));
4696
+ if (!isAlias) {
4697
+ quoted.push({
4698
+ name: decodeQuotedIdentifier(whole, name),
4699
+ index,
4700
+ tail: isPathTail(withoutValueLiterals, index)
4701
+ });
4702
+ }
4703
+ return `"${" ".repeat(whole.length - 2)}"`;
4704
+ });
4705
+ const descent = /[A-Za-z0-9_"]\s*[.[]/.exec(withoutLiterals);
4706
+ const rootEnd = descent ? descent.index + 1 : Number.POSITIVE_INFINITY;
4707
+ const place = (name, index, tail) => {
4708
+ if (tail || index >= rootEnd)
4709
+ nested.add(name);
4710
+ else
4711
+ top.add(name);
4712
+ };
4713
+ for (const entry of quoted)
4714
+ place(entry.name, entry.index, entry.tail);
4715
+ const identifiers = withoutLiterals.matchAll(/([A-Za-z_][A-Za-z0-9_]*)(\s*[:(])?/g);
4716
+ const reserved = new Set(["true", "false", "null", "and", "or", "not"]);
4717
+ for (const match of identifiers) {
4718
+ const [, name, trailing] = match;
4719
+ if (trailing || reserved.has(name))
4720
+ continue;
4721
+ place(name, match.index, isPathTail(withoutLiterals, match.index));
4722
+ }
4723
+ return {
4724
+ top: [...top],
4725
+ nested: [...nested].filter((name) => !top.has(name)),
4726
+ hasPredicate: /\[\s*\?/.test(withoutValueLiterals)
4727
+ };
4728
+ }
4729
+ function appearsBelowTopLevel(data, name) {
4730
+ let budget = 2000;
4731
+ const visit = (value, depth) => {
4732
+ if (budget-- <= 0 || depth > 4)
4733
+ return false;
4734
+ if (value === null || typeof value !== "object")
4735
+ return false;
4736
+ if (Array.isArray(value))
4737
+ return value.some((entry) => visit(entry, depth));
4738
+ const record = value;
4739
+ if (depth > 0 && Object.hasOwn(record, name))
4740
+ return true;
4741
+ return Object.values(record).some((entry) => visit(entry, depth + 1));
4742
+ };
4743
+ return visit(data, 0);
4744
+ }
4745
+ function alwaysNullKeys(records) {
4746
+ const objects = records.filter((r) => r != null && typeof r === "object" && !Array.isArray(r));
4747
+ if (objects.length === 0 || objects.length !== records.length)
4748
+ return [];
4749
+ const keys = [...new Set(objects.flatMap((o) => Object.keys(o)))];
4750
+ if (keys.length === 0)
4751
+ return [];
4752
+ const nullKeys = keys.filter((key) => objects.every((record) => record[key] === null));
4753
+ return nullKeys.length === keys.length ? nullKeys : [];
4754
+ }
4755
+ function carriesOnlyNulls(value) {
4756
+ if (value === null)
4757
+ return true;
4758
+ if (Array.isArray(value)) {
4759
+ return value.length > 0 && value.every(carriesOnlyNulls);
4760
+ }
4761
+ if (typeof value === "object" && value !== undefined) {
4762
+ const values = Object.values(value);
4763
+ return values.length > 0 && values.every(carriesOnlyNulls);
4764
+ }
4765
+ return false;
4766
+ }
4767
+ function nameList(names, cap2 = 12) {
4768
+ const shown = names.slice(0, cap2).map((n) => `\`${n}\``);
4769
+ const rest = names.length - shown.length;
4770
+ return shown.join(", ") + (rest > 0 ? `, and ${rest} more` : "");
4771
+ }
4772
+ function buildFilterWarning(filter, data, outcome) {
4773
+ const present = availableFields(data);
4774
+ const refs = referencedFields(filter);
4775
+ const unknown = refs.top.filter((name) => !present.includes(name) && !appearsBelowTopLevel(data, name));
4776
+ const unchecked = refs.nested.filter((name) => !present.includes(name));
4777
+ const count = countRecords(data);
4778
+ const scope = `${count} record(s)`;
4779
+ const isNotAField = (names) => `${nameList(names)} ${names.length === 1 ? "is not a field" : "are not fields"} on the ${scope} it read`;
4780
+ 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" : "";
4781
+ const withSoundness = (base) => soundness ? `${base}, and ${soundness}` : base;
4782
+ let detail;
4783
+ let lede;
4784
+ if (outcome.kind === "null-elements") {
4785
+ lede = "returned only null values";
4786
+ const projected = `all ${outcome.count} of the elements it projected are null`;
4787
+ if (unknown.length > 0) {
4788
+ detail = `${projected}, because ${isNotAField(unknown)}`;
4789
+ } else if (unchecked.length > 0) {
4790
+ detail = withSoundness(projected);
4791
+ } else {
4792
+ 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`;
4793
+ }
4794
+ } else if (outcome.kind === "null-rows") {
4795
+ lede = "returned only null values";
4796
+ const projected = `every value it projected is null on all ${outcome.count} row(s)`;
4797
+ detail = unknown.length > 0 ? `${projected}, because ${isNotAField(unknown)}` : withSoundness(projected);
4798
+ } else if (outcome.kind === "null-values") {
4799
+ lede = "returned only null values";
4800
+ const projected = `every key it projected (${nameList(outcome.keys)}) is null`;
4801
+ const sameSet = unknown.length === outcome.keys.length && outcome.keys.every((k) => unknown.includes(k));
4802
+ if (sameSet) {
4803
+ detail = `${isNotAField(outcome.keys)}, so every key it projected is null`;
4804
+ } else if (unknown.length > 0) {
4805
+ detail = `${projected}, because ${isNotAField(unknown)}`;
4806
+ } else {
4807
+ detail = withSoundness(`${projected} on all ${scope}`);
4808
+ }
4809
+ } else {
4810
+ lede = "returned nothing";
4811
+ if (unknown.length > 0) {
4812
+ detail = isNotAField(unknown);
4813
+ } else {
4814
+ const selection = refs.hasPredicate ? "no record matched" : "the expression resolved to no value";
4815
+ detail = withSoundness(`${selection} — it read ${scope}`);
4816
+ }
4817
+ }
4818
+ const fields = present.length > 0 ? ` Available fields: ${nameList(present)}.` : "";
4819
+ return `--output-filter ${JSON.stringify(filter)} ${lede}: ${detail}.${fields}`;
4820
+ }
4821
+ function appendWarning(existing, note) {
4822
+ return existing ? `${existing} ${note}` : note;
4823
+ }
4824
+ function applyFilter(data, filter, onWarning) {
4667
4825
  const codec = requireJmespath();
4668
4826
  let result;
4669
4827
  try {
@@ -4671,9 +4829,34 @@ function applyFilter(data, filter) {
4671
4829
  } catch (err) {
4672
4830
  throw new FilterEvaluationError(filter, err);
4673
4831
  }
4674
- if (result == null)
4832
+ const inputCount = countRecords(data);
4833
+ const warn = (outcome) => {
4834
+ if (inputCount === 0)
4835
+ return;
4836
+ const note = buildFilterWarning(filter, data, outcome);
4837
+ getOutputSink().writeErr(`[WARN] ${note}
4838
+ `);
4839
+ onWarning?.(note);
4840
+ };
4841
+ const warnIfAllNull = (records) => {
4842
+ const keys = alwaysNullKeys(records);
4843
+ if (keys.length > 0)
4844
+ warn({ kind: "null-values", keys });
4845
+ };
4846
+ if (result == null) {
4847
+ warn({ kind: "empty" });
4675
4848
  return [];
4849
+ }
4676
4850
  if (Array.isArray(result)) {
4851
+ if (result.length === 0) {
4852
+ warn({ kind: "empty" });
4853
+ } else if (result.every((entry) => entry === null)) {
4854
+ warn({ kind: "null-elements", count: result.length });
4855
+ } else if (result.every((entry) => Array.isArray(entry)) && carriesOnlyNulls(result)) {
4856
+ warn({ kind: "null-rows", count: result.length });
4857
+ } else {
4858
+ warnIfAllNull(result);
4859
+ }
4677
4860
  if (result.length > 0 && typeof result[0] !== "object") {
4678
4861
  const fieldMatch = filter.match(/\.(\w+)$/);
4679
4862
  const key = fieldMatch ? fieldMatch[1] : "Value";
@@ -4681,10 +4864,30 @@ function applyFilter(data, filter) {
4681
4864
  }
4682
4865
  return result;
4683
4866
  }
4684
- if (typeof result === "object")
4867
+ if (typeof result === "object") {
4868
+ warnIfAllNull([result]);
4685
4869
  return result;
4870
+ }
4686
4871
  return { Value: result };
4687
4872
  }
4873
+ function filterFailureData(envelope) {
4874
+ const filter = getOutputFilter();
4875
+ const data = envelope.Data;
4876
+ if (!filter || data == null)
4877
+ return;
4878
+ let note;
4879
+ const [filterError, filtered] = catchError(() => applyFilter(data, filter, (n) => {
4880
+ note = n;
4881
+ }));
4882
+ if (filterError) {
4883
+ envelope.Warning = appendWarning(envelope.Warning, `--output-filter was not applied, so Data is shown in full: ${filterError.message}`);
4884
+ return;
4885
+ }
4886
+ envelope.Data = filtered;
4887
+ if (note) {
4888
+ envelope.Warning = appendWarning(envelope.Warning, note);
4889
+ }
4890
+ }
4688
4891
  function defaultErrorCodeForResult(result) {
4689
4892
  switch (result) {
4690
4893
  case RESULTS.AuthenticationError:
@@ -4767,8 +4970,14 @@ var OutputFormatter;
4767
4970
  }
4768
4971
  const filter = getOutputFilter();
4769
4972
  if (filter) {
4770
- const filtered = applyFilter(data.Data, filter);
4973
+ let note;
4974
+ const filtered = applyFilter(data.Data, filter, (n) => {
4975
+ note = n;
4976
+ });
4771
4977
  data.Data = normalize ? normalizeDataKeys(filtered, verbatim, subtrees && { refs: subtrees.refs, mode: "skip" }) : filtered;
4978
+ if (note) {
4979
+ data.Warning = appendWarning(data.Warning, note);
4980
+ }
4772
4981
  }
4773
4982
  logOutput(normalizeOutputKeys(data), getOutputFormat(), options?.tableRowStyle);
4774
4983
  }
@@ -4796,6 +5005,7 @@ var OutputFormatter;
4796
5005
  delete envelope.TelemetryErrorClass;
4797
5006
  delete envelope.TelemetryTerminalOutcome;
4798
5007
  delete envelope.TelemetryTerminalSignal;
5008
+ filterFailureData(envelope);
4799
5009
  if (!suppressTelemetry) {
4800
5010
  telemetry.trackEvent(CommonTelemetryEvents.Error, {
4801
5011
  result: data.Result,
@@ -4844,13 +5054,20 @@ var OutputFormatter;
4844
5054
  OutputFormatter.log = log;
4845
5055
  function formatToString(data) {
4846
5056
  const filter = getOutputFilter();
5057
+ const envelope = data;
4847
5058
  if ("Data" in data && data.Data != null) {
4848
5059
  data.Data = normalizeDataKeys(data.Data);
4849
5060
  if (filter) {
4850
- data.Data = normalizeDataKeys(applyFilter(data.Data, filter));
5061
+ let note;
5062
+ data.Data = normalizeDataKeys(applyFilter(data.Data, filter, (n) => {
5063
+ note = n;
5064
+ }));
5065
+ if (note) {
5066
+ envelope.Warning = appendWarning(envelope.Warning, note);
5067
+ }
4851
5068
  }
4852
5069
  }
4853
- const output = normalizeOutputKeys(data);
5070
+ const output = normalizeOutputKeys(envelope);
4854
5071
  const lines = [];
4855
5072
  const sink = getOutputSink();
4856
5073
  printOutput(output, getOutputFormat(), (msg) => {
@@ -7451,4 +7668,4 @@ export {
7451
7668
  registerCommands
7452
7669
  };
7453
7670
 
7454
- //# debugId=A0F3192F03CE7C3964756E2164756E21
7671
+ //# debugId=2453649C1BE3874564756E2164756E21
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@uipath/guardrails-tool",
3
3
  "author": "UiPath",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
- "version": "1.203.0-preview.233",
5
+ "version": "1.203.0-preview.237",
6
6
  "description": "CLI plugin for UiPath AI Trust Layer guardrail configurations.",
7
7
  "private": false,
8
8
  "repository": {
@@ -24,5 +24,5 @@
24
24
  "files": [
25
25
  "dist"
26
26
  ],
27
- "gitHead": "641614a6f9817662baaf51dabdebbfa2a9334b1b"
27
+ "gitHead": "4ad3e17a66f2c7fb7fe1f0e3e04a5b6175a0a9a3"
28
28
  }