Skip to content

Commit

Permalink
Refactor with TypeScript
Browse files Browse the repository at this point in the history
  • Loading branch information
mcmath committed Jun 15, 2016
1 parent 936d281 commit 154c9fb
Show file tree
Hide file tree
Showing 16 changed files with 385 additions and 230 deletions.
5 changes: 0 additions & 5 deletions .eslintrc.yml

This file was deleted.

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/coverage/
/lib/
/node_modules/
/typings/
/npm-debug.log
7 changes: 5 additions & 2 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/coverage/
/test/
/typings/
/src/
/lib/*.test.*
/.editorconfig
/.eslintrc.yml
/.gitignore
/.travis.yml
/tsconfig.json
/tslint.json
8 changes: 7 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ node_js:
- "4"
- "0.12"
- "0.10"
before_script:
- npm run ci:typings
after_success:
- npm run coveralls
- npm run ci:coveralls
before_deploy:
- npm run build
deploy:
provider: npm
email:
Expand All @@ -17,3 +21,5 @@ deploy:
repo: akim-mcmath/deep-map-keys
node: "4"
tags: true
after_deploy:
- npm run build:remove
107 changes: 70 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
# deep-map-keys
# Deep Map Keys

[![Version][version-badge]][npm]
[![License][license-badge]][license]
[![Build][build-badge]][travis]
[![Coverage][coverage-badge]][coveralls]
[![Dependencies][dependencies-badge]][gemnasium]

Recurses through a JSON-like object and transforms its keys, returning a new object.
**Deep Map Keys** recurses through an object and transforms its keys – and
the keys of any nested objects – according to some function.

## Install

Install via [npm][npm].
Install Deep Map Keys via [npm][npm].

```sh
npm install --save deep-map-keys
Expand Down Expand Up @@ -38,8 +39,11 @@ let comment = {
let result = deepMapKeys(comment, key => {
return key.replace(/_(\w)/g, (match, char) => char.toUpperCase());
});
```

And the result will look like this:

console.log(result); /*
```js
{
commentId: 42,
userId: 1024,
Expand All @@ -49,46 +53,75 @@ console.log(result); /*
{ userId: 3820, userName: 'Rafiki' },
{ userId: 8391, userName: 'Zazu' }
]
};
*/
}
```

## API

### `deepMapKeys(object, transformFn, [options])`

Applies `transformFn` to each key in an object. Keys are visited recursively,
so nested keys will be transformed. A new object is always returned; the
original object is unmodified.

##### object

`object`

The object whose keys are to be transformed. This object may be an `Array`.

##### transformFn

`function`

The function to call for each key. The return value of the function
determines the transformed value. The function is called with a single
argument:

* **key**: The key being transformed.

##### options

`object` (optional)

An options object. The following options are accepted:

* **thisArg**: Sets the value of `this` within `transformFn`.
#### `deepMapKeys(object, mapFn, [options])`

#### Parameters

<table>
<thead>
<tr>
<th align="left">Param</th>
<th align="left">Type</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>object</td>
<td><code>any</code></td>
<td>
The object whose keys are to be transformed. Typically, this will be
a complex object containing other nested objects. This object may be an
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array">
<code>Array</code></a>, in which case the keys of any objects it
contains will be transformed.
</td>
</tr>
<tr>
<td>mapFn</td>
<td><code>function</code></td>
<td>
The function used to transform each key. The function is
called with two arguments:
<ul>
<li>
<strong>key</strong> &lt;<code>string</code>&gt;
The key being transformed
</li>
<li>
<strong>value</strong> &lt;<code>any</code>&gt;
The value of the node whose key is being transformed
</li>
</ul>
The return value determines the new name of the key, and must therefore
be a string.
</td>
</tr>
<tr>
<td>[options]</td>
<td><code>object</code></td>
<td>
An optional options object. The following option is accepted:
<ul>
<li>
<strong>thisArg</strong> &lt;<code>any = undefined</code>&gt;
Sets the value of
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this"><code>this</code></a>
within <code>mapFn()</code>
</li>
</ul>
</td>
</tr>
</tbody>
</table>

#### Returns

`object`

Returns a new object.

## License
Expand Down
64 changes: 4 additions & 60 deletions lib/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 20 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
{
"name": "deep-map-keys",
"version": "1.0.0",
"description": "Transforms keys of a JSON-like object",
"description": "Transforms nested keys of complex objects",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
"scripts": {
"test:lint": "eslint lib",
"test:unit": "istanbul cover _mocha",
"build:compile": "tsc",
"build:remove": "rimraf lib",
"build": "npm run build:remove && npm run build:compile",
"test:lint": "tslint 'src/**/*.ts'",
"test:unit": "istanbul cover -e .ts -x '*.test.ts' _mocha -- 'src/**/*.test.ts' --compilers ts:ts-node/register",
"test:report": "npm test && open coverage/lcov-report/index.html",
"test": "npm run test:lint && npm run test:unit",
"coveralls": "cat coverage/lcov.info | coveralls"
"ci:typings": "typings install",
"ci:coveralls": "cat coverage/lcov.info | coveralls"
},
"engines": {
"node": ">=0.10"
Expand All @@ -20,19 +26,24 @@
"nested",
"object",
"array",
"json"
"json",
"typescript",
"typings"
],
"author": "Akim McMath <[email protected]>",
"license": "MIT",
"devDependencies": {
"chai": "^3.5.0",
"coffee-script": "^1.10.0",
"coveralls": "^2.11.9",
"eslint": "^2.12.0",
"istanbul": "^0.4.3",
"istanbul": "1.0.0-alpha.2",
"mocha": "^2.5.3",
"rimraf": "^2.5.2",
"sinon": "^1.17.4",
"sinon-chai": "^2.8.0"
"sinon-chai": "^2.8.0",
"ts-node": "^0.9.1",
"tslint": "^3.11.0",
"typescript": "^1.8.10",
"typings": "^1.1.0"
},
"dependencies": {},
"repository": {
Expand Down
51 changes: 51 additions & 0 deletions src/deep-map-keys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import {isArray, isFunction, isObject, isVoid} from './lang';

export interface MapFn {
(key: string, value: any): string;
}

export interface Options {
thisArg?: any;
}

export function deepMapKeys<T>(object: any, mapFn: MapFn, options?: Options): T {
options = isVoid(options) ? {} : options;

if (!mapFn) {
throw new Error('mapFn is required');
} else if (!isFunction(mapFn)) {
throw new TypeError('mapFn must be a function');
} else if (!isObject(options)) {
throw new TypeError('options must be an object');
}

return map(object, mapFn, options);
}

function map(value: any, fn: MapFn, opts: Options): any {
return isArray(value) ? mapArray(value, fn, opts) :
isObject(value) ? mapObject(value, fn, opts) :
value;
}

function mapArray(arr: any[], fn: MapFn, opts: Options): any[] {
let result: any[] = [];
let len = arr.length;

for (let i = 0; i < len; i++) {
result.push(map(arr[i], fn, opts));
}

return result;
}

function mapObject(obj: {[key: string]: any}, fn: MapFn, opts: Options): {[key: string]: any} {
let result: {[key: string]: any} = {};

for (let key in obj) {
let value = obj[key];
result[fn.call(opts.thisArg, key, value)] = map(value, fn, opts);
}

return result;
}
Loading

0 comments on commit 154c9fb

Please sign in to comment.