
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
A collection of functions that operate on principles found in Rails,
specifically with regard to figuring out if a given value is blank
or present.
import { strict: assert } from "assert";
import { isPresent, isBlank } from "railsish";
// It treats empty or invalid values as blank...
assert(isBlank([]), "an empty array is blank");
assert(isBlank({}), "an empty object is blank");
assert(isBlank(new Date("2020-03-32")), "an invalid date is blank");
assert(isBlank(NaN), "NaN is blank");
assert(isBlank("\n\t "), "a string containing only whitespace is blank");
// But there's a special case: 0 is present!
assert(isPresent(0), "0 is present");
Related to the above concepts, railsish includes some helper methods
that can be used to extract values from nested objects, perform some
checks, and do what you want them to.
import { strict: assert } from "assert";
import { getPresent } from "railsish";
assert.equal(getPresent({ foo: { bar: { baz: null } } }, "foo.bar.baz", "quux"), "quux", "it will return a default value");
import { strict: assert } from "assert";
import { getPresentNumber, getPresentString } from "railsish";
assert.equal(getPresentNumber({ foo: "-3.14" }, "foo"), -3.14, "fetching a numeric string will cast it");
assert.equal(getPresentString({ foo: "\t" }, "foo", "default"), "default", "whitespace-only strings are not present");
Sometimes you want to work with boolean values directly, distinct from blankness and presence,
and so there’s also the booleanize function. It works a little differently, in that it does
treat 0, and certain string values as falsey. It’s intended for use with API responses or
other inconsistent data containing booleanesque values that aren’t true or false.
import { booleanize } from "railsish";
booleanize(0) === false
booleanize("0") == false
// an empty object
booleanize({}) === false
// an empty array
booleanize([]) === false
booleanize(new Int8Array()) === false
// an empty string
booleanize("") === false
// a string that's only whitespace
booleanize(" ") === false
// special string handling: the following are case-insensitive
booleanize("F") === false
booleanize("n") === false
booleanize("no") === false
booleanize("nil") === false
booleanize("NULL") === false
booleanize("FALSE") === false
There’s a helper method for this one, too, that uses its logic instead:
import { strict: assert } from "assert";
import { getBoolean } from "railsish";
assert.fail(getBoolean({ foo: [] }, "foo"), "it will booleanize the value at a given path");
isPresent and isBlank trace their inspiration to Rails and ActiveSupport’s Object#blank? logic.
booleanize is loosely inspired by how ActiveRecord converts values from forms to booleans,
but has been expanded for handling other edge cases I’ve come across when developing.
Check to see if a given value is “present”, translated from Rails’ standards into JavaScript.
It is a boolean complement of {@linkcode module:railsish/presence.isBlank isBlank}. Simply put, if an object is not blank, it is considered present.
value any Returns boolean
Check to see if a given value is “blank”, translated from Rails’ standards into JavaScript.
Certain values are truthy in JS that are considered blank by this function, namely:
"\n\t \r\n"{}Map or SetDate object, e.g. new Date("2020-03-32")Additionally, 0 is considered false but is not considered blank,
as it is a finite number.
value any Returns boolean
Convert a provided value to a boolean with some handy logic.
This is used to handle cases where the value should be a
boolean, but might be coming from an API or some other representation
that is not explicitly true / false
value any something to convertbooleanize(0) === false
booleanize("0") == false
// an empty object
booleanize({}) === false
// an empty array
booleanize([]) === false
booleanize(new Int8Array()) === false
// an empty string
booleanize("") === false
// a string that's only whitespace
booleanize(" ") === false
// special string handling: the following are case-insensitive
booleanize("F") === false
booleanize("n") === false
booleanize("no") === false
booleanize("nil") === false
booleanize("NULL") === false
booleanize("FALSE") === false
Returns boolean the booleanized value
Methods used to fetch various deeply-nested values based on presence or booleanization from an object.
Process an API response, elasticsearch document, JSON document, or anything else and remove the need for complex code like:
import { getPresentArray }
const response = {
foo: {
bar: {
baz: {
quux: []
}
}
}
};
// instead of this:
function extractDeepValue(value) {
if (value && value.foo) {
if (value.foo.bar) {
if (value.foo.bar.baz) {
if (Array.isArray(value.foo.bar.baz.quux) && value.foo.bar.baz.quux.length > 0) {
return value;
}
}
}
}
return ["default"];
};
extractDeepValue(response, ["default"]);
// you can just:
getPresentArray(response, "foo.bar.baz.quux", ["default"]);
While all of the get___ accessors accept a defaultValue as their third parameter,
no type-checking or related validation is performed on it: it’s returned as is. This
is by design, so that you can handle unset values at a higher level.
import { getPresentArray } from "railsish";
const NO_TAGS_SELECTED = Symbol("NO_TAGS");
const getSelectedTags = (config) => getPresentArray(config, "user.selected.tags", NO_TAGS_SELECTED);
// A contrived express handler
export async function renderSelectedTags(req, res) {
const tags = getSelectedTags(req.user.config);
if (tags === NO_TAGS_SELECTED) {
// take the user to a
return res.json({
error: "User needs to select tags",
code: "SELECT_TAGS_FIRST"
}).status(400);
}
const tagResponse = await myDB.getTags(tags);
res.json(tagResponse);
}
Get a property from object at path that
isPresent.
Returns object?
Get a boolean value from object at path.
// It'll booleanize a deeply-nested value
getBoolean({ foo: { bar: [] } }, "foo.bar") === false;
Returns boolean
Returns function?
Returns number?
Retrieve a present string from an object at path.
getPresentString({ foo: "\t" }, "foo", "default") === "default";
Returns string?
Extract an Array-typed value from object at path.
Unlike getPresentArray, the array can be blank.
Returns array?
Extract an Array-typed value from object at path.
If the value is blank, it will return defaultValue instead.
Returns array?
Some additional lower-level helper methods that get used elsewhere
Check if a provided value is a plain object with at least 1 key set.
value any isPresentObject({}) === false
isPresentObject({ foo: "bar" }) === true
isPresentObject([]) === false
isPresentObject(new Foo()) === false
isPresentObject(Object.create(null)) === false
Returns boolean
Test if a provided object is a blank, plain object.
value object isBlankObject({}) === true
isBlankObject({ foo: "bar" }) === false
isBlankObject([]) === false
isBlankObject(new Foo()) === false
isBlankObject(Object.create(null)) === false
Returns boolean
A duck-typing method to check if a property on object named name is a function.
object any an objectname string a function nameReturns boolean whether typeof object[name] === "function"
A duck-typing method to check if a property on object at the provided path is a function.
Similar to respondTo, but allows you to use an arbitrarily nested path.
object any an objectpath (string | array<number, string>) a path to a possible function à la lodash.getReturns boolean whether typeof get(object, path) === "function"
Some helpers for jest ship with this library that you can install into your test environment.
import { install as installRailsishMatchers } from "railsish/jest-matchers"
installRailsishMatchers(expect)
describe("some tests", () => {
it("returns a present response", () => {
expect(myLibrary.doSomething()).toBePresent();
});
it("returns something blank", () => {
expect(anonymousRequest.getCurrentUser()).toBeBlank();
});
it("implements foo", () => {
expect({ foo: () => "bar" }).toRespondTo("foo");
});
});
Install the associated matchers into your
jest environment to have presence, blankness, booleanization, and response helpers.
expect object jest’s global expect methodexpect.extend function the function that will accept the jest matchers// in a file called by "setupFilesAfterEnv":
import { install } from "railsish/jest-matchers"
install(expect);
Returns void
A collection of matchers for use with jest.
Type: object
received any something to check for presenceexpected expect(0).toBePresent();
expect([]).not.toBePresent();
expect(false).not.toBePresent();
expect("some string").toBePresent();
expect({}).not.toBePresent();
expect({ foo: "bar" }).toBePresent();
expect
Returns jestMatcherResult
received any something to check for blanknessexpected expect(0).not.toBeBlank();
expect([]).toBeBlank();
expect({}).toBeBlank();
expect(NaN).toBeBlank();
expect(Infinity).not.toBeBlank();
expect("\t\n\t").toBeBlank();
Returns jestMatcherResult
Test a value to see how it booleanizes.
received any something to booleanizeexpected boolean the value that booleanize should evaluate toexpect("some text").toBooleanizeAs(true);
expect([]).toBooleanizeAs(false);
Returns jestMatcherResult
A wrapper around matchers.toBooleanizeAs with expected set to false.
received any something to booleanizeexpected expect("some text").toBooleanizeTrue();
expect([]).not.toBooleanizeTrue();
Returns jestMatcherResult
A wrapper around matchers.toBooleanizeAs with expected set to false.
received any something to booleanizeexpected expect("some text").not.toBooleanizeFalse();
expect([]).toBooleanizeFalse();
Returns jestMatcherResult
received any something that might have a functionexpected string a function nameexpect(new Date()).toRespondTo("toISOString");
Returns jestMatcherResult
received any something that might have a functionexpected (string | Array<string>) a path to a functionexpect({ foo: { bar: { baz: () => "quux" } } }).toRespondToPath("foo.bar.baz");
Returns jestMatcherResult
An interface returned from a jest matcher.
FAQs
Rails-like blank and presence helpers, with related property access methods
We found that railsish demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.