@helpers4/url 2.0.0-alpha.9 → 2.0.0-beta.3

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 CHANGED
@@ -15,6 +15,7 @@ A set of helpers for working with URLs.
15
15
  - cleanPath
16
16
  - extractPureURI
17
17
  - onlyPath
18
+ - parsePackageRepository
18
19
  - relativeURLToAbsolute
19
20
  - withLeadingSlash
20
21
  - withTrailingSlash
@@ -26,9 +27,12 @@ A set of helpers for working with URLs.
26
27
 
27
28
  <!-- AUTOMATIC-SIBLINGS -->
28
29
  - [array](../array)
30
+ - [ci](../ci)
31
+ - [commit](../commit)
29
32
  - [date](../date)
30
33
  - [function](../function)
31
- - [math](../math)
34
+ - [id](../id)
35
+ - [markdown](../markdown)
32
36
  - [number](../number)
33
37
  - [object](../object)
34
38
  - [observable](../observable)
@@ -44,15 +48,18 @@ A set of helpers for working with URLs.
44
48
  | Name | Package | Source Code | Description |
45
49
  |------|---------|-------------|-------------|
46
50
  | array | [@helpers4/array](https://www.npmjs.com/package/@helpers4/array) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/array) | Array manipulation utilities |
47
- | date | [@helpers4/date](https://www.npmjs.com/package/@helpers4/date) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/date) | date utilities |
51
+ | ci | [@helpers4/ci](https://www.npmjs.com/package/@helpers4/ci) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/ci) | CI/CD workflow status utilities |
52
+ | commit | [@helpers4/commit](https://www.npmjs.com/package/@helpers4/commit) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/commit) | Conventional Commits parsing and analysis |
53
+ | date | [@helpers4/date](https://www.npmjs.com/package/@helpers4/date) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/date) | Date and time utility functions |
48
54
  | function | [@helpers4/function](https://www.npmjs.com/package/@helpers4/function) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/function) | Function utilities and type guards |
49
- | math | [@helpers4/math](https://www.npmjs.com/package/@helpers4/math) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/math) | math utilities |
50
- | number | [@helpers4/number](https://www.npmjs.com/package/@helpers4/number) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/number) | number utilities |
55
+ | id | [@helpers4/id](https://www.npmjs.com/package/@helpers4/id) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/id) | Unique identifier generation utilities |
56
+ | markdown | [@helpers4/markdown](https://www.npmjs.com/package/@helpers4/markdown) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/markdown) | Markdown formatting and escaping utilities |
57
+ | number | [@helpers4/number](https://www.npmjs.com/package/@helpers4/number) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/number) | Number utility functions and validation |
51
58
  | object | [@helpers4/object](https://www.npmjs.com/package/@helpers4/object) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/object) | Object manipulation utilities |
52
59
  | observable | [@helpers4/observable](https://www.npmjs.com/package/@helpers4/observable) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/observable) | Observable utilities and combinators |
53
60
  | promise | [@helpers4/promise](https://www.npmjs.com/package/@helpers4/promise) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/promise) | Promise utilities and error handling |
54
61
  | string | [@helpers4/string](https://www.npmjs.com/package/@helpers4/string) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/string) | String manipulation and formatting utilities |
55
- | type | [@helpers4/type](https://www.npmjs.com/package/@helpers4/type) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/type) | type utilities |
62
+ | type | [@helpers4/type](https://www.npmjs.com/package/@helpers4/type) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/type) | Type checking and validation utilities |
56
63
  | url | [@helpers4/url](https://www.npmjs.com/package/@helpers4/url) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/url) | URL parsing and manipulation utilities |
57
64
  | version | [@helpers4/version](https://www.npmjs.com/package/@helpers4/version) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/version) | Version string manipulation utilities |
58
65
  <!-- /AUTOMATIC-CATEGORIES-TABLE -->
package/lib/index.d.ts CHANGED
@@ -115,6 +115,81 @@ declare function onlyPath(url: null): null;
115
115
  */
116
116
  declare function onlyPath(url: undefined): undefined;
117
117
 
118
+ /**
119
+ * This file is part of helpers4.
120
+ * Copyright (C) 2025 baxyz
121
+ * SPDX-License-Identifier: LGPL-3.0-or-later
122
+ */
123
+ /**
124
+ * Structured representation of a parsed `repository` field from `package.json`.
125
+ *
126
+ * @since next
127
+ */
128
+ interface PackageRepository {
129
+ /**
130
+ * VCS type (e.g. `'git'`, `'svn'`).
131
+ * Defaults to `'git'` when using shorthand string forms.
132
+ */
133
+ readonly type: string;
134
+ /**
135
+ * Hosting platform.
136
+ * Well-known values: `'github'`, `'gitlab'`, `'bitbucket'`, `'gist'`.
137
+ * Falls back to the raw domain (e.g. `'codeberg.org'`) for unknown hosts.
138
+ */
139
+ readonly host: 'github' | 'gitlab' | 'bitbucket' | 'gist' | (string & {});
140
+ /**
141
+ * `<owner>/<repo>` slug.
142
+ * `undefined` for gist shorthands (`gist:<id>`) and unrecognised URL shapes.
143
+ */
144
+ readonly slug: string | undefined;
145
+ /**
146
+ * Repository owner or organisation.
147
+ * `undefined` for gist shorthands.
148
+ */
149
+ readonly owner: string | undefined;
150
+ /**
151
+ * Repository name.
152
+ * `undefined` for gist shorthands.
153
+ */
154
+ readonly repo: string | undefined;
155
+ /**
156
+ * Gist identifier — only set when using the `gist:<id>` shorthand form.
157
+ */
158
+ readonly gistId: string | undefined;
159
+ /**
160
+ * Monorepo sub-directory from the `directory` field of the object form.
161
+ * `undefined` when using shorthand string forms or when no `directory` is specified.
162
+ */
163
+ readonly directory: string | undefined;
164
+ }
165
+ /**
166
+ * Parse the `repository` field from `package.json` into a structured object.
167
+ *
168
+ * Supports all npm-specified formats:
169
+ * - **Object form**: `{ "type": "git", "url": "...", "directory": "..." }`
170
+ * - **GitHub shorthand**: `"owner/repo"` or `"github:owner/repo"`
171
+ * - **Platform shorthands**: `"gitlab:owner/repo"`, `"bitbucket:owner/repo"`
172
+ * - **Gist shorthand**: `"gist:<id>"`
173
+ * - **URL forms**: `git+https://`, `https://`, `git://`, `git@` SSH, `git+ssh://`
174
+ *
175
+ * Returns `undefined` for `null`, `undefined`, arrays, or values that cannot
176
+ * be matched to any recognised format.
177
+ *
178
+ * @param repository - The `repository` field value from `package.json`.
179
+ * @returns A parsed {@link PackageRepository} object, or `undefined` if the
180
+ * input cannot be parsed.
181
+ * @example
182
+ * parsePackageRepository({ type: 'git', url: 'git+https://github.com/helpers4/typescript.git' })
183
+ * // => { type: 'git', host: 'github', slug: 'helpers4/typescript', owner: 'helpers4',
184
+ * // repo: 'typescript', gistId: undefined, directory: undefined }
185
+ * @example
186
+ * parsePackageRepository('github:helpers4/typescript')
187
+ * // => { type: 'git', host: 'github', slug: 'helpers4/typescript', owner: 'helpers4',
188
+ * // repo: 'typescript', gistId: undefined, directory: undefined }
189
+ * @since next
190
+ */
191
+ declare function parsePackageRepository(repository: unknown): PackageRepository | undefined;
192
+
118
193
  /**
119
194
  * This file is part of helpers4.
120
195
  * Copyright (C) 2025 baxyz
@@ -434,4 +509,5 @@ declare function withoutTrailingSlash(url: undefined): undefined;
434
509
  */
435
510
  declare function withoutTrailingSlash(url: null): null;
436
511
 
437
- export { cleanPath, extractPureURI, onlyPath, relativeURLToAbsolute, withLeadingSlash, withTrailingSlash, withoutLeadingSlash, withoutTrailingSlash };
512
+ export { cleanPath, extractPureURI, onlyPath, parsePackageRepository, relativeURLToAbsolute, withLeadingSlash, withTrailingSlash, withoutLeadingSlash, withoutTrailingSlash };
513
+ export type { PackageRepository };
package/lib/index.js CHANGED
@@ -68,6 +68,116 @@ function onlyPath(url) {
68
68
  return path;
69
69
  }
70
70
  //#endregion
71
+ //#region helpers/url/parsePackageRepository.ts
72
+ /** Maps known GitHub/GitLab/Bitbucket domains to their platform name. */
73
+ var DOMAIN_TO_HOST = {
74
+ "github.com": "github",
75
+ "gitlab.com": "gitlab",
76
+ "bitbucket.org": "bitbucket"
77
+ };
78
+ /** SCP-style SSH URL: `git@github.com:owner/repo.git` */
79
+ var RE_SSH_SCP = /^git@([\w.-]+):([\w.-]+\/[\w.-]+?)(?:\.git)?(?:[#?].*)?$/;
80
+ /**
81
+ * URL-form remote: `git+https://…`, `https://…`, `git://…`, `git+ssh://git@…`
82
+ * Captures: [1] domain, [2] owner/repo path
83
+ */
84
+ var RE_URL = /^(?:git\+(?:https?|ssh)|https?|git):\/\/(?:[^@/]+@)?([\w.-]+)\/([\w.-]+\/[\w.-]+?)(?:\.git)?(?:[#?].*)?$/;
85
+ function makeOwnerRepoResult(type, host, rawPath, directory) {
86
+ const slashIdx = rawPath.indexOf("/");
87
+ const owner = rawPath.slice(0, slashIdx);
88
+ const repo = rawPath.slice(slashIdx + 1);
89
+ return {
90
+ type,
91
+ host,
92
+ slug: `${owner}/${repo}`,
93
+ owner,
94
+ repo,
95
+ gistId: void 0,
96
+ directory
97
+ };
98
+ }
99
+ function parseRawUrl(raw, type, directory) {
100
+ const shorthandMatch = /^(github|gitlab|bitbucket):([\w.-]+\/[\w.-]+)$/.exec(raw);
101
+ if (shorthandMatch) {
102
+ const host = shorthandMatch[1];
103
+ const slug = shorthandMatch[2];
104
+ const slashIdx = slug.indexOf("/");
105
+ return {
106
+ type,
107
+ host,
108
+ slug,
109
+ owner: slug.slice(0, slashIdx),
110
+ repo: slug.slice(slashIdx + 1),
111
+ gistId: void 0,
112
+ directory
113
+ };
114
+ }
115
+ const gistMatch = /^gist:([\w-]+)$/.exec(raw);
116
+ if (gistMatch) return {
117
+ type,
118
+ host: "gist",
119
+ slug: void 0,
120
+ owner: void 0,
121
+ repo: void 0,
122
+ gistId: gistMatch[1],
123
+ directory
124
+ };
125
+ const bareMatch = /^([\w.-]+)\/([\w.-]+)$/.exec(raw);
126
+ if (bareMatch) {
127
+ const owner = bareMatch[1];
128
+ const repo = bareMatch[2];
129
+ return {
130
+ type,
131
+ host: "github",
132
+ slug: `${owner}/${repo}`,
133
+ owner,
134
+ repo,
135
+ gistId: void 0,
136
+ directory
137
+ };
138
+ }
139
+ const sshMatch = RE_SSH_SCP.exec(raw);
140
+ if (sshMatch) return makeOwnerRepoResult(type, DOMAIN_TO_HOST[sshMatch[1]] ?? sshMatch[1], sshMatch[2], directory);
141
+ const urlMatch = RE_URL.exec(raw);
142
+ if (urlMatch) return makeOwnerRepoResult(type, DOMAIN_TO_HOST[urlMatch[1]] ?? urlMatch[1], urlMatch[2], directory);
143
+ }
144
+ /**
145
+ * Parse the `repository` field from `package.json` into a structured object.
146
+ *
147
+ * Supports all npm-specified formats:
148
+ * - **Object form**: `{ "type": "git", "url": "...", "directory": "..." }`
149
+ * - **GitHub shorthand**: `"owner/repo"` or `"github:owner/repo"`
150
+ * - **Platform shorthands**: `"gitlab:owner/repo"`, `"bitbucket:owner/repo"`
151
+ * - **Gist shorthand**: `"gist:<id>"`
152
+ * - **URL forms**: `git+https://`, `https://`, `git://`, `git@` SSH, `git+ssh://`
153
+ *
154
+ * Returns `undefined` for `null`, `undefined`, arrays, or values that cannot
155
+ * be matched to any recognised format.
156
+ *
157
+ * @param repository - The `repository` field value from `package.json`.
158
+ * @returns A parsed {@link PackageRepository} object, or `undefined` if the
159
+ * input cannot be parsed.
160
+ * @example
161
+ * parsePackageRepository({ type: 'git', url: 'git+https://github.com/helpers4/typescript.git' })
162
+ * // => { type: 'git', host: 'github', slug: 'helpers4/typescript', owner: 'helpers4',
163
+ * // repo: 'typescript', gistId: undefined, directory: undefined }
164
+ * @example
165
+ * parsePackageRepository('github:helpers4/typescript')
166
+ * // => { type: 'git', host: 'github', slug: 'helpers4/typescript', owner: 'helpers4',
167
+ * // repo: 'typescript', gistId: undefined, directory: undefined }
168
+ * @since next
169
+ */
170
+ function parsePackageRepository(repository) {
171
+ if (repository === null || repository === void 0) return void 0;
172
+ if (typeof repository === "string") return parseRawUrl(repository, "git", void 0);
173
+ if (typeof repository === "object" && !Array.isArray(repository)) {
174
+ const obj = repository;
175
+ const rawUrl = obj["url"];
176
+ if (typeof rawUrl !== "string") return void 0;
177
+ return parseRawUrl(rawUrl, typeof obj["type"] === "string" ? obj["type"] : "git", typeof obj["directory"] === "string" ? obj["directory"] : void 0);
178
+ }
179
+ }
180
+ //#endregion
71
181
  //#region helpers/url/withoutTrailingSlash.ts
72
182
  /**
73
183
  * Removes the trailing slash `/` from the given URL if it is present.
@@ -94,7 +204,7 @@ function onlyPath(url) {
94
204
  */
95
205
  function withoutTrailingSlash(url) {
96
206
  if (url === void 0 || url === null) return url;
97
- return url[url.length - 1] === "/" ? url.slice(0, -1) : url;
207
+ return url.replace(/\/+$/, "");
98
208
  }
99
209
  //#endregion
100
210
  //#region helpers/url/withLeadingSlash.ts
@@ -198,6 +308,6 @@ function withoutLeadingSlash(url) {
198
308
  return url[0] === "/" ? url.slice(1) : url;
199
309
  }
200
310
  //#endregion
201
- export { cleanPath, extractPureURI, onlyPath, relativeURLToAbsolute, withLeadingSlash, withTrailingSlash, withoutLeadingSlash, withoutTrailingSlash };
311
+ export { cleanPath, extractPureURI, onlyPath, parsePackageRepository, relativeURLToAbsolute, withLeadingSlash, withTrailingSlash, withoutLeadingSlash, withoutTrailingSlash };
202
312
 
203
313
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../helpers/url/cleanPath.ts","../../../helpers/url/extractPureURI.ts","../../../helpers/url/onlyPath.ts","../../../helpers/url/withoutTrailingSlash.ts","../../../helpers/url/withLeadingSlash.ts","../../../helpers/url/relativeURLToAbsolute.ts","../../../helpers/url/withTrailingSlash.ts","../../../helpers/url/withoutLeadingSlash.ts"],"sourcesContent":["/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Clean an URL by removing duplicate slashes.\n * The protocol part of the URL is not modified.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The cleaned URL string, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @example\n * ```ts\n * cleanPath('/path//to///resource') // => '/path/to/resource'\n * cleanPath('http://example.com//path//to///resource') // => 'http://example.com/path/to/resource'\n * cleanPath(undefined) // => undefined\n * cleanPath(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function cleanPath(\n url: string | undefined | null,\n): string | undefined | null {\n if (url === undefined || url === null) {\n return url\n }\n return url.replace(/([^:]\\/)\\/+/g, '$1')\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/*\n * This program is under the terms of the GNU Lesser General Public License version 3\n * The full license information can be found in LICENSE in the root directory of this project.\n */\n\n/**\n * Extracts the pure URI from a URL by removing query parameters and fragments.\n *\n * @param url - The URL string to process\n * @returns The URI without query parameters and fragments, or the original value if undefined/null\n * @since 1.9.0\n */\nexport function extractPureURI(url: string): string;\nexport function extractPureURI(url: undefined): undefined;\nexport function extractPureURI(url: null): null;\nexport function extractPureURI(url: string | undefined | null): string | undefined | null {\n if (url === undefined || url === null) {\n return url;\n }\n\n // Find the first occurrence of ? or #\n const queryIndex = url.indexOf('?');\n const fragmentIndex = url.indexOf('#');\n\n let cutIndex = -1;\n\n if (queryIndex !== -1 && fragmentIndex !== -1) {\n // Both exist, take the earliest one\n cutIndex = Math.min(queryIndex, fragmentIndex);\n } else if (queryIndex !== -1) {\n // Only query exists\n cutIndex = queryIndex;\n } else if (fragmentIndex !== -1) {\n // Only fragment exists\n cutIndex = fragmentIndex;\n }\n\n // If no query or fragment found, return the original string\n if (cutIndex === -1) {\n return url;\n }\n\n // Return the substring up to the first ? or #\n return url.substring(0, cutIndex);\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Extract only the path from an URI with optional query and fragments.\n *\n * For example, all these parameters will return `/path`:\n * - `/path`\n * - `/path?query=thing`\n * - `/path#fragment`\n * - `/path?query=thing#fragment`\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without query and fragment, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @example\n * ```ts\n * onlyPath('/path') // => '/path'\n * onlyPath('/path?query=thing') // => '/path'\n * onlyPath('/path#fragment') // => '/path'\n * onlyPath('/path?query=thing#fragment') // => '/path'\n * onlyPath(undefined) // => undefined\n * onlyPath(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function onlyPath(url: string): string\n\n/**\n * Extract only the path from an URI with optional query and fragments.\n *\n * For example, all these parameters will return `/path`:\n * - `/path`\n * - `/path?query=thing`\n * - `/path#fragment`\n * - `/path?query=thing#fragment`\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without query and fragment, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @example\n * ```ts\n * onlyPath('/path') // => '/path'\n * onlyPath('/path?query=thing') // => '/path'\n * onlyPath('/path#fragment') // => '/path'\n * onlyPath('/path?query=thing#fragment') // => '/path'\n * onlyPath(undefined) // => undefined\n * onlyPath(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function onlyPath(url: null): null\n\n/**\n * Extract only the path from an URI with optional query and fragments.\n *\n * For example, all these parameters will return `/path`:\n * - `/path`\n * - `/path?query=thing`\n * - `/path#fragment`\n * - `/path?query=thing#fragment`\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without query and fragment, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @example\n * ```ts\n * onlyPath('/path') // => '/path'\n * onlyPath('/path?query=thing') // => '/path'\n * onlyPath('/path#fragment') // => '/path'\n * onlyPath('/path?query=thing#fragment') // => '/path'\n * onlyPath(undefined) // => undefined\n * onlyPath(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function onlyPath(url: undefined): undefined\n\n/**\n * Extract only the path from an URI with optional query and fragments.\n *\n * For example, all these parameters will return `/path`:\n * - `/path`\n * - `/path?query=thing`\n * - `/path#fragment`\n * - `/path?query=thing#fragment`\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without query and fragment, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @example\n * ```ts\n * onlyPath('/path') // => '/path'\n * onlyPath('/path?query=thing') // => '/path'\n * onlyPath('/path#fragment') // => '/path'\n * onlyPath('/path?query=thing#fragment') // => '/path'\n * onlyPath(undefined) // => undefined\n * onlyPath(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function onlyPath(\n url: string | undefined | null,\n): string | undefined | null {\n if (url === undefined || url === null) {\n return url\n }\n const [path] = url.split(/[?#]/)\n return path\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Removes the trailing slash `/` from the given URL if it is present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * without a trailing slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withoutTrailingSlash\n *\n * @example\n * ```ts\n * withoutTrailingSlash('') // => ''\n * withoutTrailingSlash('/') // => ''\n * withoutTrailingSlash('no/slash/') // => 'no/slash'\n * withoutTrailingSlash('already/has/slash') // => 'already/has/slash'\n * withoutTrailingSlash(undefined) // => undefined\n * withoutTrailingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withoutTrailingSlash(url: string): string\n\n/**\n * Removes the trailing slash `/` from the given URL if it is present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * without a trailing slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withoutTrailingSlash\n *\n * @example\n * ```ts\n * withoutTrailingSlash('') // => ''\n * withoutTrailingSlash('/') // => ''\n * withoutTrailingSlash('no/slash/') // => 'no/slash'\n * withoutTrailingSlash('already/has/slash') // => 'already/has/slash'\n * withoutTrailingSlash(undefined) // => undefined\n * withoutTrailingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withoutTrailingSlash(url: undefined): undefined\n\n/**\n * Removes the trailing slash `/` from the given URL if it is present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * without a trailing slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withoutTrailingSlash\n *\n * @example\n * ```ts\n * withoutTrailingSlash('') // => ''\n * withoutTrailingSlash('/') // => ''\n * withoutTrailingSlash('no/slash/') // => 'no/slash'\n * withoutTrailingSlash('already/has/slash') // => 'already/has/slash'\n * withoutTrailingSlash(undefined) // => undefined\n * withoutTrailingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withoutTrailingSlash(url: null): null\n\n/**\n * Removes the trailing slash `/` from the given URL if it is present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * without a trailing slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withoutTrailingSlash\n *\n * @example\n * ```ts\n * withoutTrailingSlash('') // => ''\n * withoutTrailingSlash('/') // => ''\n * withoutTrailingSlash('no/slash/') // => 'no/slash'\n * withoutTrailingSlash('already/has/slash') // => 'already/has/slash'\n * withoutTrailingSlash(undefined) // => undefined\n * withoutTrailingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withoutTrailingSlash(\n url: string | undefined | null,\n): string | undefined | null {\n if (url === undefined || url === null) {\n return url\n }\n return url[url.length - 1] === '/' ? url.slice(0, -1) : url\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Adds a leading slash `/` to the given URL if it is not already present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * with a leading slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string with a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withLeadingSlash\n *\n * @example\n * ```ts\n * withLeadingSlash('') // => '/'\n * withLeadingSlash('no/slash') // => '/no/slash'\n * withLeadingSlash('/already/has/slash') // => '/already/has/slash'\n * withLeadingSlash(undefined) // => undefined\n * withLeadingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withLeadingSlash(url: string): string\n\n/**\n * Adds a leading slash `/` to the given URL if it is not already present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * with a leading slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string with a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withLeadingSlash\n *\n * @example\n * ```ts\n * withLeadingSlash('') // => '/'\n * withLeadingSlash('no/slash') // => '/no/slash'\n * withLeadingSlash('/already/has/slash') // => '/already/has/slash'\n * withLeadingSlash(undefined) // => undefined\n * withLeadingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withLeadingSlash(url: undefined): undefined\n\n/**\n * Adds a leading slash `/` to the given URL if it is not already present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * with a leading slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string with a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withLeadingSlash\n *\n * @example\n * ```ts\n * withLeadingSlash('') // => '/'\n * withLeadingSlash('no/slash') // => '/no/slash'\n * withLeadingSlash('/already/has/slash') // => '/already/has/slash'\n * withLeadingSlash(undefined) // => undefined\n * withLeadingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withLeadingSlash(url: null): null\n\n/**\n * Adds a leading slash `/` to the given URL if it is not already present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * with a leading slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string with a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withLeadingSlash\n *\n * @example\n * ```ts\n * withLeadingSlash('') // => '/'\n * withLeadingSlash('no/slash') // => '/no/slash'\n * withLeadingSlash('/already/has/slash') // => '/already/has/slash'\n * withLeadingSlash(undefined) // => undefined\n * withLeadingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withLeadingSlash(\n url: string | undefined | null,\n): string | undefined | null {\n if (url === undefined || url === null) {\n return url\n }\n return url[0] === '/' ? url : '/' + url\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/*\n * This program is under the terms of the GNU Lesser General Public License version 3\n * The full license information can be found in LICENSE in the root directory of this project.\n */\n\nimport { withoutTrailingSlash } from \"./withoutTrailingSlash\";\nimport { withLeadingSlash } from \"./withLeadingSlash\";\nimport { cleanPath } from \"./cleanPath\";\n\n/**\n * Converts a relative URL to an absolute URL using the current document base URI.\n * @param relativeUrl - The relative URL to convert\n * @returns The absolute URL\n * @since 1.0.0\n */\nexport function relativeURLToAbsolute(relativeUrl: string): string {\n return (\n withoutTrailingSlash(document.baseURI ?? window.location.origin) +\n cleanPath(withLeadingSlash(relativeUrl))\n );\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Adds a trailing slash `/` to the given URL if it is not already present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * with a trailing slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string with a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withTrailingSlash\n *\n * @example\n * ```ts\n * withTrailingSlash('') // => '/'\n * withTrailingSlash('no/slash') // => 'no/slash/'\n * withTrailingSlash('already/has/slash/') // => 'already/has/slash/'\n * withTrailingSlash(undefined) // => undefined\n * withTrailingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withTrailingSlash(url: string): string\n\n/**\n * Adds a trailing slash `/` to the given URL if it is not already present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * with a trailing slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string with a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withTrailingSlash\n *\n * @example\n * ```ts\n * withTrailingSlash('') // => '/'\n * withTrailingSlash('no/slash') // => 'no/slash/'\n * withTrailingSlash('already/has/slash/') // => 'already/has/slash/'\n * withTrailingSlash(undefined) // => undefined\n * withTrailingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withTrailingSlash(url: undefined): undefined\n\n/**\n * Adds a trailing slash `/` to the given URL if it is not already present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * with a trailing slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string with a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withTrailingSlash\n *\n * @example\n * ```ts\n * withTrailingSlash('') // => '/'\n * withTrailingSlash('no/slash') // => 'no/slash/'\n * withTrailingSlash('already/has/slash/') // => 'already/has/slash/'\n * withTrailingSlash(undefined) // => undefined\n * withTrailingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withTrailingSlash(url: null): null\n\n/**\n * Adds a trailing slash `/` to the given URL if it is not already present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * with a trailing slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string with a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withTrailingSlash\n *\n * @example\n * ```ts\n * withTrailingSlash('') // => '/'\n * withTrailingSlash('no/slash') // => 'no/slash/'\n * withTrailingSlash('already/has/slash/') // => 'already/has/slash/'\n * withTrailingSlash(undefined) // => undefined\n * withTrailingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withTrailingSlash(\n url: string | undefined | null,\n): string | undefined | null {\n if (url === undefined || url === null) {\n return url\n }\n return url[url.length - 1] === '/' ? url : url + '/'\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Removes the leading slash `/` from the given URL if it is present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * without a leading slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withoutLeadingSlash\n *\n * @example\n * ```ts\n * withoutLeadingSlash('') // => ''\n * withoutLeadingSlash('/') // => ''\n * withoutLeadingSlash('/no/slash') // => 'no/slash'\n * withoutLeadingSlash('already/has/slash') // => 'already/has/slash'\n * withoutLeadingSlash(undefined) // => undefined\n * withoutLeadingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withoutLeadingSlash(url: string): string\n\n/**\n * Removes the leading slash `/` from the given URL if it is present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * without a leading slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withoutLeadingSlash\n *\n * @example\n * ```ts\n * withoutLeadingSlash('') // => ''\n * withoutLeadingSlash('/') // => ''\n * withoutLeadingSlash('/no/slash') // => 'no/slash'\n * withoutLeadingSlash('already/has/slash') // => 'already/has/slash'\n * withoutLeadingSlash(undefined) // => undefined\n * withoutLeadingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withoutLeadingSlash(url: undefined): undefined\n\n/**\n * Removes the leading slash `/` from the given URL if it is present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * without a leading slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withoutLeadingSlash\n *\n * @example\n * ```ts\n * withoutLeadingSlash('') // => ''\n * withoutLeadingSlash('/') // => ''\n * withoutLeadingSlash('/no/slash') // => 'no/slash'\n * withoutLeadingSlash('already/has/slash') // => 'already/has/slash'\n * withoutLeadingSlash(undefined) // => undefined\n * withoutLeadingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withoutLeadingSlash(url: null): null\n\n/**\n * Removes the leading slash `/` from the given URL if it is present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * without a leading slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withoutLeadingSlash\n *\n * @example\n * ```ts\n * withoutLeadingSlash('') // => ''\n * withoutLeadingSlash('/') // => ''\n * withoutLeadingSlash('/no/slash') // => 'no/slash'\n * withoutLeadingSlash('already/has/slash') // => 'already/has/slash'\n * withoutLeadingSlash(undefined) // => undefined\n * withoutLeadingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withoutLeadingSlash(\n url: string | undefined | null,\n): string | undefined | null {\n if (url === undefined || url === null) {\n return url\n }\n return url[0] === '/' ? url.slice(1) : url\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,UACd,KAC2B;AAC3B,KAAI,QAAQ,KAAA,KAAa,QAAQ,KAC/B,QAAO;AAET,QAAO,IAAI,QAAQ,gBAAgB,KAAK;;;;ACP1C,SAAgB,eAAe,KAA2D;AACxF,KAAI,QAAQ,KAAA,KAAa,QAAQ,KAC/B,QAAO;CAIT,MAAM,aAAa,IAAI,QAAQ,IAAI;CACnC,MAAM,gBAAgB,IAAI,QAAQ,IAAI;CAEtC,IAAI,WAAW;AAEf,KAAI,eAAe,MAAM,kBAAkB,GAEzC,YAAW,KAAK,IAAI,YAAY,cAAc;UACrC,eAAe,GAExB,YAAW;UACF,kBAAkB,GAE3B,YAAW;AAIb,KAAI,aAAa,GACf,QAAO;AAIT,QAAO,IAAI,UAAU,GAAG,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;ACuDnC,SAAgB,SACd,KAC2B;AAC3B,KAAI,QAAQ,KAAA,KAAa,QAAQ,KAC/B,QAAO;CAET,MAAM,CAAC,QAAQ,IAAI,MAAM,OAAO;AAChC,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;ACPT,SAAgB,qBACd,KAC2B;AAC3B,KAAI,QAAQ,KAAA,KAAa,QAAQ,KAC/B,QAAO;AAET,QAAO,IAAI,IAAI,SAAS,OAAO,MAAM,IAAI,MAAM,GAAG,GAAG,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;ACV1D,SAAgB,iBACd,KAC2B;AAC3B,KAAI,QAAQ,KAAA,KAAa,QAAQ,KAC/B,QAAO;AAET,QAAO,IAAI,OAAO,MAAM,MAAM,MAAM;;;;;;;;;;;;;;;ACrFtC,SAAgB,sBAAsB,aAA6B;AAC/D,QACI,qBAAqB,SAAS,WAAW,OAAO,SAAS,OAAO,GAChE,UAAU,iBAAiB,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;AC4EhD,SAAgB,kBACd,KAC2B;AAC3B,KAAI,QAAQ,KAAA,KAAa,QAAQ,KAC/B,QAAO;AAET,QAAO,IAAI,IAAI,SAAS,OAAO,MAAM,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;ACFnD,SAAgB,oBACd,KAC2B;AAC3B,KAAI,QAAQ,KAAA,KAAa,QAAQ,KAC/B,QAAO;AAET,QAAO,IAAI,OAAO,MAAM,IAAI,MAAM,EAAE,GAAG"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../helpers/url/cleanPath.ts","../../../helpers/url/extractPureURI.ts","../../../helpers/url/onlyPath.ts","../../../helpers/url/parsePackageRepository.ts","../../../helpers/url/withoutTrailingSlash.ts","../../../helpers/url/withLeadingSlash.ts","../../../helpers/url/relativeURLToAbsolute.ts","../../../helpers/url/withTrailingSlash.ts","../../../helpers/url/withoutLeadingSlash.ts"],"sourcesContent":["/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Clean an URL by removing duplicate slashes.\n * The protocol part of the URL is not modified.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The cleaned URL string, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @example\n * ```ts\n * cleanPath('/path//to///resource') // => '/path/to/resource'\n * cleanPath('http://example.com//path//to///resource') // => 'http://example.com/path/to/resource'\n * cleanPath(undefined) // => undefined\n * cleanPath(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function cleanPath(\n url: string | undefined | null,\n): string | undefined | null {\n if (url === undefined || url === null) {\n return url\n }\n return url.replace(/([^:]\\/)\\/+/g, '$1')\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/*\n * This program is under the terms of the GNU Lesser General Public License version 3\n * The full license information can be found in LICENSE in the root directory of this project.\n */\n\n/**\n * Extracts the pure URI from a URL by removing query parameters and fragments.\n *\n * @param url - The URL string to process\n * @returns The URI without query parameters and fragments, or the original value if undefined/null\n * @since 1.9.0\n */\nexport function extractPureURI(url: string): string;\nexport function extractPureURI(url: undefined): undefined;\nexport function extractPureURI(url: null): null;\nexport function extractPureURI(url: string | undefined | null): string | undefined | null {\n if (url === undefined || url === null) {\n return url;\n }\n\n // Find the first occurrence of ? or #\n const queryIndex = url.indexOf('?');\n const fragmentIndex = url.indexOf('#');\n\n let cutIndex = -1;\n\n if (queryIndex !== -1 && fragmentIndex !== -1) {\n // Both exist, take the earliest one\n cutIndex = Math.min(queryIndex, fragmentIndex);\n } else if (queryIndex !== -1) {\n // Only query exists\n cutIndex = queryIndex;\n } else if (fragmentIndex !== -1) {\n // Only fragment exists\n cutIndex = fragmentIndex;\n }\n\n // If no query or fragment found, return the original string\n if (cutIndex === -1) {\n return url;\n }\n\n // Return the substring up to the first ? or #\n return url.substring(0, cutIndex);\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Extract only the path from an URI with optional query and fragments.\n *\n * For example, all these parameters will return `/path`:\n * - `/path`\n * - `/path?query=thing`\n * - `/path#fragment`\n * - `/path?query=thing#fragment`\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without query and fragment, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @example\n * ```ts\n * onlyPath('/path') // => '/path'\n * onlyPath('/path?query=thing') // => '/path'\n * onlyPath('/path#fragment') // => '/path'\n * onlyPath('/path?query=thing#fragment') // => '/path'\n * onlyPath(undefined) // => undefined\n * onlyPath(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function onlyPath(url: string): string\n\n/**\n * Extract only the path from an URI with optional query and fragments.\n *\n * For example, all these parameters will return `/path`:\n * - `/path`\n * - `/path?query=thing`\n * - `/path#fragment`\n * - `/path?query=thing#fragment`\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without query and fragment, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @example\n * ```ts\n * onlyPath('/path') // => '/path'\n * onlyPath('/path?query=thing') // => '/path'\n * onlyPath('/path#fragment') // => '/path'\n * onlyPath('/path?query=thing#fragment') // => '/path'\n * onlyPath(undefined) // => undefined\n * onlyPath(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function onlyPath(url: null): null\n\n/**\n * Extract only the path from an URI with optional query and fragments.\n *\n * For example, all these parameters will return `/path`:\n * - `/path`\n * - `/path?query=thing`\n * - `/path#fragment`\n * - `/path?query=thing#fragment`\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without query and fragment, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @example\n * ```ts\n * onlyPath('/path') // => '/path'\n * onlyPath('/path?query=thing') // => '/path'\n * onlyPath('/path#fragment') // => '/path'\n * onlyPath('/path?query=thing#fragment') // => '/path'\n * onlyPath(undefined) // => undefined\n * onlyPath(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function onlyPath(url: undefined): undefined\n\n/**\n * Extract only the path from an URI with optional query and fragments.\n *\n * For example, all these parameters will return `/path`:\n * - `/path`\n * - `/path?query=thing`\n * - `/path#fragment`\n * - `/path?query=thing#fragment`\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without query and fragment, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @example\n * ```ts\n * onlyPath('/path') // => '/path'\n * onlyPath('/path?query=thing') // => '/path'\n * onlyPath('/path#fragment') // => '/path'\n * onlyPath('/path?query=thing#fragment') // => '/path'\n * onlyPath(undefined) // => undefined\n * onlyPath(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function onlyPath(\n url: string | undefined | null,\n): string | undefined | null {\n if (url === undefined || url === null) {\n return url\n }\n const [path] = url.split(/[?#]/)\n return path\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Structured representation of a parsed `repository` field from `package.json`.\n *\n * @since next\n */\nexport interface PackageRepository {\n /**\n * VCS type (e.g. `'git'`, `'svn'`).\n * Defaults to `'git'` when using shorthand string forms.\n */\n readonly type: string;\n /**\n * Hosting platform.\n * Well-known values: `'github'`, `'gitlab'`, `'bitbucket'`, `'gist'`.\n * Falls back to the raw domain (e.g. `'codeberg.org'`) for unknown hosts.\n */\n readonly host: 'github' | 'gitlab' | 'bitbucket' | 'gist' | (string & {});\n /**\n * `<owner>/<repo>` slug.\n * `undefined` for gist shorthands (`gist:<id>`) and unrecognised URL shapes.\n */\n readonly slug: string | undefined;\n /**\n * Repository owner or organisation.\n * `undefined` for gist shorthands.\n */\n readonly owner: string | undefined;\n /**\n * Repository name.\n * `undefined` for gist shorthands.\n */\n readonly repo: string | undefined;\n /**\n * Gist identifier — only set when using the `gist:<id>` shorthand form.\n */\n readonly gistId: string | undefined;\n /**\n * Monorepo sub-directory from the `directory` field of the object form.\n * `undefined` when using shorthand string forms or when no `directory` is specified.\n */\n readonly directory: string | undefined;\n}\n\n/** Maps known GitHub/GitLab/Bitbucket domains to their platform name. */\nconst DOMAIN_TO_HOST: Record<string, string> = {\n 'github.com': 'github',\n 'gitlab.com': 'gitlab',\n 'bitbucket.org': 'bitbucket',\n};\n\n/** SCP-style SSH URL: `git@github.com:owner/repo.git` */\nconst RE_SSH_SCP = /^git@([\\w.-]+):([\\w.-]+\\/[\\w.-]+?)(?:\\.git)?(?:[#?].*)?$/;\n\n/**\n * URL-form remote: `git+https://…`, `https://…`, `git://…`, `git+ssh://git@…`\n * Captures: [1] domain, [2] owner/repo path\n */\nconst RE_URL =\n /^(?:git\\+(?:https?|ssh)|https?|git):\\/\\/(?:[^@/]+@)?([\\w.-]+)\\/([\\w.-]+\\/[\\w.-]+?)(?:\\.git)?(?:[#?].*)?$/;\n\nfunction makeOwnerRepoResult(\n type: string,\n host: string,\n rawPath: string,\n directory: string | undefined,\n): PackageRepository {\n const slashIdx = rawPath.indexOf('/');\n const owner = rawPath.slice(0, slashIdx);\n const repo = rawPath.slice(slashIdx + 1);\n return { type, host, slug: `${owner}/${repo}`, owner, repo, gistId: undefined, directory };\n}\n\nfunction parseRawUrl(\n raw: string,\n type: string,\n directory: string | undefined,\n): PackageRepository | undefined {\n // Shorthand prefix: \"github:owner/repo\", \"gitlab:owner/repo\", \"bitbucket:owner/repo\"\n const shorthandMatch = /^(github|gitlab|bitbucket):([\\w.-]+\\/[\\w.-]+)$/.exec(raw);\n if (shorthandMatch) {\n const host = shorthandMatch[1] as 'github' | 'gitlab' | 'bitbucket';\n const slug = shorthandMatch[2];\n const slashIdx = slug.indexOf('/');\n const owner = slug.slice(0, slashIdx);\n const repo = slug.slice(slashIdx + 1);\n return { type, host, slug, owner, repo, gistId: undefined, directory };\n }\n\n // Gist shorthand: \"gist:<id>\"\n const gistMatch = /^gist:([\\w-]+)$/.exec(raw);\n if (gistMatch) {\n return { type, host: 'gist', slug: undefined, owner: undefined, repo: undefined, gistId: gistMatch[1], directory };\n }\n\n // Bare GitHub shorthand: \"owner/repo\" (no colon prefix, no protocol)\n const bareMatch = /^([\\w.-]+)\\/([\\w.-]+)$/.exec(raw);\n if (bareMatch) {\n const owner = bareMatch[1];\n const repo = bareMatch[2];\n return { type, host: 'github', slug: `${owner}/${repo}`, owner, repo, gistId: undefined, directory };\n }\n\n // SCP-style SSH: git@github.com:owner/repo.git\n const sshMatch = RE_SSH_SCP.exec(raw);\n if (sshMatch) {\n const host = DOMAIN_TO_HOST[sshMatch[1]] ?? sshMatch[1];\n return makeOwnerRepoResult(type, host, sshMatch[2], directory);\n }\n\n // URL-form: https://, git+https://, git://, git+ssh://\n const urlMatch = RE_URL.exec(raw);\n if (urlMatch) {\n const host = DOMAIN_TO_HOST[urlMatch[1]] ?? urlMatch[1];\n return makeOwnerRepoResult(type, host, urlMatch[2], directory);\n }\n\n return undefined;\n}\n\n/**\n * Parse the `repository` field from `package.json` into a structured object.\n *\n * Supports all npm-specified formats:\n * - **Object form**: `{ \"type\": \"git\", \"url\": \"...\", \"directory\": \"...\" }`\n * - **GitHub shorthand**: `\"owner/repo\"` or `\"github:owner/repo\"`\n * - **Platform shorthands**: `\"gitlab:owner/repo\"`, `\"bitbucket:owner/repo\"`\n * - **Gist shorthand**: `\"gist:<id>\"`\n * - **URL forms**: `git+https://`, `https://`, `git://`, `git@` SSH, `git+ssh://`\n *\n * Returns `undefined` for `null`, `undefined`, arrays, or values that cannot\n * be matched to any recognised format.\n *\n * @param repository - The `repository` field value from `package.json`.\n * @returns A parsed {@link PackageRepository} object, or `undefined` if the\n * input cannot be parsed.\n * @example\n * parsePackageRepository({ type: 'git', url: 'git+https://github.com/helpers4/typescript.git' })\n * // => { type: 'git', host: 'github', slug: 'helpers4/typescript', owner: 'helpers4',\n * // repo: 'typescript', gistId: undefined, directory: undefined }\n * @example\n * parsePackageRepository('github:helpers4/typescript')\n * // => { type: 'git', host: 'github', slug: 'helpers4/typescript', owner: 'helpers4',\n * // repo: 'typescript', gistId: undefined, directory: undefined }\n * @since next\n */\nexport function parsePackageRepository(repository: unknown): PackageRepository | undefined {\n if (repository === null || repository === undefined) return undefined;\n\n if (typeof repository === 'string') {\n return parseRawUrl(repository, 'git', undefined);\n }\n\n if (typeof repository === 'object' && !Array.isArray(repository)) {\n const obj = repository as Record<string, unknown>;\n const rawUrl = obj['url'];\n if (typeof rawUrl !== 'string') return undefined;\n const type = typeof obj['type'] === 'string' ? (obj['type'] as string) : 'git';\n const directory = typeof obj['directory'] === 'string' ? (obj['directory'] as string) : undefined;\n return parseRawUrl(rawUrl, type, directory);\n }\n\n return undefined;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Removes the trailing slash `/` from the given URL if it is present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * without a trailing slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withoutTrailingSlash\n *\n * @example\n * ```ts\n * withoutTrailingSlash('') // => ''\n * withoutTrailingSlash('/') // => ''\n * withoutTrailingSlash('no/slash/') // => 'no/slash'\n * withoutTrailingSlash('already/has/slash') // => 'already/has/slash'\n * withoutTrailingSlash(undefined) // => undefined\n * withoutTrailingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withoutTrailingSlash(url: string): string\n\n/**\n * Removes the trailing slash `/` from the given URL if it is present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * without a trailing slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withoutTrailingSlash\n *\n * @example\n * ```ts\n * withoutTrailingSlash('') // => ''\n * withoutTrailingSlash('/') // => ''\n * withoutTrailingSlash('no/slash/') // => 'no/slash'\n * withoutTrailingSlash('already/has/slash') // => 'already/has/slash'\n * withoutTrailingSlash(undefined) // => undefined\n * withoutTrailingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withoutTrailingSlash(url: undefined): undefined\n\n/**\n * Removes the trailing slash `/` from the given URL if it is present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * without a trailing slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withoutTrailingSlash\n *\n * @example\n * ```ts\n * withoutTrailingSlash('') // => ''\n * withoutTrailingSlash('/') // => ''\n * withoutTrailingSlash('no/slash/') // => 'no/slash'\n * withoutTrailingSlash('already/has/slash') // => 'already/has/slash'\n * withoutTrailingSlash(undefined) // => undefined\n * withoutTrailingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withoutTrailingSlash(url: null): null\n\n/**\n * Removes the trailing slash `/` from the given URL if it is present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * without a trailing slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withoutTrailingSlash\n *\n * @example\n * ```ts\n * withoutTrailingSlash('') // => ''\n * withoutTrailingSlash('/') // => ''\n * withoutTrailingSlash('no/slash/') // => 'no/slash'\n * withoutTrailingSlash('already/has/slash') // => 'already/has/slash'\n * withoutTrailingSlash(undefined) // => undefined\n * withoutTrailingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withoutTrailingSlash(\n url: string | undefined | null,\n): string | undefined | null {\n if (url === undefined || url === null) {\n return url\n }\n return url.replace(/\\/+$/, '')\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Adds a leading slash `/` to the given URL if it is not already present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * with a leading slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string with a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withLeadingSlash\n *\n * @example\n * ```ts\n * withLeadingSlash('') // => '/'\n * withLeadingSlash('no/slash') // => '/no/slash'\n * withLeadingSlash('/already/has/slash') // => '/already/has/slash'\n * withLeadingSlash(undefined) // => undefined\n * withLeadingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withLeadingSlash(url: string): string\n\n/**\n * Adds a leading slash `/` to the given URL if it is not already present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * with a leading slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string with a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withLeadingSlash\n *\n * @example\n * ```ts\n * withLeadingSlash('') // => '/'\n * withLeadingSlash('no/slash') // => '/no/slash'\n * withLeadingSlash('/already/has/slash') // => '/already/has/slash'\n * withLeadingSlash(undefined) // => undefined\n * withLeadingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withLeadingSlash(url: undefined): undefined\n\n/**\n * Adds a leading slash `/` to the given URL if it is not already present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * with a leading slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string with a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withLeadingSlash\n *\n * @example\n * ```ts\n * withLeadingSlash('') // => '/'\n * withLeadingSlash('no/slash') // => '/no/slash'\n * withLeadingSlash('/already/has/slash') // => '/already/has/slash'\n * withLeadingSlash(undefined) // => undefined\n * withLeadingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withLeadingSlash(url: null): null\n\n/**\n * Adds a leading slash `/` to the given URL if it is not already present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * with a leading slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string with a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withLeadingSlash\n *\n * @example\n * ```ts\n * withLeadingSlash('') // => '/'\n * withLeadingSlash('no/slash') // => '/no/slash'\n * withLeadingSlash('/already/has/slash') // => '/already/has/slash'\n * withLeadingSlash(undefined) // => undefined\n * withLeadingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withLeadingSlash(\n url: string | undefined | null,\n): string | undefined | null {\n if (url === undefined || url === null) {\n return url\n }\n return url[0] === '/' ? url : '/' + url\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/*\n * This program is under the terms of the GNU Lesser General Public License version 3\n * The full license information can be found in LICENSE in the root directory of this project.\n */\n\nimport { withoutTrailingSlash } from \"./withoutTrailingSlash\";\nimport { withLeadingSlash } from \"./withLeadingSlash\";\nimport { cleanPath } from \"./cleanPath\";\n\n/**\n * Converts a relative URL to an absolute URL using the current document base URI.\n * @param relativeUrl - The relative URL to convert\n * @returns The absolute URL\n * @since 1.0.0\n */\nexport function relativeURLToAbsolute(relativeUrl: string): string {\n return (\n withoutTrailingSlash(document.baseURI ?? window.location.origin) +\n cleanPath(withLeadingSlash(relativeUrl))\n );\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Adds a trailing slash `/` to the given URL if it is not already present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * with a trailing slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string with a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withTrailingSlash\n *\n * @example\n * ```ts\n * withTrailingSlash('') // => '/'\n * withTrailingSlash('no/slash') // => 'no/slash/'\n * withTrailingSlash('already/has/slash/') // => 'already/has/slash/'\n * withTrailingSlash(undefined) // => undefined\n * withTrailingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withTrailingSlash(url: string): string\n\n/**\n * Adds a trailing slash `/` to the given URL if it is not already present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * with a trailing slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string with a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withTrailingSlash\n *\n * @example\n * ```ts\n * withTrailingSlash('') // => '/'\n * withTrailingSlash('no/slash') // => 'no/slash/'\n * withTrailingSlash('already/has/slash/') // => 'already/has/slash/'\n * withTrailingSlash(undefined) // => undefined\n * withTrailingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withTrailingSlash(url: undefined): undefined\n\n/**\n * Adds a trailing slash `/` to the given URL if it is not already present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * with a trailing slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string with a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withTrailingSlash\n *\n * @example\n * ```ts\n * withTrailingSlash('') // => '/'\n * withTrailingSlash('no/slash') // => 'no/slash/'\n * withTrailingSlash('already/has/slash/') // => 'already/has/slash/'\n * withTrailingSlash(undefined) // => undefined\n * withTrailingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withTrailingSlash(url: null): null\n\n/**\n * Adds a trailing slash `/` to the given URL if it is not already present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * with a trailing slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string with a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withTrailingSlash\n *\n * @example\n * ```ts\n * withTrailingSlash('') // => '/'\n * withTrailingSlash('no/slash') // => 'no/slash/'\n * withTrailingSlash('already/has/slash/') // => 'already/has/slash/'\n * withTrailingSlash(undefined) // => undefined\n * withTrailingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withTrailingSlash(\n url: string | undefined | null,\n): string | undefined | null {\n if (url === undefined || url === null) {\n return url\n }\n return url[url.length - 1] === '/' ? url : url + '/'\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Removes the leading slash `/` from the given URL if it is present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * without a leading slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withoutLeadingSlash\n *\n * @example\n * ```ts\n * withoutLeadingSlash('') // => ''\n * withoutLeadingSlash('/') // => ''\n * withoutLeadingSlash('/no/slash') // => 'no/slash'\n * withoutLeadingSlash('already/has/slash') // => 'already/has/slash'\n * withoutLeadingSlash(undefined) // => undefined\n * withoutLeadingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withoutLeadingSlash(url: string): string\n\n/**\n * Removes the leading slash `/` from the given URL if it is present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * without a leading slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withoutLeadingSlash\n *\n * @example\n * ```ts\n * withoutLeadingSlash('') // => ''\n * withoutLeadingSlash('/') // => ''\n * withoutLeadingSlash('/no/slash') // => 'no/slash'\n * withoutLeadingSlash('already/has/slash') // => 'already/has/slash'\n * withoutLeadingSlash(undefined) // => undefined\n * withoutLeadingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withoutLeadingSlash(url: undefined): undefined\n\n/**\n * Removes the leading slash `/` from the given URL if it is present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * without a leading slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withoutLeadingSlash\n *\n * @example\n * ```ts\n * withoutLeadingSlash('') // => ''\n * withoutLeadingSlash('/') // => ''\n * withoutLeadingSlash('/no/slash') // => 'no/slash'\n * withoutLeadingSlash('already/has/slash') // => 'already/has/slash'\n * withoutLeadingSlash(undefined) // => undefined\n * withoutLeadingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withoutLeadingSlash(url: null): null\n\n/**\n * Removes the leading slash `/` from the given URL if it is present.\n *\n * This function is useful for ensuring that URLs are properly formatted\n * without a leading slash, which is often required in web development for\n * consistency and to avoid issues with relative paths.\n *\n * @param url - The URL string to be processed. Can be `string`, `undefined`, or `null`.\n * @returns The URL string without a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.\n *\n * @see https://radashi.js.org/reference/url/withoutLeadingSlash\n *\n * @example\n * ```ts\n * withoutLeadingSlash('') // => ''\n * withoutLeadingSlash('/') // => ''\n * withoutLeadingSlash('/no/slash') // => 'no/slash'\n * withoutLeadingSlash('already/has/slash') // => 'already/has/slash'\n * withoutLeadingSlash(undefined) // => undefined\n * withoutLeadingSlash(null) // => null\n * ```\n * @since 1.0.0\n */\nexport function withoutLeadingSlash(\n url: string | undefined | null,\n): string | undefined | null {\n if (url === undefined || url === null) {\n return url\n }\n return url[0] === '/' ? url.slice(1) : url\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,UACd,KAC2B;CAC3B,IAAI,QAAQ,KAAA,KAAa,QAAQ,MAC/B,OAAO;CAET,OAAO,IAAI,QAAQ,gBAAgB,KAAK;;;;ACP1C,SAAgB,eAAe,KAA2D;CACxF,IAAI,QAAQ,KAAA,KAAa,QAAQ,MAC/B,OAAO;CAIT,MAAM,aAAa,IAAI,QAAQ,IAAI;CACnC,MAAM,gBAAgB,IAAI,QAAQ,IAAI;CAEtC,IAAI,WAAW;CAEf,IAAI,eAAe,MAAM,kBAAkB,IAEzC,WAAW,KAAK,IAAI,YAAY,cAAc;MACzC,IAAI,eAAe,IAExB,WAAW;MACN,IAAI,kBAAkB,IAE3B,WAAW;CAIb,IAAI,aAAa,IACf,OAAO;CAIT,OAAO,IAAI,UAAU,GAAG,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;ACuDnC,SAAgB,SACd,KAC2B;CAC3B,IAAI,QAAQ,KAAA,KAAa,QAAQ,MAC/B,OAAO;CAET,MAAM,CAAC,QAAQ,IAAI,MAAM,OAAO;CAChC,OAAO;;;;;AC7DT,IAAM,iBAAyC;CAC7C,cAAc;CACd,cAAc;CACd,iBAAiB;CAClB;;AAGD,IAAM,aAAa;;;;;AAMnB,IAAM,SACJ;AAEF,SAAS,oBACP,MACA,MACA,SACA,WACmB;CACnB,MAAM,WAAW,QAAQ,QAAQ,IAAI;CACrC,MAAM,QAAQ,QAAQ,MAAM,GAAG,SAAS;CACxC,MAAM,OAAO,QAAQ,MAAM,WAAW,EAAE;CACxC,OAAO;EAAE;EAAM;EAAM,MAAM,GAAG,MAAM,GAAG;EAAQ;EAAO;EAAM,QAAQ,KAAA;EAAW;EAAW;;AAG5F,SAAS,YACP,KACA,MACA,WAC+B;CAE/B,MAAM,iBAAiB,iDAAiD,KAAK,IAAI;CACjF,IAAI,gBAAgB;EAClB,MAAM,OAAO,eAAe;EAC5B,MAAM,OAAO,eAAe;EAC5B,MAAM,WAAW,KAAK,QAAQ,IAAI;EAGlC,OAAO;GAAE;GAAM;GAAM;GAAM,OAFb,KAAK,MAAM,GAAG,SAED;GAAO,MADrB,KAAK,MAAM,WAAW,EACD;GAAM,QAAQ,KAAA;GAAW;GAAW;;CAIxE,MAAM,YAAY,kBAAkB,KAAK,IAAI;CAC7C,IAAI,WACF,OAAO;EAAE;EAAM,MAAM;EAAQ,MAAM,KAAA;EAAW,OAAO,KAAA;EAAW,MAAM,KAAA;EAAW,QAAQ,UAAU;EAAI;EAAW;CAIpH,MAAM,YAAY,yBAAyB,KAAK,IAAI;CACpD,IAAI,WAAW;EACb,MAAM,QAAQ,UAAU;EACxB,MAAM,OAAO,UAAU;EACvB,OAAO;GAAE;GAAM,MAAM;GAAU,MAAM,GAAG,MAAM,GAAG;GAAQ;GAAO;GAAM,QAAQ,KAAA;GAAW;GAAW;;CAItG,MAAM,WAAW,WAAW,KAAK,IAAI;CACrC,IAAI,UAEF,OAAO,oBAAoB,MADd,eAAe,SAAS,OAAO,SAAS,IACd,SAAS,IAAI,UAAU;CAIhE,MAAM,WAAW,OAAO,KAAK,IAAI;CACjC,IAAI,UAEF,OAAO,oBAAoB,MADd,eAAe,SAAS,OAAO,SAAS,IACd,SAAS,IAAI,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgClE,SAAgB,uBAAuB,YAAoD;CACzF,IAAI,eAAe,QAAQ,eAAe,KAAA,GAAW,OAAO,KAAA;CAE5D,IAAI,OAAO,eAAe,UACxB,OAAO,YAAY,YAAY,OAAO,KAAA,EAAU;CAGlD,IAAI,OAAO,eAAe,YAAY,CAAC,MAAM,QAAQ,WAAW,EAAE;EAChE,MAAM,MAAM;EACZ,MAAM,SAAS,IAAI;EACnB,IAAI,OAAO,WAAW,UAAU,OAAO,KAAA;EAGvC,OAAO,YAAY,QAFN,OAAO,IAAI,YAAY,WAAY,IAAI,UAAqB,OACvD,OAAO,IAAI,iBAAiB,WAAY,IAAI,eAA0B,KAAA,EAC7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5D/C,SAAgB,qBACd,KAC2B;CAC3B,IAAI,QAAQ,KAAA,KAAa,QAAQ,MAC/B,OAAO;CAET,OAAO,IAAI,QAAQ,QAAQ,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;ACVhC,SAAgB,iBACd,KAC2B;CAC3B,IAAI,QAAQ,KAAA,KAAa,QAAQ,MAC/B,OAAO;CAET,OAAO,IAAI,OAAO,MAAM,MAAM,MAAM;;;;;;;;;;;;;;;ACrFtC,SAAgB,sBAAsB,aAA6B;CAC/D,OACI,qBAAqB,SAAS,WAAW,OAAO,SAAS,OAAO,GAChE,UAAU,iBAAiB,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;AC4EhD,SAAgB,kBACd,KAC2B;CAC3B,IAAI,QAAQ,KAAA,KAAa,QAAQ,MAC/B,OAAO;CAET,OAAO,IAAI,IAAI,SAAS,OAAO,MAAM,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;ACFnD,SAAgB,oBACd,KAC2B;CAC3B,IAAI,QAAQ,KAAA,KAAa,QAAQ,MAC/B,OAAO;CAET,OAAO,IAAI,OAAO,MAAM,IAAI,MAAM,EAAE,GAAG"}
package/llms.txt ADDED
@@ -0,0 +1,519 @@
1
+ # @helpers4/url
2
+
3
+ > Tree-shakable TypeScript utility functions for the `url` domain.
4
+ > Package: `@helpers4/url` — Version: 2.0.0-beta.3
5
+ > License: LGPL-3.0-or-later
6
+
7
+ ## Installation
8
+
9
+ ```sh
10
+ npm install @helpers4/url
11
+ # or
12
+ pnpm add @helpers4/url
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```typescript
18
+ import { cleanPath, extractPureURI, onlyPath, ... } from '@helpers4/url';
19
+ ```
20
+
21
+ ## Functions
22
+
23
+ | Function | Description |
24
+ |---|---|
25
+ | `cleanPath` | Clean an URL by removing duplicate slashes. The protocol part of the URL is not modified. |
26
+ | `extractPureURI` | Extracts the pure URI from a URL by removing query parameters and fragments. |
27
+ | `onlyPath` | Extract only the path from an URI with optional query and fragments. For example, all these paramet |
28
+ | `parsePackageRepository` | Parse the `repository` field from `package.json` into a structured object. Supports all npm-specifi |
29
+ | `relativeURLToAbsolute` | Converts a relative URL to an absolute URL using the current document base URI. |
30
+ | `withLeadingSlash` | Adds a leading slash `/` to the given URL if it is not already present. This function is useful for |
31
+ | `withoutLeadingSlash` | Removes the leading slash `/` from the given URL if it is present. This function is useful for ensu |
32
+ | `withoutTrailingSlash` | Removes the trailing slash `/` from the given URL if it is present. This function is useful for ens |
33
+ | `withTrailingSlash` | Adds a trailing slash `/` to the given URL if it is not already present. This function is useful fo |
34
+
35
+ ---
36
+
37
+ ## API Reference
38
+
39
+ ### `cleanPath`
40
+
41
+ Clean an URL by removing duplicate slashes.
42
+ The protocol part of the URL is not modified.
43
+
44
+ ```typescript
45
+ import { cleanPath } from '@helpers4/url';
46
+
47
+ cleanPath(url: string | null | undefined): string | null | undefined
48
+ ```
49
+
50
+ **Parameters:**
51
+
52
+ - `url: string | null | undefined` — The URL string to be processed. Can be `string`, `undefined`, or `null`.
53
+
54
+ **Returns:** `string | null | undefined` — The cleaned URL string, or `undefined` if the input is `undefined`, or `null` if the input is `null`.
55
+
56
+ **Examples:**
57
+
58
+ *Remove duplicate slashes*
59
+
60
+ Cleans an URL by removing duplicate slashes while preserving the protocol.
61
+
62
+ ```typescript
63
+ cleanPath('/path//to///resource')
64
+ // => '/path/to/resource'
65
+ ```
66
+
67
+ *Preserve protocol*
68
+
69
+ The double slash after the protocol (http://) is not modified.
70
+
71
+ ```typescript
72
+ cleanPath('http://example.com//path')
73
+ // => 'http://example.com/path'
74
+ ```
75
+
76
+ *Handle null and undefined*
77
+
78
+ Returns null for null input and undefined for undefined input.
79
+
80
+ ```typescript
81
+ cleanPath(null) // => null
82
+ cleanPath(undefined) // => undefined
83
+ ```
84
+
85
+ ---
86
+
87
+ ### `extractPureURI`
88
+
89
+ Extracts the pure URI from a URL by removing query parameters and fragments.
90
+
91
+ ```typescript
92
+ import { extractPureURI } from '@helpers4/url';
93
+
94
+ extractPureURI(url: string): string
95
+ ```
96
+
97
+ **Parameters:**
98
+
99
+ - `url: string` — The URL string to process
100
+
101
+ **Returns:** `string` — The URI without query parameters and fragments, or the original value if undefined/null
102
+
103
+ ```typescript
104
+ import { extractPureURI } from '@helpers4/url';
105
+
106
+ extractPureURI(url: undefined): undefined
107
+ ```
108
+
109
+ **Parameters:**
110
+
111
+ - `url: undefined` — The URL string to process
112
+
113
+ **Returns:** `undefined` — The URI without query parameters and fragments, or the original value if undefined/null
114
+
115
+ ```typescript
116
+ import { extractPureURI } from '@helpers4/url';
117
+
118
+ extractPureURI(url: null): null
119
+ ```
120
+
121
+ **Parameters:**
122
+
123
+ - `url: null` — The URL string to process
124
+
125
+ **Returns:** `null` — The URI without query parameters and fragments, or the original value if undefined/null
126
+
127
+ **Examples:**
128
+
129
+ *Remove query parameters and fragments*
130
+
131
+ Strips everything after ? or # from the URL.
132
+
133
+ ```typescript
134
+ extractPureURI('https://example.com/path?query=1#section')
135
+ // => 'https://example.com/path'
136
+ ```
137
+
138
+ ---
139
+
140
+ ### `onlyPath`
141
+
142
+ Extract only the path from an URI with optional query and fragments.
143
+
144
+ For example, all these parameters will return `/path`:
145
+ - `/path`
146
+ - `/path?query=thing`
147
+ - `/path#fragment`
148
+ - `/path?query=thing#fragment`
149
+
150
+ ```typescript
151
+ import { onlyPath } from '@helpers4/url';
152
+
153
+ onlyPath(url: string): string
154
+ ```
155
+
156
+ **Parameters:**
157
+
158
+ - `url: string` — The URL string to be processed. Can be `string`, `undefined`, or `null`.
159
+
160
+ **Returns:** `string` — The URL string without query and fragment, or `undefined` if the input is `undefined`, or `null` if the input is `null`.
161
+
162
+ ```typescript
163
+ import { onlyPath } from '@helpers4/url';
164
+
165
+ onlyPath(url: null): null
166
+ ```
167
+
168
+ **Parameters:**
169
+
170
+ - `url: null` — The URL string to be processed. Can be `string`, `undefined`, or `null`.
171
+
172
+ **Returns:** `null` — The URL string without query and fragment, or `undefined` if the input is `undefined`, or `null` if the input is `null`.
173
+
174
+ ```typescript
175
+ import { onlyPath } from '@helpers4/url';
176
+
177
+ onlyPath(url: undefined): undefined
178
+ ```
179
+
180
+ **Parameters:**
181
+
182
+ - `url: undefined` — The URL string to be processed. Can be `string`, `undefined`, or `null`.
183
+
184
+ **Returns:** `undefined` — The URL string without query and fragment, or `undefined` if the input is `undefined`, or `null` if the input is `null`.
185
+
186
+ **Examples:**
187
+
188
+ *Extract the path from a URL*
189
+
190
+ Strips query parameters and fragments from a URL path.
191
+
192
+ ```typescript
193
+ onlyPath('/path?query=thing#fragment')
194
+ // => '/path'
195
+ ```
196
+
197
+ ---
198
+
199
+ ### `parsePackageRepository`
200
+
201
+ Parse the `repository` field from `package.json` into a structured object.
202
+
203
+ Supports all npm-specified formats:
204
+ - **Object form**: `{ "type": "git", "url": "...", "directory": "..." }`
205
+ - **GitHub shorthand**: `"owner/repo"` or `"github:owner/repo"`
206
+ - **Platform shorthands**: `"gitlab:owner/repo"`, `"bitbucket:owner/repo"`
207
+ - **Gist shorthand**: `"gist:<id>"`
208
+ - **URL forms**: `git+https://`, `https://`, `git://`, `git@` SSH, `git+ssh://`
209
+
210
+ Returns `undefined` for `null`, `undefined`, arrays, or values that cannot
211
+ be matched to any recognised format.
212
+
213
+ ```typescript
214
+ import { parsePackageRepository } from '@helpers4/url';
215
+
216
+ parsePackageRepository(repository: unknown): PackageRepository | undefined
217
+ ```
218
+
219
+ **Parameters:**
220
+
221
+ - `repository: unknown` — The `repository` field value from `package.json`.
222
+
223
+ **Returns:** `PackageRepository | undefined` — A parsed PackageRepository object, or `undefined` if the
224
+ input cannot be parsed.
225
+
226
+ **Examples:**
227
+
228
+ *Parse the npm canonical object form*
229
+
230
+ Parses the full object form written by npm publish.
231
+
232
+ ```typescript
233
+ parsePackageRepository({ type: 'git', url: 'git+https://github.com/helpers4/typescript.git' })
234
+ // => { type: 'git', host: 'github', slug: 'helpers4/typescript',
235
+ // owner: 'helpers4', repo: 'typescript', gistId: undefined, directory: undefined }
236
+ ```
237
+
238
+ *Parse npm shorthand forms*
239
+
240
+ npm accepts "owner/repo", "github:owner/repo", "gitlab:owner/repo" etc. as shorthand.
241
+
242
+ ```typescript
243
+ parsePackageRepository('helpers4/typescript')
244
+ // => { host: 'github', slug: 'helpers4/typescript', owner: 'helpers4', repo: 'typescript', ... }
245
+
246
+ parsePackageRepository('gitlab:myorg/myproject')
247
+ // => { host: 'gitlab', slug: 'myorg/myproject', owner: 'myorg', repo: 'myproject', ... }
248
+
249
+ parsePackageRepository('gist:11081aaa281')
250
+ // => { host: 'gist', gistId: '11081aaa281', slug: undefined, owner: undefined, ... }
251
+ ```
252
+
253
+ ---
254
+
255
+ ### `relativeURLToAbsolute`
256
+
257
+ Converts a relative URL to an absolute URL using the current document base URI.
258
+
259
+ ```typescript
260
+ import { relativeURLToAbsolute } from '@helpers4/url';
261
+
262
+ relativeURLToAbsolute(relativeUrl: string): string
263
+ ```
264
+
265
+ **Parameters:**
266
+
267
+ - `relativeUrl: string` — The relative URL to convert
268
+
269
+ **Returns:** `string` — The absolute URL
270
+
271
+ **Examples:**
272
+
273
+ *Convert a relative URL to absolute*
274
+
275
+ Prepends the base URI to a relative path, cleaning duplicate slashes.
276
+
277
+ ```typescript
278
+ relativeURLToAbsolute('/api/data')
279
+ // => 'http://localhost/api/data' (depends on document.baseURI)
280
+ ```
281
+
282
+ ---
283
+
284
+ ### `withLeadingSlash`
285
+
286
+ Adds a leading slash `/` to the given URL if it is not already present.
287
+
288
+ This function is useful for ensuring that URLs are properly formatted
289
+ with a leading slash, which is often required in web development for
290
+ consistency and to avoid issues with relative paths.
291
+
292
+ ```typescript
293
+ import { withLeadingSlash } from '@helpers4/url';
294
+
295
+ withLeadingSlash(url: string): string
296
+ ```
297
+
298
+ **Parameters:**
299
+
300
+ - `url: string` — The URL string to be processed. Can be `string`, `undefined`, or `null`.
301
+
302
+ **Returns:** `string` — The URL string with a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.
303
+
304
+ ```typescript
305
+ import { withLeadingSlash } from '@helpers4/url';
306
+
307
+ withLeadingSlash(url: undefined): undefined
308
+ ```
309
+
310
+ **Parameters:**
311
+
312
+ - `url: undefined` — The URL string to be processed. Can be `string`, `undefined`, or `null`.
313
+
314
+ **Returns:** `undefined` — The URL string with a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.
315
+
316
+ ```typescript
317
+ import { withLeadingSlash } from '@helpers4/url';
318
+
319
+ withLeadingSlash(url: null): null
320
+ ```
321
+
322
+ **Parameters:**
323
+
324
+ - `url: null` — The URL string to be processed. Can be `string`, `undefined`, or `null`.
325
+
326
+ **Returns:** `null` — The URL string with a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.
327
+
328
+ **Examples:**
329
+
330
+ *Add a leading slash*
331
+
332
+ Ensures the URL starts with a forward slash.
333
+
334
+ ```typescript
335
+ withLeadingSlash('path/to/resource')
336
+ // => '/path/to/resource'
337
+ ```
338
+
339
+ *Already has leading slash*
340
+
341
+ Does not add a duplicate slash.
342
+
343
+ ```typescript
344
+ withLeadingSlash('/already/has/slash')
345
+ // => '/already/has/slash'
346
+ ```
347
+
348
+ ---
349
+
350
+ ### `withoutLeadingSlash`
351
+
352
+ Removes the leading slash `/` from the given URL if it is present.
353
+
354
+ This function is useful for ensuring that URLs are properly formatted
355
+ without a leading slash, which is often required in web development for
356
+ consistency and to avoid issues with relative paths.
357
+
358
+ ```typescript
359
+ import { withoutLeadingSlash } from '@helpers4/url';
360
+
361
+ withoutLeadingSlash(url: string): string
362
+ ```
363
+
364
+ **Parameters:**
365
+
366
+ - `url: string` — The URL string to be processed. Can be `string`, `undefined`, or `null`.
367
+
368
+ **Returns:** `string` — The URL string without a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.
369
+
370
+ ```typescript
371
+ import { withoutLeadingSlash } from '@helpers4/url';
372
+
373
+ withoutLeadingSlash(url: undefined): undefined
374
+ ```
375
+
376
+ **Parameters:**
377
+
378
+ - `url: undefined` — The URL string to be processed. Can be `string`, `undefined`, or `null`.
379
+
380
+ **Returns:** `undefined` — The URL string without a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.
381
+
382
+ ```typescript
383
+ import { withoutLeadingSlash } from '@helpers4/url';
384
+
385
+ withoutLeadingSlash(url: null): null
386
+ ```
387
+
388
+ **Parameters:**
389
+
390
+ - `url: null` — The URL string to be processed. Can be `string`, `undefined`, or `null`.
391
+
392
+ **Returns:** `null` — The URL string without a leading slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.
393
+
394
+ **Examples:**
395
+
396
+ *Remove leading slash*
397
+
398
+ Strips the leading slash from a URL path.
399
+
400
+ ```typescript
401
+ withoutLeadingSlash('/path/to/resource')
402
+ // => 'path/to/resource'
403
+ ```
404
+
405
+ ---
406
+
407
+ ### `withoutTrailingSlash`
408
+
409
+ Removes the trailing slash `/` from the given URL if it is present.
410
+
411
+ This function is useful for ensuring that URLs are properly formatted
412
+ without a trailing slash, which is often required in web development for
413
+ consistency and to avoid issues with relative paths.
414
+
415
+ ```typescript
416
+ import { withoutTrailingSlash } from '@helpers4/url';
417
+
418
+ withoutTrailingSlash(url: string): string
419
+ ```
420
+
421
+ **Parameters:**
422
+
423
+ - `url: string` — The URL string to be processed. Can be `string`, `undefined`, or `null`.
424
+
425
+ **Returns:** `string` — The URL string without a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.
426
+
427
+ ```typescript
428
+ import { withoutTrailingSlash } from '@helpers4/url';
429
+
430
+ withoutTrailingSlash(url: undefined): undefined
431
+ ```
432
+
433
+ **Parameters:**
434
+
435
+ - `url: undefined` — The URL string to be processed. Can be `string`, `undefined`, or `null`.
436
+
437
+ **Returns:** `undefined` — The URL string without a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.
438
+
439
+ ```typescript
440
+ import { withoutTrailingSlash } from '@helpers4/url';
441
+
442
+ withoutTrailingSlash(url: null): null
443
+ ```
444
+
445
+ **Parameters:**
446
+
447
+ - `url: null` — The URL string to be processed. Can be `string`, `undefined`, or `null`.
448
+
449
+ **Returns:** `null` — The URL string without a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.
450
+
451
+ **Examples:**
452
+
453
+ *Remove trailing slash*
454
+
455
+ Strips the trailing slash from a URL path.
456
+
457
+ ```typescript
458
+ withoutTrailingSlash('path/to/resource/')
459
+ // => 'path/to/resource'
460
+ ```
461
+
462
+ ---
463
+
464
+ ### `withTrailingSlash`
465
+
466
+ Adds a trailing slash `/` to the given URL if it is not already present.
467
+
468
+ This function is useful for ensuring that URLs are properly formatted
469
+ with a trailing slash, which is often required in web development for
470
+ consistency and to avoid issues with relative paths.
471
+
472
+ ```typescript
473
+ import { withTrailingSlash } from '@helpers4/url';
474
+
475
+ withTrailingSlash(url: string): string
476
+ ```
477
+
478
+ **Parameters:**
479
+
480
+ - `url: string` — The URL string to be processed. Can be `string`, `undefined`, or `null`.
481
+
482
+ **Returns:** `string` — The URL string with a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.
483
+
484
+ ```typescript
485
+ import { withTrailingSlash } from '@helpers4/url';
486
+
487
+ withTrailingSlash(url: undefined): undefined
488
+ ```
489
+
490
+ **Parameters:**
491
+
492
+ - `url: undefined` — The URL string to be processed. Can be `string`, `undefined`, or `null`.
493
+
494
+ **Returns:** `undefined` — The URL string with a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.
495
+
496
+ ```typescript
497
+ import { withTrailingSlash } from '@helpers4/url';
498
+
499
+ withTrailingSlash(url: null): null
500
+ ```
501
+
502
+ **Parameters:**
503
+
504
+ - `url: null` — The URL string to be processed. Can be `string`, `undefined`, or `null`.
505
+
506
+ **Returns:** `null` — The URL string with a trailing slash, or `undefined` if the input is `undefined`, or `null` if the input is `null`.
507
+
508
+ **Examples:**
509
+
510
+ *Add a trailing slash*
511
+
512
+ Ensures the URL ends with a forward slash.
513
+
514
+ ```typescript
515
+ withTrailingSlash('path/to/resource')
516
+ // => 'path/to/resource/'
517
+ ```
518
+
519
+ ---
package/meta/api.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "category": "url",
3
- "version": "2.0.0-alpha.9",
3
+ "version": "2.0.0-beta.3",
4
4
  "functions": [
5
5
  {
6
6
  "name": "cleanPath",
@@ -165,6 +165,49 @@
165
165
  ],
166
166
  "sourceFile": "onlyPath.ts"
167
167
  },
168
+ {
169
+ "name": "parsePackageRepository",
170
+ "kind": "function",
171
+ "description": "Parse the `repository` field from `package.json` into a structured object.\n\nSupports all npm-specified formats:\n- **Object form**: `{ \"type\": \"git\", \"url\": \"...\", \"directory\": \"...\" }`\n- **GitHub shorthand**: `\"owner/repo\"` or `\"github:owner/repo\"`\n- **Platform shorthands**: `\"gitlab:owner/repo\"`, `\"bitbucket:owner/repo\"`\n- **Gist shorthand**: `\"gist:<id>\"`\n- **URL forms**: `git+https://`, `https://`, `git://`, `git@` SSH, `git+ssh://`\n\nReturns `undefined` for `null`, `undefined`, arrays, or values that cannot\nbe matched to any recognised format.",
172
+ "since": "next",
173
+ "signatures": [
174
+ {
175
+ "signature": "parsePackageRepository(repository: unknown): PackageRepository | undefined",
176
+ "description": "Parse the `repository` field from `package.json` into a structured object.\n\nSupports all npm-specified formats:\n- **Object form**: `{ \"type\": \"git\", \"url\": \"...\", \"directory\": \"...\" }`\n- **GitHub shorthand**: `\"owner/repo\"` or `\"github:owner/repo\"`\n- **Platform shorthands**: `\"gitlab:owner/repo\"`, `\"bitbucket:owner/repo\"`\n- **Gist shorthand**: `\"gist:<id>\"`\n- **URL forms**: `git+https://`, `https://`, `git://`, `git@` SSH, `git+ssh://`\n\nReturns `undefined` for `null`, `undefined`, arrays, or values that cannot\nbe matched to any recognised format.",
177
+ "params": [
178
+ {
179
+ "name": "repository",
180
+ "type": "unknown",
181
+ "description": "The `repository` field value from `package.json`."
182
+ }
183
+ ],
184
+ "returns": {
185
+ "type": "PackageRepository | undefined",
186
+ "description": "A parsed PackageRepository object, or `undefined` if the\n input cannot be parsed."
187
+ }
188
+ }
189
+ ],
190
+ "examples": [
191
+ {
192
+ "title": "Parse the npm canonical object form",
193
+ "description": "Parses the full object form written by npm publish.",
194
+ "code": "parsePackageRepository({ type: 'git', url: 'git+https://github.com/helpers4/typescript.git' })\n// => { type: 'git', host: 'github', slug: 'helpers4/typescript',\n// owner: 'helpers4', repo: 'typescript', gistId: undefined, directory: undefined }"
195
+ },
196
+ {
197
+ "title": "Parse npm shorthand forms",
198
+ "description": "npm accepts \"owner/repo\", \"github:owner/repo\", \"gitlab:owner/repo\" etc. as shorthand.",
199
+ "code": "parsePackageRepository('helpers4/typescript')\n// => { host: 'github', slug: 'helpers4/typescript', owner: 'helpers4', repo: 'typescript', ... }\n\nparsePackageRepository('gitlab:myorg/myproject')\n// => { host: 'gitlab', slug: 'myorg/myproject', owner: 'myorg', repo: 'myproject', ... }\n\nparsePackageRepository('gist:11081aaa281')\n// => { host: 'gist', gistId: '11081aaa281', slug: undefined, owner: undefined, ... }"
200
+ }
201
+ ],
202
+ "sourceFile": "parsePackageRepository.ts",
203
+ "relatedTypes": [
204
+ {
205
+ "name": "PackageRepository",
206
+ "description": "Structured representation of a parsed `repository` field from `package.json`.",
207
+ "typeDefinition": "interface PackageRepository {\n directory: string | undefined;\n gistId: string | undefined;\n host: string & object | \"github\" | \"gitlab\" | \"bitbucket\" | \"gist\";\n owner: string | undefined;\n repo: string | undefined;\n slug: string | undefined;\n type: string;\n}"
208
+ }
209
+ ]
210
+ },
168
211
  {
169
212
  "name": "relativeURLToAbsolute",
170
213
  "kind": "function",
@@ -0,0 +1,6 @@
1
+ {
2
+ "category": "url",
3
+ "label": "URL",
4
+ "smallDescription": "URL parsing and manipulation utilities",
5
+ "description": "Utilities for working with URLs including path cleaning, slash management, and URL transformation"
6
+ }
@@ -41,6 +41,21 @@
41
41
  }
42
42
  ]
43
43
  },
44
+ {
45
+ "name": "parsePackageRepository",
46
+ "examples": [
47
+ {
48
+ "title": "Parse the npm canonical object form",
49
+ "description": "Parses the full object form written by npm publish.",
50
+ "code": "parsePackageRepository({ type: 'git', url: 'git+https://github.com/helpers4/typescript.git' })\n// => { type: 'git', host: 'github', slug: 'helpers4/typescript',\n// owner: 'helpers4', repo: 'typescript', gistId: undefined, directory: undefined }"
51
+ },
52
+ {
53
+ "title": "Parse npm shorthand forms",
54
+ "description": "npm accepts \"owner/repo\", \"github:owner/repo\", \"gitlab:owner/repo\" etc. as shorthand.",
55
+ "code": "parsePackageRepository('helpers4/typescript')\n// => { host: 'github', slug: 'helpers4/typescript', owner: 'helpers4', repo: 'typescript', ... }\n\nparsePackageRepository('gitlab:myorg/myproject')\n// => { host: 'gitlab', slug: 'myorg/myproject', owner: 'myorg', repo: 'myproject', ... }\n\nparsePackageRepository('gist:11081aaa281')\n// => { host: 'gist', gistId: '11081aaa281', slug: undefined, owner: undefined, ... }"
56
+ }
57
+ ]
58
+ },
44
59
  {
45
60
  "name": "relativeURLToAbsolute",
46
61
  "examples": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helpers4/url",
3
- "version": "2.0.0-alpha.9",
3
+ "version": "2.0.0-beta.3",
4
4
  "description": "A set of helpers in TS/JS, compatible with tree-shaking, for url.",
5
5
  "author": "baxyz <baxy@etik.com>",
6
6
  "license": "LGPL-3.0",
@@ -21,6 +21,7 @@
21
21
  "./meta/api.json": "./meta/api.json",
22
22
  "./meta/examples.json": "./meta/examples.json",
23
23
  "./meta/licenses.json": "./meta/licenses.json",
24
+ "./llms.txt": "./llms.txt",
24
25
  "./package.json": "./package.json"
25
26
  },
26
27
  "keywords": [
@@ -29,6 +30,7 @@
29
30
  "cleanPath",
30
31
  "extractPureURI",
31
32
  "onlyPath",
33
+ "parsePackageRepository",
32
34
  "relativeURLToAbsolute",
33
35
  "withLeadingSlash",
34
36
  "withTrailingSlash",
@@ -40,6 +42,7 @@
40
42
  "lib/index.d.ts",
41
43
  "lib/index.js.map",
42
44
  "meta/",
45
+ "llms.txt",
43
46
  "LICENSE.md",
44
47
  "package.json",
45
48
  "README.md"