unjs / ufo Goto Github PK
View Code? Open in Web Editor NEW๐ URL utils for humans
License: MIT License
๐ URL utils for humans
License: MIT License
Hello,
I have a case where we have an encoded slash in an URL (comes from an external api).
For example this one:
http://localhost/abc/deg%2f
Please note it is using the lowercase version of the encoding %2f
and not %2F
.
The library transforms this url into http://localhost/abc/deg/
and thus it breaks our routing.
decodeURIComponent('%2f')
does transform %2f into /
I could not find anything forbidding people to use lowercase versions when encoding.
When typing directly the URL, Chrome does not transform http://localhost/abc/deg%2f
into http://localhost/abc/deg/
.
So I think the library should support those lowercase encoded versions.
Double ?
added when using stringifyParsedURL
let path = '/?query=value#test';
let parsedPath = ufo.parsePath(path)
// {pathname: "/", search: "?query=value", hash: "#test"}
ufo.stringifyParsedURL(parsedPath );
// Returns
// "/??query=value#test"
// Should be
// "/?query=value#test"
Thanks!
ufo.withTrailingSlash('/path?a=1')
// Result: /path?a=1/
Would expect /path/?a=1
Currently used decodeURIComponent
after parse pathname.
So path like /a/b%2Fc
will be after "normalization" /a/b/c
.
By IMHO it's not a clear and destructive
?
inside of a query value should be url encoded to %3F
parseURL('D:/a/framework/framework/test/fixtures/basic/pages/[...slug].vue?macro=true')
// {
// protocol: '',
// auth: '',
// host: '',
// pathname: '',
// search: '',
// hash: ''
// }
Hey team,
I've gone ahead and sent an email to [email protected] to report an issue affecting "unjs/ufo", is there anything else I'll need to do to report this?
Cheers,
Sam
Currently, we can't remove a query param from the original path using the query object given in withQuery
without rebuild the entire URL.
Based on the Vue Router behaviour, if you send a undefined
value to a query parameter, it removes from the path; if you want to keep the param, but send it without value, then you can use a null
value. This represent a breaking change, but it has the most sense for this scenario, because the undefined
value should represent a value that does not exists, not "an empty value": for a empty value, we have the null
value.
const path = withQuery('https://example.com?page=2', { page: undefined });
console.log(path); // Return "https://example.com?page"
const path = withQuery('https://example.com?page=2', { page: null });
console.log(path); // Return "https://example.com?page"
const path = withQuery('https://example.com?page=2', { page: undefined });
console.log(path); // Return "https://example.com"
const path = withQuery('https://example.com?page=2', { page: null });
console.log(path); // Return "https://example.com?page"
Function parseQuery returns this object for query 'param=3¶m=':
{
param: [
"3",
""
]
}
But return value for query 'param=¶m=3' is different:
{
param: "3"
}
As i figured out, it happens because of using if (obj[key])
condition, instead of checking if (obj[key] !== undefined)
if (obj[key]) { <-- here is a problem
if (Array.isArray(obj[key])) {
obj[key].push(value);
} else {
obj[key] = [obj[key], value];
}
} else {
obj[key] = value;
}
Reprodution:
require('ufo').withQuery('http://a.com?v=1', { foo: 'bar', bar: 'baz' })
Returns:
http://a.com?v=1?foo=bar
Expected:
http://a.com?v=1&foo=bar
investigate prototype pollution possibility with query keys
Hey,
Parsing an URL with a port and a hash without a slash in-between results in an improperly parsed URL, where hash
is empty and host
contains the hash.
Also, shouldn't there be an entry fort port
?
Input: parseURL('https://domain.test:3000#owo')
Current output:
{
protocol: 'https:',
auth: '',
host: 'domain.test:3000#owo',
pathname: '',
search: '',
hash: ''
}
Expected output:
{
protocol: 'https:',
auth: '',
host: 'domain.test:3000',
pathname: '',
search: '',
hash: '#owo'
}
const myurl = withQuery('https://example.com', {'abc':'123'})
// https://example.com?abc=123
const urlObject = parseQuery(myurl)
// current => {https://example.com?abc: "123"} โ
// expected => {abc: "123"}
console.log(myurl);
console.log(urlObject);
While the url with extra &
parses the query params correctly.
But, chromium browsers remove this extra &
and thus it cannot be used.
const urlObject = parseQuery(`https://example.com?&abc=123 `)
// {https://example.com?: "", abc: "123 "}
console.log(urlObject);
After f0241d4 Nuxt no longer transpiles this package when it's used on the client-side.
It's supposed to do that as it has ufo
in transpile
array by default: https://github.com/nuxt/nuxt.js/blob/777a4b7f5033c86c37cbd93008f3ca792e4af8bc/packages/webpack/src/config/base.js#L78-L78
It works with 0.7.9 version of the package but not 0.7.11.
I have verified that it's due to changing the browser export from index.js
to index.cjs
but not sure why as I'm not that familiar with babel/webpack. Manually renaming the file and reverting the export name in package.json
to index.js
makes it work again.
Expected:
hasProtocol('tel:0123456789') === true
(this is potentially a breaking change)
Currerrently, parseURL('avatars0.githubusercontent.com')
results into { pathname: 'avatars0.githubusercontent.com', search: '', hash: '' }
whis is wrong! We might either add a fallback protocol or throw an error for this.
hasProtocol('localhost:3000')
// true
Hi, I have a problem when nuxt run development mode
FATAL Package subpath './package.json' is not defined by "exports" in /Users/hienanh/client-barber/node_modules/@nuxt/ufo/package.json
at throwExportsNotFound (internal/modules/esm/resolve.js:290:9)
at packageExportsResolve (internal/modules/esm/resolve.js:513:3)
at resolveExports (internal/modules/cjs/loader.js:432:36)
at Function.Module._findPath (internal/modules/cjs/loader.js:472:31)
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:867:27)
at Function.Module._load (internal/modules/cjs/loader.js:725:27)
at Module.require (internal/modules/cjs/loader.js:952:19)
at require (internal/modules/cjs/helpers.js:88:18)
at Resolver.requireModule (node_modules/@nuxt/core/dist/core.js:618:26)
at Builder.validateTemplate (node_modules/@nuxt/builder/dist/builder.js:5674:38)
at Builder.build (node_modules/@nuxt/builder/dist/builder.js:5602:12)
at Object.run (node_modules/@nuxt/cli/dist/cli-build.js:109:7)
at NuxtCommand.run (node_modules/@nuxt/cli/dist/cli-index.js:2803:7)
โญโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ โ
โ โ Nuxt Fatal Error โ
โ โ
โ Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath โ
โ './package.json' is not defined by "exports" in โ
โ /Users/hienanh/client-barber/node_modules/@nuxt/ufo/package.json โ
โ โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
Help me
Node18
expect(withQuery("/test", { paths: "path1%7Cpath2" })).toBe(
"/test?paths=path1%7Cpath2"
);
This is an issue from Nuxt: nuxt/nuxt#22186
I'm trying to use useFetch function with params containing "%7C", but ufo will encode % to %25, how can I get "%7C"?
Also, why is %7C converted to | again?
No response
ufo/resolveURL
was originally based on native URL
but then due to platform differences and need for polyfill, we switched to lighter utils.
Using createURL
/$URL
for resolveURL
does unnecessary encoding/decoding and adds more to the bundle. We can internally use parseURL
now.
Also, we can still keep $URL
it as a ponyfill but docs need to be improved it is not exactly the same as whatwg URL.
for example,
withBase('//user:[email protected]/', 'https://anotherdomain.com/')
// https://anotherdomain.com/user:[email protected]/
Expected: https://user:[email protected]/
Tested with urijs
and new URL()
, both are working correctly. But failed in ufo
new URL('//user:[email protected]/', 'https://anotherdomain.com/').toString()
// 'https://user:[email protected]/'
new URI('//user:[email protected]/').absoluteTo('https://anotherdomain.com/').toString()
// 'https://user:[email protected]/'
It whould be a great help if parseURL also strip filenames like http://foo.com/foo/bar.png?test=123#token
into { protocol: 'http:', auth: '', host: 'foo.com', pathname: '/foo', search: '?test=123', hash: '#token', filename: 'bar.png' }
.
I think its a great feature because files are also a part of url.
When using withQuery
, arrays of objects are not serialized properly and becomes [object+Object]
.
I'd expect it to be at least stringify with JSON.stringify
.
Current result:
withQuery('http://localhost:3000', { filters: [{ id: 1}, { name: 'ufo' }] })
// 'http://localhost:3000?filters=[object+Object]&filters=[object+Object]'
Expected results:
withQuery('http://localhost:3000', { filters: [{ id: 1}, { name: 'ufo' }] })
// 'http://localhost:3000?filters=%7B+id%3A+1%7D&filters=%7B+name%3A+%27ufo%27+%7D'
Node v16.20.0
Ufo v1.3.0
https://stackblitz.com/edit/stackblitz-starters-t7ehhr?file=index.mjs
normalizeURL
encodes urls incorrectly, different to encodeURI
https://example.com/?foo=^bar
expected https://example.com/?foo=%5Ebar
actual https://example.com/?foo=^bar
https://example.com/?foo=bar%60s
expected https://example.com/?foo=bar%60s
actual https://example.com/?foo=bar`s
No response
No response
Reported by @Kolobok12309 (#31 (comment))
Current behavior:
normalizeURL('/test%2Bfile.txt') = '/test+file.txt'
Expected behavior:
normalizeURL('/test%2Bfile.txt') = '/test%2Bfile.txt'
Hey ๐๐ป
Right now, query methods, mainly withQuery
, is not compatible with vue-routers LocationQuery
.
vue-router:
type LocationQueryValue = string | null;
type LocationQuery = Record<string, LocationQueryValue | LocationQueryValue[]>;
ufo:
type QueryValue = string | string[] | undefined;
type QueryObject = Record<string, QueryValue>;
joinURL(null, './')
// WRONG: '/./' but probably should produce './'
joinURL('/', './')
// WRONG: '/./' but probably should produce: '/'
I have a usecase which requires me to pass a query-string-like string as a query value.
import { withQuery } from 'ufo'
const url = withQuery('https://example.com', { p: 'k1=v1&k2=v2' })
const url2 = new URL('https://example.com')
url2.searchParams.set('p', 'k1=v1&k2=v2')
console.log('withQuery', url)
console.log('URL', url2.href)
The above sample prints the following results.
withQuery https://example.com?p=k1=v1%26k2=v2
URL https://example.com/?p=k1%3Dv1%26k2%3Dv2
As you can see, ufo does not encode =
char while URL does.
Is there any reason to not escape equal char in a query value?
Would be great if ufo can encode equal char as well.
(related to #14)
// Current
joinURL('/', './') = '/./'
// Expected
joinURL('/', './') = '/'
I was looking for a function to take back in the same object type that came from parseURL. I found it looking through the source code (stringifyParsedURL
). Please update the README if it's supposed to be public knowledge.
In server API When we use getQuery()
function to parse params from query, it provides type as QueryValue | QueryValue[]
.
It would be great if we could provide types to this params.
check below code snippet.
export default defineEventHandler((event) => {
const queries = getQuery(event)
const searchQuery = queries.q
}
here the type of searchQuery is QueryValue | QueryValue[]
, but I want type to be string | undefined
.It would be great If I could narrow down type to string | undefined
.currently I am providing types using typeof for every param.
reference: nuxt/nuxt#22262
node: v18.13.0
ufo: version 1.1.2
It might not depends on node version.
> const { stringifyQuery } = require('ufo')
> stringifyQuery({ 'a': 'X', 'b[]': [], c: "Y" })
'a=X&&c=Y'
If the parameter has an empty array as value, a double ampersand is generated and generated URL is invalid.
Expected behavior:
> stringifyQuery({ 'a': 'X', 'b[]': [], c: "Y" })
'a=X&c=Y'
Especially, the "double ampersand" breaks my Nuxt/Rails hybrid application.
The behavior generates url like the following:
"https://localhost:3001/api/v1/users/search?page=1&perPage=25&sortBy=email-asc&&fullName=aaa;bbbb"
Ruby on Rails parses the query parameter as the following
{"page"=>"1",
"per_page"=>"25",
"sort_by"=>"email-asc",
"full_name"=>"aaa",
"bbbb"=>nil,
"format"=>:json,
"controller"=>"api/v1/users",
"action"=>"search",
"user"=>{}}
full_name=aaa;bbbb
was separated to "full_name" => "aaa"
and "bbbb" => ''
and the value after semicolon is ignored in my search form.
No response
No response
Checking if a url is the same with regex
Version: 1.2.0
https://stackblitz.com/edit/js-smsxy5?file=index.js
parseURL('data:image/png;base64,aaa//bbbbbb/ccc')
// { auth: "", hash: "", host: "bbbbbb", pathname: "/ccc", protocol: "", search: "" }
When a data URL is passed into parseURL()
it might detect a host and a pathname based on the base64 content of the data URL.
Downstream issue: unjs/nitro#1431
No response
http://localhost/?redirect=http://google.com?q=test
http://localhost/?redirect=http://google.com?q=test
http://localhost/?redirect=http://google.com?q
(reported by @gabrielrobert via nuxt/nuxt#8550 (comment))
chrome 75.0.3770
and firefox 67
and other
Run ufo
code from browser like chrome 75.0.3770
SyntaxError: "missing ( before catch"
Error from this fragment
Lines 117 to 123 in ab3d4eb
Simple replace catch {
-> catch (err) {
fix it
No response
Hi, first of all, thanks a lot for this, I've been struggling with slashes since I started working with nuxt. As I understand, how it works now you have to apply the desired method to each link. It would be awesome if this could be set globally in nuxt.config.js
in order to enforce a consistent slash policy.
When we encode a query not a url. we should use encodeURIComponent not encodeURI.
Because query value will contain =
as character, it should be encode to %3D
, but encodeURI will think it is Reserved Characters for url, actually query value is URI's component.
Line 56 in 94347b0
Hi, I have a problem when nuxt
hits the parseURL
function with a relative URL containing other URLs.
On my case parseURL
throws an Invalid URL
error when parsing this relative URL:
/auth/callback#state=XXX&access_token=XXX&token_type=Bearer&expires_in=XXX&scope=email%20profile%20https://www.googleapis.com/auth/userinfo.email%20openid%20https://www.googleapis.com/auth/gmail.modify%20https://www.googleapis.com/auth/gmail.compose%20https://www.googleapis.com/auth/gmail.send%20https://mail.google.com/%20https://www.googleapis.com/auth/userinfo.profile&authuser=0&prompt=consent
It appears to be because hasProtocol
matches https:/
on https://www.googleapis.com/auth/userinfo.email
.
Hello!
I want to replace qs
with ufo as the latter is much more lighter and it's already included in nuxt, so I think it's a good and powerful replacement :).
I'm struggling to use withQuery
as it expects a QueryType object, which only accepts strings or array of strings. I want to pass a boolean variable.
How I can accomplish it without using 'true'
? Is the parsing of booleans out of the scope of ufo?
Thank you very much in advance!
As ufo
is implementing a standard, then the current is the correct behaviour. See https://url.spec.whatwg.org/#urlsearchparams.
Name: Ufo
Version: 1.1.2
Add any query params in which key is having space in it.
Add any query params in which key is having space in it and check space is converted to '+' sign while encoding but while decoding '+' sign is not getting converted back to space.
No response
No response
There is not documentation for parseURL
in your README. Is it intended?
Thanks
withHttp('foo.bar.com') // expected: http://foo.bar.com
withHttps('foo.bar.com') // expected: https://foo.bar.com
Reference: unjs/ofetch#113
Current behavior:
// http://base/http://domain
ufo.withBase('http://domain', 'http://base')
New behavior:
// http://domain
ufo.withBase('http://domain', 'http://base'})
URL behavior:
// http://domain/
new URL('http://domain', 'http://base').toString()
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.
.github/workflows/autofix.yml
actions/checkout v3
actions/setup-node v4
autofix-ci/action ff86a557419858bb967097bfc916833f5647fa8c
.github/workflows/ci.yml
actions/checkout v3
actions/setup-node v4
codecov/codecov-action v4
package.json
@types/node ^20.16.1
@vitest/coverage-v8 ^2.0.5
automd ^0.3.8
changelogen ^0.5.5
eslint ^9.9.1
eslint-config-unjs ^0.3.2
jiti ^1.21.6
prettier ^3.3.3
typescript ^5.5.4
unbuild ^2.0.0
untyped ^1.4.2
vitest ^2.0.5
pnpm 9.8.0
When using e.g. {json: '{"test":["content"]}'}
as query object, the result differs a lot from URLSearchParams
and some systems do not accept the input.
Reproduction (StackBlitz):
import { withQuery } from 'ufo'
const content = {json: '{"test":["content"]}'}
// json=%7B%22test%22%3A%5B%22content%22%5D%7D
const urlSearchParams = new URLSearchParams(content).toString()
// json={%22test%22:[%22content%22]}
const ufoResult = withQuery('', content)
While the colon :
does not need to be encoded necessarily, the square and curly brackets should be. Some APIs won't accept input then.
Example calls:
I have often had use for adding and removing protocols.
Some type of implementation for something like withHttps
, withHttp
, withoutProtocol
would be really nice.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.