Skip to content

Commit

Permalink
feat: value/ensure
Browse files Browse the repository at this point in the history
Comming with common ensure utils
  • Loading branch information
medikoo committed Mar 25, 2019
1 parent b25c71f commit dd6d8cb
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 0 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,24 @@ _Value_ is assumed to be any JavaScript value that's neither `null` nor `undefin

##### `value/is`

Confirms whether passed argument is a _value_

```javascript
const isValue = require("type/value/is");

isValue({}); // true
isValue(null); // false
```

##### `value/ensure`

Ensures if given argument is a _value_. If it's a value it is returned back, if not `TypeError` is thrown

```javascript
const ensureValue = require("type/value/ensure");

const obj = {};

ensureValue(obj); // obj
ensureValue(null); // Thrown TypeError: Cannot use null
```
18 changes: 18 additions & 0 deletions lib/resolve-exception.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"use strict";

var isValue = require("../value/is")
, isObject = require("../object/is")
, stringCoerce = require("../string/coerce")
, toShortString = require("./to-short-string");

var resolveMessage = function (message, value) {
return message.replace("%v", toShortString(value));
};

module.exports = function (value, defaultMessage, inputOptions) {
if (!isObject(inputOptions)) throw new TypeError(resolveMessage(defaultMessage, value));
if (inputOptions.isOptional && !isValue(value)) return null;
var errorMessage = stringCoerce(inputOptions.errorMessage);
if (!isValue(errorMessage)) errorMessage = defaultMessage;
throw new TypeError(resolveMessage(errorMessage, value));
};
10 changes: 10 additions & 0 deletions lib/safe-to-string.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"use strict";

module.exports = function (value) {
try {
return value.toString();
} catch (error) {
try { return String(value); }
catch (error2) { return null; }
}
};
28 changes: 28 additions & 0 deletions lib/to-short-string.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"use strict";

var safeToString = require("./safe-to-string");

var reNewLine = /[\n\r\u2028\u2029]/g;

module.exports = function (value) {
var string = safeToString(value);
if (string === null) return "<Non-coercible to string value>";
// Trim if too long
if (string.length > 100) string = string.slice(0, 99) + "…";
// Replace eventual new lines
string = string.replace(reNewLine, function (char) {
switch (char) {
case "\n":
return "\\n";
case "\r":
return "\\r";
case "\u2028":
return "\\u2028";
case "\u2029":
return "\\u2029";
default:
throw new Error("Unexpected character");
}
});
return string;
};
35 changes: 35 additions & 0 deletions test/lib/resolve-exception.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"use strict";

var assert = require("chai").assert
, handleException = require("../../lib/resolve-exception");

describe("lib/handle-exception", function () {
it("Should throw TypeError", function () {
try {
handleException(12, "Invalid value");
throw new Error("Unexpected");
} catch (error) {
assert.equal(error.name, "TypeError");
assert.equal(error.message, "Invalid value");
}
});
it("Should resolve value in default message", function () {
try {
handleException(12, "%v is invalid");
throw new Error("Unexpected");
} catch (error) {
assert.equal(error.message, "12 is invalid");
}
});
it("Should support optional values via inputOptions.isOptional", function () {
assert.equal(handleException(null, "%v is invalid", { isOptional: true }));
});
it("Should support custome error message via inputOptions.errorMessage", function () {
try {
handleException(12, "%v is invalid", { errorMessage: "%v is not supported age" });
throw new Error("Unexpected");
} catch (error) {
assert.equal(error.message, "12 is not supported age");
}
});
});
32 changes: 32 additions & 0 deletions test/lib/safe-to-string.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"use strict";

var assert = require("chai").assert
, safeToString = require("../../lib/safe-to-string");

describe("lib/safe-to-string", function () {
it("Should return input string", function () { assert.equal(safeToString("foo"), "foo"); });
it("Should coerce numbers", function () { assert.equal(safeToString(12), "12"); });
it("Should coerce booleans", function () { assert.equal(safeToString(true), "true"); });
it("Should coerce string objects", function () {
assert.equal(safeToString(new String("bar")), "bar");
});
it("Should coerce objects", function () {
assert.equal(
safeToString({ toString: function () { return "Some object"; } }), "Some object"
);
});
it("Should coerce null", function () { assert.equal(safeToString(null), "null"); });
it("Should coerce undefined", function () {
assert.equal(safeToString(undefined), "undefined");
});

if (typeof Symbol === "function") {
it("Should coerce symbols", function () {
// eslint-disable-next-line no-undef
assert.equal(safeToString(Symbol()), "Symbol()");
});
}
it("Should return null for non coercible values", function () {
assert.equal(safeToString({ toString: null }), null);
});
});
41 changes: 41 additions & 0 deletions test/lib/to-short-string.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"use strict";

var assert = require("chai").assert
, toShortString = require("../../lib/to-short-string");

describe("lib/to-short-string", function () {
it("Should return input string", function () { assert.equal(toShortString("foo"), "foo"); });
it("Should coerce numbers", function () { assert.equal(toShortString(12), "12"); });
it("Should coerce booleans", function () { assert.equal(toShortString(true), "true"); });
it("Should coerce string objects", function () {
assert.equal(toShortString(new String("bar")), "bar");
});
it("Should coerce objects", function () {
assert.equal(
toShortString({ toString: function () { return "Some object"; } }), "Some object"
);
});
it("Should coerce null", function () { assert.equal(toShortString(null), "null"); });
it("Should coerce undefined", function () {
assert.equal(toShortString(undefined), "undefined");
});

if (typeof Symbol === "function") {
it("Should coerce symbols", function () {
// eslint-disable-next-line no-undef
assert.equal(toShortString(Symbol()), "Symbol()");
});
}
it("Should return replacement non coercible values", function () {
assert.equal(toShortString({ toString: null }), "<Non-coercible to string value>");
});

it("Should replace new line characters", function () {
assert.equal(toShortString("foo\n\rbar"), "foo\\n\\rbar");
});
it("Should truncate long string", function () {
var str = Math.random().toString(36);
while (str.length < 200) str += str;
assert.equal(toShortString(str).length, 100);
});
});
20 changes: 20 additions & 0 deletions test/value/ensure.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"use strict";

var assert = require("chai").assert
, ensureValue = require("../../value/ensure");

describe("value/ensure", function () {
it("Should return input value", function () {
var value = {};
assert.equal(ensureValue(value), value);
});
it("Should crash on no value", function () {
try {
ensureValue(null);
throw new Error("Unexpected");
} catch (error) {
assert.equal(error.name, "TypeError");
assert.equal(error.message, "Cannot use null");
}
});
});
9 changes: 9 additions & 0 deletions value/ensure.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"use strict";

var resolveException = require("../lib/resolve-exception")
, is = require("./is");

module.exports = function (value/*, options*/) {
if (is(value)) return value;
return resolveException(value, "Cannot use %v", arguments[1]);
};

0 comments on commit dd6d8cb

Please sign in to comment.