<commit_before>import React from 'react';
import ObjectInspector from '@alexkuz/react-object-inspector';
import Dock from 'react-dock';

let _debugPopupHost;
let _debugPopupWrapper;

let _enabled = false;

function init(config) {
  if (_debugPopupHost) {
    return;
  }

  class DebugPopupHost extends React.Component {
    constructor(props) {
      super(props);
      const nullComponent = {
        pinRect: { left: -10000, right: -10000, top: -1000 },
        component: null
      };

      this.state = {
        components: [nullComponent],
        isVisible: false,
        shownComponent: nullComponent,
        position: 'left'
      };
    }

    render() {
      const { position, components: [{ pinRect }] } = this.state;

      const pinStyle = {
        position: 'absolute',
        backgroundColor: '#FFFF33',
        width: '16px',
        height: '16px',
        left: (position === 'left' ?
          (pinRect.right + window.scrollX - 24) + 'px' :
          (pinRect.left + window.scrollX + 8) + 'px'
        ),
        top: (pinRect.top + window.scrollY + 8) + 'px',
        borderRadius: '100px',
        boxShadow: '0 1px 4px rgba(0,0,0,0.3)',
        pointerEvents: 'auto',
        cursor: 'pointer'
      };

      const wrapperStyle = {
        position: 'absolute',
        zIndex: '999999999',
        top: 0,
        left: 0,
        width: 0,
        height: 0
      };

      const bittonsStyle = {
        position: 'absolute',
        top: '15px',
        right: '15px',
        cursor: 'pointer'
      };

      return (

          <Dock isVisible={this.state.isVisible}
                position={this.state.position}
                onVisibleChanged={isVisible => this.setState({ isVisible })}
                dimMode='none'>

                {'\u21E4'}

                {'\u21E5'}

                ×

            {this.state.isVisible && this.renderPanels()}
          </Dock>

      );
    }

    renderPanels() {
      const { getPanels } = this.props;
      const panels = getPanels([
        { name: 'props', getData: (c) => c.props },
        { name: 'state', getData: (c) => c.state },
        { name: 'context', getData: (c) => c.context },
      ]);
      const component = this.state.shownComponent.component;

      function getDataElement(panel) {
        const data = panel.getData(component);
        const isElement = React.isValidElement(data);

        return isElement ? data : <ObjectInspector className='RT-debug-inspector' data={data} />
      }

      return (

          {panels.map((panel, idx) =>

{panel.name}

              {getDataElement(panel)}

          )}

      );
    }

    addComponent(component, rect) {
      this.setState({ components: [{
        component,
        pinRect: rect
      }, ...this.state.components] });
    }

    removeComponent(component) {
      this.setState({ components: this.state.components.filter(c => c.component !== component) });
    }

    handleCloseClick = () => {
      this.setState({ isVisible: false });
    }

    handleLeftClick = () => {
      this.setState({ position: 'left' });
    }

    handleRightClick = () => {
      this.setState({ position: 'right' });
    }

    handlePinClick = () => {
      const { isVisible, components: [topComponent], shownComponent } = this.state;
      this.setState({
        isVisible: !isVisible || topComponent !== shownComponent,
        shownComponent: topComponent
      });
    }

    getPinElement() {
      return React.findDOMNode(this.refs.pin);
    }
  }

  _debugPopupWrapper = document.createElement('div');
  document.body.appendChild(_debugPopupWrapper);

  _debugPopupHost = React.render(
    <DebugPopupHost getPanels={config.getPanels} />,
    _debugPopupWrapper
  );
}

function deinit() {
  if (_debugPopupWrapper) {
    React.unmountComponentAtNode(_debugPopupWrapper);
    document.body.removeChild(_debugPopupWrapper);
    _debugPopupWrapper = null;
  }
  _debugPopupHost = null;
}

let triggerCalled = false;

export default function(options) {
  const config = Object.assign({
    enabledTrigger: cb => cb(true),
    getPanels: panels => panels,
    showPin: () => true
  }, options.imports[0]);

  function enter(e) {
    if (!_enabled || !config.showPin(this)) return;
    var rect = e.target.getBoundingClientRect();
    _debugPopupHost.addComponent(this, rect);
  }

  function leave(e) {
    if (!_enabled || !config.showPin(this)) return;
    if (e.toElement === _debugPopupHost.getPinElement()) {
      return;
    }
    _debugPopupHost.removeComponent(this);
  }

  function wrapClass(componentClass) {
    function WrappedClass() {
      componentClass.apply(this, arguments);

      this.handleMouseEnter = e => {
        enter.call(this, e);
      }

      this.handleMouseLeave = e => {
        leave.call(this, e);
      }
    }

    WrappedClass.prototype = Object.create(componentClass.prototype);
    WrappedClass.prototype.constructor = componentClass;
    WrappedClass.displayName = componentClass.displayName ||
      componentClass.prototype.constructor.name;

    Object.getOwnPropertyNames(componentClass)
      .filter(n => ['length', 'name', 'prototype'].indexOf(n) === -1)
      .forEach(n => WrappedClass[n] = componentClass[n]);

    WrappedClass.prototype.componentDidMount = function() {
      if (componentClass.prototype.componentDidMount) {
        componentClass.prototype.componentDidMount.call(this);
      }

      var el = React.findDOMNode(this);
      el.addEventListener('mouseenter', this.handleMouseEnter);
      el.addEventListener('mouseleave', this.handleMouseLeave);
    }

    WrappedClass.prototype.componentWillUnmount = function() {
      if (componentClass.prototype.componentWillUnmount) {
        componentClass.prototype.componentWillUnmount.call(this);
      }

      var el = React.findDOMNode(this);
      el.removeEventListener('mouseenter', this.handleMouseEnter);
      el.removeEventListener('mouseleave', this.handleMouseLeave);
    }

    return WrappedClass;
  }

  if (!triggerCalled) {
    config.enabledTrigger(enabled => {
      _enabled = enabled;
      if (enabled) {
        init(config);
      } else {
        deinit();
      }
    });
    triggerCalled = true;
  }

  return componentClass => wrapClass(componentClass);
}
<commit_msg>add component to getPanels args<commit_after>import React from 'react';
import ObjectInspector from '@alexkuz/react-object-inspector';
import Dock from 'react-dock';

let _debugPopupHost;
let _debugPopupWrapper;

let _enabled = false;

function init(config) {
  if (_debugPopupHost) {
    return;
  }

  class DebugPopupHost extends React.Component {
    constructor(props) {
      super(props);
      const nullComponent = {
        pinRect: { left: -10000, right: -10000, top: -1000 },
        component: null
      };

      this.state = {
        components: [nullComponent],
        isVisible: false,
        shownComponent: nullComponent,
        position: 'left'
      };
    }

    render() {
      const { position, components: [{ pinRect }] } = this.state;

      const pinStyle = {
        position: 'absolute',
        backgroundColor: '#FFFF33',
        width: '16px',
        height: '16px',
        left: (position === 'left' ?
          (pinRect.right + window.scrollX - 24) + 'px' :
          (pinRect.left + window.scrollX + 8) + 'px'
        ),
        top: (pinRect.top + window.scrollY + 8) + 'px',
        borderRadius: '100px',
        boxShadow: '0 1px 4px rgba(0,0,0,0.3)',
        pointerEvents: 'auto',
        cursor: 'pointer'
      };

      const wrapperStyle = {
        position: 'absolute',
        zIndex: '999999999',
        top: 0,
        left: 0,
        width: 0,
        height: 0
      };

      const bittonsStyle = {
        position: 'absolute',
        top: '15px',
        right: '15px',
        cursor: 'pointer',
        lineHeight: '15px'
      };

      return (

          <Dock isVisible={this.state.isVisible}
                position={this.state.position}
                onVisibleChanged={isVisible => this.setState({ isVisible })}
                dimMode='none'>

                {'\u21E4'}

                {'\u21E5'}

                ×

            {this.state.isVisible && this.renderPanels()}
          </Dock>

      );
    }

    renderPanels() {
      const { getPanels } = this.props;
      const component = this.state.shownComponent.component;

      const panels = getPanels([
        { name: 'props', data: component.props },
        { name: 'state', data: component.state },
        { name: 'context', data: component.context },
      ], component);

      function getDataElement(panel) {
        const data = panel.data;
        const isElement = React.isValidElement(data);

        return isElement ? data : <ObjectInspector className='RT-debug-inspector' data={data} />
      }

      return (

          {panels.map((panel, idx) =>

{panel.name}

              {getDataElement(panel)}

          )}

      );
    }

    addComponent(component, rect) {
      this.setState({ components: [{
        component,
        pinRect: rect
      }, ...this.state.components] });
    }

    removeComponent(component) {
      this.setState({ components: this.state.components.filter(c => c.component !== component) });
    }

    handleCloseClick = () => {
      this.setState({ isVisible: false });
    }

    handleLeftClick = () => {
      this.setState({ position: 'left' });
    }

    handleRightClick = () => {
      this.setState({ position: 'right' });
    }

    handlePinClick = () => {
      const { isVisible, components: [topComponent], shownComponent } = this.state;
      this.setState({
        isVisible: !isVisible || topComponent !== shownComponent,
        shownComponent: topComponent
      });
    }

    getPinElement() {
      return React.findDOMNode(this.refs.pin);
    }
  }

  _debugPopupWrapper = document.createElement('div');
  document.body.appendChild(_debugPopupWrapper);

  _debugPopupHost = React.render(
    <DebugPopupHost getPanels={config.getPanels} />,
    _debugPopupWrapper
  );
}

function deinit() {
  if (_debugPopupWrapper) {
    React.unmountComponentAtNode(_debugPopupWrapper);
    document.body.removeChild(_debugPopupWrapper);
    _debugPopupWrapper = null;
  }
  _debugPopupHost = null;
}

let triggerCalled = false;

export default function(options) {
  const config = Object.assign({
    enabledTrigger: cb => cb(true),
    getPanels: panels => panels,
    showPin: () => true
  }, options.imports[0]);

  function enter(e) {
    if (!_enabled || !config.showPin(this)) return;
    var rect = e.target.getBoundingClientRect();
    _debugPopupHost.addComponent(this, rect);
  }

  function leave(e) {
    if (!_enabled || !config.showPin(this)) return;
    if (e.toElement === _debugPopupHost.getPinElement()) {
      return;
    }
    _debugPopupHost.removeComponent(this);
  }

  function wrapClass(componentClass) {
    function WrappedClass() {
      componentClass.apply(this, arguments);

      this.handleMouseEnter = e => {
        enter.call(this, e);
      }

      this.handleMouseLeave = e => {
        leave.call(this, e);
      }
    }

    WrappedClass.prototype = Object.create(componentClass.prototype);
    WrappedClass.prototype.constructor = componentClass;
    WrappedClass.displayName = componentClass.displayName ||
      componentClass.prototype.constructor.name;

    Object.getOwnPropertyNames(componentClass)
      .filter(n => ['length', 'name', 'prototype'].indexOf(n) === -1)
      .forEach(n => WrappedClass[n] = componentClass[n]);

    WrappedClass.prototype.componentDidMount = function() {
      if (componentClass.prototype.componentDidMount) {
        componentClass.prototype.componentDidMount.call(this);
      }

      var el = React.findDOMNode(this);
      el.addEventListener('mouseenter', this.handleMouseEnter);
      el.addEventListener('mouseleave', this.handleMouseLeave);
    }

    WrappedClass.prototype.componentWillUnmount = function() {
      if (componentClass.prototype.componentWillUnmount) {
        componentClass.prototype.componentWillUnmount.call(this);
      }

      var el = React.findDOMNode(this);
      el.removeEventListener('mouseenter', this.handleMouseEnter);
      el.removeEventListener('mouseleave', this.handleMouseLeave);
    }

    return WrappedClass;
  }

  if (!triggerCalled) {
    config.enabledTrigger(enabled => {
      _enabled = enabled;
      if (enabled) {
        init(config);
      } else {
        deinit();
      }
    });
    triggerCalled = true;
  }

  return componentClass => wrapClass(componentClass);
}
<|endoftext|>


