@uipath/authz-commands 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.
Files changed (2) hide show
  1. package/dist/index.js +224 -7
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -7018,7 +7018,165 @@ class FilterImplicitLimitError extends Error {
7018
7018
  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).";
7019
7019
  }
7020
7020
  }
7021
- function applyFilter(data, filter) {
7021
+ function countRecords(data) {
7022
+ if (Array.isArray(data))
7023
+ return data.length;
7024
+ return data == null ? 0 : 1;
7025
+ }
7026
+ function availableFields(data) {
7027
+ const records = Array.isArray(data) ? data : [data];
7028
+ const keys = new Set;
7029
+ for (const record of records) {
7030
+ if (record && typeof record === "object" && !Array.isArray(record)) {
7031
+ for (const key of Object.keys(record))
7032
+ keys.add(key);
7033
+ }
7034
+ }
7035
+ return [...keys];
7036
+ }
7037
+ function decodeQuotedIdentifier(whole, inner) {
7038
+ const [error, decoded] = catchError2(() => JSON.parse(whole));
7039
+ if (!error && typeof decoded === "string")
7040
+ return decoded;
7041
+ return inner.replace(/\\(.)/g, "$1");
7042
+ }
7043
+ function referencedFields(filter) {
7044
+ const top = new Set;
7045
+ const nested = new Set;
7046
+ const withoutValueLiterals = filter.replace(/'(?:\\.|[^'\\])*'/g, " ").replace(/`(?:\\.|[^`\\])*`/g, " ");
7047
+ const isPathTail = (text, index) => text[index - 1] === "." && /[A-Za-z0-9_"]/.test(text[index - 2] ?? "");
7048
+ const quoted = [];
7049
+ const withoutLiterals = withoutValueLiterals.replace(/"((?:\\.|[^"\\])*)"/g, (whole, name, index) => {
7050
+ const isAlias = /^\s*:/.test(withoutValueLiterals.slice(index + whole.length));
7051
+ if (!isAlias) {
7052
+ quoted.push({
7053
+ name: decodeQuotedIdentifier(whole, name),
7054
+ index,
7055
+ tail: isPathTail(withoutValueLiterals, index)
7056
+ });
7057
+ }
7058
+ return `"${" ".repeat(whole.length - 2)}"`;
7059
+ });
7060
+ const descent = /[A-Za-z0-9_"]\s*[.[]/.exec(withoutLiterals);
7061
+ const rootEnd = descent ? descent.index + 1 : Number.POSITIVE_INFINITY;
7062
+ const place = (name, index, tail) => {
7063
+ if (tail || index >= rootEnd)
7064
+ nested.add(name);
7065
+ else
7066
+ top.add(name);
7067
+ };
7068
+ for (const entry of quoted)
7069
+ place(entry.name, entry.index, entry.tail);
7070
+ const identifiers = withoutLiterals.matchAll(/([A-Za-z_][A-Za-z0-9_]*)(\s*[:(])?/g);
7071
+ const reserved = new Set(["true", "false", "null", "and", "or", "not"]);
7072
+ for (const match of identifiers) {
7073
+ const [, name, trailing] = match;
7074
+ if (trailing || reserved.has(name))
7075
+ continue;
7076
+ place(name, match.index, isPathTail(withoutLiterals, match.index));
7077
+ }
7078
+ return {
7079
+ top: [...top],
7080
+ nested: [...nested].filter((name) => !top.has(name)),
7081
+ hasPredicate: /\[\s*\?/.test(withoutValueLiterals)
7082
+ };
7083
+ }
7084
+ function appearsBelowTopLevel(data, name) {
7085
+ let budget = 2000;
7086
+ const visit = (value, depth) => {
7087
+ if (budget-- <= 0 || depth > 4)
7088
+ return false;
7089
+ if (value === null || typeof value !== "object")
7090
+ return false;
7091
+ if (Array.isArray(value))
7092
+ return value.some((entry) => visit(entry, depth));
7093
+ const record = value;
7094
+ if (depth > 0 && Object.hasOwn(record, name))
7095
+ return true;
7096
+ return Object.values(record).some((entry) => visit(entry, depth + 1));
7097
+ };
7098
+ return visit(data, 0);
7099
+ }
7100
+ function alwaysNullKeys(records) {
7101
+ const objects = records.filter((r) => r != null && typeof r === "object" && !Array.isArray(r));
7102
+ if (objects.length === 0 || objects.length !== records.length)
7103
+ return [];
7104
+ const keys = [...new Set(objects.flatMap((o) => Object.keys(o)))];
7105
+ if (keys.length === 0)
7106
+ return [];
7107
+ const nullKeys = keys.filter((key) => objects.every((record) => record[key] === null));
7108
+ return nullKeys.length === keys.length ? nullKeys : [];
7109
+ }
7110
+ function carriesOnlyNulls(value) {
7111
+ if (value === null)
7112
+ return true;
7113
+ if (Array.isArray(value)) {
7114
+ return value.length > 0 && value.every(carriesOnlyNulls);
7115
+ }
7116
+ if (typeof value === "object" && value !== undefined) {
7117
+ const values = Object.values(value);
7118
+ return values.length > 0 && values.every(carriesOnlyNulls);
7119
+ }
7120
+ return false;
7121
+ }
7122
+ function nameList(names, cap2 = 12) {
7123
+ const shown = names.slice(0, cap2).map((n) => `\`${n}\``);
7124
+ const rest = names.length - shown.length;
7125
+ return shown.join(", ") + (rest > 0 ? `, and ${rest} more` : "");
7126
+ }
7127
+ function buildFilterWarning(filter, data, outcome) {
7128
+ const present = availableFields(data);
7129
+ const refs = referencedFields(filter);
7130
+ const unknown = refs.top.filter((name) => !present.includes(name) && !appearsBelowTopLevel(data, name));
7131
+ const unchecked = refs.nested.filter((name) => !present.includes(name));
7132
+ const count = countRecords(data);
7133
+ const scope = `${count} record(s)`;
7134
+ const isNotAField = (names) => `${nameList(names)} ${names.length === 1 ? "is not a field" : "are not fields"} on the ${scope} it read`;
7135
+ 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" : "";
7136
+ const withSoundness = (base) => soundness ? `${base}, and ${soundness}` : base;
7137
+ let detail;
7138
+ let lede;
7139
+ if (outcome.kind === "null-elements") {
7140
+ lede = "returned only null values";
7141
+ const projected = `all ${outcome.count} of the elements it projected are null`;
7142
+ if (unknown.length > 0) {
7143
+ detail = `${projected}, because ${isNotAField(unknown)}`;
7144
+ } else if (unchecked.length > 0) {
7145
+ detail = withSoundness(projected);
7146
+ } else {
7147
+ 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`;
7148
+ }
7149
+ } else if (outcome.kind === "null-rows") {
7150
+ lede = "returned only null values";
7151
+ const projected = `every value it projected is null on all ${outcome.count} row(s)`;
7152
+ detail = unknown.length > 0 ? `${projected}, because ${isNotAField(unknown)}` : withSoundness(projected);
7153
+ } else if (outcome.kind === "null-values") {
7154
+ lede = "returned only null values";
7155
+ const projected = `every key it projected (${nameList(outcome.keys)}) is null`;
7156
+ const sameSet = unknown.length === outcome.keys.length && outcome.keys.every((k) => unknown.includes(k));
7157
+ if (sameSet) {
7158
+ detail = `${isNotAField(outcome.keys)}, so every key it projected is null`;
7159
+ } else if (unknown.length > 0) {
7160
+ detail = `${projected}, because ${isNotAField(unknown)}`;
7161
+ } else {
7162
+ detail = withSoundness(`${projected} on all ${scope}`);
7163
+ }
7164
+ } else {
7165
+ lede = "returned nothing";
7166
+ if (unknown.length > 0) {
7167
+ detail = isNotAField(unknown);
7168
+ } else {
7169
+ const selection = refs.hasPredicate ? "no record matched" : "the expression resolved to no value";
7170
+ detail = withSoundness(`${selection} — it read ${scope}`);
7171
+ }
7172
+ }
7173
+ const fields = present.length > 0 ? ` Available fields: ${nameList(present)}.` : "";
7174
+ return `--output-filter ${JSON.stringify(filter)} ${lede}: ${detail}.${fields}`;
7175
+ }
7176
+ function appendWarning(existing, note) {
7177
+ return existing ? `${existing} ${note}` : note;
7178
+ }
7179
+ function applyFilter(data, filter, onWarning) {
7022
7180
  const codec = requireJmespath();
7023
7181
  let result;
7024
7182
  try {
@@ -7026,9 +7184,34 @@ function applyFilter(data, filter) {
7026
7184
  } catch (err) {
7027
7185
  throw new FilterEvaluationError(filter, err);
7028
7186
  }
7029
- if (result == null)
7187
+ const inputCount = countRecords(data);
7188
+ const warn = (outcome) => {
7189
+ if (inputCount === 0)
7190
+ return;
7191
+ const note = buildFilterWarning(filter, data, outcome);
7192
+ getOutputSink().writeErr(`[WARN] ${note}
7193
+ `);
7194
+ onWarning?.(note);
7195
+ };
7196
+ const warnIfAllNull = (records) => {
7197
+ const keys = alwaysNullKeys(records);
7198
+ if (keys.length > 0)
7199
+ warn({ kind: "null-values", keys });
7200
+ };
7201
+ if (result == null) {
7202
+ warn({ kind: "empty" });
7030
7203
  return [];
7204
+ }
7031
7205
  if (Array.isArray(result)) {
7206
+ if (result.length === 0) {
7207
+ warn({ kind: "empty" });
7208
+ } else if (result.every((entry) => entry === null)) {
7209
+ warn({ kind: "null-elements", count: result.length });
7210
+ } else if (result.every((entry) => Array.isArray(entry)) && carriesOnlyNulls(result)) {
7211
+ warn({ kind: "null-rows", count: result.length });
7212
+ } else {
7213
+ warnIfAllNull(result);
7214
+ }
7032
7215
  if (result.length > 0 && typeof result[0] !== "object") {
7033
7216
  const fieldMatch = filter.match(/\.(\w+)$/);
7034
7217
  const key = fieldMatch ? fieldMatch[1] : "Value";
@@ -7036,10 +7219,30 @@ function applyFilter(data, filter) {
7036
7219
  }
7037
7220
  return result;
7038
7221
  }
7039
- if (typeof result === "object")
7222
+ if (typeof result === "object") {
7223
+ warnIfAllNull([result]);
7040
7224
  return result;
7225
+ }
7041
7226
  return { Value: result };
7042
7227
  }
7228
+ function filterFailureData(envelope) {
7229
+ const filter = getOutputFilter();
7230
+ const data = envelope.Data;
7231
+ if (!filter || data == null)
7232
+ return;
7233
+ let note;
7234
+ const [filterError, filtered] = catchError2(() => applyFilter(data, filter, (n) => {
7235
+ note = n;
7236
+ }));
7237
+ if (filterError) {
7238
+ envelope.Warning = appendWarning(envelope.Warning, `--output-filter was not applied, so Data is shown in full: ${filterError.message}`);
7239
+ return;
7240
+ }
7241
+ envelope.Data = filtered;
7242
+ if (note) {
7243
+ envelope.Warning = appendWarning(envelope.Warning, note);
7244
+ }
7245
+ }
7043
7246
  function defaultErrorCodeForResult(result) {
7044
7247
  switch (result) {
7045
7248
  case RESULTS.AuthenticationError:
@@ -7122,8 +7325,14 @@ var OutputFormatter;
7122
7325
  }
7123
7326
  const filter = getOutputFilter();
7124
7327
  if (filter) {
7125
- const filtered = applyFilter(data.Data, filter);
7328
+ let note;
7329
+ const filtered = applyFilter(data.Data, filter, (n) => {
7330
+ note = n;
7331
+ });
7126
7332
  data.Data = normalize ? normalizeDataKeys(filtered, verbatim, subtrees && { refs: subtrees.refs, mode: "skip" }) : filtered;
7333
+ if (note) {
7334
+ data.Warning = appendWarning(data.Warning, note);
7335
+ }
7127
7336
  }
7128
7337
  logOutput(normalizeOutputKeys(data), getOutputFormat(), options?.tableRowStyle);
7129
7338
  }
@@ -7151,6 +7360,7 @@ var OutputFormatter;
7151
7360
  delete envelope.TelemetryErrorClass;
7152
7361
  delete envelope.TelemetryTerminalOutcome;
7153
7362
  delete envelope.TelemetryTerminalSignal;
7363
+ filterFailureData(envelope);
7154
7364
  if (!suppressTelemetry) {
7155
7365
  telemetry.trackEvent(CommonTelemetryEvents.Error, {
7156
7366
  result: data.Result,
@@ -7199,13 +7409,20 @@ var OutputFormatter;
7199
7409
  OutputFormatter.log = log;
7200
7410
  function formatToString(data) {
7201
7411
  const filter = getOutputFilter();
7412
+ const envelope = data;
7202
7413
  if ("Data" in data && data.Data != null) {
7203
7414
  data.Data = normalizeDataKeys(data.Data);
7204
7415
  if (filter) {
7205
- data.Data = normalizeDataKeys(applyFilter(data.Data, filter));
7416
+ let note;
7417
+ data.Data = normalizeDataKeys(applyFilter(data.Data, filter, (n) => {
7418
+ note = n;
7419
+ }));
7420
+ if (note) {
7421
+ envelope.Warning = appendWarning(envelope.Warning, note);
7422
+ }
7206
7423
  }
7207
7424
  }
7208
- const output = normalizeOutputKeys(data);
7425
+ const output = normalizeOutputKeys(envelope);
7209
7426
  const lines = [];
7210
7427
  const sink = getOutputSink();
7211
7428
  printOutput(output, getOutputFormat(), (msg) => {
@@ -10626,4 +10843,4 @@ export {
10626
10843
  registerCommands
10627
10844
  };
10628
10845
 
10629
- //# debugId=38E8B0A86603C39264756E2164756E21
10846
+ //# debugId=DD1B3228E67B284864756E2164756E21
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@uipath/authz-commands",
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": "Admin CLI commands for the UiPath Authorization service. Library composed by admin-tool, not a standalone CLI tool.",
6
6
  "private": false,
7
7
  "repository": {
@@ -25,5 +25,5 @@
25
25
  "files": [
26
26
  "dist"
27
27
  ],
28
- "gitHead": "a09041733b628c3f6b658a1f58349ea0f40bb492"
28
+ "gitHead": "537e43df1d3583633cfd3a0b88634f9ce3ba9d6b"
29
29
  }