node package manager

useless

Use Less. Do More. JavaScript on steroids.

Use Less. Do More.

A cross-platform JavaScript toolbox for writing complex web applications. Currently in pre-release stage, missing some basic documentation and being under heavy development. In near future, it will be split into several loosely coupled NPM modules, for everyone's convenience. Stay tuned.

Installing | Building | Wiki

> npm install useless
  • New unit test system based on Promises (will replace the old buggy Testosterone thing).

  • Splitting of distinct framework parts to separate projects (finally, useful ones).

  • Webpack Hot Module Replacement now works (run the example app and try change example/index.css). It was previously broken due to webpack-dev-server incompatilibity with Webpack 2. This is solved by introducing webpack-hot-fix.js.

  • You can now use ES6 getter syntax for defining properties in components/traits: get something () { ... }

  • Working on webpack and babel integration for building front-end code (see the webpack server trait and the example app). Will feature continuous builds, hot module replacement, CSS imports and shared code extraction — all configurable from server's config.

  • More NPM modules to come: StackTracey and get-source.

  • ANSI color management now available as separate NPM module: ansicolor.

  • asTable function now available as a separate NPM module: as-table.

  • String.ify function now available as a separate NPM module: string.ify.

  • A wiki entry explaining the Stream concept. Thanks to @kroitor for the translation/adaptation from Russian!

  • Build system now utilizes webpack for squashing require imports. All external dependencies (e.g. underscore) now embedded in useless.client.js — no need to link them separately.

  • Component methods init / beforeInit / afterInit now support Promise interface for asynchronous initialization. Old callback-passing style is gone.

  • A wiki entry explaining the new __ namespace (brought by Promise+). It contains a pack of highly abstract data-processing algorithms that can handle any type of data (arrays, objects, scalars) and any kind of operator function (either sync or async).

  • An early alpha of the new HTTP server framework built around the recent Androgene subsystem. See a brief example here. It allows to write and debug complex asynchronous chains in no time, with unprecedented level of the error reporting legibility.

  • A working prototype of Androgene subsystem, delivering the "supervised Promises" concept for asynchronous/nonlinear logging and stack traces. It is also a core mechanism behind the upcoming unit test system (will replace the old Testosterone thing).

  • Read more...

> node example.js

If everything's ok, example app will be running at http://localhost:1333. Currently there's not much example code, but it's on the way.

You may want to look into these projects (built upon Useless.js):

  • Skychat — a simple WebRTC paint/chat app.
  • Wyg — a revolutionary WYSIWYG editor (demo).

How-to & Examples

Vec2 = $prototype ({
 
    /*  Constructor
     */
    constructor: function (x, y) { this.x = x; this.y = y },
 
    /*  Instance method
     */
    add (other) { return new Vec2 (this.x + other.x, this.y + other.y) }
 
    /*  Instance property (.length)
     */
    get length () { return Math.sqrt (this.x * this.x + this.y * this.y) }),
 
    /*  Static property: Vec2.zero
     */
    zero: $static ($property (function () { return new Vec2 (0, 0) })),
 
    /*  Static method: Vec2.dot (a, b)
     */
    dot: $static (function (a, b) { return a.x * b.x + a.y * b.y }),
 
    /*  Tag groups for convenience
     */
    $static: {
        unit: $property (function () { return new Vec2 (1, 1) }),
        one:  $alias ('unit') }, // member aliases 
})
 
/*  Inheritance (relies on native JavaScript prototype semantics)
 */
BetterVec2 = $extends (Vec2, { /* ... */ })

How-to & Examples

  • Binds own methods to this automatically
  • Manages bindable $trigger / $barrier / $observableProperty members
  • Tracks bound components / auto-unbinds upon deinitialization
  • Holds parent-child relationship / handles automatic deinitialization
  • Enables $traits to chain into method calls by overlapping method definitions
  • Enforces configuration contracts ($requires, $defaults)

How-to & Examples | Reference

  • _.trigger, _.triggerOnce / one-to-many broadcast
  • _.barrier / synchronization primitive
  • _.observable / state change notifications

Raw API (same for every mentioned primitive):

var mouseMoved = _.trigger ()
 
/*  Binding
 */
mouseMoved (function (x, y) { }) // bind 
mouseMoved (someCallback)        // bind another 
mouseMoved.once (someCallback)   // bind with 'once' semantics (auto-unbinds itself upon calling) 
 
/*  Calling
 */
mouseMove (12, 33)               // call 
 
/*  Unbinding
 */
mouseMove.off (someCallback)     // unbinds specific listener 
mouseMove.off ()                 // unbinds everything 
_.off (someCallback)             // unbinds callback from everything it's bound to 

Using $component:

Compo = $component ({
 
    didLayout:     $trigger (),
    layoutReady:   $barrier (),             // it's like jQueryish $(document).ready 
    value:         $observableProperty (),  // for property change notifications 
    
    init: function () {
        doSomeUselessAsyncJob (function () {
           this.layoutReady () }) }, // signals that layout is ready 
 
    doLayout: function () {
        this.didLayout () } })       // simply call to perform multicast 
compo = new Compo ()
 
compo.didLayout (function () {
    /*  Gets called whenether layout has rebuilt */ })
 
compo.layoutReady (function () {
    /*  Postpones until DOM is ready.
        If already, calls immediately (like $(document).ready) */ })
 
compo.valueChange (function (value, oldValue) {
    /*  Gets called whenether property has assigned distinct value */ })
 
compo.value = 10 // simply assign a value to notify listeners 
compo.value = 10 // won't trigger, as not changed 

Raw API:

_.onAfter   (Player.prototype, 'move', function (x, y) { /* this will execute after move calls */ })
_.onBefore  (Player.prototype, 'move', function (x, y) { /* this will execute before */ })
_.intercept (Player.prototype, 'move', function (x, y, originalMethod) {
    originalMethod.call (this, x, y) })

Using $component + 'once' semantics:

Button = $component ({
    layout: $bindable (function () { /* ... */ }) })
    
button = new Button ()
button.layout.onceBefore (function () { log ("I'm called before next layout()") })
button.layout ()
button.layout () // won't print anything 

Reference

Working with ranges:

    _.lerp  (t, min, max)  // linear interpolation between min and max 
    _.clamp (n, min, max)  // clips if out of range 
    
    /*  Projects from one range to another (super useful in widgets implementation)
     */
    _.rescale (t, [fromMin, fromMax], [toMin, toMax], { clamp: true })

Vector math (Vec2, Transform, BBox, Bezier, intersections):

   var offsetVec = this.anchor.sub (this.center).normal.perp.scale (
                       Bezier.cubic1D (
                           Vec2.dot (direction.normal, upVector), 0, 1.22, 0, 1.9))
   var where = this.bodyBBox.nearestPointTo (this.anchor, this.borderRadius)
   domElement.css (BBox.fromPoints (pts).grow (20).offset (position.inverse).css)

  • Cross-platform uncaught exception handling (works around incomplete 'onerror' impl. in Safari).
  • Uncaught exceptions pass through network API calls
  • Client displays server's exceptions as if it was single environment
  • Complete API for it's internals
  • Strips third party calls (clean mode)
  • Fetches source code (local/remote)
  • Nice output
    • Console mode (replaces default Node.js exception printer)
    • GUI mode (a pop-up dialog with expandable source lines)

How-to & Examples

  • Tests before code
  • Tests as documentantion
  • Rich library of assertions
  • Asynchronous / nested assertions
  • Intercepts global log, displaying it in running assertion context
  • Custom assertions
  • Humane error reporting
  • Browser-side support (see demo: youtube.com/watch?v=IWLE8omFnQw)

Reference / examples

  • Platform-independent
  • Color output (even in WebInspector)
  • Shows code location
  • Configurable object printer
  • Table layout formatting
  • Hookable/interceptable

Example (pseudo-code):

require ('useless')
 
