@jsenv/urls 2.4.1 → 2.5.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/urls",
3
- "version": "2.4.1",
3
+ "version": "2.5.1",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,6 +28,6 @@
28
28
  "test": "node --conditions=development ./scripts/test.mjs"
29
29
  },
30
30
  "dependencies": {
31
- "@jsenv/humanize": "1.2.6"
31
+ "@jsenv/humanize": "1.2.7"
32
32
  }
33
33
  }
package/src/main.js CHANGED
@@ -11,8 +11,9 @@ export {
11
11
  injectQueryParamWithoutEncoding,
12
12
  injectQueryParamIntoSpecifierWithoutEncoding,
13
13
  renderUrlOrRelativeUrlFilename,
14
- setUrlExtension,
15
14
  setUrlFilename,
15
+ setUrlBasename,
16
+ setUrlExtension,
16
17
  ensurePathnameTrailingSlash,
17
18
  removePathnameTrailingSlash,
18
19
  asUrlUntilPathname,
@@ -42,3 +43,5 @@ export { urlToResource } from "./url_to_resource.js";
42
43
  export { urlToScheme } from "./url_to_scheme.js";
43
44
 
44
45
  export { getCommonPathname } from "./common_pathname.js";
46
+
47
+ export { yieldAncestorUrls } from "./yield_ancestor_urls.js";
@@ -1,7 +1,23 @@
1
1
  import { urlToFilename } from "./url_to_filename.js";
2
2
 
3
- export const urlToBasename = (url) => {
3
+ export const urlToBasename = (url, removeAllExtensions) => {
4
4
  const filename = urlToFilename(url);
5
+ const basename = filenameToBasename(filename);
6
+ if (!removeAllExtensions) {
7
+ return basename;
8
+ }
9
+ let currentBasename = basename;
10
+ // eslint-disable-next-line no-constant-condition
11
+ while (true) {
12
+ const nextBasename = filenameToBasename(basename);
13
+ if (nextBasename === currentBasename) {
14
+ return currentBasename;
15
+ }
16
+ currentBasename = nextBasename;
17
+ }
18
+ };
19
+
20
+ export const filenameToBasename = (filename) => {
5
21
  const dotLastIndex = filename.lastIndexOf(".");
6
22
  const basename =
7
23
  dotLastIndex === -1 ? filename : filename.slice(0, dotLastIndex);
@@ -2,6 +2,10 @@ import { urlToPathname } from "./url_to_pathname.js";
2
2
 
3
3
  export const urlToFilename = (url) => {
4
4
  const pathname = urlToPathname(url);
5
+ return pathnameToFilename(pathname);
6
+ };
7
+
8
+ export const pathnameToFilename = (pathname) => {
5
9
  const pathnameBeforeLastSlash = pathname.endsWith("/")
6
10
  ? pathname.slice(0, -1)
7
11
  : pathname;
package/src/url_utils.js CHANGED
@@ -1,4 +1,6 @@
1
+ import { filenameToBasename } from "./url_to_basename.js";
1
2
  import { urlToExtension } from "./url_to_extension.js";
3
+ import { pathnameToFilename } from "./url_to_filename.js";
2
4
  import { urlToOrigin } from "./url_to_origin.js";
3
5
  import { urlToResource } from "./url_to_resource.js";
4
6
 
@@ -139,6 +141,9 @@ export const renderUrlOrRelativeUrlFilename = (urlOrRelativeUrl, renderer) => {
139
141
  export const setUrlExtension = (url, extension) => {
140
142
  const origin = urlToOrigin(url);
141
143
  const currentExtension = urlToExtension(url);
144
+ if (typeof extension === "function") {
145
+ extension = extension(currentExtension);
146
+ }
142
147
  const resource = urlToResource(url);
143
148
  const [pathname, search] = resource.split("?");
144
149
  const pathnameWithoutExtension = currentExtension
@@ -157,14 +162,22 @@ export const setUrlExtension = (url, extension) => {
157
162
  };
158
163
 
159
164
  export const setUrlFilename = (url, filename) => {
160
- const urlObject = new URL(url);
161
- let { origin, search, hash } = urlObject;
162
- // origin is "null" for "file://" urls with Node.js
163
- if (origin === "null" && urlObject.href.startsWith("file:")) {
164
- origin = "file://";
165
- }
166
- const parentPathname = new URL("./", urlObject).pathname;
167
- return `${origin}${parentPathname}${filename}${search}${hash}`;
165
+ const parentPathname = new URL("./", url).pathname;
166
+ return transformUrlPathname(url, (pathname) => {
167
+ if (typeof filename === "function") {
168
+ filename = filename(pathnameToFilename(pathname));
169
+ }
170
+ return `${parentPathname}${filename}`;
171
+ });
172
+ };
173
+
174
+ export const setUrlBasename = (url, basename) => {
175
+ return setUrlFilename(url, (filename) => {
176
+ if (typeof basename === "function") {
177
+ basename = basename(filenameToBasename(filename));
178
+ }
179
+ return `${basename}${urlToExtension(url)}`;
180
+ });
168
181
  };
169
182
 
170
183
  const transformUrlPathname = (url, transformer) => {
@@ -0,0 +1,45 @@
1
+ import { ensurePathnameTrailingSlash } from "./url_utils.js";
2
+
3
+ export function* yieldAncestorUrls(url, rootUrl, { yieldSelf } = {}) {
4
+ url = String(url);
5
+ if (rootUrl) rootUrl = ensurePathnameTrailingSlash(String(rootUrl));
6
+ let currentUrl = url;
7
+ if (currentUrl === rootUrl || currentUrl === "file:///") {
8
+ return;
9
+ }
10
+ if (yieldSelf) {
11
+ yield currentUrl;
12
+ }
13
+ while (true) {
14
+ currentUrl = getParentUrl(currentUrl);
15
+ if (currentUrl === rootUrl || currentUrl === "file:///") {
16
+ break;
17
+ }
18
+ yield currentUrl;
19
+ }
20
+ }
21
+
22
+ const getParentUrl = (url) => {
23
+ if (url.startsWith("file://")) {
24
+ // With node.js new URL('../', 'file:///C:/').href
25
+ // returns "file:///C:/" instead of "file:///"
26
+ const resource = url.slice("file://".length);
27
+ const slashLastIndex = resource.lastIndexOf("/");
28
+ if (slashLastIndex === -1) {
29
+ return url;
30
+ }
31
+ const lastCharIndex = resource.length - 1;
32
+ if (slashLastIndex === lastCharIndex) {
33
+ const slashBeforeLastIndex = resource.lastIndexOf(
34
+ "/",
35
+ slashLastIndex - 1,
36
+ );
37
+ if (slashBeforeLastIndex === -1) {
38
+ return url;
39
+ }
40
+ return `file://${resource.slice(0, slashBeforeLastIndex + 1)}`;
41
+ }
42
+ return `file://${resource.slice(0, slashLastIndex + 1)}`;
43
+ }
44
+ return new URL(url.endsWith("/") ? "../" : "./", url).href;
45
+ };