<commit_before>// @flow

import {createAction, type ActionType} from 'redux-actions'

import {createVoidPayloadAction, secureFetch} from '../../common/actions'
import {fetchDeployment} from './deployments'
import {fetchFeedSource} from './feeds'
import {downloadMergedFeedViaToken} from './projects'
import {downloadSnapshotViaCredentials} from '../../editor/actions/snapshots'

import type {ServerJob} from '../../types'
import type {dispatchFn, getStateFn} from '../../types/reducers'

type ErrorMessage = {
  action?: string,
  detail?: any,
  message: string,
  title?: string
}

export const clearStatusModal = createVoidPayloadAction('CLEAR_STATUS_MODAL')
const handlingFinishedJob = createAction(
  'HANDLING_FINISHED_JOB',
  (payload: ServerJob) => payload
)
export const receiveJobs = createAction(
  'RECEIVE_JOBS',
  (payload: Array<ServerJob>) => payload
)
export const removeRetiredJob = createAction(
  'REMOVE_RETIRED_JOB',
  (payload: ServerJob) => payload
)
export const setErrorMessage = createAction(
  'SET_ERROR_MESSAGE',
  (payload: ErrorMessage | Promise<ErrorMessage>) => payload
)
export const setJobMonitorTimer = createAction(
  'SET_JOBMONITOR_TIMER',
  (payload: ?IntervalID) => payload
)
export const setJobMonitorVisible = createAction(
  'SET_JOBMONITOR_VISIBLE',
  (payload: boolean) => payload
)
const setAppInfo = createAction(
  'SET_APP_INFO',
  (payload: {
    commit: string,
    repoUrl: string
  }) => payload
)

export type StatusActions = ActionType<typeof clearStatusModal> |
  ActionType<typeof handlingFinishedJob> |
  ActionType<typeof receiveJobs> |
  ActionType<typeof removeRetiredJob> |
  ActionType<typeof setJobMonitorTimer> |
  ActionType<typeof setJobMonitorVisible> |
  ActionType<typeof setErrorMessage> |
  ActionType<typeof setAppInfo>

/**
 * Check status of user's jobs. Handle any finished jobs and if there are no
 * remaining active jobs, stop job monitor.
 */
export function checkJobStatus () {
  return function (dispatch: dispatchFn, getState: getStateFn) {
    return dispatch(secureFetch(`/api/manager/secure/status/jobs`))
      .then(response => response.json())
      .then(jobs => {
        // Check for any just-finished jobs
        const completedJobs = jobs
          .filter(job => job.status.completed || job.status.error)
        completedJobs
          // Retire any completed or errored jobs.
          .forEach(job => dispatch(handleFinishedJob(job)))

        const remainingJobs = jobs
          .filter(job => !job.status.completed && !job.status.error)
        if (remainingJobs.length === 0) {
          // If there are no remaining jobs, stop the timer.
          dispatch(stopJobMonitor())
        }
        // Add remaining jobs to set of active jobs. Note, this may be an empty
        // array if finished jobs have been handled, but that is the expected
        // behavior because these finished jobs will appear in a "retired" state.
        dispatch(receiveJobs(remainingJobs))
      })
  }
}

export function fetchAppInfo () {
  return function (dispatch: dispatchFn, getState: getStateFn) {
    // only fetch if we don't yet have server info
    if (!getState().status.appInfo) {
      // fetch info.  If an error occurs or response json doesn't match, set
      // server info to value indicating an unknown commit and repoUrl
      return dispatch(secureFetch('/api/manager/public/appinfo'))
        .then(response => response.json())
        .then(info => {
          if (info.commit && info.repoUrl) {
            info.repoUrl = info.repoUrl.replace('.git', '')
            dispatch(setAppInfo(info))
          } else {
            throw new Error('unable to interpret app info')
          }
        })
        .catch(() => {
          dispatch(setAppInfo({
            commit: 'unknown',
            repoUrl: '?'
          }))
        })
    }
  }
}

/* eslint-disable complexity */
export function handleFinishedJob (job: ServerJob) {
  return function (dispatch: dispatchFn, getState: getStateFn) {
    dispatch(handlingFinishedJob(job))
    switch (job.type) {
      case 'VALIDATE_FEED':
        if (!job.feedSourceId) {
          // FIXME use setErrorMessage instead?
          console.warn('No feedSourceId found on job')
          return
        }
        dispatch(fetchFeedSource(job.feedSourceId, true))
        break
      // CREATE_SNAPSHOT accounts for both creating an initial snapshot from GTFS
      // as well as "restoring" a snapshot to the active buffer, which essentially
      // just creates a copy of the snapshot to restore and points at the new
      // snapshot for the new buffer.
      case 'CREATE_SNAPSHOT':
        if (!job.feedSourceId) {
          // FIXME use setErrorMessage instead?
          console.warn('No feedSourceId found on job')
          return
        }
        dispatch(fetchFeedSource(job.feedSourceId, true))
        break
      // case 'PROCESS_SNAPSHOT':
      //   dispatch(fetchSnapshots(job.feedVersion.feedSource))
      //   break
      //
      case 'CREATE_FEEDVERSION_FROM_SNAPSHOT':
        if (!job.feedSourceId) {
          // FIXME use setErrorMessage instead?
          console.warn('No feedSourceId found on job')
          return
        }
        dispatch(fetchFeedSource(job.feedSourceId, true))
        break
      case 'EXPORT_SNAPSHOT_TO_GTFS':
        if (job.parentJobId) {
          console.log('Not downloading snapshot GTFS. Export job part of feed version creation.')
        } else {
          if (job.snapshot) {
            dispatch(downloadSnapshotViaCredentials(job.snapshot, false))
          }
        }
        break
      case 'MERGE_PROJECT_FEEDS':
        if (!job.project) {
          // FIXME use setErrorMessage instead?
          console.warn('No project found on job')
          return
        }
        dispatch(downloadMergedFeedViaToken(job.project, false))
        break
      case 'DEPLOY_TO_OTP':
        return dispatch(fetchDeployment(job.deploymentId))
      // No completion step for build transport network. User should just
      // re-request isochrones.
      case 'BUILD_TRANSPORT_NETWORK':
      default:
        console.warn(`No completion step defined for job type ${job.type}`)
    }
  }
}

export function handleJobResponse (response: Response, message: string) {
  return function (dispatch: dispatchFn, getState: getStateFn) {
    if (response.status >= 400) {
      const props = message
        ? {message}
        // If no message specified, use error message supplied by JSON response
        : response.json()
      return dispatch(setErrorMessage(props))
    } else {
      // Resulting JSON contains message and job ID wich which to monitor job.
      const json: {jobId: number, message: string} = (response.json(): any)
      dispatch(startJobMonitor())
      // Return json with job ID in case it is needed upstream
      return json
    }
  }
}

/**
 * Start job monitor. This stops any existing timer function and initializes
 * the fetch user jobs status function on a timer.
 */
export function startJobMonitor (showMonitor: boolean = true) {
  return function (dispatch: dispatchFn, getState: getStateFn) {
    stopCurrentTimer(getState())

    const timerFunction = () => dispatch(checkJobStatus())
    // make an initial call right now
    timerFunction()
    const timer = setInterval(timerFunction, 2000)
    if (showMonitor) {
      dispatch(setJobMonitorVisible(true))
    }
    dispatch(setJobMonitorTimer(timer))
  }
}

/**
 * Stop job time function stored with timer ID stored in state.
 */
function stopCurrentTimer (state) {
  const {timer} = state.status.jobMonitor
  if (timer) clearInterval(timer)
}

/**
 * Stop current job timer function and set job monitor (timer ID) to null.
 */
export function stopJobMonitor () {
  return function (dispatch: dispatchFn, getState: getStateFn) {
    stopCurrentTimer(getState())
    dispatch(setJobMonitorTimer(null))
  }
}
<commit_msg>fix(job-monitor): only start continuous job fetch if jobs exist<commit_after>// @flow

import {createAction, type ActionType} from 'redux-actions'

import {createVoidPayloadAction, secureFetch} from '../../common/actions'
import {fetchDeployment} from './deployments'
import {fetchFeedSource} from './feeds'
import {downloadMergedFeedViaToken} from './projects'
import {downloadSnapshotViaCredentials} from '../../editor/actions/snapshots'

import type {ServerJob} from '../../types'
import type {dispatchFn, getStateFn} from '../../types/reducers'

type ErrorMessage = {
  action?: string,
  detail?: any,
  message: string,
  title?: string
}

export const clearStatusModal = createVoidPayloadAction('CLEAR_STATUS_MODAL')
const handlingFinishedJob = createAction(
  'HANDLING_FINISHED_JOB',
  (payload: ServerJob) => payload
)
export const receiveJobs = createAction(
  'RECEIVE_JOBS',
  (payload: Array<ServerJob>) => payload
)
export const removeRetiredJob = createAction(
  'REMOVE_RETIRED_JOB',
  (payload: ServerJob) => payload
)
export const setErrorMessage = createAction(
  'SET_ERROR_MESSAGE',
  (payload: ErrorMessage | Promise<ErrorMessage>) => payload
)
export const setJobMonitorTimer = createAction(
  'SET_JOBMONITOR_TIMER',
  (payload: ?IntervalID) => payload
)
export const setJobMonitorVisible = createAction(
  'SET_JOBMONITOR_VISIBLE',
  (payload: boolean) => payload
)
const setAppInfo = createAction(
  'SET_APP_INFO',
  (payload: {
    commit: string,
    repoUrl: string
  }) => payload
)

export type StatusActions = ActionType<typeof clearStatusModal> |
  ActionType<typeof handlingFinishedJob> |
  ActionType<typeof receiveJobs> |
  ActionType<typeof removeRetiredJob> |
  ActionType<typeof setJobMonitorTimer> |
  ActionType<typeof setJobMonitorVisible> |
  ActionType<typeof setErrorMessage> |
  ActionType<typeof setAppInfo>

/**
 * Check status of user's jobs. Handle any finished jobs and if there are no
 * remaining active jobs, stop job monitor.
 */
export function checkJobStatus () {
  return function (dispatch: dispatchFn, getState: getStateFn) {
    return dispatch(secureFetch(`/api/manager/secure/status/jobs`))
      .then(response => response.json())
      .then(jobs => {
        // Check for any just-finished jobs
        const completedJobs = jobs
          .filter(job => job.status.completed || job.status.error)
        completedJobs
          // Retire any completed or errored jobs.
          .forEach(job => dispatch(handleFinishedJob(job)))

        const remainingJobs = jobs
          .filter(job => !job.status.completed && !job.status.error)
        if (remainingJobs.length === 0) {
          // If there are no remaining jobs, stop the timer.
          dispatch(stopJobMonitor())
        }
        // Add remaining jobs to set of active jobs. Note, this may be an empty
        // array if finished jobs have been handled, but that is the expected
        // behavior because these finished jobs will appear in a "retired" state.
        dispatch(receiveJobs(remainingJobs))
        return jobs
      })
  }
}

export function fetchAppInfo () {
  return function (dispatch: dispatchFn, getState: getStateFn) {
    // only fetch if we don't yet have server info
    if (!getState().status.appInfo) {
      // fetch info.  If an error occurs or response json doesn't match, set
      // server info to value indicating an unknown commit and repoUrl
      return dispatch(secureFetch('/api/manager/public/appinfo'))
        .then(response => response.json())
        .then(info => {
          if (info.commit && info.repoUrl) {
            info.repoUrl = info.repoUrl.replace('.git', '')
            dispatch(setAppInfo(info))
          } else {
            throw new Error('unable to interpret app info')
          }
        })
        .catch(() => {
          dispatch(setAppInfo({
            commit: 'unknown',
            repoUrl: '?'
          }))
        })
    }
  }
}

/* eslint-disable complexity */
export function handleFinishedJob (job: ServerJob) {
  return function (dispatch: dispatchFn, getState: getStateFn) {
    dispatch(handlingFinishedJob(job))
    switch (job.type) {
      case 'VALIDATE_FEED':
        if (!job.feedSourceId) {
          // FIXME use setErrorMessage instead?
          console.warn('No feedSourceId found on job')
          return
        }
        dispatch(fetchFeedSource(job.feedSourceId, true))
        break
      // CREATE_SNAPSHOT accounts for both creating an initial snapshot from GTFS
      // as well as "restoring" a snapshot to the active buffer, which essentially
      // just creates a copy of the snapshot to restore and points at the new
      // snapshot for the new buffer.
      case 'CREATE_SNAPSHOT':
        if (!job.feedSourceId) {
          // FIXME use setErrorMessage instead?
          console.warn('No feedSourceId found on job')
          return
        }
        dispatch(fetchFeedSource(job.feedSourceId, true))
        break
      // case 'PROCESS_SNAPSHOT':
      //   dispatch(fetchSnapshots(job.feedVersion.feedSource))
      //   break
      //
      case 'CREATE_FEEDVERSION_FROM_SNAPSHOT':
        if (!job.feedSourceId) {
          // FIXME use setErrorMessage instead?
          console.warn('No feedSourceId found on job')
          return
        }
        dispatch(fetchFeedSource(job.feedSourceId, true))
        break
      case 'EXPORT_SNAPSHOT_TO_GTFS':
        if (job.parentJobId) {
          console.log('Not downloading snapshot GTFS. Export job part of feed version creation.')
        } else {
          if (job.snapshot) {
            dispatch(downloadSnapshotViaCredentials(job.snapshot, false))
          }
        }
        break
      case 'MERGE_PROJECT_FEEDS':
        if (!job.project) {
          // FIXME use setErrorMessage instead?
          console.warn('No project found on job')
          return
        }
        dispatch(downloadMergedFeedViaToken(job.project, false))
        break
      case 'DEPLOY_TO_OTP':
        return dispatch(fetchDeployment(job.deploymentId))
      // No completion step for build transport network. User should just
      // re-request isochrones.
      case 'BUILD_TRANSPORT_NETWORK':
      default:
        console.warn(`No completion step defined for job type ${job.type}`)
    }
  }
}

export function handleJobResponse (response: Response, message: string) {
  return function (dispatch: dispatchFn, getState: getStateFn) {
    if (response.status >= 400) {
      const props = message
        ? {message}
        // If no message specified, use error message supplied by JSON response
        : response.json()
      return dispatch(setErrorMessage(props))
    } else {
      // Resulting JSON contains message and job ID wich which to monitor job.
      const json: {jobId: number, message: string} = (response.json(): any)
      dispatch(startJobMonitor())
      // Return json with job ID in case it is needed upstream
      return json
    }
  }
}

/**
 * Start job monitor. This stops any existing timer function and initializes
 * the fetch user jobs status function on a timer.
 */
export function startJobMonitor (showMonitor: boolean = true) {
  return function (dispatch: dispatchFn, getState: getStateFn) {
    stopCurrentTimer(getState())

    const timerFunction = () => dispatch(checkJobStatus())
    // make an initial call right now
    timerFunction()
      .then(jobs => {
        if (jobs.length > 0) {
          // Set up a check for every two seconds if jobs are running.
          const timer = setInterval(timerFunction, 2000)
          dispatch(setJobMonitorTimer(timer))
          if (showMonitor) dispatch(setJobMonitorVisible(true))
        }
      })
      .catch(err => console.warn('Error fetchings jobs', err))
  }
}

/**
 * Stop job time function stored with timer ID stored in state.
 */
function stopCurrentTimer (state) {
  const {timer} = state.status.jobMonitor
  if (timer) clearInterval(timer)
}

/**
 * Stop current job timer function and set job monitor (timer ID) to null.
 */
export function stopJobMonitor () {
  return function (dispatch: dispatchFn, getState: getStateFn) {
    stopCurrentTimer(getState())
    dispatch(setJobMonitorTimer(null))
  }
}
<|endoftext|>


<commit_before>import VictoryChart from "./components/victory-chart/victory-chart";
import VictoryLine from "./components/victory-line/victory-line";
import VictoryAxis from "./components/victory-axis/victory-axis";
import VictoryArea from "./components/victory-area/victory-area";
import VictoryBar from "./components/victory-bar/victory-bar";
import VictoryScatter from "./components/victory-scatter/victory-scatter";
import VictoryGroup from "./components/victory-group/victory-group";
import VictoryStack from "./components/victory-stack/victory-stack";
import VictoryCandlestick from "./components/victory-candlestick/victory-candlestick";

export {
  VictoryChart,
  VictoryLine,
  VictoryAxis,
  VictoryArea,
  VictoryBar,
  VictoryScatter,
  VictoryGroup,
  VictoryStack,
  VictoryCandlestick
};
<commit_msg>alter export format<commit_after>export { default as VictoryChart } from "./components/victory-chart/victory-chart";
export { default as VictoryLine } from "./components/victory-line/victory-line";
export { default as VictoryAxis } from "./components/victory-axis/victory-axis";
export { default as VictoryArea } from "./components/victory-area/victory-area";
export { default as VictoryBar } from "./components/victory-bar/victory-bar";
export { default as VictoryScatter } from "./components/victory-scatter/victory-scatter";
export { default as VictoryGroup } from "./components/victory-group/victory-group";
export { default as VictoryStack } from "./components/victory-stack/victory-stack";
export {
  default as VictoryCandlestick
} from "./components/victory-candlestick/victory-candlestick";
<|endoftext|>


<commit_before>'use strict';

import React from 'react'
import ReactDOM from 'react-dom'
import {AppContainer} from 'react-hot-loader'
import configureStore from './store/configureStore'
import Root from './containers/Root'
import Reactotron from 'reactotron'

if (process.env.NODE_ENV === 'development') {
  Reactotron.connect() // connect with defaults
}

const store = configureStore();
const rootElement = document.getElementById('root');

ReactDOM.render(
  <AppContainer>
    <Root store={store}/>
  </AppContainer>,
  rootElement
);

if (module.hot) {
  module.hot.accept('./containers/Root', () => {
    const NextRoot = require('./containers/Root').default;
    ReactDOM.render(
      <AppContainer>
        <NextRoot store={store}/>
      </AppContainer>,
      rootElement
    );
  });
}
<commit_msg>NS: suppress hot-loader warning<commit_after>'use strict';

require("react-hot-loader/patch");

import React from 'react'
import ReactDOM from 'react-dom'
import {AppContainer} from 'react-hot-loader'
import configureStore from './store/configureStore'
import Root from './containers/Root'
import Reactotron from 'reactotron'

if (process.env.NODE_ENV === 'development') {
  Reactotron.connect() // connect with defaults
}

const store = configureStore();
const rootElement = document.getElementById('root');

ReactDOM.render(
  <AppContainer>
    <Root store={store}/>
  </AppContainer>,
  rootElement
);

if (module.hot) {
  module.hot.accept('./containers/Root', () => {
    const NextRoot = require('./containers/Root').default;
    ReactDOM.render(
      <AppContainer>
        <NextRoot store={store}/>
      </AppContainer>,
      rootElement
    );
  });
}
<|endoftext|>


<commit_before>function defaultEqualityCheck(a, b) {
  return a === b
}

export function defaultMemoize(func, equalityCheck = defaultEqualityCheck) {
  let lastArgs = null
  let lastResult = null
  return (...args) => {
    if (
      lastArgs !== null &&
      lastArgs.length === args.length &&
      args.every((value, index) => equalityCheck(value, lastArgs[index], index))
    ) {
      return lastResult
    }
    lastResult = func(...args)
    lastArgs = args
    return lastResult
  }
}

function getDependencies(funcs) {
  const dependencies = Array.isArray(funcs[0]) ? funcs[0] : funcs

  if (!dependencies.every(dep => typeof dep === 'function')) {
    const dependencyTypes = dependencies.map(
      dep => typeof dep
    ).join(', ')
    throw new Error(
      `Selector creators expect all input-selectors to be functions, ` +
      `instead received the following types: [${dependencyTypes}]`
    )
  }

  return dependencies
}

export function createSelectorCreator(memoize, ...memoizeOptions) {
  return (...funcs) => {
    let recomputations = 0
    const resultFunc = funcs.pop()
    const dependencies = getDependencies(funcs)

    const memoizedResultFunc = memoize(
      (...args) => {
        recomputations++
        return resultFunc(...args)
      },
      ...memoizeOptions
    )

    const selector = (state, props, ...args) => {
      const params = dependencies.map(
        dependency => dependency(state, props, ...args)
      )
      return memoizedResultFunc(...params)
    }

    selector.resultFunc = resultFunc
    selector.recomputations = () => recomputations
    selector.resetRecomputations = () => recomputations = 0
    return selector
  }
}

export const createSelector = createSelectorCreator(defaultMemoize)

export function createStructuredSelector(selectors, selectorCreator = createSelector) {
  if (typeof selectors !== 'object') {
    throw new Error(
      `createStructuredSelector expects first argument to be an object ` +
      `where each property is a selector, instead received a ${typeof selectors}`
    )
  }
  const objectKeys = Object.keys(selectors)
  return selectorCreator(
    objectKeys.map(key => selectors[key]),
    (...values) => {
      return values.reduce((composition, value, index) => {
        composition[objectKeys[index]] = value
        return composition
      }, {})
    }
  )
}
<commit_msg>Speed up selector execution<commit_after>function defaultEqualityCheck(a, b) {
  return a === b
}

function areArgumentsShallowlyEqual(equalityCheck, prev, next) {
  if (prev === next) {
    return true
  }

  if (prev === null || next === null || prev.length !== next.length) {
    return false
  }

  const length = prev.length
  for (let i = 0; i < length; i++) {
    if (!equalityCheck(prev[i], next[i])) {
      return false
    }
  }

  return true
}

