Skip to content

Commit 5a18069

Browse files
authored
fix(util-endpoints): handle negative index in getAttr (#1956)
1 parent cb76b1f commit 5a18069

File tree

4 files changed

+69
-3
lines changed

4 files changed

+69
-3
lines changed

.changeset/eight-squids-visit.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@smithy/util-endpoints": patch
3+
---
4+
5+
fix getAttr function when using negative index

packages/util-endpoints/src/lib/getAttr.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ describe(getAttr.name, () => {
3636
it.each([
3737
[mockArr[0], "[0]", ["0"]],
3838
[mockArr[1], "[1]", ["1"]],
39+
[mockArr[1], "[-1]", ["-1"]],
40+
[mockArr[0], "[-2]", ["-2"]],
3941
])("returns '%s' for '%s'", (output, input, pathList) => {
4042
testSuccess(mockArr, input, output, pathList);
4143
});

packages/util-endpoints/src/lib/getAttr.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ export const getAttr = (value: GetAttrValue, path: string): GetAttrValue =>
1111
if (typeof acc !== "object") {
1212
throw new EndpointError(`Index '${index}' in '${path}' not found in '${JSON.stringify(value)}'`);
1313
} else if (Array.isArray(acc)) {
14-
return acc[parseInt(index)];
14+
const i = parseInt(index);
15+
return acc[i < 0 ? acc.length + i : i];
1516
}
1617
return acc[index];
1718
}, value);

packages/util-endpoints/src/resolveEndpoint.integ.spec.ts

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
import { existsSync, readdirSync } from "fs";
2-
import { resolve } from "path";
1+
import { existsSync, readdirSync } from "node:fs";
2+
import { resolve } from "node:path";
33
import { describe, expect, test as it } from "vitest";
44

5+
import { BinaryDecisionDiagram } from "./bdd/BinaryDecisionDiagram";
6+
import { decideEndpoint } from "./decideEndpoint";
57
import { resolveEndpoint } from "./resolveEndpoint";
68
import { EndpointError } from "./types";
79

@@ -46,3 +48,59 @@ describe(resolveEndpoint.name, () => {
4648
}
4749
});
4850
});
51+
52+
describe(decideEndpoint.name, () => {
53+
describe("split, ite, and getAttr with negative index", () => {
54+
const r = 100_000_000;
55+
56+
const conditions = [
57+
["split", [{ ref: "Splittable" }, ".", 0], "parts"],
58+
["getAttr", [{ ref: "parts" }, "[-2]"], "tld"],
59+
["stringEquals", [{ ref: "tld" }, "com"], "isCom"],
60+
];
61+
62+
const results = [[{ fn: "ite", argv: [{ ref: "isCom" }, "https://api.___.com", "https://api.___.net"] }, {}, {}]];
63+
64+
const nodes = new Int32Array([
65+
0,
66+
0,
67+
0,
68+
// (2, start) - split Splittable by "." with unlimited parts and proceed to node 3.
69+
0,
70+
3,
71+
-1,
72+
// (3) - getAttr [-2] and assign to tld, proceed to node 4.
73+
1,
74+
4,
75+
-1,
76+
// (4) - compare tld to "com" as isCom and proceed to terminal 0.
77+
2,
78+
r + 0,
79+
r + 0,
80+
]);
81+
82+
const bdd = BinaryDecisionDiagram.from(nodes, 2, conditions, results);
83+
84+
it("should resolve endpoint using split + getAttr[-1] + ite", () => {
85+
const endpoint = decideEndpoint(bdd, {
86+
endpointParams: { Splittable: "___.com.___" },
87+
});
88+
expect(endpoint).toEqual({
89+
url: new URL("https://api.___.com"),
90+
properties: {},
91+
headers: {},
92+
});
93+
});
94+
95+
it("should pick alternate URL when getAttr[-1] yields non-com TLD", () => {
96+
const endpoint = decideEndpoint(bdd, {
97+
endpointParams: { Splittable: "___.org.___" },
98+
});
99+
expect(endpoint).toEqual({
100+
url: new URL("https://api.___.net"),
101+
properties: {},
102+
headers: {},
103+
});
104+
});
105+
});
106+
});

0 commit comments

Comments
 (0)