@uipath/oms-commands 1.203.0-preview.235 → 1.203.0-preview.240

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/index.js +224 -7
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -4992,7 +4992,165 @@ class FilterImplicitLimitError extends Error {
4992
4992
  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).";
4993
4993
  }
4994
4994
  }
4995
- function applyFilter(data, filter) {
4995
+ function countRecords(data) {
4996
+ if (Array.isArray(data))
4997
+ return data.length;
4998
+ return data == null ? 0 : 1;
4999
+ }
5000
+ function availableFields(data) {
5001
+ const records = Array.isArray(data) ? data : [data];
5002
+ const keys = new Set;
5003
+ for (const record of records) {
5004
+ if (record && typeof record === "object" && !Array.isArray(record)) {
5005
+ for (const key of Object.keys(record))
5006
+ keys.add(key);
5007
+ }
5008
+ }
5009
+ return [...keys];
5010
+ }
5011
+ function decodeQuotedIdentifier(whole, inner) {
5012
+ const [error, decoded] = catchError(() => JSON.parse(whole));
5013
+ if (!error && typeof decoded === "string")
5014
+ return decoded;
5015
+ return inner.replace(/\\(.)/g, "$1");
5016
+ }
5017
+ function referencedFields(filter) {
5018
+ const top = new Set;
5019
+ const nested = new Set;
5020
+ const withoutValueLiterals = filter.replace(/'(?:\\.|[^'\\])*'/g, " ").replace(/`(?:\\.|[^`\\])*`/g, " ");
5021
+ const isPathTail = (text, index) => text[index - 1] === "." && /[A-Za-z0-9_"]/.test(text[index - 2] ?? "");
5022
+ const quoted = [];
5023
+ const withoutLiterals = withoutValueLiterals.replace(/"((?:\\.|[^"\\])*)"/g, (whole, name, index) => {
5024
+ const isAlias = /^\s*:/.test(withoutValueLiterals.slice(index + whole.length));
5025
+ if (!isAlias) {
5026
+ quoted.push({
5027
+ name: decodeQuotedIdentifier(whole, name),
5028
+ index,
5029
+ tail: isPathTail(withoutValueLiterals, index)
5030
+ });
5031
+ }
5032
+ return `"${" ".repeat(whole.length - 2)}"`;
5033
+ });
5034
+ const descent = /[A-Za-z0-9_"]\s*[.[]/.exec(withoutLiterals);
5035
+ const rootEnd = descent ? descent.index + 1 : Number.POSITIVE_INFINITY;
5036
+ const place = (name, index, tail) => {
5037
+ if (tail || index >= rootEnd)
5038
+ nested.add(name);
5039
+ else
5040
+ top.add(name);
5041
+ };
5042
+ for (const entry of quoted)
5043
+ place(entry.name, entry.index, entry.tail);
5044
+ const identifiers = withoutLiterals.matchAll(/([A-Za-z_][A-Za-z0-9_]*)(\s*[:(])?/g);
5045
+ const reserved = new Set(["true", "false", "null", "and", "or", "not"]);
5046
+ for (const match of identifiers) {
5047
+ const [, name, trailing] = match;
5048
+ if (trailing || reserved.has(name))
5049
+ continue;
5050
+ place(name, match.index, isPathTail(withoutLiterals, match.index));
5051
+ }
5052
+ return {
5053
+ top: [...top],
5054
+ nested: [...nested].filter((name) => !top.has(name)),
5055
+ hasPredicate: /\[\s*\?/.test(withoutValueLiterals)
5056
+ };
5057
+ }
5058
+ function appearsBelowTopLevel(data, name) {
5059
+ let budget = 2000;
5060
+ const visit = (value, depth) => {
5061
+ if (budget-- <= 0 || depth > 4)
5062
+ return false;
5063
+ if (value === null || typeof value !== "object")
5064
+ return false;
5065
+ if (Array.isArray(value))
5066
+ return value.some((entry) => visit(entry, depth));
5067
+ const record = value;
5068
+ if (depth > 0 && Object.hasOwn(record, name))
5069
+ return true;
5070
+ return Object.values(record).some((entry) => visit(entry, depth + 1));
5071
+ };
5072
+ return visit(data, 0);
5073
+ }
5074
+ function alwaysNullKeys(records) {
5075
+ const objects = records.filter((r) => r != null && typeof r === "object" && !Array.isArray(r));
5076
+ if (objects.length === 0 || objects.length !== records.length)
5077
+ return [];
5078
+ const keys = [...new Set(objects.flatMap((o) => Object.keys(o)))];
5079
+ if (keys.length === 0)
5080
+ return [];
5081
+ const nullKeys = keys.filter((key) => objects.every((record) => record[key] === null));
5082
+ return nullKeys.length === keys.length ? nullKeys : [];
5083
+ }
5084
+ function carriesOnlyNulls(value) {
5085
+ if (value === null)
5086
+ return true;
5087
+ if (Array.isArray(value)) {
5088
+ return value.length > 0 && value.every(carriesOnlyNulls);
5089
+ }
5090
+ if (typeof value === "object" && value !== undefined) {
5091
+ const values = Object.values(value);
5092
+ return values.length > 0 && values.every(carriesOnlyNulls);
5093
+ }
5094
+ return false;
5095
+ }
5096
+ function nameList(names, cap2 = 12) {
5097
+ const shown = names.slice(0, cap2).map((n) => `\`${n}\``);
5098
+ const rest = names.length - shown.length;
5099
+ return shown.join(", ") + (rest > 0 ? `, and ${rest} more` : "");
5100
+ }
5101
+ function buildFilterWarning(filter, data, outcome) {
5102
+ const present = availableFields(data);
5103
+ const refs = referencedFields(filter);
5104
+ const unknown = refs.top.filter((name) => !present.includes(name) && !appearsBelowTopLevel(data, name));
5105
+ const unchecked = refs.nested.filter((name) => !present.includes(name));
5106
+ const count = countRecords(data);
5107
+ const scope = `${count} record(s)`;
5108
+ const isNotAField = (names) => `${nameList(names)} ${names.length === 1 ? "is not a field" : "are not fields"} on the ${scope} it read`;
5109
+ 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" : "";
5110
+ const withSoundness = (base) => soundness ? `${base}, and ${soundness}` : base;
5111
+ let detail;
5112
+ let lede;
5113
+ if (outcome.kind === "null-elements") {
5114
+ lede = "returned only null values";
5115
+ const projected = `all ${outcome.count} of the elements it projected are null`;
5116
+ if (unknown.length > 0) {
5117
+ detail = `${projected}, because ${isNotAField(unknown)}`;
5118
+ } else if (unchecked.length > 0) {
5119
+ detail = withSoundness(projected);
5120
+ } else {
5121
+ 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`;
5122
+ }
5123
+ } else if (outcome.kind === "null-rows") {
5124
+ lede = "returned only null values";
5125
+ const projected = `every value it projected is null on all ${outcome.count} row(s)`;
5126
+ detail = unknown.length > 0 ? `${projected}, because ${isNotAField(unknown)}` : withSoundness(projected);
5127
+ } else if (outcome.kind === "null-values") {
5128
+ lede = "returned only null values";
5129
+ const projected = `every key it projected (${nameList(outcome.keys)}) is null`;
5130
+ const sameSet = unknown.length === outcome.keys.length && outcome.keys.every((k) => unknown.includes(k));
5131
+ if (sameSet) {
5132
+ detail = `${isNotAField(outcome.keys)}, so every key it projected is null`;
5133
+ } else if (unknown.length > 0) {
5134
+ detail = `${projected}, because ${isNotAField(unknown)}`;
5135
+ } else {
5136
+ detail = withSoundness(`${projected} on all ${scope}`);
5137
+ }
5138
+ } else {
5139
+ lede = "returned nothing";
5140
+ if (unknown.length > 0) {
5141
+ detail = isNotAField(unknown);
5142
+ } else {
5143
+ const selection = refs.hasPredicate ? "no record matched" : "the expression resolved to no value";
5144
+ detail = withSoundness(`${selection} — it read ${scope}`);
5145
+ }
5146
+ }
5147
+ const fields = present.length > 0 ? ` Available fields: ${nameList(present)}.` : "";
5148
+ return `--output-filter ${JSON.stringify(filter)} ${lede}: ${detail}.${fields}`;
5149
+ }
5150
+ function appendWarning(existing, note) {
5151
+ return existing ? `${existing} ${note}` : note;
5152
+ }
5153
+ function applyFilter(data, filter, onWarning) {
4996
5154
  const codec = requireJmespath();
4997
5155
  let result;
4998
5156
  try {
@@ -5000,9 +5158,34 @@ function applyFilter(data, filter) {
5000
5158
  } catch (err) {
5001
5159
  throw new FilterEvaluationError(filter, err);
5002
5160
  }
5003
- if (result == null)
5161
+ const inputCount = countRecords(data);
5162
+ const warn = (outcome) => {
5163
+ if (inputCount === 0)
5164
+ return;
5165
+ const note = buildFilterWarning(filter, data, outcome);
5166
+ getOutputSink().writeErr(`[WARN] ${note}
5167
+ `);
5168
+ onWarning?.(note);
5169
+ };
5170
+ const warnIfAllNull = (records) => {
5171
+ const keys = alwaysNullKeys(records);
5172
+ if (keys.length > 0)
5173
+ warn({ kind: "null-values", keys });
5174
+ };
5175
+ if (result == null) {
5176
+ warn({ kind: "empty" });
5004
5177
  return [];
5178
+ }
5005
5179
  if (Array.isArray(result)) {
5180
+ if (result.length === 0) {
5181
+ warn({ kind: "empty" });
5182
+ } else if (result.every((entry) => entry === null)) {
5183
+ warn({ kind: "null-elements", count: result.length });
5184
+ } else if (result.every((entry) => Array.isArray(entry)) && carriesOnlyNulls(result)) {
5185
+ warn({ kind: "null-rows", count: result.length });
5186
+ } else {
5187
+ warnIfAllNull(result);
5188
+ }
5006
5189
  if (result.length > 0 && typeof result[0] !== "object") {
5007
5190
  const fieldMatch = filter.match(/\.(\w+)$/);
5008
5191
  const key = fieldMatch ? fieldMatch[1] : "Value";
@@ -5010,10 +5193,30 @@ function applyFilter(data, filter) {
5010
5193
  }
5011
5194
  return result;
5012
5195
  }
5013
- if (typeof result === "object")
5196
+ if (typeof result === "object") {
5197
+ warnIfAllNull([result]);
5014
5198
  return result;
5199
+ }
5015
5200
  return { Value: result };
5016
5201
  }
5202
+ function filterFailureData(envelope) {
5203
+ const filter = getOutputFilter();
5204
+ const data = envelope.Data;
5205
+ if (!filter || data == null)
5206
+ return;
5207
+ let note;
5208
+ const [filterError, filtered] = catchError(() => applyFilter(data, filter, (n) => {
5209
+ note = n;
5210
+ }));
5211
+ if (filterError) {
5212
+ envelope.Warning = appendWarning(envelope.Warning, `--output-filter was not applied, so Data is shown in full: ${filterError.message}`);
5213
+ return;
5214
+ }
5215
+ envelope.Data = filtered;
5216
+ if (note) {
5217
+ envelope.Warning = appendWarning(envelope.Warning, note);
5218
+ }
5219
+ }
5017
5220
  function defaultErrorCodeForResult(result) {
5018
5221
  switch (result) {
5019
5222
  case RESULTS.AuthenticationError:
@@ -5096,8 +5299,14 @@ var OutputFormatter;
5096
5299
  }
5097
5300
  const filter = getOutputFilter();
5098
5301
  if (filter) {
5099
- const filtered = applyFilter(data.Data, filter);
5302
+ let note;
5303
+ const filtered = applyFilter(data.Data, filter, (n) => {
5304
+ note = n;
5305
+ });
5100
5306
  data.Data = normalize ? normalizeDataKeys(filtered, verbatim, subtrees && { refs: subtrees.refs, mode: "skip" }) : filtered;
5307
+ if (note) {
5308
+ data.Warning = appendWarning(data.Warning, note);
5309
+ }
5101
5310
  }
5102
5311
  logOutput(normalizeOutputKeys(data), getOutputFormat(), options?.tableRowStyle);
5103
5312
  }
@@ -5125,6 +5334,7 @@ var OutputFormatter;
5125
5334
  delete envelope.TelemetryErrorClass;
5126
5335
  delete envelope.TelemetryTerminalOutcome;
5127
5336
  delete envelope.TelemetryTerminalSignal;
5337
+ filterFailureData(envelope);
5128
5338
  if (!suppressTelemetry) {
5129
5339
  telemetry.trackEvent(CommonTelemetryEvents.Error, {
5130
5340
  result: data.Result,
@@ -5173,13 +5383,20 @@ var OutputFormatter;
5173
5383
  OutputFormatter.log = log;
5174
5384
  function formatToString(data) {
5175
5385
  const filter = getOutputFilter();
5386
+ const envelope = data;
5176
5387
  if ("Data" in data && data.Data != null) {
5177
5388
  data.Data = normalizeDataKeys(data.Data);
5178
5389
  if (filter) {
5179
- data.Data = normalizeDataKeys(applyFilter(data.Data, filter));
5390
+ let note;
5391
+ data.Data = normalizeDataKeys(applyFilter(data.Data, filter, (n) => {
5392
+ note = n;
5393
+ }));
5394
+ if (note) {
5395
+ envelope.Warning = appendWarning(envelope.Warning, note);
5396
+ }
5180
5397
  }
5181
5398
  }
5182
- const output = normalizeOutputKeys(data);
5399
+ const output = normalizeOutputKeys(envelope);
5183
5400
  const lines = [];
5184
5401
  const sink = getOutputSink();
5185
5402
  printOutput(output, getOutputFormat(), (msg) => {
@@ -13766,4 +13983,4 @@ export {
13766
13983
  registerCommands
13767
13984
  };
13768
13985
 
13769
- //# debugId=A876B4B73A00529C64756E2164756E21
13986
+ //# debugId=97A52DA6DCF4055C64756E2164756E21
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@uipath/oms-commands",
3
3
  "author": "UiPath",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
- "version": "1.203.0-preview.235",
5
+ "version": "1.203.0-preview.240",
6
6
  "description": "Admin CLI commands for the UiPath Organization Management Service. Library composed by admin-tool, not a standalone CLI tool.",
7
7
  "private": false,
8
8
  "repository": {
@@ -26,5 +26,5 @@
26
26
  "files": [
27
27
  "dist"
28
28
  ],
29
- "gitHead": "4788b04c17a4429e5a994af2c3eba3898d1c4b13"
29
+ "gitHead": "95409ea61d359dff5465afaf59cb3a5efae542af"
30
30
  }