export function defaultMemoize(func, equalityCheck = defaultEqualityCheck) {
  let lastArgs = null
  let lastResult = null

  return function () {
    if (!areArgumentsShallowlyEqual(equalityCheck, lastArgs, arguments)) {
      lastResult = func.apply(null, arguments)
    }

    lastArgs = arguments
    return lastResult
  }
}

function getDependencies(funcs) {
  const dependencies = Array.isArray(funcs[0]) ? funcs[0] : funcs

  if (!dependencies.every(dep => typeof dep === 'function')) {
    const dependencyTypes = dependencies.map(
      dep => typeof dep
    ).join(', ')
    throw new Error(
      'Selector creators expect all input-selectors to be functions, ' +
      `instead received the following types: [${dependencyTypes}]`
    )
  }

  return dependencies
}

export function createSelectorCreator(memoize, ...memoizeOptions) {
  return (...funcs) => {
    let recomputations = 0
    const resultFunc = funcs.pop()
    const dependencies = getDependencies(funcs)

    const memoizedResultFunc = memoize(
      function () {
        recomputations++
        return resultFunc.apply(null, arguments)
      },
      ...memoizeOptions
    )

    function selector() {
      const params = []
      const length = dependencies.length

      for (let i = 0; i < length; i++) {
        params.push(dependencies[i].apply(null, arguments))
      }

      return memoizedResultFunc.apply(null, params)
    }

    selector.resultFunc = resultFunc
    selector.recomputations = () => recomputations
    selector.resetRecomputations = () => recomputations = 0
    return selector
  }
}

export const createSelector = createSelectorCreator(defaultMemoize)

