├── .gitattribute ├── .gitignore ├── .travis.yml ├── package.json ├── license ├── index.js ├── test.js └── README.md /.gitattribute: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea/ 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | script: "npm test" 5 | after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls" -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deep-keys", 3 | "version": "0.5.0", 4 | "description": "Creates an array composed of the own enumerable property names(including nested) of an object.", 5 | "license": "MIT", 6 | "repository": "a8m/deep-keys", 7 | "author": { 8 | "name": "Ariel Mashraki", 9 | "email": "ariel@mashraki.co.il", 10 | "url": "https://github.com/a8m/deep-keys" 11 | }, 12 | "engines": { 13 | "node": ">=0.10.0" 14 | }, 15 | "scripts": { 16 | "test": "./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha -- -u exports test.js" 17 | }, 18 | "files": [ 19 | "index.js" 20 | ], 21 | "keywords": [ 22 | "map", 23 | "obj", 24 | "object", 25 | "key", 26 | "keys", 27 | "deep-keys", 28 | "nested-keys" 29 | ], 30 | "devDependencies": { 31 | "istanbul": "^0.3.2", 32 | "mocha": "^3.5.3" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Ariel Mashraki (github.com/a8m) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @description 5 | * returns {boolean} True if `value` is an `Object` but not `null` 6 | * @param value 7 | * @returns {boolean} 8 | */ 9 | function isObject(value) { 10 | return value !== null && typeof value === 'object' && !(value instanceof Date); 11 | } 12 | 13 | /** 14 | * @description 15 | * Determines if a reference is an `Array`. 16 | * @param {*} value Reference to check. 17 | * @returns {boolean} True if `value` is an `Array`. 18 | */ 19 | var isArray = Array.isArray; 20 | 21 | function deepKeys(obj, stack, parent, intermediate) { 22 | Object.keys(obj).forEach(function(el) { 23 | // Escape . in the element name 24 | var escaped = el.replace(/\./g, '\\\.'); 25 | // If it's a nested object 26 | if(isObject(obj[el]) && !isArray(obj[el])) { 27 | // Concatenate the new parent if exist 28 | var p = parent ? parent + '.' + escaped : parent; 29 | // Push intermediate parent key if flag is true 30 | if (intermediate) stack.push(parent ? p : escaped); 31 | deepKeys(obj[el], stack, p || escaped, intermediate); 32 | } else { 33 | // Create and save the key 34 | var key = parent ? parent + '.' + escaped : escaped; 35 | stack.push(key) 36 | } 37 | }); 38 | return stack 39 | } 40 | 41 | /** 42 | * @description 43 | * Get an object, and return an array composed of it's properties names(nested too). 44 | * With intermediate equals to true, we include also the intermediate parent keys into the result 45 | * @param obj {Object} 46 | * @param intermediate {Boolean} 47 | * @returns {Array} 48 | * @example 49 | * deepKeys({ a:1, b: { c:2, d: { e: 3 } } }) ==> ["a", "b.c", "b.d.e"] 50 | * @example 51 | * deepKeys({ b: { c:2, d: { e: 3 } } }, true) ==> ["b", "b.c", "b.d", "b.d.e"] 52 | * @example 53 | * deepKeys({ 'a.': { b: 1 }) ==> ["a\..b"] 54 | */ 55 | module.exports = function (obj, intermediate) { 56 | return deepKeys(obj, [], null, intermediate); 57 | }; 58 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var keys = require('./'); 5 | 6 | //o1, o2, msg 7 | var expectEqual = assert.deepEqual; 8 | 9 | describe('deep-keys', function() { 10 | 11 | it('should return array composed of it\'s properties names', function() { 12 | expectEqual(keys({ a:1, b:2, c:3, d:4 }), ['a', 'b', 'c', 'd']); 13 | expectEqual(keys({}), []); 14 | }); 15 | 16 | it('should return owned properties', function() { 17 | var obj = { 18 | a: { b: 1, c: 2 } 19 | }; 20 | expectEqual(keys(obj.a), ['b', 'c']); 21 | }); 22 | 23 | it('should return deep keys', function() { 24 | var obj1 = { 25 | a: 1, 26 | b: { c: 1 }, 27 | c: { d: { e: 1 }, f: 1 }, 28 | d: { e: { f: { g: 1, h: 2 } } }, 29 | e: 2, 30 | f: { g: [] } 31 | }; 32 | expectEqual(keys(obj1), ['a', 'b.c', 'c.d.e', 'c.f', 'd.e.f.g', 'd.e.f.h', 'e', 'f.g']); 33 | 34 | var obj2 = { 35 | type: 'customer', 36 | details: { 37 | name: 'Ariel', age: 26, address: { city: 'Tel Aviv', country: 'Israel' } 38 | }, 39 | isActive: true, 40 | createdAt: new Date() 41 | }; 42 | expectEqual(keys(obj2), [ 43 | 'type', 44 | 'details.name', 45 | 'details.age', 46 | 'details.address.city', 47 | 'details.address.country', 48 | 'isActive', 49 | 'createdAt' 50 | ]); 51 | }); 52 | 53 | it('should return deep keys including intermediate parent keys', function() { 54 | var obj1 = { 55 | a: 1, 56 | b: { c: 1 }, 57 | c: { d: { e: 1 }, f: 1 }, 58 | d: { e: { f: { g: 1, h: 2 } } }, 59 | e: 2, 60 | f: { g: [] } 61 | }; 62 | expectEqual(keys(obj1, true), ['a', 'b', 'b.c', 'c', 'c.d', 'c.d.e', 'c.f', 63 | 'd', 'd.e', 'd.e.f', 'd.e.f.g', 'd.e.f.h', 'e', 'f', 'f.g']); 64 | }); 65 | 66 | it('should escape . in key names', function() { 67 | var obj1 = { a: { '.b': 1 } }; 68 | expectEqual(keys(obj1), ['a.\\.b']); 69 | var obj2 = { 'a.': { b: 1 } }; 70 | expectEqual(keys(obj2, true), ['a\\.', 'a\\..b']); 71 | var obj3 = { a: { 'b.d': { c: 1 } } }; 72 | expectEqual(keys(obj3), ['a.b\\.d.c']); 73 | var obj4 = { a: { 'b.d': { c: 1 } } }; 74 | expectEqual(keys(obj4, true), ['a','a.b\\.d', 'a.b\\.d.c']); 75 | }); 76 | 77 | }); 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # deep-keys 2 | [![NPM version][npm-image]][npm-url] 3 | [![Build status][travis-image]][travis-url] 4 | [![Test coverage][coveralls-image]][coveralls-url] 5 | [![Dependency Status][david-image]][david-url] 6 | [![License][license-image]][license-url] 7 | [![Downloads][downloads-image]][downloads-url] 8 | 9 | > Creates an array composed of the own enumerable property names(including nested) of an object. 10 | 11 | **Note:** This kit works great with [obj-parse](https://github.com/a8m/obj-parse) _(get and set object properties in a fast and elegant way)._ 12 | 13 | ## Install 14 | 15 | ```sh 16 | $ npm install --save deep-keys 17 | ``` 18 | 19 | ## Usage 20 | ##### `deepKeys(obj, intermediate[optional])` 21 | ```js 22 | var deepKeys = require('deep-keys'); 23 | 24 | var obj1 = { 25 | a: 1, 26 | b: { c: 1 }, 27 | c: { d: { e: 1 }, f: 1 }, 28 | d: { e: { f: { g: 1, h: 2 } } }, 29 | e: 2, 30 | f: { g: [] } 31 | }; 32 | deepKeys(obj1); 33 | //=> ['a', 'b.c', 'c.d.e', 'c.f', 'd.e.f.g', 'd.e.f.h', 'e', 'f.g'] 34 | 35 | var obj2 = { 36 | type: 'customer', 37 | details: { 38 | name: 'Ariel', age: 26, address: { city: 'Tel Aviv', country: 'Israel' } 39 | }, 40 | isActive: true 41 | }; 42 | deepKeys(obj2); 43 | //=> ['type', 'details.name', 'details.age', 'details.address.city', 'details.address.country', 'isActive'] 44 | 45 | // intermediate example 46 | var obj3 = {a:{b:{c:1}}}; 47 | deepKeys(obj3); //=> [ 'a.b.c' ] 48 | deepKeys(obj3, true); //=> [ 'a', 'a.b', 'a.b.c' ] 49 | 50 | // Dots in key names get escaped 51 | var obj4 = { 'a.': { b: 1} }; 52 | deepKeys(obj4) //=> [ 'a\\..b' ] 53 | ``` 54 | 55 | 56 | ## License 57 | 58 | MIT © [Ariel Mashraki](https://github.com/a8m) 59 | 60 | [npm-image]: https://img.shields.io/npm/v/deep-keys.svg?style=flat-square 61 | [npm-url]: https://npmjs.org/package/deep-keys 62 | [travis-image]: https://img.shields.io/travis/a8m/deep-keys.svg?style=flat-square 63 | [travis-url]: https://travis-ci.org/a8m/deep-keys 64 | [coveralls-image]: https://img.shields.io/coveralls/a8m/deep-keys.svg?style=flat-square 65 | [coveralls-url]: https://coveralls.io/r/a8m/deep-keys 66 | [david-image]: http://img.shields.io/david/a8m/deep-keys.svg?style=flat-square 67 | [david-url]: https://david-dm.org/a8m/deep-keys 68 | [license-image]: http://img.shields.io/npm/l/deep-keys.svg?style=flat-square 69 | [license-url]: LICENSE 70 | [downloads-image]: http://img.shields.io/npm/dm/deep-keys.svg?style=flat-square 71 | [downloads-url]: https://npmjs.org/package/deep-keys 72 | 73 | --------------------------------------------------------------------------------