From 324c6cb1ccffa25e65abd264e43890b7e4bdbdb4 Mon Sep 17 00:00:00 2001 From: "JH.Lee" Date: Thu, 29 Jan 2026 12:39:29 +0900 Subject: [PATCH] feat(plugin-history-sync): add encode option to Route interface Add encode function to convert activity params to URL string params, complementing the existing decode function for the reverse operation. Co-Authored-By: Claude Opus 4.5 --- .changeset/purple-chefs-greet.md | 5 +++++ extensions/plugin-history-sync/src/RouteLike.ts | 5 +++++ .../src/makeTemplate.spec.ts | 17 +++++++++++++++++ .../plugin-history-sync/src/makeTemplate.ts | 11 +++++++---- 4 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 .changeset/purple-chefs-greet.md diff --git a/.changeset/purple-chefs-greet.md b/.changeset/purple-chefs-greet.md new file mode 100644 index 000000000..8be460e1e --- /dev/null +++ b/.changeset/purple-chefs-greet.md @@ -0,0 +1,5 @@ +--- +"@stackflow/plugin-history-sync": minor +--- + +Add encode option to Route interface for converting activity params to URL string params diff --git a/extensions/plugin-history-sync/src/RouteLike.ts b/extensions/plugin-history-sync/src/RouteLike.ts index 617908f83..aa6224a30 100644 --- a/extensions/plugin-history-sync/src/RouteLike.ts +++ b/extensions/plugin-history-sync/src/RouteLike.ts @@ -9,6 +9,11 @@ export type Route = { decode?: ( params: Record, ) => ComponentType extends ActivityComponentType ? U : {}; + encode?: ( + params: ComponentType extends ActivityComponentType + ? U + : Record, + ) => Record; defaultHistory?: ( params: Record, ) => HistoryEntry[] | DefaultHistoryDescriptor; diff --git a/extensions/plugin-history-sync/src/makeTemplate.spec.ts b/extensions/plugin-history-sync/src/makeTemplate.spec.ts index 1c6c23cfe..376e6922d 100644 --- a/extensions/plugin-history-sync/src/makeTemplate.spec.ts +++ b/extensions/plugin-history-sync/src/makeTemplate.spec.ts @@ -76,3 +76,20 @@ test("makeTemplate - parse with given decode function", () => { articleId: 1234, }); }); + +test("makeTemplate - fill with encode function using JSON.stringify for object params", () => { + const template = makeTemplate({ + path: "/search", + encode: (params) => ({ + filter: JSON.stringify(params.filter), + }), + }); + + expect( + template.fill({ + filter: { category: "tech", tags: ["javascript", "react"] }, + }), + ).toEqual( + "/search/?filter=%7B%22category%22%3A%22tech%22%2C%22tags%22%3A%5B%22javascript%22%2C%22react%22%5D%7D", + ); +}); diff --git a/extensions/plugin-history-sync/src/makeTemplate.ts b/extensions/plugin-history-sync/src/makeTemplate.ts index 0d57769ff..acd8618dc 100644 --- a/extensions/plugin-history-sync/src/makeTemplate.ts +++ b/extensions/plugin-history-sync/src/makeTemplate.ts @@ -46,7 +46,7 @@ export interface UrlPatternOptions { } export function makeTemplate( - { path, decode }: Route, + { path, decode, encode }: Route, urlPatternOptions?: UrlPatternOptions, ) { const pattern = new UrlPattern(`${path}(/)`, urlPatternOptions); @@ -58,11 +58,14 @@ export function makeTemplate( : (pattern as any).names.length; return { - fill(params: { [key: string]: string | undefined }) { - const pathname = pattern.stringify(params); + fill(params: { [key: string]: any }) { + const encodedParams: { [key: string]: string | undefined } = encode + ? encode(params as Parameters[0]) + : params; + const pathname = pattern.stringify(encodedParams); const pathParams = pattern.match(pathname); - const searchParamsMap = { ...params }; + const searchParamsMap = { ...encodedParams }; Object.keys(pathParams).forEach((key) => { delete searchParamsMap[key];