Skip to content

Commit

Permalink
Merge 60f1863 into 8c23a8b
Browse files Browse the repository at this point in the history
  • Loading branch information
taras committed Aug 14, 2017
2 parents 8c23a8b + 60f1863 commit f2a2150
Show file tree
Hide file tree
Showing 20 changed files with 501 additions and 741 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
language: node_js

node_js:
- "8"
- "7"
- "6.2"
- "6.3"
- "6.4"
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

<a name="0.1.1"></a>
## [0.1.1](https://github.com/DxCx/ts-library-starter/compare/v0.1.0...v0.1.1) (2017-08-13)



<a name="0.1.0"></a>
# [0.1.0](https://github.com/DxCx/ts-library-starter/compare/v0.0.6...v0.1.0) (2016-09-19)

Expand Down
662 changes: 5 additions & 657 deletions LICENSE

Large diffs are not rendered by default.

139 changes: 87 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,54 +1,89 @@
# ts-library-starter
[![NPM version](https://img.shields.io/npm/v/ts-library-starter.svg)](https://www.npmjs.com/package/ts-library-starter)
[![Build Status](https://travis-ci.org/DxCx/ts-library-starter.svg?branch=master)](https://travis-ci.org/DxCx/ts-library-starter)
[![Coverage Status](https://coveralls.io/repos/github/DxCx/ts-library-starter/badge.svg?branch=master)](https://coveralls.io/github/DxCx/ts-library-starter?branch=master)
# ioo - Immutable Object Operators
[![NPM version](https://img.shields.io/npm/v/ioo.svg)](https://www.npmjs.com/package/ioo)
[![Build Status](https://travis-ci.org/this-dot/ioo.svg?branch=master)](https://travis-ci.org/this-dot/ioo)
[![Coverage Status](https://coveralls.io/repos/github/this-dot/ioo/badge.svg?branch=master)](https://coveralls.io/github/this-dot/ioo?branch=master)
[![Standard Version](https://img.shields.io/badge/release-standard%20version-brightgreen.svg)](https://github.com/conventional-changelog/standard-version)

Example git project that is used for typescript libraries as a starter pack

What does it include:
----
1. exported class as example for an npm moudle
2. packaging for npm modules (webpack + tslint + awesome-typescript-loader + dts-bundle)
3. testings for npm modules (jest)
4. code coverage (jest) when running tests
5. Typescript => ES6 => ES5 (babel)
6. Two versions embed in the package, one for node, one for browser (browserify)

Notes
----
Please note that you will need to rename the library name in some files:

1. webpack.config.js (bundle_opts)
2. package.json (ofcourse ;))
Also don't forget to reset package version ;)

Useful commands:
----
npm run prebuild - install NPM dependancies
npm run build - build the library files
npm run test - run the tests
npm run test:watch - run the tests (watch-mode)
npm run coverage - run the tests with coverage
npm run coverage:watch - run the tests with coverage (watch-mode)
npm run pack - build the library, make sure the tests passes, and then pack the library (creates .tgz)
npm run release - prepare package for next release

Files explained:
----
1. src - directory is used for typescript code that is part of the project
1a. src/Example.ts - Just an example exported library, used to should import in tests.
1b. src/Example.spec.ts - tests for the example class
1c. src/index.ts - index, which functionality is exported from the library
1d. src/main.ts - just wrapper for index
3. package.json - file is used to describe the library
4. tsconfig.json - configuration file for the library compilation
6. tslint.json - configuration file for the linter (both test and library)
8. webpack.config.js - configuration file of the compilation automation process for the library

Output files explained:
----
1. node_modules - directory npm creates with all the dependencies of the module (result of npm install)
2. dist - directory contains the compiled library (javascript + typings)
3. <module_name>-<module_version>.tgz - final tgz file for publish. (result of npm run pack)
4. coverage - code coverage report output made by istanbul
# Installation

```sh
npm install --save ioo
```

# Operations

## mapObject(object, ( key: string, value: any ) => any): {}

Iterate over keys of the object and invoke the callback for every key, passing the key and value on that key. The callback signature is meant to be similar to `Array.prototype.map`. Value returned from the callback will become the new value on that key.

```ts
mapObject({ firstName: 'peter', lastName: 'griffin' }, ( key, value ) => value.toUpperCase() )
// => { firstName: 'Peter', lastName: 'Griffin' }
```

For more code examples, checkout [src/mapObject.test.ts](src/mapObject.test.ts)

## reduceObject(object, ( result: any, key: string, value: any ) => any, initial: any ): any

Reduce the object to a single value. The result can be another object. The callback signature is meant to be similar to `Array.prototype.reduce`. This operator will invoke the callback for each property. The callback will receive the result of previous operation or initial value, the key and value at that property.

```ts
reduceObject({ firstName: 'peter', lastName: 'griffin' }, ( result, key, value ) => {
if (result) {
return `${result} ${value}`;
} else {
return value;
}
}, null);
// => peter griffin

reduceObject({ firstName: 'peter', lastName: 'griffin' }, ( result, key, value ) => {
return {
...result,
[key.toLowerCase()]: value
};
}, {});
// => { firstname: 'peter', lastname: 'griffin' }
```

For more code examples, checkout [src/reduceObject.test.ts](src/reduceObject.test.ts)

## filterObject(object, ( key: string, value: any ) => {} ): {}

Iterate the keys of the object and invoke the callback for each key and value pair. If the callback returns a truthy value then
the key will be included in the output object. The callback signature is meant to be similar to `Array.prototype.filter`.

```ts
filterObject({ firstName: 'peter', lastName: 'griffin', age: 62 }, ( key, value ) => {
return typeof value === 'string';
});
// => { firstName: 'peter', lastName: 'griffin' }
```

For more code examples, checkout [src/filterObject.test.ts](src/filterObject.test.ts)

## set(path: Array<string | number>, value: any, data: Array | {}): Array | {}

`set` operator will create a new object with value replaced at given path. It uses lenses from [Ramda.js](http://ramdajs.com/docs/#set) to ensure that all objects that are parents to the object that received the value become new objects as well. This is particularly helpful in frameworks like React and Glimmer.js that compare state by reference. The path can mix objects and arrays. Use integer for array keys and strings for object keys.

```ts
set([ 'a', 0, 'b' ], 'e', { a: [ { b: 'c' }, { b: 'd' } ]});
//=> { a: [ { b: 'e' } , { b: 'd' } ] }
```

For more code examples, checkout [src/set.test.ts](src/set.test.ts)

## get(path: Array<string | number>, data: Array | {}): any

`get` counterpart to `set`. It accepts a path array of strings or integers and returns value found that path.

```ts
set([ 'a', 0, 'b' ], { a: [ { b: 'c' }, { b: 'd' } ]});
//=> c
```

For more code examples, checkout [src/get.test.ts](src/get.test.ts)

# Credit

Big thanks to [Charles Lowell](http://github.com/cowboyd) who wrote the map/reduceObject functions and showed me how to use lenses.
10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ts-library-starter",
"version": "0.1.0",
"name": "ioo",
"version": "0.1.1",
"description": "Example git project that is used for typescript libraries as a starter pack",
"main": "dist/main.js",
"typings": "dist/main.d.ts",
Expand Down Expand Up @@ -66,11 +66,13 @@
"webpack": "2.1.0-beta.22",
"webpack-node-externals": "^1.4.3"
},
"dependencies": {},
"dependencies": {
"ramda": "0.24.1"
},
"jest": {
"scriptPreprocessor": "node_modules/typescript-babel-jest",
"testEnvironment": "node",
"testRegex": ".*\\.spec\\.ts$",
"testRegex": ".*\\.test\\.ts$",
"moduleFileExtensions": [
"ts",
"js",
Expand Down
17 changes: 0 additions & 17 deletions src/Example.spec.ts

This file was deleted.

10 changes: 0 additions & 10 deletions src/Example.ts

This file was deleted.

21 changes: 21 additions & 0 deletions src/eachProperty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const { keys } = Object;
/**
* Invoke callback for each property and pass key and value to each property.
*
* eachProperty({ a: 'b', c: 'd'}, (key, value) => console.log(key, value)})
* // ab
* // cd
*
* @param object {}
* @param fn: (key: string, value: any) => any
*/
export default function eachProperty(
object: {},
fn: (key: string, value: any) => any
): void {
if (typeof object === 'object') {
keys(object).forEach(function(key) {
fn(key, object[key]);
});
}
}
22 changes: 22 additions & 0 deletions src/eachPropety.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use strict';

import 'jest';
require('babel-core/register');
require('babel-polyfill');

import eachProperty from './eachProperty';

describe('eachProperty', () => {
let callback;
beforeEach(() => {
callback = jest.fn();
eachProperty({ a: 'b', c: 'd' }, callback);
});
it('invokes callback for each property', () => {
expect(callback.mock.calls.length).toEqual(2);
});
it('passes key and value to callback', () => {
expect(callback.mock.calls[0]).toEqual(['a', 'b']);
expect(callback.mock.calls[1]).toEqual(['c', 'd']);
});
});
51 changes: 51 additions & 0 deletions src/filterObject.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
'use strict';

import 'jest';
require('babel-core/register');
require('babel-polyfill');

import filterObject from './filterObject';

describe('filterObject', () => {
let original = { small: 1, smallish: 2, big: 4 };
let callback, result;

describe('callback use', () => {
beforeEach(() => {
callback = jest
.fn()
.mockReturnValueOnce(false)
.mockReturnValueOnce(true)
.mockReturnValueOnce(undefined);
result = filterObject(original, callback);
});
it('was called three times', () => {
expect(callback.mock.calls.length).toEqual(3);
});
it('removed items that returned false', () => {
expect(result).toEqual({ smallish: 2 });
});
it('passed key and value', () => {
expect(callback.mock.calls[0]).toEqual(['small', 1]);
expect(callback.mock.calls[1]).toEqual(['smallish', 2]);
expect(callback.mock.calls[2]).toEqual(['big', 4]);
});
});

describe('result', () => {
beforeEach(() => {
result = filterObject(
original,
(key, value) => key.indexOf('small') === -1
);
});

it('returns a new object', () => {
expect(result).not.toEqual(original);
});

it('returns filtered hash', () => {
expect(result).toEqual({ big: 4 });
});
});
});
28 changes: 28 additions & 0 deletions src/filterObject.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import reduceObject from './reduceObject';

/**
* Create a new hash with keys and their corresponding values
* removed based on result of callback operation. E.g.
*
* filterObject({ small: 1, smallish: 2, big: 4}, (key, value) => value < 3 })
*
* { small: 1, smallish: 2 }
*
* @param object
* @param fn
*/
export default function filterObject(object: {}, fn: (key, value) => boolean) {
return reduceObject(
object,
(result, key, value) => {
if (fn(key, value)) {
return {
...result,
[key]: value
};
}
return result;
},
{}
);
}
24 changes: 24 additions & 0 deletions src/get.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use strict';

import 'jest';
require('babel-core/register');
require('babel-polyfill');

import get from './get';

describe('get', () => {
describe('array', () => {
const original = [{ a: { b: { c: 'd' } } }, { e: 'f' }];

it('gets value from deeply nested path', () => {
expect(get([0, 'a', 'b', 'c'], original)).toEqual('d');
});
});

describe('object', () => {
const original = { a: { b: { c: 'd' } } };
it('gets value an object', () => {
expect(get(['a', 'b', 'c'], original)).toEqual('d');
});
});
});
10 changes: 10 additions & 0 deletions src/get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import * as lensPath from 'ramda/src/lensPath';
import * as view from 'ramda/src/view';

export default function get(
path: Array<string | number>,
data: {} | Array<any>
) {
let lens = lensPath(path);
return view(lens, data);
}
9 changes: 8 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,8 @@
export { Example } from "./Example";
import get from './get';
import set from './set';
import reduceObject from './reduceObject';
import mapObject from './mapObject';
import filterObject from './filterObject';
import eachProperty from './eachProperty';

export { eachProperty, filterObject, mapObject, reduceObject, set, get };

0 comments on commit f2a2150

Please sign in to comment.