@naverpay/nurl 1.0.3-rc.251117-e85b322 → 1.1.0-canary.251230-92343a8
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/README.md +84 -14
- package/dist/cjs/index.d.ts +9 -0
- package/dist/cjs/nurl.js +1 -1
- package/dist/cjs/utils.js +1 -1
- package/dist/esm/index.d.mts +9 -0
- package/dist/esm/nurl.mjs +80 -43
- package/dist/esm/utils.mjs +43 -39
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ NURL is a powerful URL manipulation library that extends the standard URL class.
|
|
|
25
25
|
### Basic Usage
|
|
26
26
|
|
|
27
27
|
```javascript
|
|
28
|
-
import {
|
|
28
|
+
import {NURL} from 'nurl'
|
|
29
29
|
|
|
30
30
|
// Create URL from string
|
|
31
31
|
const url1 = new NURL('https://example.com/users/123?name=John')
|
|
@@ -36,9 +36,9 @@ const url2 = new NURL(standardUrl)
|
|
|
36
36
|
|
|
37
37
|
// Create URL from custom options object
|
|
38
38
|
const url3 = new NURL({
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
baseUrl: 'https://example.com',
|
|
40
|
+
pathname: '/users/:id',
|
|
41
|
+
query: {id: '123', name: 'John'},
|
|
42
42
|
})
|
|
43
43
|
|
|
44
44
|
// Create empty URL
|
|
@@ -49,9 +49,9 @@ const url5 = NURL.create('https://example.com')
|
|
|
49
49
|
|
|
50
50
|
// The factory function also works with options object
|
|
51
51
|
const url6 = NURL.create({
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
baseUrl: 'https://example.com',
|
|
53
|
+
pathname: '/users/:id',
|
|
54
|
+
query: {id: '123', name: 'John'},
|
|
55
55
|
})
|
|
56
56
|
```
|
|
57
57
|
|
|
@@ -61,13 +61,13 @@ NURL processes dynamic segments in the pathname and replaces them with values fr
|
|
|
61
61
|
|
|
62
62
|
```javascript
|
|
63
63
|
const url = new NURL({
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
71
|
})
|
|
72
72
|
|
|
73
73
|
console.log(url.href)
|
|
@@ -84,6 +84,59 @@ console.log(url.hostname) // xn--bj0bj06e.xn--hq1bm8jm9l
|
|
|
84
84
|
console.log(url.decodedHostname) // 한글.도메인 (in human-readable format)
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
+
### URL Pattern Matching
|
|
88
|
+
|
|
89
|
+
NURL supports `NURL.match(url, pattern)` static method to match a URL path against a pattern with dynamic segments:
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
NURL.match('/v1/user/12345/info', '/v1/user/:userId/info')
|
|
93
|
+
// → { userId: '12345' }
|
|
94
|
+
|
|
95
|
+
NURL.match('/v1/friends/SENDMONEY/block/111/222', '/v1/friends/:serviceCode/block/:nidNo/:friendNidNo')
|
|
96
|
+
// → { serviceCode: 'SENDMONEY', nidNo: '111', friendNidNo: '222' }
|
|
97
|
+
|
|
98
|
+
NURL.match('/v1/user/12345', '/v1/admin/:id')
|
|
99
|
+
// → null (no match)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Masking Path Parameters
|
|
103
|
+
|
|
104
|
+
NURL provides `NURL.mask(url, options)` static method to mask sensitive path parameters in a URL for logging purposes:
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
// Default masking (**** with length 4)
|
|
108
|
+
NURL.mask('/v1/user/12345/info', {
|
|
109
|
+
patterns: ['/v1/user/:userId/info'],
|
|
110
|
+
sensitiveParams: ['userId'],
|
|
111
|
+
})
|
|
112
|
+
// → '/v1/user/****/info'
|
|
113
|
+
|
|
114
|
+
// Custom mask character and length
|
|
115
|
+
NURL.mask('/v1/user/12345/info', {
|
|
116
|
+
patterns: ['/v1/user/[userId]/info'],
|
|
117
|
+
sensitiveParams: ['userId'],
|
|
118
|
+
maskChar: 'X',
|
|
119
|
+
maskLength: 6,
|
|
120
|
+
})
|
|
121
|
+
// → '/v1/user/XXXXXX/info'
|
|
122
|
+
|
|
123
|
+
// Preserve original value length
|
|
124
|
+
NURL.mask('/v1/user/12345/info', {
|
|
125
|
+
patterns: ['/v1/user/:userId/info'],
|
|
126
|
+
sensitiveParams: ['userId'],
|
|
127
|
+
preserveLength: true,
|
|
128
|
+
})
|
|
129
|
+
// → '/v1/user/*****/info' (5 chars, same as '12345')
|
|
130
|
+
|
|
131
|
+
// Multiple sensitive params
|
|
132
|
+
NURL.mask('/v1/friends/SENDMONEY/block/12345/67890', {
|
|
133
|
+
patterns: ['/v1/friends/:serviceCode/block/[nidNo]/:friendNidNo'],
|
|
134
|
+
sensitiveParams: ['nidNo', 'friendNidNo'],
|
|
135
|
+
preserveLength: true,
|
|
136
|
+
})
|
|
137
|
+
// → '/v1/friends/SENDMONEY/block/*****/*****' (5 and 5 chars)
|
|
138
|
+
```
|
|
139
|
+
|
|
87
140
|
## API
|
|
88
141
|
|
|
89
142
|
### `constructor(input?: string | URL | URLOptions)`
|
|
@@ -113,6 +166,23 @@ NURL inherits all properties from the standard URL class:
|
|
|
113
166
|
- `toString()`: Returns the URL as a string
|
|
114
167
|
- `toJSON()`: Returns the URL as a JSON representation
|
|
115
168
|
|
|
169
|
+
### Static Methods
|
|
170
|
+
|
|
171
|
+
- `NURL.create(input?: string | URL | URLOptions): NURL`
|
|
172
|
+
- Factory function to create a NURL instance without the `new` keyword.
|
|
173
|
+
- `NURL.canParse(url: string): boolean`
|
|
174
|
+
- Checks if the given string can be parsed as a valid URL.
|
|
175
|
+
- `NURL.match(url: string, pattern: string): Record<string, string> | null`
|
|
176
|
+
- Matches a URL path against a pattern with dynamic segments and returns an object with extracted parameters or `null` if no match.
|
|
177
|
+
- `NURL.mask(url: string, options: MaskOptions): string`
|
|
178
|
+
- Masks sensitive path parameters in a URL based on the provided options.
|
|
179
|
+
- `MaskOptions`:
|
|
180
|
+
- `patterns: string[]`: Array of URL patterns with dynamic segments.
|
|
181
|
+
- `sensitiveParams: string[]`: Array of path parameters to be masked.
|
|
182
|
+
- `maskChar?: string`: Character used for masking (default: `'*'`).
|
|
183
|
+
- `maskLength?: number`: Length of the mask (default: `4`).
|
|
184
|
+
- `preserveLength?: boolean`: If true, mask length matches original value length (overrides `maskLength`).
|
|
185
|
+
|
|
116
186
|
## Important Notes
|
|
117
187
|
|
|
118
188
|
1. NURL's setter methods behave differently from the standard URL. They are designed to consider dynamic segment and query parameter replacement functionality.
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -5,6 +5,13 @@ interface URLOptions extends Partial<Pick<URL, 'href' | 'protocol' | 'host' | 'h
|
|
|
5
5
|
query?: Query;
|
|
6
6
|
basePath?: string;
|
|
7
7
|
}
|
|
8
|
+
interface MaskOptions {
|
|
9
|
+
patterns: string[];
|
|
10
|
+
sensitiveParams: string[];
|
|
11
|
+
maskChar?: string;
|
|
12
|
+
maskLength?: number;
|
|
13
|
+
preserveLength?: boolean;
|
|
14
|
+
}
|
|
8
15
|
declare class NURL implements URL {
|
|
9
16
|
private _href;
|
|
10
17
|
private _protocol;
|
|
@@ -72,6 +79,8 @@ declare class NURL implements URL {
|
|
|
72
79
|
private encodeHostname;
|
|
73
80
|
get decodedIDN(): string;
|
|
74
81
|
get decodedHostname(): string;
|
|
82
|
+
static match(url: string, pattern: string): Record<string, string> | null;
|
|
83
|
+
static mask(url: string, { patterns, sensitiveParams, maskChar, maskLength, preserveLength }: MaskOptions): string;
|
|
75
84
|
}
|
|
76
85
|
|
|
77
86
|
export { NURL as default };
|
package/dist/cjs/nurl.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";const
|
|
1
|
+
"use strict";const l=require("./punycode.js"),a=require("./utils.js");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._basePath="",this.punycodePrefix="xn--",this._searchParams=new URLSearchParams,typeof t=="string"||t instanceof URL)this.href=t.toString();else if(t){if(t.basePath&&(this._basePath=t.basePath.startsWith("/")?t.basePath:`/${t.basePath}`),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!==void 0&&(t.pathname===""?this._pathname="":this.pathname=a.refinePathnameWithQuery(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=a.refineQueryWithPathname(t.pathname??"",t.query);Object.keys(s).length>0&&(this.search=new URLSearchParams(a.convertQueryToArray(s)).toString())}this.updateHref()}}static withBasePath(t){return s=>typeof s=="string"||s instanceof URL?new c({href:s.toString(),basePath:t}):new c({...s,basePath:t})}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._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){const e=c.parseStringToURLLike(t);if(!e)throw console.warn(`Can not parse ${t}`),s;this._href=e.href,this._protocol=e.protocol,this._host=e.hostname,this._hostname=e.hostname,this._port=e.port,this._pathname=e.pathname,this._search=e.search,this._hash=e.hash,this._origin=e.origin,this._username=e.username,this._password=e.password,this._searchParams=e.searchParams}}static parseStringToURLLike(t){const s=/^(?:(https?:\/\/)(?:([^:@]+)(?::([^@]+))?@)?((?:[^/:?#]+)(?::(\d+))?)?)?([/][^?#]*)?(\?[^#]*)?(#.*)?$/,e=t.match(s),[r=t,i="",n="",_="",h="",o="",m="",p="",f=""]=e||[];if(!e||i&&!h&&!m&&!p&&!f)return null;const d=i&&h?`${i}//${h}${o?`:${o}`:""}`:"";return{href:r,protocol:i,host:h,hostname:h,port:o,pathname:t?m||"/":"",search:p,hash:f,origin:d,username:n,password:_,searchParams:new URLSearchParams(p)}}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){let s=t;if(t===""){s="/",this._pathname=s,this.updateHref();return}this._basePath&&!s.startsWith(this._basePath)&&(s=`${this._basePath}${s.startsWith("/")?"":"/"}${s}`);const e=s.split("/").map(r=>a.isDynamicPath(r)?r:encodeURI(r)).join("/");this._pathname=e.startsWith("/")?e:`/${e}`,this.updateHref()}get search(){return this._search}set search(t){this._search=t.startsWith("?")?t:`?${t}`,this._searchParams=new URLSearchParams(t),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=a.getDynamicPaths(this._pathname).map(a.extractPathKey);Object.keys(t).forEach(r=>{e.includes(r)?this._pathname=a.refinePathnameWithQuery(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"?(...i)=>{const n=r.apply(t,i);return this._search=this._searchParams.toString()?`?${this._searchParams.toString()}`:"",this.updateHref(),n}: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(){const t=this._pathname;if(this._baseUrl){const s=new URL(this._baseUrl);s.pathname=t,s.search=this._search,s.hash=this._hash,this._href=s.href,this._origin=s.origin}else this._href=`${this._protocol}${this._protocol&&"//"}${this._username}${this._password?":"+this._password:""}${this._username||this._password?"@":""}${this._hostname}${this._port?":"+this._port:""}${t}${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(a.isASCIICodeChar(e))return`${this.punycodePrefix}${l.encode(s)}`;return s}).join(".")}get decodedIDN(){let t=this._href;return this._hostname.split(".").forEach(s=>{t=t.replace(s,l.decode(s.replace(this.punycodePrefix,"")))}),t}get decodedHostname(){return this._hostname.split(".").map(t=>l.decode(t.replace(this.punycodePrefix,""))).join(".")}static match(t,s){if(!c.canParse(t)||!c.canParse(s))return null;const e=t.split(/[?#]/)[0]?.split("/").filter(Boolean)||[],r=s.split(/[?#]/)[0]?.split("/").filter(Boolean)||[];if(e.length!==r.length)return null;const i={};for(let n=0;n<r.length;n++){const _=r[n],h=e[n];if(a.isDynamicPath(_)){const o=a.extractPathKey(_);i[o]=h}else if(_!==h)return null}return i}static mask(t,{patterns:s,sensitiveParams:e,maskChar:r="*",maskLength:i=4,preserveLength:n=!1}){const _=[...s].sort((h,o)=>a.getPathPriority(o)>a.getPathPriority(h)?1:-1);for(const h of _){const o=c.create(t),m=c.match(o.pathname,h);if(m)return e.forEach(p=>{if(p in m){const f=m[p],d=n?f.length:i;m[p]=r.repeat(d)}}),o.pathname=a.refinePathnameWithQuery(h,m),o.toString()}return t}}module.exports=c;
|
package/dist/cjs/utils.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=/^:/,P=/^\[.*\]$/;function o(t){return y.test(t)||P.test(t)}function s(t){return t.split("/").filter(o)}function a(t){return t.slice(1,y.test(t)?void 0:-1)}function h(t,r){return s(t).reduce((e,n)=>{const i=a(n),u=r[i];return u&&typeof u=="string"?e.replace(n,u):e},t)}function m(t,r){return s(t).reduce((e,n)=>{const i=a(n);if(typeof e[i]!="string")return e;const{[i]:d,...f}=e;return f},r)}const g=127;function A(t){return t.charCodeAt(0)>g}function c(t){return["string","number","boolean"].includes(typeof t)}function l(t){return Object.entries(t).flatMap(([r,e])=>c(e)?[[r,String(e)]]:Array.isArray(e)&&e.every(c)?e.map(n=>[r,String(n)]):[])}function C(t){return t.split("/").filter(Boolean).map(e=>o(e)?"1":"2").join("")}exports.convertQueryToArray=l;exports.extractPathKey=a;exports.getDynamicPaths=s;exports.getPathPriority=C;exports.isASCIICodeChar=A;exports.isDynamicPath=o;exports.refinePathnameWithQuery=h;exports.refineQueryWithPathname=m;
|
package/dist/esm/index.d.mts
CHANGED
|
@@ -5,6 +5,13 @@ interface URLOptions extends Partial<Pick<URL, 'href' | 'protocol' | 'host' | 'h
|
|
|
5
5
|
query?: Query;
|
|
6
6
|
basePath?: string;
|
|
7
7
|
}
|
|
8
|
+
interface MaskOptions {
|
|
9
|
+
patterns: string[];
|
|
10
|
+
sensitiveParams: string[];
|
|
11
|
+
maskChar?: string;
|
|
12
|
+
maskLength?: number;
|
|
13
|
+
preserveLength?: boolean;
|
|
14
|
+
}
|
|
8
15
|
declare class NURL implements URL {
|
|
9
16
|
private _href;
|
|
10
17
|
private _protocol;
|
|
@@ -72,6 +79,8 @@ declare class NURL implements URL {
|
|
|
72
79
|
private encodeHostname;
|
|
73
80
|
get decodedIDN(): string;
|
|
74
81
|
get decodedHostname(): string;
|
|
82
|
+
static match(url: string, pattern: string): Record<string, string> | null;
|
|
83
|
+
static mask(url: string, { patterns, sensitiveParams, maskChar, maskLength, preserveLength }: MaskOptions): string;
|
|
75
84
|
}
|
|
76
85
|
|
|
77
86
|
export { NURL as default };
|
package/dist/esm/nurl.mjs
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import { encode as
|
|
2
|
-
import { refinePathnameWithQuery as
|
|
3
|
-
class
|
|
1
|
+
import { encode as $, decode as d } from "./punycode.mjs";
|
|
2
|
+
import { refinePathnameWithQuery as l, refineQueryWithPathname as w, convertQueryToArray as S, isDynamicPath as P, getDynamicPaths as y, extractPathKey as g, isASCIICodeChar as b, getPathPriority as u } from "./utils.mjs";
|
|
3
|
+
class n {
|
|
4
4
|
constructor(t) {
|
|
5
5
|
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._basePath = "", this.punycodePrefix = "xn--", this._searchParams = new URLSearchParams(), typeof t == "string" || t instanceof URL)
|
|
6
6
|
this.href = t.toString();
|
|
7
7
|
else if (t) {
|
|
8
|
-
if (t.basePath && (this._basePath = t.basePath.startsWith("/") ? t.basePath : `/${t.basePath}`), 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 !== void 0 && (t.pathname === "" ? this._pathname = "" : this.pathname =
|
|
9
|
-
const s =
|
|
10
|
-
Object.keys(s).length > 0 && (this.search = new URLSearchParams(
|
|
8
|
+
if (t.basePath && (this._basePath = t.basePath.startsWith("/") ? t.basePath : `/${t.basePath}`), 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 !== void 0 && (t.pathname === "" ? this._pathname = "" : this.pathname = l(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) {
|
|
9
|
+
const s = w(t.pathname ?? "", t.query);
|
|
10
|
+
Object.keys(s).length > 0 && (this.search = new URLSearchParams(S(s)).toString());
|
|
11
11
|
}
|
|
12
12
|
this.updateHref();
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
static withBasePath(t) {
|
|
16
|
-
return (s) => typeof s == "string" || s instanceof URL ? new
|
|
16
|
+
return (s) => typeof s == "string" || s instanceof URL ? new n({
|
|
17
17
|
href: s.toString(),
|
|
18
18
|
basePath: t
|
|
19
|
-
}) : new
|
|
19
|
+
}) : new n({
|
|
20
20
|
...s,
|
|
21
21
|
basePath: t
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
24
|
static create(t) {
|
|
25
|
-
return new
|
|
25
|
+
return new n(t);
|
|
26
26
|
}
|
|
27
27
|
static canParse(t) {
|
|
28
28
|
if (t.startsWith("/"))
|
|
@@ -53,30 +53,30 @@ class i {
|
|
|
53
53
|
const s = new URL(t);
|
|
54
54
|
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;
|
|
55
55
|
} catch (s) {
|
|
56
|
-
const e =
|
|
56
|
+
const e = n.parseStringToURLLike(t);
|
|
57
57
|
if (!e)
|
|
58
58
|
throw console.warn(`Can not parse ${t}`), s;
|
|
59
59
|
this._href = e.href, this._protocol = e.protocol, this._host = e.hostname, this._hostname = e.hostname, this._port = e.port, this._pathname = e.pathname, this._search = e.search, this._hash = e.hash, this._origin = e.origin, this._username = e.username, this._password = e.password, this._searchParams = e.searchParams;
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
static parseStringToURLLike(t) {
|
|
63
|
-
const s = /^(?:(https?:\/\/)(?:([^:@]+)(?::([^@]+))?@)?((?:[^/:?#]+)(?::(\d+))?)?)?([/][^?#]*)?(\?[^#]*)?(#.*)?$/, e = t.match(s), [
|
|
64
|
-
if (!e ||
|
|
63
|
+
const s = /^(?:(https?:\/\/)(?:([^:@]+)(?::([^@]+))?@)?((?:[^/:?#]+)(?::(\d+))?)?)?([/][^?#]*)?(\?[^#]*)?(#.*)?$/, e = t.match(s), [r = t, a = "", i = "", m = "", h = "", o = "", c = "", _ = "", p = ""] = e || [];
|
|
64
|
+
if (!e || a && !h && !c && !_ && !p)
|
|
65
65
|
return null;
|
|
66
|
-
const
|
|
66
|
+
const f = a && h ? `${a}//${h}${o ? `:${o}` : ""}` : "";
|
|
67
67
|
return {
|
|
68
|
-
href:
|
|
69
|
-
protocol:
|
|
70
|
-
host:
|
|
71
|
-
hostname:
|
|
72
|
-
port:
|
|
73
|
-
pathname: t ?
|
|
74
|
-
search:
|
|
75
|
-
hash:
|
|
76
|
-
origin:
|
|
77
|
-
username:
|
|
78
|
-
password:
|
|
79
|
-
searchParams: new URLSearchParams(
|
|
68
|
+
href: r,
|
|
69
|
+
protocol: a,
|
|
70
|
+
host: h,
|
|
71
|
+
hostname: h,
|
|
72
|
+
port: o,
|
|
73
|
+
pathname: t ? c || "/" : "",
|
|
74
|
+
search: _,
|
|
75
|
+
hash: p,
|
|
76
|
+
origin: f,
|
|
77
|
+
username: i,
|
|
78
|
+
password: m,
|
|
79
|
+
searchParams: new URLSearchParams(_)
|
|
80
80
|
};
|
|
81
81
|
}
|
|
82
82
|
get protocol() {
|
|
@@ -89,8 +89,8 @@ class i {
|
|
|
89
89
|
return this._host;
|
|
90
90
|
}
|
|
91
91
|
set host(t) {
|
|
92
|
-
const [s, e] = t.split(":"),
|
|
93
|
-
this._host = e ? `${
|
|
92
|
+
const [s, e] = t.split(":"), r = this.encodeHostname(s);
|
|
93
|
+
this._host = e ? `${r}:${e}` : r, this._hostname = r, this._port = e || "", this.updateHref();
|
|
94
94
|
}
|
|
95
95
|
get hostname() {
|
|
96
96
|
return this._hostname;
|
|
@@ -115,7 +115,7 @@ class i {
|
|
|
115
115
|
return;
|
|
116
116
|
}
|
|
117
117
|
this._basePath && !s.startsWith(this._basePath) && (s = `${this._basePath}${s.startsWith("/") ? "" : "/"}${s}`);
|
|
118
|
-
const e = s.split("/").map((
|
|
118
|
+
const e = s.split("/").map((r) => P(r) ? r : encodeURI(r)).join("/");
|
|
119
119
|
this._pathname = e.startsWith("/") ? e : `/${e}`, this.updateHref();
|
|
120
120
|
}
|
|
121
121
|
get search() {
|
|
@@ -129,11 +129,11 @@ class i {
|
|
|
129
129
|
this._search = s.toString() ? `?${s.toString()}` : "", this._searchParams = s, this.updateHref();
|
|
130
130
|
}
|
|
131
131
|
appendSearchParams(t) {
|
|
132
|
-
const s = new URLSearchParams(this._searchParams), e =
|
|
133
|
-
Object.keys(t).forEach((
|
|
134
|
-
e.includes(
|
|
135
|
-
[
|
|
136
|
-
}) : s.append(
|
|
132
|
+
const s = new URLSearchParams(this._searchParams), e = y(this._pathname).map(g);
|
|
133
|
+
Object.keys(t).forEach((r) => {
|
|
134
|
+
e.includes(r) ? this._pathname = l(this._pathname, {
|
|
135
|
+
[r]: t[r]
|
|
136
|
+
}) : s.append(r, t[r]);
|
|
137
137
|
}), this._search = s.toString() ? `?${s.toString()}` : "", this._searchParams = s, this.updateHref();
|
|
138
138
|
}
|
|
139
139
|
removeSearchParams(...t) {
|
|
@@ -145,11 +145,11 @@ class i {
|
|
|
145
145
|
get searchParams() {
|
|
146
146
|
return new Proxy(this._searchParams, {
|
|
147
147
|
get: (t, s, e) => {
|
|
148
|
-
const
|
|
149
|
-
return typeof
|
|
150
|
-
const
|
|
151
|
-
return this._search = this._searchParams.toString() ? `?${this._searchParams.toString()}` : "", this.updateHref(),
|
|
152
|
-
} :
|
|
148
|
+
const r = Reflect.get(t, s, e);
|
|
149
|
+
return typeof r == "function" ? (...a) => {
|
|
150
|
+
const i = r.apply(t, a);
|
|
151
|
+
return this._search = this._searchParams.toString() ? `?${this._searchParams.toString()}` : "", this.updateHref(), i;
|
|
152
|
+
} : r;
|
|
153
153
|
}
|
|
154
154
|
});
|
|
155
155
|
}
|
|
@@ -191,21 +191,58 @@ class i {
|
|
|
191
191
|
encodeHostname(t) {
|
|
192
192
|
return t.split(".").map((s) => {
|
|
193
193
|
for (const e of s)
|
|
194
|
-
if (
|
|
195
|
-
return `${this.punycodePrefix}${
|
|
194
|
+
if (b(e))
|
|
195
|
+
return `${this.punycodePrefix}${$(s)}`;
|
|
196
196
|
return s;
|
|
197
197
|
}).join(".");
|
|
198
198
|
}
|
|
199
199
|
get decodedIDN() {
|
|
200
200
|
let t = this._href;
|
|
201
201
|
return this._hostname.split(".").forEach((s) => {
|
|
202
|
-
t = t.replace(s,
|
|
202
|
+
t = t.replace(s, d(s.replace(this.punycodePrefix, "")));
|
|
203
203
|
}), t;
|
|
204
204
|
}
|
|
205
205
|
get decodedHostname() {
|
|
206
|
-
return this._hostname.split(".").map((t) =>
|
|
206
|
+
return this._hostname.split(".").map((t) => d(t.replace(this.punycodePrefix, ""))).join(".");
|
|
207
|
+
}
|
|
208
|
+
static match(t, s) {
|
|
209
|
+
if (!n.canParse(t) || !n.canParse(s))
|
|
210
|
+
return null;
|
|
211
|
+
const e = t.split(/[?#]/)[0]?.split("/").filter(Boolean) || [], r = s.split(/[?#]/)[0]?.split("/").filter(Boolean) || [];
|
|
212
|
+
if (e.length !== r.length)
|
|
213
|
+
return null;
|
|
214
|
+
const a = {};
|
|
215
|
+
for (let i = 0; i < r.length; i++) {
|
|
216
|
+
const m = r[i], h = e[i];
|
|
217
|
+
if (P(m)) {
|
|
218
|
+
const o = g(m);
|
|
219
|
+
a[o] = h;
|
|
220
|
+
} else if (m !== h)
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
return a;
|
|
224
|
+
}
|
|
225
|
+
static mask(t, {
|
|
226
|
+
patterns: s,
|
|
227
|
+
sensitiveParams: e,
|
|
228
|
+
maskChar: r = "*",
|
|
229
|
+
maskLength: a = 4,
|
|
230
|
+
preserveLength: i = !1
|
|
231
|
+
}) {
|
|
232
|
+
const m = [...s].sort((h, o) => u(o) > u(h) ? 1 : -1);
|
|
233
|
+
for (const h of m) {
|
|
234
|
+
const o = n.create(t), c = n.match(o.pathname, h);
|
|
235
|
+
if (c)
|
|
236
|
+
return e.forEach((_) => {
|
|
237
|
+
if (_ in c) {
|
|
238
|
+
const p = c[_], f = i ? p.length : a;
|
|
239
|
+
c[_] = r.repeat(f);
|
|
240
|
+
}
|
|
241
|
+
}), o.pathname = l(h, c), o.toString();
|
|
242
|
+
}
|
|
243
|
+
return t;
|
|
207
244
|
}
|
|
208
245
|
}
|
|
209
246
|
export {
|
|
210
|
-
|
|
247
|
+
n as default
|
|
211
248
|
};
|
package/dist/esm/utils.mjs
CHANGED
|
@@ -1,47 +1,51 @@
|
|
|
1
|
-
const s = /^:/,
|
|
2
|
-
function
|
|
3
|
-
return s.test(
|
|
4
|
-
}
|
|
5
|
-
function
|
|
6
|
-
return
|
|
7
|
-
}
|
|
8
|
-
function
|
|
9
|
-
return
|
|
10
|
-
}
|
|
11
|
-
function
|
|
12
|
-
return
|
|
13
|
-
const i =
|
|
14
|
-
return u && typeof u == "string" ?
|
|
1
|
+
const s = /^:/, A = /^\[.*\]$/;
|
|
2
|
+
function c(t) {
|
|
3
|
+
return s.test(t) || A.test(t);
|
|
4
|
+
}
|
|
5
|
+
function f(t) {
|
|
6
|
+
return t.split("/").filter(c);
|
|
7
|
+
}
|
|
8
|
+
function y(t) {
|
|
9
|
+
return t.slice(1, s.test(t) ? void 0 : -1);
|
|
10
|
+
}
|
|
11
|
+
function l(t, r) {
|
|
12
|
+
return f(t).reduce((e, n) => {
|
|
13
|
+
const i = y(n), u = r[i];
|
|
14
|
+
return u && typeof u == "string" ? e.replace(n, u) : e;
|
|
15
|
+
}, t);
|
|
16
|
+
}
|
|
17
|
+
function m(t, r) {
|
|
18
|
+
return f(t).reduce((e, n) => {
|
|
19
|
+
const i = y(n);
|
|
20
|
+
if (typeof e[i] != "string")
|
|
21
|
+
return e;
|
|
22
|
+
const {
|
|
23
|
+
[i]: g,
|
|
24
|
+
...a
|
|
25
|
+
} = e;
|
|
26
|
+
return a;
|
|
15
27
|
}, r);
|
|
16
28
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (typeof t[i] != "string")
|
|
21
|
-
return t;
|
|
22
|
-
const {
|
|
23
|
-
[i]: P,
|
|
24
|
-
...y
|
|
25
|
-
} = t;
|
|
26
|
-
return y;
|
|
27
|
-
}, e);
|
|
29
|
+
const P = 127;
|
|
30
|
+
function C(t) {
|
|
31
|
+
return t.charCodeAt(0) > P;
|
|
28
32
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return r.charCodeAt(0) > C;
|
|
33
|
+
function o(t) {
|
|
34
|
+
return ["string", "number", "boolean"].includes(typeof t);
|
|
32
35
|
}
|
|
33
|
-
function
|
|
34
|
-
return [
|
|
36
|
+
function _(t) {
|
|
37
|
+
return Object.entries(t).flatMap(([r, e]) => o(e) ? [[r, String(e)]] : Array.isArray(e) && e.every(o) ? e.map((n) => [r, String(n)]) : []);
|
|
35
38
|
}
|
|
36
|
-
function
|
|
37
|
-
return
|
|
39
|
+
function d(t) {
|
|
40
|
+
return t.split("/").filter(Boolean).map((e) => c(e) ? "1" : "2").join("");
|
|
38
41
|
}
|
|
39
42
|
export {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
_ as convertQueryToArray,
|
|
44
|
+
y as extractPathKey,
|
|
45
|
+
f as getDynamicPaths,
|
|
46
|
+
d as getPathPriority,
|
|
47
|
+
C as isASCIICodeChar,
|
|
48
|
+
c as isDynamicPath,
|
|
49
|
+
l as refinePathnameWithQuery,
|
|
50
|
+
m as refineQueryWithPathname
|
|
47
51
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naverpay/nurl",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0-canary.251230-92343a8",
|
|
4
4
|
"description": "URL build library",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"module": "./dist/esm/index.mjs",
|
|
@@ -56,6 +56,6 @@
|
|
|
56
56
|
"release": "changeset publish",
|
|
57
57
|
"markdownlint": "markdownlint '**/*.md' '#.changeset' '#**/CHANGELOG.md'",
|
|
58
58
|
"markdownlint:fix": "markdownlint --fix '**/*.md' '#.changeset' '#**/CHANGELOG.md'",
|
|
59
|
-
"release:canary": "changeset publish --no-git-tag --tag=
|
|
59
|
+
"release:canary": "changeset publish --no-git-tag --tag=canary --directory dist"
|
|
60
60
|
}
|
|
61
61
|
}
|