(ns ird.node
"The one namespace that touches Node-specific modules (fs, readline) and
byte helpers. Modules are required lazily so nothing here runs at load
time; the rest of the library only needs Node 18 globals (fetch, Buffer,
TextEncoder, BigInt).
Uses js/require, which works under every shadow-cljs Node target and
vanilla ClojureScript's :target :nodejs. For an ESM build without a
`require` global, use shadow-cljs's :keep-native-requires (or provide one
via node:module's createRequire)."
(:require [clojure.string :as str]
[ird.async :as a]))
(def ^:private fsp (delay (js/require "node:fs/promises")))
(def ^:private readline (delay (js/require "node:readline/promises")))
(defn read-file
"Channel of the file's bytes (a Buffer, which is a Uint8Array) or an
Error when it cannot be read."
[path]
(a/promise->chan (.readFile ^js @fsp path)))
(defn question
"Print PROMPT and deliver the trimmed line typed on stdin."
[prompt]
(let [^js rl (.createInterface ^js @readline #js {:input js/process.stdin
:output js/process.stdout})]
(a/promise->chan (-> (.question rl prompt)
(.finally #(.close rl))
(.then str/trim)))))
(defn base64-encode
"Standard base64 of BYTES (Uint8Array, Buffer or ArrayBuffer)."
[bytes]
(.toString (js/Buffer.from bytes) "base64"))
(defn base64-decode
"Decode standard base64 text S into a Uint8Array."
[s]
(js/Uint8Array.from (js/Buffer.from s "base64")))
(defn utf8-bytes
"UTF-8 encode string S into a Uint8Array."
[s]
(.encode (js/TextEncoder.) s))
(defn utf8-string
"Decode UTF-8 BYTES (Uint8Array/Buffer) into a string."
[bytes]
(.decode (js/TextDecoder.) bytes))
(defn bytes?
"True for the byte sources this library sends as-is: Uint8Array (incl.
Buffer), ArrayBuffer, Blob, ReadableStream."
[v]
(or (instance? js/Uint8Array v)
(instance? js/ArrayBuffer v)
(and (exists? js/Blob) (instance? js/Blob v))
(and (exists? js/ReadableStream) (instance? js/ReadableStream v))))