Skip to content

Commit

Permalink
Extended functionality combine
Browse files Browse the repository at this point in the history
  • Loading branch information
iHaiduk committed May 7, 2020
1 parent 6c2bf59 commit d964204
Show file tree
Hide file tree
Showing 19 changed files with 626 additions and 68 deletions.
2 changes: 1 addition & 1 deletion .coveralls.yml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
repo_token: nrqVHIHupByIBoGrcvFwdOIpWpmv0m7BA
repo_token: L6D0g1PobZ0Wrn8lGAKGURRLIo3Ld13vD
207 changes: 202 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,203 @@
# Tree Combiner
# Flexible chain [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/facebook/react/blob/master/LICENSE) [![npm version](https://badge.fury.io/js/flexible-chain.svg)](https://badge.fury.io/js/flexible-chain) [![Build Status](https://travis-ci.org/iHaiduk/flexible-chain.svg?branch=master)](https://travis-ci.org/iHaiduk/flexible-chain) [![Coverage Status](https://coveralls.io/repos/github/iHaiduk/flexible-chain/badge.svg?branch=master)](https://coveralls.io/github/iHaiduk/flexible-chain?branch=master) [![devDependencies Status](https://david-dm.org/iHaiduk/flexible-chain/dev-status.svg)](https://david-dm.org/iHaiduk/flexible-chain?type=dev)

