Code Monkey home page Code Monkey logo

ufo's Introduction

ufo

npm version npm downloads bundle Codecov

URL utils for humans.

Install

Install using npm or your favourite package manager:

Install package:

# npm
npm install ufo

# yarn
yarn add ufo

# pnpm
pnpm install ufo

# bun
bun install ufo

Import utils:

// ESM
import { normalizeURL, joinURL } from "ufo";

// CommonJS
const { normalizeURL, joinURL } = require("ufo");

// Deno
import { parseURL } from "https://unpkg.com/ufo/dist/index.mjs";

Encoding Utils

decode(text)

Decode text using decodeURIComponent. Returns the original text if it fails.

decodePath(text)

Decode path section of URL (consistent with encodePath for slash encoding).

decodeQueryKey(text)

Decodes query key (consistent with encodeQueryKey for plus encoding).

decodeQueryValue(text)

Decode query value (consistent with encodeQueryValue for plus encoding).

encode(text)

Encode characters that need to be encoded on the path, search and hash sections of the URL.

encodeHash(text)

Encode characters that need to be encoded on the hash section of the URL.

encodeHost(name)

Encodes hostname with punycode encoding.

encodeParam(text)

Encode characters that need to be encoded on the path section of the URL as a param. This function encodes everything encodePath does plus the slash (/) character.

encodePath(text)

Encode characters that need to be encoded on the path section of the URL.

encodeQueryKey(text)

Encode characters that need to be encoded query values on the query section of the URL and also encodes the = character.

encodeQueryValue(input)

Encode characters that need to be encoded query values on the query section of the URL.

Parsing Utils

parseAuth(input)

Takes a string of the form username:password and returns an object with the username and password decoded.

parseFilename(input)

Parses a url and returns last segment in path as filename.

If { strict: true } is passed as the second argument, it will only return the last segment only if ending with an extension.

Example:

// Result: filename.ext
parseFilename("http://example.com/path/to/filename.ext");

// Result: undefined
parseFilename("/path/to/.hidden-file", { strict: true });

parseHost(input)

Takes a string, and returns an object with two properties: hostname and port.

parsePath(input)

Splits the input string into three parts, and returns an object with those three parts.

parseURL(input, defaultProto?)

Takes a URL string and returns an object with the URL's protocol, auth, host, pathname, search, and hash.

Example:

parseURL("http://foo.com/foo?test=123#token");
// { protocol: 'http:', auth: '', host: 'foo.com', pathname: '/foo', search: '?test=123', hash: '#token' }

parseURL("foo.com/foo?test=123#token");
// { pathname: 'foo.com/foo', search: '?test=123', hash: '#token' }

parseURL("foo.com/foo?test=123#token", "https://");
// { protocol: 'https:', auth: '', host: 'foo.com', pathname: '/foo', search: '?test=123', hash: '#token' }

stringifyParsedURL(parsed)

Takes a ParsedURL object and returns the stringified URL.

Example:

const obj = parseURL("http://foo.com/foo?test=123#token");
obj.host = "bar.com";

stringifyParsedURL(obj); // "http://bar.com/foo?test=123#token"

Query Utils

encodeQueryItem(key, value)

Encodes a pair of key and value into a url query string value.

If the value is an array, it will be encoded as multiple key-value pairs with the same key.

parseQuery(parametersString)

Parses and decodes a query string into an object.

input can be a query string with or without the leading ?

stringifyQuery(query)

Stringfies and encodes a query object into a query string.

Utils

cleanDoubleSlashes(input)

Removes double slashes from the URL.

Example:

cleanDoubleSlashes("//foo//bar//"); // "/foo/bar/"

cleanDoubleSlashes("http://example.com/analyze//http://localhost:3000//");
// Returns "http://example.com/analyze/http://localhost:3000/"

getQuery(input)

Parses and decods the query object of an input URL into an object.

Example:

getQuery("http://foo.com/foo?test=123&unicode=%E5%A5%BD");
// { test: "123", unicode: "ๅฅฝ" }

hasLeadingSlash(input)

Checks if the input has a leading slash. (e.g. /foo)

hasProtocol(inputString, opts)

hasTrailingSlash(input, respectQueryAndFragment?)

Checks if the input has a trailing slash.

isEmptyURL(url)

Checks if the input url is empty or /.

isEqual(a, b, options)

Checks if two paths are equal regardless of encoding, trailing slash, and leading slash differences.

You can make slash check strict by setting { trailingSlash: true, leadingSlash: true } as options. You can make encoding check strict by setting { encoding: true } as options.

Example:

isEqual("/foo", "foo"); // true
isEqual("foo/", "foo"); // true
isEqual("/foo bar", "/foo%20bar"); // true

// Strict compare
isEqual("/foo", "foo", { leadingSlash: true }); // false
isEqual("foo/", "foo", { trailingSlash: true }); // false
isEqual("/foo bar", "/foo%20bar", { encoding: true }); // false

isNonEmptyURL(url)

Checks if the input url is not empty nor /.

isRelative(inputString)

Check if a path starts with ./ or ../.

