diff --git a/code/lib/manager-api/package.json b/code/lib/manager-api/package.json index 49270d11882d..5868ec58a2a9 100644 --- a/code/lib/manager-api/package.json +++ b/code/lib/manager-api/package.json @@ -62,7 +62,6 @@ }, "devDependencies": { "@types/lodash": "^4.14.167", - "@types/qs": "^6", "@types/semver": "^7.3.4", "flush-promises": "^1.0.2", "react": "^18.2.0", diff --git a/code/lib/preview-api/package.json b/code/lib/preview-api/package.json index 75415839d0d2..9655ed05df26 100644 --- a/code/lib/preview-api/package.json +++ b/code/lib/preview-api/package.json @@ -50,11 +50,10 @@ "@storybook/csf": "^0.1.8", "@storybook/global": "^5.0.0", "@storybook/types": "workspace:*", - "@types/qs": "^6.9.5", "dequal": "^2.0.2", "lodash": "^4.17.21", "memoizerific": "^1.11.3", - "qs": "^6.10.0", + "picoquery": "^2.0.0", "tiny-invariant": "^1.3.1", "ts-dedent": "^2.0.0", "util-deprecate": "^1.0.2" diff --git a/code/lib/preview-api/src/modules/preview-web/SelectionStore.ts b/code/lib/preview-api/src/modules/preview-web/SelectionStore.ts index 4faa9cb1089f..4b11ced29088 100644 --- a/code/lib/preview-api/src/modules/preview-web/SelectionStore.ts +++ b/code/lib/preview-api/src/modules/preview-web/SelectionStore.ts @@ -20,5 +20,5 @@ export interface SelectionStore { setSelection(selection: Selection): void; - setQueryParams(queryParams: qs.ParsedQs): void; + setQueryParams(queryParams: Record): void; } diff --git a/code/lib/preview-api/src/modules/preview-web/UrlStore.ts b/code/lib/preview-api/src/modules/preview-web/UrlStore.ts index b7890cc3687a..8a6dc78943aa 100644 --- a/code/lib/preview-api/src/modules/preview-web/UrlStore.ts +++ b/code/lib/preview-api/src/modules/preview-web/UrlStore.ts @@ -1,5 +1,5 @@ import { global } from '@storybook/global'; -import qs from 'qs'; +import * as pq from 'picoquery'; import type { ViewMode } from '@storybook/types'; import { parseArgsParam } from './parseArgsParam'; @@ -20,19 +20,17 @@ const getQueryString = ({ extraParams, }: { selection?: Selection; - extraParams?: qs.ParsedQs; + extraParams?: Record; }) => { const search = typeof document !== 'undefined' ? document.location.search : ''; - const { path, selectedKind, selectedStory, ...rest } = qs.parse(search, { - ignoreQueryPrefix: true, - }); - return qs.stringify( - { + const { path, selectedKind, selectedStory, ...rest } = pq.parse(search); + return ( + '?' + + pq.stringify({ ...rest, ...extraParams, ...(selection && { id: selection.storyId, viewMode: selection.viewMode }), - }, - { encode: false, addQueryPrefix: true } + }) ); }; @@ -45,10 +43,10 @@ export const setPath = (selection?: Selection) => { }; type ValueOf = T[keyof T]; -const isObject = (val: Record) => +const isObject = (val: Record): val is object => val != null && typeof val === 'object' && Array.isArray(val) === false; -const getFirstString = (v: ValueOf): string | void => { +const getFirstString = (v: ValueOf>): string | void => { if (v === undefined) { return undefined; } @@ -58,15 +56,17 @@ const getFirstString = (v: ValueOf): string | void => { if (Array.isArray(v)) { return getFirstString(v[0]); } - if (isObject(v)) { - return getFirstString(Object.values(v).filter(Boolean) as string[]); + if (isObject(v as Record)) { + return getFirstString( + Object.values(v as Record).filter(Boolean) as string[] + ); } return undefined; }; export const getSelectionSpecifierFromPath: () => SelectionSpecifier | null = () => { if (typeof document !== 'undefined') { - const query = qs.parse(document.location.search, { ignoreQueryPrefix: true }); + const query = pq.parse(document.location.search); const args = typeof query.args === 'string' ? parseArgsParam(query.args) : undefined; const globals = typeof query.globals === 'string' ? parseArgsParam(query.globals) : undefined; @@ -100,7 +100,7 @@ export class UrlStore implements SelectionStore { setPath(this.selection); } - setQueryParams(queryParams: qs.ParsedQs) { + setQueryParams(queryParams: Record) { const query = getQueryString({ extraParams: queryParams }); const { hash = '' } = document.location; history.replaceState({}, '', `${document.location.pathname}${query}${hash}`); diff --git a/code/lib/router/package.json b/code/lib/router/package.json index c9a4b1bf2888..93fedc2b0737 100644 --- a/code/lib/router/package.json +++ b/code/lib/router/package.json @@ -51,7 +51,7 @@ "dependencies": { "@storybook/client-logger": "workspace:*", "memoizerific": "^1.11.3", - "qs": "^6.10.0" + "picoquery": "^2.0.0" }, "devDependencies": { "@storybook/global": "^5.0.0", diff --git a/code/ui/manager/package.json b/code/ui/manager/package.json index a976dab95595..96a8bc844cf8 100644 --- a/code/ui/manager/package.json +++ b/code/ui/manager/package.json @@ -97,8 +97,8 @@ "lodash": "^4.17.21", "markdown-to-jsx": "^7.4.5", "memoizerific": "^1.11.3", + "picoquery": "^2.0.0", "polished": "^4.2.2", - "qs": "^6.10.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-draggable": "^4.4.5", diff --git a/code/ui/manager/src/components/preview/utils/stringifyQueryParams.tsx b/code/ui/manager/src/components/preview/utils/stringifyQueryParams.tsx index 4175503808bb..08fb52a4fa16 100644 --- a/code/ui/manager/src/components/preview/utils/stringifyQueryParams.tsx +++ b/code/ui/manager/src/components/preview/utils/stringifyQueryParams.tsx @@ -1,4 +1,4 @@ -import qs from 'qs'; +import { stringify } from 'picoquery'; export const stringifyQueryParams = (queryParams: Record) => - qs.stringify(queryParams, { addQueryPrefix: true, encode: false }).replace(/^\?/, '&'); + '?' + stringify(queryParams); diff --git a/code/yarn.lock b/code/yarn.lock index da5523a1023d..8ad3e1b4bbcc 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6232,7 +6232,6 @@ __metadata: "@storybook/theming": "workspace:*" "@storybook/types": "workspace:*" "@types/lodash": "npm:^4.14.167" - "@types/qs": "npm:^6" "@types/semver": "npm:^7.3.4" dequal: "npm:^2.0.2" flush-promises: "npm:^1.0.2" @@ -6277,8 +6276,8 @@ __metadata: lodash: "npm:^4.17.21" markdown-to-jsx: "npm:^7.4.5" memoizerific: "npm:^1.11.3" + picoquery: "npm:^2.0.0" polished: "npm:^4.2.2" - qs: "npm:^6.10.0" react: "npm:^18.2.0" react-dom: "npm:^18.2.0" react-draggable: "npm:^4.4.5" @@ -6568,12 +6567,11 @@ __metadata: "@storybook/csf": "npm:^0.1.8" "@storybook/global": "npm:^5.0.0" "@storybook/types": "workspace:*" - "@types/qs": "npm:^6.9.5" ansi-to-html: "npm:^0.6.11" dequal: "npm:^2.0.2" lodash: "npm:^4.17.21" memoizerific: "npm:^1.11.3" - qs: "npm:^6.10.0" + picoquery: "npm:^2.0.0" slash: "npm:^5.0.0" tiny-invariant: "npm:^1.3.1" ts-dedent: "npm:^2.0.0" @@ -6877,7 +6875,7 @@ __metadata: dequal: "npm:^2.0.2" lodash: "npm:^4.17.21" memoizerific: "npm:^1.11.3" - qs: "npm:^6.10.0" + picoquery: "npm:^2.0.0" react: "npm:^18.2.0" react-dom: "npm:^18.2.0" react-router-dom: "npm:6.0.2" @@ -8191,7 +8189,7 @@ __metadata: languageName: node linkType: hard -"@types/qs@npm:*, @types/qs@npm:^6, @types/qs@npm:^6.9.5": +"@types/qs@npm:*": version: 6.9.10 resolution: "@types/qs@npm:6.9.10" checksum: 10c0/6be12e5f062d1b41eb037d59bf9cb65bc9410cedd5e6da832dfd7c8e2b3f4c91e81c9b90b51811140770e5052c6c4e8361181bd9437ddcd4515dc128b7c00353 @@ -14953,6 +14951,13 @@ __metadata: languageName: node linkType: hard +"fast-decode-uri-component@npm:^1.0.1": + version: 1.0.1 + resolution: "fast-decode-uri-component@npm:1.0.1" + checksum: 10c0/039d50c2e99d64f999c3f2126c23fbf75a04a4117e218a149ca0b1d2aeb8c834b7b19d643b9d35d4eabce357189a6a94085f78cf48869e6e26cc59b036284bc3 + languageName: node + linkType: hard + "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" @@ -22493,6 +22498,15 @@ __metadata: languageName: node linkType: hard +"picoquery@npm:^2.0.0": + version: 2.0.0 + resolution: "picoquery@npm:2.0.0" + dependencies: + fast-decode-uri-component: "npm:^1.0.1" + checksum: 10c0/19af5200dccc00149df0946795d35a57a9c6601f524ea042d4ddbe6c1a81e2206890a9fbbcfeef2593051e72a3e8e7d71c7956698b0610b82620108e589e6f0c + languageName: node + linkType: hard + "pidtree@npm:0.6.0": version: 0.6.0 resolution: "pidtree@npm:0.6.0" @@ -23340,7 +23354,7 @@ __metadata: languageName: node linkType: hard -"qs@npm:^6.10.0, qs@npm:^6.10.1, qs@npm:^6.11.2, qs@npm:^6.4.0": +"qs@npm:^6.10.1, qs@npm:^6.11.2, qs@npm:^6.4.0": version: 6.11.2 resolution: "qs@npm:6.11.2" dependencies: