etnbrd/flx-compiler

View on GitHub
lib/js-printer/builders.js

Summary

Maintainability
B
6 hrs
Test Coverage
'use strict';


var b = require('ast-types').builders,
    esprima = require('esprima');

function requireflx() {
  return b.variableDeclaration('var', [
      b.variableDeclarator(b.identifier('flx'), b.callExpression(
          b.identifier('require'), // Anonymize the function expression.
          [b.literal('flx')]
          ))
      ]);
}

function starter(next) {
  return b.callExpression(
    b.memberExpression(
      b.identifier('flx'),
      b.identifier('start'),
      false
    ),
    [
      b.callExpression(
        b.memberExpression(
          b.identifier('flx'),
          b.identifier('m'),
          false
        ),
        [
          b.literal(next),
          b.objectExpression([])
        ]
      )
    ]
  );
}

function startPlaceholder(next, signature) {

  var _signature = [];
  if (signature) {
    _signature = Object.keys(signature).map(function(need) {
      return need + ': ' + need + ',\n'; 

      // b.property('init', b.identifier(need), b.identifier(need));
    });
  }

  _signature = _signature.join('\n');

  var code = [
    'function placeholder() {',
    '  return flx.start(flx.m(\'' + next + '\', {',
    '    _args: arguments,',
    '    _sign: {' + _signature + '}',
    '  }));',
    '}'
  ].join('\n');

  var ast = esprima.parse(code);

  // TODO WAT ?
  ast.body[0].type = 'FunctionExpression';

  return ast.body[0];
}

function register(name, fn, scope) {

  function _register(name, fn, scope) { 
    var _scope = b.objectExpression([]);
    if (scope) {
      _scope = b.objectExpression(
            Object.keys(scope).map(function(id) {
              return b.property('init', b.identifier(id), b.identifier(id));
            })
          );
    }

    return b.expressionStatement(
        b.callExpression(
          b.memberExpression(b.identifier('flx'), b.identifier('register'), false),
          [
            b.literal(name),
            fn,
            _scope
          ])
        );
  }

  function _capsule(fn) {

    var templates = {
      capsule: function capsule(msg) {
          (function reply(truc) { return this; }).apply(this, msg._args);
      }
    }

    var ast = esprima.parse(templates.capsule.toString()).body[0];
    ast.type = 'FunctionExpression';

    // console.log(fn.body);

    // START
    if (fn.type === 'FunctionDeclaration'){
      ast.body.body[0].expression.callee.object.body = fn.body;
      ast.body.body[0].expression.callee.object.params = fn.params;
      ast.body.body[0].expression.callee.object.id = fn.id;
    }
    // START
    if (fn.type === 'FunctionExpression') {
      ast.body.body[0].expression.callee.object = fn;
    }

    // POST
    if (fn.type === 'CallExpression') {

      var cb = fn.rupturePoint.cb;
      var fecb = b.functionExpression(cb.id, cb.params, cb.body);

      fn.rupturePoint.cb = fecb;
      ast.body.body[0].expression = fn;

      // console.log(fn.rupturePoint.cb);


      // TODO here we plug some pipes : the put a .bind(this) in the callback to let it access the fluxion context, instead of the global.
      fn.rupturePoint.call.arguments[fn.rupturePoint.cbIndex] = b.callExpression(b.memberExpression(fn.rupturePoint.cb, b.identifier('bind'), false),[b.thisExpression()]);
    }

    // TODO : UH WAT ??? I thin what I meant was : why the fuck do I need to deep copy this function ?

    return ast;
  }

  return _register(name, _capsule(fn), scope);
}

function signatureModifier(name) {
  return b.memberExpression(
    b.memberExpression(
      b.identifier('msg'),
      b.identifier('_sign'),
      false
    ),
    b.identifier(name),
    false
   );
}

function scopeModifier(name) {
  return b.memberExpression (
    b.thisExpression(),
    b.identifier(name),
    false
  );
}

function syncModifier(name) {
  return scopeModifier(name);
}

function syncBuilder(sync, flx) {

  // TODO this is a quick fix.
  // we need to make sure we don't send a variable to a fluxion that don't need it.

  // TODO remove the second argument, and retrieve the current flx by other means.

  // TODO there is still some bugs with Problem#5 : the value of _rep sent to the client is delayed by one request.
  var i,
      upstreams = {};


  for (i in sync) { var dep = sync[i];
    upstreams = dep.variable.references.reduce(function(upstreams, ref) {
      if (ref.from.flx.name !== flx.name && !ref.from.flx.root) {
        upstreams[ref.from.flx.name] = ref.from.flx;
      }
      return upstreams;
    }, upstreams);
  }

  var deps = Object.keys(sync).reduce(function(deps, sync) {
    return deps += sync + ': this.' + sync;
  }, '');

  var code = [
    'flx.start(flx.m(\'' + Object.keys(upstreams).join('\', \'') + '\', {_update: {' + deps + '}}))'
  ].join('\n');

  return esprima.parse(code);

}

function fn(body) {
  return b.functionExpression(b.identifier('root'), [], b.blockStatement(body));
}

function postPlaceholder(next, signature, args) {

  var _signature = [];
  if (signature) {
    _signature = Object.keys(signature).map(function(need) {
      return need + ': ' + need + ',\n'; 

      // b.property('init', b.identifier(need), b.identifier(need));
    });
  }

  _signature = _signature.join('\n');

  // TODO 
  // var templates = {
  //   placeholder :
  //     function placeholder() {
  //       return flx.post(flx.m(next, {
  //         _args: arguments,
  //         _sign: {}
  //       }));
  //     }
  //   }
  // }

  // var ast = esprima.parse(templates.placeholder.toString()).body[0];

  // var code = [
  //   'function placeholder() {',
  //   '  return flx.post(flx.m(\'' + next + '\', {',
  //   '    _args: arguments,',
  //   '    _sign: {' + _signature + '}',
  //   '  }));',
  //   '}'
  // ].join('\n');

  var code = [
    '  flx.post(flx.m(\'' + next + '\', {',
    '    _args: arguments,',
    '    _sign: {' + _signature + '}',
    '  }));'
  ].join('\n');


  var ast = esprima.parse(code).body[0].expression;

  // ast.type = 'FunctionExpression';
  // ast.params = args; // TODO Why the fuck did I put this line here ? must be a good reason, can't remember it though.

  return ast;
}

module.exports = {
  requireflx: requireflx,
  starter: starter,

  register: register,
  start: startPlaceholder,
  post: postPlaceholder,

  signatureModifier: signatureModifier,
  scopeModifier: scopeModifier,
  syncModifier: syncModifier,

  syncBuilder: syncBuilder,

  fnCapsule: fn
};