Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7698c14

Browse files
committed
Fix dedup URL params
The depedency, url-parse, will dedup repeated url params. For example`?fop=1&foo2` and will keep the first one. This doesn't play nicely with railsRack params as dups may indicate a structural array. This change migrates`url-parse` to the browser's own 'URLSearchParams' and `URL`.With the change, we had to:1. Make minimal changes to `url.ts` helpers. You'll notice that we have a FAKE_ORIGIN as a fallback for the`URL` usage, but in every instances, we have no 't need the origin at all. Either we replace the origin with a blankor we only a part of the url like pathname.2. baseUrl is required, but existing testing in isolation has it as optional. The update to the tests now reflectthat requirement
1 parent24cae64 commit7698c14

File tree

13 files changed

+233
-192
lines changed

13 files changed

+233
-192
lines changed

‎superglue/lib/action_creators/index.ts‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import{urlToPageKey,getIn}from'../utils'
2-
importparsefrom'url-parse'
1+
import{urlToPageKey,getIn,propsAtParam}from'../utils'
32
import{
43
saveResponse,
54
GRAFTING_ERROR,
@@ -31,11 +30,9 @@ function fetchDeferments(
3130
successAction=GRAFTING_SUCCESS,
3231
failAction=GRAFTING_ERROR,
3332
}){
34-
constparsedUrl=newparse(url,true)
35-
3633
// props_at will always be present in a graft response
3734
// That's why this is marked `as string`
38-
constkeyPath=parsedUrl.query.props_atasstring
35+
constkeyPath=propsAtParam(url)asstring
3936

4037
returndispatch(remote(url,{ pageKey}))
4138
.then(()=>{

‎superglue/lib/action_creators/requests.ts‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import {
33
parseResponse,
44
needsRefresh,
55
urlToPageKey,
6-
withoutBusters,
76
hasPropsAt,
87
propsAtParam,
98
removePropsAt,
@@ -76,7 +75,6 @@ export const remote: RemoteCreator = (
7675
...rest
7776
}={}
7877
)=>{
79-
path=withoutBusters(path)
8078
targetPageKey=targetPageKey&&urlToPageKey(targetPageKey)
8179

8280
return(dispatch,getState)=>{
@@ -146,8 +144,6 @@ export const visit: VisitCreator = (
146144
...rest
147145
}={}
148146
)=>{
149-
path=withoutBusters(path)
150-
151147
return(dispatch,getState)=>{
152148
constcurrentPageKey=getState().superglue.currentPageKey
153149
placeholderKey=

‎superglue/lib/components/Navigation.tsx‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import React, {
66
useImperativeHandle,
77
ForwardedRef,
88
}from'react'
9-
import{urlToPageKey,pathWithoutBZParams}from'../utils'
9+
import{urlToPageKey}from'../utils'
1010
import{removePage,setActivePage}from'../actions'
1111
import{
1212
HistoryState,
@@ -164,7 +164,6 @@ const NavigationProvider = forwardRef(function NavigationProvider(
164164
returnfalse
165165
}
166166

167-
path=pathWithoutBZParams(path)
168167
constnextPageKey=urlToPageKey(path)
169168
consthasPage=Object.prototype.hasOwnProperty.call(
170169
store.getState().pages,

‎superglue/lib/index.tsx‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
importReact,{useRef,useMemo}from'react'
2-
importparsefrom'url-parse'
32
import{config}from'./config'
43
import{urlToPageKey,ujsHandlers,argsForHistory}from'./utils'
54
import{saveAndProcessPage}from'./action_creators'
@@ -53,8 +52,7 @@ export const prepareStore = (
5352
initialPage:VisitResponse,
5453
path:string
5554
)=>{
56-
constlocation=parse(path)
57-
constinitialPageKey=urlToPageKey(location.href)
55+
constinitialPageKey=urlToPageKey(path)
5856
const{ csrfToken}=initialPage
5957

6058
store.dispatch(
@@ -83,7 +81,7 @@ export const setup = ({
8381

8482
const{ visit, remote}=buildVisitAndRemote(navigatorRef,store)
8583

86-
constinitialPageKey=urlToPageKey(parse(path).href)
84+
constinitialPageKey=urlToPageKey(path)
8785
constnextHistory=history||createHistory()
8886
nextHistory.replace(...argsForHistory(path))
8987
prepareStore(store,initialPage,path)

‎superglue/lib/utils/request.ts‎

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
importparsefrom'url-parse'
21
import{formatForXHR}from'./url'
32
import{config}from'../config'
43
import{BasicRequestInit,ParsedResponse,RootState}from'../types'
@@ -91,11 +90,7 @@ export function argsForFetch(
9190
nextHeaders['x-csrf-token']=currentState.csrfToken
9291
}
9392

94-
constfetchPath=newparse(
95-
formatForXHR(pathQuery),
96-
config.baseUrl||{},
97-
true
98-
)
93+
constfetchPath=newURL(formatForXHR(pathQuery),config.baseUrl)
9994

10095
constcredentials='same-origin'
10196

@@ -113,13 +108,9 @@ export function argsForFetch(
113108
}
114109

115110
if(currentState.currentPageKey){
116-
constreferrer=newparse(
117-
currentState.currentPageKey,
118-
config.baseUrl||{},
119-
false
120-
).href
111+
constreferrer=newURL(currentState.currentPageKey,config.baseUrl)
121112

122-
options.referrer=referrer
113+
options.referrer=referrer.toString()
123114
}
124115

125116
if(method=='GET'||method=='HEAD'){
@@ -129,8 +120,11 @@ export function argsForFetch(
129120
)
130121

131122
// TODO: Add coverage for this
132-
constnextQuery={ ...fetchPath.query, ...Object.fromEntries(allData)}
133-
fetchPath.set('query',nextQuery)
123+
// Form data should override anything in the URL params First we
124+
// delete every key. Then append the new keys accounting for
125+
// duplicate keys that represent structural arrays.
126+
allData.forEach((value,key)=>fetchPath.searchParams.delete(key))
127+
allData.forEach((value,key)=>fetchPath.searchParams.append(key,value))
134128
}
135129

136130
deleteoptions.body

‎superglue/lib/utils/ujs.ts‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import{withoutBusters}from'./url'
21
import{
32
Handlers,
43
UJSHandlers,
@@ -77,13 +76,12 @@ export class HandlerBuilder {
7776

7877
event.preventDefault()
7978

80-
leturl=form.getAttribute('action')
79+
consturl=form.getAttribute('action')
8180
if(!url){
8281
return
8382
}
8483

8584
constmethod=(form.getAttribute('method')||'POST').toUpperCase()
86-
url=withoutBusters(url)
8785

8886
this.visitOrRemote(form,url,{
8987
method,
@@ -103,11 +101,10 @@ export class HandlerBuilder {
103101
}
104102

105103
event.preventDefault()
106-
leturl=link.getAttribute('href')
104+
consturl=link.getAttribute('href')
107105
if(!url){
108106
return
109107
}
110-
url=withoutBusters(url)
111108

112109
this.visitOrRemote(link,url,{method:'GET'})
113110
}

‎superglue/lib/utils/url.ts‎

Lines changed: 25 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,43 @@
1-
importparsefrom'url-parse'
21
import{PageKey}from'../types'
32

3+
constFAKE_ORIGIN='https://example.com'
4+
45
exportfunctionpathQuery(url:string):string{
5-
const{ pathname, query}=newparse(url,{})
6+
const{ pathname,search:query}=newURL(url,FAKE_ORIGIN)
67

78
returnpathname+query
89
}
910

1011
exportfunctionpathQueryHash(url:string):string{
11-
const{ pathname,query, hash}=newparse(url,{})
12+
const{ pathname,hash,search:query}=newURL(url,FAKE_ORIGIN)
1213

1314
returnpathname+query+hash
1415
}
1516

1617
exportfunctionhasPropsAt(url:string):boolean{
17-
constparsed=newparse(url,{},true)
18-
constquery=parsed.query
18+
const{ searchParams}=newURL(url,FAKE_ORIGIN)
1919

20-
return!!query['props_at']
20+
returnsearchParams.has('props_at')
2121
}
2222

23-
exportfunctionpropsAtParam(url:string):string|undefined{
24-
constparsed=newparse(url,{},true)
25-
constquery=parsed.query
23+
exportfunctionpropsAtParam(url:string):string|null{
24+
const{ searchParams}=newURL(url,FAKE_ORIGIN)
2625

27-
returnquery['props_at']
26+
returnsearchParams.get('props_at')
2827
}
2928

3029
exportfunctionwithFormatJson(url:string):string{
31-
constparsed=newparse(url,{},true)
32-
parsed.query['format']='json'
33-
34-
returnparsed.toString()
35-
}
30+
constparsed=newURL(url,FAKE_ORIGIN)
31+
parsed.searchParams.set('format','json')
3632

37-
exportfunctionpathWithoutBZParams(url:string):string{
38-
constparsed=newparse(url,{},true)
39-
constquery=parsed.query
40-
41-
deletequery['props_at']
42-
deletequery['format']
43-
parsed.set('query',query)
44-
45-
returnpathQueryHash(parsed.toString())
33+
returnparsed.href.replace(parsed.origin,'')
4634
}
4735

4836
exportfunctionremovePropsAt(url:string):string{
49-
constparsed=newparse(url,{},true)
50-
constquery=parsed.query
51-
52-
deletequery['props_at']
53-
parsed.set('query',query)
37+
constparsed=newURL(url,FAKE_ORIGIN)
38+
parsed.searchParams.delete('props_at')
5439

55-
returnparsed.toString()
40+
returnparsed.href.replace(parsed.origin,'')
5641
}
5742

5843
/**
@@ -62,29 +47,18 @@ export function removePropsAt(url: string): string {
6247
*@returns
6348
*/
6449
exportfunctionurlToPageKey(url:string):PageKey{
65-
constparsed=newparse(url,{},true)
66-
constquery=parsed.query
67-
68-
deletequery['props_at']
69-
deletequery['format']
70-
parsed.set('query',query)
50+
constparsed=newURL(url,FAKE_ORIGIN)
51+
parsed.searchParams.delete('props_at')
52+
parsed.searchParams.delete('format')
7153

7254
returnpathQuery(parsed.toString())
7355
}
7456

7557
exportfunctionwithoutHash(url:string):string{
76-
constparsed=newparse(url,{},true)
77-
parsed.set('hash','')
78-
returnparsed.toString()
79-
}
80-
81-
exportfunctionwithoutBusters(url:string):string{
82-
constparsed=newparse(url,{},true)
83-
constquery=parsed.query
84-
deletequery['format']
85-
parsed.set('query',query)
58+
constparsed=newURL(url,FAKE_ORIGIN)
59+
parsed.hash=''
8660

87-
returnpathQuery(parsed.toString())
61+
returnparsed.href.replace(parsed.origin,'')
8862
}
8963

9064
exportfunctionformatForXHR(url:string):string{
@@ -94,10 +68,12 @@ export function formatForXHR(url: string): string {
9468
}
9569

9670
exportfunctionparsePageKey(pageKey:PageKey){
97-
const{ pathname, query}=newparse(pageKey,{},true)
71+
const{ pathname, searchParams}=newURL(pageKey,FAKE_ORIGIN)
72+
73+
constsearch=Object.fromEntries(searchParams)
9874

9975
return{
10076
pathname,
101-
search:query,
77+
search,
10278
}
10379
}

‎superglue/package.json‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
"@testing-library/react":"^16.0.1",
5151
"@testing-library/user-event":"^14.5.2",
5252
"@types/node":"^22.10.1",
53-
"@types/url-parse":"^1.4.11",
5453
"@typescript-eslint/eslint-plugin":"^7.15.0",
5554
"@typescript-eslint/parser":"^7.15.0",
5655
"@vitejs/plugin-react":"^4.3.1",
@@ -79,12 +78,11 @@
7978
"vitest":"^2.0.2"
8079
},
8180
"peerDependencies": {
81+
"@reduxjs/toolkit":"^2.2.8",
8282
"react":"^18 || ^19",
83-
"react-redux":"^9 || ^8",
84-
"@reduxjs/toolkit":"^2.2.8"
83+
"react-redux":"^9 || ^8"
8584
},
8685
"dependencies": {
87-
"history":"^5.3.0",
88-
"url-parse":"^1.5.1"
86+
"history":"^5.3.0"
8987
}
9088
}

‎superglue/spec/helpers/polyfill.js‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import{AbortController}from'abortcontroller-polyfill/dist/cjs-ponyfill'
2-
import{TextEncoder,TextDecoder}from'util'
32
import{JSDOM}from'jsdom'
43

54
functionsetUpDomEnvironment(){
@@ -26,5 +25,3 @@ function copyProps(src, target) {
2625
setUpDomEnvironment()
2726

2827
global.AbortController=AbortController
29-
global.TextEncoder=TextEncoder
30-
global.TextDecoder=TextDecoder

‎superglue/spec/helpers/setup.js‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,11 @@
11
import'@testing-library/jest-dom/vitest'
2+
import{vi}from'vitest'
3+
4+
vi.mock(import('../../lib/config.ts'),()=>{
5+
return{
6+
config:{
7+
baseUrl:'https://example.com',
8+
maxPages:20,
9+
},
10+
}
11+
})

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp