0.1.355 • Published 6 years ago

useless v0.1.355

Weekly downloads
4
License
MIT
Repository
github
Last release
6 years ago

Use Less. Do More.

A research project, from which I learned a lot. Especially how one shouldn't write code and web frameworks in particular :)

In near future, it will be split into several loosely coupled, clean and maintainable NPM modules, for everyone's convenience. Stay tuned.

Installing | Wiki

> npm install useless

Browser builds

Upcoming features

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

Recent updates / changelog

  • You can override config with command line args, e.g. node example webpack.offline=false, using server/config.js trait.

  • You can now handle interactive terminal input with server/stdin.js trait.

  • ololog logging facility is now separate project (redesigned from a scratch)

  • meta-fields facility now available as a separate NPM module.

  • webpack server trait now supports compress option for crunching scripts with Google Closure Compiler.

  • 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...

Running example app

node example

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).

Server app framework

require ('./useless')

UselessApp = $singleton (Component, {

    $defaults: {
        webpackEntries: {
            entry: {
                'shared': { // duplicate code will be extracted to shared.js
                    'useless.client':   "./node_modules/useless/build/useless.client.js",
                    'useless.devtools': "./node_modules/useless/build/useless.devtools.js",
                    'index':            "./example/index.js",
                }
            }
        },
        config: {
            webpack: {
                hotReload: true
            }
        }
    },

    $depends: [
        require ('./server/supervisor'), // for auto-reload on code change
        require ('./server/webpack'),
        require ('./server/http')
    ],

/*  Members starting with "/" are HTTP request handlers         */

    '/hello-world':       () => "Hello world!",          // text/plain; charset=utf-8
    '/hello-world/json':  () => ({ foo: 42, bar: 777 }), // application/json; charset=utf-8

/*  File serving  */

    '/':             () => $this.file ('./static/index.html'), // $this is a smart alias for `this`, accessible from anywhere in the request execution context
    '/static/:file': () => $this.file ('./static'),            // any file from ./static folder

/*  Query params matching  */

    '/sqr?x={\\d+}':          ({ x    }) => Math.pow (Number (x),         2),  // x²
    '/pow?x={\\d+}&n={\\d+}': ({ x, n }) => Math.pow (Number (x), Number (n)), // x^n
                 
/*  Put your JSONAPI stuff in /api    */

    '/api': { // tree-style definitions are supported
        
        'login':  { post: async () => $this.doLogin (await $this.receiveJSON) },
        '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.               */

    async doLogin ({ email, password }) {

        if (await this.findUser ({ email, password })) {

            $http.setCookies ({ email, password })

        } else {

            throw new Error ('Wrong credentials')
        }
    },

    async findUser (criteria) { /* ... */ },

    init () {

        log.ok ('App started')
    }
})

Example report generated from a Promise chain:

Promise stack demo

Following are $traits defined at useless/server:

Macro processor for prototype definitions

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, { /* ... */ })

Component model

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)

Multicast model for method calls with simple functional I/O

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

Bindable methods for ad-hoc code injection

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

Math utility for front-end works

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)

Error handling

node.js stacktrace

Panic.js demo

  • 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)

Test framework

How-to & Examples

assertion demo

assertion demo

  • 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)

And more..

0.1.355

6 years ago

0.1.354

6 years ago

0.1.353

6 years ago

0.1.352

6 years ago

0.1.351

6 years ago

0.1.350

6 years ago

0.1.349

6 years ago

0.1.348

7 years ago

0.1.347

7 years ago

0.1.346

7 years ago

0.1.345

7 years ago

0.1.344

7 years ago

0.1.343

7 years ago

0.1.342

7 years ago

0.1.341

7 years ago

0.1.340

7 years ago

0.1.339

7 years ago

0.1.338

7 years ago

0.1.337

7 years ago

0.1.336

7 years ago

0.1.335

7 years ago

0.1.334

7 years ago

0.1.333

7 years ago

0.1.332

7 years ago

0.1.331

7 years ago

0.1.330

7 years ago

0.1.329

7 years ago

0.1.328

7 years ago

0.1.327

7 years ago

0.1.326

7 years ago

0.1.325

7 years ago

0.1.324

7 years ago

0.1.323

7 years ago

0.1.322

7 years ago

0.1.321

7 years ago

0.1.320

7 years ago

0.1.319

7 years ago

0.1.318

7 years ago

0.1.317

7 years ago

0.1.316

7 years ago

0.1.315

7 years ago

