NiceScript
A naive attempt to simplify life of a fellow JavaScript programmer.
Example ( JS Bin )
const { Box, Div, B, Switch } = nice;
const tasks = Box(['Feed the fish', 'Buy milk']);
const decorate = Switch
.equal('Watch tv')('Read book')
.match(/buy/i).use(s => [s, B(' $').color('#3A3')]);
const taskView = t => Div(t)
.margin('1em 0')
.padding('.5em')
.borderRadius('.5em')
.backgroundColor('#DEF');
Box.by(tasks, ts => Div(ts.map(decorate).map(taskView))).show();
tasks.push('Walk the dog', 'Watch tv');
More examples:
Install
npm install nicescript
Then in node.js script:
const nice = require('nicescript')();
Browser:
<script src="https://unpkg.com/nicescript/nice.js"></script>
or
<script src="https://cdn.jsdelivr.net/npm/nicescript/nice.js"></script>
Tests
npm test
Basic features
- Types
- Functions - adds couple features to regular JS functions.
- Switch - finally convenient.
- Boxes - to handle state changes.
- Tag - use all above to to create html UI.
Nice values
Single values
const n = nice(5);
n();
n(6);
n();
Object values
const o = nice.Object({ a: 1 });
o('a');
o('b');
o('b', 5);
o('b');
Types
Each value in NiceScript has a type. Here is a root of types hierarchy:
- Anything
- Something
- Nothing
- Error
- Undefined
- Null
- NotFound
- Fail
- ...
Wrapping values
Call nice with js 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);
User types
nice.Type('Dog')
.String('title')
.Number('weight')
.by((z, title) => z.title(title));
let d = nice.Dog('Jim').weight(5);
d.name();
d.weight();
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 do not 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 changes it's arguments.
After definition named Check can be used in Switch and 'is' statements.
Action
Changes first argument. Action always returns it's first argument so you can
call multiple actions in a row.
nice.Action.Number.Number('times', (a, b) => a * b);
const n = nice(5);
n.times(3).times(2);
n();
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)();
Calling mapping on box will create new box that follows changes in the original.
const a = nice.Box('qwe');
const b = a.concat('!').listen(console.log);
a('asd');
Calling action on box will change its content.
const a = nice.Box([1, 2]).listen(console.log);
a.push(3);
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.by(data, Switch
.string.use(s => Div('Data: ', s))
.default(Div('Loading...')));
div.listen(d => console.log(d.html));
data('Some data');
div.show();