Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
725257b
feature: add contracts fields with null value
Dec 20, 2020
d18e274
chore: husky pre push script adjust for only test that really matter
Dec 20, 2020
c8b2080
style: remove commented area
Dec 20, 2020
0457864
chore: update package.json version to 2.0.0
Dec 20, 2020
2ed23c0
fix: remove saveMethod from store
Dec 20, 2020
73286d7
refactor: core architecture reorganisation
Dec 20, 2020
394d66e
feature: nucleo state first poc
Dec 22, 2020
d99c399
refactor: overall clean up and folder organisation
Dec 22, 2020
f6325fe
chore: fix pre push hook
Dec 22, 2020
8163979
tests: fix modules import in state spec
Dec 22, 2020
b4bf93f
refactor: make overall new api compatible inside the core code
Dec 28, 2020
5713f61
style: remove commented lines from store.ts
Dec 28, 2020
4910576
feature: super power primitive types to have verification from user f…
Dec 28, 2020
62b48c6
tests: remove commented legacy tests
Dec 28, 2020
d592e6f
style: change interface name for NucleoList
Dec 28, 2020
9139dfd
refactor: remove export from local interfaces in types
Dec 28, 2020
c10e45e
style: rename contracts to model and store.ts to nucleoState.ts
Dec 29, 2020
c5e5dc5
style: rename contracts to models in nucleoState
Dec 29, 2020
219f0e3
style: rename NucleoObject to NucleoModel
Dec 29, 2020
dcf5618
docs: adapt the readme.md to the project changes
Dec 29, 2020
cdc1c9c
docs: remove API_DOCUMENTATION.md
Dec 29, 2020
8996d31
docs: fix code example in readme.md
Dec 29, 2020
02879fe
docs: fix code example in readme.md
Dec 29, 2020
447b003
chore(deps): addition of package-lock file
May 20, 2021
ec3cc45
tests(state): add tests for state model
May 20, 2021
910e203
feature(types): add some atomic states
May 21, 2021
f2bc283
feature(lists): remove rule that incomplete lists are not allowed
May 22, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
620 changes: 0 additions & 620 deletions API_DOCUMENTATION.md

This file was deleted.

230 changes: 27 additions & 203 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,16 @@

Nucleo creates and manages a strongly typed and predictable state container.

## Roadmap

It's in this project milestones https://github.com/mtmr0x/nucleo/milestones;

For requesting any feature, please open an issue with the prefix "[FEATURE REQUEST]".

## Why

JavaScript is a really dynamic language which we can't always rely in the language resilience from types perspective. Every project has types problems and developers can not make sure all the time the data is predictable. Inspired by how GraphQL does a great job with safety and trustful data and Redux by its simplicity on storing state, Nucleo was idealized to make sure the data model (contracts) and the data types are expected and reliable.
JavaScript is a language with some difficulties to rely on type safety. Every project has problems with types and develoeprs can not cover everything because most of it is due user input, couldn't being predictable. Inspired by how GraphQL does a great job with type safety and with a mission critical Front-End App I was working on back then I idealised Nucleo to work with a predefined model and make sure you will never save the wrong data to its state.

## Installation

Using NPM:

```
npm install nucleojs --save
npm install nucleojs
```

