tools#
File, process, string, and object utilities, with a selected Lodash build.
Install#
npm i @nodedk/tools
Usage#
var tools = require('@nodedk/tools')
async function main() {
var config = await tools.read('./config.json')
var files = await tools.tree('./app')
console.log(tools.get(config, 'server.port', 3000))
console.log(files)
console.log(tools.slug('Hello, world!'))
}
main().catch(console.error)
Functions are synchronous unless described as returning a Promise.
Files and paths#
Paths passed to file helpers are resolved with resolve(). Methods that
write or append resolve without a value.
resolve(...parts): joins path parts and returns an absolute path. A leading~expands to the home directory;@expands to the current directory.basext(file): returns[base, extension, filename]; the extension has no dot.exist(file): Promise of whetherstatsucceeds.isDir(file),isFile(file): Promises of directory/file checks; false on stat errors. Follow symbolic links.isSymlink(file): Promise of a symbolic-link check usinglstat.read(file, encoding): Promise of file contents or a loaded module. With no encoding,.js,.json,.mjs,.cjs,.wasm, and.nodeuserequire(),.ymlusesyaml.load, and other files return UTF-8 text. Pass'utf8'to read source text instead of loading a module. Module caching and runtime module-format support apply.write(file, content): creates parent directories and overwrites the file. Objects/arrays are serialized for.jsonand.yml; other content is passed tofs.writeFile. Directory creation uses a shell command, so use trusted paths without shell metacharacters.append(file, content): appends text or bytes; does not create parent directories.edit(file, fn): reads UTF-8 text, calls synchronousfn(text), then writes its result. A falsy result writes an empty string.dir(file): Promise of entry names, or anErrorobject if reading fails.walk(directory, fn): recursively callsfn(file, parentDirectory)for files. Returns a Promise after traversal; callback Promises are not awaited.tree(root): Promise of an array of absolute file paths;[]for a missing root.env(file, mode): Promise of configuration loaded fromfile, merged withname.<mode>.extwhen present. Nested objects merge; arrays concatenate. Missing files contribute{}.
var tools = require('@nodedk/tools')
async function main() {
var config = await tools.env('./config.json', 'production')
await tools.write('./data/config.json', config)
await tools.append('./data/events.log', 'Started\n')
await tools.edit('./data/events.log', function (text) {
return text.replace('Started', 'Ready')
})
await tools.walk('./data', function (file, directory) {
console.log(directory, file)
})
}
main().catch(console.error)
Commands and terminal input#
These helpers execute local commands. run, cap, and pass return Promises
of combined, trimmed stdout and stderr. A nonzero command exit still resolves;
the result does not include an exit code.
run(command = '', options = {}): executes a command and prints its output. Options:shell(default true),stdio(default'pipe'), andquiet(default false). Keep stdout and stderr piped so output can be collected.cap(command = '', options = {}): setsoptions.quiet = true, then callsrun.pass(command = '', options = {}): inherits stdin, pipes output, and callsrun. Updatesoptions.stdioin place.ask(prompt = '> ', options = {}): Promise of one input line. Options are passed toreadline.createInterface, overriding stdin/stdout defaults.key(fn): enables raw terminal input and adds akeypresslistenerfn(text, key). Returns no value; requires a TTY and leaves raw mode enabled.print(value): replaces the current terminal line, without a newline. Objects are JSON-stringified. Returns no value.exit(message, code = 0): optionally logs a message, then exits the process.sleep(seconds = 1): Promise that resolves after the delay.
var tools = require('@nodedk/tools')
async function main() {
var version = await tools.cap('node --version')
var name = await tools.ask('Name: ')
tools.print(tools.format('%s uses %s', name, version))
await tools.sleep(1)
}
main().catch(console.error)
IDs and hashes#
uuid(): UUID version 4 string, supplied byuuid.v4. Also accepts that function’soptions, outputbuffer, and byteoffsetarguments.cuid(): CUID2 string, supplied bycreateId().hex(size = 20): random hexadecimal string ofsizecharacters.md5(value): hexadecimal MD5 digest of a string or supported byte input.hash(value, saltRounds = 10): Promise of a bcrypt hash; coerces input to a string.compare(plain, hash): Promise of a bcrypt match boolean; coerces both to strings.
var tools = require('@nodedk/tools')
async function main() {
var hash = await tools.hash('example-password')
console.log(await tools.compare('example-password', hash))
console.log(tools.uuid(), tools.cuid(), tools.hex(32))
}
main().catch(console.error)
Type checks and conversion#
Every check below takes one value and returns a boolean.
isEmail(value): simple non-whitespacename@domain.suffixpattern.isId(value): at least 24 lowercase letters or digits.isURL(value): matches an HTTP(S) orwww.address within the string.isDateString(value): matches the library’s timestamp pattern; this is a format check, not full calendar validation.isDateObject(value): Lodash Date-object check, including invalid Dates.isDate(value): accepts a Date object or a matching date string.isRegExpString(value): matches%r/pattern/flags, withiandgflags.isRegExpObject(value): Lodash RegExp-object check.isRegExp(value): accepts a RegExp object or encoded regex string.isBool(value): boolean conversion. The strings'false','null','NaN','undefined', and'0'become false; all others use!!value.
type(value) returns the lowercase object-tag name, such as 'array',
'date', 'null', or 'undefined'.
convert(value, type) supports 'string' and 'id' via String, 'integer'
via parseInt, 'float' via parseFloat, 'date' via new Date, and
'boolean' via isBool. Unknown types pass through unchanged.
unstring(value, options = {}) recursively restores encoded RegExps and
parseable timestamp strings. Objects/arrays are updated in place; a primitive
returns its converted value. options is currently unused. Timestamp 0
is not converted because the parser result is tested for truthiness.
tools.convert('42', 'integer') // 42
tools.isBool('false') // false
tools.unstring({ pattern: '%r/hello/i', at: '2026-09-11T10:00:00Z' })
Strings and display#
format(template, ...values): replaces one%sper value, in order. Arrays join with', '; plain objects become'key: value'pairs.strip(text, separator = '\n'): trims each segment and rejoins with the separator.slug(value): lowercases, transliterates common accented characters, replaces separators with hyphens, and removes unsupported characters.shorten(name, max = 20): trims and collapses whitespace. When longer thanmax, abbreviates every word except the last to an initial.maxis a trigger, not a guaranteed output length.json(value):JSON.stringify(value, null, 2).colorize(): random pale HSL color string.inspect(value, options = {}): deep-clones the value, returnsutil.inspectoutput, and prints it unlessquietis true. Inspection options are forwarded toutil.inspect.excludesets listed object paths to null in the clone; the current implementation replaces the options variable while processing exclusions, so do not combine it with other options.
tools.format('Members: %s', ['Ada', 'Kim']) // 'Members: Ada, Kim'
tools.strip(' one \n two ') // 'one\ntwo'
tools.shorten('Ada Augusta Lovelace', 15) // 'A. A. Lovelace'
var text = tools.inspect({ name: 'Ada' }, { quiet: true, depth: null })
Objects and arrays#
deepTrim(object, characters = ''): trims the selected characters from every nested string in place; returns no value. The default empty character set leaves strings unchanged. Pass' 'to trim spaces.dot(object, separator = '.'): returns flattened paths for nested plain objects. Arrays remain leaf values.undot(object, separator = '.'): rebuilds nested values using Lodashset.separatorjoins nested source keys; Lodash still interprets dots/brackets in the resulting paths.clean(data, ...types): removes nullish leaf values by default, or leaf values matchingtype()names when provided. Mutates and returns data. Arrays are spliced during traversal; adjacent removable elements can be skipped.traverse(object, fn, path = []): awaitsfn(key, value, parent, path)for each leaf.pathdescribes the parent; appendkeyfor the full leaf path. Adds a non-enumerable_parentreference to nested objects. Resolves without a value.sortByNumber(array, comparator): sorts in place and returns the array. Defaults to comparing leading numbers in strings. Pass a standard(a, b) => numbercomparator to override it.
var data = { user: { name: ' Ada ' }, roles: ['editor'] }
tools.deepTrim(data, ' ')
var flat = tools.dot(data)
// { 'user.name': 'Ada', roles: ['editor'] }
var nested = tools.undot(flat)
await tools.traverse(nested, function (key, value, parent, path) {
console.log(path.concat(key), value)
})
Lodash functions#
The selected Lodash build is available as tools.lodash and copied onto
tools. Root isDate and isRegExp are the extended checks above; use
tools.lodash.isDate and tools.lodash.isRegExp for object-only checks.
cloneDeep(value): recursively clones a value.get(object, path, defaultValue): reads a dot/bracket path or path array.set(object, path, value): writes a path in place and returns the object.pick(object, ...paths),omit(object, ...paths): return selected or excluded properties; paths may be arrays.merge(object, ...sources): recursively merges into the first object and returns it; arrays merge by index.mergeWith(object, ...sources, customizer): merges withcustomizer(objectValue, sourceValue, key, object, source, stack). Returningundefineduses the default merge behavior.sortBy(collection, ...iteratees): returns values in stable ascending order. Iteratees may be property paths, functions, or supported Lodash shorthands.transform(object, iteratee, accumulator): builds and returns an accumulator;iteratee(accumulator, value, key, object)may return false to stop. An omitted accumulator uses a matching empty container.trim(string = '', characters): trims whitespace by default or selected characters when supplied.isArray,isBoolean,isEmpty,isFunction,isInteger,isNil,isNumber,isPlainObject,isString,isUndefined: single-value Lodash predicates.isNilaccepts null/undefined;isNumberincludesNaNand boxed numbers;isEmptychecks collection contents rather than truthiness.
The build also exposes these Lodash helpers:
constant(value): returns a function that always returnsvalue.identity(value): returns its argument.property(path): returns a function that reads the path from an object.iteratee(value): creates a callback from a function, property path,[path, expectedValue], or object matcher.flatten(array): flattens one array level.last(array): returns the final item orundefined.keys(object),keysIn(object): enumerable string keys, own-only or also inherited.hasIn(object, path): checks a path, including inherited properties.toPlainObject(value): copies enumerable own and inherited properties.memoize(fn, resolver): caches function results. The optional resolver receives the same arguments and chooses a cache key; otherwise the first argument is the key. The returned function exposes.cache.eq(value, other): SameValueZero equality, includingNaNequal toNaN.toNumber(value),toFinite(value),toInteger(value),toString(value): Lodash conversions to the named type. Finite/integer conversion mapsNaNto0and bounds infinities; string conversion maps nullish values to''.isArguments,isArrayLike,isArrayLikeObject,isBuffer,isLength,isMap,isObject,isObjectLike,isSet,isSymbol,isTypedArray: single-value Lodash predicates. Array-like values have a valid.lengthand are not functions; the object variant also requires an object.stubArray(),stubFalse(): return a fresh[]orfalse._: reference to the custom Lodash export.
Other exports#
mode:NODE_ENVcaptured when the module loads.NODE_EXTENSIONS:['js', 'json', 'mjs', 'cjs', 'wasm', 'node'].regexp: regular expressions namedemail,id,reg,date,url,slug,ip,image,domain, andsubdomain. Use.test(value)for a match.yaml: thejs-yamlmodule, includingload(source, options)anddump(value, options).lazy(moduleName): returns a proxy that loads a module on its first call or property access. Calls forward arguments andthisto the module’s exported function. Resolution is based on the working directory captured whentoolsloads.
var tools = require('@nodedk/tools')
var path = tools.lazy('node:path')
console.log(path.basename('/app/index.js'))
Development#
Rebuild the selected Lodash functions listed in scripts/build.js:
npm run build
The generated file is lib/lodash.js.
Created by Vidar Eldøy