UselessApp = $singleton (Component, {
 
    $depends: [
        require ('useless/server/tests'),
        require ('useless/server/webpack'),
        require ('useless/server/http') ],
 
    /*    URL router schema
     */
    api: function () { return {
        
        '/':             this.file ('./static/index.html'),
        '/static/:file': this.file ('./static'),            // directory 
    
        'hello-world':       () => { return "Hello world!"        }, // plain text 
        'hello-world/json':  () => { return { foo: 42, bar: 777 } }, // JSON 
        
        /*    Tree-style defintions, Promise-backed method chains
         */
        'api': {
            'login':  { post: [this.receiveJSON, this.doLogin] },
            'logout': { post: () => $http.removeCookies (['email', 'password']) } } } },
 
    /*  A complex request handler example, demonstrating some core features.
    
        All execution is wrapped into so-called "supervised Promise chain",
        so you don't need to pass the request context explicitly, it is always
        available as $http object in any promise callback related to request
        represented by that object.
        
        All thrown errors and all log messages are handled by the engine
        automagically. It builds a process/event hierarchy that reflects the
        actual execution flow, so you don't need to run a debugger to see what's
        going on, it's all in the log. Request is automatically ended when an
        unhandled exception occurs, no need to trigger it explicitly.
     */
    doLogin: function () {
        var login = _.pick ($http.env, 'email', 'password') // 'receiveJSON' writes to $http.env 
        if (login.email && login.password) {
            return this.db.users
                    .find (login)
                    .count ()
                    .then (count => {
                                    if (count > 0) {
                                        $http.setCookies (login) }
                                    else {
                                        throw new Error ('Wrong credentials') } }) }
        else {
                throw new Error ('Empty email or password') } },
 
    init: function (then) {
            log.ok ('App started')
            then () } })

Example report generated from a Promise chain:

Following are $traits defined at useless/server:

  • api.js URL routing
  • args.js command line arguments parsing
  • config.js handles config.json and default parameters
  • deploy.js self-deployment protocol (automatic builds)
  • devtools.js developer-mode APIs for Git / source code access
  • exceptions.js custom unhandled exception printer
  • history.js journal for DB operation
  • http.js request serving basics
  • supervisor.js auto-restart on source code change
  • templating.js basic templating (via underscore)
  • tests.js self-tests on startup for TDD
  • uploads.js file/image uploads
  • uptime.js uptime tracking
  • websocket.js WebSocket utility

Installing

Type npm install useless in root directory of your project.

  1. Go to node_modules subfolder of your project
  2. Run git clone https://github.com/xpl/useless.git, go to useless folder
  3. Run npm install to install dependencies
  4. Optionally, run node build to test if everything's ok

Go to /build folder and pick files needed.

There also exist a compressed (minified) version of each file.

Building

Build command:

node build <header-file-1> <header-file-2> ... <header-file-N> <output-folder> [no-compress] [no-stripped] [no-supervisor]

For building everything, run:

node build

It will generate ./build/***.js by squashing all require imports into a single monolithic file. Produced result will undergo stripping of tests and comments, and then finally compiled using Google Closure Compiler, outputting minified result to ./build/***.min.js

Disables minification. Greatly speeds up build.

Disables generation of ***.stripped.js files.

Disables file monitor (for termination after run).

To make reduced/extended distribution (with some submodules disabled or enabled), you can create your own version of default header file, commenting out unneeded $include directives or including additional ones. There exists ./useless.client.js as an example of custom distribution.

Applications that are based on top of useless/server can easily enable automatic rebuilds feature by adding following $traits to main application component:

$traits: [        
        require ('useless/server/tests'),
        require ('useless/server/webpack'),
        require ('useless/server/supervisor')

This will add test & build phase to app startup sequence, aborting if something went wrong and re-starting if source code has changed.

Default settings:

buildScriptPaths: [process.cwd (), $uselessPath],
buildScripts: ['useless.js', 'useless.micro.js', 'useless.devtools.js'],
buildPath: $uselessPath + 'build/',