@vbarbarosh/node-helpers 3.74.1 → 3.76.0
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 +29 -3
- package/dist/browser.js +1 -2504
- package/package.json +31 -11
- package/src/HeartbeatServer.js +24 -3
- package/src/HeartbeatServer.md +33 -0
- package/src/array_chunk.js +1 -1
- package/src/array_chunk.md +8 -0
- package/src/array_chunk_balanced.md +14 -0
- package/src/array_fps.md +12 -0
- package/src/array_gcd.js +4 -2
- package/src/array_gcd.md +2 -1
- package/src/array_group.js +3 -3
- package/src/array_group.md +14 -0
- package/src/array_group_map.js +3 -3
- package/src/array_group_map.md +13 -0
- package/src/array_index.js +2 -2
- package/src/array_index.md +9 -0
- package/src/array_lcm.js +4 -2
- package/src/array_lcm.md +2 -1
- package/src/array_max.js +11 -4
- package/src/array_max.md +1 -1
- package/src/array_min.js +11 -4
- package/src/array_min.md +1 -1
- package/src/array_permutations.js +4 -0
- package/src/array_permutations.md +13 -0
- package/src/array_sort.js +7 -2
- package/src/array_sort.md +13 -0
- package/src/array_sort_other.js +8 -5
- package/src/array_sort_other.md +11 -0
- package/src/array_sum.js +2 -2
- package/src/array_sum.md +8 -0
- package/src/array_unique.js +2 -2
- package/src/array_unique_last.js +2 -2
- package/src/assert_valid_expires_at.md +10 -0
- package/src/clamp.md +9 -0
- package/src/cli-apps/watchdog.js +5 -0
- package/src/cli.js +3 -1
- package/src/cli.md +15 -0
- package/src/const_stream.md +7 -0
- package/src/const_type.md +5 -0
- package/src/countdown.js +22 -5
- package/src/countdown.md +21 -0
- package/src/crypto_decrypt_aes256.md +13 -0
- package/src/crypto_encrypt_aes256.md +13 -0
- package/src/crypto_hash_md5.md +10 -0
- package/src/crypto_hash_sha256.md +10 -0
- package/src/crypto_hmac_sha256.md +11 -0
- package/src/date_add_hours.md +8 -0
- package/src/date_add_milliseconds.md +4 -0
- package/src/date_add_minutes.md +4 -0
- package/src/date_add_months.md +13 -0
- package/src/date_add_seconds.md +4 -0
- package/src/date_diff_seconds.md +4 -0
- package/src/date_is_leap_year.md +9 -0
- package/src/escape_content_disposition.js +6 -3
- package/src/escape_content_disposition.md +13 -0
- package/src/escape_regexp.md +7 -0
- package/src/eta.js +7 -1
- package/src/eta.md +18 -0
- package/src/factorize_ms.js +3 -0
- package/src/factorize_ms.md +10 -0
- package/src/fastdl.js +14 -3
- package/src/fcmp_dates.md +12 -0
- package/src/fcmp_default.js +7 -0
- package/src/fcmp_default.md +29 -0
- package/src/fcmp_default_desc.js +4 -7
- package/src/fcmp_default_desc.md +10 -0
- package/src/fcmp_from_spec.md +13 -0
- package/src/fcmp_numbers.md +11 -0
- package/src/fcmp_tuples.md +17 -0
- package/src/fcmp_utf8_bin.md +14 -0
- package/src/fcmp_utf8_ci.md +14 -0
- package/src/fcmp_utf8_cs.md +15 -0
- package/src/fcmp_utf8_natural_bin.js +38 -0
- package/src/fcmp_utf8_natural_bin.md +8 -0
- package/src/fcmp_utf8_natural_ci.md +13 -0
- package/src/fcmp_utf8_natural_cs.md +13 -0
- package/src/fcmpx.md +26 -9
- package/src/filter1_from_spec.js +3 -3
- package/src/format_bytes.md +15 -0
- package/src/format_date.md +7 -0
- package/src/format_date_fs.md +7 -0
- package/src/format_date_human.md +6 -0
- package/src/format_date_ymd.md +6 -0
- package/src/format_error_report.js +3 -3
- package/src/format_error_report.md +12 -0
- package/src/format_kilo.md +13 -0
- package/src/format_ms.js +3 -2
- package/src/format_ms.md +12 -0
- package/src/format_ms2.js +6 -3
- package/src/format_ms2.md +12 -0
- package/src/format_ms3.js +3 -2
- package/src/format_ms3.md +12 -0
- package/src/format_percents.md +10 -0
- package/src/format_progress_bytes.md +13 -0
- package/src/format_progress_kilo.md +10 -0
- package/src/format_seconds.md +11 -0
- package/src/format_thousands.md +9 -0
- package/src/fs_append.md +7 -0
- package/src/fs_append_json.md +8 -0
- package/src/fs_append_utf8.md +6 -0
- package/src/fs_assert_file_exists.md +3 -0
- package/src/fs_assert_file_readable.js +1 -1
- package/src/fs_assert_file_readable.md +3 -0
- package/src/fs_assert_file_socket.md +2 -0
- package/src/fs_copy.md +7 -0
- package/src/fs_copy_excl.md +2 -0
- package/src/fs_exists.md +6 -0
- package/src/fs_fclose.md +5 -0
- package/src/fs_fi.js +13 -1
- package/src/fs_fi.md +11 -0
- package/src/fs_file_md5.md +8 -0
- package/src/fs_find.md +7 -0
- package/src/fs_fopen.md +6 -0
- package/src/fs_fread.js +2 -2
- package/src/fs_fread.md +11 -0
- package/src/fs_fsize.md +2 -0
- package/src/fs_fstat.md +2 -0
- package/src/fs_fwrite.js +2 -2
- package/src/fs_fwrite.md +9 -0
- package/src/fs_list.md +5 -0
- package/src/fs_list_deep.md +5 -0
- package/src/fs_ls.md +2 -0
- package/src/fs_lsr.md +4 -0
- package/src/fs_lstat.md +3 -0
- package/src/fs_mkdir.md +3 -0
- package/src/fs_mkdirp.js +3 -30
- package/src/fs_mkdirp.md +7 -0
- package/src/fs_path_basename.md +2 -0
- package/src/fs_path_dirname.md +2 -0
- package/src/fs_path_extname.md +9 -0
- package/src/fs_path_join.md +2 -0
- package/src/fs_path_relative.md +2 -0
- package/src/fs_path_resolve.md +2 -0
- package/src/fs_path_tempdir.md +2 -0
- package/src/fs_path_untildify.md +8 -0
- package/src/fs_read.md +3 -0
- package/src/fs_read_buffer.md +5 -0
- package/src/fs_read_json.md +6 -0
- package/src/fs_read_lines.md +7 -0
- package/src/fs_read_stream.md +2 -0
- package/src/fs_read_utf8.md +5 -0
- package/src/fs_readdir.md +3 -0
- package/src/fs_readlink.md +6 -0
- package/src/fs_rename.md +6 -0
- package/src/fs_rm.md +4 -0
- package/src/fs_rmdir.md +3 -0
- package/src/fs_rmf.md +2 -0
- package/src/fs_rmrf.md +8 -0
- package/src/fs_sha256.js +16 -0
- package/src/fs_sha256.md +9 -0
- package/src/fs_size.js +2 -2
- package/src/fs_size.md +6 -0
- package/src/fs_stat.md +2 -0
- package/src/fs_tempdir.js +20 -5
- package/src/fs_touch.md +6 -0
- package/src/fs_walk.js +2 -2
- package/src/fs_walk.md +14 -0
- package/src/fs_write.md +3 -0
- package/src/fs_write_json.md +7 -0
- package/src/fs_write_stream.md +2 -0
- package/src/gettype.md +13 -0
- package/src/http_delete.md +11 -0
- package/src/http_get_blob.md +8 -0
- package/src/http_get_buffer.md +10 -0
- package/src/http_get_file.js +8 -8
- package/src/http_get_file.md +14 -0
- package/src/http_get_json.md +10 -0
- package/src/http_get_stream.md +14 -0
- package/src/http_get_stream_range.js +27 -9
- package/src/http_get_stream_range.md +22 -0
- package/src/http_get_utf8.md +9 -0
- package/src/http_head.md +9 -0
- package/src/http_patch_json.md +10 -0
- package/src/http_post_json.md +11 -0
- package/src/http_post_multipart.md +15 -0
- package/src/http_post_urlencoded.md +11 -0
- package/src/http_put_buffer.md +9 -0
- package/src/http_put_file.js +9 -6
- package/src/http_put_file.md +16 -0
- package/src/http_put_json.md +11 -0
- package/src/http_put_utf8.md +9 -0
- package/src/http_range_parse.js +6 -3
- package/src/http_range_parse.md +18 -0
- package/src/http_stream_range.js +35 -22
- package/src/http_stream_range.md +29 -0
- package/src/identity.md +2 -0
- package/src/ignore.md +2 -0
- package/src/json_stringify_safe.md +10 -0
- package/src/json_stringify_stable.md +9 -0
- package/src/logger.js +2 -3
- package/src/logger.md +15 -0
- package/src/make_progress.js +8 -5
- package/src/make_progress.md +20 -0
- package/src/math_gcd.js +2 -1
- package/src/mongo_stream_upsert.js +10 -3
- package/src/mongo_stream_upsert.md +17 -0
- package/src/mongo_stream_write.js +10 -3
- package/src/mongo_stream_write.md +16 -0
- package/src/msval.md +10 -0
- package/src/now_fs.md +7 -0
- package/src/now_human.md +6 -0
- package/src/object_defaults.md +11 -0
- package/src/object_schema.js +2 -1
- package/src/object_schema.md +12 -0
- package/src/object_walk_preorder.md +16 -0
- package/src/parallel.js +23 -10
- package/src/parse_bytes.js +4 -2
- package/src/parse_bytes.md +15 -0
- package/src/parse_hms.js +1 -1
- package/src/parse_http_content_range.js +9 -5
- package/src/parse_http_content_range.md +16 -0
- package/src/perf_end_human.md +10 -0
- package/src/perf_end_ms.md +8 -0
- package/src/perf_measure.md +10 -0
- package/src/perf_measure_human.md +8 -0
- package/src/perf_start.md +9 -0
- package/src/pgid_exists.md +6 -0
- package/src/pgid_kill_grace.js +1 -1
- package/src/pgid_kill_grace.md +15 -0
- package/src/pid_exists.md +5 -0
- package/src/pid_kill_grace.js +1 -1
- package/src/pid_kill_grace.md +14 -0
- package/src/plural.md +13 -0
- package/src/random_hex.md +9 -0
- package/src/random_int.md +8 -0
- package/src/range.js +4 -2
- package/src/range.md +2 -0
- package/src/redis_connect.js +1 -1
- package/src/redis_connect.md +10 -0
- package/src/redis_lshift.md +14 -0
- package/src/redis_poll.js +1 -0
- package/src/redis_poll.md +17 -0
- package/src/redis_poll_zshift_callback_rpush.js +1 -2
- package/src/redis_poll_zshift_callback_rpush.md +17 -0
- package/src/redis_poll_zshift_spawn_rpush.js +2 -1
- package/src/redis_poll_zshift_spawn_rpush.md +20 -0
- package/src/redis_zshift.md +14 -0
- package/src/round.js +7 -8
- package/src/round.md +15 -0
- package/src/sanitize_dash_name.md +13 -0
- package/src/sanitize_filename.md +9 -0
- package/src/sanitize_var_name.md +14 -0
- package/src/sftp_get_file_info.js +2 -2
- package/src/sftp_get_file_info.md +14 -0
- package/src/sftp_get_stream_range.js +32 -22
- package/src/sftp_get_stream_range.md +20 -0
- package/src/shell_curl_progress.js +2 -1
- package/src/shell_curl_progress.md +17 -0
- package/src/shell_lines.js +2 -2
- package/src/shell_lines.md +1 -1
- package/src/shell_spawn.js +7 -0
- package/src/shell_ytdlp_progress.js +2 -1
- package/src/shell_ytdlp_progress.md +17 -0
- package/src/str_camel_to_snake.md +11 -0
- package/src/str_parse_kv.md +11 -0
- package/src/stream_curl_progress.md +14 -0
- package/src/stream_data_ln.js +7 -1
- package/src/stream_discard.md +8 -0
- package/src/stream_group.md +3 -0
- package/src/stream_gunzip.md +7 -0
- package/src/stream_hash.md +10 -0
- package/src/stream_map.js +8 -1
- package/src/stream_map_parallel.js +9 -1
- package/src/stream_md5.md +9 -0
- package/src/stream_multiplex.js +11 -0
- package/src/stream_multiplex.md +16 -0
- package/src/stream_through.md +3 -0
- package/src/stream_transform.md +2 -0
- package/src/stream_xml_analyze.js +9 -1
- package/src/stream_xml_parse.js +9 -1
- package/src/stream_ytdlp_progress.js +1 -1
- package/src/stream_ytdlp_progress.md +18 -0
- package/src/strtr.js +15 -5
- package/src/strtr.md +11 -0
- package/src/urlclean.js +9 -2
- package/src/urlmod.js +5 -0
- package/src/urlparts.md +17 -0
- package/src/wait_while.js +1 -1
- package/src/wait_while.md +1 -1
- package/src/HeartbeatServer.test.js +0 -31
- package/src/array_chunk.test.js +0 -24
- package/src/array_chunk_balanced.test.js +0 -37
- package/src/array_fps.test.js +0 -72
- package/src/array_gcd.test.js +0 -10
- package/src/array_index.test.js +0 -14
- package/src/array_lcm.test.js +0 -12
- package/src/array_max.test.js +0 -20
- package/src/array_min.test.js +0 -20
- package/src/array_permutations.test.js +0 -20
- package/src/array_sort.test.js +0 -85
- package/src/array_sort_other.test.js +0 -9
- package/src/array_sum.test.js +0 -11
- package/src/cli-apps/watchdog.d/connect_close.js +0 -17
- package/src/cli-apps/watchdog.d/connect_close2.js +0 -20
- package/src/cli-apps/watchdog.d/connect_close3.js +0 -25
- package/src/cli-apps/watchdog.d/connect_no_ping.js +0 -13
- package/src/cli-apps/watchdog.d/early_exit.js +0 -7
- package/src/cli-apps/watchdog.d/flood.js +0 -13
- package/src/cli-apps/watchdog.d/flood2.js +0 -15
- package/src/cli-apps/watchdog.d/hang.js +0 -8
- package/src/cli-apps/watchdog.d/huge_delay.js +0 -18
- package/src/cli-apps/watchdog.d/ignore_sigterm.js +0 -29
- package/src/cli-apps/watchdog.d/late_heartbeat.js +0 -21
- package/src/cli-apps/watchdog.d/my-exit-after-2-pings.js +0 -16
- package/src/cli-apps/watchdog.d/my-happy-path.js +0 -16
- package/src/cli-apps/watchdog.d/my-ignore-sigterm.js +0 -22
- package/src/cli-apps/watchdog.d/my-never-ping.js +0 -15
- package/src/cli-apps/watchdog.d/no_heartbeat.js +0 -5
- package/src/cli-apps/watchdog.d/ok.js +0 -17
- package/src/cli-apps/watchdog.d/quick-exit-after-2-pings.js +0 -15
- package/src/cli-apps/watchdog.d/quick-hang-after-1-ping.js +0 -15
- package/src/cli-apps/watchdog.d/spawn_children.js +0 -14
- package/src/cli-apps/watchdog.test.js +0 -48
- package/src/crypto_encrypt_aes256.test.js +0 -10
- package/src/crypto_hash_sha256.test.js +0 -10
- package/src/date_add_months.test.js +0 -40
- package/src/date_is_leap_year.test.js +0 -14
- package/src/escape_content_disposition.test.js +0 -22
- package/src/fcmp_from_spec.test.js +0 -91
- package/src/fcmpx.test.js +0 -173
- package/src/filter1_from_spec.test.js +0 -31
- package/src/format_bytes.test.js +0 -22
- package/src/format_error_report.d/src/1.js +0 -26
- package/src/format_error_report.d/src/2.js +0 -29
- package/src/format_kilo.test.js +0 -25
- package/src/format_ms.test.js +0 -33
- package/src/format_ms2.test.js +0 -33
- package/src/format_ms3.test.js +0 -33
- package/src/format_percents.test.js +0 -22
- package/src/format_progress_bytes.test.js +0 -19
- package/src/format_progress_kilo.test.js +0 -19
- package/src/format_seconds.test.js +0 -42
- package/src/format_thousands.test.js +0 -28
- package/src/fs_file_md5.test.js +0 -11
- package/src/fs_mkdirp.test.js +0 -24
- package/src/fs_path_extname.test.js +0 -22
- package/src/gettype.test.js +0 -27
- package/src/object_schema.test.js +0 -15
- package/src/object_walk_preorder.test.js +0 -17
- package/src/parallel.test.js +0 -11
- package/src/parse_bytes.test.js +0 -21
- package/src/parse_hms.test.js +0 -32
- package/src/parse_http_content_range.test.js +0 -14
- package/src/pid_kill_grace.d/ignore-sigterm-for-10ms.js +0 -33
- package/src/pid_kill_grace.d/ignore-sigterm.js +0 -22
- package/src/pid_kill_grace.test.js +0 -63
- package/src/ping_socket.test.js +0 -58
- package/src/plural.test.js +0 -20
- package/src/range.test.js +0 -41
- package/src/redis_lshift.test.js +0 -57
- package/src/redis_zshift.test.js +0 -58
- package/src/round.test.js +0 -56
- package/src/sanitize_dash_name.test.js +0 -59
- package/src/sanitize_var_name.test.js +0 -39
- package/src/shell_spawn.test.js +0 -30
- package/src/str_camel_to_snake.test.js +0 -17
- package/src/stream_curl_progress.d/basic +0 -3
- package/src/stream_curl_progress.d/basic.json +0 -42
- package/src/stream_curl_progress.test.js +0 -17
- package/src/stream_data_ln.test.js +0 -24
- package/src/stream_map_parallel.test.js +0 -26
- package/src/stream_multiplex.test.js +0 -67
- package/src/stream_strpbrk.test.js +0 -29
- package/src/urlclean.test.js +0 -18
- package/src/urlmod.test.js +0 -40
- package/src/urlparts.test.js +0 -294
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Locale-aware natural string comparison, case-sensitive: `localeCompare` with
|
|
2
|
+
`{numeric: true, sensitivity: 'variant'}`. Digit chunks compare as numbers
|
|
3
|
+
(`'file2' < 'file10'`), base letters dominate (`'apple2' < 'Banana1'`), and
|
|
4
|
+
case/accents distinguish otherwise equal strings.
|
|
5
|
+
|
|
6
|
+
```js
|
|
7
|
+
['a10', 'a2', 'A20', 'A3'].sort(fcmp_utf8_natural_cs) // 'a2' 'A3' 'a10' 'A20'
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Results depend on the runtime locale/ICU — the exact order of case variants
|
|
11
|
+
varies between machines. For deterministic natural order (uppercase before
|
|
12
|
+
lowercase, identical everywhere) use `fcmp_utf8_natural_bin`, the string order
|
|
13
|
+
behind `fcmp_default`/`fcmpx`. For ignoring case use `fcmp_utf8_natural_ci`.
|
package/src/fcmpx.md
CHANGED
|
@@ -1,17 +1,34 @@
|
|
|
1
|
-
Comparator builder using compact expressions
|
|
1
|
+
Comparator builder using compact expressions: creates an `fcmp` function
|
|
2
|
+
suitable for `[].sort()`. Values compare with `fcmp_default` (natural order —
|
|
3
|
+
see `fcmp_default.md`) unless a custom `fcmp` is given.
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
**Expression forms** (composable — an array mixes any of them as sort keys,
|
|
6
|
+
first key wins, later keys break ties):
|
|
4
7
|
|
|
5
8
|
```js
|
|
6
|
-
fcmpx('user.email')
|
|
7
|
-
fcmpx('-user.age
|
|
8
|
-
fcmpx(
|
|
9
|
-
fcmpx(
|
|
10
|
-
fcmpx(
|
|
9
|
+
fcmpx('user.email') // dotted property path
|
|
10
|
+
fcmpx('-user.age') // '-' prefix → descending
|
|
11
|
+
fcmpx('-user.age,user.email') // comma → multiple keys
|
|
12
|
+
fcmpx(v => v.user.email) // read function
|
|
13
|
+
fcmpx('') // '' or '.' → the item itself
|
|
14
|
+
fcmpx(['-age', 'name']) // array of keys
|
|
15
|
+
fcmpx({read: 'v', fcmp: (a, b) => b - a}) // object form: custom comparator
|
|
16
|
+
fcmpx({read: 'type', top: ['dir']}) // listed values first, in listed order
|
|
17
|
+
fcmpx({read: 'type', bottom: ['tmp']}) // listed values last
|
|
18
|
+
fcmpx({read: 'age', desc: true}) // descending via object form
|
|
11
19
|
```
|
|
12
20
|
|
|
13
|
-
|
|
14
|
-
|
|
21
|
+
```js
|
|
22
|
+
users.sort(fcmpx('-age,name'));
|
|
23
|
+
// age 35 first, ties by name; {name: 'bob'} (no age) goes last
|
|
24
|
+
|
|
25
|
+
files.sort(fcmpx([{read: 'type', top: ['dir', 'file']}, 'name']));
|
|
26
|
+
// dirs, then files, then everything else — each group sorted by name
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Missing values:** `null`/`undefined` (and dead-end paths) are considered
|
|
30
|
+
greater than any defined value, so they always land after all defined values —
|
|
31
|
+
even in descending order.
|
|
15
32
|
|
|
16
33
|
- YouTube: [Сортировка объектов в JavaScript](https://www.youtube.com/watch?v=rHEH_JfQjL4)
|
|
17
34
|
- https://github.com/vbarbarosh/speaking/tree/master/20250822-js-sort-fcmpx
|
package/src/filter1_from_spec.js
CHANGED
|
@@ -39,8 +39,8 @@ function parse_spec(spec)
|
|
|
39
39
|
function parse_expr(expr)
|
|
40
40
|
{
|
|
41
41
|
let substr;
|
|
42
|
-
let starts
|
|
43
|
-
let ends
|
|
42
|
+
let starts; // ^
|
|
43
|
+
let ends; // $
|
|
44
44
|
substr = expr.replaceAll('^', '');
|
|
45
45
|
starts = (substr.length !== expr.length);
|
|
46
46
|
expr = substr;
|
|
@@ -50,7 +50,7 @@ function parse_expr(expr)
|
|
|
50
50
|
substr = expr.replaceAll('!', '');
|
|
51
51
|
if ((expr.length - substr.length) % 2) { // not
|
|
52
52
|
if (starts && ends) {
|
|
53
|
-
return s => !s.startsWith(substr) &&
|
|
53
|
+
return s => !(s.startsWith(substr) && s.endsWith(substr));
|
|
54
54
|
}
|
|
55
55
|
if (starts) {
|
|
56
56
|
return s => !s.startsWith(substr);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Formats a byte count as a human-readable size using base-1024 math with
|
|
2
|
+
`B`/`KB`/`MB`/`GB`/`TB`/`PB` suffixes.
|
|
3
|
+
|
|
4
|
+
- Non-number or `NaN` input returns `'n/a'`.
|
|
5
|
+
- `0` returns `'0KB'`; any other value below 1024 returns `'1KB'` — sizes are
|
|
6
|
+
never shown in bytes or fractions of a KB.
|
|
7
|
+
- Values up to 1 MB are rounded to a whole number; above 1 MB two decimals are
|
|
8
|
+
kept, with a trailing `.00` collapsed to `.0`.
|
|
9
|
+
|
|
10
|
+
```js
|
|
11
|
+
format_bytes(500) // '1KB'
|
|
12
|
+
format_bytes(2048) // '2KB'
|
|
13
|
+
format_bytes(2*1024*1024) // '2.0MB'
|
|
14
|
+
format_bytes(35.45*1024*1024) // '35.45MB'
|
|
15
|
+
```
|
|
@@ -37,11 +37,11 @@ ${JSON.stringify(error.response.config.headers||{}, null, 4).slice(1, -1).replac
|
|
|
37
37
|
|
|
38
38
|
${error.response.status} ${error.response.statusText}
|
|
39
39
|
|
|
40
|
-
${(error.response.data
|
|
40
|
+
${String(error.response.data ?? '').slice(0, 10240) || 'n/a'}
|
|
41
41
|
|
|
42
42
|
--- STACK ---
|
|
43
43
|
|
|
44
|
-
${error.stack
|
|
44
|
+
${error.stack ?? 'n/a'}
|
|
45
45
|
`.trimStart();
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -58,7 +58,7 @@ ${JSON.stringify(error.config.headers||{}, null, 4).slice(1, -1).replace(/^\s+|,
|
|
|
58
58
|
|
|
59
59
|
--- STACK ---
|
|
60
60
|
|
|
61
|
-
${error.stack
|
|
61
|
+
${error.stack ?? 'n/a'}
|
|
62
62
|
`.trimStart();
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Formats an error into a multi-line text report suitable for logs. Axios
|
|
2
|
+
errors get special treatment; everything else becomes indented JSON.
|
|
3
|
+
|
|
4
|
+
**Rules:**
|
|
5
|
+
- Axios error with a response (`error.response.status/statusText/config`) —
|
|
6
|
+
plain-text report with `--- REQUEST ---` (method, url, headers),
|
|
7
|
+
`--- RESPONSE ---` (status, first 10240 chars of body), and `--- STACK ---` sections.
|
|
8
|
+
- Axios error without a response (`error.config`) — same, minus the RESPONSE section.
|
|
9
|
+
- Any other truthy error — JSON with `code`, `name`, `message`, and `stack`
|
|
10
|
+
split into an array of lines (circular-safe via `json_stringify_safe`).
|
|
11
|
+
- Falsy error — `{"error":null}`-style JSON; `undefined` is reported as the
|
|
12
|
+
string `'---undefined---'`.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Formats a number in metric (base-1000) notation with `K`/`M`/`G`/`T`/`P`
|
|
2
|
+
suffixes.
|
|
3
|
+
|
|
4
|
+
- Non-number or `NaN` input returns `'n/a'`.
|
|
5
|
+
- `0` returns `'0'`; values below 1000 are rounded to a whole number, no
|
|
6
|
+
suffix.
|
|
7
|
+
- Values of 1000 and above always keep two decimals.
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
format_kilo(55.55) // '56'
|
|
11
|
+
format_kilo(1500) // '1.50K'
|
|
12
|
+
format_kilo(35.45e6) // '35.45M'
|
|
13
|
+
```
|
package/src/format_ms.js
CHANGED
|
@@ -10,11 +10,12 @@ function format_ms(ms)
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
// 00:05
|
|
13
|
+
const sign = ms < 0 ? '-' : '';
|
|
13
14
|
const [h, m, s] = factorize_ms(ms);
|
|
14
15
|
if (h) {
|
|
15
|
-
return `0${h}:0${m}:0${s}`.replace(/0+(?=\d\d)/g, '');
|
|
16
|
+
return sign + `0${h}:0${m}:0${s}`.replace(/0+(?=\d\d)/g, '');
|
|
16
17
|
}
|
|
17
|
-
return `0${m}:0${s}`.replace(/0+(?=\d\d)/g, '');
|
|
18
|
+
return sign + `0${m}:0${s}`.replace(/0+(?=\d\d)/g, '');
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
module.exports = format_ms;
|
package/src/format_ms.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Formats a millisecond duration as `MM:SS`, or `HH:MM:SS` when there is a
|
|
2
|
+
nonzero hours part (via `factorize_ms`). Fields are zero-padded to two digits;
|
|
3
|
+
the hours field grows as needed (`'999:00:00'`). Sub-second precision is
|
|
4
|
+
truncated, not rounded. Falsy input formats as `0`; negative input is
|
|
5
|
+
factorized by magnitude and prefixed with `'-'`.
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
format_ms(5445) // '00:05'
|
|
9
|
+
format_ms(1500.7) // '00:01'
|
|
10
|
+
format_ms(3661000) // '01:01:01'
|
|
11
|
+
format_ms(-61000) // '-01:01'
|
|
12
|
+
```
|
package/src/format_ms2.js
CHANGED
|
@@ -10,11 +10,14 @@ function format_ms2(ms)
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
// 00:05.45
|
|
13
|
-
|
|
13
|
+
// Round to centiseconds before factorizing so the carry propagates:
|
|
14
|
+
// rounding the factorized remainder would turn 5999 into "00:05.100"
|
|
15
|
+
const sign = ms < 0 ? '-' : '';
|
|
16
|
+
const [h, m, s, xx] = factorize_ms(Math.round(Math.abs(ms)/10)*10);
|
|
14
17
|
if (h) {
|
|
15
|
-
return `0${h}:0${m}:0${s}.0${
|
|
18
|
+
return sign + `0${h}:0${m}:0${s}.0${xx/10}`.replace(/0+(?=\d\d)/g, '');
|
|
16
19
|
}
|
|
17
|
-
return `0${m}:0${s}.0${
|
|
20
|
+
return sign + `0${m}:0${s}.0${xx/10}`.replace(/0+(?=\d\d)/g, '');
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
module.exports = format_ms2;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Formats a millisecond duration as `MM:SS.cc` (centiseconds), or `HH:MM:SS.cc`
|
|
2
|
+
when there is a nonzero hours part. The value is rounded to the nearest
|
|
3
|
+
centisecond *before* factorizing, so the carry propagates through the larger
|
|
4
|
+
units. Falsy input formats as `0`; negative input is factorized by magnitude
|
|
5
|
+
and prefixed with `'-'`.
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
format_ms2(5445) // '00:05.45'
|
|
9
|
+
format_ms2(5999) // '00:06.00' (rounding carries into seconds)
|
|
10
|
+
format_ms2(3599999) // '01:00:00.00' (…and all the way up)
|
|
11
|
+
format_ms2(-3661500) // '-01:01:01.50'
|
|
12
|
+
```
|
package/src/format_ms3.js
CHANGED
|
@@ -10,11 +10,12 @@ function format_ms3(ms, include_zero_hours = false)
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
// 00:05.445
|
|
13
|
+
const sign = ms < 0 ? '-' : '';
|
|
13
14
|
const [h, m, s, xx] = factorize_ms(ms);
|
|
14
15
|
if (h || include_zero_hours) {
|
|
15
|
-
return `0${h}:0${m}:0${s}.00${xx}`.replace(/0+(?=\d\d+[:.]|\d\d\d)/g, '');
|
|
16
|
+
return sign + `0${h}:0${m}:0${s}.00${xx}`.replace(/0+(?=\d\d+[:.]|\d\d\d)/g, '');
|
|
16
17
|
}
|
|
17
|
-
return `0${m}:0${s}.00${xx}`.replace(/0+(?=\d\d+[:.]|\d\d\d)/g, '')
|
|
18
|
+
return sign + `0${m}:0${s}.00${xx}`.replace(/0+(?=\d\d+[:.]|\d\d\d)/g, '')
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
module.exports = format_ms3;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Formats a millisecond duration as `MM:SS.mmm` (full milliseconds), or
|
|
2
|
+
`HH:MM:SS.mmm` when there is a nonzero hours part. Sub-millisecond fractions
|
|
3
|
+
are truncated, not rounded. Pass `include_zero_hours = true` to force the
|
|
4
|
+
hours field even when it is zero. Falsy input formats as `0`; negative input
|
|
5
|
+
is factorized by magnitude and prefixed with `'-'`.
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
format_ms3(5445) // '00:05.445'
|
|
9
|
+
format_ms3(5445, true) // '00:00:05.445'
|
|
10
|
+
format_ms3(1500.7) // '00:01.500'
|
|
11
|
+
format_ms3(-3661500) // '-01:01:01.500'
|
|
12
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Formats a fraction (`0` to `1`) as a percentage with two decimal places. The
|
|
2
|
+
exact endpoints drop the decimals: `0` gives `'0%'` and `1` gives `'100%'`,
|
|
3
|
+
while everything in between keeps them (`'50.00%'`).
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
format_percents(0) // '0%'
|
|
7
|
+
format_percents(0.0101) // '1.01%'
|
|
8
|
+
format_percents(0.5) // '50.00%'
|
|
9
|
+
format_percents(1) // '100%'
|
|
10
|
+
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Formats a `make_progress` snapshot (`{percents, total, done, rate, eta, duration}`)
|
|
2
|
+
as a one-line byte-progress string, using 1024-based units (`format_bytes`).
|
|
3
|
+
Unknown parts (zero/null rate, eta, total) render as `~`; the layout degrades
|
|
4
|
+
as less is known: full form → `done of ~` (no total) → `~ duration=…`
|
|
5
|
+
(nothing done) → `~`. When `done > total`, the percents/total part is
|
|
6
|
+
dropped entirely.
|
|
7
|
+
|
|
8
|
+
```js
|
|
9
|
+
format_progress_bytes({percents: 0.2525, total: 15*1024*1024, done: 5*1024*1024, rate: 10*1024*1024, eta: 5, duration: 1})
|
|
10
|
+
// '25.25% | 5.0MB of 15.0MB at 10.0MB/s ETA 00:00:05 duration=00:00:01'
|
|
11
|
+
format_progress_bytes({percents: 0, total: 0, done: 0, rate: 0, eta: 0, duration: 0})
|
|
12
|
+
// '~'
|
|
13
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Formats a `make_progress` snapshot (`{percents, total, done, rate, eta, duration}`)
|
|
2
|
+
as a one-line progress string using metric 1000-based units (`format_kilo`) —
|
|
3
|
+
for counting items, jobs, rows, etc. Identical layout and degradation rules
|
|
4
|
+
to `format_progress_bytes`: unknown parts render as `~`, and when
|
|
5
|
+
`done > total` the percents/total part is dropped.
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
format_progress_kilo({percents: 0.2525, total: 15e6, done: 5e6, rate: 10e6, eta: 5, duration: 1})
|
|
9
|
+
// '25.25% | 5.00M of 15.00M at 10.00M/s ETA 00:00:05 duration=00:00:01'
|
|
10
|
+
```
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Formats a duration in seconds as `HH:MM:SS`. Hours are always present and grow
|
|
2
|
+
beyond two digits as needed. Fractional seconds are truncated toward zero. The
|
|
3
|
+
`'-'` prefix appears only for `seconds <= -1`, so values in `(-1, 0)` format as
|
|
4
|
+
plain `'00:00:00'`.
|
|
5
|
+
|
|
6
|
+
```js
|
|
7
|
+
format_seconds(3661) // '01:01:01'
|
|
8
|
+
format_seconds(1000000) // '277:46:40'
|
|
9
|
+
format_seconds(-0.9) // '00:00:00'
|
|
10
|
+
format_seconds(-1) // '-00:00:01'
|
|
11
|
+
```
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Formats a number with commas as thousands separators. Works on the value's
|
|
2
|
+
`toString()` output: only the integer part is grouped, fractional digits are
|
|
3
|
+
left untouched, and negative numbers are handled.
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
format_thousands(1234567) // '1,234,567'
|
|
7
|
+
format_thousands(-1000) // '-1,000'
|
|
8
|
+
format_thousands(123456789.01234) // '123,456,789.01234'
|
|
9
|
+
```
|
package/src/fs_append.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Appends data to a file, creating the file if it does not exist.
|
|
2
|
+
Thin wrapper over `fs.promises.appendFile(file, data, options)`; `data` may be a string or a `Buffer`.
|
|
3
|
+
See `fs_append_utf8` for text and `fs_append_json` for JSON lines.
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
fs_append(file, data, options) → Promise<void>
|
|
7
|
+
```
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Appends a value to a file as one line of JSON (JSON Lines format).
|
|
2
|
+
The value is serialized with `json_stringify_stable` (object keys sorted) and followed by a newline.
|
|
3
|
+
|
|
4
|
+
```js
|
|
5
|
+
await fs_append_json(file, {b: 1, a: [2]});
|
|
6
|
+
await fs_append_json(file, 'x');
|
|
7
|
+
// file content: '{"a":[2],"b":1}\n"x"\n'
|
|
8
|
+
```
|
package/src/fs_copy.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copies `src` to `dest`, overwriting `dest` if it exists.
|
|
2
|
+
Thin wrapper over `fs.promises.copyFile(src, dest, mode)`; `mode` takes `fs.constants` copy flags.
|
|
3
|
+
Use `fs_copy_excl` to fail instead of overwriting.
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
fs_copy(src, dest, mode) → Promise<void>
|
|
7
|
+
```
|
package/src/fs_exists.md
ADDED
package/src/fs_fclose.md
ADDED
package/src/fs_fi.js
CHANGED
|
@@ -15,7 +15,19 @@ async function fs_fi(pathname)
|
|
|
15
15
|
const target = await fs_readlink(fi.pathname);
|
|
16
16
|
const target_pathname = fs_path_resolve(fs_path_dirname(pathname), target);
|
|
17
17
|
fi.target = target;
|
|
18
|
-
|
|
18
|
+
try {
|
|
19
|
+
fi.target_fi = await fs_lstat(target_pathname);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
if (!['ENOENT', 'ENOTDIR', 'ELOOP'].includes(error.code)) {
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
// A broken symlink is a legitimate directory entry: report it
|
|
26
|
+
// with target_fi = null instead of failing the whole listing
|
|
27
|
+
// (fs_find, fs_list, fs_ls, fs_lsr, fs_list_deep).
|
|
28
|
+
fi.target_fi = null;
|
|
29
|
+
return fi;
|
|
30
|
+
}
|
|
19
31
|
fi.target_fi.pathname = target_pathname;
|
|
20
32
|
fi.target_fi.basename = fs_path_basename(target_pathname);
|
|
21
33
|
flags(fi.target_fi);
|
package/src/fs_fi.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Returns extended file info: an lstat `Stats` object augmented with `pathname`, `basename`,
|
|
2
|
+
`flags` (e.g. `['is_file']`) and `flags_map` (e.g. `{is_file: true}`).
|
|
3
|
+
For a symlink it also resolves the target: `target` is the raw link text and `target_fi`
|
|
4
|
+
the target's own info object — or `null` for a broken symlink, so directory listings
|
|
5
|
+
(`fs_find`, `fs_list`, ...) never fail on dangling links.
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
await fs_fi('/tmp/d/link'); // link → 'data.txt'
|
|
9
|
+
// { ..., flags: ['is_symbolic_link'], target: 'data.txt',
|
|
10
|
+
// target_fi: { pathname: '/tmp/d/data.txt', flags: ['is_file'], ... } }
|
|
11
|
+
```
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Computes the MD5 of a file by streaming it (constant memory regardless of
|
|
2
|
+
file size). The second argument is the digest encoding, `'hex'` by default;
|
|
3
|
+
any `crypto` digest encoding (e.g. `'base64'`) works.
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
await fs_file_md5('/tmp/data.txt') // '5eb63bbbe01eeed093cb22bb8f5acdc3'
|
|
7
|
+
await fs_file_md5('/tmp/data.txt', 'base64') // 'XrY7u+Ae7tCTyyK7j1rNww=='
|
|
8
|
+
```
|
package/src/fs_find.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Recursively lists a directory tree as an array of `fs_fi` info objects with absolute
|
|
2
|
+
pathnames — the root entry first, then its contents depth-first in `readdir` order.
|
|
3
|
+
A non-directory pathname yields just its own entry.
|
|
4
|
+
Broken symlinks are reported (`target_fi: null`) instead of failing the walk,
|
|
5
|
+
and symlinks to directories are not descended into.
|
|
6
|
+
See `fs_list` for a shallow listing and `fs_list_deep` for a recursive one
|
|
7
|
+
that keeps pathnames relative to the input.
|
package/src/fs_fopen.md
ADDED
package/src/fs_fread.js
CHANGED
|
@@ -5,12 +5,12 @@ const fs = require('fs');
|
|
|
5
5
|
*/
|
|
6
6
|
async function fs_fread(fp, buffer, offset = null, size = buffer.length)
|
|
7
7
|
{
|
|
8
|
-
const
|
|
8
|
+
const bytes_read = await new Promise(function (resolve, reject) {
|
|
9
9
|
fs.read(fp, buffer, 0, size, offset, function (error, out) {
|
|
10
10
|
error ? reject(error) : resolve(out);
|
|
11
11
|
});
|
|
12
12
|
});
|
|
13
|
-
return (
|
|
13
|
+
return (bytes_read === buffer.length) ? buffer : buffer.subarray(0, bytes_read);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
module.exports = fs_fread;
|
package/src/fs_fread.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Reads up to `size` bytes (default: the buffer length) from a file descriptor into the start of `buffer`.
|
|
2
|
+
With `offset = null` (default) it reads from the current file position and advances it;
|
|
3
|
+
an explicit `offset` reads at that position without moving it.
|
|
4
|
+
Resolves with the filled part of the buffer: `buffer` itself when filled exactly,
|
|
5
|
+
otherwise `buffer.subarray(0, bytes_read)` — an empty chunk past the end of file.
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
const fp = await fs_fopen(file); // file content: 'hello world'
|
|
9
|
+
await fs_fread(fp, Buffer.alloc(1024), 6, 5); // <Buffer 'world'>
|
|
10
|
+
await fs_fread(fp, Buffer.alloc(1024), 100); // <Buffer > (length 0)
|
|
11
|
+
```
|
package/src/fs_fsize.md
ADDED
package/src/fs_fstat.md
ADDED
package/src/fs_fwrite.js
CHANGED
|
@@ -5,12 +5,12 @@ const fs = require('fs');
|
|
|
5
5
|
*/
|
|
6
6
|
async function fs_fwrite(fp, buffer, offset = null)
|
|
7
7
|
{
|
|
8
|
-
const
|
|
8
|
+
const bytes_written = await new Promise(function (resolve, reject) {
|
|
9
9
|
fs.write(fp, buffer, 0, buffer.length, offset, function (error, out) {
|
|
10
10
|
error ? reject(error) : resolve(out);
|
|
11
11
|
});
|
|
12
12
|
});
|
|
13
|
-
return
|
|
13
|
+
return bytes_written;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
module.exports = fs_fwrite;
|
package/src/fs_fwrite.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Writes the whole `buffer` to a file descriptor and resolves with `bytes_written`.
|
|
2
|
+
With `offset = null` (default) it writes at the current file position;
|
|
3
|
+
pass an explicit `offset` to write at that position instead.
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
const fp = await fs_fopen(file, 'w');
|
|
7
|
+
await fs_fwrite(fp, Buffer.from('hello world')); // 11
|
|
8
|
+
await fs_fwrite(fp, Buffer.from('WORLD'), 6); // 5 — file is now 'hello WORLD'
|
|
9
|
+
```
|
package/src/fs_list.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Shallow directory listing: resolves with an array of `fs_fi` info objects for the direct
|
|
2
|
+
entries of `pathname` (the directory itself is not included).
|
|
3
|
+
A non-directory pathname yields `[fi]` of itself.
|
|
4
|
+
Entry pathnames are `pathname` joined with each name, so they stay relative if the input is relative.
|
|
5
|
+
See `fs_list_deep` and `fs_find` for recursive variants.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Recursively lists `path` as an array of `fs_fi` info objects, including the root entry
|
|
2
|
+
itself and every directory below it.
|
|
3
|
+
Traversal is stack-based: the root comes first, but the rest is in no particular order.
|
|
4
|
+
Pathnames are joined from the input, so they stay relative if the input is relative.
|
|
5
|
+
See `fs_list` (shallow) and `fs_find` (recursive, absolute pathnames, depth-first order).
|
package/src/fs_ls.md
ADDED
package/src/fs_lsr.md
ADDED
package/src/fs_lstat.md
ADDED
package/src/fs_mkdir.md
ADDED
package/src/fs_mkdirp.js
CHANGED
|
@@ -1,36 +1,9 @@
|
|
|
1
|
-
const
|
|
2
|
-
const fs_mkdir = require('./fs_mkdir');
|
|
3
|
-
const fs_path_dirname = require('./fs_path_dirname');
|
|
1
|
+
const fs = require('fs');
|
|
4
2
|
|
|
5
3
|
async function fs_mkdirp(pathname)
|
|
6
4
|
{
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
for (let p = pathname; p && p !== '/'; p = fs_path_dirname(p)) {
|
|
10
|
-
if (await fs_exists(p)) {
|
|
11
|
-
break;
|
|
12
|
-
}
|
|
13
|
-
parents.push(p);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
while (parents.length) {
|
|
17
|
-
try {
|
|
18
|
-
await fs_mkdir(parents.pop());
|
|
19
|
-
}
|
|
20
|
-
catch (error) {
|
|
21
|
-
// Error: EEXIST: file already exists, mkdir [...]
|
|
22
|
-
if (error.code === 'EEXIST') {
|
|
23
|
-
// Exiting here is not correct. When two processes are running in parallel,
|
|
24
|
-
// one tries to create `a/b/c` and another `a`. When second process creates
|
|
25
|
-
// `a`, the first process will get `EEXIST` and stops (break) creating any
|
|
26
|
-
// nested directories, which is not correct.
|
|
27
|
-
// break;
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
|
-
throw error;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
5
|
+
// Unlike the native call, resolves with `pathname` (handy for chaining).
|
|
6
|
+
await fs.promises.mkdir(pathname, {recursive: true});
|
|
34
7
|
return pathname;
|
|
35
8
|
}
|
|
36
9
|
|
package/src/fs_mkdirp.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Creates a directory and any missing parents (`mkdir -p`). An already existing directory
|
|
2
|
+
is fine (safe to call in parallel), but a path that exists as a regular file rejects with `EEXIST`.
|
|
3
|
+
Unlike the native call, resolves with `pathname` itself — handy for chaining.
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
await fs_mkdirp('/tmp/a/b/c'); // '/tmp/a/b/c'
|
|
7
|
+
```
|