export function createStructuredSelector(selectors, selectorCreator = createSelector) {
  if (typeof selectors !== 'object') {
    throw new Error(
      'createStructuredSelector expects first argument to be an object ' +
      `where each property is a selector, instead received a ${typeof selectors}`
    )
  }
  const objectKeys = Object.keys(selectors)
  return selectorCreator(
    objectKeys.map(key => selectors[key]),
    (...values) => {
      return values.reduce((composition, value, index) => {
        composition[objectKeys[index]] = value
        return composition
      }, {})
    }
  )
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

export const MOUSE_RIGHT_BUTTON = 2;

export default class TrackingLink extends Component {
  static propTypes = {
    children: PropTypes.node.isRequired,
    href: PropTypes.string.isRequired,
    className: PropTypes.string,
    onClick: PropTypes.func,
    targetBlank: PropTypes.bool,
    preventDefault: PropTypes.bool,
    trackingTimeout: PropTypes.number
  };

  static defaultProps = {
    trackingTimeout: 500, // ms
  };

  /* istanbul ignore next */
  constructor(props) {
    super(props);

    this.linkEl = null;

    this.onClick = this.onClick.bind(this);
    this.navigateToUrl = this.navigateToUrl.bind(this);
    this.resolveByTimeout = this.resolveByTimeout.bind(this);
    this.isMouseWheelClick = this.isMouseWheelClick.bind(this);
    this.isChrome = this.isChrome.bind(this);
  }

  onClick(event) {
    event.preventDefault();

    const nativeEvent = event.nativeEvent;

    // on Windows right click triggers touchTap event (react-tap-event-plugin bug)
    if (nativeEvent.button === MOUSE_RIGHT_BUTTON) {
      return false;
    }

    const { onClick: trackingFunction, trackingTimeout } = this.props;

    // try to track the click but with the timeout
    // in case of tracking-blocking browser extensions or failure to load analytics scripts
    return Promise
      .race([
        trackingFunction(event),
        this.resolveByTimeout(trackingTimeout),
      ])
      .then(this.navigateToUrl(nativeEvent));
  }

  navigateToUrl(event) {
    return () => {
      const {
        href,
        targetBlank,
        preventDefault,
      } = this.props;

      const ctrlKeyPressed = event.metaKey || event.ctrlKey;
      const mouseWheelClick = this.isMouseWheelClick(event);
      const isChrome = this.isChrome();

      // in chrome it's not possible to prevent opening a new tab on mouse wheel click
      // so we prevent opening url in the current tab and allow to open it in a new tab by Chrome
      // for other browsers we'll open in a new tab
      if (mouseWheelClick && isChrome) {
        return false;
      }

      if (href && !preventDefault) {
        if (targetBlank || ctrlKeyPressed || (mouseWheelClick && !isChrome)) {
          global.window.open(href, '_blank');
        } else {
          global.location.href = href;
        }
      }

      return true;
    };
  }

  resolveByTimeout(timeout) {
    return new Promise(resolve => {
      global.setTimeout(resolve, timeout);
    });
  }

  isMouseWheelClick(event) {
    let mouseWheelClick = false;

    if (event.which && event.which === 2) {
      mouseWheelClick = true;
    } else if (event.button && event.button === 1) {
      mouseWheelClick = true;
    }

    return mouseWheelClick;
  }

  isChrome() {
    return global.navigator.userAgent.indexOf('Chrome') > -1;
  }

  render() {
    const {
      children,
      href,
      className: addtionalClassName,
      onClick: trackingFunction,
    } = this.props;

    const className = classNames('TrackingLink', {
      [addtionalClassName]: !!addtionalClassName,
    });
    const onClick = trackingFunction ? this.onClick : undefined;

    return (
      <a
        className={className}
        href={href}
        onClick={onClick}
        ref={linkEl => { this.linkEl = linkEl; }}
      >
        {children}
      </a>
    );
  }
}
<commit_msg>Corrects need help btn behavior in Safari<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

export const MOUSE_RIGHT_BUTTON = 2;

export default class TrackingLink extends Component {
  static propTypes = {
    children: PropTypes.node.isRequired,
    href: PropTypes.string.isRequired,
    className: PropTypes.string,
    onClick: PropTypes.func,
    targetBlank: PropTypes.bool,
    preventDefault: PropTypes.bool,
    trackingTimeout: PropTypes.number
  };

  static defaultProps = {
    trackingTimeout: 500, // ms
  };

  /* istanbul ignore next */
  constructor(props) {
    super(props);

    this.linkEl = null;

    this.onClick = this.onClick.bind(this);
    this.navigateToUrl = this.navigateToUrl.bind(this);
    this.resolveByTimeout = this.resolveByTimeout.bind(this);
    this.isMouseWheelClick = this.isMouseWheelClick.bind(this);
    this.isChrome = this.isChrome.bind(this);
    this.isSafari = this.isSafari.bind(this);
    this.isFloatingNeedHelpBtn = this.isFloatingNeedHelpBtn.bind(this);
    this.windowRef = null;
  }

  onClick(event) {
    event.preventDefault();

    const nativeEvent = event.nativeEvent;

    // on Windows right click triggers touchTap event (react-tap-event-plugin bug)
    if (nativeEvent.button === MOUSE_RIGHT_BUTTON) {
      return false;
    }

    const { onClick: trackingFunction, trackingTimeout, className } = this.props;

    const isSafari = this.isSafari();
    const isFloatingNeedHelpBtn = this.isFloatingNeedHelpBtn(className);

    if (isSafari && isFloatingNeedHelpBtn) {
      // Safari blocks any window.open() calls made inside an async call
      // the workaround is to call window.open() prior to the
      // async call and then set the window location/url when the promise resolves.
      // we're specifically targeting the floating 'NEED HELP?' button on Safari
      // because this solution affects UX too greatly to use across the board
      this.windowRef = global.window.open();
    }

    // try to track the click but with the timeout
    // in case of tracking-blocking browser extensions or failure to load analytics scripts
    return Promise
      .race([
        trackingFunction(event),
        this.resolveByTimeout(trackingTimeout),
      ])
      .then(this.navigateToUrl(nativeEvent));
  }

  navigateToUrl(event) {
    return () => {
      const {
        href,
        targetBlank,
        preventDefault,
      } = this.props;

      const ctrlKeyPressed = event.metaKey || event.ctrlKey;
      const mouseWheelClick = this.isMouseWheelClick(event);
      const isChrome = this.isChrome();

      // in chrome it's not possible to prevent opening a new tab on mouse wheel click
      // so we prevent opening url in the current tab and allow to open it in a new tab by Chrome
      // for other browsers we'll open in a new tab
      if (mouseWheelClick && isChrome) {
        return false;
      }

      if (href && !preventDefault) {
        if (targetBlank || ctrlKeyPressed || (mouseWheelClick && !isChrome)) {

          // aka if we've detected Safari and the floating 'NEED HELP?' button
          if (this.windowRef) {
            this.windowRef.location = href;
          } else {
            global.window.open(href, '_blank');
          }

        } else {

          // necessary to prevent blank page from loading
          if (this.windowRef) {
            this.windowRef.close();
            this.windowRef = null;
          }

          global.location.href = href;
        }
      }

      return true;
    };
  }

  resolveByTimeout(timeout) {
    return new Promise(resolve => {
      global.setTimeout(resolve, timeout);
    });
  }

  isMouseWheelClick(event) {
    let mouseWheelClick = false;

    if (event.which && event.which === 2) {
      mouseWheelClick = true;
    } else if (event.button && event.button === 1) {
      mouseWheelClick = true;
    }

    return mouseWheelClick;
  }

  isChrome() {
    return global.navigator.userAgent.indexOf('Chrome') > -1;
  }

  isSafari() {
    return global.navigator.userAgent.indexOf('Safari') > -1;
  }

  isFloatingNeedHelpBtn(className) {
    if (!className) {
      return false;
    }

    const floatingHelpBtn = 'DashboardPage__floating-help-btn'.toLowerCase();

    return className.toLowerCase() === floatingHelpBtn;
  }

  render() {
    const {
      children,
      href,
      className: addtionalClassName,
      onClick: trackingFunction,
    } = this.props;

    const className = classNames('TrackingLink', {
      [addtionalClassName]: !!addtionalClassName,
    });
    const onClick = trackingFunction ? this.onClick : undefined;

    return (
      <a
        className={className}
        href={href}
        onClick={onClick}
        ref={linkEl => { this.linkEl = linkEl; }}
      >
        {children}
      </a>
    );
  }
}
<|endoftext|>


<commit_before>import postcss from 'postcss';
import path from 'path';
import reduceFunctionCall from 'reduce-function-call';
import fs from 'fs';
import url from 'url';
import crypto from 'crypto';
import pathExists from 'path-exists';
import mkdirp from 'mkdirp';
import {_extend} from 'util';

const tags = [
    'path',
    'name',
    'hash',
    'ext'
];

/**
 * return quote type
 *
 * @param  {String} string quoted (or not) value
 * @return {String} quote if any, or empty string
 */
function getUrlMetaData(string) {
    let quote = '';
    const quotes = ['\"', '\''];
    const trimedString = string.trim();
    quotes.forEach((q) => {
        if (
            trimedString.charAt(0) === q &&
            trimedString.charAt(trimedString.length - 1) === q
        ) {
            quote = q;
        }
    });

    const urlMeta = {
        before: string.slice(0, string.indexOf(quote)),
        quote: quote,
        value: quote ?
            trimedString.substr(1, trimedString.length - 2)
            : trimedString,
        after: string.slice(string.lastIndexOf(quote) + 1)
    };
    return urlMeta;
}

/**
 * Create an css url() from a path and a quote style
 *
 * @param {String} urlMeta url meta data
 * @param {String} newPath url path
 * @return {String} new url()
 */
function createUrl(urlMeta, newPath) {
    return urlMeta.before +
        urlMeta.quote +
        (newPath || urlMeta.value) +
        urlMeta.quote +
        urlMeta.after;
}

/**
 * writeFile
 *
 * function to write the asset file in dest
 *
 * @param  {object} fileMeta
 * @return {contents|boolean}
 */
function writeFile(fileMeta) {
    return new Promise((resolve, reject) => {
        fs.writeFile(fileMeta.resultAbsolutePath, fileMeta.contents, (err) => {
            if (err) {
                reject(`Can't write in ${fileMeta.resultAbsolutePath}`);
            } else {
                resolve(fileMeta);
            }
        });
    });
}

/**
 * [fileExists description]
 * @param  {[type]} filepath [description]
 * @return {[type]}          [description]
 */
function copyFile(fileMeta, transform) {
    return pathExists(fileMeta.resultAbsolutePath)
        .then((exists) => {
            fileMeta.exists = exists;
            if (exists) {
                return fileMeta;
            }

            mkdirp.sync(path.dirname(fileMeta.resultAbsolutePath));
            return transform(fileMeta);
        })
        .then((fmTransform) => {
            if (fmTransform.exists) {
                return fmTransform;
            }
            return writeFile(fmTransform);
        });
}

/**
 * getFileMeta
 *
 * Helper function that reads the file ang get some helpful information
 * to the copy process.
 *
 * @param  {string} dirname
 * @param  {string} value
 * @param  {Object} options
 * @return {Object} meta information from the resource
 */
function getFileMeta(dirname, value, opts) {
    const parseUrl = url.parse(path.resolve(dirname, value), true);
    const fileMeta = {};

    // path between the basePath and the filename
    let i = 0;
    while (!fileMeta.src && i < opts.src.length) {
        if (parseUrl.pathname.indexOf(opts.src[i]) !== -1) {
            fileMeta.src = opts.src[i];
        }
        i++;
    }

    if (!(fileMeta.src)) {
        throw new Error('Error in postcss-copy: "src" ' +
        `not found in ${parseUrl.pathname}`);
    }

    return new Promise((resolve, reject) => {
        fs.readFile(parseUrl.pathname, (err, contents) => {
            if (err) {
                reject(`Can't read the file in ${parseUrl.pathname}`);
            } else {
                fileMeta.contents = contents;
                fileMeta.hash = opts.hashFunction(fileMeta.contents);
                fileMeta.fullName = path.basename(parseUrl.pathname);
                // name without extension
                fileMeta.name = path.basename(
                    parseUrl.pathname,
                    path.extname(parseUrl.pathname)
                );
                // extension without the '.'
                fileMeta.ext = path.extname(parseUrl.pathname).replace('.', '');
                // the absolute path without the #hash param
                fileMeta.absolutePath = parseUrl.pathname;

                fileMeta.path = fileMeta
                    .absolutePath
                    .replace(fileMeta.src, '')
                    .replace(fileMeta.fullName, '')
                    .replace(/^\/+|\/+$/gm, '');
                fileMeta.extra = (parseUrl.search ? parseUrl.search : '') +
                    (parseUrl.hash ? parseUrl.hash : '');

                resolve(fileMeta);
            }
        });
    });
}

/**
 * update the url result
 * @param {Object} decl postcss declaration
 * @param {string} old value
 * @param {Object} urlMeta url meta data
 * @param  {String} new url
 * @return {Object} return decl postcss declaration with url updated
 */
function updateUrl(decl, oldValue, urlMeta, resultUrl) {
    decl.value = decl.value.replace(
        oldValue,
        createUrl(urlMeta, resultUrl)
    );
    return decl.value;
}

/**
 * processCopy
 *
 * @param {Object} result
 * @param {Object} urlMeta url meta data
 * @param {Object} options
 * @param {Object} decl postcss declaration
 * @param {string} old value
 * @return {String} new url
 */
function processCopy(result, urlMeta, opts, decl, oldValue) {
    // ignore absolute urls, hasshes or data uris
    if (urlMeta.value.indexOf('/') === 0 ||
        urlMeta.value.indexOf('data:') === 0 ||
        urlMeta.value.indexOf('#') === 0 ||
        /^[a-z]+:\/\//.test(urlMeta.value)
    ) {
        return updateUrl(decl, oldValue, urlMeta);
    }

    /**
     * dirname of the read file css
     * @type {String}
     */
    const dirname = path.dirname(decl.source.input.file);

    return getFileMeta(dirname, urlMeta.value, opts)
        .then((fileMeta) => {
            let tpl = opts.template;
            tags.forEach((tag) => {
                tpl = tpl.replace(
                    '[' + tag + ']',
                    fileMeta[tag] ? fileMeta[tag] : opts[tag]
                );
            });
            fileMeta.resultAbsolutePath = path.resolve(opts.dest, tpl);

            return copyFile(fileMeta, opts.transform);
        })
        .then((fileMeta) => {
            const resultUrl = path.relative(
                opts.keepRelativePath
                    ? dirname.replace(fileMeta.src, opts.dest)
                    : opts.dest,
                fileMeta.resultAbsolutePath
            ) + fileMeta.extra;

            return updateUrl(decl, oldValue, urlMeta, resultUrl);
        })
        .catch((err) => {
            decl.warn(result, err);
            return updateUrl(decl, oldValue, urlMeta);
        });
}

/**
 * Processes one declaration
 *
 * @param {Object} result
 * @param {Object} decl  postcss declaration
 * @param {Object} options plugin options
 * @return {void}
 */
function processDecl(result, decl, opts) {
    return new Promise((resolve, reject) => {
        const promises = [];

        reduceFunctionCall(decl.value, 'url', (value) => {
            const urlMeta = getUrlMetaData(value);

            promises.push(processCopy(result, urlMeta, opts, decl, value));
        });

        Promise.all(promises).then(resolve, reject);
    });
}

/**
 * Initialize the postcss-copy plugin
 * @param  {Object} plugin options
 * @return {void}
 *
 * userOpts = {
 * 		src: {String} optional
 * 		dest: {String} optional
 *      template: {String} optional (default 'assets/[hash].[ext]')
 * }
 */
function init(userOpts = {}) {
    let opts = {
        template: 'assets/[hash].[ext]',
        keepRelativePath: true,
        hashFunction(contents) {
            return crypto.createHash('sha1')
                .update(contents)
                .digest('hex')
                .substr(0, 16);
        },
        transform(fileMeta) {
            return fileMeta;
        }
    };
    opts = _extend(opts, userOpts);

    return (style, result) => {
        if (opts.src) {
            if (typeof opts.src === 'string') {
                opts.src = [path.resolve(opts.src)];
            } else {
                opts.src = opts.src.map((elem) => path.resolve(elem));
            }
        } else {
            throw new Error('Option `src` is required in postcss-copy');
        }
        if (opts.dest) {
            opts.dest = path.resolve(opts.dest);
        } else {
            throw new Error('Option `dest` is required in postcss-copy');
        }

        return new Promise((resolve, reject) => {
            const promises = [];
            style.walkDecls(decl => {
                if (decl.value && decl.value.indexOf('url(') > -1) {
                    promises.push(processDecl(result, decl, opts));
                }
            });
            Promise.all(promises).then(resolve, reject);
        });
    };
}

export default postcss.plugin('postcss-copy', init);
<commit_msg>minor fix error using postcss-import and keepRelativePath<commit_after>import postcss from 'postcss';
import path from 'path';
import reduceFunctionCall from 'reduce-function-call';
import fs from 'fs';
import url from 'url';
import crypto from 'crypto';
import pathExists from 'path-exists';
import mkdirp from 'mkdirp';
import {_extend} from 'util';

const tags = [
    'path',
    'name',
    'hash',
    'ext'
];

/**
 * return quote type
 *
 * @param  {String} string quoted (or not) value
 * @return {String} quote if any, or empty string
 */
function getUrlMetaData(string) {
    let quote = '';
    const quotes = ['\"', '\''];
    const trimedString = string.trim();
    quotes.forEach((q) => {
        if (
            trimedString.charAt(0) === q &&
            trimedString.charAt(trimedString.length - 1) === q
        ) {
            quote = q;
        }
    });

    const urlMeta = {
        before: string.slice(0, string.indexOf(quote)),
        quote: quote,
        value: quote ?
            trimedString.substr(1, trimedString.length - 2)
            : trimedString,
        after: string.slice(string.lastIndexOf(quote) + 1)
    };
    return urlMeta;
}

/**
 * Create an css url() from a path and a quote style
 *
 * @param {String} urlMeta url meta data
 * @param {String} newPath url path
 * @return {String} new url()
 */
function createUrl(urlMeta, newPath) {
    return urlMeta.before +
        urlMeta.quote +
        (newPath || urlMeta.value) +
        urlMeta.quote +
        urlMeta.after;
}

/**
 * writeFile
 *
 * function to write the asset file in dest
 *
 * @param  {object} fileMeta
 * @return {contents|boolean}
 */
function writeFile(fileMeta) {
    return new Promise((resolve, reject) => {
        fs.writeFile(fileMeta.resultAbsolutePath, fileMeta.contents, (err) => {
            if (err) {
                reject(`Can't write in ${fileMeta.resultAbsolutePath}`);
            } else {
                resolve(fileMeta);
            }
        });
    });
}

/**
 * [fileExists description]
 * @param  {[type]} filepath [description]
 * @return {[type]}          [description]
 */
function copyFile(fileMeta, transform) {
    return pathExists(fileMeta.resultAbsolutePath)
        .then((exists) => {
            fileMeta.exists = exists;
            if (exists) {
                return fileMeta;
            }

            mkdirp.sync(path.dirname(fileMeta.resultAbsolutePath));
            return transform(fileMeta);
        })
        .then((fmTransform) => {
            if (fmTransform.exists) {
                return fmTransform;
            }
            return writeFile(fmTransform);
        });
}

/**
 * getFileMeta
 *
 * Helper function that reads the file ang get some helpful information
 * to the copy process.
 *
 * @param  {string} dirname
 * @param  {string} value
 * @param  {Object} options
 * @return {Object} meta information from the resource
 */
function getFileMeta(dirname, value, opts) {
    const parseUrl = url.parse(path.resolve(dirname, value), true);
    const fileMeta = {};

    // path between the basePath and the filename
    let i = 0;
    while (!fileMeta.src && i < opts.src.length) {
        if (parseUrl.pathname.indexOf(opts.src[i]) !== -1) {
            fileMeta.src = opts.src[i];
        }
        i++;
    }

    if (!(fileMeta.src)) {
        throw new Error('Error in postcss-copy: "src" ' +
        `not found in ${parseUrl.pathname}`);
    }

    return new Promise((resolve, reject) => {
        fs.readFile(parseUrl.pathname, (err, contents) => {
            if (err) {
                reject(`Can't read the file in ${parseUrl.pathname}`);
            } else {
                fileMeta.contents = contents;
                fileMeta.hash = opts.hashFunction(fileMeta.contents);
                fileMeta.fullName = path.basename(parseUrl.pathname);
                // name without extension
                fileMeta.name = path.basename(
                    parseUrl.pathname,
                    path.extname(parseUrl.pathname)
                );
                // extension without the '.'
                fileMeta.ext = path.extname(parseUrl.pathname).replace('.', '');
                // the absolute path without the #hash param
                fileMeta.absolutePath = parseUrl.pathname;

                fileMeta.path = fileMeta
                    .absolutePath
                    .replace(fileMeta.src, '')
                    .replace(fileMeta.fullName, '')
                    .replace(/^\/+|\/+$/gm, '');
                fileMeta.extra = (parseUrl.search ? parseUrl.search : '') +
                    (parseUrl.hash ? parseUrl.hash : '');

                resolve(fileMeta);
            }
        });
    });
}

/**
 * update the url result
 * @param {Object} decl postcss declaration
 * @param {string} old value
 * @param {Object} urlMeta url meta data
 * @param  {String} new url
 * @return {Object} return decl postcss declaration with url updated
 */
function updateUrl(decl, oldValue, urlMeta, resultUrl) {
    decl.value = decl.value.replace(
        oldValue,
        createUrl(urlMeta, resultUrl)
    );
    return decl.value;
}

/**
 * processCopy
 *
 * @param {Object} result
 * @param {Object} urlMeta url meta data
 * @param {Object} options
 * @param {Object} decl postcss declaration
 * @param {string} old value
 * @return {String} new url
 */
function processCopy(result, urlMeta, opts, decl, oldValue) {
    // ignore absolute urls, hasshes or data uris
    if (urlMeta.value.indexOf('/') === 0 ||
        urlMeta.value.indexOf('data:') === 0 ||
        urlMeta.value.indexOf('#') === 0 ||
        /^[a-z]+:\/\//.test(urlMeta.value)
    ) {
        return updateUrl(decl, oldValue, urlMeta);
    }

    /**
     * dirname of the read file css
     * @type {String}
     */
    const dirname = path.dirname(decl.source.input.file);

    return getFileMeta(dirname, urlMeta.value, opts)
        .then((fileMeta) => {
            let tpl = opts.template;
            tags.forEach((tag) => {
                tpl = tpl.replace(
                    '[' + tag + ']',
                    fileMeta[tag] ? fileMeta[tag] : opts[tag]
                );
            });
            fileMeta.resultAbsolutePath = path.resolve(opts.dest, tpl);

            return copyFile(fileMeta, opts.transform);
        })
        .then((fileMeta) => {
            const resultUrl = path.relative(
                opts.keepRelativePath
                    ? dirname.replace(fileMeta.src, opts.dest)
                    : opts.to,
                fileMeta.resultAbsolutePath
            ) + fileMeta.extra;
            return updateUrl(decl, oldValue, urlMeta, resultUrl);
        })
        .catch((err) => {
            decl.warn(result, err);
            return updateUrl(decl, oldValue, urlMeta);
        });
}

/**
 * Processes one declaration
 *
 * @param {Object} result
 * @param {Object} decl  postcss declaration
 * @param {Object} options plugin options
 * @return {void}
 */
function processDecl(result, decl, opts) {
    return new Promise((resolve, reject) => {
        const promises = [];

        reduceFunctionCall(decl.value, 'url', (value) => {
            const urlMeta = getUrlMetaData(value);

            promises.push(processCopy(result, urlMeta, opts, decl, value));
        });

        Promise.all(promises).then(resolve, reject);
    });
}

/**
 * Initialize the postcss-copy plugin
 * @param  {Object} plugin options
 * @return {void}
 *
 * userOpts = {
 * 		src: {String} optional
 * 		dest: {String} optional
 *      template: {String} optional (default 'assets/[hash].[ext]')
 * }
 */
function init(userOpts = {}) {
    let opts = {
        template: 'assets/[hash].[ext]',
        keepRelativePath: true,
        hashFunction(contents) {
            return crypto.createHash('sha1')
                .update(contents)
                .digest('hex')
                .substr(0, 16);
        },
        transform(fileMeta) {
            return fileMeta;
        }
    };
    opts = _extend(opts, userOpts);

    return (style, result) => {
        if (opts.src) {
            if (typeof opts.src === 'string') {
                opts.src = [path.resolve(opts.src)];
            } else {
                opts.src = opts.src.map((elem) => path.resolve(elem));
            }
        } else {
            throw new Error('Option `src` is required in postcss-copy');
        }
        if (opts.dest) {
            opts.dest = path.resolve(opts.dest);
        } else {
            throw new Error('Option `dest` is required in postcss-copy');
        }

        if (!(opts.keepRelativePath)) {
            if (result.opts && result.opts.to) {
                opts.to = path.dirname(path.resolve(result.opts.to));
            } else {
                opts.to = opts.dest;
            }
        }

        return new Promise((resolve, reject) => {
            const promises = [];
            style.walkDecls(decl => {
                if (decl.value && decl.value.indexOf('url(') > -1) {
                    promises.push(processDecl(result, decl, opts));
                }
            });
            Promise.all(promises).then(resolve, reject);
        });
    };
}

export default postcss.plugin('postcss-copy', init);
<|endoftext|>


<commit_before>const asciiTable = require('ascii-table');

class Profiler {
  constructor(embark) {
    this.embark = embark;
    this.logger = embark.logger;
    this.events = embark.events;

    this.registerConsoleCommand();
  }

  profile(contractName, contract) {
    const self = this;
    let table = new asciiTable(contractName);
    table.setHeading('Function', 'Payable', 'Mutability', 'Inputs', 'Outputs');
    contract.abiDefinition.forEach((abiMethod) => {
      switch(abiMethod.type) {
        case "constructor":
          table.addRow("constructor", abiMethod.payable, abiMethod.stateMutability, this.formatParams(abiMethod.inputs), this.formatParams(abiMethod.outputs));
          break;
        default:
          table.addRow(abiMethod.name, abiMethod.payable, abiMethod.stateMutability, this.formatParams(abiMethod.inputs), this.formatParams(abiMethod.outputs));
      }
    });
    self.logger.info(table.toString());
  }

  formatParams(params) {
    if (!params || !params.length) {
      return "()";
    }
    let paramString = "(";
    let mappedParams = params.map(param => param.type);
    paramString += mappedParams.join(',');
    paramString += ")";
    return paramString;
  }

  registerConsoleCommand() {
    const self = this;
    self.embark.registerConsoleCommand((cmd, _options) => {
      let cmdName = cmd.split(' ')[0];
      let contractName = cmd.split(' ')[1];
      if (cmdName === 'profile') {
          self.events.request('contracts:contract', contractName, (contract) => {
               self.logger.info("--  profile for " + contractName);
               this.profile(contractName, contract);
          });
          return "";
      }
      return false;
    });
  }
}

module.exports = Profiler;
<commit_msg>wip<commit_after>const asciiTable = require('ascii-table');
const ethAbi = require('web3-eth-abi');

class Profiler {
  constructor(embark) {
    this.embark = embark;
    this.logger = embark.logger;
    this.events = embark.events;

    this.registerConsoleCommand();
  }

  profile(contractName, contract) {
    const self = this;
    let table = new asciiTable(contractName);
    table.setHeading('Function', 'Payable', 'Mutability', 'Inputs', 'Outputs');
    contract.abiDefinition.forEach((abiMethod) => {
      switch(abiMethod.type) {
        case "constructor":
          table.addRow("constructor", abiMethod.payable, abiMethod.stateMutability, this.formatParams(abiMethod.inputs), this.formatParams(abiMethod.outputs));
          break;
        default:
          table.addRow(abiMethod.name, abiMethod.payable, abiMethod.stateMutability, this.formatParams(abiMethod.inputs), this.formatParams(abiMethod.outputs));
      }
    });
    self.logger.info(table.toString());
  }

  formatParams(params) {
    if (!params || !params.length) {
      return "()";
    }
    let paramString = "(";
    let mappedParams = params.map(param => param.type);
    paramString += mappedParams.join(',');
    paramString += ")";
    return paramString;
  }

  generateGasEstimation(method) {

  }

  generateRandomType(type) {
    switch(type) {
      case "uint256":
      case "uint"
    }
  }

  registerConsoleCommand() {
    const self = this;
    self.embark.registerConsoleCommand((cmd, _options) => {
      let cmdName = cmd.split(' ')[0];
      let contractName = cmd.split(' ')[1];
      if (cmdName === 'profile') {
          self.events.request('contracts:contract', contractName, (contract) => {
               self.logger.info("--  profile for " + contractName);
               this.profile(contractName, contract);
          });
          return "";
      }
      return false;
    });
  }
}

module.exports = Profiler;
<|endoftext|>


<commit_before>var MESSENGER_ID = 0,
    MessengerPrototype;

module.exports = Messenger;

function Messenger(adapter) {
    var _this = this;

    this.__id = (MESSENGER_ID++).toString(36);
    this.__messageId = 0;
    this.__callbacks = {};
    this.__listeners = {};

    this.__adapter = adapter;

    adapter.addMessageListener(function onMessage(data) {
        _this.onMessage(data);
    });
}
MessengerPrototype = Messenger.prototype;

MessengerPrototype.onMessage = function(message) {
    var id = message.id,
        name = message.name,
        callbacks = this.__callbacks,
        callback = callbacks[id],
        listeners, adapter;

    if (name) {
        listeners = this.__listeners;
        adapter = this.__adapter;

        if (listeners[name]) {
            Messenger_emit(this, listeners[name], message.data, function callback(error, data) {
                adapter.postMessage({
                    id: id,
                    error: error || undefined,
                    data: data
                });
            });
        }
    } else {
        if (callback && isMatch(id, this.__id)) {
            callback(message.error, message.data);
            delete callbacks[id];
        }
    }
};

MessengerPrototype.emit = function(name, data, callback) {
    var id = this.__id + "-" + (this.__messageId++).toString(36);

    if (callback) {
        this.__callbacks[id] = callback;
    }

    this.__adapter.postMessage({
        id: id,
        name: name,
        data: data
    });
};

MessengerPrototype.send = MessengerPrototype.emit;

MessengerPrototype.on = function(name, callback) {
    var listeners = this.__listeners,
        listener = listeners[name] || (listeners[name] = []);

    listener[listener.length] = callback;
};

MessengerPrototype.off = function(name, callback) {
    var listeners = this.__listeners,
        listener = listeners[name],
        i;

    if (listener) {
        i = listener.length;

        while (i--) {
            if (listener[i] === callback) {
                listener.splice(i, 1);
            }
        }

        if (listener.length === 0) {
            delete listeners[name];
        }
    }
};

function Messenger_emit(_this, listeners, data, callback) {
    var index = 0,
        length = listeners.length,
        called = false;

    function done(err, data) {
        if (called === false) {
            called = true;
            callback(err, data);
        }
    }

    function next(err, data) {
        if (err || index === length) {
            done(err, data);
        } else {
            listeners[index++](data, next, _this);
        }
    }

    next(undefined, data);
}

function isMatch(messageId, id) {
    return messageId.split("-")[0] === id;
}
<commit_msg>updates<commit_after>var MESSENGER_ID = 0,
    MessengerPrototype;

module.exports = Messenger;

function Messenger(adapter) {
    var _this = this;

    this.__id = (MESSENGER_ID++).toString(36);
    this.__messageId = 0;
    this.__callbacks = {};
    this.__listeners = {};

    this.__adapter = adapter;

    adapter.addMessageListener(function onMessage(data) {
        _this.onMessage(data);
    });
}
MessengerPrototype = Messenger.prototype;

MessengerPrototype.onMessage = function(message) {
    var id = message.id,
        name = message.name,
        callbacks = this.__callbacks,
        callback = callbacks[id],
        listeners, adapter;

    if (name) {
        listeners = this.__listeners;
        adapter = this.__adapter;

        if (listeners[name]) {
            Messenger_emit(this, listeners[name], message.data, function emitCallback(error, data) {
                adapter.postMessage({
                    id: id,
                    error: error || undefined,
                    data: data
                });
            });
        }
    } else {
        if (callback && isMatch(id, this.__id)) {
            callback(message.error, message.data, this);
            delete callbacks[id];
        }
    }
};

MessengerPrototype.emit = function(name, data, callback) {
    var id = this.__id + "-" + (this.__messageId++).toString(36);

    if (callback) {
        this.__callbacks[id] = callback;
    }

    this.__adapter.postMessage({
        id: id,
        name: name,
        data: data
    });
};

MessengerPrototype.send = MessengerPrototype.emit;

MessengerPrototype.on = function(name, callback) {
    var listeners = this.__listeners,
        listener = listeners[name] || (listeners[name] = []);

    listener[listener.length] = callback;
};

MessengerPrototype.off = function(name, callback) {
    var listeners = this.__listeners,
        listener = listeners[name],
        i;

    if (listener) {
        i = listener.length;

        while (i--) {
            if (listener[i] === callback) {
                listener.splice(i, 1);
            }
        }

        if (listener.length === 0) {
            delete listeners[name];
        }
    }
};

function Messenger_emit(_this, listeners, data, callback) {
    var index = 0,
        length = listeners.length,
        called = false;

    function done(error, data) {
        if (called === false) {
            called = true;
            callback(error, data);
        }
    }

    function next(error, data) {
        if (error || index === length) {
            done(error, data);
        } else {
            listeners[index++](data, next, _this);
        }
    }

    next(undefined, data);
}

function isMatch(messageId, id) {
    return messageId.split("-")[0] === id;
}
<|endoftext|>


<commit_before>const browserify = require('browserify');
const budo = require('budo');
const babelify = require('babelify');
const path = require('path');
const compile = require('idyll-compiler');
const fs = require('fs');
const watch = require('node-watch');
const changeCase = require('change-case');
const envify = require('envify');
const brfs = require('brfs');
const reactPreset = require('babel-preset-react');
const es2015Preset = require('babel-preset-es2015');
const compression = require('compression');
const resolve = require('resolve');
const Mustache = require('mustache');
const ReactDOMServer = require('react-dom/server');
const React = require('react');
const Baby = require('babyparse');
const UglifyJS = require("uglify-js");

const css = require('./assets/css');
const filterAST = require('./assets/ast');

require('babel-core/register')({
    presets: ['react']
});

const idyll = (inputPath, opts, cb) => {
  options = Object.assign({}, {
    output: 'build',
    htmlTemplate: '_index.html',
    componentFolder: 'components',
    defaultComponents: path.join('components', 'default'),
    dataFolder: 'data',
    layout: 'blog',
    theme: 'idyll',
    compilerOptions: {
      spellcheck: true
    },
    build: true
  }, opts || {});

  const inputDirectory = path.dirname(inputPath);
  // Expose an "idyll" field on package.json
  const inputPackage = require(path.join(inputDirectory, 'package.json'));
  const inputConfig = Object.assign({}, {
    components: {}
  }, inputPackage.idyll || {});
  Object.keys(inputConfig.components).forEach(key => {
    inputConfig.components[changeCase.paramCase(key)] = inputConfig.components[key];
  });

  const IDL_FILE = inputPath;
  const TMP_PATH = path.resolve(path.join(inputDirectory, '.idyll'));

  if (!fs.existsSync(TMP_PATH)){
    fs.mkdirSync(TMP_PATH);
  }

  const BUILD_PATH = path.resolve(options.output);
  const HTML_TEMPLATE = path.resolve(options.htmlTemplate);
  const JAVASCRIPT_OUTPUT = path.resolve(path.join(BUILD_PATH, 'index.js'));
  const HTML_OUTPUT = path.resolve(path.join(BUILD_PATH, 'index.html'));
  const AST_FILE = path.resolve(path.join(TMP_PATH, 'ast.json'));
  const COMPONENT_FILE = path.resolve(path.join(TMP_PATH, 'components.js'));
  const DATA_FILE = path.resolve(path.join(TMP_PATH, 'data.js'));
  const CUSTOM_COMPONENTS_FOLDER = path.resolve(options.componentFolder);
  const DEFAULT_COMPONENTS_FOLDER = path.resolve(options.defaultComponents);
  const DATA_FOLDER = path.resolve(options.dataFolder);
  const IDYLL_PATH = path.resolve(__dirname);

  const components = fs.readdirSync(DEFAULT_COMPONENTS_FOLDER);
  let customComponents = [];
  try {
    customComponents = fs.readdirSync(CUSTOM_COMPONENTS_FOLDER);
  } catch(e) {
    console.log(e);
  }

  const writeCSS = () => {
    fs.writeFileSync(path.join(BUILD_PATH, 'styles.css'), css(options));
  };

  const writeData = (data) => {
    fs.writeFileSync(DATA_FILE, `module.exports = ${JSON.stringify(data)}`);
  };

  const writeHTML = (meta) => {
    process.env['AST_FILE'] = AST_FILE;
    process.env['COMPONENT_FILE'] = COMPONENT_FILE;
    process.env['DATA_FILE'] = DATA_FILE;
    process.env['IDYLL_PATH'] = IDYLL_PATH;

    // const InteractiveDocument = require('./client/component');
    // tree.meta.idyllContent = ReactDOMServer.renderToString(React.createElement(InteractiveDocument));
    const output = Mustache.render(fs.readFileSync(HTML_TEMPLATE, 'utf8'), meta);
    fs.writeFileSync(HTML_OUTPUT, output);
  };

  const interpretAST = (ast) => {
    const ignoreNames = ['var', 'data', 'meta', 'derived'];

    const getMeta = (ast) => {
      // there should only be one meta node
      const metaNode = getNodesByName('meta', ast)[0];
      // data is stored in props, hence [1]
      return metaNode[1].reduce(
        (acc, prop) => {
          acc[prop[0]] = prop[1][1];
          return acc;
        },
        {}
      )
    }

    const getData = (acc, node) => {
      // can be multiple data nodes
      const dataNodes = getNodesByName('data', ast);

      // turn each data node into a field on an object
      // whose key is the name prop
      // and whose value is the parsed data
      return dataNodes.reduce(
        (acc, dataNode) => {
          const props = dataNode[1];
          const { name, source } = props.reduce(
            (hash, val) => {
              hash[val[0]] = val[1][1];
              return hash;
            },
            {}
          );

          if (source.endsWith('.csv')) {
            acc[name] = Baby.parseFiles(path.join(DATA_FOLDER, source), { header: true }).data;
          } else {
            acc[name] = require(path.join(DATA_FOLDER, source));
          }

          return acc;
        },
        {}
      );
    }

    return {
      meta: getMeta(ast),
      data: getData(ast)
    }
  };

  const writeAST = (ast) => {
    fs.writeFileSync(AST_FILE, JSON.stringify(filterAST(ast)));
  };

  const writeTemplates = (ast) => {
    const outputComponents = [];
    const outputData = {};
    const checkedComponents = [];
    const ignoreNames = ['var', 'data', 'meta', 'derived'];

    const handleNode = (node) => {
      if (typeof node === 'string') {
        return;
      }
      const name = changeCase.paramCase(node[0]);
      const props = node[1];
      const children = node[2] || [];
      if (ignoreNames.indexOf(name) === -1 && checkedComponents.indexOf(name) === -1) {
        if (inputConfig.components[name]) {
          const compPath = path.parse(path.join(inputDirectory, inputConfig.components[name]));
          outputComponents.push(`'${name}': require('${path.join(path.relative(TMP_PATH, compPath.dir), compPath.base).replace(/\\/g, '/')}')`);
        } else if (customComponents.indexOf(name + '.js') > -1) {
          outputComponents.push(`'${name}': require('${path.relative(TMP_PATH, path.join(CUSTOM_COMPONENTS_FOLDER, name)).replace(/\\/g, '/')}')`);
        } else if (components.indexOf(name + '.js') > -1) {
          outputComponents.push(`'${name}': require('${path.relative(TMP_PATH, path.join(DEFAULT_COMPONENTS_FOLDER, name)).replace(/\\/g, '/')}')`);
        } else {
          try {
            // npm modules are required via relative paths to support working with a locally linked idyll
            const compPath = path.parse(resolve.sync(name, {basedir: inputDirectory}));
            outputComponents.push(`'${name}': require('${path.join(path.relative(TMP_PATH, compPath.dir), compPath.base).replace(/\\/g, '/')}')`);
          } catch (err) {
            if (node[0].toLowerCase() !== node[0]) throw new Error(`Component named ${node[0]} could not be found.`)
          }
        }
        checkedComponents.push(name);
      }
      children.map(handleNode);
    }
    ast.map(handleNode);

    fs.writeFileSync(COMPONENT_FILE, `module.exports = {\n${outputComponents.join(',\n')}\n} `);
  }

  const build = (cb) => {
    process.env['NODE_ENV'] = 'production';
    // this path stuff is pretty ugly but necessary until client files don't rely on env vars
    const clientDir = path.join(__dirname, 'client');
    const visitorsDir = path.join(clientDir, 'visitors');
    var b = browserify(path.join(clientDir, 'build.js'), {
      transform: [
        [ babelify, { presets: [ reactPreset, es2015Preset ] } ],
        [ envify, {
          AST_FILE: path.join(path.relative(clientDir, TMP_PATH), path.parse(AST_FILE).base),
          COMPONENT_FILE: path.join(path.relative(visitorsDir, TMP_PATH), path.parse(COMPONENT_FILE).base),
          DATA_FILE: path.join(path.relative(visitorsDir, TMP_PATH), path.parse(DATA_FILE).base),
          IDYLL_PATH
        } ],
        [ brfs ]
      ]
    });
    b.bundle(function(err, buff) {
      if (err) {
        console.log(err);
        return;
      }
      const jsOutput = UglifyJS.minify(buff.toString('utf8'), {
        fromString: true
      });
      fs.writeFileSync(JAVASCRIPT_OUTPUT, jsOutput.code);
      compileAndWriteFiles();
      cb && cb();
    });
  }

  const start = () => {
    const watchedFiles = CSS_INPUT ? [IDL_FILE, CSS_INPUT] : [IDL_FILE];
    watch(watchedFiles, (filename) => {
      if (filename.indexOf('.css') !== -1) {
        writeCSS();
      } else {
        compileAndWriteFiles();
      }

    });

    budo(path.resolve(path.join(__dirname, 'client', 'live.js')), {
      live: true,
      open: true,
      forceDefaultIndex: true,
      css: path.join(options.output, 'styles.css'),
      middleware: compression(),
      watchGlob: '**/*.{html,css,json,js}',
      browserify: {
        transform: [
          [ babelify, { presets: [ reactPreset, es2015Preset ] } ],
          [ envify, {
            AST_FILE,
            COMPONENT_FILE,
            DATA_FILE,
            IDYLL_PATH } ],
          [ brfs ]
        ]
      }
    });
    compileAndWriteFiles();
  }

  const getNodesByName = (name, tree) => {
    const byName = (acc, val) => {
      if (typeof val === 'string') return acc;
      if (changeCase.paramCase(val[0]) === name) acc.push(val);

      if (val[2] && typeof val[2] !== 'string') acc = val[2].reduce(byName, acc);

      return acc;
    }

    return tree.reduce(
      byName,
      []
    )
  }

  const compileAndWriteFiles = () => {
    const idlInput = fs.readFileSync(IDL_FILE, 'utf8');
    try {
      const ast = compile(idlInput, options.compilerOptions);
      const tree = interpretAST(ast);

      writeAST(ast);
      writeHTML(tree.meta);
      writeData(tree.data);
      writeTemplates(ast);
      writeCSS();
    } catch(err) {
      console.log(err.message);
    }
  }

  if (options.build) {
    build(cb);
  } else {
    start();
  }
};

module.exports = idyll;
<commit_msg>Fix incorrect params<commit_after>const browserify = require('browserify');
const budo = require('budo');
const babelify = require('babelify');
const path = require('path');
const compile = require('idyll-compiler');
const fs = require('fs');
const watch = require('node-watch');
const changeCase = require('change-case');
const envify = require('envify');
const brfs = require('brfs');
const reactPreset = require('babel-preset-react');
const es2015Preset = require('babel-preset-es2015');
const compression = require('compression');
const resolve = require('resolve');
const Mustache = require('mustache');
const ReactDOMServer = require('react-dom/server');
const React = require('react');
const Baby = require('babyparse');
const UglifyJS = require("uglify-js");

const css = require('./assets/css');
const filterAST = require('./assets/ast');

require('babel-core/register')({
    presets: ['react']
});

const idyll = (inputPath, opts, cb) => {
  options = Object.assign({}, {
    output: 'build',
    htmlTemplate: '_index.html',
    componentFolder: 'components',
    defaultComponents: path.join('components', 'default'),
    dataFolder: 'data',
    layout: 'blog',
    theme: 'idyll',
    compilerOptions: {
      spellcheck: true
    },
    build: true
  }, opts || {});

  const inputDirectory = path.dirname(inputPath);
  // Expose an "idyll" field on package.json
  const inputPackage = require(path.join(inputDirectory, 'package.json'));
  const inputConfig = Object.assign({}, {
    components: {}
  }, inputPackage.idyll || {});
  Object.keys(inputConfig.components).forEach(key => {
    inputConfig.components[changeCase.paramCase(key)] = inputConfig.components[key];
  });

  const IDL_FILE = inputPath;
  const TMP_PATH = path.resolve(path.join(inputDirectory, '.idyll'));

  if (!fs.existsSync(TMP_PATH)){
    fs.mkdirSync(TMP_PATH);
  }

  const BUILD_PATH = path.resolve(options.output);
  const HTML_TEMPLATE = path.resolve(options.htmlTemplate);
  const JAVASCRIPT_OUTPUT = path.resolve(path.join(BUILD_PATH, 'index.js'));
  const HTML_OUTPUT = path.resolve(path.join(BUILD_PATH, 'index.html'));
  const AST_FILE = path.resolve(path.join(TMP_PATH, 'ast.json'));
  const COMPONENT_FILE = path.resolve(path.join(TMP_PATH, 'components.js'));
  const DATA_FILE = path.resolve(path.join(TMP_PATH, 'data.js'));
  const CUSTOM_COMPONENTS_FOLDER = path.resolve(options.componentFolder);
  const DEFAULT_COMPONENTS_FOLDER = path.resolve(options.defaultComponents);
  const DATA_FOLDER = path.resolve(options.dataFolder);
  const IDYLL_PATH = path.resolve(__dirname);

  const components = fs.readdirSync(DEFAULT_COMPONENTS_FOLDER);
  let customComponents = [];
  try {
    customComponents = fs.readdirSync(CUSTOM_COMPONENTS_FOLDER);
  } catch(e) {
    console.log(e);
  }

  const writeCSS = () => {
    fs.writeFileSync(path.join(BUILD_PATH, 'styles.css'), css(options));
  };

  const writeData = (data) => {
    fs.writeFileSync(DATA_FILE, `module.exports = ${JSON.stringify(data)}`);
  };

  const writeHTML = (meta) => {
    process.env['AST_FILE'] = AST_FILE;
    process.env['COMPONENT_FILE'] = COMPONENT_FILE;
    process.env['DATA_FILE'] = DATA_FILE;
    process.env['IDYLL_PATH'] = IDYLL_PATH;

    // const InteractiveDocument = require('./client/component');
    // tree.meta.idyllContent = ReactDOMServer.renderToString(React.createElement(InteractiveDocument));
    const output = Mustache.render(fs.readFileSync(HTML_TEMPLATE, 'utf8'), meta);
    fs.writeFileSync(HTML_OUTPUT, output);
  };

  const interpretAST = (ast) => {
    const ignoreNames = ['var', 'data', 'meta', 'derived'];

    const getMeta = (ast) => {
      // there should only be one meta node
      const metaNode = getNodesByName('meta', ast)[0];
      // data is stored in props, hence [1]
      return metaNode[1].reduce(
        (acc, prop) => {
          acc[prop[0]] = prop[1][1];
          return acc;
        },
        {}
      )
    }

    const getData = (ast) => {
      // can be multiple data nodes
      const dataNodes = getNodesByName('data', ast);

      // turn each data node into a field on an object
      // whose key is the name prop
      // and whose value is the parsed data
      return dataNodes.reduce(
        (acc, dataNode) => {
          const props = dataNode[1];
          const { name, source } = props.reduce(
            (hash, val) => {
              hash[val[0]] = val[1][1];
              return hash;
            },
            {}
          );

          if (source.endsWith('.csv')) {
            acc[name] = Baby.parseFiles(path.join(DATA_FOLDER, source), { header: true }).data;
          } else {
            acc[name] = require(path.join(DATA_FOLDER, source));
          }

          return acc;
        },
        {}
      );
    }

    return {
      meta: getMeta(ast),
      data: getData(ast)
    }
  };

  const writeAST = (ast) => {
    fs.writeFileSync(AST_FILE, JSON.stringify(filterAST(ast)));
  };

  const writeTemplates = (ast) => {
    const outputComponents = [];
    const outputData = {};
    const checkedComponents = [];
    const ignoreNames = ['var', 'data', 'meta', 'derived'];

    const handleNode = (node) => {
      if (typeof node === 'string') {
        return;
      }
      const name = changeCase.paramCase(node[0]);
      const props = node[1];
      const children = node[2] || [];
      if (ignoreNames.indexOf(name) === -1 && checkedComponents.indexOf(name) === -1) {
        if (inputConfig.components[name]) {
          const compPath = path.parse(path.join(inputDirectory, inputConfig.components[name]));
          outputComponents.push(`'${name}': require('${path.join(path.relative(TMP_PATH, compPath.dir), compPath.base).replace(/\\/g, '/')}')`);
        } else if (customComponents.indexOf(name + '.js') > -1) {
          outputComponents.push(`'${name}': require('${path.relative(TMP_PATH, path.join(CUSTOM_COMPONENTS_FOLDER, name)).replace(/\\/g, '/')}')`);
        } else if (components.indexOf(name + '.js') > -1) {
          outputComponents.push(`'${name}': require('${path.relative(TMP_PATH, path.join(DEFAULT_COMPONENTS_FOLDER, name)).replace(/\\/g, '/')}')`);
        } else {
          try {
            // npm modules are required via relative paths to support working with a locally linked idyll
            const compPath = path.parse(resolve.sync(name, {basedir: inputDirectory}));
            outputComponents.push(`'${name}': require('${path.join(path.relative(TMP_PATH, compPath.dir), compPath.base).replace(/\\/g, '/')}')`);
          } catch (err) {
            if (node[0].toLowerCase() !== node[0]) throw new Error(`Component named ${node[0]} could not be found.`)
          }
        }
        checkedComponents.push(name);
      }
      children.map(handleNode);
    }
    ast.map(handleNode);

    fs.writeFileSync(COMPONENT_FILE, `module.exports = {\n${outputComponents.join(',\n')}\n} `);
  }

  const build = (cb) => {
    process.env['NODE_ENV'] = 'production';
    // this path stuff is pretty ugly but necessary until client files don't rely on env vars
    const clientDir = path.join(__dirname, 'client');
    const visitorsDir = path.join(clientDir, 'visitors');
    var b = browserify(path.join(clientDir, 'build.js'), {
      transform: [
        [ babelify, { presets: [ reactPreset, es2015Preset ] } ],
        [ envify, {
          AST_FILE: path.join(path.relative(clientDir, TMP_PATH), path.parse(AST_FILE).base),
          COMPONENT_FILE: path.join(path.relative(visitorsDir, TMP_PATH), path.parse(COMPONENT_FILE).base),
          DATA_FILE: path.join(path.relative(visitorsDir, TMP_PATH), path.parse(DATA_FILE).base),
          IDYLL_PATH
        } ],
        [ brfs ]
      ]
    });
    b.bundle(function(err, buff) {
      if (err) {
        console.log(err);
        return;
      }
      const jsOutput = UglifyJS.minify(buff.toString('utf8'), {
        fromString: true
      });
      fs.writeFileSync(JAVASCRIPT_OUTPUT, jsOutput.code);
      compileAndWriteFiles();
      cb && cb();
    });
  }

  const start = () => {
    const watchedFiles = CSS_INPUT ? [IDL_FILE, CSS_INPUT] : [IDL_FILE];
    watch(watchedFiles, (filename) => {
      if (filename.indexOf('.css') !== -1) {
        writeCSS();
      } else {
        compileAndWriteFiles();
      }

    });

    budo(path.resolve(path.join(__dirname, 'client', 'live.js')), {
      live: true,
      open: true,
      forceDefaultIndex: true,
      css: path.join(options.output, 'styles.css'),
      middleware: compression(),
      watchGlob: '**/*.{html,css,json,js}',
      browserify: {
        transform: [
          [ babelify, { presets: [ reactPreset, es2015Preset ] } ],
          [ envify, {
            AST_FILE,
            COMPONENT_FILE,
            DATA_FILE,
            IDYLL_PATH } ],
          [ brfs ]
        ]
      }
    });
    compileAndWriteFiles();
  }

  const getNodesByName = (name, tree) => {
    const byName = (acc, val) => {
      if (typeof val === 'string') return acc;
      if (changeCase.paramCase(val[0]) === name) acc.push(val);

      if (val[2] && typeof val[2] !== 'string') acc = val[2].reduce(byName, acc);

      return acc;
    }

    return tree.reduce(
      byName,
      []
    )
  }

  const compileAndWriteFiles = () => {
    const idlInput = fs.readFileSync(IDL_FILE, 'utf8');
    try {
      const ast = compile(idlInput, options.compilerOptions);
      const tree = interpretAST(ast);

      writeAST(ast);
      writeHTML(tree.meta);
      writeData(tree.data);
      writeTemplates(ast);
      writeCSS();
    } catch(err) {
      console.log(err.message);
    }
  }

  if (options.build) {
    build(cb);
  } else {
    start();
  }
};

module.exports = idyll;
<|endoftext|>