0.1.314

7 years ago

0.1.313

7 years ago

0.1.310

7 years ago

0.1.309

7 years ago

0.1.308

7 years ago

0.1.306

7 years ago

0.1.305

7 years ago

0.1.304

7 years ago

0.1.303

7 years ago

0.1.302

7 years ago

0.1.301

7 years ago

0.1.300

7 years ago

0.1.299

7 years ago

0.1.298

7 years ago

0.1.297

7 years ago

0.1.296

7 years ago

0.1.295

7 years ago

0.1.294

7 years ago

0.1.293

7 years ago

0.1.292

7 years ago

0.1.291

7 years ago

0.1.289

7 years ago

0.1.288

7 years ago

0.1.287

7 years ago

0.1.286

7 years ago

0.1.285

7 years ago

0.1.284

7 years ago

0.1.283

7 years ago

0.1.282

7 years ago

0.1.281

7 years ago

0.1.280

7 years ago

0.1.279

7 years ago

0.1.278

7 years ago

0.1.277

7 years ago

0.1.276

7 years ago

0.1.275

7 years ago

0.1.274

7 years ago

0.1.272

8 years ago

0.1.271

8 years ago

0.1.270

8 years ago

0.1.268

8 years ago

0.1.267

8 years ago

0.1.266

8 years ago

0.1.265

8 years ago

0.1.264

8 years ago

0.1.263

8 years ago

0.1.262

8 years ago

0.1.261

8 years ago

0.1.260

8 years ago

0.1.259

8 years ago

0.1.258

8 years ago

0.1.257

8 years ago

0.1.256

8 years ago

0.1.255

8 years ago

0.1.254

8 years ago

0.1.253

8 years ago

0.1.252

8 years ago

0.1.251

8 years ago

0.1.250

8 years ago

0.1.249

8 years ago

0.1.248

8 years ago

0.1.247

8 years ago

0.1.246

8 years ago

0.1.245

8 years ago

0.1.244

8 years ago

0.1.243

8 years ago

0.1.242

8 years ago

0.1.241

8 years ago

0.1.240

8 years ago

0.1.239

8 years ago

0.1.238

8 years ago

0.1.237

8 years ago

0.1.236

8 years ago

0.0.236

8 years ago

0.0.234

8 years ago

0.0.233

8 years ago

0.0.232

8 years ago

0.0.231

8 years ago

0.0.230

8 years ago

0.0.229

8 years ago

0.0.228

8 years ago

0.0.227

8 years ago

0.0.222

8 years ago

0.0.221

8 years ago

0.0.220

8 years ago

0.0.219

8 years ago

0.0.218

8 years ago

0.0.217

8 years ago

0.0.216

8 years ago

0.0.215

8 years ago

0.0.214

8 years ago

0.0.213

8 years ago

0.0.212

8 years ago

0.0.211

8 years ago

0.0.210

8 years ago

0.0.209

8 years ago

0.0.208

8 years ago

0.0.207

8 years ago

0.0.206

8 years ago

0.0.205

8 years ago

0.0.204

8 years ago

0.0.203

8 years ago

0.0.202

8 years ago

0.0.201

8 years ago

0.0.200

8 years ago

0.0.199

8 years ago

0.0.198

8 years ago

0.0.197

8 years ago

0.0.196

8 years ago

0.0.195

8 years ago

0.0.194

8 years ago

0.0.193

8 years ago

0.0.192

8 years ago

0.0.191

8 years ago

0.0.190

8 years ago

0.0.189

8 years ago

0.0.188

8 years ago

0.0.187

8 years ago

0.0.186

8 years ago

0.0.185

8 years ago

0.0.184

8 years ago

0.0.183

8 years ago

0.0.182

8 years ago

0.0.181

8 years ago

0.0.180

8 years ago

0.0.179

8 years ago

0.0.178

8 years ago

0.0.177

8 years ago

0.0.176

8 years ago

0.0.175

8 years ago

0.0.174

8 years ago

0.0.171

8 years ago

0.0.170

8 years ago

0.0.169

8 years ago

0.0.168

8 years ago

0.0.167

8 years ago

0.0.166

8 years ago

0.0.165

8 years ago

0.0.164

8 years ago

0.0.163

8 years ago

0.0.162

8 years ago

0.0.161

8 years ago

0.0.160

8 years ago

0.0.159

8 years ago

0.0.158

8 years ago

0.0.157

8 years ago

0.0.156

8 years ago

0.0.154

8 years ago

