@naverpay/nurl 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +128 -0
- package/dist/cjs/index.d.ts +58 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/esm/index.d.mts +58 -0
- package/dist/esm/index.mjs +202 -0
- package/dist/esm/index.mjs.map +1 -0
- package/package.json +72 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 NaverPayDev
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<h1 align="center">@naverpay/nurl</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://www.npmjs.com/package/@naverpay/nurl">
|
|
5
|
+
<img src="https://img.shields.io/npm/v/@naverpay/nurl.svg?style=flat" alt="npm version">
|
|
6
|
+
</a>
|
|
7
|
+
<a href="https://bundlephobia.com/result?p=@naverpay/nurl">
|
|
8
|
+
<img src="https://badgen.net/bundlephobia/minzip/@naverpay/nurl" alt="minzipped size">
|
|
9
|
+
</a>
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
NURL is a powerful URL manipulation library that extends the standard URL class. It provides dynamic segment processing and flexible URL creation capabilities.
|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
|
|
16
|
+
- Extends and implements the URL class
|
|
17
|
+
- Supports various URL creation methods (string, URL object, custom options object)
|
|
18
|
+
- Provides a factory function NURL.create() for creating instances without the new keyword
|
|
19
|
+
- Dynamic segment processing functionality
|
|
20
|
+
- Setters behave differently from the standard URL
|
|
21
|
+
- Provides decoded hostname for IDN (Internationalized Domain Names) support
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
### Basic Usage
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
import { NURL } from 'nurl'
|
|
29
|
+
|
|
30
|
+
// Create URL from string
|
|
31
|
+
const url1 = new NURL('https://example.com/users/123?name=John')
|
|
32
|
+
|
|
33
|
+
// Create URL from existing URL object
|
|
34
|
+
const standardUrl = new URL('https://example.com')
|
|
35
|
+
const url2 = new NURL(standardUrl)
|
|
36
|
+
|
|
37
|
+
// Create URL from custom options object
|
|
38
|
+
const url3 = new NURL({
|
|
39
|
+
baseUrl: 'https://example.com',
|
|
40
|
+
pathname: '/users/:id',
|
|
41
|
+
query: { id: '123', name: 'John' }
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
// Create empty URL
|
|
45
|
+
const url4 = new NURL()
|
|
46
|
+
|
|
47
|
+
// Using the factory function
|
|
48
|
+
const url5 = NURL.create('https://example.com')
|
|
49
|
+
|
|
50
|
+
// The factory function also works with options object
|
|
51
|
+
const url6 = NURL.create({
|
|
52
|
+
baseUrl: 'https://example.com',
|
|
53
|
+
pathname: '/users/:id',
|
|
54
|
+
query: { id: '123', name: 'John' }
|
|
55
|
+
})
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Dynamic Segment Processing
|
|
59
|
+
|
|
60
|
+
NURL processes dynamic segments in the pathname and replaces them with values from the query object. If a dynamic segment doesn't have a corresponding query value, it remains unchanged in the pathname without any encoding:
|
|
61
|
+
|
|
62
|
+
```javascript
|
|
63
|
+
const url = new NURL({
|
|
64
|
+
baseUrl: 'https://api.example.com',
|
|
65
|
+
pathname: '/users/:a/posts/[b]/[c]',
|
|
66
|
+
query: {
|
|
67
|
+
a: '123',
|
|
68
|
+
b: '456',
|
|
69
|
+
format: 'json'
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
console.log(url.href)
|
|
74
|
+
// Output: https://api.example.com/users/123/posts/456/[c]?format=json
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### IDN Support
|
|
78
|
+
|
|
79
|
+
NURL automatically handles Internationalized Domain Names:
|
|
80
|
+
|
|
81
|
+
```javascript
|
|
82
|
+
const url = new NURL('https://한글.도메인')
|
|
83
|
+
console.log(url.hostname) // xn--bj0bj06e.xn--hq1bm8jm9l
|
|
84
|
+
console.log(url.decodedHostname) // 한글.도메인 (in human-readable format)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## API
|
|
88
|
+
|
|
89
|
+
### `constructor(input?: string | URL | URLOptions)`
|
|
90
|
+
|
|
91
|
+
- `input`: Can be one of the following:
|
|
92
|
+
- `string`: Standard URL string
|
|
93
|
+
- `URL`: Standard URL object
|
|
94
|
+
- `URLOptions`: Custom options object that extends `Partial<URL>` and includes:
|
|
95
|
+
- `baseUrl?: string`: Optional base URL string
|
|
96
|
+
- `query?: Record<string, string>`: Optional object for query parameters
|
|
97
|
+
- Can include any property from the standard URL object (e.g., `pathname`, `protocol`, etc.)
|
|
98
|
+
|
|
99
|
+
### Dynamic Segments
|
|
100
|
+
|
|
101
|
+
- Supports `:paramName` or `[paramName]` format in the pathname.
|
|
102
|
+
- If a corresponding key exists in the query object or URLOptions, the dynamic segment is replaced with its value.
|
|
103
|
+
- If a corresponding key does not exist, the dynamic segment remains unchanged in the pathname without throwing an error.
|
|
104
|
+
|
|
105
|
+
### Properties
|
|
106
|
+
|
|
107
|
+
NURL inherits all properties from the standard URL class:
|
|
108
|
+
|
|
109
|
+
- `href`, `origin`, `protocol`, `username`, `password`, `host`, `hostname`, `port`, `pathname`, `search`, `searchParams`, `hash`
|
|
110
|
+
|
|
111
|
+
### Methods
|
|
112
|
+
|
|
113
|
+
- `toString()`: Returns the URL as a string
|
|
114
|
+
- `toJSON()`: Returns the URL as a JSON representation
|
|
115
|
+
|
|
116
|
+
## Important Notes
|
|
117
|
+
|
|
118
|
+
1. NURL's setter methods behave differently from the standard URL. They are designed to consider dynamic segment and query parameter replacement functionality.
|
|
119
|
+
2. When created with no arguments, all properties are initialized as empty strings.
|
|
120
|
+
3. When using `URLOptions`, if a query value corresponding to a dynamic segment is missing, the dynamic segment remains unchanged in the pathname.
|
|
121
|
+
4. Dynamic segments only support the `:paramName` or `[paramName]` format.
|
|
122
|
+
|
|
123
|
+
## Differences from Standard URL
|
|
124
|
+
|
|
125
|
+
1. **Constructor Flexibility**: NURL can create a URL from a string, URL object, or custom options object.
|
|
126
|
+
2. **Empty URL Creation**: NURL can create an empty URL when called with no arguments.
|
|
127
|
+
3. **Dynamic Segments**: NURL supports dynamic segments in the pathname.
|
|
128
|
+
4. **Setter Behavior**: NURL's setter methods behave differently from the standard URL, considering dynamic segment processing and query parameter replacement.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
interface URLOptions extends Partial<URL> {
|
|
2
|
+
baseUrl?: string;
|
|
3
|
+
query?: Record<string, string>;
|
|
4
|
+
}
|
|
5
|
+
declare class NURL implements URL {
|
|
6
|
+
private _href;
|
|
7
|
+
private _protocol;
|
|
8
|
+
private _host;
|
|
9
|
+
private _hostname;
|
|
10
|
+
private _port;
|
|
11
|
+
private _pathname;
|
|
12
|
+
private _search;
|
|
13
|
+
private _hash;
|
|
14
|
+
private _origin;
|
|
15
|
+
private _username;
|
|
16
|
+
private _password;
|
|
17
|
+
private _baseUrl;
|
|
18
|
+
private _searchParams;
|
|
19
|
+
constructor(input?: string | URL | URLOptions);
|
|
20
|
+
static create(input?: string | URL | URLOptions): NURL;
|
|
21
|
+
static canParse(input: string): boolean;
|
|
22
|
+
get baseUrl(): string;
|
|
23
|
+
set baseUrl(value: string);
|
|
24
|
+
get href(): string;
|
|
25
|
+
set href(value: string);
|
|
26
|
+
get protocol(): string;
|
|
27
|
+
set protocol(value: string);
|
|
28
|
+
get host(): string;
|
|
29
|
+
set host(value: string);
|
|
30
|
+
get hostname(): string;
|
|
31
|
+
set hostname(value: string);
|
|
32
|
+
get port(): string;
|
|
33
|
+
set port(value: string);
|
|
34
|
+
get pathname(): string;
|
|
35
|
+
set pathname(pathname: string);
|
|
36
|
+
get search(): string;
|
|
37
|
+
set search(search: string);
|
|
38
|
+
setSearchParams(_params: Record<string, string>): void;
|
|
39
|
+
appendSearchParams(_params: Record<string, string>): void;
|
|
40
|
+
removeSearchParams(..._keys: string[]): void;
|
|
41
|
+
get searchParams(): URLSearchParams;
|
|
42
|
+
get hash(): string;
|
|
43
|
+
set hash(value: string);
|
|
44
|
+
get origin(): string;
|
|
45
|
+
get username(): string;
|
|
46
|
+
set username(value: string);
|
|
47
|
+
get password(): string;
|
|
48
|
+
set password(value: string);
|
|
49
|
+
private updateHref;
|
|
50
|
+
toString(): string;
|
|
51
|
+
toJSON(): string;
|
|
52
|
+
private punycodePrefix;
|
|
53
|
+
private encodeHostname;
|
|
54
|
+
get decodedIDN(): string;
|
|
55
|
+
get decodedHostname(): string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { NURL as default };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const i=require("punycode/"),f=/^:/,d=/^\[.*\]$/;function p(h){return f.test(h)||d.test(h)}function o(h){return h.split("/").filter(p)}function n(h){return h.slice(1,f.test(h)?void 0:-1)}function m(h,t){return o(h).reduce((s,e)=>{const r=n(e);return t[r]?s.replace(e,t[r]):s},h)}function u(h,t){return o(h).reduce((s,e)=>{const r=n(e),{[r]:_,...a}=s;return a},t)}const l=127;function P(h){return h.charCodeAt(0)>l}class c{constructor(t){if(this._href="",this._protocol="",this._host="",this._hostname="",this._port="",this._pathname="",this._search="",this._hash="",this._origin="",this._username="",this._password="",this._baseUrl="",this._searchParams=new URLSearchParams,this.punycodePrefix="xn--",this._searchParams=new URLSearchParams,typeof t=="string"||t instanceof URL)this.href=t.toString();else if(t){if(t.baseUrl&&(this.baseUrl=t.baseUrl),t.href&&(this.href=t.href),t.protocol&&(this.protocol=t.protocol),t.host&&(this.host=t.host),t.hostname&&(this.hostname=t.hostname),t.port&&(this.port=t.port),t.pathname&&(this.pathname=m(t.pathname,t.query??{})),t.search&&(this.search=t.search),t.hash&&(this.hash=t.hash),t.username&&(this.username=t.username),t.password&&(this.password=t.password),t.query){const s=u(t.pathname??"",t.query);Object.keys(s).length>0&&(this.search=new URLSearchParams(s).toString())}this.updateHref()}}static create(t){return new c(t)}static canParse(t){if(t.startsWith("/"))return/^\/[^?#]*(\?[^#]*)?(#.*)?$/.test(t);try{return new URL(t),!0}catch{return/^[^:/?#]+(\.[^:/?#]+)+(\/[^?#]*(\?[^#]*)?(#.*)?)?$/.test(t)}}get baseUrl(){return this._baseUrl}set baseUrl(t){this._baseUrl=t;try{const s=new URL(t);this._protocol=s.protocol,this._host=s.host,this._hostname=s.hostname,this._port=s.port,this._origin=s.origin,this._username=s.username,this._password=s.password,s.pathname!=="/"&&(this._pathname=s.pathname),s.search&&(this._search=s.search,this._searchParams=new URLSearchParams(s.search)),s.hash&&(this._hash=s.hash),this.updateHref()}catch(s){console.warn(`Invalid baseUrl: ${t}`,s)}}get href(){return this.pathname.length===1?`${this._href}/`:this._href}set href(t){try{const s=new URL(t);this._href=s.href,this._protocol=s.protocol,this._host=s.host,this._hostname=s.hostname,this._port=s.port,this._pathname=s.pathname,this._search=s.search,this._hash=s.hash,this._origin=s.origin,this._username=s.username,this._password=s.password,this._searchParams=s.searchParams}catch(s){console.warn(`Can not parse ${t}`,s)}}get protocol(){return this._protocol}set protocol(t){this._protocol=t,this.updateHref()}get host(){return this._host}set host(t){const[s,e]=t.split(":"),r=this.encodeHostname(s);this._host=e?`${r}:${e}`:r,this._hostname=r,this._port=e||"",this.updateHref()}get hostname(){return this._hostname}set hostname(t){const s=this.encodeHostname(t);this._hostname=s,this._host=this._port?`${s}:${this._port}`:s,this.updateHref()}get port(){return this._port}set port(t){this._port=t,this._host=`${this._hostname}${t?":"+t:""}`,this.updateHref()}get pathname(){return this._pathname}set pathname(t){const s=t.split("/").map(e=>p(e)?e:encodeURI(e)).join("/");this._pathname=s.startsWith("/")?s:`/${s}`,this.updateHref()}get search(){return this._search}set search(t){const s=encodeURI(t);this._search=s.startsWith("?")?s:`?${s}`,this._searchParams=new URLSearchParams(s),this.updateHref()}setSearchParams(t){const s=new URLSearchParams(t);this._search=s.toString()?`?${s.toString()}`:"",this._searchParams=s,this.updateHref()}appendSearchParams(t){const s=new URLSearchParams(this._searchParams),e=o(this._pathname).map(n);Object.keys(t).forEach(r=>{e.includes(r)?this._pathname=m(this._pathname,{[r]:t[r]}):s.append(r,t[r])}),this._search=s.toString()?`?${s.toString()}`:"",this._searchParams=s,this.updateHref()}removeSearchParams(...t){const s=new URLSearchParams(this._searchParams);t.forEach(e=>{s.delete(e)}),this._search=s.toString()?`?${s.toString()}`:"",this._searchParams=s,this.updateHref()}get searchParams(){return new Proxy(this._searchParams,{get:(t,s,e)=>{const r=Reflect.get(t,s,e);return typeof r=="function"?(..._)=>{const a=r.apply(t,_);return this._search=this._searchParams.toString()?`?${this._searchParams.toString()}`:"",this.updateHref(),a}:r}})}get hash(){return this._hash}set hash(t){this._hash=t.startsWith("#")?t:`#${t}`,this.updateHref()}get origin(){return this._origin}get username(){return this._username}set username(t){this._username=t,this.updateHref()}get password(){return this._password}set password(t){this._password=t,this.updateHref()}updateHref(){if(this._baseUrl){const t=new URL(this._baseUrl);t.pathname=this._pathname,t.search=this._search,t.hash=this._hash,this._href=t.href,this._origin=t.origin}else this._href=`${this._protocol}${this._protocol&&"//"}${this._username}${this._password?":"+this._password:""}${this._username||this._password?"@":""}${this._hostname}${this._port?":"+this._port:""}${this._pathname==="/"?"":this._pathname}${this._search}${this._hash}`,this._origin=`${this._protocol}//${this._hostname}${this._port?":"+this._port:""}`}toString(){return this.href}toJSON(){return this.href}encodeHostname(t){return t.split(".").map(s=>{for(const e of s)if(P(e))return`${this.punycodePrefix}${i.encode(s)}`;return s}).join(".")}get decodedIDN(){let t=this._href;return this._hostname.split(".").forEach(s=>{t=t.replace(s,i.decode(s.replace(this.punycodePrefix,"")))}),t}get decodedHostname(){return this._hostname.split(".").map(t=>i.decode(t.replace(this.punycodePrefix,""))).join(".")}}module.exports=c;
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/utils.ts","../../src/nurl.ts"],"sourcesContent":["const DYNAMIC_PATH_COLON_REGEXP = /^:/\nconst DYNAMIC_PATH_BRACKETS_REGEXP = /^\\[.*\\]$/\n\nexport function isDynamicPath(path: string) {\n return DYNAMIC_PATH_COLON_REGEXP.test(path) || DYNAMIC_PATH_BRACKETS_REGEXP.test(path)\n}\n\nexport function getDynamicPaths(pathname: string): string[] {\n return pathname.split('/').filter(isDynamicPath)\n}\n\nexport function extractPathKey(path: string): string {\n return path.slice(1, DYNAMIC_PATH_COLON_REGEXP.test(path) ? undefined : -1)\n}\n\n/**\n * Replaces dynamic paths in the pathname with values from the query\n * @param {string} pathname\n * @param {Record<string, string>} query\n * @returns {string} refined pathname\n */\nexport function refinePathnameWithQuery(pathname: string, query: Record<string, string>): string {\n return getDynamicPaths(pathname).reduce((acc, path) => {\n const pathKey = extractPathKey(path)\n return query[pathKey] ? acc.replace(path, query[pathKey]) : acc\n }, pathname)\n}\n\n/**\n * Removes queries that have already been used in the pathname.\n * @param {string} pathname\n * @param {Record<string, string>} query\n * @returns {Record<string, string>} refined query\n */\nexport function refineQueryWithPathname(pathname: string, query: Record<string, string>): Record<string, string> {\n return getDynamicPaths(pathname).reduce((acc, path) => {\n const pathKey = extractPathKey(path)\n const {[pathKey]: _, ...remainingQuery} = acc\n return remainingQuery\n }, query)\n}\n\nconst MAX_ASCII_CODE = 127\nexport function isASCIICodeChar(char: string) {\n return char.charCodeAt(0) > MAX_ASCII_CODE\n}\n","/**\n * Note: The trailing slash in the import path 'punycode/' is intentional.\n * It ensures that this third-party module is used instead of the built-in\n * Node.js 'punycode' module, which has been deprecated since Node.js v7.0.0.\n * @see https://github.com/mathiasbynens/punycode.js#installation\n * @see https://nodejs.org/api/punycode.html for deprecation info\n */\nimport {decode, encode} from 'punycode/'\n\nimport {\n extractPathKey,\n getDynamicPaths,\n isASCIICodeChar,\n isDynamicPath,\n refinePathnameWithQuery,\n refineQueryWithPathname,\n} from './utils'\n\ninterface URLOptions extends Partial<URL> {\n baseUrl?: string\n query?: Record<string, string>\n}\n\nexport default class NURL implements URL {\n private _href: string = ''\n private _protocol: string = ''\n private _host: string = ''\n private _hostname: string = ''\n private _port: string = ''\n private _pathname: string = ''\n private _search: string = ''\n private _hash: string = ''\n private _origin: string = ''\n private _username: string = ''\n private _password: string = ''\n private _baseUrl: string = ''\n private _searchParams: URLSearchParams = new URLSearchParams()\n\n constructor(input?: string | URL | URLOptions) {\n this._searchParams = new URLSearchParams()\n if (typeof input === 'string' || input instanceof URL) {\n this.href = input.toString()\n } else if (input) {\n if (input.baseUrl) {\n this.baseUrl = input.baseUrl\n }\n if (input.href) {\n this.href = input.href\n }\n if (input.protocol) {\n this.protocol = input.protocol\n }\n if (input.host) {\n this.host = input.host\n }\n if (input.hostname) {\n this.hostname = input.hostname\n }\n if (input.port) {\n this.port = input.port\n }\n if (input.pathname) {\n this.pathname = refinePathnameWithQuery(input.pathname, input.query ?? {})\n }\n if (input.search) {\n this.search = input.search\n }\n if (input.hash) {\n this.hash = input.hash\n }\n if (input.username) {\n this.username = input.username\n }\n if (input.password) {\n this.password = input.password\n }\n if (input.query) {\n const refinedQuery = refineQueryWithPathname(input.pathname ?? '', input.query)\n if (Object.keys(refinedQuery).length > 0) {\n this.search = new URLSearchParams(refinedQuery).toString()\n }\n }\n this.updateHref()\n }\n }\n\n static create(input?: string | URL | URLOptions) {\n return new NURL(input)\n }\n\n static canParse(input: string): boolean {\n if (input.startsWith('/')) {\n return /^\\/[^?#]*(\\?[^#]*)?(#.*)?$/.test(input)\n }\n\n try {\n // eslint-disable-next-line no-new\n new URL(input)\n return true\n } catch {\n // URL 생성자로 파싱할 수 없는 경우, 추가적인 검사를 수행\n // 예: 'example.com' 또는 'example.com/path'와 같은 형식 허용\n return /^[^:/?#]+(\\.[^:/?#]+)+(\\/[^?#]*(\\?[^#]*)?(#.*)?)?$/.test(input)\n }\n }\n\n get baseUrl(): string {\n return this._baseUrl\n }\n\n set baseUrl(value: string) {\n this._baseUrl = value\n try {\n const url = new URL(value)\n this._protocol = url.protocol\n this._host = url.host\n this._hostname = url.hostname\n this._port = url.port\n this._origin = url.origin\n this._username = url.username\n this._password = url.password\n if (url.pathname !== '/') {\n this._pathname = url.pathname\n }\n if (url.search) {\n this._search = url.search\n this._searchParams = new URLSearchParams(url.search)\n }\n if (url.hash) {\n this._hash = url.hash\n }\n this.updateHref()\n } catch (error) {\n // eslint-disable-next-line no-console\n console.warn(`Invalid baseUrl: ${value}`, error)\n }\n }\n\n get href(): string {\n return this.pathname.length === 1 ? `${this._href}/` : this._href\n }\n\n set href(value: string) {\n try {\n const url = new URL(value)\n this._href = url.href\n this._protocol = url.protocol\n this._host = url.host\n this._hostname = url.hostname\n this._port = url.port\n this._pathname = url.pathname\n this._search = url.search\n this._hash = url.hash\n this._origin = url.origin\n this._username = url.username\n this._password = url.password\n this._searchParams = url.searchParams\n } catch (error) {\n // eslint-disable-next-line no-console\n console.warn(`Can not parse ${value}`, error)\n }\n }\n\n get protocol(): string {\n return this._protocol\n }\n\n set protocol(value: string) {\n this._protocol = value\n this.updateHref()\n }\n\n get host(): string {\n return this._host\n }\n\n set host(value: string) {\n const [hostname, port] = value.split(':')\n\n const encodedHostname = this.encodeHostname(hostname)\n\n this._host = port ? `${encodedHostname}:${port}` : encodedHostname\n this._hostname = encodedHostname\n this._port = port || ''\n this.updateHref()\n }\n\n get hostname(): string {\n return this._hostname\n }\n\n set hostname(value: string) {\n const encodedHostname = this.encodeHostname(value)\n\n this._hostname = encodedHostname\n this._host = this._port ? `${encodedHostname}:${this._port}` : encodedHostname\n this.updateHref()\n }\n\n get port(): string {\n return this._port\n }\n\n set port(value: string) {\n this._port = value\n this._host = `${this._hostname}${value ? ':' + value : ''}`\n this.updateHref()\n }\n\n get pathname(): string {\n return this._pathname\n }\n\n set pathname(pathname: string) {\n const encodedPathname = pathname\n .split('/')\n .map((segment) => (isDynamicPath(segment) ? segment : encodeURI(segment)))\n .join('/')\n\n this._pathname = encodedPathname.startsWith('/') ? encodedPathname : `/${encodedPathname}`\n this.updateHref()\n }\n\n get search(): string {\n return this._search\n }\n\n set search(search: string) {\n const encodedSearch = encodeURI(search)\n this._search = encodedSearch.startsWith('?') ? encodedSearch : `?${encodedSearch}`\n this._searchParams = new URLSearchParams(encodedSearch)\n this.updateHref()\n }\n\n setSearchParams(_params: Record<string, string>): void {\n const searchParams = new URLSearchParams(_params)\n\n this._search = searchParams.toString() ? `?${searchParams.toString()}` : ''\n this._searchParams = searchParams\n this.updateHref()\n }\n\n appendSearchParams(_params: Record<string, string>): void {\n const searchParams = new URLSearchParams(this._searchParams)\n const dynamicRoutes = getDynamicPaths(this._pathname).map(extractPathKey)\n\n Object.keys(_params).forEach((key) => {\n if (dynamicRoutes.includes(key)) {\n this._pathname = refinePathnameWithQuery(this._pathname, {[key]: _params[key]})\n } else {\n searchParams.append(key, _params[key])\n }\n })\n\n this._search = searchParams.toString() ? `?${searchParams.toString()}` : ''\n this._searchParams = searchParams\n this.updateHref()\n }\n\n removeSearchParams(..._keys: string[]): void {\n const searchParams = new URLSearchParams(this._searchParams)\n\n _keys.forEach((key) => {\n searchParams.delete(key)\n })\n\n this._search = searchParams.toString() ? `?${searchParams.toString()}` : ''\n this._searchParams = searchParams\n this.updateHref()\n }\n\n get searchParams(): URLSearchParams {\n return new Proxy(this._searchParams, {\n get: (target, prop, receiver) => {\n const value = Reflect.get(target, prop, receiver)\n if (typeof value === 'function') {\n return (...args: unknown[]) => {\n const result = value.apply(target, args)\n this._search = this._searchParams.toString() ? `?${this._searchParams.toString()}` : ''\n this.updateHref()\n return result\n }\n }\n return value\n },\n })\n }\n\n get hash(): string {\n return this._hash\n }\n\n set hash(value: string) {\n this._hash = value.startsWith('#') ? value : `#${value}`\n this.updateHref()\n }\n\n get origin(): string {\n return this._origin\n }\n\n get username(): string {\n return this._username\n }\n\n set username(value: string) {\n this._username = value\n this.updateHref()\n }\n\n get password(): string {\n return this._password\n }\n\n set password(value: string) {\n this._password = value\n this.updateHref()\n }\n\n private updateHref() {\n if (this._baseUrl) {\n const baseUrl = new URL(this._baseUrl)\n baseUrl.pathname = this._pathname\n baseUrl.search = this._search\n baseUrl.hash = this._hash\n this._href = baseUrl.href\n this._origin = baseUrl.origin\n } else {\n this._href = `${this._protocol}${this._protocol && '//'}${this._username}${this._password ? ':' + this._password : ''}${\n this._username || this._password ? '@' : ''\n }${this._hostname}${this._port ? ':' + this._port : ''}${this._pathname === '/' ? '' : this._pathname}${this._search}${this._hash}`\n\n this._origin = `${this._protocol}//${this._hostname}${this._port ? ':' + this._port : ''}`\n }\n }\n\n toString(): string {\n return this.href\n }\n\n toJSON(): string {\n return this.href\n }\n\n private punycodePrefix = 'xn--'\n\n private encodeHostname(hostname: string): string {\n return hostname\n .split('.')\n .map((segment) => {\n for (const char of segment) {\n if (isASCIICodeChar(char)) {\n return `${this.punycodePrefix}${encode(segment)}`\n }\n }\n return segment\n })\n .join('.')\n }\n\n get decodedIDN(): string {\n let href = this._href\n\n this._hostname.split('.').forEach((segment) => {\n href = href.replace(segment, decode(segment.replace(this.punycodePrefix, '')))\n })\n\n return href\n }\n\n get decodedHostname(): string {\n return this._hostname\n .split('.')\n .map((segment) => decode(segment.replace(this.punycodePrefix, '')))\n .join('.')\n }\n}\n"],"names":["DYNAMIC_PATH_COLON_REGEXP","DYNAMIC_PATH_BRACKETS_REGEXP","isDynamicPath","path","test","getDynamicPaths","pathname","split","filter","extractPathKey","slice","refinePathnameWithQuery","query","reduce","acc","pathKey","replace","refineQueryWithPathname","_","remainingQuery","MAX_ASCII_CODE","isASCIICodeChar","char","charCodeAt","NURL","constructor","input","_href","_protocol","_host","_hostname","_port","_pathname","_search","_hash","_origin","_username","_password","_baseUrl","_searchParams","URLSearchParams","punycodePrefix","URL","href","toString","baseUrl","protocol","host","hostname","port","search","hash","username","password","refinedQuery","Object","keys","length","updateHref","create","canParse","startsWith","value","url","origin","error","console","warn","searchParams","encodedHostname","encodeHostname","encodedPathname","map","segment","encodeURI","join","encodedSearch","setSearchParams","_params","appendSearchParams","dynamicRoutes","forEach","key","includes","append","removeSearchParams","_keys","delete","Proxy","get","target","prop","receiver","Reflect","args","result","apply","toJSON","encode","decodedIDN","decode","decodedHostname"],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
interface URLOptions extends Partial<URL> {
|
|
2
|
+
baseUrl?: string;
|
|
3
|
+
query?: Record<string, string>;
|
|
4
|
+
}
|
|
5
|
+
declare class NURL implements URL {
|
|
6
|
+
private _href;
|
|
7
|
+
private _protocol;
|
|
8
|
+
private _host;
|
|
9
|
+
private _hostname;
|
|
10
|
+
private _port;
|
|
11
|
+
private _pathname;
|
|
12
|
+
private _search;
|
|
13
|
+
private _hash;
|
|
14
|
+
private _origin;
|
|
15
|
+
private _username;
|
|
16
|
+
private _password;
|
|
17
|
+
private _baseUrl;
|
|
18
|
+
private _searchParams;
|
|
19
|
+
constructor(input?: string | URL | URLOptions);
|
|
20
|
+
static create(input?: string | URL | URLOptions): NURL;
|
|
21
|
+
static canParse(input: string): boolean;
|
|
22
|
+
get baseUrl(): string;
|
|
23
|
+
set baseUrl(value: string);
|
|
24
|
+
get href(): string;
|
|
25
|
+
set href(value: string);
|
|
26
|
+
get protocol(): string;
|
|
27
|
+
set protocol(value: string);
|
|
28
|
+
get host(): string;
|
|
29
|
+
set host(value: string);
|
|
30
|
+
get hostname(): string;
|
|
31
|
+
set hostname(value: string);
|
|
32
|
+
get port(): string;
|
|
33
|
+
set port(value: string);
|
|
34
|
+
get pathname(): string;
|
|
35
|
+
set pathname(pathname: string);
|
|
36
|
+
get search(): string;
|
|
37
|
+
set search(search: string);
|
|
38
|
+
setSearchParams(_params: Record<string, string>): void;
|
|
39
|
+
appendSearchParams(_params: Record<string, string>): void;
|
|
40
|
+
removeSearchParams(..._keys: string[]): void;
|
|
41
|
+
get searchParams(): URLSearchParams;
|
|
42
|
+
get hash(): string;
|
|
43
|
+
set hash(value: string);
|
|
44
|
+
get origin(): string;
|
|
45
|
+
get username(): string;
|
|
46
|
+
set username(value: string);
|
|
47
|
+
get password(): string;
|
|
48
|
+
set password(value: string);
|
|
49
|
+
private updateHref;
|
|
50
|
+
toString(): string;
|
|
51
|
+
toJSON(): string;
|
|
52
|
+
private punycodePrefix;
|
|
53
|
+
private encodeHostname;
|
|
54
|
+
get decodedIDN(): string;
|
|
55
|
+
get decodedHostname(): string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { NURL as default };
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { encode as d, decode as c } from "punycode/";
|
|
2
|
+
const m = /^:/, u = /^\[.*\]$/;
|
|
3
|
+
function f(h) {
|
|
4
|
+
return m.test(h) || u.test(h);
|
|
5
|
+
}
|
|
6
|
+
function i(h) {
|
|
7
|
+
return h.split("/").filter(f);
|
|
8
|
+
}
|
|
9
|
+
function o(h) {
|
|
10
|
+
return h.slice(1, m.test(h) ? void 0 : -1);
|
|
11
|
+
}
|
|
12
|
+
function _(h, t) {
|
|
13
|
+
return i(h).reduce((s, e) => {
|
|
14
|
+
const r = o(e);
|
|
15
|
+
return t[r] ? s.replace(e, t[r]) : s;
|
|
16
|
+
}, h);
|
|
17
|
+
}
|
|
18
|
+
function l(h, t) {
|
|
19
|
+
return i(h).reduce((s, e) => {
|
|
20
|
+
const r = o(e), {
|
|
21
|
+
[r]: n,
|
|
22
|
+
...a
|
|
23
|
+
} = s;
|
|
24
|
+
return a;
|
|
25
|
+
}, t);
|
|
26
|
+
}
|
|
27
|
+
const P = 127;
|
|
28
|
+
function g(h) {
|
|
29
|
+
return h.charCodeAt(0) > P;
|
|
30
|
+
}
|
|
31
|
+
class p {
|
|
32
|
+
constructor(t) {
|
|
33
|
+
if (this._href = "", this._protocol = "", this._host = "", this._hostname = "", this._port = "", this._pathname = "", this._search = "", this._hash = "", this._origin = "", this._username = "", this._password = "", this._baseUrl = "", this._searchParams = new URLSearchParams(), this.punycodePrefix = "xn--", this._searchParams = new URLSearchParams(), typeof t == "string" || t instanceof URL)
|
|
34
|
+
this.href = t.toString();
|
|
35
|
+
else if (t) {
|
|
36
|
+
if (t.baseUrl && (this.baseUrl = t.baseUrl), t.href && (this.href = t.href), t.protocol && (this.protocol = t.protocol), t.host && (this.host = t.host), t.hostname && (this.hostname = t.hostname), t.port && (this.port = t.port), t.pathname && (this.pathname = _(t.pathname, t.query ?? {})), t.search && (this.search = t.search), t.hash && (this.hash = t.hash), t.username && (this.username = t.username), t.password && (this.password = t.password), t.query) {
|
|
37
|
+
const s = l(t.pathname ?? "", t.query);
|
|
38
|
+
Object.keys(s).length > 0 && (this.search = new URLSearchParams(s).toString());
|
|
39
|
+
}
|
|
40
|
+
this.updateHref();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
static create(t) {
|
|
44
|
+
return new p(t);
|
|
45
|
+
}
|
|
46
|
+
static canParse(t) {
|
|
47
|
+
if (t.startsWith("/"))
|
|
48
|
+
return /^\/[^?#]*(\?[^#]*)?(#.*)?$/.test(t);
|
|
49
|
+
try {
|
|
50
|
+
return new URL(t), !0;
|
|
51
|
+
} catch {
|
|
52
|
+
return /^[^:/?#]+(\.[^:/?#]+)+(\/[^?#]*(\?[^#]*)?(#.*)?)?$/.test(t);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
get baseUrl() {
|
|
56
|
+
return this._baseUrl;
|
|
57
|
+
}
|
|
58
|
+
set baseUrl(t) {
|
|
59
|
+
this._baseUrl = t;
|
|
60
|
+
try {
|
|
61
|
+
const s = new URL(t);
|
|
62
|
+
this._protocol = s.protocol, this._host = s.host, this._hostname = s.hostname, this._port = s.port, this._origin = s.origin, this._username = s.username, this._password = s.password, s.pathname !== "/" && (this._pathname = s.pathname), s.search && (this._search = s.search, this._searchParams = new URLSearchParams(s.search)), s.hash && (this._hash = s.hash), this.updateHref();
|
|
63
|
+
} catch (s) {
|
|
64
|
+
console.warn(`Invalid baseUrl: ${t}`, s);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
get href() {
|
|
68
|
+
return this.pathname.length === 1 ? `${this._href}/` : this._href;
|
|
69
|
+
}
|
|
70
|
+
set href(t) {
|
|
71
|
+
try {
|
|
72
|
+
const s = new URL(t);
|
|
73
|
+
this._href = s.href, this._protocol = s.protocol, this._host = s.host, this._hostname = s.hostname, this._port = s.port, this._pathname = s.pathname, this._search = s.search, this._hash = s.hash, this._origin = s.origin, this._username = s.username, this._password = s.password, this._searchParams = s.searchParams;
|
|
74
|
+
} catch (s) {
|
|
75
|
+
console.warn(`Can not parse ${t}`, s);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
get protocol() {
|
|
79
|
+
return this._protocol;
|
|
80
|
+
}
|
|
81
|
+
set protocol(t) {
|
|
82
|
+
this._protocol = t, this.updateHref();
|
|
83
|
+
}
|
|
84
|
+
get host() {
|
|
85
|
+
return this._host;
|
|
86
|
+
}
|
|
87
|
+
set host(t) {
|
|
88
|
+
const [s, e] = t.split(":"), r = this.encodeHostname(s);
|
|
89
|
+
this._host = e ? `${r}:${e}` : r, this._hostname = r, this._port = e || "", this.updateHref();
|
|
90
|
+
}
|
|
91
|
+
get hostname() {
|
|
92
|
+
return this._hostname;
|
|
93
|
+
}
|
|
94
|
+
set hostname(t) {
|
|
95
|
+
const s = this.encodeHostname(t);
|
|
96
|
+
this._hostname = s, this._host = this._port ? `${s}:${this._port}` : s, this.updateHref();
|
|
97
|
+
}
|
|
98
|
+
get port() {
|
|
99
|
+
return this._port;
|
|
100
|
+
}
|
|
101
|
+
set port(t) {
|
|
102
|
+
this._port = t, this._host = `${this._hostname}${t ? ":" + t : ""}`, this.updateHref();
|
|
103
|
+
}
|
|
104
|
+
get pathname() {
|
|
105
|
+
return this._pathname;
|
|
106
|
+
}
|
|
107
|
+
set pathname(t) {
|
|
108
|
+
const s = t.split("/").map((e) => f(e) ? e : encodeURI(e)).join("/");
|
|
109
|
+
this._pathname = s.startsWith("/") ? s : `/${s}`, this.updateHref();
|
|
110
|
+
}
|
|
111
|
+
get search() {
|
|
112
|
+
return this._search;
|
|
113
|
+
}
|
|
114
|
+
set search(t) {
|
|
115
|
+
const s = encodeURI(t);
|
|
116
|
+
this._search = s.startsWith("?") ? s : `?${s}`, this._searchParams = new URLSearchParams(s), this.updateHref();
|
|
117
|
+
}
|
|
118
|
+
setSearchParams(t) {
|
|
119
|
+
const s = new URLSearchParams(t);
|
|
120
|
+
this._search = s.toString() ? `?${s.toString()}` : "", this._searchParams = s, this.updateHref();
|
|
121
|
+
}
|
|
122
|
+
appendSearchParams(t) {
|
|
123
|
+
const s = new URLSearchParams(this._searchParams), e = i(this._pathname).map(o);
|
|
124
|
+
Object.keys(t).forEach((r) => {
|
|
125
|
+
e.includes(r) ? this._pathname = _(this._pathname, {
|
|
126
|
+
[r]: t[r]
|
|
127
|
+
}) : s.append(r, t[r]);
|
|
128
|
+
}), this._search = s.toString() ? `?${s.toString()}` : "", this._searchParams = s, this.updateHref();
|
|
129
|
+
}
|
|
130
|
+
removeSearchParams(...t) {
|
|
131
|
+
const s = new URLSearchParams(this._searchParams);
|
|
132
|
+
t.forEach((e) => {
|
|
133
|
+
s.delete(e);
|
|
134
|
+
}), this._search = s.toString() ? `?${s.toString()}` : "", this._searchParams = s, this.updateHref();
|
|
135
|
+
}
|
|
136
|
+
get searchParams() {
|
|
137
|
+
return new Proxy(this._searchParams, {
|
|
138
|
+
get: (t, s, e) => {
|
|
139
|
+
const r = Reflect.get(t, s, e);
|
|
140
|
+
return typeof r == "function" ? (...n) => {
|
|
141
|
+
const a = r.apply(t, n);
|
|
142
|
+
return this._search = this._searchParams.toString() ? `?${this._searchParams.toString()}` : "", this.updateHref(), a;
|
|
143
|
+
} : r;
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
get hash() {
|
|
148
|
+
return this._hash;
|
|
149
|
+
}
|
|
150
|
+
set hash(t) {
|
|
151
|
+
this._hash = t.startsWith("#") ? t : `#${t}`, this.updateHref();
|
|
152
|
+
}
|
|
153
|
+
get origin() {
|
|
154
|
+
return this._origin;
|
|
155
|
+
}
|
|
156
|
+
get username() {
|
|
157
|
+
return this._username;
|
|
158
|
+
}
|
|
159
|
+
set username(t) {
|
|
160
|
+
this._username = t, this.updateHref();
|
|
161
|
+
}
|
|
162
|
+
get password() {
|
|
163
|
+
return this._password;
|
|
164
|
+
}
|
|
165
|
+
set password(t) {
|
|
166
|
+
this._password = t, this.updateHref();
|
|
167
|
+
}
|
|
168
|
+
updateHref() {
|
|
169
|
+
if (this._baseUrl) {
|
|
170
|
+
const t = new URL(this._baseUrl);
|
|
171
|
+
t.pathname = this._pathname, t.search = this._search, t.hash = this._hash, this._href = t.href, this._origin = t.origin;
|
|
172
|
+
} else
|
|
173
|
+
this._href = `${this._protocol}${this._protocol && "//"}${this._username}${this._password ? ":" + this._password : ""}${this._username || this._password ? "@" : ""}${this._hostname}${this._port ? ":" + this._port : ""}${this._pathname === "/" ? "" : this._pathname}${this._search}${this._hash}`, this._origin = `${this._protocol}//${this._hostname}${this._port ? ":" + this._port : ""}`;
|
|
174
|
+
}
|
|
175
|
+
toString() {
|
|
176
|
+
return this.href;
|
|
177
|
+
}
|
|
178
|
+
toJSON() {
|
|
179
|
+
return this.href;
|
|
180
|
+
}
|
|
181
|
+
encodeHostname(t) {
|
|
182
|
+
return t.split(".").map((s) => {
|
|
183
|
+
for (const e of s)
|
|
184
|
+
if (g(e))
|
|
185
|
+
return `${this.punycodePrefix}${d(s)}`;
|
|
186
|
+
return s;
|
|
187
|
+
}).join(".");
|
|
188
|
+
}
|
|
189
|
+
get decodedIDN() {
|
|
190
|
+
let t = this._href;
|
|
191
|
+
return this._hostname.split(".").forEach((s) => {
|
|
192
|
+
t = t.replace(s, c(s.replace(this.punycodePrefix, "")));
|
|
193
|
+
}), t;
|
|
194
|
+
}
|
|
195
|
+
get decodedHostname() {
|
|
196
|
+
return this._hostname.split(".").map((t) => c(t.replace(this.punycodePrefix, ""))).join(".");
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
export {
|
|
200
|
+
p as default
|
|
201
|
+
};
|
|
202
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../src/utils.ts","../../src/nurl.ts"],"sourcesContent":["const DYNAMIC_PATH_COLON_REGEXP = /^:/\nconst DYNAMIC_PATH_BRACKETS_REGEXP = /^\\[.*\\]$/\n\nexport function isDynamicPath(path: string) {\n return DYNAMIC_PATH_COLON_REGEXP.test(path) || DYNAMIC_PATH_BRACKETS_REGEXP.test(path)\n}\n\nexport function getDynamicPaths(pathname: string): string[] {\n return pathname.split('/').filter(isDynamicPath)\n}\n\nexport function extractPathKey(path: string): string {\n return path.slice(1, DYNAMIC_PATH_COLON_REGEXP.test(path) ? undefined : -1)\n}\n\n/**\n * Replaces dynamic paths in the pathname with values from the query\n * @param {string} pathname\n * @param {Record<string, string>} query\n * @returns {string} refined pathname\n */\nexport function refinePathnameWithQuery(pathname: string, query: Record<string, string>): string {\n return getDynamicPaths(pathname).reduce((acc, path) => {\n const pathKey = extractPathKey(path)\n return query[pathKey] ? acc.replace(path, query[pathKey]) : acc\n }, pathname)\n}\n\n/**\n * Removes queries that have already been used in the pathname.\n * @param {string} pathname\n * @param {Record<string, string>} query\n * @returns {Record<string, string>} refined query\n */\nexport function refineQueryWithPathname(pathname: string, query: Record<string, string>): Record<string, string> {\n return getDynamicPaths(pathname).reduce((acc, path) => {\n const pathKey = extractPathKey(path)\n const {[pathKey]: _, ...remainingQuery} = acc\n return remainingQuery\n }, query)\n}\n\nconst MAX_ASCII_CODE = 127\nexport function isASCIICodeChar(char: string) {\n return char.charCodeAt(0) > MAX_ASCII_CODE\n}\n","/**\n * Note: The trailing slash in the import path 'punycode/' is intentional.\n * It ensures that this third-party module is used instead of the built-in\n * Node.js 'punycode' module, which has been deprecated since Node.js v7.0.0.\n * @see https://github.com/mathiasbynens/punycode.js#installation\n * @see https://nodejs.org/api/punycode.html for deprecation info\n */\nimport {decode, encode} from 'punycode/'\n\nimport {\n extractPathKey,\n getDynamicPaths,\n isASCIICodeChar,\n isDynamicPath,\n refinePathnameWithQuery,\n refineQueryWithPathname,\n} from './utils'\n\ninterface URLOptions extends Partial<URL> {\n baseUrl?: string\n query?: Record<string, string>\n}\n\nexport default class NURL implements URL {\n private _href: string = ''\n private _protocol: string = ''\n private _host: string = ''\n private _hostname: string = ''\n private _port: string = ''\n private _pathname: string = ''\n private _search: string = ''\n private _hash: string = ''\n private _origin: string = ''\n private _username: string = ''\n private _password: string = ''\n private _baseUrl: string = ''\n private _searchParams: URLSearchParams = new URLSearchParams()\n\n constructor(input?: string | URL | URLOptions) {\n this._searchParams = new URLSearchParams()\n if (typeof input === 'string' || input instanceof URL) {\n this.href = input.toString()\n } else if (input) {\n if (input.baseUrl) {\n this.baseUrl = input.baseUrl\n }\n if (input.href) {\n this.href = input.href\n }\n if (input.protocol) {\n this.protocol = input.protocol\n }\n if (input.host) {\n this.host = input.host\n }\n if (input.hostname) {\n this.hostname = input.hostname\n }\n if (input.port) {\n this.port = input.port\n }\n if (input.pathname) {\n this.pathname = refinePathnameWithQuery(input.pathname, input.query ?? {})\n }\n if (input.search) {\n this.search = input.search\n }\n if (input.hash) {\n this.hash = input.hash\n }\n if (input.username) {\n this.username = input.username\n }\n if (input.password) {\n this.password = input.password\n }\n if (input.query) {\n const refinedQuery = refineQueryWithPathname(input.pathname ?? '', input.query)\n if (Object.keys(refinedQuery).length > 0) {\n this.search = new URLSearchParams(refinedQuery).toString()\n }\n }\n this.updateHref()\n }\n }\n\n static create(input?: string | URL | URLOptions) {\n return new NURL(input)\n }\n\n static canParse(input: string): boolean {\n if (input.startsWith('/')) {\n return /^\\/[^?#]*(\\?[^#]*)?(#.*)?$/.test(input)\n }\n\n try {\n // eslint-disable-next-line no-new\n new URL(input)\n return true\n } catch {\n // URL 생성자로 파싱할 수 없는 경우, 추가적인 검사를 수행\n // 예: 'example.com' 또는 'example.com/path'와 같은 형식 허용\n return /^[^:/?#]+(\\.[^:/?#]+)+(\\/[^?#]*(\\?[^#]*)?(#.*)?)?$/.test(input)\n }\n }\n\n get baseUrl(): string {\n return this._baseUrl\n }\n\n set baseUrl(value: string) {\n this._baseUrl = value\n try {\n const url = new URL(value)\n this._protocol = url.protocol\n this._host = url.host\n this._hostname = url.hostname\n this._port = url.port\n this._origin = url.origin\n this._username = url.username\n this._password = url.password\n if (url.pathname !== '/') {\n this._pathname = url.pathname\n }\n if (url.search) {\n this._search = url.search\n this._searchParams = new URLSearchParams(url.search)\n }\n if (url.hash) {\n this._hash = url.hash\n }\n this.updateHref()\n } catch (error) {\n // eslint-disable-next-line no-console\n console.warn(`Invalid baseUrl: ${value}`, error)\n }\n }\n\n get href(): string {\n return this.pathname.length === 1 ? `${this._href}/` : this._href\n }\n\n set href(value: string) {\n try {\n const url = new URL(value)\n this._href = url.href\n this._protocol = url.protocol\n this._host = url.host\n this._hostname = url.hostname\n this._port = url.port\n this._pathname = url.pathname\n this._search = url.search\n this._hash = url.hash\n this._origin = url.origin\n this._username = url.username\n this._password = url.password\n this._searchParams = url.searchParams\n } catch (error) {\n // eslint-disable-next-line no-console\n console.warn(`Can not parse ${value}`, error)\n }\n }\n\n get protocol(): string {\n return this._protocol\n }\n\n set protocol(value: string) {\n this._protocol = value\n this.updateHref()\n }\n\n get host(): string {\n return this._host\n }\n\n set host(value: string) {\n const [hostname, port] = value.split(':')\n\n const encodedHostname = this.encodeHostname(hostname)\n\n this._host = port ? `${encodedHostname}:${port}` : encodedHostname\n this._hostname = encodedHostname\n this._port = port || ''\n this.updateHref()\n }\n\n get hostname(): string {\n return this._hostname\n }\n\n set hostname(value: string) {\n const encodedHostname = this.encodeHostname(value)\n\n this._hostname = encodedHostname\n this._host = this._port ? `${encodedHostname}:${this._port}` : encodedHostname\n this.updateHref()\n }\n\n get port(): string {\n return this._port\n }\n\n set port(value: string) {\n this._port = value\n this._host = `${this._hostname}${value ? ':' + value : ''}`\n this.updateHref()\n }\n\n get pathname(): string {\n return this._pathname\n }\n\n set pathname(pathname: string) {\n const encodedPathname = pathname\n .split('/')\n .map((segment) => (isDynamicPath(segment) ? segment : encodeURI(segment)))\n .join('/')\n\n this._pathname = encodedPathname.startsWith('/') ? encodedPathname : `/${encodedPathname}`\n this.updateHref()\n }\n\n get search(): string {\n return this._search\n }\n\n set search(search: string) {\n const encodedSearch = encodeURI(search)\n this._search = encodedSearch.startsWith('?') ? encodedSearch : `?${encodedSearch}`\n this._searchParams = new URLSearchParams(encodedSearch)\n this.updateHref()\n }\n\n setSearchParams(_params: Record<string, string>): void {\n const searchParams = new URLSearchParams(_params)\n\n this._search = searchParams.toString() ? `?${searchParams.toString()}` : ''\n this._searchParams = searchParams\n this.updateHref()\n }\n\n appendSearchParams(_params: Record<string, string>): void {\n const searchParams = new URLSearchParams(this._searchParams)\n const dynamicRoutes = getDynamicPaths(this._pathname).map(extractPathKey)\n\n Object.keys(_params).forEach((key) => {\n if (dynamicRoutes.includes(key)) {\n this._pathname = refinePathnameWithQuery(this._pathname, {[key]: _params[key]})\n } else {\n searchParams.append(key, _params[key])\n }\n })\n\n this._search = searchParams.toString() ? `?${searchParams.toString()}` : ''\n this._searchParams = searchParams\n this.updateHref()\n }\n\n removeSearchParams(..._keys: string[]): void {\n const searchParams = new URLSearchParams(this._searchParams)\n\n _keys.forEach((key) => {\n searchParams.delete(key)\n })\n\n this._search = searchParams.toString() ? `?${searchParams.toString()}` : ''\n this._searchParams = searchParams\n this.updateHref()\n }\n\n get searchParams(): URLSearchParams {\n return new Proxy(this._searchParams, {\n get: (target, prop, receiver) => {\n const value = Reflect.get(target, prop, receiver)\n if (typeof value === 'function') {\n return (...args: unknown[]) => {\n const result = value.apply(target, args)\n this._search = this._searchParams.toString() ? `?${this._searchParams.toString()}` : ''\n this.updateHref()\n return result\n }\n }\n return value\n },\n })\n }\n\n get hash(): string {\n return this._hash\n }\n\n set hash(value: string) {\n this._hash = value.startsWith('#') ? value : `#${value}`\n this.updateHref()\n }\n\n get origin(): string {\n return this._origin\n }\n\n get username(): string {\n return this._username\n }\n\n set username(value: string) {\n this._username = value\n this.updateHref()\n }\n\n get password(): string {\n return this._password\n }\n\n set password(value: string) {\n this._password = value\n this.updateHref()\n }\n\n private updateHref() {\n if (this._baseUrl) {\n const baseUrl = new URL(this._baseUrl)\n baseUrl.pathname = this._pathname\n baseUrl.search = this._search\n baseUrl.hash = this._hash\n this._href = baseUrl.href\n this._origin = baseUrl.origin\n } else {\n this._href = `${this._protocol}${this._protocol && '//'}${this._username}${this._password ? ':' + this._password : ''}${\n this._username || this._password ? '@' : ''\n }${this._hostname}${this._port ? ':' + this._port : ''}${this._pathname === '/' ? '' : this._pathname}${this._search}${this._hash}`\n\n this._origin = `${this._protocol}//${this._hostname}${this._port ? ':' + this._port : ''}`\n }\n }\n\n toString(): string {\n return this.href\n }\n\n toJSON(): string {\n return this.href\n }\n\n private punycodePrefix = 'xn--'\n\n private encodeHostname(hostname: string): string {\n return hostname\n .split('.')\n .map((segment) => {\n for (const char of segment) {\n if (isASCIICodeChar(char)) {\n return `${this.punycodePrefix}${encode(segment)}`\n }\n }\n return segment\n })\n .join('.')\n }\n\n get decodedIDN(): string {\n let href = this._href\n\n this._hostname.split('.').forEach((segment) => {\n href = href.replace(segment, decode(segment.replace(this.punycodePrefix, '')))\n })\n\n return href\n }\n\n get decodedHostname(): string {\n return this._hostname\n .split('.')\n .map((segment) => decode(segment.replace(this.punycodePrefix, '')))\n .join('.')\n }\n}\n"],"names":["DYNAMIC_PATH_COLON_REGEXP","DYNAMIC_PATH_BRACKETS_REGEXP","isDynamicPath","path","test","getDynamicPaths","pathname","split","filter","extractPathKey","slice","refinePathnameWithQuery","query","reduce","acc","pathKey","replace","refineQueryWithPathname","_","remainingQuery","MAX_ASCII_CODE","isASCIICodeChar","char","charCodeAt","NURL","constructor","input","_href","_protocol","_host","_hostname","_port","_pathname","_search","_hash","_origin","_username","_password","_baseUrl","_searchParams","URLSearchParams","punycodePrefix","URL","href","toString","baseUrl","protocol","host","hostname","port","search","hash","username","password","refinedQuery","Object","keys","length","updateHref","create","canParse","startsWith","value","url","origin","error","console","warn","searchParams","encodedHostname","encodeHostname","encodedPathname","map","segment","encodeURI","join","encodedSearch","setSearchParams","_params","appendSearchParams","dynamicRoutes","forEach","key","includes","append","removeSearchParams","_keys","delete","Proxy","get","target","prop","receiver","Reflect","args","result","apply","toJSON","encode","decodedIDN","decode","decodedHostname"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@naverpay/nurl",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "URL build library",
|
|
5
|
+
"main": "./dist/cjs/index.js",
|
|
6
|
+
"module": "./dist/module/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": {
|
|
10
|
+
"types": "./dist/esm/index.d.mts",
|
|
11
|
+
"default": "./dist/esm/index.mjs"
|
|
12
|
+
},
|
|
13
|
+
"require": {
|
|
14
|
+
"types": "./dist/cjs/index.d.ts",
|
|
15
|
+
"default": "./dist/cjs/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"./package.json": "./package.json"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"keywords": [
|
|
25
|
+
"url",
|
|
26
|
+
"uri"
|
|
27
|
+
],
|
|
28
|
+
"author": "@NaverPayDev/frontend",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "https://github.com/NaverPayDev/nurl.git"
|
|
32
|
+
},
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@babel/runtime-corejs3": "^7.25.6",
|
|
36
|
+
"punycode": "^2.3.1"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@babel/plugin-transform-runtime": "^7.25.4",
|
|
40
|
+
"@babel/preset-env": "^7.25.4",
|
|
41
|
+
"@babel/runtime-corejs3": "^7.25.6",
|
|
42
|
+
"@changesets/cli": "^2.27.7",
|
|
43
|
+
"@naverpay/browserslist-config": "^1.6.1",
|
|
44
|
+
"@naverpay/editorconfig": "^0.0.4",
|
|
45
|
+
"@naverpay/eslint-config": "^1.0.7",
|
|
46
|
+
"@naverpay/markdown-lint": "^0.0.3",
|
|
47
|
+
"@naverpay/prettier-config": "^1.0.0",
|
|
48
|
+
"@rollup/plugin-babel": "^6.0.4",
|
|
49
|
+
"@types/punycode": "^2.1.4",
|
|
50
|
+
"browserslist-to-esbuild": "^2.1.1",
|
|
51
|
+
"tsup": "^8.2.4",
|
|
52
|
+
"typescript": "^5.5.4",
|
|
53
|
+
"vite": "^5.4.3",
|
|
54
|
+
"vitest": "^2.0.5"
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"clean": "rm -rf dist",
|
|
58
|
+
"build": "pnpm clean && vite build -c vite.config.mts && pnpm build-declarations",
|
|
59
|
+
"build-declarations:cjs": "tsup src/index.ts --format cjs --dts-only --out-dir ./dist/cjs --minify",
|
|
60
|
+
"build-declarations:esm": "tsup src/index.ts --format esm --dts-only --out-dir ./dist/esm --minify",
|
|
61
|
+
"build-declarations": "pnpm build-declarations:cjs && pnpm build-declarations:esm",
|
|
62
|
+
"test": "vitest run",
|
|
63
|
+
"test:watch": "vitest watch",
|
|
64
|
+
"lint": "eslint '**/*.{js,jsx,ts,tsx}'",
|
|
65
|
+
"lint:fix": "pnpm run lint --fix",
|
|
66
|
+
"prettier": "prettier --check '**/*.{json,yaml,md,ts,tsx,js,jsx}'",
|
|
67
|
+
"prettier:fix": "prettier --write '**/*.{json,yaml,md,ts,tsx,js,jsx}'",
|
|
68
|
+
"release": "changeset publish",
|
|
69
|
+
"markdownlint": "markdownlint '**/*.md' '#.changeset' '#**/CHANGELOG.md'",
|
|
70
|
+
"markdownlint:fix": "markdownlint --fix '**/*.md' '#.changeset' '#**/CHANGELOG.md'"
|
|
71
|
+
}
|
|
72
|
+
}
|