@jsenv/filesystem 4.2.3 → 4.2.4

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.
Files changed (47) hide show
  1. package/README.md +17 -17
  2. package/package.json +4 -4
  3. package/src/assertDirectoryPresence.js +10 -10
  4. package/src/assertFilePresence.js +10 -10
  5. package/src/bufferToEtag.js +11 -11
  6. package/src/collectDirectoryMatchReport.js +38 -38
  7. package/src/collectFiles.js +35 -35
  8. package/src/comparePathnames.js +23 -23
  9. package/src/copyDirectoryContent.js +37 -37
  10. package/src/copyEntry.js +88 -88
  11. package/src/directory_url_validation.js +14 -14
  12. package/src/ensureEmptyDirectory.js +13 -13
  13. package/src/ensureParentDirectories.js +9 -9
  14. package/src/ensureWindowsDriveLetter.js +19 -19
  15. package/src/fileSystemRootUrl.js +1 -1
  16. package/src/file_url_validation.js +14 -14
  17. package/src/getRealFileSystemUrlSync.js +24 -24
  18. package/src/grantPermissionsOnEntry.js +9 -9
  19. package/src/internal/createWatcher.js +12 -12
  20. package/src/internal/getCommandArgument.js +7 -7
  21. package/src/internal/guard_second_call.js +20 -20
  22. package/src/internal/permissions.js +26 -26
  23. package/src/internal/read_entry_info.js +8 -8
  24. package/src/internal/statsToType.js +9 -9
  25. package/src/internal/track_resources.js +12 -12
  26. package/src/internal/urlTargetsSameFileSystemPath.js +4 -4
  27. package/src/listFilesMatching.js +5 -5
  28. package/src/main.js +35 -35
  29. package/src/moveDirectoryContent.js +37 -37
  30. package/src/moveEntry.js +44 -44
  31. package/src/readDirectory.js +21 -21
  32. package/src/readEntryModificationTime.js +4 -4
  33. package/src/readEntryPermissions.js +10 -10
  34. package/src/readEntryStat.js +27 -27
  35. package/src/readFile.js +12 -12
  36. package/src/readFileSync.js +9 -9
  37. package/src/readSymbolicLink.js +9 -9
  38. package/src/registerDirectoryLifecycle.js +118 -118
  39. package/src/registerFileLifecycle.js +66 -66
  40. package/src/removeEntry.js +81 -81
  41. package/src/testEntryPermissions.js +15 -15
  42. package/src/writeDirectory.js +17 -17
  43. package/src/writeEntryModificationTime.js +10 -10
  44. package/src/writeEntryPermissions.js +26 -26
  45. package/src/writeFile.js +16 -16
  46. package/src/writeFileSync.js +10 -10
  47. package/src/writeSymbolicLink.js +39 -39
package/README.md CHANGED
@@ -5,7 +5,7 @@ Collection of functions to interact with filesystem in Node.js
5
5
  ## List files using pattern matching
6
6
 
7
7
  ```js
8
- import { listFilesMatching } from "@jsenv/filesystem"
8
+ import { listFilesMatching } from "@jsenv/filesystem";
9
9
 
10
10
  const jsFiles = await listFilesMatching({
11
11
  directoryUrl: new URL("./", import.meta.url),
@@ -13,7 +13,7 @@ const jsFiles = await listFilesMatching({
13
13
  "./**/*.js": true,
14
14
  "./**/*.test.js": false,
15
15
  },
16
- })
16
+ });
17
17
  ```
18
18
 
19
19
  ```console
@@ -26,45 +26,45 @@ const jsFiles = await listFilesMatching({
26
26
  ## Watch a specific file changes
27
27
 
28
28
  ```js
29
- import { readFileSync } from "node:fs"
30
- import { registerFileLifecycle } from "@jsenv/filesystem"
29
+ import { readFileSync } from "node:fs";
30
+ import { registerFileLifecycle } from "@jsenv/filesystem";
31
31
 
