@uipath/common 1.203.0-preview.235 → 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.
- package/dist/formatter.d.ts +15 -0
- package/dist/index.js +225 -7
- package/package.json +2 -2
package/dist/formatter.d.ts
CHANGED
|
@@ -103,6 +103,13 @@ export declare class SuccessOutput {
|
|
|
103
103
|
Data: DataRecord | DataRecord[];
|
|
104
104
|
Pagination?: Pagination;
|
|
105
105
|
Instructions?: string;
|
|
106
|
+
/**
|
|
107
|
+
* A note for the caller that does not change the `Data` contract — e.g.
|
|
108
|
+
* why `--output-filter` returned nothing. Declared here because agents
|
|
109
|
+
* read the envelope and nothing else; `emitList` and the filter paths
|
|
110
|
+
* both set it.
|
|
111
|
+
*/
|
|
112
|
+
Warning?: string;
|
|
106
113
|
Log?: string;
|
|
107
114
|
constructor(code: string, data: DataRecord | DataRecord[]);
|
|
108
115
|
}
|
|
@@ -317,6 +324,9 @@ export declare namespace OutputFormatter {
|
|
|
317
324
|
*
|
|
318
325
|
* **Side-effect:** records the exit code through {@link setExitCode}, so a
|
|
319
326
|
* printed failure exits non-zero even when no `context.exit()` follows.
|
|
327
|
+
*
|
|
328
|
+
* `--output-filter` projects `Data` here as it does in {@link success};
|
|
329
|
+
* see {@link filterFailureData}.
|
|
320
330
|
*/
|
|
321
331
|
function error(data: FailureOutput): void;
|
|
322
332
|
/** Emit a list result. Always uses `Result: "Success"` — an empty list is not an error. */
|
|
@@ -333,6 +343,11 @@ export declare namespace OutputFormatter {
|
|
|
333
343
|
/**
|
|
334
344
|
* Format structured output to a string without writing to console.
|
|
335
345
|
* Useful when the caller needs the formatted string (e.g., Commander's formatHelp).
|
|
346
|
+
*
|
|
347
|
+
* This is the structured-help path, so it carries the filter note on the
|
|
348
|
+
* envelope like {@link success} does: a mistyped filter against `--help`
|
|
349
|
+
* is the same ambiguity as one against a list, and stdout is the only
|
|
350
|
+
* channel its reader has.
|
|
336
351
|
*/
|
|
337
352
|
function formatToString(data: StructuredOutput): string;
|
|
338
353
|
}
|
package/dist/index.js
CHANGED
|
@@ -10922,6 +10922,7 @@ class SuccessOutput {
|
|
|
10922
10922
|
Data;
|
|
10923
10923
|
Pagination;
|
|
10924
10924
|
Instructions;
|
|
10925
|
+
Warning;
|
|
10925
10926
|
Log;
|
|
10926
10927
|
constructor(code, data) {
|
|
10927
10928
|
this.Code = code;
|
|
@@ -11563,7 +11564,165 @@ class ConfigurationError extends Error {
|
|
|
11563
11564
|
function isConfigurationError(error) {
|
|
11564
11565
|
return typeof error === "object" && error !== null && "__brand" in error && error.__brand === "ConfigurationError";
|
|
11565
11566
|
}
|
|
11566
|
-
function
|
|
11567
|
+
function countRecords(data) {
|
|
11568
|
+
if (Array.isArray(data))
|
|
11569
|
+
return data.length;
|
|
11570
|
+
return data == null ? 0 : 1;
|
|
11571
|
+
}
|
|
11572
|
+
function availableFields(data) {
|
|
11573
|
+
const records = Array.isArray(data) ? data : [data];
|
|
11574
|
+
const keys = new Set;
|
|
11575
|
+
for (const record of records) {
|
|
11576
|
+
if (record && typeof record === "object" && !Array.isArray(record)) {
|
|
11577
|
+
for (const key of Object.keys(record))
|
|
11578
|
+
keys.add(key);
|
|
11579
|
+
}
|
|
11580
|
+
}
|
|
11581
|
+
return [...keys];
|
|
11582
|
+
}
|
|
11583
|
+
function decodeQuotedIdentifier(whole, inner) {
|
|
11584
|
+
const [error, decoded] = catchError(() => JSON.parse(whole));
|
|
11585
|
+
if (!error && typeof decoded === "string")
|
|
11586
|
+
return decoded;
|
|
11587
|
+
return inner.replace(/\\(.)/g, "$1");
|
|
11588
|
+
}
|
|
11589
|
+
function referencedFields(filter) {
|
|
11590
|
+
const top = new Set;
|
|
11591
|
+
const nested = new Set;
|
|
11592
|
+
const withoutValueLiterals = filter.replace(/'(?:\\.|[^'\\])*'/g, " ").replace(/`(?:\\.|[^`\\])*`/g, " ");
|
|
11593
|
+
const isPathTail = (text, index) => text[index - 1] === "." && /[A-Za-z0-9_"]/.test(text[index - 2] ?? "");
|
|
11594
|
+
const quoted = [];
|
|
11595
|
+
const withoutLiterals = withoutValueLiterals.replace(/"((?:\\.|[^"\\])*)"/g, (whole, name, index) => {
|
|
11596
|
+
const isAlias = /^\s*:/.test(withoutValueLiterals.slice(index + whole.length));
|
|
11597
|
+
if (!isAlias) {
|
|
11598
|
+
quoted.push({
|
|
11599
|
+
name: decodeQuotedIdentifier(whole, name),
|
|
11600
|
+
index,
|
|
11601
|
+
tail: isPathTail(withoutValueLiterals, index)
|
|
11602
|
+
});
|
|
11603
|
+
}
|
|
11604
|
+
return `"${" ".repeat(whole.length - 2)}"`;
|
|
11605
|
+
});
|
|
11606
|
+
const descent = /[A-Za-z0-9_"]\s*[.[]/.exec(withoutLiterals);
|
|
11607
|
+
const rootEnd = descent ? descent.index + 1 : Number.POSITIVE_INFINITY;
|
|
11608
|
+
const place = (name, index, tail) => {
|
|
11609
|
+
if (tail || index >= rootEnd)
|
|
11610
|
+
nested.add(name);
|
|
11611
|
+
else
|
|
11612
|
+
top.add(name);
|
|
11613
|
+
};
|
|
11614
|
+
for (const entry of quoted)
|
|
11615
|
+
place(entry.name, entry.index, entry.tail);
|
|
11616
|
+
const identifiers = withoutLiterals.matchAll(/([A-Za-z_][A-Za-z0-9_]*)(\s*[:(])?/g);
|
|
11617
|
+
const reserved = new Set(["true", "false", "null", "and", "or", "not"]);
|
|
11618
|
+
for (const match of identifiers) {
|
|
11619
|
+
const [, name, trailing] = match;
|
|
11620
|
+
if (trailing || reserved.has(name))
|
|
11621
|
+
continue;
|
|
11622
|
+
place(name, match.index, isPathTail(withoutLiterals, match.index));
|
|
11623
|
+
}
|
|
11624
|
+
return {
|
|
11625
|
+
top: [...top],
|
|
11626
|
+
nested: [...nested].filter((name) => !top.has(name)),
|
|
11627
|
+
hasPredicate: /\[\s*\?/.test(withoutValueLiterals)
|
|
11628
|
+
};
|
|
11629
|
+
}
|
|
11630
|
+
function appearsBelowTopLevel(data, name) {
|
|
11631
|
+
let budget = 2000;
|
|
11632
|
+
const visit = (value, depth) => {
|
|
11633
|
+
if (budget-- <= 0 || depth > 4)
|
|
11634
|
+
return false;
|
|
11635
|
+
if (value === null || typeof value !== "object")
|
|
11636
|
+
return false;
|
|
11637
|
+
if (Array.isArray(value))
|
|
11638
|
+
return value.some((entry) => visit(entry, depth));
|
|
11639
|
+
const record = value;
|
|
11640
|
+
if (depth > 0 && Object.hasOwn(record, name))
|
|
11641
|
+
return true;
|
|
11642
|
+
return Object.values(record).some((entry) => visit(entry, depth + 1));
|
|
11643
|
+
};
|
|
11644
|
+
return visit(data, 0);
|
|
11645
|
+
}
|
|
11646
|
+
function alwaysNullKeys(records) {
|
|
11647
|
+
const objects = records.filter((r) => r != null && typeof r === "object" && !Array.isArray(r));
|
|
11648
|
+
if (objects.length === 0 || objects.length !== records.length)
|
|
11649
|
+
return [];
|
|
11650
|
+
const keys = [...new Set(objects.flatMap((o) => Object.keys(o)))];
|
|
11651
|
+
if (keys.length === 0)
|
|
11652
|
+
return [];
|
|
11653
|
+
const nullKeys = keys.filter((key) => objects.every((record) => record[key] === null));
|
|
11654
|
+
return nullKeys.length === keys.length ? nullKeys : [];
|
|
11655
|
+
}
|
|
11656
|
+
function carriesOnlyNulls(value) {
|
|
11657
|
+
if (value === null)
|
|
11658
|
+
return true;
|
|
11659
|
+
if (Array.isArray(value)) {
|
|
11660
|
+
return value.length > 0 && value.every(carriesOnlyNulls);
|
|
11661
|
+
}
|
|
11662
|
+
if (typeof value === "object" && value !== undefined) {
|
|
11663
|
+
const values = Object.values(value);
|
|
11664
|
+
return values.length > 0 && values.every(carriesOnlyNulls);
|
|
11665
|
+
}
|
|
11666
|
+
return false;
|
|
11667
|
+
}
|
|
11668
|
+
function nameList(names, cap2 = 12) {
|
|
11669
|
+
const shown = names.slice(0, cap2).map((n) => `\`${n}\``);
|
|
11670
|
+
const rest = names.length - shown.length;
|
|
11671
|
+
return shown.join(", ") + (rest > 0 ? `, and ${rest} more` : "");
|
|
11672
|
+
}
|
|
11673
|
+
function buildFilterWarning(filter, data, outcome) {
|
|
11674
|
+
const present = availableFields(data);
|
|
11675
|
+
const refs = referencedFields(filter);
|
|
11676
|
+
const unknown = refs.top.filter((name) => !present.includes(name) && !appearsBelowTopLevel(data, name));
|
|
11677
|
+
const unchecked = refs.nested.filter((name) => !present.includes(name));
|
|
11678
|
+
const count = countRecords(data);
|
|
11679
|
+
const scope = `${count} record(s)`;
|
|
11680
|
+
const isNotAField = (names) => `${nameList(names)} ${names.length === 1 ? "is not a field" : "are not fields"} on the ${scope} it read`;
|
|
11681
|
+
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" : "";
|
|
11682
|
+
const withSoundness = (base) => soundness ? `${base}, and ${soundness}` : base;
|
|
11683
|
+
let detail;
|
|
11684
|
+
let lede;
|
|
11685
|
+
if (outcome.kind === "null-elements") {
|
|
11686
|
+
lede = "returned only null values";
|
|
11687
|
+
const projected = `all ${outcome.count} of the elements it projected are null`;
|
|
11688
|
+
if (unknown.length > 0) {
|
|
11689
|
+
detail = `${projected}, because ${isNotAField(unknown)}`;
|
|
11690
|
+
} else if (unchecked.length > 0) {
|
|
11691
|
+
detail = withSoundness(projected);
|
|
11692
|
+
} else {
|
|
11693
|
+
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`;
|
|
11694
|
+
}
|
|
11695
|
+
} else if (outcome.kind === "null-rows") {
|
|
11696
|
+
lede = "returned only null values";
|
|
11697
|
+
const projected = `every value it projected is null on all ${outcome.count} row(s)`;
|
|
11698
|
+
detail = unknown.length > 0 ? `${projected}, because ${isNotAField(unknown)}` : withSoundness(projected);
|
|
11699
|
+
} else if (outcome.kind === "null-values") {
|
|
11700
|
+
lede = "returned only null values";
|
|
11701
|
+
const projected = `every key it projected (${nameList(outcome.keys)}) is null`;
|
|
11702
|
+
const sameSet = unknown.length === outcome.keys.length && outcome.keys.every((k) => unknown.includes(k));
|
|
11703
|
+
if (sameSet) {
|
|
11704
|
+
detail = `${isNotAField(outcome.keys)}, so every key it projected is null`;
|
|
11705
|
+
} else if (unknown.length > 0) {
|
|
11706
|
+
detail = `${projected}, because ${isNotAField(unknown)}`;
|
|
11707
|
+
} else {
|
|
11708
|
+
detail = withSoundness(`${projected} on all ${scope}`);
|
|
11709
|
+
}
|
|
11710
|
+
} else {
|
|
11711
|
+
lede = "returned nothing";
|
|
11712
|
+
if (unknown.length > 0) {
|
|
11713
|
+
detail = isNotAField(unknown);
|
|
11714
|
+
} else {
|
|
11715
|
+
const selection = refs.hasPredicate ? "no record matched" : "the expression resolved to no value";
|
|
11716
|
+
detail = withSoundness(`${selection} — it read ${scope}`);
|
|
11717
|
+
}
|
|
11718
|
+
}
|
|
11719
|
+
const fields = present.length > 0 ? ` Available fields: ${nameList(present)}.` : "";
|
|
11720
|
+
return `--output-filter ${JSON.stringify(filter)} ${lede}: ${detail}.${fields}`;
|
|
11721
|
+
}
|
|
11722
|
+
function appendWarning(existing, note) {
|
|
11723
|
+
return existing ? `${existing} ${note}` : note;
|
|
11724
|
+
}
|
|
11725
|
+
function applyFilter(data, filter, onWarning) {
|
|
11567
11726
|
const codec = requireJmespath();
|
|
11568
11727
|
let result;
|
|
11569
11728
|
try {
|
|
@@ -11571,9 +11730,34 @@ function applyFilter(data, filter) {
|
|
|
11571
11730
|
} catch (err) {
|
|
11572
11731
|
throw new FilterEvaluationError(filter, err);
|
|
11573
11732
|
}
|
|
11574
|
-
|
|
11733
|
+
const inputCount = countRecords(data);
|
|
11734
|
+
const warn = (outcome) => {
|
|
11735
|
+
if (inputCount === 0)
|
|
11736
|
+
return;
|
|
11737
|
+
const note = buildFilterWarning(filter, data, outcome);
|
|
11738
|
+
getOutputSink().writeErr(`[WARN] ${note}
|
|
11739
|
+
`);
|
|
11740
|
+
onWarning?.(note);
|
|
11741
|
+
};
|
|
11742
|
+
const warnIfAllNull = (records) => {
|
|
11743
|
+
const keys = alwaysNullKeys(records);
|
|
11744
|
+
if (keys.length > 0)
|
|
11745
|
+
warn({ kind: "null-values", keys });
|
|
11746
|
+
};
|
|
11747
|
+
if (result == null) {
|
|
11748
|
+
warn({ kind: "empty" });
|
|
11575
11749
|
return [];
|
|
11750
|
+
}
|
|
11576
11751
|
if (Array.isArray(result)) {
|
|
11752
|
+
if (result.length === 0) {
|
|
11753
|
+
warn({ kind: "empty" });
|
|
11754
|
+
} else if (result.every((entry) => entry === null)) {
|
|
11755
|
+
warn({ kind: "null-elements", count: result.length });
|
|
11756
|
+
} else if (result.every((entry) => Array.isArray(entry)) && carriesOnlyNulls(result)) {
|
|
11757
|
+
warn({ kind: "null-rows", count: result.length });
|
|
11758
|
+
} else {
|
|
11759
|
+
warnIfAllNull(result);
|
|
11760
|
+
}
|
|
11577
11761
|
if (result.length > 0 && typeof result[0] !== "object") {
|
|
11578
11762
|
const fieldMatch = filter.match(/\.(\w+)$/);
|
|
11579
11763
|
const key = fieldMatch ? fieldMatch[1] : "Value";
|
|
@@ -11581,10 +11765,30 @@ function applyFilter(data, filter) {
|
|
|
11581
11765
|
}
|
|
11582
11766
|
return result;
|
|
11583
11767
|
}
|
|
11584
|
-
if (typeof result === "object")
|
|
11768
|
+
if (typeof result === "object") {
|
|
11769
|
+
warnIfAllNull([result]);
|
|
11585
11770
|
return result;
|
|
11771
|
+
}
|
|
11586
11772
|
return { Value: result };
|
|
11587
11773
|
}
|
|
11774
|
+
function filterFailureData(envelope) {
|
|
11775
|
+
const filter = getOutputFilter();
|
|
11776
|
+
const data = envelope.Data;
|
|
11777
|
+
if (!filter || data == null)
|
|
11778
|
+
return;
|
|
11779
|
+
let note;
|
|
11780
|
+
const [filterError, filtered] = catchError(() => applyFilter(data, filter, (n) => {
|
|
11781
|
+
note = n;
|
|
11782
|
+
}));
|
|
11783
|
+
if (filterError) {
|
|
11784
|
+
envelope.Warning = appendWarning(envelope.Warning, `--output-filter was not applied, so Data is shown in full: ${filterError.message}`);
|
|
11785
|
+
return;
|
|
11786
|
+
}
|
|
11787
|
+
envelope.Data = filtered;
|
|
11788
|
+
if (note) {
|
|
11789
|
+
envelope.Warning = appendWarning(envelope.Warning, note);
|
|
11790
|
+
}
|
|
11791
|
+
}
|
|
11588
11792
|
function defaultErrorCodeForResult(result) {
|
|
11589
11793
|
switch (result) {
|
|
11590
11794
|
case RESULTS.AuthenticationError:
|
|
@@ -11667,8 +11871,14 @@ var OutputFormatter;
|
|
|
11667
11871
|
}
|
|
11668
11872
|
const filter = getOutputFilter();
|
|
11669
11873
|
if (filter) {
|
|
11670
|
-
|
|
11874
|
+
let note;
|
|
11875
|
+
const filtered = applyFilter(data.Data, filter, (n) => {
|
|
11876
|
+
note = n;
|
|
11877
|
+
});
|
|
11671
11878
|
data.Data = normalize ? normalizeDataKeys(filtered, verbatim, subtrees && { refs: subtrees.refs, mode: "skip" }) : filtered;
|
|
11879
|
+
if (note) {
|
|
11880
|
+
data.Warning = appendWarning(data.Warning, note);
|
|
11881
|
+
}
|
|
11672
11882
|
}
|
|
11673
11883
|
logOutput(normalizeOutputKeys(data), getOutputFormat(), options?.tableRowStyle);
|
|
11674
11884
|
}
|
|
@@ -11696,6 +11906,7 @@ var OutputFormatter;
|
|
|
11696
11906
|
delete envelope.TelemetryErrorClass;
|
|
11697
11907
|
delete envelope.TelemetryTerminalOutcome;
|
|
11698
11908
|
delete envelope.TelemetryTerminalSignal;
|
|
11909
|
+
filterFailureData(envelope);
|
|
11699
11910
|
if (!suppressTelemetry) {
|
|
11700
11911
|
telemetry.trackEvent(CommonTelemetryEvents.Error, {
|
|
11701
11912
|
result: data.Result,
|
|
@@ -11744,13 +11955,20 @@ var OutputFormatter;
|
|
|
11744
11955
|
OutputFormatter.log = log;
|
|
11745
11956
|
function formatToString(data) {
|
|
11746
11957
|
const filter = getOutputFilter();
|
|
11958
|
+
const envelope = data;
|
|
11747
11959
|
if ("Data" in data && data.Data != null) {
|
|
11748
11960
|
data.Data = normalizeDataKeys(data.Data);
|
|
11749
11961
|
if (filter) {
|
|
11750
|
-
|
|
11962
|
+
let note;
|
|
11963
|
+
data.Data = normalizeDataKeys(applyFilter(data.Data, filter, (n) => {
|
|
11964
|
+
note = n;
|
|
11965
|
+
}));
|
|
11966
|
+
if (note) {
|
|
11967
|
+
envelope.Warning = appendWarning(envelope.Warning, note);
|
|
11968
|
+
}
|
|
11751
11969
|
}
|
|
11752
11970
|
}
|
|
11753
|
-
const output = normalizeOutputKeys(
|
|
11971
|
+
const output = normalizeOutputKeys(envelope);
|
|
11754
11972
|
const lines = [];
|
|
11755
11973
|
const sink = getOutputSink();
|
|
11756
11974
|
printOutput(output, getOutputFormat(), (msg) => {
|
|
@@ -14032,4 +14250,4 @@ export {
|
|
|
14032
14250
|
writeTelemetrySpoolFile
|
|
14033
14251
|
};
|
|
14034
14252
|
|
|
14035
|
-
//# debugId=
|
|
14253
|
+
//# debugId=C7396FAC1D7B6F8064756E2164756E21
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@uipath/common",
|
|
3
3
|
"author": "UiPath",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
5
|
-
"version": "1.203.0-preview.
|
|
5
|
+
"version": "1.203.0-preview.237",
|
|
6
6
|
"description": "Common infrastructure needed by uip tools.",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -80,5 +80,5 @@
|
|
|
80
80
|
"mihaigirleanu",
|
|
81
81
|
"vlad-uipath"
|
|
82
82
|
],
|
|
83
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "4ad3e17a66f2c7fb7fe1f0e3e04a5b6175a0a9a3"
|
|
84
84
|
}
|