[![npm version](https://badge.fury.io/js/tree-combiner.svg)](https://badge.fury.io/js/tree-combiner)
[![Build Status](https://travis-ci.org/iHaiduk/tree-combiner.svg?branch=master)](https://travis-ci.org/iHaiduk/tree-combiner)
[![Coverage Status](https://coveralls.io/repos/github/iHaiduk/tree-combiner/badge.svg?branch=master)](https://coveralls.io/github/iHaiduk/tree-combiner?branch=master)
[![devDependencies Status](https://david-dm.org/iHaiduk/tree-combiner/dev-status.svg)](https://david-dm.org/iHaiduk/tree-combiner?type=dev)
## Install

Install from the NPM repository using yarn or npm:

```shell
yarn add flexible-chain
```
Or
```shell
npm install flexible-chain
```

## Motivation
We have a lot of repetitive code and the chore of writing different combinations. Also, over time, we forget what a piece of code should do and spend more time understanding it. This utility helps to make your code more flexible, understandable and transparent.

## Solution
Tree Combiner is a small but powerful utility for creating tree chains and obtaining results after combining it.

## Example

### Simple
Simple use for creating various chains
```typescript
import { combine, ValueOf } from "flexible-chain";

const colorProps = {
Red: {
color: 'red',
},
/* ... */
};

const sizeProps = {
L: {
fontSize: 16,
},
/* ... */
};

export const initialFontTree = { ...colorProps, ...sizeProps };

type ResultType = ValueOf<typeof colorProps> & ValueOf<typeof sizeProps>;

export const fontResult = {
View: (style: ResultType): ResultType => style,
Color: (style: ResultType): string => style.color,
Size: (style: ResultType): number => style.fontSize,
};

const Font = combine(initialFontTree, fontResult);

console.log(Font.Red.View); // {color: 'red'}
console.log(Font.Red.L.View); // {color: 'red', fontSize: 16}

console.log(Font.Red.L.Color); // 'red'
console.log(Font.Red.L.Size); // 16
```

### Custom
More flexible and specific use of combine for your tasks. For example, when you want the state to be not an object (by default), but a different data type.
```typescript
import { combine, ValueOf } from "flexible-chain";

export const mainLanguageKey = {
Hello: 'Hello',
Welcome: 'Welcome',
};

export const secondaryLanguageKey = {
Dear: 'dear',
To: 'to',
};

export const initialLanguageTree = { ...mainLanguageKey, ...secondaryLanguageKey };

type Keys = ValueOf<typeof mainLanguageKey> & ValueOf<typeof secondaryLanguageKey>;
type ResultLanguageType = Array<Keys>;

export const customResultTree = {
Key: (keys: ResultLanguageType) => keys.join('.'),
Keys: (keys: ResultLanguageType) => keys,
Name: (keys: ResultLanguageType) => (name: string) => `${[...keys, name].join(' ')}!`,
Length: (keys: ResultLanguageType) => keys.length,
};

export const customConcatenationFn = (prev: ResultLanguageType, key: Keys) => [...prev, key];

export const customInitialState = [];

const Salutation = combine(initialLanguageTree, customResultTree, customConcatenationFn, customInitialState);

console.log(Salutation.Hello.Dear.Key); // 'Hello.dear'
console.log(Salutation.Hello.Dear.Keys); // ['Hello', 'dear']

console.log(Salutation.Hello.Length); // 1
console.log(Salutation.Hello.Dear.Length); // 2
/* ... N ... */

console.log(Salutation.Hello.Name('Kris')); // 'Hello Kris!'
console.log(Salutation.Welcome.To.Name('flexible-chain')); // 'Welcome to flexible-chain!';
```

### React & React-Native
You can also make beautiful chains for react components.

### React web style
```typescript jsx
import { combine, combineComponent } from "flexible-chain";

const SpanComponent = (props: any) => <span {...props} />;
const ParagraphComponent = (props: any) => <p {...props} />;

const componentColors = {
White: {
color: 'white',
},
Red: {
color: 'red',
},
/* ... */
};

const componentFontStyle = {
Italic: {
fontStyle: 'italic',
},
Oblique: {
fontStyle: 'oblique',
},
/* ... */
};

const componentFontWeight = {
Bold: {
fontWeight: 'bold',
},
/* ... */
};

const componentStyles = { ...componentColors, ...componentFontStyle, ...componentFontWeight };

type ComponentProps = {};

const componentResult = {
Text: combineComponent<ComponentProps, typeof componentStyles>(SpanComponent, 'style'),
Paragraph: combineComponent<ComponentProps, typeof componentStyles>(ParagraphComponent, 'style'),
};

const UserInfo = combine(componentStyles, componentResult);

const UserProfile = () => (
<>
<UserInfo.White.Bold.Text>User Name</UserInfo.White.Bold.Text>
<UserInfo.White.Bold.Italic.Text>User Surname</UserInfo.White.Bold.Italic.Text>
<UserInfo.Red.Oblique.Paragraph>User Role</UserInfo.Red.Oblique.Paragraph>
/* ... */
</>
);

const HeaderUserInfo = () => (
<>
<UserInfo.White.Bold.Paragraph>User Name</UserInfo.White.Bold.Paragraph>
<UserInfo.Red.Italic.Paragraph>User Role</UserInfo.Red.Italic.Paragraph>
/* ... */
</>
);

console.log(UserProfile); // ->
/*
<span style={{color: 'white', fontWeight: 'bold'}}>User Name</span>
<span style={{color: 'white', fontWeight: 'bold', fontStyle: 'italic'}}>User Surname</span>
<p style={{color: 'red', fontStyle: 'oblique'}}>User Role</p>
*/

```

### React web classes
```typescript jsx
import { combine, combineComponent } from "flexible-chain";
import cs from 'classnames';

import styles from './style.module.css';

/* ... */

const SpanComponent = ({classes, ...props}: any) => {
return <span className={cs(classes)} {...props} />;
}

const componentResult = {
Text: combineComponent(SpanComponent, 'classes'),
};

const UserInfo = combine(styles, componentResult);

/* ... */
```

#### P.S.
Above are the most simple and commonly used options. You can combine more complex and dynamic connections for easier reuse.
5 changes: 3 additions & 2 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
presets: [
['@babel/preset-env', {targets: {node: 'current'}}],
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-typescript',
'@babel/preset-react',
],
};
};
6 changes: 4 additions & 2 deletions jestconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
"transform": {
"^.+\\.(t|j)sx?$": "ts-jest"
},
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
"moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"]
"testRegex": "(/tests/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
"moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"],

"moduleDirectories": ["node_modules"]
}
37 changes: 23 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "tree-combiner",
"name": "flexible-chain",
"description": "This library will help you quickly and clearly build your code by building a chain of trees.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand All @@ -8,33 +8,48 @@
"lint": "tslint --format stylish --project tsconfig.json",
"lint:fix": "yarn run lint --fix",
"format": "prettier --write \"./src/**/*.{ts,tsx,js}\"",
"test": "jest",
"test": "jest --config=jestconfig.json",
"test:watch": "jest --config=jestconfig.json --watch",
"test:coverage": "yarn jest --coverage",
"coveralls": "yarn test:coverage && cat ./coverage/lcov.info | coveralls"
},
"keywords": [
"flex",
"chain",
"flex chain",
"object field tree",
"js tree",
"typescript tree"
"typescript chain",
"typescript tree",
"react",
"react-native",
"react-native-web",
"react tree"
],
"repository": {
"type": "git",
"url": "git+https://github.com/iHaiduk/tree-combiner.git"
"url": "git+https://github.com/iHaiduk/flexible-chain.git"
},
"author": "Ihor Haiduk",
"license": "MIT",
"bugs": {
"url": "https://github.com/iHaiduk/tree-combiner/issues"
"url": "https://github.com/iHaiduk/flexible-chain/issues"
},
"homepage": "https://github.com/iHaiduk/tree-combiner#readme",
"homepage": "https://github.com/iHaiduk/flexible-chain#readme",
"devDependencies": {
"@babel/preset-env": "^7.9.6",
"@babel/preset-react": "^7.9.4",
"@babel/preset-typescript": "^7.9.0",
"@types/jest": "^25.2.1",
"@types/react": "^16.9.34",
"@types/react-test-renderer": "^16.9.2",
"coveralls": "^3.1.0",
"jest": "^26.0.1",
"prettier": "^2.0.5",
"ts-jest": "^25.4.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-test-renderer": "^16.13.1",
"ts-jest": "^25.5.0",
"tslint": "^6.1.2",
"tslint-config-prettier": "^1.18.0",
"tslint-config-standard": "^9.0.0",
Expand All @@ -46,18 +61,12 @@
"tslint-sonarts": "^1.9.0",
"typescript": "^3.8.3"
},
"peerDependencies": {
"react": "^16.13.1"
},
"publishConfig": {
"access": "public"
},
"prepublishOnly": "npm test && npm run lint",
"prepare": "npm run build",
"preversion": "npm run lint",
"version": "0.0.1",
"postversion": "git push && git push --tags",
"dependencies": {
"coveralls": "^3.1.0"
}
"postversion": "git push && git push --tags"
}
30 changes: 30 additions & 0 deletions src/__mocks__/combine-component.mock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as React from 'react';

export const componentColors = {
White: {
color: 'white',
},
Red: {
color: 'red',
},
};

export const componentFontWeight = {
Bold: {
fontWeight: 'bold',
},
};

export const componentFontStyle = {
Italic: {
fontStyle: 'italic',
},
Oblique: {
fontStyle: 'oblique',
},
};

export const componentStyles = { ...componentColors, ...componentFontWeight, ...componentFontStyle };

export const SpanComponent = (props: any) => <span {...props} />;
export const ParagraphComponent = (props: any) => <p {...props} />;
27 changes: 27 additions & 0 deletions src/__mocks__/custom-combine.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ValueOf } from '../types/helper.type';

export const mainLanguageKey = {
Hello: 'Hello',
Welcome: 'Welcome',
};

export const secondaryLanguageKey = {
Dear: 'dear',
To: 'to',
};

export const initialLanguageTree = { ...mainLanguageKey, ...secondaryLanguageKey };

type Keys = ValueOf<typeof mainLanguageKey> & ValueOf<typeof secondaryLanguageKey>;
type ResultLanguageType = Array<Keys>;

export const customResultTree = {
Key: (keys: ResultLanguageType) => keys.join('.'),
Keys: (keys: ResultLanguageType) => keys,
User: (keys: ResultLanguageType) => (name: string) => `${[...keys, name].join(' ')}!`,
Length: (keys: ResultLanguageType) => keys.length,
};

export const customConcatenationFn = (prev: ResultLanguageType, key: Keys) => [...prev, key];

export const customInitialState = [];

0 comments on commit d964204

Please sign in to comment.