32
- const packageJSONFileUrl = new URL("./package.json", import.meta.url)
33
- let packageJSON = null
32
+ const packageJSONFileUrl = new URL("./package.json", import.meta.url);
33
+ let packageJSON = null;
34
34
  const unregister = registerFileLifecycle(packageJSONFileUrl, {
35
35
  added: () => {
36
- packageJSON = JSON.parse(String(readFileSync(packageJSONFileUrl)))
36
+ packageJSON = JSON.parse(String(readFileSync(packageJSONFileUrl)));
37
37
  },
38
38
  updated: () => {
39
- packageJSON = JSON.parse(String(readFileSync(packageJSONFileUrl)))
39
+ packageJSON = JSON.parse(String(readFileSync(packageJSONFileUrl)));
40
40
  },
41
41
  removed: () => {
42
- packageJSON = null
42
+ packageJSON = null;
43
43
  },
44
44
  notifyExistent: true,
45
- })
46
- unregister() // stop watching the file changes
45
+ });
46
+ unregister(); // stop watching the file changes
47
47
  ```
48
48
 
49
49
  ## Watch many files changes
50
50
 
51
51
  ```js
52
- import { registerDirectoryLifecycle } from "@jsenv/filesystem"
52
+ import { registerDirectoryLifecycle } from "@jsenv/filesystem";
53
53
 