0.0.153

8 years ago

0.0.152

8 years ago

0.0.151

8 years ago

0.0.150

8 years ago

0.0.149

8 years ago

0.0.148

8 years ago

0.0.147

8 years ago

0.0.146

8 years ago

0.0.145

8 years ago

0.0.144

8 years ago

0.0.143

8 years ago

0.0.142

8 years ago

0.0.141

8 years ago

0.0.140

8 years ago

0.0.139

8 years ago

0.0.138

8 years ago

0.0.137

8 years ago

0.0.136

8 years ago

0.0.134

8 years ago

0.0.131

8 years ago

0.0.130

8 years ago

0.0.129

8 years ago

0.0.128

8 years ago

0.0.127

8 years ago

0.0.126

8 years ago

0.0.125

8 years ago

0.0.122

8 years ago

0.0.120

8 years ago

0.0.119

8 years ago

0.0.118

8 years ago

0.0.117

8 years ago

0.0.116

8 years ago

0.0.115

8 years ago

0.0.114

8 years ago

0.0.113

8 years ago

0.0.112

8 years ago

0.0.111

8 years ago

0.0.110

8 years ago

0.0.109

8 years ago

0.0.108

8 years ago

0.0.107

8 years ago

0.0.106

8 years ago

0.0.105

8 years ago

0.0.104

8 years ago

0.0.103

8 years ago

0.0.102

8 years ago

0.0.101

8 years ago

0.0.100

8 years ago

0.0.99

8 years ago

0.0.98

8 years ago

0.0.97

8 years ago

0.0.96

8 years ago

0.0.95

8 years ago

0.0.94

8 years ago

0.0.93

8 years ago

0.0.92

8 years ago

0.0.91

8 years ago

0.0.90

8 years ago

0.0.89

8 years ago

0.0.88

8 years ago

0.0.87

8 years ago

0.0.86

8 years ago

0.0.85

8 years ago

0.0.84

8 years ago

0.0.83

8 years ago

0.0.82

8 years ago

0.0.81

8 years ago

0.0.80

8 years ago

0.0.79

8 years ago

0.0.78

8 years ago

0.0.77

8 years ago

0.0.76

8 years ago

0.0.75

8 years ago

0.0.74

8 years ago

0.0.73

8 years ago

0.0.72

8 years ago

0.0.71

8 years ago

0.0.70

8 years ago

0.0.69

8 years ago

0.0.68

8 years ago

0.0.67

8 years ago

0.0.66

8 years ago

0.0.65

8 years ago

0.0.64

8 years ago

0.0.63

8 years ago

0.0.62

8 years ago

0.0.61

8 years ago

0.0.60

8 years ago

0.0.59

8 years ago

0.0.58

8 years ago

0.0.57

8 years ago

0.0.56

8 years ago

0.0.55

8 years ago

0.0.54

8 years ago

0.0.53

8 years ago

0.0.52

8 years ago

0.0.51

9 years ago

0.0.50

9 years ago

0.0.49

9 years ago

0.0.48

9 years ago

0.0.47

9 years ago

0.0.46

9 years ago

0.0.45

9 years ago

0.0.44

9 years ago

0.0.43

9 years ago

0.0.42

9 years ago

0.0.41

9 years ago

0.0.40

9 years ago

0.0.39

9 years ago

0.0.38

9 years ago

0.0.37

9 years ago

0.0.36

9 years ago

0.0.35

9 years ago

0.0.34

9 years ago

0.0.33

9 years ago

0.0.32

9 years ago

0.0.31

9 years ago

0.0.30

9 years ago

0.0.29

9 years ago

0.0.28

9 years ago

0.0.27

9 years ago

0.0.26

9 years ago

0.0.25

9 years ago

0.0.24

9 years ago

0.0.23

9 years ago

0.0.22

9 years ago

0.0.21

9 years ago

0.0.20

9 years ago

0.0.19

9 years ago

0.0.18

9 years ago

0.0.17

9 years ago

0.0.16

9 years ago

0.0.15

9 years ago

0.0.14

9 years ago

0.0.13

9 years ago

0.0.12

9 years ago

0.0.11

9 years ago

0.0.10

9 years ago

0.0.9

9 years ago

0.0.8

9 years ago

0.0.7

9 years ago

0.0.6

9 years ago

0.0.5

9 years ago

0.0.4

9 years ago

0.0.3

9 years ago

0.0.2

9 years ago

0.0.0

9 years ago

0.0.1

13 years ago