NiceScript
A naive attempt to simplify life of a fellow JavaScript programmer.
![Build Status](https://travis-ci.org/nicescript/nicescript.svg?branch=master)
Install
npm install nicescript
Then in node.js script:
const nice = require('nicescript')();
Browser:
<script src="https://cdn.jsdelivr.net/npm/nicescript/nice.js"></script>
Examples
Tests
npm test
Basic features
- Types - sometimes they useful.
- Functions - adds couple features to regular JS functions.
- Switch - finally convenient.
- Boxes - to handle data flow.
- Tag - use all above to to create dom/html UI.
Values
Single values
const n = nice.Number(5);
n();
n(6);
n();
Object values
const o = nice.Object({ a: 1 });
o('a');
o('b');
o('b', 5);
o('b');
Wrapping values
Call nice with value to wrap it with most appropriate type.
const nice = require('nicescript')();
nice(4);
nice("");
nice(true);
nice({});
nice([]);
nice(1, 2, 3);
nice(null);
Types
Predefined types
- Anything
- Something
- Nothing
- Error
- Undefined
- Null
- NotFound
- Fail
- ...
User types
nice.Type('Dog')
.String('title')
.Number('weight')
.by((z, title) => z.title(title));
let d = nice.Dog('Jim');
d.name();
d.is.Object()
Type name should start with capital letter.
Functions
const f = nice.Function(n => n + 1);
f(1);
const plusTwo = nice.Function('plusTwo', n => n + 2);
plusTwo(1);
nice.plusTwo(1);
const x2 = nice.Function.number('x2', n => n * 2);
x2(21);
nice.x2(21);
nice.Number(1).x2();
x2('q');
x2.string(s => s + '!');
x2(21);
x2('q');
Function name should start with lowercase letter.
Function types
Mapping
Clean function that never changes it's arguments.
NiceScript will always wrap result of Mapping.
nice.Mapping.Number.Number('times', (a, b) => a * b);
const n = nice(5);
const n2 = n.times(3).times(2);
n()
n2()
Check
Returns boolean. Never chenges it's arguments.
After definition named Check can be used in Switch and 'is' statements.
Action
Changes first argument. Each body of Action should return nice.Ok or nice.Fail
or throw exception. Function returns it's first argument.
nice.Action.Number.Number('times', (a, b) => a * b);
const n = nice(5);
n.times(3).times(2);
n();
Interfaces
Switch
Delayed argumet
const f = nice.Switch
.equal(1)(11)
.number(22)
.string.use(s => s + '!')
.Nothing(':(')
.default(42);
f(1);
f(3);
f('qwe');
f([]);
f(0);
f(undefined);
f(null);
Instant argument
nice.Check('meat', v => ['pork', 'beef'].includes(v));
const tiger = { say: console.log };
function feedTiger(tiger, food){
tiger.hungry = nice.Switch(food)
.meat(false)
.default.use(name => tiger.say('I do not like ' + name) || true);
}
feedTiger(tiger, 'apple');
feedTiger(tiger, 'beef');
Switch vs Function overload
Overloaded Function will search for best match while Switch will use first match.
nice.Function.Nothing(() => 1).Null(() => 2)(null);
nice.Switch.Nothing.use(() => 1).Null.use(() => 2)(null);
Besides current implementation of Switch use only first argument.
Boxes
Stateful observable components.
const { Box } = nice;
let b = Box(1);
b.listen(console.log)
b(2);
b();
let b2 = Box.use(b).by(n => n * 2);
b(3);
let square = Box()
.Number('x', 5)
.Number('y', 5)
.by((x, y) => x * y);
square();
square.x(10).y(b)();
Tag
const div = nice.Div('Normal ', 'text ')
.I('italic ').up
.add('normal ')
.B('red bold').color('red').up
.margin('10px')
.fontSize('20px');
div.html
div.show();
Add some Boxes to handle asynchronous cases.
const { Box, Div, Switch, Nothing } = nice;
const data = Box(Nothing);
const div = Box().use(data)
.by(Switch
.string.use(s => Div('Data: ', s))
.default(Div('Loading...')));
div.listen(d => console.log(d.html));
data('Some data');
div.show();