@uipath/authz-commands 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/index.js +224 -7
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -7268,7 +7268,165 @@ class FilterImplicitLimitError extends Error {
7268
7268
  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).";
7269
7269
  }
7270
7270
  }
7271
- function applyFilter(data, filter) {
7271
+ function countRecords(data) {
7272
+ if (Array.isArray(data))
7273
+ return data.length;
7274
+ return data == null ? 0 : 1;
7275
+ }
7276
+ function availableFields(data) {
7277
+ const records = Array.isArray(data) ? data : [data];
7278
+ const keys = new Set;
7279
+ for (const record of records) {
7280
+ if (record && typeof record === "object" && !Array.isArray(record)) {
7281
+ for (const key of Object.keys(record))
7282
+ keys.add(key);
7283
+ }
7284
+ }
7285
+ return [...keys];
7286
+ }
7287
+ function decodeQuotedIdentifier(whole, inner) {
7288
+ const [error, decoded] = catchError2(() => JSON.parse(whole));
7289
+ if (!error && typeof decoded === "string")
7290
+ return decoded;
7291
+ return inner.replace(/\\(.)/g, "$1");
7292
+ }
7293
+ function referencedFields(filter) {
7294
+ const top = new Set;
7295
+ const nested = new Set;
7296
+ const withoutValueLiterals = filter.replace(/'(?:\\.|[^'\\])*'/g, " ").replace(/`(?:\\.|[^`\\])*`/g, " ");
7297
+ const isPathTail = (text, index) => text[index - 1] === "." && /[A-Za-z0-9_"]/.test(text[index - 2] ?? "");
7298
+ const quoted = [];
7299
+ const withoutLiterals = withoutValueLiterals.replace(/"((?:\\.|[^"\\])*)"/g, (whole, name, index) => {
7300
+ const isAlias = /^\s*:/.test(withoutValueLiterals.slice(index + whole.length));
7301
+ if (!isAlias) {
7302
+ quoted.push({
7303
+ name: decodeQuotedIdentifier(whole, name),
7304
+ index,
7305
+ tail: isPathTail(withoutValueLiterals, index)
7306
+ });
7307
+ }
7308
+ return `"${" ".repeat(whole.length - 2)}"`;
7309
+ });
7310
+ const descent = /[A-Za-z0-9_"]\s*[.[]/.exec(withoutLiterals);
7311
+ const rootEnd = descent ? descent.index + 1 : Number.POSITIVE_INFINITY;
7312
+ const place = (name, index, tail) => {
7313
+ if (tail || index >= rootEnd)
7314
+ nested.add(name);
7315
+ else
7316
+ top.add(name);
7317
+ };
7318
+ for (const entry of quoted)
7319
+ place(entry.name, entry.index, entry.tail);
7320
+ const identifiers = withoutLiterals.matchAll(/([A-Za-z_][A-Za-z0-9_]*)(\s*[:(])?/g);
7321
+ const reserved = new Set(["true", "false", "null", "and", "or", "not"]);
7322
+ for (const match of identifiers) {
7323
+ const [, name, trailing] = match;
7324
+ if (trailing || reserved.has(name))
7325
+ continue;
7326
+ place(name, match.index, isPathTail(withoutLiterals, match.index));
7327
+ }
7328
+ return {
7329
+ top: [...top],
7330
+ nested: [...nested].filter((name) => !top.has(name)),
7331
+ hasPredicate: /\[\s*\?/.test(withoutValueLiterals)
7332
+ };
7333
+ }
7334
+ function appearsBelowTopLevel(data, name) {
7335
+ let budget = 2000;
7336
+ const visit = (value, depth) => {
7337
+ if (budget-- <= 0 || depth > 4)
7338
+ return false;
7339
+ if (value === null || typeof value !== "object")
7340
+ return false;
7341
+ if (Array.isArray(value))
7342
+ return value.some((entry) => visit(entry, depth));
7343
+ const record = value;
7344
+ if (depth > 0 && Object.hasOwn(record, name))
7345
+ return true;
7346
+ return Object.values(record).some((entry) => visit(entry, depth + 1));
7347
+ };
7348
+ return visit(data, 0);
7349
+ }
7350
+ function alwaysNullKeys(records) {
7351
+ const objects = records.filter((r) => r != null && typeof r === "object" && !Array.isArray(r));
7352
+ if (objects.length === 0 || objects.length !== records.length)
7353
+ return [];
7354
+ const keys = [...new Set(objects.flatMap((o) => Object.keys(o)))];
7355
+ if (keys.length === 0)
7356
+ return [];
7357
+ const nullKeys = keys.filter((key) => objects.every((record) => record[key] === null));
7358
+ return nullKeys.length === keys.length ? nullKeys : [];
7359
+ }
7360
+ function carriesOnlyNulls(value) {
7361
+ if (value === null)
7362
+ return true;
7363
+ if (Array.isArray(value)) {
7364
+ return value.length > 0 && value.every(carriesOnlyNulls);
7365
+ }
7366
+ if (typeof value === "object" && value !== undefined) {
7367
+ const values = Object.values(value);
7368
+ return values.length > 0 && values.every(carriesOnlyNulls);
7369
+ }
7370
+ return false;
7371
+ }
7372
+ function nameList(names, cap2 = 12) {
7373
+ const shown = names.slice(0, cap2).map((n) => `\`${n}\``);
7374
+ const rest = names.length - shown.length;
7375
+ return shown.join(", ") + (rest > 0 ? `, and ${rest} more` : "");
7376
+ }
7377
+ function buildFilterWarning(filter, data, outcome) {
7378
+ const present = availableFields(data);
7379
+ const refs = referencedFields(filter);
7380
+ const unknown = refs.top.filter((name) => !present.includes(name) && !appearsBelowTopLevel(data, name));
7381
+ const unchecked = refs.nested.filter((name) => !present.includes(name));
7382
+ const count = countRecords(data);
7383
+ const scope = `${count} record(s)`;
7384
+ const isNotAField = (names) => `${nameList(names)} ${names.length === 1 ? "is not a field" : "are not fields"} on the ${scope} it read`;
7385
+ 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" : "";
7386
+ const withSoundness = (base) => soundness ? `${base}, and ${soundness}` : base;
7387
+ let detail;
7388
+ let lede;
7389
+ if (outcome.kind === "null-elements") {
7390
+ lede = "returned only null values";
7391
+ const projected = `all ${outcome.count} of the elements it projected are null`;
7392
+ if (unknown.length > 0) {
7393
+ detail = `${projected}, because ${isNotAField(unknown)}`;
7394
+ } else if (unchecked.length > 0) {
7395
+ detail = withSoundness(projected);
7396
+ } else {
7397
+ 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`;
7398
+ }
7399
+ } else if (outcome.kind === "null-rows") {
7400
+ lede = "returned only null values";
7401
+ const projected = `every value it projected is null on all ${outcome.count} row(s)`;
7402
+ detail = unknown.length > 0 ? `${projected}, because ${isNotAField(unknown)}` : withSoundness(projected);
7403
+ } else if (outcome.kind === "null-values") {
7404
+ lede = "returned only null values";
7405
+ const projected = `every key it projected (${nameList(outcome.keys)}) is null`;
7406
+ const sameSet = unknown.length === outcome.keys.length && outcome.keys.every((k) => unknown.includes(k));
7407
+ if (sameSet) {
7408
+ detail = `${isNotAField(outcome.keys)}, so every key it projected is null`;
7409
+ } else if (unknown.length > 0) {
7410
+ detail = `${projected}, because ${isNotAField(unknown)}`;
7411
+ } else {
7412
+ detail = withSoundness(`${projected} on all ${scope}`);
7413
+ }
7414
+ } else {
7415
+ lede = "returned nothing";
7416
+ if (unknown.length > 0) {
7417
+ detail = isNotAField(unknown);
7418
+ } else {
7419
+ const selection = refs.hasPredicate ? "no record matched" : "the expression resolved to no value";
7420
+ detail = withSoundness(`${selection} — it read ${scope}`);
7421
+ }
7422
+ }
7423
+ const fields = present.length > 0 ? ` Available fields: ${nameList(present)}.` : "";
7424
+ return `--output-filter ${JSON.stringify(filter)} ${lede}: ${detail}.${fields}`;
7425
+ }
7426
+ function appendWarning(existing, note) {
7427
+ return existing ? `${existing} ${note}` : note;
7428
+ }
7429
+ function applyFilter(data, filter, onWarning) {
7272
7430
  const codec = requireJmespath();
7273
7431
  let result;
7274
7432
  try {
@@ -7276,9 +7434,34 @@ function applyFilter(data, filter) {
7276
7434
  } catch (err) {
7277
7435
  throw new FilterEvaluationError(filter, err);
7278
7436
  }
7279
- if (result == null)
7437
+ const inputCount = countRecords(data);
7438
+ const warn = (outcome) => {
7439
+ if (inputCount === 0)
7440
+ return;
7441
+ const note = buildFilterWarning(filter, data, outcome);
7442
+ getOutputSink().writeErr(`[WARN] ${note}
7443
+ `);
7444
+ onWarning?.(note);
7445
+ };
7446
+ const warnIfAllNull = (records) => {
7447
+ const keys = alwaysNullKeys(records);
7448
+ if (keys.length > 0)
7449
+ warn({ kind: "null-values", keys });
7450
+ };
7451
+ if (result == null) {
7452
+ warn({ kind: "empty" });
7280
7453
  return [];
7454
+ }
7281
7455
  if (Array.isArray(result)) {
7456
+ if (result.length === 0) {
7457
+ warn({ kind: "empty" });
7458
+ } else if (result.every((entry) => entry === null)) {
7459
+ warn({ kind: "null-elements", count: result.length });
7460
+ } else if (result.every((entry) => Array.isArray(entry)) && carriesOnlyNulls(result)) {
7461
+ warn({ kind: "null-rows", count: result.length });
7462
+ } else {
7463
+ warnIfAllNull(result);
7464
+ }
7282
7465
  if (result.length > 0 && typeof result[0] !== "object") {
7283
7466
  const fieldMatch = filter.match(/\.(\w+)$/);
7284
7467
  const key = fieldMatch ? fieldMatch[1] : "Value";
@@ -7286,10 +7469,30 @@ function applyFilter(data, filter) {
7286
7469
  }
7287
7470
  return result;
7288
7471
  }
7289
- if (typeof result === "object")
7472
+ if (typeof result === "object") {
7473
+ warnIfAllNull([result]);
7290
7474
  return result;
7475
+ }
7291
7476
  return { Value: result };
7292
7477
  }
7478
+ function filterFailureData(envelope) {
7479
+ const filter = getOutputFilter();
7480
+ const data = envelope.Data;
7481
+ if (!filter || data == null)
7482
+ return;
7483
+ let note;
7484
+ const [filterError, filtered] = catchError2(() => applyFilter(data, filter, (n) => {
7485
+ note = n;
7486
+ }));
7487
+ if (filterError) {
7488
+ envelope.Warning = appendWarning(envelope.Warning, `--output-filter was not applied, so Data is shown in full: ${filterError.message}`);
7489
+ return;
7490
+ }
7491
+ envelope.Data = filtered;
7492
+ if (note) {
7493
+ envelope.Warning = appendWarning(envelope.Warning, note);
7494
+ }
7495
+ }
7293
7496
  function defaultErrorCodeForResult(result) {
7294
7497
  switch (result) {
7295
7498
  case RESULTS.AuthenticationError:
@@ -7372,8 +7575,14 @@ var OutputFormatter;
7372
7575
  }
7373
7576
  const filter = getOutputFilter();
7374
7577
  if (filter) {
7375
- const filtered = applyFilter(data.Data, filter);
7578
+ let note;
7579
+ const filtered = applyFilter(data.Data, filter, (n) => {
7580
+ note = n;
7581
+ });
7376
7582
  data.Data = normalize ? normalizeDataKeys(filtered, verbatim, subtrees && { refs: subtrees.refs, mode: "skip" }) : filtered;
7583
+ if (note) {
7584
+ data.Warning = appendWarning(data.Warning, note);
7585
+ }
7377
7586
  }
7378
7587
  logOutput(normalizeOutputKeys(data), getOutputFormat(), options?.tableRowStyle);
7379
7588
  }
@@ -7401,6 +7610,7 @@ var OutputFormatter;
7401
7610
  delete envelope.TelemetryErrorClass;
7402
7611
  delete envelope.TelemetryTerminalOutcome;
7403
7612
  delete envelope.TelemetryTerminalSignal;
7613
+ filterFailureData(envelope);
7404
7614
  if (!suppressTelemetry) {
7405
7615
  telemetry.trackEvent(CommonTelemetryEvents.Error, {
7406
7616
  result: data.Result,
@@ -7449,13 +7659,20 @@ var OutputFormatter;
7449
7659
  OutputFormatter.log = log;
7450
7660
  function formatToString(data) {
7451
7661
  const filter = getOutputFilter();
7662
+ const envelope = data;
7452
7663
  if ("Data" in data && data.Data != null) {
7453
7664
  data.Data = normalizeDataKeys(data.Data);
7454
7665
  if (filter) {
7455
- data.Data = normalizeDataKeys(applyFilter(data.Data, filter));
7666
+ let note;
7667
+ data.Data = normalizeDataKeys(applyFilter(data.Data, filter, (n) => {
7668
+ note = n;
7669
+ }));
7670
+ if (note) {
7671
+ envelope.Warning = appendWarning(envelope.Warning, note);
7672
+ }
7456
7673
  }
7457
7674
  }
7458
- const output = normalizeOutputKeys(data);
7675
+ const output = normalizeOutputKeys(envelope);
7459
7676
  const lines = [];
7460
7677
  const sink = getOutputSink();
7461
7678
  printOutput(output, getOutputFormat(), (msg) => {
@@ -10877,4 +11094,4 @@ export {
10877
11094
  registerCommands
10878
11095
  };
10879
11096
 
10880
- //# debugId=6E2EC35A8728EE7964756E2164756E21
11097
+ //# debugId=6EEE5B5474DB930C64756E2164756E21
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@uipath/authz-commands",
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": "Admin CLI commands for the UiPath Authorization 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": "641614a6f9817662baaf51dabdebbfa2a9334b1b"
29
+ "gitHead": "4ad3e17a66f2c7fb7fe1f0e3e04a5b6175a0a9a3"
30
30
  }