54
- const directoryContentDescription = {}
54
+ const directoryContentDescription = {};
55
55
  const unregister = registerDirectoryLifecycle("file:///directory/", {
56
56
  watchPatterns: {
57
57
  "./**/*": true,
58
58
  "./node_modules/": false,
59
59
  },
60
60
  added: ({ relativeUrl, type }) => {
61
- directoryContentDescription[relativeUrl] = type
61
+ directoryContentDescription[relativeUrl] = type;
62
62
  },
63
63
  removed: ({ relativeUrl }) => {
64
- delete directoryContentDescription[relativeUrl]
64
+ delete directoryContentDescription[relativeUrl];
65
65
  },
66
- })
67
- unregister() // stop watching the directory changes
66
+ });
67
+ unregister(); // stop watching the directory changes
68
68
  ```
69
69
 
70
70
  # API
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@jsenv/filesystem",
3
- "version": "4.2.3",
3
+ "version": "4.2.4",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
7
- "url": "https://github.com/jsenv/jsenv-core",
8
- "directory": "packages/filesystem"
7
+ "url": "https://github.com/jsenv/core",
8
+ "directory": "packages/independent/filesystem"
9
9
  },
10
10
  "publishConfig": {
11
11
  "access": "public"
@@ -29,7 +29,7 @@
29
29
  "test": "node --conditions=development ./scripts/test.mjs"
30
30
  },
31
31
  "dependencies": {
32
- "@jsenv/urls": "2.0.0",
32
+ "@jsenv/urls": "2.1.0",
33
33
  "@jsenv/url-meta": "8.1.0",
34
34
  "@jsenv/abort": "4.2.4"
35
35
  }
@@ -1,24 +1,24 @@
1
- import { urlToFileSystemPath } from "@jsenv/urls"
1
+ import { urlToFileSystemPath } from "@jsenv/urls";
2
2
 
3
- import { assertAndNormalizeFileUrl } from "./file_url_validation.js"
4
- import { statsToType } from "./internal/statsToType.js"
5
- import { readEntryStat } from "./readEntryStat.js"
3
+ import { assertAndNormalizeFileUrl } from "./file_url_validation.js";
4
+ import { statsToType } from "./internal/statsToType.js";
5
+ import { readEntryStat } from "./readEntryStat.js";
6
6
 
7
7
  export const assertDirectoryPresence = async (source) => {
8
- const sourceUrl = assertAndNormalizeFileUrl(source)
9
- const sourcePath = urlToFileSystemPath(sourceUrl)
8
+ const sourceUrl = assertAndNormalizeFileUrl(source);
9
+ const sourcePath = urlToFileSystemPath(sourceUrl);
10
10
 
11
11
  const sourceStats = await readEntryStat(sourceUrl, {
12
12
  nullIfNotFound: true,
13
- })
13
+ });
14
14
  if (!sourceStats) {
15
- throw new Error(`directory not found at ${sourcePath}`)
15
+ throw new Error(`directory not found at ${sourcePath}`);
16
16
  }
17
17
  if (!sourceStats.isDirectory()) {
18
18
  throw new Error(
19
19
  `directory expected at ${sourcePath} and found ${statsToType(
20
20
  sourceStats,
21
21
  )} instead`,
22
- )
22
+ );
23
23
  }
24
- }
24
+ };
@@ -1,24 +1,24 @@
1
- import { urlToFileSystemPath } from "@jsenv/urls"
1
+ import { urlToFileSystemPath } from "@jsenv/urls";
2
2
 
3
- import { assertAndNormalizeFileUrl } from "./file_url_validation.js"
4
- import { statsToType } from "./internal/statsToType.js"
5
- import { readEntryStat } from "./readEntryStat.js"
3
+ import { assertAndNormalizeFileUrl } from "./file_url_validation.js";
4
+ import { statsToType } from "./internal/statsToType.js";
5
+ import { readEntryStat } from "./readEntryStat.js";
6
6
 
7
7
  export const assertFilePresence = async (source) => {
8
- const sourceUrl = assertAndNormalizeFileUrl(source)
9
- const sourcePath = urlToFileSystemPath(sourceUrl)
8
+ const sourceUrl = assertAndNormalizeFileUrl(source);
9
+ const sourcePath = urlToFileSystemPath(sourceUrl);
10
10
 
11
11
  const sourceStats = await readEntryStat(sourceUrl, {
12
12
  nullIfNotFound: true,
13
- })
13
+ });
14
14
  if (!sourceStats) {
15
- throw new Error(`file not found at ${sourcePath}`)
15
+ throw new Error(`file not found at ${sourcePath}`);
16
16
  }
17
17
  if (!sourceStats.isFile()) {
18
18
  throw new Error(
19
19
  `file expected at ${sourcePath} and found ${statsToType(
20
20
  sourceStats,
21
21
  )} instead`,
22
- )
22
+ );
23
23
  }
24
- }
24
+ };
@@ -5,25 +5,25 @@
5
5
  * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
6
6
  */
7
7
 
8
- import { createHash } from "node:crypto"
8
+ import { createHash } from "node:crypto";
9
9
 
10
- const ETAG_FOR_EMPTY_CONTENT = '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"'
10
+ const ETAG_FOR_EMPTY_CONTENT = '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"';
11
11
 
12
12
  export const bufferToEtag = (buffer) => {
13
13
  if (!Buffer.isBuffer(buffer)) {
14
- throw new TypeError(`buffer expected, got ${buffer}`)
14
+ throw new TypeError(`buffer expected, got ${buffer}`);
15
15
  }
16
16
 
17
17
  if (buffer.length === 0) {
18
- return ETAG_FOR_EMPTY_CONTENT
18
+ return ETAG_FOR_EMPTY_CONTENT;
19
19
  }
20
20
 
21
- const hash = createHash("sha1")
22
- hash.update(buffer, "utf8")
21
+ const hash = createHash("sha1");
22
+ hash.update(buffer, "utf8");
23
23
 
24
- const hashBase64String = hash.digest("base64")
25
- const hashBase64StringSubset = hashBase64String.slice(0, 27)
26
- const length = buffer.length
24
+ const hashBase64String = hash.digest("base64");
25
+ const hashBase64StringSubset = hashBase64String.slice(0, 27);
26
+ const length = buffer.length;
27
27
 
28
- return `"${length.toString(16)}-${hashBase64StringSubset}"`
29
- }
28
+ return `"${length.toString(16)}-${hashBase64StringSubset}"`;
29
+ };
@@ -1,11 +1,11 @@
1
- import { Abort } from "@jsenv/abort"
1
+ import { Abort } from "@jsenv/abort";
2
2
 
3
- import { URL_META } from "@jsenv/url-meta"
4
- import { urlToRelativeUrl } from "@jsenv/urls"
5
- import { assertAndNormalizeDirectoryUrl } from "./directory_url_validation.js"
6
- import { readDirectory } from "./readDirectory.js"
7
- import { readEntryStat } from "./readEntryStat.js"
8
- import { comparePathnames } from "./comparePathnames.js"
3
+ import { URL_META } from "@jsenv/url-meta";
4
+ import { urlToRelativeUrl } from "@jsenv/urls";
5
+ import { assertAndNormalizeDirectoryUrl } from "./directory_url_validation.js";
6
+ import { readDirectory } from "./readDirectory.js";
7
+ import { readEntryStat } from "./readEntryStat.js";
8
+ import { comparePathnames } from "./comparePathnames.js";
9
9
 
10
10
  export const collectDirectoryMatchReport = async ({
11
11
  signal = new AbortController().signal,
@@ -13,31 +13,31 @@ export const collectDirectoryMatchReport = async ({
13
13
  associations,
14
14
  predicate,
15
15
  }) => {
16
- const matchingArray = []
17
- const ignoredArray = []
16
+ const matchingArray = [];
17
+ const ignoredArray = [];
18
18
 
19
- const rootDirectoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl)
19
+ const rootDirectoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl);
20
20
  if (typeof predicate !== "function") {
21
- throw new TypeError(`predicate must be a function, got ${predicate}`)
21
+ throw new TypeError(`predicate must be a function, got ${predicate}`);
22
22
  }
23
- associations = URL_META.resolveAssociations(associations, rootDirectoryUrl)
23
+ associations = URL_META.resolveAssociations(associations, rootDirectoryUrl);
24
24
 
25
- const collectOperation = Abort.startOperation()
26
- collectOperation.addAbortSignal(signal)
25
+ const collectOperation = Abort.startOperation();
26
+ collectOperation.addAbortSignal(signal);
27
27
 
28
28
  const visitDirectory = async (directoryUrl) => {
29
- collectOperation.throwIfAborted()
30
- const directoryItems = await readDirectory(directoryUrl)
29
+ collectOperation.throwIfAborted();
30
+ const directoryItems = await readDirectory(directoryUrl);
31
31
 
32
32
  await Promise.all(
33
33
  directoryItems.map(async (directoryItem) => {
34
- const directoryChildNodeUrl = `${directoryUrl}${directoryItem}`
34
+ const directoryChildNodeUrl = `${directoryUrl}${directoryItem}`;
35
35
  const relativeUrl = urlToRelativeUrl(
36
36
  directoryChildNodeUrl,
37
37
  rootDirectoryUrl,
38
- )
38
+ );
39
39
 
40
- collectOperation.throwIfAborted()
40
+ collectOperation.throwIfAborted();
41
41
  const directoryChildNodeStats = await readEntryStat(
42
42
  directoryChildNodeUrl,
43
43
  {
@@ -49,10 +49,10 @@ export const collectDirectoryMatchReport = async ({
49
49
  // because directoryPath is recursively traversed
50
50
  followLink: false,
51
51
  },
52
- )
52
+ );
53
53
 
54
54
  if (directoryChildNodeStats.isDirectory()) {
55
- const subDirectoryUrl = `${directoryChildNodeUrl}/`
55
+ const subDirectoryUrl = `${directoryChildNodeUrl}/`;
56
56
 
57
57
  if (
58
58
  !URL_META.urlChildMayMatch({
@@ -66,53 +66,53 @@ export const collectDirectoryMatchReport = async ({
66
66
  ? relativeUrl
67
67
  : `${relativeUrl}/`,
68
68
  fileStats: directoryChildNodeStats,
69
- })
69
+ });
70
70
 
71
- return
71
+ return;
72
72
  }
73
73
 
74
- await visitDirectory(subDirectoryUrl)
75
- return
74
+ await visitDirectory(subDirectoryUrl);
75
+ return;
76
76
  }
77
77
 
78
78
  if (directoryChildNodeStats.isFile()) {
79
79
  const meta = URL_META.applyAssociations({
80
80
  url: directoryChildNodeUrl,
81
81
  associations,
82
- })
82
+ });
83
83
  if (!predicate(meta)) {
84
84
  ignoredArray.push({
85
85
  relativeUrl,
86
86
  meta,
87
87
  fileStats: directoryChildNodeStats,
88
- })
89
- return
88
+ });
89
+ return;
90
90
  }
91
91
 
92
92
  matchingArray.push({
93
93
  relativeUrl,
94
94
  meta,
95
95
  fileStats: directoryChildNodeStats,
96
- })
97
- return
96
+ });
97
+ return;
98
98
  }
99
99
  }),
100
- )
101
- }
100
+ );
101
+ };
102
102
 
103
103
  try {
104
- await visitDirectory(rootDirectoryUrl)
104
+ await visitDirectory(rootDirectoryUrl);
105
105
 
106
106
  return {
107
107
  matchingArray: sortByRelativeUrl(matchingArray),
108
108
  ignoredArray: sortByRelativeUrl(ignoredArray),
109
- }
109
+ };
110
110
  } finally {
111
- await collectOperation.end()
111
+ await collectOperation.end();
112
112
  }
113
- }
113
+ };
114
114
 
115
115
  const sortByRelativeUrl = (array) =>
116
116
  array.sort((left, right) => {
117
- return comparePathnames(left.relativeUrl, right.relativeUrl)
118
- })
117
+ return comparePathnames(left.relativeUrl, right.relativeUrl);
118
+ });
@@ -1,11 +1,11 @@
1
- import { Abort } from "@jsenv/abort"
2
- import { URL_META } from "@jsenv/url-meta"
3
- import { urlToRelativeUrl } from "@jsenv/urls"
1
+ import { Abort } from "@jsenv/abort";
2
+ import { URL_META } from "@jsenv/url-meta";
3
+ import { urlToRelativeUrl } from "@jsenv/urls";
4
4
 
5
- import { assertAndNormalizeDirectoryUrl } from "./directory_url_validation.js"
6
- import { readDirectory } from "./readDirectory.js"
7
- import { readEntryStat } from "./readEntryStat.js"
8
- import { comparePathnames } from "./comparePathnames.js"
5
+ import { assertAndNormalizeDirectoryUrl } from "./directory_url_validation.js";
6
+ import { readDirectory } from "./readDirectory.js";
7
+ import { readEntryStat } from "./readEntryStat.js";
8
+ import { comparePathnames } from "./comparePathnames.js";
9
9
 
10
10
  export const collectFiles = async ({
11
11
  signal = new AbortController().signal,
@@ -13,24 +13,24 @@ export const collectFiles = async ({
13
13
  associations,
14
14
  predicate,
15
15
  }) => {
16
- const rootDirectoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl)
16
+ const rootDirectoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl);
17
17
  if (typeof predicate !== "function") {
18
- throw new TypeError(`predicate must be a function, got ${predicate}`)
18
+ throw new TypeError(`predicate must be a function, got ${predicate}`);
19
19
  }
20
- associations = URL_META.resolveAssociations(associations, rootDirectoryUrl)
20
+ associations = URL_META.resolveAssociations(associations, rootDirectoryUrl);
21
21
 
22
- const collectOperation = Abort.startOperation()
23
- collectOperation.addAbortSignal(signal)
22
+ const collectOperation = Abort.startOperation();
23
+ collectOperation.addAbortSignal(signal);
24
24
 
25
- const matchingFileResultArray = []
25
+ const matchingFileResultArray = [];
26
26
  const visitDirectory = async (directoryUrl) => {
27
- collectOperation.throwIfAborted()
28
- const directoryItems = await readDirectory(directoryUrl)
27
+ collectOperation.throwIfAborted();
28
+ const directoryItems = await readDirectory(directoryUrl);
29
29
 
30
30
  await Promise.all(
31
31
  directoryItems.map(async (directoryItem) => {
32
- const directoryChildNodeUrl = `${directoryUrl}${directoryItem}`
33
- collectOperation.throwIfAborted()
32
+ const directoryChildNodeUrl = `${directoryUrl}${directoryItem}`;
33
+ collectOperation.throwIfAborted();
34
34
  const directoryChildNodeStats = await readEntryStat(
35
35
  directoryChildNodeUrl,
36
36
  {
@@ -42,10 +42,10 @@ export const collectFiles = async ({
42
42
  // because directoryPath is recursively traversed
43
43
  followLink: false,
44
44
  },
45
- )
45
+ );
46
46
 
47
47
  if (directoryChildNodeStats.isDirectory()) {
48
- const subDirectoryUrl = `${directoryChildNodeUrl}/`
48
+ const subDirectoryUrl = `${directoryChildNodeUrl}/`;
49
49
  if (
50
50
  !URL_META.urlChildMayMatch({
51
51
  url: subDirectoryUrl,
@@ -53,47 +53,47 @@ export const collectFiles = async ({
53
53
  predicate,
54
54
  })
55
55
  ) {
56
- return
56
+ return;
57
57
  }
58
- await visitDirectory(subDirectoryUrl)
59
- return
58
+ await visitDirectory(subDirectoryUrl);
59
+ return;
60
60
  }
61
61
 
62
62
  if (directoryChildNodeStats.isFile()) {
63
63
  const meta = URL_META.applyAssociations({
64
64
  url: directoryChildNodeUrl,
65
65
  associations,
66
- })
67
- if (!predicate(meta)) return
66
+ });
67
+ if (!predicate(meta)) return;
68
68
 
69
69
  const relativeUrl = urlToRelativeUrl(
70
70
  directoryChildNodeUrl,
71
71
  rootDirectoryUrl,
72
- )
72
+ );
73
73
  matchingFileResultArray.push({
74
74
  url: new URL(relativeUrl, rootDirectoryUrl).href,
75
75
  relativeUrl: decodeURIComponent(relativeUrl),
76
76
  meta,
77
77
  fileStats: directoryChildNodeStats,
78
- })
79
- return
78
+ });
79
+ return;
80
80
  }
81
81
  }),
82
- )
83
- }
82
+ );
83
+ };
84
84
 
85
85
  try {
86
- await visitDirectory(rootDirectoryUrl)
86
+ await visitDirectory(rootDirectoryUrl);
87
87
 
88
88
  // When we operate on thoose files later it feels more natural
89
89
  // to perform operation in the same order they appear in the filesystem.
90
90
  // It also allow to get a predictable return value.
91
91
  // For that reason we sort matchingFileResultArray
92
92
  matchingFileResultArray.sort((leftFile, rightFile) => {
93
- return comparePathnames(leftFile.relativeUrl, rightFile.relativeUrl)
94
- })
95
- return matchingFileResultArray
93
+ return comparePathnames(leftFile.relativeUrl, rightFile.relativeUrl);
94
+ });
95
+ return matchingFileResultArray;
96
96
  } finally {
97
- await collectOperation.end()
97
+ await collectOperation.end();
98
98
  }
99
- }
99
+ };
@@ -1,49 +1,49 @@
1
1
  export const comparePathnames = (leftPathame, rightPathname) => {
2
- const leftPartArray = leftPathame.split("/")
3
- const rightPartArray = rightPathname.split("/")
2
+ const leftPartArray = leftPathame.split("/");
3
+ const rightPartArray = rightPathname.split("/");
4
4
 
5
- const leftLength = leftPartArray.length
6
- const rightLength = rightPartArray.length
5
+ const leftLength = leftPartArray.length;
6
+ const rightLength = rightPartArray.length;
7
7
 
8
- const maxLength = Math.max(leftLength, rightLength)
9
- let i = 0
8
+ const maxLength = Math.max(leftLength, rightLength);
9
+ let i = 0;
10
10
  while (i < maxLength) {
11
- const leftPartExists = i in leftPartArray
12
- const rightPartExists = i in rightPartArray
11
+ const leftPartExists = i in leftPartArray;
12
+ const rightPartExists = i in rightPartArray;
13
13
 
14
14
  // longer comes first
15
15
  if (!leftPartExists) {
16
- return +1
16
+ return +1;
17
17
  }
18
18
  if (!rightPartExists) {
19
- return -1
19
+ return -1;
20
20
  }
21
21
 
22
- const leftPartIsLast = i === leftPartArray.length - 1
23
- const rightPartIsLast = i === rightPartArray.length - 1
22
+ const leftPartIsLast = i === leftPartArray.length - 1;
23
+ const rightPartIsLast = i === rightPartArray.length - 1;
24
24
  // folder comes first
25
25
  if (leftPartIsLast && !rightPartIsLast) {
26
- return +1
26
+ return +1;
27
27
  }
28
28
  if (!leftPartIsLast && rightPartIsLast) {
29
- return -1
29
+ return -1;
30
30
  }
31
31
 
32
- const leftPart = leftPartArray[i]
33
- const rightPart = rightPartArray[i]
34
- i++
32
+ const leftPart = leftPartArray[i];
33
+ const rightPart = rightPartArray[i];
34
+ i++;
35
35
  // local comparison comes first
36
- const comparison = leftPart.localeCompare(rightPart)
36
+ const comparison = leftPart.localeCompare(rightPart);
37
37
  if (comparison !== 0) {
38
- return comparison
38
+ return comparison;
39
39
  }
40
40
  }
41
41
 
42
42
  if (leftLength < rightLength) {
43
- return +1
43
+ return +1;
44
44
  }
45
45
  if (leftLength > rightLength) {
46
- return -1
46
+ return -1;
47
47
  }
48
- return 0
49
- }
48
+ return 0;
49
+ };