Example:

isRelative("./foo"); // true

isSamePath(p1, p2)

Check two paths are equal or not. Trailing slash and encoding are normalized before comparison.

Example:

isSamePath("/foo", "/foo/"); // true

isScriptProtocol(protocol?)

Checks if the input protocol is any of the dangerous blob:, data:, javascript: or vbscript: protocols.

joinRelativeURL()

Joins multiple URL segments into a single URL and also handles relative paths with ./ and ../.

Example:

joinRelativeURL("/a", "../b", "./c"); // "/b/c"

joinURL(base)

Joins multiple URL segments into a single URL.

Example:

joinURL("a", "/b", "/c"); // "a/b/c"

normalizeURL(input)

Normlizes inputed url:

  • Ensures url is properly encoded - Ensures pathname starts with slash - Preserves protocol/host if provided

Example:

normalizeURL("test?query=123 123#hash, test");
// Returns "test?query=123%20123#hash,%20test"

normalizeURL("http://localhost:3000");
// Returns "http://localhost:3000"

resolveURL(base)

Resolves multiple URL segments into a single URL.

Example:

resolveURL("http://foo.com/foo?test=123#token", "bar", "baz");
// Returns "http://foo.com/foo/bar/baz?test=123#token"

withBase(input, base)

Ensures the URL or pathname has a trailing slash.

If input aleady start with base, it will not be added again.

withFragment(input, hash)

Add/Replace the fragment section of the URL.

Example:

withFragment("/foo", "bar"); // "/foo#bar"
withFragment("/foo#bar", "baz"); // "/foo#baz"
withFragment("/foo#bar", ""); // "/foo"

withHttp(input)

Adds or replaces url protocol to http://.

Example:

withHttp("https://example.com"); // http://example.com

withHttps(input)

Adds or replaces url protocol to https://.

Example:

withHttps("http://example.com"); // https://example.com

withLeadingSlash(input)

Ensures the URL or pathname has a leading slash.

withoutBase(input, base)

Removes the base from the URL or pathname.

If input does not start with base, it will not be removed.

withoutFragment(input)

Removes the fragment section from the URL.

Example:

withoutFragment("http://example.com/foo?q=123#bar")
// Returns "http://example.com/foo?q=123"

withoutHost(input)

Removes the host from the URL preserving everything else.

Example:

withoutHost("http://example.com/foo?q=123#bar")
// Returns "/foo?q=123#bar"

withoutLeadingSlash(input)

Removes leading slash from the URL or pathname.

withoutProtocol(input)

Removes the protocol from the input.

Example:

withoutProtocol("http://example.com"); // "example.com"

withoutTrailingSlash(input, respectQueryAndFragment?)

Removes trailing slash from the URL or pathname.

If second argument is true, it will only remove the trailing slash if it's not part of the query or fragment with cost of more expensive operations.

Example:

withoutTrailingSlash("/foo/"); // "/foo"

withoutTrailingSlash("/path/?query=true", true); // "/path?query=true"

withProtocol(input, protocol)

Adds or Replaces protocol of the input URL.

Example:

withProtocol("http://example.com", "ftp://"); // "ftp://example.com"

withQuery(input, query)

Add/Replace the query section of the URL.

Example:

withQuery("/foo?page=a", { token: "secret" }); // "/foo?page=a&token=secret"

withTrailingSlash(input, respectQueryAndFragment?)

Ensures url ends with a trailing slash.

If seccond argument is true, it will only add the trailing slash if it's not part of the query or fragment with cost of more expensive operation.

Example:

withTrailingSlash("/foo"); // "/foo/"

withTrailingSlash("/path?query=true", true); // "/path/?query=true"

License

MIT

Special thanks to Eduardo San Martin Morote (posva) for encoding utilities

ufo's People

Contributors

airmoi avatar aryraditya avatar atinux avatar aurelienbottazini avatar autofix-ci[bot] avatar bokub avatar brandonlinu avatar daniacu avatar danielroe avatar divine avatar ea-agital avatar felixonmars avatar hecktarzuli avatar hexrw avatar ignisda avatar madebyfabian avatar mannil avatar natanfeitosa avatar nozomuikuta avatar oleghalin avatar pi0 avatar podlebar avatar rajkadhi10 avatar renovate[bot] avatar smeng9 avatar thijsw avatar trurlmcbyte avatar yshrsmz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

ufo's Issues

Improperly parsed hash in URLs with port

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?

Reproduction

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'
}

Encoded slash in URL

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.

equal char in query value is not encoded

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.

parseURL without proto

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.

override urls with protocol with `withBase`

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()

destructive decode of pathname

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

Key with space in query params not working properly

Environment

Name: Ufo
Version: 1.1.2

Reproduction

Add any query params in which key is having space in it.

Describe the bug

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.

Additional context

No response

Logs

No response

invalid handling of `withBase` on different origins

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]/'

query compat with vue-routers `LocationObject`

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>;

stringifyParsedURL isn't documented

Describe the feature

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.

Additional information

  • Would you be willing to help implement this feature?

