Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contributors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,5 @@
- fz6m
- TkDodo
- infoxicator
- KostiantynPopovych
- CanRau
29 changes: 28 additions & 1 deletion packages/react-router/__tests__/generatePath-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe("generatePath", () => {
"/courses/routing/grades"
);
expect(generatePath("*", { "*": "routing/grades" })).toBe(
"/routing/grades"
"routing/grades"
);
});
});
Expand All @@ -42,4 +42,31 @@ describe("generatePath", () => {
expect(generatePath("/courses/*", {})).toBe("/courses");
});
});

it("throws only on on missing named parameters, but not missing splat params", () => {
expect(() => generatePath(":foo")).toThrow();
expect(() => generatePath("/:foo")).toThrow();
expect(() => generatePath("*")).not.toThrow();
expect(() => generatePath("/*")).not.toThrow();
});

it("only interpolates and does not add slashes", () => {
expect(generatePath("*")).toBe("");
expect(generatePath("/*")).toBe("/");

expect(generatePath("foo*")).toBe("foo");
expect(generatePath("/foo*")).toBe("/foo");

expect(generatePath(":foo", { foo: "bar" })).toBe("bar");
expect(generatePath("/:foo", { foo: "bar" })).toBe("/bar");

expect(generatePath("*", { "*": "bar" })).toBe("bar");
expect(generatePath("/*", { "*": "bar" })).toBe("/bar");

expect(generatePath("foo:bar", { bar: "baz" })).toBe("foobaz");
expect(generatePath("/foo:bar", { bar: "baz" })).toBe("/foobaz");

expect(generatePath("foo*", { "*": "bar" })).toBe("foobar");
expect(generatePath("/foo*", { "*": "bar" })).toBe("/foobar");
});
});
11 changes: 9 additions & 2 deletions packages/router/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -485,10 +485,17 @@ export function generatePath<Path extends string>(
invariant(params[key] != null, `Missing ":${key}" param`);
return params[key]!;
})
.replace(/\/*\*$/, (_) => {
.replace(/(\/?)\*/, (_, prefix, __, str) => {
const star = "*" as PathParam<Path>;

return params[star] == null ? "" : params[star].replace(/^\/*/, "/");
if (params[star] == null) {
// If no splat was provided, trim the trailing slash _unless_ it's
// the entire path
return str === "/*" ? "/" : "";
}

// Apply the splat
return `${prefix}${params[star]}`;
});
}

Expand Down