Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

core-functions

Package Overview
Dependencies
Maintainers
1
Versions
48
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

core-functions - npm Package Compare versions

Comparing version 2.0.7 to 2.0.8

2

package.json
{
"name": "core-functions",
"version": "2.0.7",
"version": "2.0.8",
"description": "Core functions, utilities and classes for working with Node/JavaScript primitives and built-in objects, including strings, booleans, Promises, base 64, Arrays, Objects, standard AppErrors, etc.",

@@ -5,0 +5,0 @@ "author": "Byron du Preez",

@@ -1,2 +0,2 @@

# core-functions v2.0.7
# core-functions v2.0.8

@@ -106,2 +106,10 @@ Core functions, utilities and classes for working with Node/JavaScript primitives and built-in objects, including

### 2.0.8
- Changed `strings.js` module's `stringify` function:
- To handle circular dependencies in objects and arrays
- To recursively stringify objects & their properties itself, instead of relying on `JSON.stringify`
- To add an optional `useToStringForErrors` argument to convert Errors using their `toString` methods (if true) or
as objects (if false), but with their `message` and `name` (but not `stack`) properties visible in the result
- To add an optional `quoteStrings` argument to return given string values surrounded with double-quotes (if true)
### 2.0.7

@@ -108,0 +116,0 @@ - Change to `objects.js`:

'use strict';
const Numbers = require('./numbers');
/**

@@ -80,16 +78,98 @@ * Module containing utilities for working with strings.

/**
* Returns the given value as a string with special case handling for string, String, undefined and special numbers
* (i.e. Infinity, -Infinity and NaN), because string & String are already strings and {@linkcode JSON#stringify}
* converts: Infinity, -Infinity and NaN to 'null'; an Error to '{}'; and undefined to undefined (not 'undefined').
* Returns the given value as a string with special case handling for undefined, null, strings, numbers, booleans,
* Strings, Numbers, Booleans, Errors, Functions, Arrays, Objects and special numbers (i.e. Infinity, -Infinity and NaN)
* and also handles circular dependencies. Similar to {@linkcode JSON#stringify}, but shows more about the given value
* than JSON.stringify does, for example:
* - JSON.stringify(undefined) returns undefined, but this returns 'undefined'
* - JSON.stringify({a:undefined}) returns {}, but this returns '{"a":undefined}'
* - JSON.stringify(new Error("Boom")) returns '{}', but this returns either '{"message":"Boom","name":"Error"}' (if
* useToStringForErrors is false) or '[Error: Boom]' (if useToStringForErrors is true)
* - JSON.stringify(func) with function func() {} returns undefined, but this returns '[Function: func]'
* - JSON.stringify({fn: func}) with function func() {} returns '{}', but this returns '{"fn": [Function: func]}'
* - JSON.stringify(NaN) returns 'null', but this returns 'NaN'
* - JSON.stringify(Infinity) returns 'null', but this returns 'Infinity'
* - JSON.stringify(-Infinity) returns 'null', but this returns '-Infinity'
* - JSON.stringify applied to objects or arrays with circular dependencies throws an error (TypeError: Converting
* circular structure to JSON), but this returns a string with circular dependencies replaced with [Circular: {name}],
* where name refers to the original object that it references (using 'this' for the outermost object itself).
* For example, given the following code:
* const object = {a: 1, o: {b:2}};
* object.circular = object;
* object.o.oAgain = object.o;
* this function returns '{"a":1,"o":{"b":2,"oAgain":[Circular: this.o]},"circular":[Circular: this]}'
*
* @param {*} value the value to stringify
* @param {boolean|undefined} [useToStringForErrors] - whether to stringify errors using toString or as normal objects (default)
* @param {boolean|undefined} [quoteStrings] - whether to surround simple string values with double-quotes or not (default)
* @returns {string} the value as a string
*/
function stringify(value) {
return value === undefined ? `${value}` :
typeof value === 'string' ? value :
value instanceof String ? value.valueOf() :
Numbers.isSpecialNumber(value) || value instanceof Error ? `${value}` :
typeof value === 'function' ? isNotBlank(value.name) ? `[Function: ${value.name}]` : '[Function: anonymous]' :
Array.isArray(value) ? `[${value.map(stringify).join(", ")}]` :
JSON.stringify(value);
function stringify(value, useToStringForErrors, quoteStrings) {
const history = new WeakMap();
function stringifyWithHistory(value, name, quoteStrings) {
// Special cases for undefined and null
if (value === undefined) return 'undefined';
if (value === null) return 'null';
const typeOfValue = typeof value;
// Special cases for strings and Strings
if (typeOfValue === 'string') return quoteStrings ? `"${value}"` : value;
if (value instanceof String) return quoteStrings ? `"${value.valueOf()}"` : value.valueOf();
// Special cases for numbers and Numbers (and special numbers)
//if (typeOfValue === 'number' || value instanceof Number || Numbers.isSpecialNumber(value)) return `${value}`;
if (typeOfValue === 'number' || value instanceof Number) return `${value}`;
// Special cases for booleans and Booleans
if (typeOfValue === 'boolean' || value instanceof Boolean) return `${value}`;
// Special case for Errors - use toString() if directed, since stringify on most errors, just returns "{}"
const valueIsError = value instanceof Error;
if (valueIsError && useToStringForErrors) return `${value}`;
// Special case for Functions - show thm as [Function: {function name}]
if (typeOfValue === 'function') return isNotBlank(value.name) ? `[Function: ${value.name}]` : '[Function: anonymous]';
if (typeOfValue === 'object') {
if (history.has(value)) {
// Special case for circular values - show thm as [Circular: {property name}]
return `[Circular: ${history.get(value)}]`;
}
history.set(value, name);
// Special case for Array objects, stringify each of its elements
if (Array.isArray(value)) {
return `[${value.map((e, i) => stringifyWithHistory(e, `${name}[${i}]`, quoteStrings)).join(", ")}]`;
}
// Stringify the object
let names = Object.getOwnPropertyNames(value);
if (valueIsError) {
// Special case for Error objects - include message and name (if any), but exclude stack, which are all normally hidden with JSON.stringify
names = names.filter(n => n !== 'stack');
if (value.name) {
names.push('name');
}
}
let result = '{';
for (let i = 0; i < names.length; ++i) {
const propertyName = names[i];
const propertyValue = value[propertyName];
if (i > 0) {
result += ',';
}
result += `"${propertyName}":${stringifyWithHistory(propertyValue, `${name}.${propertyName}`, true)}`
}
result += '}';
return result;
}
// If anything else use JSON.stringify on it
return JSON.stringify(value);
}
return stringifyWithHistory(value, 'this', quoteStrings);
}

@@ -96,0 +176,0 @@

{
"name": "core-functions-tests",
"version": "2.0.7",
"version": "2.0.8",
"author": "Byron du Preez",

@@ -5,0 +5,0 @@ "license": "Apache-2.0",

@@ -245,2 +245,5 @@ 'use strict';

}
function checkWithArgs(value, errorsAsObjects, quoteStrings, expected) {
return checkEqual(t, Strings.stringify, [wrap(value, wrapInString), errorsAsObjects, quoteStrings], expected, toPrefix(value, wrapInString));
}

@@ -255,3 +258,4 @@ // undefined

check({}, wrapInString ? '[object Object]' : '{}');
check({a: 1, b: 2}, wrapInString ? '[object Object]' : `${JSON.stringify({a: 1, b: 2})}`);
check({a: 1, b: 2}, wrapInString ? '[object Object]' : JSON.stringify({a: 1, b: 2}));
check({a: 1, b: 2, o: {c: 'C'}}, wrapInString ? '[object Object]' : JSON.stringify({a: 1, b: 2, o: {c: 'C'}}));

@@ -315,2 +319,80 @@ // booleans

check('ABC', 'ABC');
checkWithArgs('ABC', false, true, '"ABC"');
// errors
check(new Error('Planned error'), wrapInString ? 'Error: Planned error' : '{"message":"Planned error","name":"Error"}');
checkWithArgs(new Error('Planned error'), true, false, wrapInString ? 'Error: Planned error' : 'Error: Planned error');
// circular objects
const circular0 = {a: 1, o: {b:2}};
circular0.circular = circular0;
circular0.o.oAgain = circular0.o;
check(circular0, wrapInString ? '[object Object]' : '{"a":1,"o":{"b":2,"oAgain":[Circular: this.o]},"circular":[Circular: this]}');
const circular1 = {a: 1, b: 2, o: {c: 'C', p: {d: 'D'}}};
circular1.thisAgain = circular1;
circular1.o.thisAgain = circular1;
circular1.o.p.thisAgain = circular1;
circular1.oAgain = circular1.o;
circular1.o.oAgain = circular1.o;
circular1.o.p.oAgain = circular1.o;
circular1.pAgain = circular1.o.p;
circular1.o.pAgain = circular1.o.p;
circular1.o.p.pAgain = circular1.o.p;
check(circular1, wrapInString ? '[object Object]' : '{"a":1,"b":2,"o":{"c":"C","p":{"d":"D","thisAgain":[Circular: this],"oAgain":[Circular: this.o],"pAgain":[Circular: this.o.p]},"thisAgain":[Circular: this],"oAgain":[Circular: this.o],"pAgain":[Circular: this.o.p]},"thisAgain":[Circular: this],"oAgain":[Circular: this.o],"pAgain":[Circular: this.o.p]}');
// circular arrays with circular objects
const array2 = ['a', {}, 123];
const circular2 = array2[1];
circular2.thisAgain = array2;
circular2.this1Again = circular2;
array2.push(array2);
check(array2, wrapInString ? 'a,[object Object],123,' : '[a, {"thisAgain":[Circular: this],"this1Again":[Circular: this[1]]}, 123, [Circular: this]]');
const array3 = ['x', {y:'Y'}, 123];
const circular3 = array3[1];
circular3.thisAgain = circular3;
circular3.arrayAgain = array3;
array3.push(array3);
check(circular3, wrapInString ? '[object Object]' : '{"y":"Y","thisAgain":[Circular: this],"arrayAgain":["x", [Circular: this], 123, [Circular: this.arrayAgain]]}');
// circular objects with circular arrays
const array4 = ['b', {z: "Z"}, 456];
const circular4 = {a: 'A', array: array4};
circular4.thisAgain = circular4;
circular4.arrayAgain = circular4.array;
array4[1].thisAgain = circular4;
array4[1].arrayAgain = circular4.array;
array4.push(array4);
check(circular4, wrapInString ? '[object Object]' : '{"a":"A","array":["b", {"z":"Z","thisAgain":[Circular: this],"arrayAgain":[Circular: this.array]}, 456, [Circular: this.array]],"thisAgain":[Circular: this],"arrayAgain":[Circular: this.array]}');
const array5 = ['c', {x: "X"}, 789];
const circular5 = {a: 'A', array: array5};
array5[1].thisAgain = array5;
array5[1].this1Again = array5[1];
array5[1].circular5 = circular5;
circular5.thisAgain = array5;
circular5.this1Again = array5[1];
circular5.this1Circular5Again = circular5;
circular5.this1Circular5ArrayAgain = circular5.array;
array5.push(array5);
check(array5, wrapInString ? 'c,[object Object],789,' : '[c, {"x":"X","thisAgain":[Circular: this],"this1Again":[Circular: this[1]],"circular5":{"a":"A","array":[Circular: this],"thisAgain":[Circular: this],"this1Again":[Circular: this[1]],"this1Circular5Again":[Circular: this[1].circular5],"this1Circular5ArrayAgain":[Circular: this]}}, 789, [Circular: this]]');
// Functions
function func() {}
check(func, wrapInString ? 'function func() {}' : '[Function: func]');
check({fn:func}, wrapInString ? '[object Object]' : '{"fn":[Function: func]}');
// undefined object properties
check({a:undefined}, wrapInString ? '[object Object]' : '{"a":undefined}');
}

@@ -317,0 +399,0 @@

@@ -68,5 +68,5 @@ 'use strict';

if (expected) {
t.ok(actual, `${toPrefix(prefix)}${stringify(actual)} ${okSuffix}`);
t.ok(actual, `${toPrefix(prefix)} ${okSuffix}`);
} else {
t.notOk(actual, `${toPrefix(prefix)}${stringify(actual)} ${notOkSuffix}`);
t.notOk(actual, `${toPrefix(prefix)} ${notOkSuffix}`);
}

@@ -73,0 +73,0 @@ }

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc