<commit_before>var net = require('net');
var util = require('./index');
var logger = require('./logger');
var config = require('../config');
var socketMgr = require('../socket-mgr');

if (!(config.reqCacheSize > 0) || config.reqCacheSize < 600) {
  config.reqCacheSize = 600;
}

if (!(config.frameCacheSize > 0) || config.frameCacheSize < 512) {
  config.frameCacheSize = 512;
}

var TIMEOUT = 36000;
var BINDING_TIMEOUT = TIMEOUT - 16000;
var CLEAR_INTERVAL = 5000;
var CACHE_TIME = CLEAR_INTERVAL * 2;
var MAX_LENGTH = config.reqCacheSize;
var OVERFLOW_LENGTH = MAX_LENGTH * 5;
var MIN_LENGTH = MAX_LENGTH - 100;
var MAX_FRAMES_LENGTH = config.frameCacheSize;
var COUNT = 100;
var count = 0;
var ids = [];
var reqData = {};
var frames = [];
var proxy, binded, timeout, interval, timer;

function disable() {
  proxy.removeListener('request', handleRequest);
  proxy.removeListener('frame', handleFrame);
  ids = [];
  reqData = {};
  frames = [];
  interval && clearInterval(interval);
  interval = null;
  binded = false;
  clearTimeout(timer);
  timer = null;
}

function resetTimer() {
  timer = null;
}

function enable() {
  if (timer) {
    return;
  }
  timer = setTimeout(resetTimer, BINDING_TIMEOUT);
  if (!binded) {
    binded = true;
    proxy.on('request', handleRequest);
    proxy.on('frame', handleFrame);
  }
  clearTimeout(timeout);
  timeout = setTimeout(disable, TIMEOUT);
  if (!interval) {
    interval = setInterval(clearCache, CLEAR_INTERVAL);
  }
}

/**
* 如果超过最大缓存数，清理如下请求数据：
* 1. 已经请求结束且结束时间超过10秒
* 2. 请求#1前面的未结束且未被ui读取过的请求
*/
function clearCache() {
  if (frames.length > MAX_FRAMES_LENGTH) {
    frames.splice(0, 100);
  }
  var len = ids.length;
  if (len <= MAX_LENGTH) {
    return;
  }

  var now = Date.now();
  var _ids = [];
  var overflow = len - OVERFLOW_LENGTH;
  if (overflow >= 0) {
    overflow = overflow + MAX_LENGTH * 2;
  }
  for (var i = 0; i < len; i++) {
    var id = ids[i];
    var curData = reqData[id];
    if (i > overflow &&
      (curData.endTime ? now - curData.endTime < CACHE_TIME : now - curData.startTime < TIMEOUT)) {
      _ids.push(id);
    } else {
      delete reqData[id];
      if (--len <= MIN_LENGTH) {
        ids = _ids.concat(ids.slice(i + 1));
        return;
      }
    }
  }
  ids = _ids;
}

function getIds(startTime, count, lastRowId) {
  startTime = startTime || lastRowId;
  if (!startTime) {
    return ids.slice(-count);
  }
  var index = 0;
  if (startTime !== '0') {
    index = ids.indexOf(startTime) + 1;
  }
  return ids.slice(index, index + count);
}

function getList(ids) {
  if (!Array.isArray(ids)) {
    return [];
  }
  return ids.map(function(id, i) {
    return reqData[id];
  });
}

function handleRequest(req) {
  var curData = req.data;
  var id = curData.id = curData.id || (curData.startTime + '-' + ++count);
  reqData[id] = curData;
  ids.indexOf(id) === -1 && ids.push(id);
}

function decodeData(frame) {
  if (frame.base64 == null) {
    frame.base64 = frame.bin ? frame.bin.toString('base64') : '';
    frame.bin = '';
  }
  return frame;
}
function handleFrame(data) {
  frames.push(data);
}

function getFrames(curReqId, lastFrameId) {
  if (!curReqId) {
    return;
  }
  var result = [];
  var count = 16;
  for (var i = frames.length - 1; i >= 0; i--) {
    var frame = frames[i];
    if (frame.reqId === curReqId && (lastFrameId ? frame.frameId > lastFrameId : count > 0)) {
      result.push(decodeData(frame));
      if (--count <= 0) {
        break;
      }
    }
  }
  return result.reverse();
}

module.exports = function init(_proxy) {
  proxy = _proxy;
  enable();
/**
* options: {
* 		startTime: timestamp || timestamp + '-' + count
* 		count: 获取新数据的数量
* 		ids: 请未结束的id列表
* }
*
* @param options
*/
  function formatFilter(filter, clientIp) {
    if (!filter.url && !filter.name && !filter.value && !filter.ip) {
      return;
    }
    var url = util.trimStr(filter.url).toLowerCase();
    var name = util.trimStr(filter.name).toLowerCase();
    var value = util.trimStr(filter.value).toLowerCase();
    var ip = util.trimStr(filter.ip);
    var list = [];
    if (ip === 'self') {
      ip = clientIp;
    } else if (ip && !net.isIP(ip)) {
      ip.split(',').forEach(function(item) {
        item = item.trim();
        if (item === 'self') {
          item = clientIp;
        }
        if (net.isIP(item) && list.indexOf(item) === -1) {
          list.push(item);
        }
      });
      ip = null;
    }
    var result;
    if (url) {
      result = {};
      result.url = url;
    }
    if (name && value) {
      result = result || {};
      result.name = name;
      result.value = value;
    }
    if (ip) {
      result = result || {};
      result.ip = ip;
    }
    if (list.length) {
      result = result || {};
      result.ipList = list.slice(0, 16);
    }
    return result;
  }
  function checkClientIp(item, filter) {
    var clientIp = item.req.ip;
    if (filter.ip && clientIp !== filter.ip) {
      return false;
    }
    var ipList = filter.ipList;
    if (!ipList) {
      return true;
    }
    var len = ipList.length;
    if (len < 3) {
      if (ipList[0] === clientIp) {
        return true;
      }
      if (ipList[1] && ipList[1] === clientIp) {
        return true;
      }
    } else {
      for (var i = 0; i < len; i++) {
        var ip = ipList[i];
        if (ip === clientIp) {
          return true;
        }
      }
    }
    return false;
  }
  function checkItem(item, filter) {
    if (!item) {
      return false;
    }
    if (!checkClientIp(item, filter)) {
      return false;
    }
    if (filter.url && item.url.toLowerCase().indexOf(filter.url) === -1) {
      return false;
    }
    if (!filter.name) {
      return true;
    }
    var value = item.req.headers[filter.name];
    if (!value || typeof value !== 'string') {
      if (!Array.isArray(value)) {
        return false;
      }
      value = value.join('\n');
    }
    value = value.toLowerCase();
    if (value.indexOf(filter.value) !== -1) {
      return true;
    }
    return value.indexOf(util.encodeURIComponent(filter.value).toLowerCase()) !== -1;
  }
  proxy.getLastDataId = function() {
    return ids[ids.length - 1];
  };

  function toBase64String(data) {
    if (Buffer.isBuffer(data.body)) {
      data.base64 = data.body.toString('base64');
      data.body = '';
    }
  }

  proxy.enableCapture = enable;
  proxy.getItem = function(id) {
    var item = reqData[id];
    if (item) {
      toBase64String(item.req);
      toBase64String(item.res);
    }
    return item;
  };

  proxy.getData = function(options, clientIp) {
    enable();
    options = options || {};
    var filter = formatFilter(options, clientIp);
    var data = {};
    var count = options.count;
    var startTime = options.startTime;
    var clearNetwork = count == 0 || startTime == -2;
    if (!clearNetwork) {
      count = count > 0 && count < COUNT ? +count : COUNT;
    }
    var newIds = (clearNetwork || startTime == -1) ? [] : getIds(startTime, count, options.lastRowId);
    var setData = function(item) {
      if (item) {
        var req = item.req;
        var res = item.res;
        toBase64String(req);
        toBase64String(res);
        if (config.secureFilter) {
          try {
            item = config.secureFilter(item, clientIp, filter) || item;
          } catch (e) {
            if (config.debugMode) {
              /* eslint-disable no-console */
              console.log(e);
            }
            logger.error(e);
          }
        }
        data[item.id] = item;
      }
    };
    if (newIds.length > 0) {
      if (filter) {
        var id = newIds[0];
        var index = ids.indexOf(newIds[0]);
        newIds = [];
        while(id && count > 0) {
          var item = reqData[id];
          if (checkItem(item, filter)) {
            setData(item);
            newIds.push(id);
            --count;
          }
          id = ids[++index];
        }
      } else if (!filter) {
        getList(newIds).forEach(setData);
      }
    }
    getList(options.ids).forEach(setData);
    var endId = ids[ids.length - 1];
    return {
      ids: options.ids || [],
      newIds: newIds,
      data: data,
      lastId: clearNetwork ? endId : newIds[newIds.length - 1],
      endId: endId,
      frames: getFrames(options.curReqId, options.lastFrameId),
      socketStatus: socketMgr.getStatus(options.curReqId)
    };
  };
};
<commit_msg>refactor: data server<commit_after>var net = require('net');
var util = require('./index');
var logger = require('./logger');
var config = require('../config');
var socketMgr = require('../socket-mgr');

if (!(config.reqCacheSize > 0) || config.reqCacheSize < 600) {
  config.reqCacheSize = 600;
}

if (!(config.frameCacheSize > 0) || config.frameCacheSize < 512) {
  config.frameCacheSize = 512;
}

var TIMEOUT = 36000;
var BINDING_TIMEOUT = 6000;
var CLEAR_INTERVAL = 5000;
var CACHE_TIME = CLEAR_INTERVAL * 2;
var MAX_LENGTH = config.reqCacheSize;
var OVERFLOW_LENGTH = MAX_LENGTH * 5;
var MIN_LENGTH = MAX_LENGTH - 100;
var MAX_FRAMES_LENGTH = config.frameCacheSize;
var COUNT = 100;
var count = 0;
var ids = [];
var reqData = {};
var frames = [];
var proxy, binded, timeout, interval, timer;

function disable() {
  proxy.removeListener('request', handleRequest);
  proxy.removeListener('frame', handleFrame);
  ids = [];
  reqData = {};
  frames = [];
  interval && clearInterval(interval);
  interval = null;
  binded = false;
  clearTimeout(timer);
  timer = null;
}

function resetTimer() {
  timer = null;
}

function enable() {
  if (timer) {
    return;
  }
  timer = setTimeout(resetTimer, BINDING_TIMEOUT);
  if (!binded) {
    binded = true;
    proxy.on('request', handleRequest);
    proxy.on('frame', handleFrame);
  }
  clearTimeout(timeout);
  timeout = setTimeout(disable, TIMEOUT);
  if (!interval) {
    interval = setInterval(clearCache, CLEAR_INTERVAL);
  }
}

/**
* 如果超过最大缓存数，清理如下请求数据：
* 1. 已经请求结束且结束时间超过10秒
* 2. 请求#1前面的未结束且未被ui读取过的请求
*/
function clearCache() {
  if (frames.length > MAX_FRAMES_LENGTH) {
    frames.splice(0, 100);
  }
  var len = ids.length;
  if (len <= MAX_LENGTH) {
    return;
  }

  var now = Date.now();
  var _ids = [];
  var overflow = len - OVERFLOW_LENGTH;
  if (overflow >= 0) {
    overflow = overflow + MAX_LENGTH * 2;
  }
  for (var i = 0; i < len; i++) {
    var id = ids[i];
    var curData = reqData[id];
    if (i > overflow &&
      (curData.endTime ? now - curData.endTime < CACHE_TIME : now - curData.startTime < TIMEOUT)) {
      _ids.push(id);
    } else {
      delete reqData[id];
      if (--len <= MIN_LENGTH) {
        ids = _ids.concat(ids.slice(i + 1));
        return;
      }
    }
  }
  ids = _ids;
}

function getIds(startTime, count, lastRowId) {
  startTime = startTime || lastRowId;
  if (!startTime) {
    return ids.slice(-count);
  }
  var index = 0;
  if (startTime !== '0') {
    index = ids.indexOf(startTime) + 1;
  }
  return ids.slice(index, index + count);
}

function getList(ids) {
  if (!Array.isArray(ids)) {
    return [];
  }
  return ids.map(function(id, i) {
    return reqData[id];
  });
}

function handleRequest(req) {
  var curData = req.data;
  var id = curData.id = curData.id || (curData.startTime + '-' + ++count);
  reqData[id] = curData;
  ids.indexOf(id) === -1 && ids.push(id);
}

function decodeData(frame) {
  if (frame.base64 == null) {
    frame.base64 = frame.bin ? frame.bin.toString('base64') : '';
    frame.bin = '';
  }
  return frame;
}
function handleFrame(data) {
  frames.push(data);
}

function getFrames(curReqId, lastFrameId) {
  if (!curReqId) {
    return;
  }
  var result = [];
  var count = 16;
  for (var i = frames.length - 1; i >= 0; i--) {
    var frame = frames[i];
    if (frame.reqId === curReqId && (lastFrameId ? frame.frameId > lastFrameId : count > 0)) {
      result.push(decodeData(frame));
      if (--count <= 0) {
        break;
      }
    }
  }
  return result.reverse();
}

module.exports = function init(_proxy) {
  proxy = _proxy;
  enable();
/**
* options: {
* 		startTime: timestamp || timestamp + '-' + count
* 		count: 获取新数据的数量
* 		ids: 请未结束的id列表
* }
*
* @param options
*/
  function formatFilter(filter, clientIp) {
    if (!filter.url && !filter.name && !filter.value && !filter.ip) {
      return;
    }
    var url = util.trimStr(filter.url).toLowerCase();
    var name = util.trimStr(filter.name).toLowerCase();
    var value = util.trimStr(filter.value).toLowerCase();
    var ip = util.trimStr(filter.ip);
    var list = [];
    if (ip === 'self') {
      ip = clientIp;
    } else if (ip && !net.isIP(ip)) {
      ip.split(',').forEach(function(item) {
        item = item.trim();
        if (item === 'self') {
          item = clientIp;
        }
        if (net.isIP(item) && list.indexOf(item) === -1) {
          list.push(item);
        }
      });
      ip = null;
    }
    var result;
    if (url) {
      result = {};
      result.url = url;
    }
    if (name && value) {
      result = result || {};
      result.name = name;
      result.value = value;
    }
    if (ip) {
      result = result || {};
      result.ip = ip;
    }
    if (list.length) {
      result = result || {};
      result.ipList = list.slice(0, 16);
    }
    return result;
  }
  function checkClientIp(item, filter) {
    var clientIp = item.req.ip;
    if (filter.ip && clientIp !== filter.ip) {
      return false;
    }
    var ipList = filter.ipList;
    if (!ipList) {
      return true;
    }
    var len = ipList.length;
    if (len < 3) {
      if (ipList[0] === clientIp) {
        return true;
      }
      if (ipList[1] && ipList[1] === clientIp) {
        return true;
      }
    } else {
      for (var i = 0; i < len; i++) {
        var ip = ipList[i];
        if (ip === clientIp) {
          return true;
        }
      }
    }
    return false;
  }
  function checkItem(item, filter) {
    if (!item) {
      return false;
    }
    if (!checkClientIp(item, filter)) {
      return false;
    }
    if (filter.url && item.url.toLowerCase().indexOf(filter.url) === -1) {
      return false;
    }
    if (!filter.name) {
      return true;
    }
    var value = item.req.headers[filter.name];
    if (!value || typeof value !== 'string') {
      if (!Array.isArray(value)) {
        return false;
      }
      value = value.join('\n');
    }
    value = value.toLowerCase();
    if (value.indexOf(filter.value) !== -1) {
      return true;
    }
    return value.indexOf(util.encodeURIComponent(filter.value).toLowerCase()) !== -1;
  }
  proxy.getLastDataId = function() {
    return ids[ids.length - 1];
  };

  function toBase64String(data) {
    if (Buffer.isBuffer(data.body)) {
      data.base64 = data.body.toString('base64');
      data.body = '';
    }
  }

  proxy.enableCapture = enable;
  proxy.getItem = function(id) {
    var item = reqData[id];
    if (item) {
      toBase64String(item.req);
      toBase64String(item.res);
    }
    return item;
  };

  proxy.getData = function(options, clientIp) {
    enable();
    options = options || {};
    var filter = formatFilter(options, clientIp);
    var data = {};
    var count = options.count;
    var startTime = options.startTime;
    var clearNetwork = count == 0 || startTime == -2;
    if (!clearNetwork) {
      count = count > 0 && count < COUNT ? +count : COUNT;
    }
    var newIds = (clearNetwork || startTime == -1) ? [] : getIds(startTime, count, options.lastRowId);
    var setData = function(item) {
      if (item) {
        var req = item.req;
        var res = item.res;
        toBase64String(req);
        toBase64String(res);
        if (config.secureFilter) {
          try {
            item = config.secureFilter(item, clientIp, filter) || item;
          } catch (e) {
            if (config.debugMode) {
              /* eslint-disable no-console */
              console.log(e);
            }
            logger.error(e);
          }
        }
        data[item.id] = item;
      }
    };
    if (newIds.length > 0) {
      if (filter) {
        var id = newIds[0];
        var index = ids.indexOf(newIds[0]);
        newIds = [];
        while(id && count > 0) {
          var item = reqData[id];
          if (checkItem(item, filter)) {
            setData(item);
            newIds.push(id);
            --count;
          }
          id = ids[++index];
        }
      } else if (!filter) {
        getList(newIds).forEach(setData);
      }
    }
    getList(options.ids).forEach(setData);
    var endId = ids[ids.length - 1];
    return {
      ids: options.ids || [],
      newIds: newIds,
      data: data,
      lastId: clearNetwork ? endId : newIds[newIds.length - 1],
      endId: endId,
      frames: getFrames(options.curReqId, options.lastFrameId),
      socketStatus: socketMgr.getStatus(options.curReqId)
    };
  };
};
<|endoftext|>


<commit_before>/*
Copyright 2017 New Vector Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import dis from '../../../dispatcher';
import AccessibleButton from '../elements/AccessibleButton';

export default React.createClass({
    displayName: 'GroupInviteTile',

    propTypes: {
        group: PropTypes.object.isRequired,
    },

    onClick: function(e) {
        dis.dispatch({
            action: 'view_group',
            group_id: this.props.group.groupId,
        });
    },

    render: function() {
        const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
        const EmojiText = sdk.getComponent('elements.EmojiText');

        const groupName = this.props.group.name || this.props.group.groupId;

        const av = <BaseAvatar name={groupName} width={24} height={24} url={this.props.group.avatarUrl} />;

        const label = <EmojiText
            element="div"
            title={this.props.group.groupId}
            className="mx_RoomTile_name"
            dir="auto"
        >
            { groupName }
        </EmojiText>;

        const badge =
!
;

        return (
            <AccessibleButton className="mx_RoomTile mx_RoomTile_highlight" onClick={this.onClick}>

                    { av }

                    { label }
                    { badge }

            </AccessibleButton>
        );
    },
});
<commit_msg>Correctly display group invite<commit_after>/*
Copyright 2017 New Vector Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import dis from '../../../dispatcher';
import AccessibleButton from '../elements/AccessibleButton';

export default React.createClass({
    displayName: 'GroupInviteTile',

    propTypes: {
        group: PropTypes.object.isRequired,
    },

    onClick: function(e) {
        dis.dispatch({
            action: 'view_group',
            group_id: this.props.group.groupId,
        });
    },

    render: function() {
        const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
        const EmojiText = sdk.getComponent('elements.EmojiText');

        const groupName = this.props.group.name || this.props.group.groupId;

        const av = <BaseAvatar name={groupName} width={24} height={24} url={this.props.group.avatarUrl} />;

        const label = <EmojiText
            element="div"
            title={this.props.group.groupId}
            className="mx_RoomTile_name mx_RoomTile_badgeShown"
            dir="auto"
        >
            { groupName }
        </EmojiText>;

        const badge =
!
;

        return (
            <AccessibleButton className="mx_RoomTile mx_RoomTile_highlight" onClick={this.onClick}>

                    { av }

                    { label }
                    { badge }

            </AccessibleButton>
        );
    },
});
<|endoftext|>


<commit_before>// Require dependencies
const fs    = require('fs-extra');
const parse = require('parse-comments');

/**
 * Create Parser class
 */
class Parser {
  /**
   * Construct Parser class
   */
  constructor() {
    // Bind public methods
    this.task = this.task.bind(this);
    this.daemon = this.daemon.bind(this);
    this.controller = this.controller.bind(this);

    // Bind private methods
    this._acl = this._acl.bind(this);
    this._uploads = this._uploads.bind(this);
  }

  /**
   * Parse controller chunk
   *
   * @param   {*} chunk
   *
   * @returns {*}
   */
  controller(chunk) {
    // Get bundles
    const bundles = chunk.path.replace(/\\/g, '/').split('bundles/').pop();

    // Set default variables
    const file     = bundles.replace('.js', '');
    const data     = chunk.contents.toString();
    const comments = parse(data);

    // Set return
    const returns = {
      api     : {},
      calls   : [],
      menus   : {},
      routes  : [],
      classes : {},
      sockets : [],
    };

    // Set class in returns
    returns.classes[file] = {
      acl      : [],
      fail     : false,
      file,
      name     : '',
      desc     : '',
      mount    : '/',
      priority : 0,
    };

    // Loop comments
    for (const com of comments) {
      // Check if class
      if (com.comment.code.includes('class')) {
        // Set class
        returns.classes[file].name = com.comment.code.split('class')[1].split('extends')[0].trim();
        returns.classes[file].desc = com.description;

        // Check for mount
        if (com.acls) {
          returns.classes[file].acl = this._acl(com.acls);
        }

        if (com.fails) {
          returns.classes[file].fail = com.fails[0].description;
        }

        if (com.mounts) {
          returns.classes[file].mount = com.mounts[0].description;
        }

        if (com.priorities) {
          returns.classes[file].priority = parseInt(com.priorities[0].description, 10);
        }
      }

      // Alias variables to object props
      const classF = returns.classes[file];

      const comPrio = com.priorities;

      const comApiReq = com['api.request'];
      const comApiRes = com['api.response'];

      // Check routes
      if (com.routes) {
        // Set function
        let fn = com.comment.code.split('(')[0].trim();

        // Set fn
        fn = fn.split(' ').length > 1 ? fn.split(' ')[fn.split(' ').length - 1] : fn;

        // Loop routes
        for (let b = 0; b < com.routes.length; b += 1) {
          // Alias variables to object props
          const routeB = com.routes[b];
          const routeBDesc = routeB.description;
          const lowRouteBType = routeB.type.toLowerCase();

          let routeCache = null;

          if (com.caches) {
            const cacheB = com.caches[b];

            const cacheBDesc = cacheB.description;

            routeCache = {
              ttl  : com.ttl ? parseInt(com.ttl[0].description, 10) : (60 * 60 * 1000),
              name : cacheB.type ? cacheBDesc.toLowerCase().trim() : `${lowRouteBType.trim()}:${routeBDesc.trim()}`,
              type : cacheB.type ? cacheB.type.toLowerCase() : cacheBDesc.replace(/\{|\}/g, '').trim(),
            };
          }

          // Set route
          const route = {
            fn,
            acl      : com.acls ? classF.acl.concat(this._acl(com.acls)) : classF.acl,
            fail     : com.fails ? com.fails[0].description : classF.fail,
            type     : lowRouteBType,
            desc     : com.description,
            view     : com.views ? com.views[0].description : false,
            class    : file,
            cache    : routeCache,
            mount    : classF.mount,
            route    : routeB.description,
            title    : com.titles ? com.titles[0].description : false,
            layout   : com.layouts ? com.layouts[0].description : false,
            upload   : com.uploads ? this._uploads(com.uploads) : false,
            priority : comPrio ? parseInt(comPrio[0].description, 10) : classF.priority,
          };

          // Push to routes
          returns.routes.push(route);
        }

        // Add API documentation
        if (com.api) {
          // Get route
          const route = (classF.mount + com.routes[0].description).split('//').join('/');

          // Set logic
          returns.api[route] = {
            fn,
            acl   : com.acls ? classF.acl.concat(this._acl(com.acls)) : classF.acl,
            api   : com.api.replace('true', '').trim(),
            type  : 'route',
            route,
            class : {
              file,
              name : classF.name,
              desc : classF.desc,
            },
            title       : com.titles ? com.titles[0].description : com.description,
            method      : com.routes[0].type.toLowerCase(),
            upload      : com.uploads ? this._uploads(com.uploads) : false,
            request     : comApiReq ? eval(`(${comApiReq.replace('true', '').trim()})`) : null,
            response    : comApiReq ? eval(`(${comApiRes.replace('true', '').trim()})`) : null,
            description : com.description,
          };
        }

        // Check if menus
        if (com.menus) {
          // Loop menus
          for (const menu of com.menus) {
            // Set path
            let path = (classF.mount + (com.routes ? com.routes[0].description : '/')).split('//').join('/');

            // Add to path
            path = path.length > 1 ? path.replace(/\/$/, '') : path;

            // Check if menu exists
            if (!returns.menus[menu.type]) returns.menus[menu.type] = [];

            // Push to menus
            returns.menus[menu.type].push({
              acl      : com.acls ? classF.acl.concat(this._acl(com.acls)) : classF.acl,
              icon     : com.icons ? com.icons[0].description : false,
              route    : path,
              title    : menu.description,
              parent   : com.parents ? com.parents[0].description : false,
              priority : comPrio ? parseInt(comPrio[0].description, 10) : classF.priority,
            });
          }
        }
      }

      // Check sockets
      if (com.sockets) {
        // Set function
        let fn = com.comment.code.split('(')[0].trim();

        // Add to fn
        fn = fn.split(' ').length > 1 ? fn.split(' ')[fn.split(' ').length - 1] : fn;

        // Loop routes
        for (const sock of com.sockets) {
          // Set route
          const socket = {
            fn,
            acl      : com.acls ? classF.acl.concat(this._acl(com.acls)) : classF.acl,
            desc     : com.description,
            name     : sock.type ? sock.type : sock.description.replace(/\{|\}/g, ''),
            class    : file,
            priority : comPrio ? parseInt(comPrio[0].description, 10) : classF.priority,
          };

          // Push to routes
          returns.sockets.push(socket);
        }
      }

      // Check sockets
      if (com.calls) {
        // Set function
        let fn = com.comment.code.split('(')[0].trim();

        // Add to fn
        fn = fn.split(' ').length > 1 ? fn.split(' ')[fn.split(' ').length - 1] : fn;

        // Loop routes
        for (const call of com.calls) {
          // Set route
          const socket = {
            fn,
            acl      : com.acls ? classF.acl.concat(this._acl(com.acls)) : classF.acl,
            desc     : com.description,
            name     : call.type ? call.type : call.description.replace(/\{|\}/g, ''),
            class    : file,
            priority : comPrio ? parseInt(comPrio[0].description, 10) : classF.priority,
          };

          // Push to routes
          returns.calls.push(socket);
        }

        // Add API documentation
        if (com.api) {
          // Get route
          const route = (classF.mount + com.routes[0].description).split('//').join('/');

          // Set logic
          returns.api[route] = {
            fn,
            acl   : com.acls ? classF.acl.concat(this._acl(com.acls)) : classF.acl,
            api   : com.api.replace('true', '').trim(),
            call  : com.calls[0].type ? com.calls[0].type : com.calls[0].description.replace(/\{|\}/g, ''),
            type  : 'call',
            class : {
              file,
              name : classF.name,
              desc : classF.desc,
            },
            title       : com.titles ? com.titles[0].description : com.description,
            request     : com['api.request'] ? eval(`(${com['api.request'].replace('true', '').trim()})`) : null,
            response    : com['api.request'] ? eval(`(${com['api.response'].replace('true', '').trim()})`) : null,
            description : com.description,
          };
        }
      }
    }

    // Return returns
    return returns;
  }

  /**
   * Parse daemon chunk
   *
   * @param   {*} chunk
   *
   * @returns {*}
   */
  daemon(chunk) {
    // Get bundles
    const bundles = chunk.path.replace(/\\/g, '/').split('bundles/').pop();

    // Set default variables
    const file     = bundles.replace('.js', '');
    const data     = chunk.contents.toString();
    const comments = parse(data);

    // Set return
    const returns = {
      daemons : {},
    };

    // Set class in returns
    returns.daemons[file] = {
      name    : '',
      desc    : '',
      express : false,
      compute : false,
    };

    // Loop comments
    for (const com of comments) {
      // Check if class
      if (!com.comment.code.includes('class')) continue;

      // Set class
      returns.daemons[file].name = com.comment.code.split('class')[1].split('extends')[0].trim();
      returns.daemons[file].desc = com.description;

      // Set express and compute threads
      let express = false;
      let compute = false;

      // Check express
      if (com.express === 'true' || com.express === true) {
        // Set express true
        express = true;
      } else if (com.express && com.express.length && !Array.isArray(com.express)) {
        // Set express as array
        express = [parseInt(com.express, 10)];
      } else if (com.express && com.express.length && Array.isArray(com.express)) {
        express = com.express.map(Number);
      }

      // Check express
      if (com.compute === 'true' || com.compute === true) {
        // Set express true
        compute = true;
      } else if (com.compute && com.compute.length && !Array.isArray(com.compute)) {
        // Set express as array
        compute = [parseInt(com.compute, 10)];
      } else if (com.compute && com.compute.length && Array.isArray(com.compute)) {
        compute = com.compute.map(Number);
      }

      // Check for mount
      if (com.express) returns.daemons[file].express = express;
      if (com.compute) returns.daemons[file].compute = compute;
    }

    // Return returns
    return returns;
  }

  /**
   * Parse daemon chunk
   *
   * @param   {*} path
   *
   * @returns {*}
   */
  task(path) {
    // Get bundles
    const bundles = path.replace(/\\/g, '/').split('bundles/');

    // Set default variables
    const file     = bundles.join('bundles/');
    const data     = fs.readFileSync(path, 'utf8');
    const comments = parse(data);

    // Set class in returns
    const task = {
      file,
      name   : '',
      desc   : '',
      task   : false,
      watch  : false,
      after  : [],
      before : [],
    };

    // Loop comments
    for (const com of comments) {
      // Check if class
      if (!com.comment.code.includes('class')) continue;

      // Set class
      task.name = com.comment.code.split('class')[1].split('extends')[0].split('{')[0].trim();
      task.desc = com.description;

      // Check for mount
      if (com.tasks) task.task = com.tasks[0].description;
      if (com.watchs) task.watch = true;

      // Do afters
      if (com.afters) {
        // Loop afters
        for (const after of com.afters) {
          // Add afters
          task.after.push(after.description);
        }
      }

      // Do afters
      if (com.befores) {
        // Loop afters
        for (const before of com.befores) {
          // Add afters
          task.before.push(before.description);
        }
      }
    }

    // Return returns
    return task;
  }

  /**
   * Returns acl array for tag
   *
   * @param   {array} tags
   *
   * @returns {*}
   *
   * @private
   */
  _acl(tags) {
    return tags.map((tag) => {
      return tag.description === 'true' || tag.description === 'false' ? tag.description === 'true' : tag.description;
    });
  }

  /**
   * Returns uploads array for route
   *
   * @param   {array} tags
   *
   * @returns {*}
   *
   * @private
   */
  _uploads(tags) {
    const updatedTags = tags;

    // Check for only type
    if (updatedTags[0].description.includes('{')) {
      // Replace type
      updatedTags[0].type = updatedTags[0].description.replace(/\{|\}/g, '');
    }

    // Set uploads
    const upload = {};

    // Alter upload
    if (updatedTags.length > 1) {
      upload.tag = 'fields';
    } else {
      upload.tag = (updatedTags[0].type && updatedTags[0].type ? updatedTags[0].type : 'array');
    }

    upload.fields = [];

    // Loop tags
    for (const tag of updatedTags) {
      // Set fields
      const field = {};

      // Check name
      field.name = (tag.name && tag.name.length ? tag.name : tag.description).trim();

      // Set max count
      if (tag.name && tag.name.length && tag.description && tag.description.length) {
        field.maxCount = parseInt(tag.description, 10);
      } else {
        field.maxCount = false;
      }

      // Push fields
      upload.fields.push(field);

      // Add to fields
      if (upload.type === 'single') {
        // Break
        break;
      }
    }

    // Return upload configuration
    return upload;
  }
}

/**
 * Export new Parser instance
 *
 * @type {Parser}
 */
module.exports = new Parser();
<commit_msg>fix parser<commit_after>// Require dependencies
const fs    = require('fs-extra');
const parse = require('parse-comments');

/**
 * Create Parser class
 */
class Parser {
  /**
   * Construct Parser class
   */
  constructor() {
    // Bind public methods
    this.task = this.task.bind(this);
    this.daemon = this.daemon.bind(this);
    this.controller = this.controller.bind(this);

    // Bind private methods
    this._acl = this._acl.bind(this);
    this._uploads = this._uploads.bind(this);
  }

  /**
   * Parse controller chunk
   *
   * @param   {*} chunk
   *
   * @returns {*}
   */
  controller(chunk) {
    // Get bundles
    const bundles = chunk.path.replace(/\\/g, '/').split('bundles/').pop();

    // Set default variables
    const file     = bundles.replace('.js', '');
    const data     = chunk.contents.toString();
    const comments = parse(data);

    // Set return
    const returns = {
      api     : {},
      calls   : [],
      menus   : {},
      routes  : [],
      classes : {},
      sockets : [],
    };

    // Set class in returns
    returns.classes[file] = {
      acl      : [],
      fail     : false,
      file,
      name     : '',
      desc     : '',
      mount    : '/',
      priority : 0,
    };

    // Loop comments
    for (const com of comments) {
      // Check if class
      if (com.comment.code.includes('class')) {
        // Set class
        returns.classes[file].name = com.comment.code.split('class')[1].split('extends')[0].trim();
        returns.classes[file].desc = com.description;

        // Check for mount
        if (com.acls) {
          returns.classes[file].acl = this._acl(com.acls);
        }

        if (com.fails) {
          returns.classes[file].fail = com.fails[0].description;
        }

        if (com.mounts) {
          returns.classes[file].mount = com.mounts[0].description;
        }

        if (com.priorities) {
          returns.classes[file].priority = parseInt(com.priorities[0].description, 10);
        }
      }

      // Alias variables to object props
      const classF = returns.classes[file];

      const comPrio = com.priorities;

      const comApiReq = com['api.request'];
      const comApiRes = com['api.response'];

      // Check routes
      if (com.routes) {
        // Set function
        let fn = com.comment.code.split('(')[0].trim();

        // Set fn
        fn = fn.split(' ').length > 1 ? fn.split(' ')[fn.split(' ').length - 1] : fn;

        // Loop routes
        for (let b = 0; b < com.routes.length; b += 1) {
          // Alias variables to object props
          const routeB = com.routes[b];
          const routeBDesc = routeB.description;
          const lowRouteBType = routeB.type.toLowerCase();

          let routeCache = null;

          if (com.caches) {
            const cacheB = com.caches[b];

            const cacheBDesc = cacheB.description;

            routeCache = {
              ttl  : com.ttl ? parseInt(com.ttl[0].description, 10) : (60 * 60 * 1000),
              name : cacheB.type ? cacheBDesc.toLowerCase().trim() : `${lowRouteBType.trim()}:${routeBDesc.trim()}`,
              type : cacheB.type ? cacheB.type.toLowerCase() : cacheBDesc.replace(/\{|\}/g, '').trim(),
            };
          }

          // Set route
          const route = {
            fn,
            acl      : com.acls ? classF.acl.concat(this._acl(com.acls)) : classF.acl,
            fail     : com.fails ? com.fails[0].description : classF.fail,
            type     : lowRouteBType,
            desc     : com.description,
            view     : com.views ? com.views[0].description : false,
            class    : file,
            cache    : routeCache,
            mount    : classF.mount,
            route    : routeB.description,
            title    : com.titles ? com.titles[0].description : false,
            layout   : com.layouts ? com.layouts[0].description : false,
            upload   : com.uploads ? this._uploads(com.uploads) : false,
            priority : comPrio ? parseInt(comPrio[0].description, 10) : classF.priority,
          };

          // Push to routes
          returns.routes.push(route);
        }

        // Add API documentation
        if (com.api) {
          // Get route
          const route = (classF.mount + com.routes[0].description).split('//').join('/');

          // Set logic
          returns.api[route] = {
            fn,
            acl   : com.acls ? classF.acl.concat(this._acl(com.acls)) : classF.acl,
            api   : com.api.replace('true', '').trim(),
            type  : 'route',
            route,
            class : {
              file,
              name : classF.name,
              desc : classF.desc,
            },
            title       : com.titles ? com.titles[0].description : com.description,
            method      : com.routes[0].type.toLowerCase(),
            upload      : com.uploads ? this._uploads(com.uploads) : false,
            request     : comApiReq ? eval(`(${comApiReq.replace('true', '').trim()})`) : null,
            response    : comApiReq ? eval(`(${comApiRes.replace('true', '').trim()})`) : null,
            description : com.description,
          };
        }

        // Check if menus
        if (com.menus) {
          // Loop menus
          for (const menu of com.menus) {
            // Set path
            let path = (classF.mount + (com.routes ? com.routes[0].description : '/')).split('//').join('/');

            // Add to path
            path = path.length > 1 ? path.replace(/\/$/, '') : path;

            // Check if menu exists
            if (!returns.menus[menu.type]) returns.menus[menu.type] = [];

            // Push to menus
            returns.menus[menu.type].push({
              acl      : com.acls ? classF.acl.concat(this._acl(com.acls)) : classF.acl,
              icon     : com.icons ? com.icons[0].description : false,
              route    : path,
              title    : menu.description,
              parent   : com.parents ? com.parents[0].description : false,
              priority : comPrio ? parseInt(comPrio[0].description, 10) : classF.priority,
            });
          }
        }
      }

      // Check sockets
      if (com.sockets) {
        // Set function
        let fn = com.comment.code.split('(')[0].trim();

        // Add to fn
        fn = fn.split(' ').length > 1 ? fn.split(' ')[fn.split(' ').length - 1] : fn;

        // Loop routes
        for (const sock of com.sockets) {
          // Set route
          const socket = {
            fn,
            acl      : com.acls ? classF.acl.concat(this._acl(com.acls)) : classF.acl,
            desc     : com.description,
            name     : sock.type ? sock.type : sock.description.replace(/\{|\}/g, ''),
            class    : file,
            priority : comPrio ? parseInt(comPrio[0].description, 10) : classF.priority,
          };

          // Push to routes
          returns.sockets.push(socket);
        }
      }

      // Check sockets
      if (com.calls) {
        // Set function
        let fn = com.comment.code.split('(')[0].trim();

        // Add to fn
        fn = fn.split(' ').length > 1 ? fn.split(' ')[fn.split(' ').length - 1] : fn;

        // Loop routes
        for (const call of com.calls) {
          // Set route
          const socket = {
            fn,
            acl      : com.acls ? classF.acl.concat(this._acl(com.acls)) : classF.acl,
            desc     : com.description,
            name     : call.type ? call.type : call.description.replace(/\{|\}/g, ''),
            class    : file,
            priority : comPrio ? parseInt(comPrio[0].description, 10) : classF.priority,
          };

          // Push to routes
          returns.calls.push(socket);
        }

        // Add API documentation
        if (com.api) {
          // Get route
          const route = (classF.mount + com.routes[0].description).split('//').join('/');

          // Set logic
          returns.api[route] = {
            fn,
            acl   : com.acls ? classF.acl.concat(this._acl(com.acls)) : classF.acl,
            api   : com.api.replace('true', '').trim(),
            call  : com.calls[0].type ? com.calls[0].type : com.calls[0].description.replace(/\{|\}/g, ''),
            type  : 'call',
            class : {
              file,
              name : classF.name,
              desc : classF.desc,
            },
            title       : com.titles ? com.titles[0].description : com.description,
            request     : com['api.request'] ? eval(`(${com['api.request'].replace('true', '').trim()})`) : null,
            response    : com['api.request'] ? eval(`(${com['api.response'].replace('true', '').trim()})`) : null,
            description : com.description,
          };
        }
      }
    }

    // Return returns
    return returns;
  }

  /**
   * Parse daemon chunk
   *
   * @param   {*} chunk
   *
   * @returns {*}
   */
  daemon(chunk) {
    // Get bundles
    const bundles = chunk.path.replace(/\\/g, '/').split('bundles/').pop();

    // Set default variables
    const file     = bundles.replace('.js', '');
    const data     = chunk.contents.toString();
    const comments = parse(data);

    // Set return
    const returns = {
      daemons : {},
    };

    // Set class in returns
    returns.daemons[file] = {
      name    : '',
      desc    : '',
      express : false,
      compute : false,
    };

    // Loop comments
    for (const com of comments) {
      // Check if class
      if (!com.comment.code.includes('class')) continue;

      // Set class
      returns.daemons[file].name = com.comment.code.split('class')[1].split('extends')[0].trim();
      returns.daemons[file].desc = com.description;

      // Set express and compute threads
      let express = false;
      let compute = false;

      // Check express
      if (com.express === 'true' || com.express === true) {
        // Set express true
        express = true;
      } else if (com.express && com.express.length && !Array.isArray(com.express)) {
        // Set express as array
        express = [parseInt(com.express, 10)];
      } else if (com.express && com.express.length && Array.isArray(com.express)) {
        express = com.express.map(Number);
      }

      // Check express
      if (com.compute === 'true' || com.compute === true) {
        // Set express true
        compute = true;
      } else if (com.compute && com.compute.length && !Array.isArray(com.compute)) {
        // Set express as array
        compute = [parseInt(com.compute, 10)];
      } else if (com.compute && com.compute.length && Array.isArray(com.compute)) {
        compute = com.compute.map(Number);
      }

      // Check for mount
      if (com.express) returns.daemons[file].express = express;
      if (com.compute) returns.daemons[file].compute = compute;
    }

    // Return returns
    return returns;
  }

  /**
   * Parse daemon chunk
   *
   * @param   {*} path
   *
   * @returns {*}
   */
  task(path) {
    // Get bundles
    const bundles = path.replace(/\\/g, '/').split('bundles/');

    // Set default variables
    const file     = bundles.join('bundles/');
    const data     = fs.readFileSync(path, 'utf8');
    const comments = parse(data);

    // Set class in returns
    const task = {
      file,
      name   : '',
      desc   : '',
      task   : false,
      watch  : false,
      after  : [],
      before : [],
    };

    // Loop comments
    for (const com of comments) {
      // Check if class
      if (!com.comment.code.includes('class')) continue;

      // Set class
      task.name = com.comment.code.split('class')[1].split('extends')[0].split('{')[0].trim();
      task.desc = com.description;

      // Check for mount
      if (com.tasks) task.task = com.tasks[0].description;
      if (com.watchs) task.watch = true;

      // Do afters
      if (com.afters) {
        // Loop afters
        for (const after of com.afters) {
          // Add afters
          task.after.push(after.description);
        }
      }

      // Do afters
      if (com.befores) {
        // Loop afters
        for (const before of com.befores) {
          // Add afters
          task.before.push(before.description);
        }
      }
    }

    // Return returns
    return task;
  }

  /**
   * Returns acl array for tag
   *
   * @param   {array} tags
   *
   * @returns {*}
   *
   * @private
   */
  _acl(tags) {
    return tags.map((tag) => {
      return tag.description === 'true' || tag.description === 'false' ? tag.description === 'true' : tag.description;
    });
  }

  /**
   * Returns uploads array for route
   *
   * @param   {array} tags
   *
   * @returns {*}
   *
   * @private
   */
  _uploads(tags) {
    const updatedTags = tags;

    // Check for only type
    if (updatedTags[0].description.includes('{')) {
      // Replace type
      updatedTags[0].type = updatedTags[0].description.replace(/\{|\}/g, '');
    }

    // Set uploads
    const upload = {};

    // Alter upload
    if (updatedTags.length > 1) {
      upload.type = 'fields';
    } else {
      upload.type = (updatedTags[0].type && updatedTags[0].type ? updatedTags[0].type : 'array');
    }

    upload.fields = [];

    // Loop tags
    for (const tag of updatedTags) {
      // Set fields
      const field = {};

      // Check name
      field.name = (tag.name && tag.name.length ? tag.name : tag.description).trim();

      // Set max count
      if (tag.name && tag.name.length && tag.description && tag.description.length) {
        field.maxCount = parseInt(tag.description, 10);
      } else {
        field.maxCount = false;
      }

      // Push fields
      upload.fields.push(field);

      // Add to fields
      if (upload.type === 'single') {
        // Break
        break;
      }
    }

    // Return upload configuration
    return upload;
  }
}

/**
 * Export new Parser instance
 *
 * @type {Parser}
 */
module.exports = new Parser();
<|endoftext|>


<commit_before>/*
Copyright 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import sdk from '../../../index';

export default class MemberDeviceInfo extends React.Component {
    render() {
        var indicator = null;
        var DeviceVerifyButtons = sdk.getComponent('elements.DeviceVerifyButtons');

        if (this.props.device.isBlocked()) {
            indicator = (

            );
        } else if (this.props.device.isVerified()) {
            indicator = (

            );
        } else {
            indicator = (

            );
        }

        var deviceName = this.props.device.ambiguous ?
            (this.props.device.getDisplayName() ? this.props.device.getDisplayName() : "") + " (" + this.props.device.deviceId + ")" :
            this.props.device.getDisplayName();

        return (

                        {deviceName}
                        {indicator}

                <DeviceVerifyButtons userId={this.props.userId} device={this.props.device} />

        );
    }
};

MemberDeviceInfo.displayName = 'MemberDeviceInfo';
MemberDeviceInfo.propTypes = {
    userId: React.PropTypes.string.isRequired,
    device: React.PropTypes.object.isRequired,
};
<commit_msg>Add the deviceId back to memberdeviceinfo<commit_after>/*
Copyright 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import sdk from '../../../index';

export default class MemberDeviceInfo extends React.Component {
    render() {
        var indicator = null;
        var DeviceVerifyButtons = sdk.getComponent('elements.DeviceVerifyButtons');

        if (this.props.device.isBlocked()) {
            indicator = (

            );
        } else if (this.props.device.isVerified()) {
            indicator = (

            );
        } else {
            indicator = (

            );
        }

        var deviceName = this.props.device.ambiguous ?
            (this.props.device.getDisplayName() ? this.props.device.getDisplayName() : "") + " (" + this.props.device.deviceId + ")" :
            this.props.device.getDisplayName();

        // add the deviceId as a titletext to help with debugging
        return (

                        {deviceName}
                        {indicator}

                <DeviceVerifyButtons userId={this.props.userId} device={this.props.device} />

        );
    }
};

MemberDeviceInfo.displayName = 'MemberDeviceInfo';
MemberDeviceInfo.propTypes = {
    userId: React.PropTypes.string.isRequired,
    device: React.PropTypes.object.isRequired,
};
<|endoftext|>


<commit_before>module.exports = function(babel) {

  var t = babel.types;

  function isGoogDefineClass(path) {
    try {
      const callee = path.node.declarations[0].init.callee;
      return callee.object.name === 'goog' &&
          callee.property.name === 'defineClass';
    } catch (e) {
      return false;
    }
  }

  function getBody(prop) {
    let body = t.blockStatement([]);
    if (prop.value.body) {
      body = prop.value.body;
    }
    return body;
  }

  function createExpressionStatementForStatics(className, objProp) {
    // Generate ClassName.staticName
    let left = t.MemberExpression(className, objProp.key);
    // Assign the key and value defined in the statics.
    const expressionStatement = t.expressionStatement(
        t.assignmentExpression('=', left, objProp.value));
    // Comments?
    if (objProp.leadingComments) {
      expressionStatement.leadingComments = objProp.leadingComments;
    }
    return expressionStatement;
  }

  /**
   * t.classMethod(kind, key, params, body, computed, static)
   * @param prop
   * @return {*}
   */
  function toClassMethod(prop) {
    const name = prop.key.name;
    const kind = name === 'constructor' ? 'constructor' : 'method';

    const method = t.classMethod(kind, prop.key, prop.value.params, getBody(prop));
    // Copy comments, if any.
    const comments = prop.leadingComments;
    if (comments) {
      method.leadingComments = comments;
    }

    return method
  }

  /**
   * Find the parent class in goog.defineClass(PARENT, {...});
   */
  function findParent(declaration) {
    try {
      const argument = declaration.init.arguments[0];
      return t.isNullLiteral(argument) ? null : argument;
    } catch (e) {
      return null;
    }
  }

  return {
    visitor: {
      VariableDeclaration: function(path) {
        if (path.parentKey !== 'body' || !isGoogDefineClass(path)) {
          return;
        }

        const declaration = path.node.declarations[0];
        const objectExpression = declaration.init.arguments[1];
        const className = t.Identifier(declaration.id.name);

        // Turn all the properties in the goog.defineClass object arg into
        // ClassMethod methods. Filter out statics.
        let statics = null;
        let classMethods = [];
        objectExpression.properties.forEach(prop => {
          if (t.isFunctionExpression(prop.value)) {
            classMethods.push(toClassMethod(prop));
          } else if (prop.key.name === 'statics') {
            statics = prop.value.properties;
          }
        });

        const classBody = t.ClassBody(classMethods);
        const superClass = findParent(declaration);
        const decorators = [];

        // Need to add a super() class in the body.
        if (superClass !== null) {
          // Find the constructor.
          const constructorMethod = classMethods
              .find(method => method.kind === 'constructor');
          if (constructorMethod) {
            // Add the super(<constructor params>) at the beginning of the fn.
            constructorMethod.body.body.unshift(
                t.ExpressionStatement(
                    t.CallExpression(t.super(), constructorMethod.params)));
          }
        }

        const classDeclaration = t.classDeclaration(className,
            superClass,
            classBody,
            decorators
        );
        path.replaceWith(classDeclaration);

        if (statics) {
          // Reverse the order so when we add the elements they are in the
          // correct order.
          statics.slice(0).reverse().forEach(objProp => {
            let expressionStatement =
                createExpressionStatementForStatics(className, objProp);
            path.insertAfter(expressionStatement);
          });
        }
      }
    }
  };
};
<commit_msg>rename to findParentClass<commit_after>module.exports = function(babel) {

  var t = babel.types;

  function isGoogDefineClass(path) {
    try {
      const callee = path.node.declarations[0].init.callee;
      return callee.object.name === 'goog' &&
          callee.property.name === 'defineClass';
    } catch (e) {
      return false;
    }
  }

  function getBody(prop) {
    let body = t.blockStatement([]);
    if (prop.value.body) {
      body = prop.value.body;
    }
    return body;
  }

  function createExpressionStatementForStatics(className, objProp) {
    // Generate ClassName.staticName
    let left = t.MemberExpression(className, objProp.key);
    // Assign the key and value defined in the statics.
    const expressionStatement = t.expressionStatement(
        t.assignmentExpression('=', left, objProp.value));
    // Comments?
    if (objProp.leadingComments) {
      expressionStatement.leadingComments = objProp.leadingComments;
    }
    return expressionStatement;
  }

  /**
   * t.classMethod(kind, key, params, body, computed, static)
   * @param prop
   * @return {*}
   */
  function toClassMethod(prop) {
    const name = prop.key.name;
    const kind = name === 'constructor' ? 'constructor' : 'method';

    const method = t.classMethod(kind, prop.key, prop.value.params, getBody(prop));
    // Copy comments, if any.
    const comments = prop.leadingComments;
    if (comments) {
      method.leadingComments = comments;
    }

    return method
  }

  /**
   * Find the parent class in goog.defineClass(PARENT, {...});
   */
  function findParentClass(declaration) {
    try {
      const argument = declaration.init.arguments[0];
      return t.isNullLiteral(argument) ? null : argument;
    } catch (e) {
      return null;
    }
  }

  return {
    visitor: {
      VariableDeclaration: function(path) {
        if (path.parentKey !== 'body' || !isGoogDefineClass(path)) {
          return;
        }

        const declaration = path.node.declarations[0];
        const objectExpression = declaration.init.arguments[1];
        const className = t.Identifier(declaration.id.name);

        // Turn all the properties in the goog.defineClass object arg into
        // ClassMethod methods. Filter out statics.
        let statics = null;
        let classMethods = [];
        objectExpression.properties.forEach(prop => {
          if (t.isFunctionExpression(prop.value)) {
            classMethods.push(toClassMethod(prop));
          } else if (prop.key.name === 'statics') {
            statics = prop.value.properties;
          }
        });

        const classBody = t.ClassBody(classMethods);
        const superClass = findParentClass(declaration);
        const decorators = [];

        // Need to add a super() class in the body.
        if (superClass !== null) {
          // Find the constructor.
          const constructorMethod = classMethods
              .find(method => method.kind === 'constructor');
          if (constructorMethod) {
            // Add the super(<constructor params>) at the beginning of the fn.
            constructorMethod.body.body.unshift(
                t.ExpressionStatement(
                    t.CallExpression(t.super(), constructorMethod.params)));
          }
        }

        const classDeclaration = t.classDeclaration(className,
            superClass,
            classBody,
            decorators
        );
        path.replaceWith(classDeclaration);

        if (statics) {
          // Reverse the order so when we add the elements they are in the
          // correct order.
          statics.slice(0).reverse().forEach(objProp => {
            let expressionStatement =
                createExpressionStatementForStatics(className, objProp);
            path.insertAfter(expressionStatement);
          });
        }
      }
    }
  };
};
<|endoftext|>


<commit_before>// info about each config option.

var url = require("url")
  , path = require("path")
  , Stream
  , abbrev = require("./abbrev")
  , log = require("./log")

try { Stream = require("stream").Stream }
catch (e) { Stream = require("net").Stream }

module.exports = exports = parseArgs

// [array,of,things] = allowed vals
// [array,of,types] allowed types
// Type : allowed type
// NaN : since it never matches, means "not allowed"
exports.types =
  { argv : NaN
  , "auto-activate" : ["always", Boolean]
  , "auto-deactivate" : Boolean
  , binroot : path
  , browser : String
  , color : Boolean
  , description : Boolean
  , dev : Boolean
  , editor : path
  , force : Boolean
  , gzipbin : String
  , globalconfig : path
  , listopts : String
  , logfd : [Number, Stream]
  , loglevel : ["silent","win","error","warn","info","verbose","silly"]
  , manroot : path
  , "must-install" : Boolean
  , outfd : [Number, Stream]
  , proxy : url
  , prune : Boolean
  , recursive : Boolean
  , registry : url
  , root : path
  , tag : String
  , tar : String
  , tmproot : path
  , "update-dependents" : Boolean
  , usage : Boolean
  , userconfig : path
  , version : Boolean
  , _exit : Boolean
  }

exports.shorthands =
  { s : ["--loglevel", "silent"]
  , d : ["--loglevel", "info"]
  , dd : ["--loglevel", "verbose"]
  , ddd : ["--loglevel", "silly"]
  , noreg : ["--no-registry"]
  , reg : ["--registry"]
  , "no-reg" : ["--no-registry"]
  , silent : ["--loglevel", "silent"]
  , verbose : ["--loglevel", "verbose"]
  , h : ["--usage"]
  , "?" : ["--usage"]
  , help : ["--usage"]
  , v : ["--version"]
  , r : ["--recursive"]
  , f : ["--force"]
  , rf : ["--recursive", "--force"]
  , desc : ["--description"]
  , "no-desc" : ["--no-description"]
  }

var typeDefs = exports.typeDefs =
  [ String
  , Boolean
  , url
  , Number
  , path
  , Stream
  ]

function parseArgs (args, types, shorthands) {
  var data = {}
    , key
    , remain = []
    , cooked = args
    , original = args.slice(0)
  if (!types) types = exports.types
  if (!shorthands) shorthands = exports.shorthands
  parse(args, data, remain, types, shorthands)
  // now data is full
  clean(data, types)
  data.argv = {remain:remain,cooked:cooked,original:original}
  return data
}

function clean (data, types) {
  Object.keys(data).forEach(function (k) {
    var val = data[k]
    if (typeof val === "string") {
      val = val.trim()
      if (val === "null" || val === "true" || val === "false") {
        val = JSON.parse(val)
      } else if (!isNaN(val)) {
        val = +val
      }
    }
    if (!types.hasOwnProperty(k)) {
      data[k] = val
      return
    }
    if (!validate(data, k, val, types[k])) {
      log.error("invalid: "+k+"="+val)
    }
  })
}

function validate (data, k, val, type) {
  if (Array.isArray(type)) {
    for (var i = 0, l = type.length; i < l; i ++) {
      if (validate(data, k, val, type[i])) return true
    }
    delete data[k]
    return false
  }
  if (type !== type) {
    delete data[k]
    return false
  }
  if (val === type) {
    data[k] = val
    return true
  }
  if (type === path || type === String) {
    data[k] = String(val)
    if (type === path && data[k].charAt(0) !== "/") {
      data[k] = path.join(process.cwd(), data[k])
    }
    return true
  }
  if (type === Number) {
    var ok = !isNaN(val)
    if (!ok) delete data[k]
    else data[k] = +val
    return ok
  }
  if (type === Boolean) {
    if (val instanceof Boolean) val = val.valueOf()
    else val = !!val
    data[k] = val
    return true
  }
  if (val === false || val === null || val === undefined) {
    data[k] = null
    return true
  }
  if (url === type) {
    val = url.parse(val)
    if (!val || !val.hostname) delete data[k]
    else data[k] = val.href
    return val
  }
  if (type === Stream) {
    var ok = val instanceof Stream
    if (!ok) delete data[k]
    return ok
  }
  return false
}

function parse (args, data, remain, types, shorthands) {
  var key = null
    , abbrevs = abbrev(Object.keys(types))
    , shortAbbr = abbrev(Object.keys(shorthands))

  for (var i = 0; i < args.length; i ++) {
    var arg = args[i]
    if (arg === "--") {
      // done with keys.
      // the rest are args.
      remain.push.apply(remain, args.slice(i + 1))
      break
    }
    if (arg.charAt(0) === "-") {
      if (arg.indexOf("=") !== -1) {
        var v = arg.split("=")
        arg = v.shift()
        v = v.join("=")
        args.splice.apply(args, [i, 1].concat(["-"+arg, v]))
      }
      arg = arg.replace(/^-+/, '')
      if (shortAbbr[arg]) arg = shortAbbr[arg]
      // see if it's a shorthand
      // if so, splice and back up to re-parse it.
      if (shorthands[arg]) {
        args.splice.apply(args, [i, 1].concat(shorthands[arg]))
        i --
        continue
      }
      var no = (arg.indexOf("no-") === 0)
        , isBool = no || types[arg] === Boolean
      if (no) arg = arg.substr(3)
      if (abbrevs[arg]) arg = abbrevs[arg]
      if (isBool) {
        // just set and move along
        data[arg] = !no
        // however, also support --bool true or --bool false
        var la = args[i + 1]
        if (la === "true" || la === "false") {
          data[arg] = JSON.parse(la)
          if (no) data[arg] = !data[arg]
          i ++
        }
        continue
      }
      var la = args[i + 1]
      data[arg] = la === undefined ? true : la
      i ++
      continue
    }
    remain.push(arg)
  }
}

if (module === require.main) {
var assert = require("assert")
  , sys = require("sys")
; [["-v", {version:true}, []]
  ,["---v", {version:true}, []]
  ,["ls -s --no-reg connect -d",
    {loglevel:"info",registry:null},["ls","connect"]]
  ,["ls ---s foo",{loglevel:"silent"},["ls","foo"]]
  ,["ls --registry blargle", {}, ["ls"]]
  ,["--no-registry", {registry:null}, []]
  ,["--no-color true", {color:false}, []]
  ,["--no-color false", {color:true}, []]
  ,["--no-color", {color:false}, []]
  ,["--color false", {color:false}, []]
  ,["--color --logfd 7", {logfd:7,color:true}, []]
  ,["--color=true", {color:true}, []]
  ,["--logfd=10", {logfd:10}, []]
  ,["--tmproot=/tmp -tar=gtar",{tmproot:"/tmp",tar:"gtar"},[]]
  ,["--tmproot=tmp -tar=gtar",
    {tmproot:path.join(process.cwd(), "tmp"),tar:"gtar"},[]]
  ,["--logfd x", {}, []]
  ].forEach(function (test) {
    var argv = test[0].split(/\s+/)
      , opts = test[1]
      , rem = test[2]
      , actual = parseArgs(argv)
    console.log(sys.inspect(actual, false, 2, true))
    for (var i in opts) {
      assert.equal(opts[i], actual[i])
    }
    assert.deepEqual(rem, actual.argv.remain)
  })
}
<commit_msg>allow double (or more) negatives.  Also: funner tests.<commit_after>// info about each config option.

var url = require("url")
  , path = require("path")
  , Stream
  , abbrev = require("./abbrev")
  , log = require("./log")

try { Stream = require("stream").Stream }
catch (e) { Stream = require("net").Stream }

module.exports = exports = parseArgs

// [array,of,things] = allowed vals
// [array,of,types] allowed types
// Type : allowed type
// NaN : since it never matches, means "not allowed"
exports.types =
  { argv : NaN
  , "auto-activate" : ["always", Boolean]
  , "auto-deactivate" : Boolean
  , binroot : path
  , browser : String
  , color : Boolean
  , description : Boolean
  , dev : Boolean
  , editor : path
  , force : Boolean
  , gzipbin : String
  , globalconfig : path
  , listopts : String
  , logfd : [Number, Stream]
  , loglevel : ["silent","win","error","warn","info","verbose","silly"]
  , manroot : path
  , "must-install" : Boolean
  , outfd : [Number, Stream]
  , proxy : url
  , prune : Boolean
  , recursive : Boolean
  , registry : url
  , root : path
  , tag : String
  , tar : String
  , tmproot : path
  , "update-dependents" : Boolean
  , usage : Boolean
  , userconfig : path
  , version : Boolean
  , _exit : Boolean
  }

exports.shorthands =
  { s : ["--loglevel", "silent"]
  , d : ["--loglevel", "info"]
  , dd : ["--loglevel", "verbose"]
  , ddd : ["--loglevel", "silly"]
  , noreg : ["--no-registry"]
  , reg : ["--registry"]
  , "no-reg" : ["--no-registry"]
  , silent : ["--loglevel", "silent"]
  , verbose : ["--loglevel", "verbose"]
  , h : ["--usage"]
  , "?" : ["--usage"]
  , help : ["--usage"]
  , v : ["--version"]
  , r : ["--recursive"]
  , f : ["--force"]
  , rf : ["--recursive", "--force"]
  , desc : ["--description"]
  , "no-desc" : ["--no-description"]
  }

var typeDefs = exports.typeDefs =
  [ String
  , Boolean
  , url
  , Number
  , path
  , Stream
  ]

function parseArgs (args, types, shorthands) {
  var data = {}
    , key
    , remain = []
    , cooked = args
    , original = args.slice(0)
  if (!types) types = exports.types
  if (!shorthands) shorthands = exports.shorthands
  parse(args, data, remain, types, shorthands)
  // now data is full
  clean(data, types)
  data.argv = {remain:remain,cooked:cooked,original:original}
  return data
}

function clean (data, types) {
  Object.keys(data).forEach(function (k) {
    var val = data[k]
    if (typeof val === "string") {
      val = val.trim()
      if (val === "null" || val === "true" || val === "false") {
        val = JSON.parse(val)
      } else if (!isNaN(val)) {
        val = +val
      }
    }
    if (!types.hasOwnProperty(k)) {
      data[k] = val
      return
    }
    if (!validate(data, k, val, types[k])) {
      log.error("invalid: "+k+"="+val)
    }
  })
}

function validate (data, k, val, type) {
  if (Array.isArray(type)) {
    for (var i = 0, l = type.length; i < l; i ++) {
      if (validate(data, k, val, type[i])) return true
    }
    delete data[k]
    return false
  }
  if (type !== type) {
    delete data[k]
    return false
  }
  if (val === type) {
    data[k] = val
    return true
  }
  if (type === path || type === String) {
    data[k] = String(val)
    if (type === path && data[k].charAt(0) !== "/") {
      data[k] = path.join(process.cwd(), data[k])
    }
    return true
  }
  if (type === Number) {
    var ok = !isNaN(val)
    if (!ok) delete data[k]
    else data[k] = +val
    return ok
  }
  if (type === Boolean) {
    if (val instanceof Boolean) val = val.valueOf()
    else val = !!val
    data[k] = val
    return true
  }
  if (val === false || val === null || val === undefined) {
    data[k] = null
    return true
  }
  if (url === type) {
    val = url.parse(val)
    if (!val || !val.hostname) delete data[k]
    else data[k] = val.href
    return val
  }
  if (type === Stream) {
    var ok = val instanceof Stream
    if (!ok) delete data[k]
    return ok
  }
  return false
}

function parse (args, data, remain, types, shorthands) {
  var key = null
    , abbrevs = abbrev(Object.keys(types))
    , shortAbbr = abbrev(Object.keys(shorthands))

  for (var i = 0; i < args.length; i ++) {
    var arg = args[i]
    if (arg.match(/^-{2,}$/)) {
      // done with keys.
      // the rest are args.
      remain.push.apply(remain, args.slice(i + 1))
      args[i] = "--"
      break
    }
    if (arg.charAt(0) === "-") {
      if (arg.indexOf("=") !== -1) {
        var v = arg.split("=")
        arg = v.shift()
        v = v.join("=")
        args.splice.apply(args, [i, 1].concat([arg, v]))
      }
      arg = arg.replace(/^-+/, '')
      if (shortAbbr[arg]) arg = shortAbbr[arg]
      // see if it's a shorthand
      // if so, splice and back up to re-parse it.
      if (shorthands[arg]) {
        args.splice.apply(args, [i, 1].concat(shorthands[arg]))
        i --
        continue
      }
      var no = false
      while (arg.toLowerCase().indexOf("no-") === 0) {
        no = !no
        arg = arg.substr(3)
      }
      var isBool = no || types[arg] === Boolean
      if (abbrevs[arg]) arg = abbrevs[arg]
      if (isBool) {
        // just set and move along
        data[arg] = !no
        // however, also support --bool true or --bool false
        var la = args[i + 1]
        if (la === "true" || la === "false") {
          data[arg] = JSON.parse(la)
          if (no) data[arg] = !data[arg]
          i ++
        }
        continue
      }
      var la = args[i + 1]
      if (la && la.match(/^-{2,}$/)) {
        la = undefined
        i --
      }
      data[arg] = la === undefined ? true : la
      i ++
      continue
    }
    remain.push(arg)
  }
}

if (module === require.main) {
var assert = require("assert")
  , sys = require("sys")
; [["-v", {version:true}, []]
  ,["---v", {version:true}, []]
  ,["ls -s --no-reg connect -d",
    {loglevel:"info",registry:null},["ls","connect"]]
  ,["ls ---s foo",{loglevel:"silent"},["ls","foo"]]
  ,["ls --registry blargle", {}, ["ls"]]
  ,["--no-registry", {registry:null}, []]
  ,["--no-color true", {color:false}, []]
  ,["--no-color false", {color:true}, []]
  ,["--no-color", {color:false}, []]
  ,["--color false", {color:false}, []]
  ,["--color --logfd 7", {logfd:7,color:true}, []]
  ,["--color=true", {color:true}, []]
  ,["--logfd=10", {logfd:10}, []]
  ,["--tmproot=/tmp -tar=gtar",{tmproot:"/tmp",tar:"gtar"},[]]
  ,["--tmproot=tmp -tar=gtar",
    {tmproot:path.join(process.cwd(), "tmp"),tar:"gtar"},[]]
  ,["--logfd x", {}, []]
  ,["a -true -- -no-false", {true:true},["a","-no-false"]]
  ,["a -no-false", {false:false},["a"]]
  ,["a -no-no-true", {true:true}, ["a"]]
  ,["a -no-no-no-false", {false:false}, ["a"]]
  ,["---NO-no-No-no-no-no-nO-no-no"+
    "-No-no-no-no-no-no-no-no-no"+
    "-no-no-no-no-NO-NO-no-no-no-no-no-no"+
    "-no-body-can-do-the-boogaloo-like-I-do"
   ,{"body-can-do-the-boogaloo-like-I-do":false}, []]
  ,["-no-strangers-to-love "+
    "--you-know the-rules --and so-do-i "+
    "---im-thinking-of=a-full-commitment "+
    "--no-you-would-get-this-from-any-other-guy "+
    "--no-gonna-give-you-up "+
    "-no-gonna-let-you-down=true "+
    "--no-no-gonna-run-around false "+
    "--desert-you=false "+
    "--make-you-cry false "+
    "--no-tell-a-lie "+
    "--no-no-and-hurt-you false"
   ,{"strangers-to-love":false
    ,"you-know":"the-rules"
    ,"and":"so-do-i"
    ,"you-would-get-this-from-any-other-guy":false
    ,"gonna-give-you-up":false
    ,"gonna-let-you-down":false
    ,"gonna-run-around":false
    ,"desert-you":false
    ,"make-you-cry":false
    ,"tell-a-lie":false
    ,"and-hurt-you":false
    },[]]
  ].forEach(function (test) {
    var argv = test[0].split(/\s+/)
      , opts = test[1]
      , rem = test[2]
      , actual = parseArgs(argv)
      , parsed = actual.argv
    delete actual.argv
    console.log(sys.inspect(actual, false, 2, true))
    for (var i in opts) {
      assert.equal(opts[i], actual[i])
    }
    assert.deepEqual(rem, parsed.remain)
  })
}
<|endoftext|>


<commit_before>var path = require('path');
var parse = require('./lib/parser').parse;

module.exports.insert = function(content, filename, indent) {
    var ret = /[\s\S]*?<\/head>/g.exec(content);

    if (ret) {
        var ast = parse(ret[0]);
        return process(ast, filename, indent);
    } else {
        throw("No head content found");
    }
}

function process(ast, filename, indent) {
    if (path.extname(filename) == '.lua') {
        ast = insert_lua(ast, filename);
    } else {
        ast = insert_css(ast, filename);
    }

    return stringify(ast, indent);
}

function insert_lua(ast, filename) {
    var notfound = true;

    ast.forEach(function(node) {
        if (node.type == 'script-src' && node.props.src == filename) {
            notfound = false;
        }
    });

    if (notfound) {
        ast.push({
            "type": "script-src",
            "props": [
                {
                    "key": "type",
                    "value": "text/x-lua"
                },
                {
                    "key": "src",
                    "value": filename
                }
            ]
        });
    }

    return ast;
}

function insert_css(ast, filename) {
    var notfound = true;

    ast.forEach(function(node) {
        if (node.type == 'link' && node.props.ref == filename) {
            notfound = false;
        }
    });

    if (notfound) {
        ast.push({
            "type": "link",
            "props": [
                {
                    "key": "type",
                    "value": "text/css"
                },
                {
                    "key": "ref",
                    "value": filename
                }
            ]
        });
    }

    return ast;
}

function stringify(ast, indent) {
    var out = indent + "\n"

    ast.forEach(function(node) {
        out += stringify_(node, indent+indent, indent);
    });
    out += indent + "";

    return out;
}

function stringify_(node, indent, i) {
    var out = "";

    if (node.type == 'style') {
        out += indent + "\n";
    } else if (node.type == 'script-src') {
        out += indent + "\n";
    } else if (node.type == 'link') {
        out += indent + "<link";
        out += stringify_props(node.props);
        out += "/>\n";
    } else if (node.type == 'comment') {
        out += align("", i) + "\n";
    }

    return out;
}

function stringify_props(props) {
    var out = "";

    props.forEach(function(prop) {
        out += ' ' + prop.key + '="' + prop.value + '"';
    });

    return out;
}

function align(value, indent) {
    value = value.replace(/\n\s*/g, "\n" + indent + indent + indent);
    value = indent + indent + indent + value;
    return value;
}<commit_msg>Return fixed content with head updated.<commit_after>var path = require('path');
var parse = require('./lib/parser').parse;

module.exports.insert = function(content, filename, indent) {
    var ret = /[\s\S]*?<\/head>/g.exec(content);

    if (ret) {
        var ast = parse(ret[0]);
        var out = process(ast, filename, indent);
        return content.replace(/[\s\S]*?<\/head>/g, out.trim());
    } else {
        throw("No head content found");
    }
}

function process(ast, filename, indent) {
    if (path.extname(filename) == '.lua') {
        ast = insert_lua(ast, filename);
    } else {
        ast = insert_css(ast, filename);
    }

    return stringify(ast, indent);
}

function insert_lua(ast, filename) {
    var notfound = true;

    ast.forEach(function(node) {
        if (node.type == 'script-src') {
            node.props.forEach(function(prop) {
                if (prop.key == 'src' && prop.value == filename) {
                    notfound = false;
                }
            })
        }
    });

    if (notfound) {
        ast.push({
            "type": "script-src",
            "props": [
                {
                    "key": "type",
                    "value": "text/x-lua"
                },
                {
                    "key": "src",
                    "value": filename
                }
            ]
        });
    }

    return ast;
}

function insert_css(ast, filename) {
    var notfound = true;

    ast.forEach(function(node) {
        if (node.type == 'link') {
            node.props.forEach(function(prop) {
                if (prop.key == 'ref' && prop.value == filename) {
                    notfound = false;
                }
            })
        }
    });

    if (notfound) {
        ast.push({
            "type": "link",
            "props": [
                {
                    "key": "type",
                    "value": "text/css"
                },
                {
                    "key": "ref",
                    "value": filename
                }
            ]
        });
    }

    return ast;
}

function stringify(ast, indent) {
    var out = indent + "\n"

    ast.forEach(function(node) {
        out += stringify_(node, indent+indent, indent);
    });
    out += indent + "";

    return out;
}

function stringify_(node, indent, i) {
    var out = "";

    if (node.type == 'style') {
        out += indent + "\n";
    } else if (node.type == 'script-src') {
        out += indent + "\n";
    } else if (node.type == 'link') {
        out += indent + "<link";
        out += stringify_props(node.props);
        out += "/>\n";
    } else if (node.type == 'comment') {
        out += align("", i) + "\n";
    }

    return out;
}

function stringify_props(props) {
    var out = "";

    props.forEach(function(prop) {
        out += ' ' + prop.key + '="' + prop.value + '"';
    });

    return out;
}

function align(value, indent) {
    value = value.replace(/\n\s*/g, "\n" + indent + indent + indent);
    value = indent + indent + indent + value;
    return value;
}<|endoftext|>


<commit_before>import CheddarOperatorToken from '../literals/op';
import {PRECEDENCE, UNARY_PRECEDENCE, RA_PRECEDENCE, TYPE} from '../consts/ops';
import * as CheddarError from '../consts/err';
import CheddarLexer from './lex';

export default class CheddarShuntingYard extends CheddarLexer {
    exec(expression) {
        if (expression && expression.Code)
            this.Code = expression.Code;
        if (expression && expression.Index)
            this.Index = expression.Index;

        // Flatten the expression
        let current = expression;
        let tokens = [];
        if (!current ||
            !current.isExpression ||
            current._Tokens.length > 2
        )
            return this.close(expression);

        while (
            current &&
            current._Tokens.length === 2 &&
            (current.tok(1).isExpression || // prevents import recursion
                current.tok(1) instanceof CheddarShuntingYard)
        ) {
            if (current.tok().isExpression) //TODO: code, index
                tokens.push(new CheddarShuntingYard().exec(current.tok()));
            else
                tokens.push(current.tok());
            if (current.tok(1) instanceof CheddarShuntingYard) {
                tokens.push(current.tok(1));
                current = null;
                break;
            } else
                current = current.tok(1);
            //TODO: make sure this covers all cases; otherwise, see when this doesn't work
        }

        if (current && current._Tokens.length > 1) {
            this.Index = current.Index;
            return this.error(CheddarError.UNEXPECTED_TOKEN);
        }

        if (current &&
            current._Tokens.length === 1) {
            if (current.tok().isExpression)
                tokens.push(new CheddarShuntingYard().exec(current.tok()));
            else
                tokens.push(current.tok());
        }

        // Reorder tokens
        let operators = [],
            precedences = [],
            unary = true;
        for (let i = 0; i < tokens.length; i++) {
            let token = tokens[i],
                previousPrecedence = 0;
            if (token instanceof CheddarShuntingYard) {
                for (let i = 0; i < token._Tokens.length; i++)
                    this.Tokens = token.tok(i);
                unary = false;
            } else if (token instanceof CheddarOperatorToken) { // It's an operator
                if (RA_PRECEDENCE.has(token.tok(0)))
                    token.Tokens = TYPE.RTL;
                else if (unary)
                    token.Tokens = TYPE.UNARY;
                else
                    token.Tokens = TYPE.LTR;

                let precedence;
                switch (token.tok(1)) {
                    case TYPE.RTL:
                        precedence = RA_PRECEDENCE.get(token.tok());
                        break;
                    case TYPE.UNARY:
                        precedence = UNARY_PRECEDENCE.get(token.tok());
                        break;
                    case TYPE.LTR:
                        precedence = PRECEDENCE.get(token.tok());
                        break;
                }

                let minus = token.tok(1) == TYPE.RTL ? 0 : 1;
                previousPrecedence = precedences[precedences.length - 1];
                while (precedence - minus < previousPrecedence) {
                    this.Tokens = operators.pop();
                    precedences.pop();
                    previousPrecedence = precedences[precedences.length - 1];
                }

                operators.push(token);
                precedences.push(precedence);
                previousPrecedence = precedence;
                unary = true;
            } else {
                this.Tokens = token;
                unary = false;
            }
        }

        this.Tokens.push(...operators.reverse());

        return this.close();
    }
}<commit_msg>Fixed shunting yard for compiled-CST support<commit_after>import CheddarOperatorToken from '../literals/op';
import {PRECEDENCE, UNARY_PRECEDENCE, RA_PRECEDENCE, TYPE} from '../consts/ops';
import * as CheddarError from '../consts/err';
import CheddarLexer from './lex';

export default class CheddarShuntingYard extends CheddarLexer {
    exec(expression) {
        if (expression && expression.Code)
            this.Code = expression.Code;
        if (expression && expression.Index)
            this.Index = expression.Index;

        // Flatten the expression
        let current = expression;
        let tokens = [];
        if (!current ||
            !current.isExpression ||
            current._Tokens.length > 2
        )
            return this.close(expression);

        while (
            current &&
            current._Tokens.length === 2 &&
            (current._Tokens[1].isExpression || // prevents import recursion
                current._Tokens[1] instanceof CheddarShuntingYard)
        ) {
            if (current._Tokens[0].isExpression) //TODO: code, index
                tokens.push(new CheddarShuntingYard().exec(current._Tokens[0]));
            else
                tokens.push(current._Tokens[0]);
            if (current._Tokens[1] instanceof CheddarShuntingYard) {
                tokens.push(current._Tokens[1]);
                current = null;
                break;
            } else
                current = current._Tokens[1];
            //TODO: make sure this covers all cases; otherwise, see when this doesn't work
        }

        if (current && current._Tokens.length > 1) {
            this.Index = current.Index;
            return this.error(CheddarError.UNEXPECTED_TOKEN);
        }

        if (current &&
            current._Tokens.length === 1) {
            if (current._Tokens[0].isExpression)
                tokens.push(new CheddarShuntingYard().exec(current._Tokens[0]));
            else
                tokens.push(current._Tokens[0]);
        }

        // Reorder tokens
        let operators = [],
            precedences = [],
            unary = true;
        for (let i = 0; i < tokens.length; i++) {
            let token = tokens[i],
                previousPrecedence = 0;
            if (token instanceof CheddarShuntingYard) {
                for (let i = 0; i < token._Tokens.length; i++)
                    this.Tokens = token._Tokens[i];
                unary = false;
            } else if (token instanceof CheddarOperatorToken) { // It's an operator
                if (RA_PRECEDENCE.has(token._Tokens[0]))
                    token.Tokens = TYPE.RTL;
                else if (unary)
                    token.Tokens = TYPE.UNARY;
                else
                    token.Tokens = TYPE.LTR;

                let precedence;
                switch (token._Tokens[1]) {
                    case TYPE.RTL:
                        precedence = RA_PRECEDENCE.get(token._Tokens[0]);
                        break;
                    case TYPE.UNARY:
                        precedence = UNARY_PRECEDENCE.get(token._Tokens[0]);
                        break;
                    case TYPE.LTR:
                        precedence = PRECEDENCE.get(token._Tokens[0]);
                        break;
                }

                let minus = token._Tokens[1] == TYPE.RTL ? 0 : 1;
                previousPrecedence = precedences[precedences.length - 1];
                while (precedence - minus < previousPrecedence) {
                    this.Tokens = operators.pop();
                    precedences.pop();
                    previousPrecedence = precedences[precedences.length - 1];
                }

                operators.push(token);
                precedences.push(precedence);
                previousPrecedence = precedence;
                unary = true;
            } else {
                this.Tokens = token;
                unary = false;
            }
        }

        this.Tokens.push(...operators.reverse());

        return this.close();
    }
}
<|endoftext|>