Error [ERR_PACKAGE_PATH_NOT_EXPORTED]

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

url constructed with 'withQuery' does not give same result with 'parseQuery'

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);

Feature Request: Setting trailing slash globally

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.

Splice filename from URL

Describe the feature

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.

Additional information

  • Would you be willing to help implement this feature?

windows paths aren't handled when parsing

parseURL('D:/a/framework/framework/test/fixtures/basic/pages/[...slug].vue?macro=true')
// {
//   protocol: '',
//   auth: '',
//   host: '',
//   pathname: '',
//   search: '',
//   hash: ''
// }

Empty array parameters generates invalid URL

Environment

node: v18.13.0
ufo: version 1.1.2

It might not depends on node version.

Reproduction

> const { stringifyQuery } = require('ufo')
> stringifyQuery({ 'a': 'X', 'b[]': [], c: "Y" })
'a=X&&c=Y'

Describe the bug

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.

Additional context

No response

Logs

No response

Allow defining type for getQuery() function via generic

Describe the feature

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

Additional information

  • Would you be willing to help implement this feature?

How can I get a "%7C" params using withQuery

Environment

Node18

Reproduction

expect(withQuery("/test", { paths: "path1%7Cpath2" })).toBe(
    "/test?paths=path1%7Cpath2"
);

Describe the bug

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"?

Additional context

Also, why is %7C converted to | again?
image

Logs

No response

Wrong parseQuery return value in case of query with array containing empty element

Function parseQuery returns this object for query 'param=3&param=':

{
    param: [
        "3",
        ""
    ]
}

But return value for query 'param=&param=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;
    }

Query param array of object is not stringified

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'

Double `?` when using with Query

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

Use of booleans

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!

decouple `resolveURL` from `$URL`

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.

Double `?` stringifyParsedURL

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!

Unexpected behavior when passing a `data:` URL into parseURL()

Environment

Version: 1.2.0

Reproduction

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: "" }

Describe the bug

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.

Additional context

Downstream issue: unjs/nitro#1431

Logs

No response

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Awaiting Schedule

These updates are awaiting their schedule. Click on a checkbox to get an update now.

  • chore(deps): update autofix-ci/action digest to ff86a55
  • chore(deps): update devdependency @types/node to ^20.14.11

Ignored or Blocked

These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.

Detected dependencies

github-actions
.github/workflows/autofix.yml
  • actions/checkout v3
  • actions/setup-node v4
  • autofix-ci/action 2891949f3779a1cafafae1523058501de3d4e944
.github/workflows/ci.yml
  • actions/checkout v3
  • actions/setup-node v4
  • codecov/codecov-action v4
npm
package.json
  • @types/node ^20.14.10
  • @vitest/coverage-v8 ^2.0.3
  • automd ^0.3.8
  • changelogen ^0.5.5
  • eslint ^9.7.0
  • eslint-config-unjs ^0.3.2
  • jiti ^1.21.6
  • prettier ^3.3.3
  • typescript ^5.5.3
  • unbuild ^2.0.0
  • untyped ^1.4.2
  • vitest ^2.0.3
  • pnpm 9.5.0

  • Check this box to trigger a request for Renovate to run again on this repository

SyntaxError: "missing ( before catch"

Environment

chrome 75.0.3770 and firefox 67 and other

Reproduction

Run ufo code from browser like chrome 75.0.3770

Describe the bug

SyntaxError: "missing ( before catch"

Error from this fragment

ufo/src/encoding.ts

Lines 117 to 123 in ab3d4eb

export function decode (text: string | number = ""): string {
try {
return decodeURIComponent("" + text);
} catch {
return "" + text;
}
}

Additional context

Simple replace catch { -> catch (err) { fix it

Logs

No response

`normalizeURL` encodes url incorrectly

Environment

Node v16.20.0
Ufo v1.3.0

Reproduction

https://stackblitz.com/edit/stackblitz-starters-t7ehhr?file=index.mjs

Describe the bug

normalizeURL encodes urls incorrectly, different to encodeURI

Additional context

No response

Logs

No response

Package no longer transpiled by Nuxt

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.

withQuery can't remove a query param from the path

Currently, we can't remove a query param from the original path using the query object given in withQuery without rebuild the entire URL.

Proposed solution

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.

Current behaviour:

For param = undefined

const path = withQuery('https://example.com?page=2', { page: undefined });
console.log(path); // Return "https://example.com?page"

For param = null

const path = withQuery('https://example.com?page=2', { page: null });
console.log(path); // Return "https://example.com?page"

Proposed behaviour:

For param = undefined

const path = withQuery('https://example.com?page=2', { page: undefined });
console.log(path); // Return "https://example.com"

For param = null

const path = withQuery('https://example.com?page=2', { page: null });
console.log(path); // Return "https://example.com?page"

parseURL fails when parsing a relative URL containing other URLs.

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.

https://github.com/nuxt-contrib/ufo/blob/d15b6f067b4bf1e17e9ae0252dd17fb55f7ec148/src/index.ts#L23-L25

`withQuery` handles inline JSON wrongly.

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:

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.