Using Yarn:
Expand All @@ -26,213 +20,42 @@ Using Yarn:
yarn add nucleojs
```

## Documentation

The links below take you to our `API_DOCUMENTATION.md` file present in this repository with deeper information and documentation to Nucleo usage.
> For TypeScript projects, there is no need to install `@types/nucleojs`, the `.d.ts` interfaces are in the project published at NPM. It should work with no issues.

- [Installation](API_DOCUMENTATION.md#installation)
- [Usage](API_DOCUMENTATION.md#usage)
- [Contracts](API_DOCUMENTATION.md#contracts)
- [Types](API_DOCUMENTATION.md#types)
- [NucleoObject](API_DOCUMENTATION.md#creating-nucleoobject)
- [Anatomy](API_DOCUMENTATION.md#nucleoobject-anatomy)
- [Usage](API_DOCUMENTATION.md#nucleoobject-usage)
- [NucleoList](API_DOCUMENTATION.md#creating-nucleolist)
- [Anatomy](API_DOCUMENTATION.md#nucleolist-anatomy)
- [Usage](API_DOCUMENTATION.md#nucleolist-usage)
- [NucleoString](API_DOCUMENTATION.md#creating-nucleostring)
- [NucleoNumber](API_DOCUMENTATION.md#creating-nucleonumber)
- [NucleoBoolean](API_DOCUMENTATION.md#creating-nucleoboolean)
- [NucleoStringAssertion](API_DOCUMENTATION.md#creating-nucleostringassertion)
- [Anatomy](API_DOCUMENTATION.md#nucleostringassertion-anatomy)
- [Usage](API_DOCUMENTATION.md#nucleostringassertion-usage)
- [NucleoNumberAssertion](API_DOCUMENTATION.md#creating-nucleonumberassertion)
- [Anatomy](API_DOCUMENTATION.md#nucleonumberassertion-anatomy)
- [Usage](API_DOCUMENTATION.md#nucleonumberassertion-usage)
- [Creating the store](API_DOCUMENTATION.md#creating-the-store)
- [Dispatching and updating the store](API_DOCUMENTATION.md#dispatching-and-updating-the-store)
- [Get contracts in store](API_DOCUMENTATION.md#get-contracts-in-store)
- [Subscribing to changes](API_DOCUMENTATION.md#subscribing-to-changes)
- [Unsubscribing](API_DOCUMENTATION.md#unsubscribing)
- [Error management](API_DOCUMENTATION.md#error-management)

## Basic usage
## How to use it

Nucleo is written in TypeScript and compatible with es2016+. Importing for a ECMAScript usage:

```javascript
import { createStore } from 'nucleojs';
```

Importing from Nucleo source for TypeScript usage just add `/src` after nucleojs module:

```javascript
import { createStore } from 'nucleojs/src';
```

### Defining a data model (contract):

```javascript
import {
import {
nucleoState,
NucleoString,
NucleoNumber,
NucleoObject,
createStore
} from 'nucleojs'

const completeNameContract = new NucleoObject({
name: 'completeNameContract',
fields: {
firstName: NucleoString,
lastName: NucleoString
}
});

const userContract = new NucleoObject({
name: 'user', // don't need to be the same name as the variable, but need to be unique
fields: {
name: completeNameContract,
age: NucleoNumber
}
});

const productsContract = new NucleoObject({
name: 'products',
NucleoBoolean,
NucleoModel,
NucleoList,
} from 'nucleojs';

// define your model
const User = new NucleoModel({
name: 'user',
fields: {
title: NucleoString
firstName: NucleoString(),
lastName: NucleoString(),
age: NucleoNumber(),
isAuthenticated: NucleoBoolean(),
scope: new NucleoList(NucleoString()),
}
});

const contracts = {
user: userContract,
products: productsContract
};

```

### Creating the store

```javascript
import { createStore } from 'nucleojs';
import * as contracts from './contracts';

const store = createStore(contracts); // send contracts to create the store
const { dispatch, update, cloneState, subscribe } = store; // these 4 functions are returned from store creation
```

### Dispatching and updating the store

Nucleo provides two methods of saving data, used for different approaches.
// create the state
const [user, updateUser] = nucleoState(User)

**dispatch:** works for saving data according to the full contract, used to save the very first contract state in the store or to update the whole contract in the store;
// send data to user state
updateUser({ name: { firstName: 'John' }, age: 28 });

**update:** works for updating parts of data, it performs a index search in the object and save it. `update` will fail if you try to first save a contract to the store using it.

---

Dispatch function, considering user contract above:

```javascript

let user = dispatch('user')({ name: { firstName: 'John', lastName: 'Nor' } });
// it'll fail because it's missing age field

user = dispatch('user')({ name: { firstName: 'John', lastName: 'Nor' }, age: 27 });
// it'll save the data to store properly

console.log(user);
/*
{
status: 'OK',
errors: [],
data: {
name: {
firstName: 'John',
lastName: 'Nor'
},
age: 27
},
}
*/
```

Update function, considering user contract above:

```javascript
const user = update('user')({ name: { firstName: 'Robert' }});
// it'll update only the user first name and only if this item has been already created in the store before

console.log(user);
/*
{
status: 'OK',
errors: [],
data: {
name: {
firstName: 'Robert',
},
},
}

It'll return the data you asked to save. To receive the new store, you will have to clone this state or subscribe to Nucleo changes through subscribe function
Check documentation for cloneState in the next section
*/
const newUser = cloneState('user');
console.log(newUser);
/*
{
name: {
firstName: 'Robert',
lastName: 'Nor',
},
age: 27,
}
*/
```

#### Update and Dispatch function signature

`update` and `dispatch` functions have the same signature albeit a discrete behavioral difference (you can find this difference in .

**Both are curried functions:**

- `update(<contract_name>)(<data_to_save_in_contract>)`;
- `dispatch(<contract_name>)(<data_to_save_in_contract>)`.

`<contract_name>`: a `string` for the contract name you want to update or dispatch. It's the `name` field for every new `NucleoObject` in the contracts definition. Those must be unique. You can find more information about contracts in API_DOCUMENTATION.md.

`<data_to_save_in_contract>`: must follow its contract model. For understanding how to use `update` and `dispatch` for saving data, check API_DOCUMENTATION.md in "Dispatching and updating the store" section.

**Both return the same object interface:**

```javascript
{
status: 'OK' | 'NOK', // a string return 'OK' for success cases and 'NOK' for errors
errors: [], // in case of errors, it will return the list of errors
data: { ... } // the data you just tried to save in store
}
```

- `status`: a string return 'OK' for success cases and 'NOK' for errors;
- `errors`: a list of objects containing the errors in this operation. Usually related to contract violations. You can find more details in API_DOCUMENTATION.md at "Error management" area.
- `data`: This is the exactly same object you tried to save at store for comparison reasons in cases of errors.

### Getting a state clone from store

The `cloneState` function receives one argument which is the contract name in store, performs a deep clone using the contracts data model as a map to predict the key/values of that contract and be able to return it with great performance.

```javascript
const user = cloneState('user');
console.log(user);
/*
{
name: {
firstName: 'Robert',
lastName: 'Nor'
},
age: 27
}
*/
// retrieve data by calling the `user` function defined above
console.log(user()); // { firstName: 'John', lastName: null, age: 28, isAuthenticated: null, scope: [] }
```

## Development
Expand All @@ -243,7 +66,7 @@ console.log(user);
- `npm run nodemon` - Start development mode and waiting for changes.
- `npm run tests` - Run automated tests.
- `npm run lint` - Validate syntax of all Typescript files.
- `npm run compile` - Compile for production.
- `npm run compile` - Compile for release.

## Contributing

Expand All @@ -256,3 +79,4 @@ To keep better organization of releases we follow the [Semantic Versioning 2.0.0
## Licence

[MIT Licence](https://github.com/mtmr0x/nucleo/blob/master/LICENCE.md) © [Matheus Marsiglio](http://mtmr0x.com)

Loading