Rick Osborne's collection of utilities for working at the terminal, with local files and processes, etc. Built on:
- @rickosborne/typical for types
- @rickosborne/guard for guards
- @rickosborne/foundation for basic data structures and algorithms
Install via your favorite package manager.
Each package supports CommonJS require
, ESM import
, and TypeScript usage.
You also have a choice: barrel imports or direct imports.
Barrel imports mean you're going to require/import everything from the same package-level namespace:
// CommonJS
const { isPlainObject, isListOf } = require("@rickosborne/guard");
// ESM / TypeScript
import { isPlainObject, isListOf } from "@rickosborne/guard";
Implications:
- Nice and simple.
- Your build system needs to do tree-shaking well ... or you'll end up adding the entire package even if you only import two functions.
The other option is to use direct imports:
// CommonJS
const { isPlainObject } = require("@rickosborne/guard/is-object");
const { isListOf } = require("@rickosborne/guard/is-list-of");
// ESM / TypeScript
import { isPlainObject } from "@rickosborne/guard/is-object.js";
import { isListOf } from "@rickosborne/guard/is-list-of.js";
Implications:
- You (probably) don't have to worry about tree-shaking as your build (likely) ends up with only the functions you need.
If you're using a modern build system, there aren't any strong reasons to prefer one way over the other. It's really just down to your personal preference.
Do you need to use file extensions? And if so, which extensions?
Honestly ... this is a dumpster fire question. It really comes down to your own setup and configuration.
Within each package itself:
- The CommonJS files all have
.cjs
extensions. - The ESM files all have
.mjs
extensions. - Node subpath exports have been set up to send
.js
imports to the.cjs
(viarequire
) or.mjs
(viaimport
) files, depending on your setup.
So, in theory, the only extension which won't work would be .ts
because the source isn't included.
If you run into a problem with a particular configuration, file a GitHub issue with:
- Your
tsconfig.json
'smodule
,moduleResolution
, andtarget
settings. - Your
package.json
'stype
andimports
settings. - An example of another package which imports correctly for you.
This package is licensed as CC-BY-NC-SA-4.0 unless otherwise noted. That is, Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International.
class FileExistsError extends Error
An error thrown when a file is expected to not exist, but does.
class FileMissingError extends Error
Error thrown if a file does not exist.
class NotFileError extends Error
Error thrown when a filesystem entry is expected to be a file, but is not.
assertFileExists: (filePath: string, config?: AssertFileExistsConfig) => Stats
compareExportsKeys: (a: string, b: string) => number
Comparator for the keys of a package.json's exports map, to ensure they are serialized in the correct order.
copyRecursiveFilterDefault: (dirEnt: Dirent) => boolean
copyRecursiveSync: (source: string, destination: string, options?: CopyRecursiveOptions) => CopyRecursiveResult
dirExists: (...parts: string[]) => boolean
Synchronous check to see if the given path exists and is a directory.
envOrArg: (nameOrNames: string | string[], options?: EnvOrArgOptions) => string | undefined
Best-effort attempt to find a configuration arg in both the environment and the command-line, when you don't want to define the entire parameter set. Tries its best to do what you mean, such as converting SNAKE_CASE
environment params to --kebab-case
command line params and vice versa. Returns ARG_FLAG if it appears the command line param is present, but is actually a flag.
function fileExists(...parts: string[]): boolean;
Synchronous check to see whether the given path exists and is a file.
function fileExists(statSync: StatSyncLike, ...parts: string[]): boolean;
Synchronous check to see whether the given path exists and is a file. This form accepts an override for fs.statSync
.
gitInfo: () => GitInfo
Get very basic git status.
pathWithPackageJson: (...parts: string[]) => string
Ensure the given path points to a package.json file and not just a directory.
positionalArgs: (args?: string[], config?: PositionalArgsConfig) => string[]
Try to find command line arguments which look like positionals. This is super, duper basic and only useful in very simple scenarios where you expect mostly positionals and no interesting flag configurations.
preparePackageJsonForSerialization: (pkg: PackageJsonLike) => PackageJsonLike
Mangle a package.json structure to make it serialize properly.
readFile: (path: string) => string
Synchronous read of a file as text using UTF-8 encoding.
readJson: <T>(path: string) => T
Synchronous read of a file as UTF-8 text, parsing it as JSON.
readPackageJson: (pathOrModuleName: string) => PackageJsonLike
Read a package.json from the given path, returning it as structured data instead of just text.
remapExports: <R extends Record<string, string>>(exports: R) => R
Given a package.json's exports map, generate a version which should serialize in the correct order.
statsForFile: (filePath: string, config?: StatsForFileConfig) => fs.Stats | undefined
Get the stats for a path, if it exists. Throws if the path does not point to a file.
writeJson: (filePath: string, value: unknown, config?: WriteJsonConfig) => void
Serialize and synchronously write out JSON to a UTF-8 text file. Has some extra special handling for package.json files.
writeText: (filePath: string, text: string, config?: WriteTextConfig) => void
Synchronously write a file as UTF-8 text.
export interface AssertFileExistsConfig
Configuration for a assertFileExists call.
export interface FileConflictErrorOptions extends ErrorOptions
Options for the FileExistsError constructor.
export interface FileMissingErrorOptions extends ErrorOptions
Options for the FileMissingError constructor.
export interface GitInfo extends RawGitInfo
Information about the current state of git.
export interface NotFileErrorOptions extends ErrorOptions
Options for the NotFileError constructor.
export interface RawGitInfo
The text values which can be obtained from a git log
invocation.
type CopyRecursiveOptions = {
copyFileSync?: (source: string, destination: string) => void;
keepIf?: (dirEnt: Dirent) => boolean;
log?: (message: string) => void;
mkdirSync?: (path: string, options: {
recursive: true;
}) => void;
onCopy?: (sourceDirEnt: Dirent, destination: string) => void;
overwrite?: boolean;
readdirSync?: (path: string, options: {
recursive: false;
encoding: "utf8";
withFileTypes: true;
}) => Dirent[];
sort?: Comparator<Dirent>;
verbose?: boolean;
};
Options for copyRecursiveSync.
type CopyRecursiveResult = {
fileCount: number;
dirCount: number;
totalCount: number;
};
type EnvOrArgOptions = {
allowBlank?: boolean;
argv?: string[];
env?: Record<string, string | undefined>;
};
Options for a call to envOrArg.
type PackageJsonLike = {
dependencies?: Record<string, string>;
devDependencies?: Record<string, string>;
exports?: {
[key: string]: {
default?: string;
import?: string;
require?: string;
types?: string;
} & Record<string, string>;
};
files?: string[];
git?: string | Record<string, string>;
main?: string;
module?: string;
name: string;
peerDependencies?: Record<string, string>;
private?: boolean;
publishConfig?: {
access: "public";
};
readme?: string;
repository?: {
directory?: string;
type?: string;
url?: string;
};
scripts?: Record<string, string>;
types?: string;
typings?: string;
version: string;
};
Oversimplified package.json type definition. Doesn't have absolutely everything, and is more of a "reasonable default" view.
type PositionalArgsConfig = {
ignoreDot?: boolean;
};
Configuration for a positionalArgs call.
type StatsForFileConfig = {
statSync?: (path: string, options: {
throwIfNoEntry: false;
}) => (undefined | fs.Stats);
throwIfNotFile?: boolean;
};
Configuration for a statsForFile call.
type StatSyncLike = (path: string, options: {
throwIfNoEntry: false;
}) => {
isFile: () => boolean;
};
type WriteJsonConfig = WriteTextConfig & {
modifyJson?: UnaryOperator<string>;
modifySorted?: <T>(value: T) => (void | undefined | T);
indent?: string | number;
writeText?: typeof writeText;
};
Configuration for a writeJson call.
type WriteTextConfig = {
consoleLog?: Consumer<string>;
finalNewline?: boolean;
relativeTo?: string;
silent?: boolean;
writeFileSync?: TriConsumer<string, string, {
encoding: "utf-8";
}>;
};
Configuration for a writeText call.
ARG_FLAG = "<flag>"
Value returned from envOrArg when an arg is present, but it appears to be a flag instead of a param.
DEPENDENCIES_KEYS: readonly ["dependencies", "devDependencies", "peerDependencies"]
Property names for the parts of a package.json which may include dependency information.
EXPORTS_ORDER: readonly ["types", "import", "require", "default"]
Reasonable order for the keys of a package.json's exports map.
isDryRun: boolean
Flag to indicate whether --dry-run was provided on the command line.