Skip to content

Commit da80130

Browse files
committed
Skip undefined properties option, tidy array out
1 parent d8d35cb commit da80130

File tree

3 files changed

+80
-57
lines changed

3 files changed

+80
-57
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ The `options` object allows some additional configuration:
4747
* **maxDepth** _(number, default: 100)_ The maximum depth of values to stringify
4848
* **maxValues** _(number, default: 100000)_ The maximum number of values to stringify
4949
* **references** _(boolean, default: false)_ Restore circular/repeated references in the object (uses IIFE)
50+
* **skipUndefinedProperties** _(boolean, default: false)_ Omits `undefined` properties instead of restoring as `undefined`
5051

5152
### Examples
5253

javascript-stringify.js

Lines changed: 69 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393
/**
9494
* Serialize the path to a string.
9595
*
96-
* @param {Array} path
96+
* @param {Array} path
9797
* @return {string}
9898
*/
9999
function toPath (path) {
@@ -111,59 +111,75 @@
111111
}
112112

113113
/**
114-
* Convert JavaScript objects into strings.
114+
* Stringify an array of values.
115+
*
116+
* @param {Array} array
117+
* @param {string} indent
118+
* @param {Function} next
119+
* @return {string}
115120
*/
116-
var OBJECT_TYPES = {
117-
'[object Array]': function (array, indent, next) {
118-
// Map array values to their stringified values with correct indentation.
119-
var values = array.map(function (value, index) {
120-
var str = next(value, index);
121+
function stringifyArray (array, indent, next) {
122+
// Map array values to their stringified values with correct indentation.
123+
var values = array.map(function (value, index) {
124+
var str = next(value, index);
121125

122-
if (str === undefined) {
123-
return String(str)
124-
}
126+
if (str === undefined) {
127+
return String(str);
128+
}
125129

126-
return indent + str.split('\n').join('\n' + indent);
127-
}).join(indent ? ',\n' : ',');
130+
return indent + str.split('\n').join('\n' + indent);
131+
}).join(indent ? ',\n' : ',');
128132

129-
// Wrap the array in newlines if we have indentation set.
130-
if (indent && values) {
131-
return '[\n' + values + '\n]';
132-
}
133+
// Wrap the array in newlines if we have indentation set.
134+
if (indent && values) {
135+
return '[\n' + values + '\n]';
136+
}
133137

134-
return '[' + values + ']';
135-
},
136-
'[object Object]': function (object, indent, next) {
137-
if (typeof Buffer === 'function' && Buffer.isBuffer(object)) {
138-
return 'new Buffer(' + stringify(object.toString()) + ')';
139-
}
138+
return '[' + values + ']';
139+
}
140140

141-
// Iterate over object keys and concat string together.
142-
var values = Object.keys(object).reduce(function (values, key) {
143-
var value = next(object[key], key);
141+
/**
142+
* Stringify a map of values.
143+
*
144+
* @param {Object} object
145+
* @param {string} indent
146+
* @param {Function} next
147+
* @return {string}
148+
*/
149+
function stringifyObject (object, indent, next) {
150+
// Iterate over object keys and concat string together.
151+
var values = Object.keys(object).reduce(function (values, key) {
152+
var value = next(object[key], key);
144153

145-
// Omit `undefined` object values.
146-
if (value === undefined) {
147-
return values;
148-
}
154+
// Omit `undefined` object values.
155+
if (value === undefined) {
156+
return values;
157+
}
149158

150-
// String format the key and value data.
151-
key = isValidVariableName(key) ? key : stringify(key);
152-
value = String(value).split('\n').join('\n' + indent);
159+
// String format the key and value data.
160+
key = isValidVariableName(key) ? key : stringify(key);
161+
value = String(value).split('\n').join('\n' + indent);
153162

154-
// Push the current object key and value into the values array.
155-
values.push(indent + key + ':' + (indent ? ' ' : '') + value);
163+
// Push the current object key and value into the values array.
164+
values.push(indent + key + ':' + (indent ? ' ' : '') + value);
156165

157-
return values;
158-
}, []).join(indent ? ',\n' : ',');
166+
return values;
167+
}, []).join(indent ? ',\n' : ',');
159168

160-
// Wrap the object in newlines if we have indentation set.
161-
if (indent && values) {
162-
return '{\n' + values + '\n}';
163-
}
169+
// Wrap the object in newlines if we have indentation set.
170+
if (indent && values) {
171+
return '{\n' + values + '\n}';
172+
}
164173

165-
return '{' + values + '}';
166-
},
174+
return '{' + values + '}';
175+
}
176+
177+
/**
178+
* Convert JavaScript objects into strings.
179+
*/
180+
var OBJECT_TYPES = {
181+
'[object Array]': stringifyArray,
182+
'[object Object]': stringifyObject,
167183
'[object Date]': function (date) {
168184
return 'new Date(' + date.getTime() + ')';
169185
},
@@ -177,21 +193,7 @@
177193
return 'new Boolean(' + boolean + ')';
178194
},
179195
'[object Uint8Array]': function (array, indent) {
180-
if (typeof Buffer === 'function' && Buffer.isBuffer(array)) {
181-
return 'new Buffer(' + stringify(array.toString()) + ')';
182-
}
183-
184-
if (indent) {
185-
var str = '';
186-
187-
for (var i = 0; i < array.length; i++) {
188-
str += indent + array[i] + ',\n'
189-
}
190-
191-
return 'new Uint8Array([\n' + str + '\n])'
192-
}
193-
194-
return 'new Uint8Array([' + array.join(indent ? ',\n' : ',') + '])'
196+
return 'new Uint8Array(' + stringifyArray(array) + ')';
195197
},
196198
'[object RegExp]': String,
197199
'[object Function]': String,
@@ -227,6 +229,11 @@
227229
return PRIMITIVE_TYPES[typeof value](value, indent, next);
228230
}
229231

232+
// Handle buffer objects before recursing (node < 6 was an object, node >= 6 is a `Uint8Array`).
233+
if (typeof Buffer === 'function' && Buffer.isBuffer(value)) {
234+
return 'new Buffer(' + next(value.toString()) + ')';
235+
}
236+
230237
// Use the internal object string to select stringification method.
231238
var toString = OBJECT_TYPES[Object.prototype.toString.call(value)];
232239

@@ -253,6 +260,7 @@
253260

254261
var maxDepth = Number(options.maxDepth) || 100;
255262
var references = !!options.references;
263+
var skipUndefinedProperties = !!options.skipUndefinedProperties;
256264
var valueCount = Number(options.maxValues) || 100000;
257265

258266
var path = [];
@@ -269,6 +277,10 @@
269277
* @return {string}
270278
*/
271279
function next (value, key) {
280+
if (skipUndefinedProperties && value === undefined) {
281+
return undefined;
282+
}
283+
272284
path.push(key);
273285
var result = recurse(value, stringify);
274286
path.pop();

test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ describe('javascript-stringify', function () {
5757
'should stringify as object shorthand',
5858
test({ key: 'value', '-': 10 }, "{key:'value','-':10}")
5959
);
60+
61+
it(
62+
'should stringify undefined keys',
63+
test({ a: true, b: undefined }, "{a:true,b:undefined}")
64+
);
65+
66+
it(
67+
'should stringify omit undefined keys',
68+
test({ a: true, b: undefined }, "{a:true}", null, { skipUndefinedProperties: true })
69+
);
6070
});
6171

6272
describe('native instances', function () {

0 commit comments

Comments
 (0)