mirror of
https://github.com/morluto/rea
synced 2026-10-27 22:45:19 -04:00
fix(environment): align comparison collection identity
This commit is contained in:
@@ -625,7 +625,8 @@ refused for them, as the manifest is not.
|
||||
|
||||
Each `GET` tool whose template ends in a parameter is an item tool, and its
|
||||
type's `collection_template` is the template without that parameter; any other
|
||||
`GET` tool is a list tool of its own template. Empty segments are ignored, so a
|
||||
`GET` tool is a list tool of its own template. Interior empty segments remain
|
||||
meaningful: `/api/books` and `/api//books` name distinct collections. A single
|
||||
trailing slash names the same collection. An item tool proves its type's
|
||||
`id_field` when every initial response carries the requested path value in the
|
||||
same field of one entity object (`id_basis: "path-parameter"`). The object is
|
||||
|
||||
@@ -130,6 +130,26 @@ describe("matchProbeRequest", () => {
|
||||
expect(item?.args).toEqual({ id: "%31" });
|
||||
});
|
||||
|
||||
it("keeps trailing slashes significant when matching HTTP route templates", () => {
|
||||
const manifest = {
|
||||
...source.manifest,
|
||||
tools: source.manifest.tools.map((tool) => ({
|
||||
...tool,
|
||||
path_template: `${tool.path_template}/`,
|
||||
})),
|
||||
};
|
||||
const request = {
|
||||
method: "GET",
|
||||
path: "/api/books/7/",
|
||||
query: null,
|
||||
body: undefined,
|
||||
};
|
||||
expect(matchProbeRequest(manifest, request)?.args).toEqual({ id: "7" });
|
||||
expect(
|
||||
matchProbeRequest(manifest, { ...request, path: "/api/books/7" }),
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
it("keeps every occurrence of a repeated query value", () => {
|
||||
const item = matchProbeRequest(environmentServeSource().manifest, {
|
||||
method: "GET",
|
||||
@@ -176,6 +196,31 @@ describe("collections under different parents", () => {
|
||||
expect(map.env(110, "/api/orgs/2/users")).toBe(20);
|
||||
});
|
||||
|
||||
it("uses state collection identity for root and trailing-slash routes", () => {
|
||||
const trailing = {
|
||||
...nestedUsers,
|
||||
path_template: `${nestedUsers.path_template}/`,
|
||||
};
|
||||
const segments = ["api", "orgs", "%32", "users", "101", ""];
|
||||
expect(collectionScope(trailing, segments)).toBe("/api/orgs/2/users");
|
||||
expect(parameterScopes(trailing, segments)).toEqual(
|
||||
parameterScopes(nestedUsers, segments),
|
||||
);
|
||||
expect(
|
||||
collectionScope({ ...nestedUsers, path_template: "/", params: [] }),
|
||||
).toBe("/");
|
||||
expect(
|
||||
collectionScope({
|
||||
...nestedUsers,
|
||||
path_template: "/api//books/",
|
||||
params: [],
|
||||
}),
|
||||
).toBe("/api//books");
|
||||
expect(
|
||||
collectionScope(trailing, ["api", "orgs", "a%2Fb", "users", "101", ""]),
|
||||
).toBe("/api/orgs/a%2Fb/users");
|
||||
});
|
||||
|
||||
it("shares a child map when the same parent is spelled with one encoding", () => {
|
||||
const encoded = ["api", "orgs", "%32", "users", "101"];
|
||||
const plain = ["api", "orgs", "2", "users", "101"];
|
||||
@@ -465,6 +510,24 @@ const compareRows = (
|
||||
return report.value.probes[0]!;
|
||||
};
|
||||
|
||||
it("learns ids from trailing-slash lists in the collection their item calls name", () => {
|
||||
const item = (id: number, name: string) => ({ id, name });
|
||||
const probe = compareRows(
|
||||
[
|
||||
["GET", "/api/books", [item(1, "Book")]],
|
||||
["GET", "/api/books/1", item(1, "Book")],
|
||||
["GET", "/api/authors/", [item(2, "Ann")]],
|
||||
["GET", "/api/authors/2/", item(2, "Ann")],
|
||||
],
|
||||
[
|
||||
["GET", "/api/books", [item(101, "Book")]],
|
||||
["GET", "/api/authors/", [item(101, "Ann")]],
|
||||
["GET", "/api/authors/101/", item(101, "Ann")],
|
||||
],
|
||||
);
|
||||
expect(probe.results.map((step) => step.equal)).toEqual([true, true, true]);
|
||||
});
|
||||
|
||||
describe("ids the comparison used to misread", () => {
|
||||
it.each([
|
||||
["", "", true],
|
||||
|
||||
@@ -59,9 +59,7 @@ const collectionAt = (
|
||||
segments?: readonly string[],
|
||||
): string => {
|
||||
const params = new Set(tool.params.map((param) => param.index));
|
||||
return `/${tool.path_template
|
||||
.slice(1)
|
||||
.split("/")
|
||||
return `/${segmentsOf(tool.path_template)
|
||||
.slice(0, end)
|
||||
.map((segment, index) => {
|
||||
if (!params.has(index)) return segment;
|
||||
@@ -78,7 +76,7 @@ export const collectionScope = (
|
||||
tool: EnvironmentManifestTool,
|
||||
segments?: readonly string[],
|
||||
): string => {
|
||||
const length = tool.path_template.slice(1).split("/").length;
|
||||
const length = segmentsOf(tool.path_template).length;
|
||||
return collectionAt(
|
||||
tool,
|
||||
tool.params.some((param) => param.index === length - 1)
|
||||
|
||||
Reference in New Issue
Block a user