<commit_before>import { ADD_SLIDE, REMOVE_SLIDE, SELECT_SLIDE, UPDATE_NAME, UPDATE_CONTENT } from '../actions';
import slidux from '.';

test('given an action with unkown type when slidux then the state is returned unchanged', () => {
    const state = { id: Date.now() };
    const action = { type: 'unknown' };
    const newState = slidux(state, action);
    expect(newState).toEqual(state);
});

test('given an action with ADD_SLIDE type when slidux then the new state contains a new slide', () => {
    const state = { slides: [] };
    const action = { type: ADD_SLIDE };
    const newState = slidux(state, action);
    expect(newState.slides.length).toEqual(1);
});

test('given an action with REMOVE_SLIDE type and an existing id when slidux then the new state has the slide with id removed', () => {
    const idToRemove = 2;
    const state = { slides: [{ id: 1 }, { id: idToRemove }, { id: 3 }] };
    const action = { type: REMOVE_SLIDE, id: idToRemove };
    const newState = slidux(state, action);
    expect(newState.slides.length).toEqual(2);
    expect(newState.slides.map(slide => slide.id)).not.toContain(idToRemove);
});

test('given an action with REMOVE_SLIDE type and a non existing id when slidux then the state is not changed', () => {
    const idToRemove = 123;
    const state = { slides: [{ id: 1 }, { id: 3 }] };
    const action = { type: REMOVE_SLIDE, id: idToRemove };
    const newState = slidux(state, action);
    expect(newState).toEqual(state);
});

test('given an action with SELECT_SLIDE type and an id when slidux then the new state selectedId is the id', () => {
    const idToSelect = 123;
    const state = {};
    const action = { type: SELECT_SLIDE, id: idToSelect };
    const newState = slidux(state, action);
    expect(newState.selectedId).toBe(idToSelect);
});

test('given an action with UPDATE_NAME type and an existing id when slidux then the new state slide has the updated name', () => {
    const idToUpdate = 123;
    const newName = 'newName';
    const state = { slides: [ { id: idToUpdate, name: 'oldName' } ]};
    const action = { type: UPDATE_NAME, id: idToUpdate, name: newName };
    const newState = slidux(state, action);
    expect(newState.slides[0].name).toBe(newName);
});

test('given an action with UPDATE_NAME type and a non existing id when slidux then the state is not changed', () => {
    const idToUpdate = 123;
    const newName = 'newName';
    const state = { slides: [ { id: 321, name: 'oldName' } ]};
    const action = { type: UPDATE_NAME, id: idToUpdate, name: newName };
    const newState = slidux(state, action);
    expect(newState).toEqual(state);
});

test('given an action with UPDATE_CONTENT type and an existing id when slidux then the new state slide has the updated content', () => {
    const idToUpdate = 123;
    const newContent = 'newContent';
    const state = { slides: [ { id: idToUpdate, content: 'oldContent' } ]};
    const action = { type: UPDATE_CONTENT, id: idToUpdate, content: newContent };
    const newState = slidux(state, action);
    expect(newState.slides[0].content).toBe(newContent);
});

test('given an action with UPDATE_CONTENT type and a non existing id when slidux then the state is not changed', () => {
    const idToUpdate = 123;
    const newContent = 'newContent';
    const state = { slides: [ { id: 321, content: 'oldContent' } ]};
    const action = { type: UPDATE_CONTENT, id: idToUpdate, content: newContent };
    const newState = slidux(state, action);
    expect(newState).toEqual(state);
});<commit_msg>update tests<commit_after>import { ADD_SLIDE, REMOVE_SLIDE, SELECT_SLIDE, UPDATE_NAME, UPDATE_CONTENT } from '../actions';
import slidux from '.';

test('given an action with unkown type when slidux then the state is returned unchanged', () => {
    const state = { id: Date.now() };
    const action = { type: 'unknown' };
    const newState = slidux(state, action);
    expect(newState).toBe(state);
});

test('given an action with ADD_SLIDE type when slidux then the new state contains a new slide', () => {
    const state = { slides: [] };
    const action = { type: ADD_SLIDE };
    const newState = slidux(state, action);
    expect(newState.slides.length).toBe(1);
});

test('given an action with REMOVE_SLIDE type and an existing id when slidux then the new state has the slide with id removed', () => {
    const idToRemove = 2;
    const state = { slides: [{ id: 1 }, { id: idToRemove }, { id: 3 }] };
    const action = { type: REMOVE_SLIDE, id: idToRemove };
    const newState = slidux(state, action);
    expect(newState.slides.length).toBe(2);
    expect(newState.slides.map(slide => slide.id)).not.toContain(idToRemove);
});

test('given an action with REMOVE_SLIDE type and a non existing id when slidux then the state is not changed', () => {
    const idToRemove = 123;
    const state = { slides: [{ id: 1 }, { id: 3 }] };
    const action = { type: REMOVE_SLIDE, id: idToRemove };
    const newState = slidux(state, action);
    expect(newState).toEqual(state);
});

test('given an action with SELECT_SLIDE type and an id when slidux then the new state selectedId is the id', () => {
    const idToSelect = 123;
    const state = {};
    const action = { type: SELECT_SLIDE, id: idToSelect };
    const newState = slidux(state, action);
    expect(newState.selectedId).toBe(idToSelect);
});

test('given an action with UPDATE_NAME type and an existing id when slidux then the new state slide has the updated name', () => {
    const idToUpdate = 123;
    const newName = 'newName';
    const state = { slides: [ { id: idToUpdate, name: 'oldName' } ]};
    const action = { type: UPDATE_NAME, id: idToUpdate, name: newName };
    const newState = slidux(state, action);
    expect(newState.slides[0].name).toBe(newName);
});

test('given an action with UPDATE_NAME type and a non existing id when slidux then the state is not changed', () => {
    const idToUpdate = 123;
    const newName = 'newName';
    const state = { slides: [ { id: 321, name: 'oldName' } ]};
    const action = { type: UPDATE_NAME, id: idToUpdate, name: newName };
    const newState = slidux(state, action);
    expect(newState).toEqual(state);
});

test('given an action with UPDATE_CONTENT type and an existing id when slidux then the new state slide has the updated content', () => {
    const idToUpdate = 123;
    const newContent = 'newContent';
    const state = { slides: [ { id: idToUpdate, content: 'oldContent' } ]};
    const action = { type: UPDATE_CONTENT, id: idToUpdate, content: newContent };
    const newState = slidux(state, action);
    expect(newState.slides[0].content).toBe(newContent);
});

test('given an action with UPDATE_CONTENT type and a non existing id when slidux then the state is not changed', () => {
    const idToUpdate = 123;
    const newContent = 'newContent';
    const state = { slides: [ { id: 321, content: 'oldContent' } ]};
    const action = { type: UPDATE_CONTENT, id: idToUpdate, content: newContent };
    const newState = slidux(state, action);
    expect(newState).toEqual(state);
});<|endoftext|>


<commit_before>// @flow
import getBasePlacement from './getBasePlacement';
import getVariationPlacement from './getVariationPlacement';
import getMainAxisFromPlacement from './getMainAxisFromPlacement';
import type {
  Rect,
  PositioningStrategy,
  Offsets,
  ClientRectObject,
} from '../types';
import { top, right, bottom, left, start, end, type Placement } from '../enums';

export default ({
  reference,
  element,
  strategy,
  placement,
  scroll,
}: {
  reference: Rect | ClientRectObject,
  element: Rect | ClientRectObject,
  strategy: PositioningStrategy,
  placement?: Placement,
  scroll: { scrollTop: number, scrollLeft: number },
}): Offsets => {
  const basePlacement = placement ? getBasePlacement(placement) : null;
  const variationPlacement = placement
    ? getVariationPlacement(placement)
    : null;

  const { scrollTop, scrollLeft } = scroll;

  let offsets;
  switch (basePlacement) {
    case top:
      offsets = {
        x: reference.x + reference.width / 2 - element.width / 2 - scrollLeft,
        y: reference.y - element.height - scrollTop,
      };
      break;
    case bottom:
      offsets = {
        x: reference.x + reference.width / 2 - element.width / 2 - scrollLeft,
        y: reference.y + reference.height - scrollTop,
      };
      break;
    case right:
      offsets = {
        x: reference.x + reference.width - scrollLeft,
        y: reference.y + reference.height / 2 - element.height / 2 - scrollTop,
      };
      break;
    case left:
      offsets = {
        x: reference.x - element.width - scrollLeft,
        y: reference.y + reference.height / 2 - element.height / 2 - scrollTop,
      };
      break;
    default:
      offsets = {
        x: reference.x - scrollLeft,
        y: reference.y - scrollTop,
      };
  }

  const mainAxis = basePlacement
    ? getMainAxisFromPlacement(basePlacement)
    : null;

  if (mainAxis != null) {
    const len = mainAxis === 'y' ? 'height' : 'width';

    switch (variationPlacement) {
      case start:
        offsets[mainAxis] -= reference[len] / 2 - element[len] / 2;
        break;
      case end:
        offsets[mainAxis] += reference[len] / 2 - element[len] / 2;
        break;
      default:
    }
  }

  return offsets;
};
<commit_msg>fix: 1px rounding error for variation placements<commit_after>// @flow
import getBasePlacement from './getBasePlacement';
import getVariationPlacement from './getVariationPlacement';
import getMainAxisFromPlacement from './getMainAxisFromPlacement';
import type {
  Rect,
  PositioningStrategy,
  Offsets,
  ClientRectObject,
} from '../types';
import { top, right, bottom, left, start, end, type Placement } from '../enums';

export default ({
  reference,
  element,
  strategy,
  placement,
  scroll,
}: {
  reference: Rect | ClientRectObject,
  element: Rect | ClientRectObject,
  strategy: PositioningStrategy,
  placement?: Placement,
  scroll: { scrollTop: number, scrollLeft: number },
}): Offsets => {
  const basePlacement = placement ? getBasePlacement(placement) : null;
  const variationPlacement = placement
    ? getVariationPlacement(placement)
    : null;

  const { scrollTop, scrollLeft } = scroll;

  let offsets;
  switch (basePlacement) {
    case top:
      offsets = {
        x: reference.x + reference.width / 2 - element.width / 2 - scrollLeft,
        y: reference.y - element.height - scrollTop,
      };
      break;
    case bottom:
      offsets = {
        x: reference.x + reference.width / 2 - element.width / 2 - scrollLeft,
        y: reference.y + reference.height - scrollTop,
      };
      break;
    case right:
      offsets = {
        x: reference.x + reference.width - scrollLeft,
        y: reference.y + reference.height / 2 - element.height / 2 - scrollTop,
      };
      break;
    case left:
      offsets = {
        x: reference.x - element.width - scrollLeft,
        y: reference.y + reference.height / 2 - element.height / 2 - scrollTop,
      };
      break;
    default:
      offsets = {
        x: reference.x - scrollLeft,
        y: reference.y - scrollTop,
      };
  }

  const mainAxis = basePlacement
    ? getMainAxisFromPlacement(basePlacement)
    : null;

  if (mainAxis != null) {
    const len = mainAxis === 'y' ? 'height' : 'width';

    switch (variationPlacement) {
      case start:
        offsets[mainAxis] =
          Math.floor(offsets[mainAxis]) -
          Math.floor(reference[len] / 2 - element[len] / 2);
        break;
      case end:
        offsets[mainAxis] =
          Math.floor(offsets[mainAxis]) +
          Math.ceil(reference[len] / 2 - element[len] / 2);
        break;
      default:
    }
  }

  return offsets;
};
<|endoftext|>


<commit_before>// @flow
import type { State, SideObject, Padding } from '../types';
import type { Placement, Boundary, RootBoundary, Context } from '../enums';
import getBoundingClientRect from '../dom-utils/getBoundingClientRect';
import getClippingRect from '../dom-utils/getClippingRect';
import getDocumentElement from '../dom-utils/getDocumentElement';
import computeOffsets from './computeOffsets';
import rectToClientRect from './rectToClientRect';
import {
  clippingParents,
  reference,
  popper,
  bottom,
  top,
  right,
  basePlacements,
  viewport,
} from '../enums';
import { isElement } from '../dom-utils/instanceOf';
import mergePaddingObject from './mergePaddingObject';
import expandToHashMap from './expandToHashMap';

type Options = {
  placement: Placement,
  boundary: Boundary,
  rootBoundary: RootBoundary,
  elementContext: Context,
  altBoundary: boolean,
  padding: Padding,
};

export default function detectOverflow(
  state: State,
  options: $Shape<Options> = {}
): SideObject {
  const {
    placement = state.placement,
    boundary = clippingParents,
    rootBoundary = viewport,
    elementContext = popper,
    altBoundary = false,
    padding = 0,
  } = options;

  const paddingObject = mergePaddingObject(
    typeof padding !== 'number'
      ? padding
      : expandToHashMap(padding, basePlacements)
  );

  const altContext = elementContext === popper ? reference : popper;

  const referenceElement = state.elements.reference;
  const popperRect = state.rects.popper;
  const element = state.elements[altBoundary ? altContext : elementContext];

  const clippingClientRect = getClippingRect(
    isElement(element) ? element : getDocumentElement(state.elements.popper),
    boundary,
    rootBoundary
  );

  const referenceClientRect = getBoundingClientRect(referenceElement);

  const popperOffsets = computeOffsets({
    reference: referenceClientRect,
    element: popperRect,
    strategy: 'absolute',
    placement,
  });

  const popperClientRect = rectToClientRect({
    ...popperRect,
    ...popperOffsets,
  });

  const elementClientRect =
    elementContext === popper ? popperClientRect : referenceClientRect;

  // positive = overflowing the clipping rect
  // 0 or negative = within the clipping rect
  const overflowOffsets = {
    top: clippingClientRect.top - elementClientRect.top + paddingObject.top,
    bottom:
      elementClientRect.bottom -
      clippingClientRect.bottom +
      paddingObject.bottom,
    left: clippingClientRect.left - elementClientRect.left + paddingObject.left,
    right:
      elementClientRect.right - clippingClientRect.right + paddingObject.right,
  };

  const offsetData = state.modifiersData.offset;

  // Offsets can be applied only to the popper element
  if (elementContext === popper && offsetData) {
    const offset = offsetData[placement];

    Object.keys(overflowOffsets).forEach(key => {
      const multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1;
      const axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x';
      overflowOffsets[key] += offset[axis] * multiply;
    });
  }

  return overflowOffsets;
}
<commit_msg>fix(detectOverflow): check contextElement<commit_after>// @flow
import type { State, SideObject, Padding } from '../types';
import type { Placement, Boundary, RootBoundary, Context } from '../enums';
import getBoundingClientRect from '../dom-utils/getBoundingClientRect';
import getClippingRect from '../dom-utils/getClippingRect';
import getDocumentElement from '../dom-utils/getDocumentElement';
import computeOffsets from './computeOffsets';
import rectToClientRect from './rectToClientRect';
import {
  clippingParents,
  reference,
  popper,
  bottom,
  top,
  right,
  basePlacements,
  viewport,
} from '../enums';
import { isElement } from '../dom-utils/instanceOf';
import mergePaddingObject from './mergePaddingObject';
import expandToHashMap from './expandToHashMap';

type Options = {
  placement: Placement,
  boundary: Boundary,
  rootBoundary: RootBoundary,
  elementContext: Context,
  altBoundary: boolean,
  padding: Padding,
};

export default function detectOverflow(
  state: State,
  options: $Shape<Options> = {}
): SideObject {
  const {
    placement = state.placement,
    boundary = clippingParents,
    rootBoundary = viewport,
    elementContext = popper,
    altBoundary = false,
    padding = 0,
  } = options;

  const paddingObject = mergePaddingObject(
    typeof padding !== 'number'
      ? padding
      : expandToHashMap(padding, basePlacements)
  );

  const altContext = elementContext === popper ? reference : popper;

  const referenceElement = state.elements.reference;
  const popperRect = state.rects.popper;
  const element = state.elements[altBoundary ? altContext : elementContext];

  const clippingClientRect = getClippingRect(
    isElement(element)
      ? element
      : element.contextElement || getDocumentElement(state.elements.popper),
    boundary,
    rootBoundary
  );

  const referenceClientRect = getBoundingClientRect(referenceElement);

  const popperOffsets = computeOffsets({
    reference: referenceClientRect,
    element: popperRect,
    strategy: 'absolute',
    placement,
  });

  const popperClientRect = rectToClientRect({
    ...popperRect,
    ...popperOffsets,
  });

  const elementClientRect =
    elementContext === popper ? popperClientRect : referenceClientRect;

  // positive = overflowing the clipping rect
  // 0 or negative = within the clipping rect
  const overflowOffsets = {
    top: clippingClientRect.top - elementClientRect.top + paddingObject.top,
    bottom:
      elementClientRect.bottom -
      clippingClientRect.bottom +
      paddingObject.bottom,
    left: clippingClientRect.left - elementClientRect.left + paddingObject.left,
    right:
      elementClientRect.right - clippingClientRect.right + paddingObject.right,
  };

  const offsetData = state.modifiersData.offset;

  // Offsets can be applied only to the popper element
  if (elementContext === popper && offsetData) {
    const offset = offsetData[placement];

    Object.keys(overflowOffsets).forEach(key => {
      const multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1;
      const axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x';
      overflowOffsets[key] += offset[axis] * multiply;
    });
  }

  return overflowOffsets;
}
<|endoftext|>


<commit_before>import Immutable from 'immutable'
import { camelizeKeys } from 'humps'
import * as ACTION_TYPES from '../constants/action_types'

// Like .getIn but for regular JS objects
// Does not break if object is missing a key in the middle
function deepGet(object, [head, ...tail], fallback = null) {
  const val = object[head]
  if (val === undefined || val === null) { return fallback }
  if (tail.length === 0) { return val }
  return deepGet(val, tail, fallback)
}

// Merge two Immutable maps while preferring data over nulls and never returning undefined.
function smartMergeDeep(oldMap, newMap) {
  const filteredNewMap = newMap.filterNot(v => v === undefined || v === null)
  return oldMap.mergeDeepWith((oldVal, newVal) => {
    if (oldVal === undefined && newVal === undefined) { return null }
    if (oldVal === null || oldVal === undefined) { return newVal }
    return newVal
  }, filteredNewMap)
}

// Given state (immutable), a key path (array[string]), and map merge the map in.
// If a value on either side is null or undefined it "loses" the merge - we always prefer data.
function smartMergeDeepIn(state, keyPath, newMap) {
  const oldMap = state.getIn(keyPath, Immutable.Map())
  const mergedMap = smartMergeDeep(oldMap, newMap)
  return state.setIn(keyPath, mergedMap)
}

function parseList(state, list, parser) {
  if (!Array.isArray(list)) { return state }
  return list.reduce(parser, state)
}

function parsePagination(state, stream, pathname, query, variables) {
  const { posts: models, next, isLastPage } = stream
  const mergedState = state.mergeDeepIn(['pages', pathname], Immutable.fromJS({
    pagination: Immutable.fromJS({ next, query, variables, isLastPage }),
  }))
  return mergedState.updateIn(['pages', pathname, 'ids'], ids =>
    ((ids || Immutable.OrderedSet()).concat(models.map(m => m.id))),
  )
}

function parseAsset(state, asset) {
  if (!asset) { return state }
  return smartMergeDeepIn(state, ['assets', asset.id], Immutable.fromJS({
    id: asset.id,
    attachment: asset.attachment,
  }))
}

function reduceAssets(assets) {
  return (assets || []).reduce((byId, asset) => (
      { ...byId, [asset.id]: asset }
    ), {})
}

function parseCategory(state, category) {
  if (!category) { return state }
  return smartMergeDeepIn(state, ['categories', category.id], Immutable.fromJS({
    id: category.id,
    slug: category.slug,
    name: category.name,
    level: category.level,
    order: category.order,
    allowInOnboarding: category.allowInOnboarding,
    isCreatorType: category.isCreatorType,
    tileImage: category.tileImage,
  }))
}

function parseArtistInviteSubmission(state, submission) {
  if (!submission || !submission.id) { return state }
  return smartMergeDeepIn(state, ['artistInviteSubmissions', submission.id], Immutable.fromJS({
    id: submission.id,
  }))
}

function parseUser(state, user) {
  if (!user) { return state }

  const state1 = smartMergeDeepIn(state, ['users', user.id], Immutable.fromJS({

    // Minumum properties
    id: user.id,
    username: user.username,
    name: user.name,
    avatar: user.avatar,

    // Extended properties
    coverImage: user.coverImage,
    badges: user.badges,
    externalLinksLink: user.externalLinksLink,
    formattedShortBio: user.formattedShortBio,
    location: user.location,

    // Settings
    isCollaboratable: deepGet(user, ['settings', 'isCollaboratable']),
    isHireable: deepGet(user, ['settings', 'isHireable']),
    hasCommentingEnabled: deepGet(user, ['settings', 'hasCommentingEnabled']),
    hasLovesEnabled: deepGet(user, ['settings', 'hasLovesEnabled']),
    hasRepostingEnabled: deepGet(user, ['settings', 'hasRepostingEnabled']),
    hasSharingEnabled: deepGet(user, ['settings', 'hasSharingEnabled']),
    postsAdultContent: deepGet(user, ['settings', 'postAdultContent']),

    // userStats
    followersCount: deepGet(user, ['userStats', 'followersCount']),
    followingCount: deepGet(user, ['userStats', 'followingCount']),
    postsCount: deepGet(user, ['userStats', 'postsCount']),
    lovesCount: deepGet(user, ['userStats', 'lovesCount']),
    totalViewsCount: deepGet(user, ['userStats', 'totalViewsCount']),

    // currentUserState
    relationshipPriority: deepGet(user, ['currentUserState', 'relationshipPriority']),
  }))
  const state2 = parseList(state1, user.categories, parseCategory)
  return state2
}

function parsePageHeader(state, pageHeader) {
  if (!pageHeader) { return state }
  const state1 = parseUser(state, pageHeader.user)
  const state2 = parseCategory(state1, pageHeader.category)
  return smartMergeDeepIn(state2, ['pageHeaders', pageHeader.id], Immutable.fromJS({
    id: pageHeader.id,
    kind: pageHeader.kind,
    slug: pageHeader.slug,
    postToken: pageHeader.postToken,
    header: pageHeader.header,
    subheader: pageHeader.subheader,
    ctaLink: pageHeader.ctaLink,
    image: pageHeader.image,
    userId: deepGet(pageHeader, ['user', 'id']),
    categoryId: deepGet(pageHeader, ['category', 'id']),
  }))
}

function postLinks(post) {
  const links = {}
  const authorId = deepGet(post, ['author', 'id'])
  if (authorId) { links.author = { id: authorId, type: 'user' } }

  const repostAuthorId = deepGet(post, ['repostedSource', 'author', 'id'])
  if (repostAuthorId) { links.repostAuthor = { id: repostAuthorId, type: 'user' } }

  const repostId = deepGet(post, ['repostedSource', 'id'])
  if (repostId) { links.repostedSource = { id: repostId, type: 'post' } }

  return links
}

// Camelize data keys, inject assets objects into appropriate region
function parseRegion(post, type, assetsById) {
  return (post[type] || []).map((region, index) => {
    const id = `${post.id}-${index}`
    const assetId = deepGet(region, ['links', 'assets'])
    const asset = assetsById[assetId]
    let data = null
    if (typeof region.data === 'object') {
      data = camelizeKeys(region.data)
    } else {
      data = region.data
    }
    if (region.kind === 'image' && typeof assetId === 'string' && asset) {
      return { ...region, data, id, asset }
    }
    return { ...region, data, id }
  })
}

function parsePost(state, post) {
  if (!post) { return state }

  const state1 = parseUser(state, post.author)
  const state2 = parseList(state1, post.assets, parseAsset)
  const state3 = parsePost(state2, post.repostedSource)
  const state4 = parseArtistInviteSubmission(state3, post.artistInviteSubmission)

  const assetsById = reduceAssets(post.assets)
  const repostAssetsById = post.repostedSource ? reduceAssets(post.repostedSource.assets) : null

  const state5 = smartMergeDeepIn(state4, ['posts', post.id], Immutable.fromJS({
    // ids
    id: post.id,
    authorId: deepGet(post, ['author', 'id']), // We don't use links for this

    // Properties
    token: post.token,
    createdAt: post.createdAt,
    artistInviteId: deepGet(post, ['artistInviteSubmission', 'artistInvite']),
    artistInviteSubmission: post.artistInviteSubmission,

    // Content
    summary: parseRegion(post, 'summary', assetsById),
    content: parseRegion(post, 'content', assetsById),
    repostContent: parseRegion(post, 'repostContent', repostAssetsById),

    // Stats
    lovesCount: deepGet(post, ['postStats', 'lovesCount']),
    commentsCount: deepGet(post, ['postStats', 'commentsCount']),
    viewsCount: deepGet(post, ['postStats', 'viewsCount']),
    repostsCount: deepGet(post, ['postStats', 'repostsCount']),

    // Current user state
    watching: deepGet(post, ['currentUserState', 'watching']),
    loved: deepGet(post, ['currentUserState', 'loved']),
    reposted: deepGet(post, ['currentUserState', 'reposted']),

    // Links
    links: postLinks(post),
  }))

  return state5
}

function parseQueryType(state, stream, pathname, query, variables) {
  const { posts } = stream
  const state1 = parseList(state, posts, parsePost)
  return parsePagination(state1, stream, pathname, query, variables)
}

function parseStream(state, { payload: { response: { data }, pathname, query, variables } }) {
  return Object.keys(data).reduce((s, key) =>
    parseQueryType(s, data[key], pathname, query, variables),
    state,
  )
}

function parseCategoryQueries(state, { payload: { response: { data } } }) {
  return parseList(state, data.categoryNav || data.allCategories, parseCategory)
}

function parsePageHeaders(state, { payload: { response: { data: { pageHeaders } } } }) {
  return parseList(state, pageHeaders, parsePageHeader)
}

// Dispatch different graphql response types for parsing (reducing)
export default function (state, action) {
  const { type } = action
  switch (type) {
    case ACTION_TYPES.V3.LOAD_STREAM_SUCCESS:
    case ACTION_TYPES.V3.LOAD_NEXT_CONTENT_SUCCESS:
      return parseStream(state, action)
    case ACTION_TYPES.V3.LOAD_CATEGORIES_SUCCESS:
      return parseCategoryQueries(state, action)
    case ACTION_TYPES.V3.LOAD_PAGE_HEADERS_SUCCESS:
      return parsePageHeaders(state, action)
    default:
      return state
  }
}
<commit_msg>Fix "return to page" new post ordering.<commit_after>import Immutable from 'immutable'
import { camelizeKeys } from 'humps'
import * as ACTION_TYPES from '../constants/action_types'

// Like .getIn but for regular JS objects
// Does not break if object is missing a key in the middle
// TODO: Immutable 4.x has a functional getIn that works on both Maps and objects.
function deepGet(object, [head, ...tail], fallback = null) {
  const val = object[head]
  if (val === undefined || val === null) { return fallback }
  if (tail.length === 0) { return val }
  return deepGet(val, tail, fallback)
}

// Merge two Immutable maps while preferring data over nulls and never returning undefined.
function smartMergeDeep(oldMap, newMap) {
  const filteredNewMap = newMap.filterNot(v => v === undefined || v === null)
  return oldMap.mergeDeepWith((oldVal, newVal) => {
    if (oldVal === undefined && newVal === undefined) { return null }
    if (oldVal === null || oldVal === undefined) { return newVal }
    return newVal
  }, filteredNewMap)
}

// Given state (immutable), a key path (array[string]), and map merge the map in.
// If a value on either side is null or undefined it "loses" the merge - we always prefer data.
function smartMergeDeepIn(state, keyPath, newMap) {
  const oldMap = state.getIn(keyPath, Immutable.Map())
  const mergedMap = smartMergeDeep(oldMap, newMap)
  return state.setIn(keyPath, mergedMap)
}

function parseList(state, list, parser) {
  if (!Array.isArray(list)) { return state }
  return list.reduce(parser, state)
}

function parsePagination(state, stream, pathname, query, variables) {
  const { posts: models, next, isLastPage } = stream
  const mergedState = state.mergeDeepIn(['pages', pathname], Immutable.fromJS({
    pagination: Immutable.fromJS({ next, query, variables, isLastPage }),
  }))
  return mergedState.updateIn(['pages', pathname, 'ids'], (existingPageIds) => {
    const newPageIds = Immutable.OrderedSet(models.map(m => m.id))
    // If we don't have any existingPageIds just return the new ids.
    if (!existingPageIds || existingPageIds.count() === 0) {
      return newPageIds
    }
    // If we have a before value in the query this is not the first page, so append to ordered set.
    if (variables.before || (variables.get && variables.get('before'))) {
      return existingPageIds.concat(newPageIds)
    }
    // If we don't have a before value this is either the first page or re-requesting the first
    // page. In that case we need to prepend to the ordered set.
    return newPageIds.concat(existingPageIds)
  })
}

function parseAsset(state, asset) {
  if (!asset) { return state }
  return smartMergeDeepIn(state, ['assets', asset.id], Immutable.fromJS({
    id: asset.id,
    attachment: asset.attachment,
  }))
}

function reduceAssets(assets) {
  return (assets || []).reduce((byId, asset) => (
      { ...byId, [asset.id]: asset }
    ), {})
}

function parseCategory(state, category) {
  if (!category) { return state }
  return smartMergeDeepIn(state, ['categories', category.id], Immutable.fromJS({
    id: category.id,
    slug: category.slug,
    name: category.name,
    level: category.level,
    order: category.order,
    allowInOnboarding: category.allowInOnboarding,
    isCreatorType: category.isCreatorType,
    tileImage: category.tileImage,
  }))
}

function parseArtistInviteSubmission(state, submission) {
  if (!submission || !submission.id) { return state }
  return smartMergeDeepIn(state, ['artistInviteSubmissions', submission.id], Immutable.fromJS({
    id: submission.id,
  }))
}

function parseUser(state, user) {
  if (!user) { return state }

  const state1 = smartMergeDeepIn(state, ['users', user.id], Immutable.fromJS({

    // Minumum properties
    id: user.id,
    username: user.username,
    name: user.name,
    avatar: user.avatar,

    // Extended properties
    coverImage: user.coverImage,
    badges: user.badges,
    externalLinksLink: user.externalLinksLink,
    formattedShortBio: user.formattedShortBio,
    location: user.location,

    // Settings
    isCollaboratable: deepGet(user, ['settings', 'isCollaboratable']),
    isHireable: deepGet(user, ['settings', 'isHireable']),
    hasCommentingEnabled: deepGet(user, ['settings', 'hasCommentingEnabled']),
    hasLovesEnabled: deepGet(user, ['settings', 'hasLovesEnabled']),
    hasRepostingEnabled: deepGet(user, ['settings', 'hasRepostingEnabled']),
    hasSharingEnabled: deepGet(user, ['settings', 'hasSharingEnabled']),
    postsAdultContent: deepGet(user, ['settings', 'postAdultContent']),

    // userStats
    followersCount: deepGet(user, ['userStats', 'followersCount']),
    followingCount: deepGet(user, ['userStats', 'followingCount']),
    postsCount: deepGet(user, ['userStats', 'postsCount']),
    lovesCount: deepGet(user, ['userStats', 'lovesCount']),
    totalViewsCount: deepGet(user, ['userStats', 'totalViewsCount']),

    // currentUserState
    relationshipPriority: deepGet(user, ['currentUserState', 'relationshipPriority']),
  }))
  const state2 = parseList(state1, user.categories, parseCategory)
  return state2
}

function parsePageHeader(state, pageHeader) {
  if (!pageHeader) { return state }
  const state1 = parseUser(state, pageHeader.user)
  const state2 = parseCategory(state1, pageHeader.category)
  return smartMergeDeepIn(state2, ['pageHeaders', pageHeader.id], Immutable.fromJS({
    id: pageHeader.id,
    kind: pageHeader.kind,
    slug: pageHeader.slug,
    postToken: pageHeader.postToken,
    header: pageHeader.header,
    subheader: pageHeader.subheader,
    ctaLink: pageHeader.ctaLink,
    image: pageHeader.image,
    userId: deepGet(pageHeader, ['user', 'id']),
    categoryId: deepGet(pageHeader, ['category', 'id']),
  }))
}

function postLinks(post) {
  const links = {}
  const authorId = deepGet(post, ['author', 'id'])
  if (authorId) { links.author = { id: authorId, type: 'user' } }

  const repostAuthorId = deepGet(post, ['repostedSource', 'author', 'id'])
  if (repostAuthorId) { links.repostAuthor = { id: repostAuthorId, type: 'user' } }

  const repostId = deepGet(post, ['repostedSource', 'id'])
  if (repostId) { links.repostedSource = { id: repostId, type: 'post' } }

  return links
}

// Camelize data keys, inject assets objects into appropriate region
function parseRegion(post, type, assetsById) {
  return (post[type] || []).map((region, index) => {
    const id = `${post.id}-${index}`
    const assetId = deepGet(region, ['links', 'assets'])
    const asset = assetsById[assetId]
    let data = null
    if (typeof region.data === 'object') {
      data = camelizeKeys(region.data)
    } else {
      data = region.data
    }
    if (region.kind === 'image' && typeof assetId === 'string' && asset) {
      return { ...region, data, id, asset }
    }
    return { ...region, data, id }
  })
}

function parsePost(state, post) {
  if (!post) { return state }

  const state1 = parseUser(state, post.author)
  const state2 = parseList(state1, post.assets, parseAsset)
  const state3 = parsePost(state2, post.repostedSource)
  const state4 = parseArtistInviteSubmission(state3, post.artistInviteSubmission)

  const assetsById = reduceAssets(post.assets)
  const repostAssetsById = post.repostedSource ? reduceAssets(post.repostedSource.assets) : null

  const state5 = smartMergeDeepIn(state4, ['posts', post.id], Immutable.fromJS({
    // ids
    id: post.id,
    authorId: deepGet(post, ['author', 'id']), // We don't use links for this

    // Properties
    token: post.token,
    createdAt: post.createdAt,
    artistInviteId: deepGet(post, ['artistInviteSubmission', 'artistInvite']),
    artistInviteSubmission: post.artistInviteSubmission,

    // Content
    summary: parseRegion(post, 'summary', assetsById),
    content: parseRegion(post, 'content', assetsById),
    repostContent: parseRegion(post, 'repostContent', repostAssetsById),

    // Stats
    lovesCount: deepGet(post, ['postStats', 'lovesCount']),
    commentsCount: deepGet(post, ['postStats', 'commentsCount']),
    viewsCount: deepGet(post, ['postStats', 'viewsCount']),
    repostsCount: deepGet(post, ['postStats', 'repostsCount']),

    // Current user state
    watching: deepGet(post, ['currentUserState', 'watching']),
    loved: deepGet(post, ['currentUserState', 'loved']),
    reposted: deepGet(post, ['currentUserState', 'reposted']),

    // Links
    links: postLinks(post),
  }))

  return state5
}

function parseQueryType(state, stream, pathname, query, variables) {
  const { posts } = stream
  const state1 = parseList(state, posts, parsePost)
  return parsePagination(state1, stream, pathname, query, variables)
}

function parseStream(state, { payload: { response: { data }, pathname, query, variables } }) {
  return Object.keys(data).reduce((s, key) =>
    parseQueryType(s, data[key], pathname, query, variables),
    state,
  )
}

function parseCategoryQueries(state, { payload: { response: { data } } }) {
  return parseList(state, data.categoryNav || data.allCategories, parseCategory)
}

function parsePageHeaders(state, { payload: { response: { data: { pageHeaders } } } }) {
  return parseList(state, pageHeaders, parsePageHeader)
}

// Dispatch different graphql response types for parsing (reducing)
export default function (state, action) {
  const { type } = action
  switch (type) {
    case ACTION_TYPES.V3.LOAD_STREAM_SUCCESS:
    case ACTION_TYPES.V3.LOAD_NEXT_CONTENT_SUCCESS:
      return parseStream(state, action)
    case ACTION_TYPES.V3.LOAD_CATEGORIES_SUCCESS:
      return parseCategoryQueries(state, action)
    case ACTION_TYPES.V3.LOAD_PAGE_HEADERS_SUCCESS:
      return parsePageHeaders(state, action)
    default:
      return state
  }
}
<|endoftext|>


<commit_before>(function (window, angular) {
  'use strict';

  var injector = angular.injector,
      isArray = angular.isArray,
      extend = angular.extend,

      debase;

  debase = function debase(moduleName, targets, opts) {
    var ignores,
        auto,
        stubs,
        moduleFunction;

    if (!moduleName) {
      throw new Error('debase requires a module name parameter');
    }

    if (!targets || (isArray(targets) && !targets.length)) {
      throw new Error('debase requires one or more target components');
    }

    if (angular.isString(targets)) {
      targets = [targets];
    }

    opts = opts || {};
    moduleFunction = function moduleFunction($provide, $injector, $utils, $options, Stub) {
      var adapter = $utils.getAdapter(opts.adapter || $options.adapter),
          contains = $utils.contains;

      Stub = angular.isObject(Stub) ? Stub.Stub : Stub;
      auto = angular.isDefined(opts.autoStub) ? opts.autoStub : $options.autoStub;
      stubs = extend({}, $options.stubs, opts.stubs);
      ignores = extend({}, $options.ignores, $utils.makeSet(opts.ignores || []));
      angular.module(moduleName)._invokeQueue.forEach(function (item) {
        var component_type = item[1],
            definition = item[2],
            name = definition[0],
            annotations;
        if (contains(targets, name)) {
          //TODO support $inject
          annotations = isArray(definition[1]) ? definition[1].slice(0, -1)
            : injector().annotate(definition[1]);
          annotations.forEach(function (name) {
            var stub;
            if (auto && !stubs[name]) {
              stubs[name] = new Stub({
                $name: name,
                $type: 'function'
              });
            }
            stub = Stub.findStub(name, {
              stubs: stubs,
              adapter: adapter,
              ignores: ignores
            });
            if (stub) {
              stub.provide($provide);
            }
          });
        }
      });

    };
    moduleFunction.$inject =
      ['$provide', '$injector', 'decipher.debaser.utils', 'decipher.debaser.options',
        'decipher.debaser.stubProvider'];

    window.beforeEach(function () {
      angular.mock.module(moduleName, moduleFunction);
      angular.mock.inject();
    });

  };
  debase.options = function options(opts) {
    var global_opts = angular.injector(['decipher.debaser']).get('decipher.debaser.options');
    angular.extend(global_opts, opts);
  };

  debase.stub = function stub(type, value, opts) {
    var new_stub,
        getBase = function getBase(stub) {
          return function base() {
            return stub;
          };
        },
        stubber = function (global_opts, constants, utils, Stub) {
          var STUB_TYPES = constants.STUB_TYPES,
              adapter,
              proxy;

          Stub = angular.isObject(Stub) ? Stub.Stub : Stub;
          if (!type) {
            throw new Error('Parameter required');
          }
          if (angular.isString(type)) {
            type = type.toLowerCase();
            if (!utils.contains(STUB_TYPES, type)) {
              throw new Error('Unknown stub type "' + type + '".  Valid types are: ' +
                STUB_TYPES.join(', ') + '. To use a custom value, do not use this function.');
            }
            adapter = utils.getAdapter(opts.adapter || global_opts.adapter);
            proxy = adapter[type](value);
            new_stub = new Stub({
              $type: type,
              $proxy: proxy
            }, opts);

            if (angular.isObject(proxy) || angular.isArray(proxy)) {
              angular.forEach(new_stub.$proxy, function (value) {
                if (angular.isFunction(value)) {
                  value.base = getBase(new_stub);
                }
              });
            } else if (angular.isFunction(proxy)) {
              proxy.base = getBase(new_stub);
            }
          } else {
            new_stub = new Stub(angular.extend({}, type, {
              $proxy: type
            }), opts);
          }

        };
    opts = opts || {};
    stubber.$inject =
      ['decipher.debaser.options', 'decipher.debaser.constants', 'decipher.debaser.utils',
        'decipher.debaser.stubProvider', '$injector'];

    angular.injector(['decipher.debaser', stubber]);

    return new_stub;
  };

  window.debase = debase;

})(window, window.angular);
<commit_msg>removing rogue inject()<commit_after>(function (window, angular) {
  'use strict';

  var injector = angular.injector,
      isArray = angular.isArray,
      extend = angular.extend,

      debase;

  debase = function debase(moduleName, targets, opts) {
    var ignores,
        auto,
        stubs,
        moduleFunction;

    if (!moduleName) {
      throw new Error('debase requires a module name parameter');
    }

    if (!targets || (isArray(targets) && !targets.length)) {
      throw new Error('debase requires one or more target components');
    }

    if (angular.isString(targets)) {
      targets = [targets];
    }

    opts = opts || {};
    moduleFunction = function moduleFunction($provide, $injector, $utils, $options, Stub) {
      var adapter = $utils.getAdapter(opts.adapter || $options.adapter),
          contains = $utils.contains;

      Stub = angular.isObject(Stub) ? Stub.Stub : Stub;
      auto = angular.isDefined(opts.autoStub) ? opts.autoStub : $options.autoStub;
      stubs = extend({}, $options.stubs, opts.stubs);
      ignores = extend({}, $options.ignores, $utils.makeSet(opts.ignores || []));
      angular.module(moduleName)._invokeQueue.forEach(function (item) {
        var component_type = item[1],
            definition = item[2],
            name = definition[0],
            annotations;
        if (contains(targets, name)) {
          //TODO support $inject
          annotations = isArray(definition[1]) ? definition[1].slice(0, -1)
            : injector().annotate(definition[1]);
          annotations.forEach(function (name) {
            var stub;
            if (auto && !stubs[name]) {
              stubs[name] = new Stub({
                $name: name,
                $type: 'function'
              });
            }
            stub = Stub.findStub(name, {
              stubs: stubs,
              adapter: adapter,
              ignores: ignores
            });
            if (stub) {
              stub.provide($provide);
            }
          });
        }
      });

    };
    moduleFunction.$inject =
      ['$provide', '$injector', 'decipher.debaser.utils', 'decipher.debaser.options',
        'decipher.debaser.stubProvider'];

    window.beforeEach(function () {
      angular.mock.module(moduleName, moduleFunction);
    });

  };
  debase.options = function options(opts) {
    var global_opts = angular.injector(['decipher.debaser']).get('decipher.debaser.options');
    angular.extend(global_opts, opts);
  };

  debase.stub = function stub(type, value, opts) {
    var new_stub,
        getBase = function getBase(stub) {
          return function base() {
            return stub;
          };
        },
        stubber = function (global_opts, constants, utils, Stub) {
          var STUB_TYPES = constants.STUB_TYPES,
              adapter,
              proxy;

          Stub = angular.isObject(Stub) ? Stub.Stub : Stub;
          if (!type) {
            throw new Error('Parameter required');
          }
          if (angular.isString(type)) {
            type = type.toLowerCase();
            if (!utils.contains(STUB_TYPES, type)) {
              throw new Error('Unknown stub type "' + type + '".  Valid types are: ' +
                STUB_TYPES.join(', ') + '. To use a custom value, do not use this function.');
            }
            adapter = utils.getAdapter(opts.adapter || global_opts.adapter);
            proxy = adapter[type](value);
            new_stub = new Stub({
              $type: type,
              $proxy: proxy
            }, opts);

            if (angular.isObject(proxy) || angular.isArray(proxy)) {
              angular.forEach(new_stub.$proxy, function (value) {
                if (angular.isFunction(value)) {
                  value.base = getBase(new_stub);
                }
              });
            } else if (angular.isFunction(proxy)) {
              proxy.base = getBase(new_stub);
            }
          } else {
            new_stub = new Stub(angular.extend({}, type, {
              $proxy: type
            }), opts);
          }

        };
    opts = opts || {};
    stubber.$inject =
      ['decipher.debaser.options', 'decipher.debaser.constants', 'decipher.debaser.utils',
        'decipher.debaser.stubProvider', '$injector'];

    angular.injector(['decipher.debaser', stubber]);

    return new_stub;
  };

  window.debase = debase;

})(window, window.angular);
<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict';

const fs = require('fs');
const path = require('path');
const meow = require('meow');

const PATH = './src/templates';
const TRANSFORM_FILE = './build/transforms.json';

const cli = meow(`
  Usage
  $ can-migrate-generate [<path> <template> ...]

  Creates files for can-migrate

  Options
  --can-version     specify CanJS version

  Examples
  can-migrate-generate can-define-array define-array --can-version=6
  can-migrate-generate can-blob import --can-version=6
`, {
  string: ['can-version']
});
console.log('flags', cli.flags)
if (!cli.input.length || cli.input.length !== 2 || !cli.flags.canVersion) {
  cli.showHelp();
  return;
}

const migrationFolder = cli.input[0];
const migrationName = cli.input[1];

// check if the folder exists
if (!fs.existsSync(path.join(PATH, migrationFolder))) {
  // make the directory
  fs.mkdirSync(path.join(PATH, migrationFolder));
}

// Create each of these extensions
const extensions = [
  {
    ext: '.js',
    type: 'transform',
    template: (transform) => {
      return `import getConfig from '../../../utils/getConfig';
import makeDebug from 'debug';

export default function transformer(file, api, options) {
  const debug = makeDebug(\`can-migrate:${transform}:\${file.path}\`);
  const config = getConfig(options.config);
  const j = api.jscodeshift;

  return j(file.source)
    .toSource();
}
`
    }
  },
  {
    ext: '-input.js',
    type: 'fixture',
    template: () => ('')
  },
  {
    ext: '-output.js',
    type: 'fixture',
    template: () => ('')
  },
  {
    ext: '-test.js',
    type: 'test',
    template: (transform, version) => {
      return `require('mocha');
const utils = require('../../../../test/utils');
const transforms = require('../../../../');

const toTest = transforms.filter(function(transform) {
  return transform.name === '${transform}.js';
})[0];

describe('${transform}', function() {

  it('', function() {
    const fn = require(toTest.file);
    const inputPath = \`fixtures/version-${version}/\${toTest.fileName.replace('.js', '-input.js')}\`;
    const outputPath = \`fixtures/version-${version}/\${toTest.fileName.replace('.js', '-output.js')}\`;
    utils.diffFiles(fn, inputPath, outputPath);
  });

});
`;
    }
  }
];
const transforms = [];

for (let i = 0; i < extensions.length; i++) {
  const current = extensions[i];
  const file = `${migrationName}${current.ext}`;
  const migration = `${migrationFolder}/${migrationName}`;
  // Create a blank file
  fs.writeFileSync(path.join(PATH, migrationFolder, file), current.template(migration, cli.flags.canVersion));

  // Add to the transforms array
  transforms.push({
    input: `${migration}${current.ext}`,
    outputPath: `${migration}${current.ext}`,
    type: current.type,
    version: cli.flags.canVersion+''
  });
}

// Parse the existing transforms and push in this transform
const transformData = JSON.parse(fs.readFileSync(TRANSFORM_FILE));
transformData.push({
  copy: transforms
});

// Write out the new transforms file
fs.writeFileSync(TRANSFORM_FILE, JSON.stringify(transformData, null, 2));

console.log(`Successfully created files and transforms for: ${migrationName}`)
<commit_msg>remove debug console.log from migrate generator<commit_after>#!/usr/bin/env node
'use strict';

const fs = require('fs');
const path = require('path');
const meow = require('meow');

const PATH = './src/templates';
const TRANSFORM_FILE = './build/transforms.json';

const cli = meow(`
  Usage
  $ can-migrate-generate [<path> <template> ...]

  Creates files for can-migrate

  Options
  --can-version     specify CanJS version

  Examples
  can-migrate-generate can-define-array define-array --can-version=6
  can-migrate-generate can-blob import --can-version=6
`, {
  string: ['can-version']
});

if (!cli.input.length || cli.input.length !== 2 || !cli.flags.canVersion) {
  cli.showHelp();
  return;
}

const migrationFolder = cli.input[0];
const migrationName = cli.input[1];

// check if the folder exists
if (!fs.existsSync(path.join(PATH, migrationFolder))) {
  // make the directory
  fs.mkdirSync(path.join(PATH, migrationFolder));
}

// Create each of these extensions
const extensions = [
  {
    ext: '.js',
    type: 'transform',
    template: (transform) => {
      return `import getConfig from '../../../utils/getConfig';
import makeDebug from 'debug';

export default function transformer(file, api, options) {
  const debug = makeDebug(\`can-migrate:${transform}:\${file.path}\`);
  const config = getConfig(options.config);
  const j = api.jscodeshift;

  return j(file.source)
    .toSource();
}
`
    }
  },
  {
    ext: '-input.js',
    type: 'fixture',
    template: () => ('')
  },
  {
    ext: '-output.js',
    type: 'fixture',
    template: () => ('')
  },
  {
    ext: '-test.js',
    type: 'test',
    template: (transform, version) => {
      return `require('mocha');
const utils = require('../../../../test/utils');
const transforms = require('../../../../');

const toTest = transforms.filter(function(transform) {
  return transform.name === '${transform}.js';
})[0];

describe('${transform}', function() {

  it('', function() {
    const fn = require(toTest.file);
    const inputPath = \`fixtures/version-${version}/\${toTest.fileName.replace('.js', '-input.js')}\`;
    const outputPath = \`fixtures/version-${version}/\${toTest.fileName.replace('.js', '-output.js')}\`;
    utils.diffFiles(fn, inputPath, outputPath);
  });

});
`;
    }
  }
];
const transforms = [];

for (let i = 0; i < extensions.length; i++) {
  const current = extensions[i];
  const file = `${migrationName}${current.ext}`;
  const migration = `${migrationFolder}/${migrationName}`;
  // Create a blank file
  fs.writeFileSync(path.join(PATH, migrationFolder, file), current.template(migration, cli.flags.canVersion));

  // Add to the transforms array
  transforms.push({
    input: `${migration}${current.ext}`,
    outputPath: `${migration}${current.ext}`,
    type: current.type,
    version: cli.flags.canVersion+''
  });
}

// Parse the existing transforms and push in this transform
const transformData = JSON.parse(fs.readFileSync(TRANSFORM_FILE));
transformData.push({
  copy: transforms
});

// Write out the new transforms file
fs.writeFileSync(TRANSFORM_FILE, JSON.stringify(transformData, null, 2));

console.log(`Successfully created files and transforms for: ${migrationName}`)
<|endoftext|>


<commit_before>// traverse the node_modules/package.json tree
// looking for duplicates.  If any duplicates are found,
// then move them up to the highest level necessary
// in order to make them no longer duplicated.
//
// This is kind of ugly, and really highlights the need for
// much better "put pkg X at folder Y" abstraction.  Oh well,
// whatever.  Perfect enemy of the good, and all that.

var fs = require("fs")
var asyncMap = require("slide").asyncMap
var path = require("path")
var readJson = require("read-package-json")
var archy = require("archy")
var util = require("util")
var RegClient = require("npm-registry-client")
var npmconf = require("npmconf")
var npm = require("npm")
var semver = require("semver")
var npm = require("npm")
var rimraf = require("rimraf")
var log = require("npmlog")
var npm = require("./npm.js")

module.exports = dedupe

dedupe.usage = "npm dedupe [pkg pkg...]"

function dedupe (args, silent, cb) {
  if (typeof silent === "function") cb = silent, silent = false
  var dryrun = false
  if (npm.command.match(/^find/)) dryrun = true
  return dedupe_(npm.prefix, args, {}, dryrun, silent, cb)
}

function dedupe_ (dir, filter, unavoidable, dryrun, silent, cb) {
  readInstalled(path.resolve(dir), {}, null, function (er, data, counter) {
    // find out which things are dupes
    var dupes = Object.keys(counter).filter(function (k) {
      if (filter.length && -1 === filter.indexOf(k)) return false
      return counter[k] > 1 && !unavoidable[k]
    }).reduce(function (s, k) {
      s[k] = []
      return s
    }, {})

    // any that are unavoidable need to remain as they are.  don't even
    // try to touch them or figure it out.  Maybe some day, we can do
    // something a bit more clever here, but for now, just skip over it,
    // and all its children.
    ;(function U (obj) {
      if (unavoidable[obj.name]) {
        obj.unavoidable = true
      }
      if (obj.parent && obj.parent.unavoidable) {
        obj.unavoidable = true
      }
      Object.keys(obj.children).forEach(function (k) {
        U(obj.children[k])
      })
    })

    // then collect them up and figure out who needs them
    ;(function C (obj) {
      if (dupes[obj.name] && !obj.unavoidable) {
        dupes[obj.name].push(obj)
        obj.duplicate = true
      }
      obj.dependents = whoDepends(obj)
      Object.keys(obj.children).forEach(function (k) {
        C(obj.children[k])
      })
    })(data)

    if (dryrun) {
      var k = Object.keys(dupes)
      if (!k.length) return cb()
      return npm.commands.ls(k, silent, cb)
    }

    var summary = Object.keys(dupes).map(function (n) {
      return [n, dupes[n].filter(function (d) {
        return d && d.parent && !d.parent.duplicate && !d.unavoidable
      }).map(function M (d) {
        return [d.path, d.version, d.dependents.map(function (k) {
          return [k.path, k.version, k.dependencies[d.name]]
        })]
      })]
    }).map(function (item) {
      var name = item[0]
      var set = item[1]

      var ranges = set.map(function (i) {
        return i[2].map(function (d) {
          return d[2]
        })
      }).reduce(function (l, r) {
        return l.concat(r)
      }, []).map(function (v, i, set) {
        if (set.indexOf(v) !== i) return false
        return v
      }).filter(function (v) {
        return v !== false
      })

      var locs = set.map(function (i) {
        return i[0]
      })

      var versions = set.map(function (i) {
        return i[1]
      }).filter(function (v, i, set) {
        return set.indexOf(v) === i
      })

      var has = set.map(function (i) {
        return [i[0], i[1]]
      }).reduce(function (set, kv) {
        set[kv[0]] = kv[1]
        return set
      }, {})

      var loc = locs.length ? locs.reduce(function (a, b) {
        // a=/path/to/node_modules/foo/node_modules/bar
        // b=/path/to/node_modules/elk/node_modules/bar
        // ==/path/to/node_modules/bar
        a = a.split(/\/node_modules\//)
        b = b.split(/\/node_modules\//)
        var name = a.pop()
        b.pop()
        // find the longest chain that both A and B share.
        // then push the name back on it, and join by /node_modules/
        var res = []
        for (var i = 0, al = a.length, bl = b.length; i < al && i < bl && a[i] === b[i]; i++);
        return a.slice(0, i).concat(name).join("/node_modules/")
      }) : undefined

      return [item[0], { item: item
                       , ranges: ranges
                       , locs: locs
                       , loc: loc
                       , has: has
                       , versions: versions
                       }]
    }).filter(function (i) {
      return i[1].loc
    })

    findVersions(npm, summary, function (er, set) {
      if (er) return cb(er)
      if (!set.length) return cb()
      installAndRetest(set, filter, dir, unavoidable, silent, cb)
    })
  })
}

function installAndRetest (set, filter, dir, unavoidable, silent, cb) {
  //return cb(null, set)
  var remove = []

  asyncMap(set, function (item, cb) {
    // [name, has, loc, locMatch, regMatch, others]
    var name = item[0]
    var has = item[1]
    var where = item[2]
    var locMatch = item[3]
    var regMatch = item[4]
    var others = item[5]

    // nothing to be done here.  oh well.  just a conflict.
    if (!locMatch && !regMatch) {
      log.warn("unavoidable conflict", item[0], item[1])
      log.warn("unavoidable conflict", "Not de-duplicating")
      unavoidable[item[0]] = true
      return cb()
    }

    // nothing to do except to clean up the extraneous deps
    if (locMatch && has[where] === locMatch) {
      remove.push.apply(remove, others)
      return cb()
    }

    if (regMatch) {
      var what = name + "@" + regMatch
      // where is /path/to/node_modules/foo/node_modules/bar
      // for package "bar", but we need it to be just
      // /path/to/node_modules/foo
      where = where.split(/\/node_modules\//)
      where.pop()
      where = where.join("/node_modules/")
      remove.push.apply(remove, others)

      return npm.commands.install(where, what, cb)
    }

    // hrm?
    return cb(new Error("danger zone\n" + name + " " +
                        + regMatch + " " + locMatch))

  }, function (er, installed) {
    if (er) return cb(er)
    asyncMap(remove, rimraf, function (er) {
      if (er) return cb(er)
      remove.forEach(function (r) {
        log.info("rm", r)
      })
      dedupe_(dir, filter, unavoidable, false, silent, cb)
    })
  })
}

function findVersions (npm, summary, cb) {
  // now, for each item in the summary, try to find the maximum version
  // that will satisfy all the ranges.  next step is to install it at
  // the specified location.
  asyncMap(summary, function (item, cb) {
    var name = item[0]
    var data = item[1]
    var loc = data.loc
    var locs = data.locs.filter(function (l) {
      return l !== loc
    })

    // not actually a dupe, or perhaps all the other copies were
    // children of a dupe, so this'll maybe be picked up later.
    if (locs.length === 0) {
      return cb()
    }

    // { <folder>: <version> }
    var has = data.has

    // the versions that we already have.
    // if one of these is ok, then prefer to use that.
    // otherwise, try fetching from the registry.
    var versions = data.versions

    var ranges = data.ranges
    npm.registry.get(name, function (er, data) {
      var regVersions = er ? [] : Object.keys(data.versions)
      var locMatch = bestMatch(versions, ranges)
      var regMatch = bestMatch(regVersions, ranges)

      cb(null, [[name, has, loc, locMatch, regMatch, locs]])
    })
  }, cb)
}

function bestMatch (versions, ranges) {
  return versions.filter(function (v) {
    return !ranges.some(function (r) {
      return !semver.satisfies(v, r)
    })
  }).sort(semver.compare).pop()
}

function readInstalled (dir, counter, parent, cb) {
  var pkg, children, realpath

  fs.realpath(dir, function (er, rp) {
    realpath = rp
    next()
  })

  readJson(path.resolve(dir, "package.json"), function (er, data) {
    if (er) return cb() // not a package, probably.
    counter[data.name] = counter[data.name] || 0
    counter[data.name]++
    pkg =
      { _id: data._id
      , name: data.name
      , version: data.version
      , dependencies: data.dependencies || {}
      , optionalDependencies: data.optionalDependencies || {}
      , devDependencies: data.devDependencies || {}
      , bundledDependencies: data.bundledDependencies || []
      , path: dir
      , realPath: dir
      , children: {}
      , parent: parent
      , family: Object.create(parent ? parent.family : null)
      , unavoidable: false
      , duplicate: false
      }
    if (parent) {
      parent.children[data.name] = pkg
      parent.family[data.name] = pkg
    }
    next()
  })

  fs.readdir(path.resolve(dir, "node_modules"), function (er, c) {
    children = c || [] // error is ok, just means no children.
    next()
  })

  function next () {
    if (!children || !pkg || !realpath) return
    pkg.realPath = realpath
    if (pkg.realPath !== pkg.path) children = []
    var d = path.resolve(dir, "node_modules")
    asyncMap(children, function (child, cb) {
      readInstalled(path.resolve(d, child), counter, pkg, cb)
    }, function (er) {
      cb(er, pkg, counter)
    })
  }
}

function whoDepends (pkg) {
  var start = pkg.parent || pkg
  return whoDepends_(pkg, [], start)
}

function whoDepends_ (pkg, who, test) {
  if (test !== pkg &&
      test.dependencies[pkg.name] &&
      test.family[pkg.name] === pkg) {
    who.push(test)
  }
  Object.keys(test.children).forEach(function (n) {
    whoDepends_(pkg, who, test.children[n])
  })
  return who
}

<commit_msg>dedupe: Handle dev/extraneous deps better<commit_after>// traverse the node_modules/package.json tree
// looking for duplicates.  If any duplicates are found,
// then move them up to the highest level necessary
// in order to make them no longer duplicated.
//
// This is kind of ugly, and really highlights the need for
// much better "put pkg X at folder Y" abstraction.  Oh well,
// whatever.  Perfect enemy of the good, and all that.

var fs = require("fs")
var asyncMap = require("slide").asyncMap
var path = require("path")
var readJson = require("read-package-json")
var archy = require("archy")
var util = require("util")
var RegClient = require("npm-registry-client")
var npmconf = require("npmconf")
var npm = require("npm")
var semver = require("semver")
var npm = require("npm")
var rimraf = require("rimraf")
var log = require("npmlog")
var npm = require("./npm.js")

module.exports = dedupe

dedupe.usage = "npm dedupe [pkg pkg...]"

function dedupe (args, silent, cb) {
  if (typeof silent === "function") cb = silent, silent = false
  var dryrun = false
  if (npm.command.match(/^find/)) dryrun = true
  return dedupe_(npm.prefix, args, {}, dryrun, silent, cb)
}

function dedupe_ (dir, filter, unavoidable, dryrun, silent, cb) {
  readInstalled(path.resolve(dir), {}, null, function (er, data, counter) {
    // find out which things are dupes
    var dupes = Object.keys(counter).filter(function (k) {
      if (filter.length && -1 === filter.indexOf(k)) return false
      return counter[k] > 1 && !unavoidable[k]
    }).reduce(function (s, k) {
      s[k] = []
      return s
    }, {})

    // any that are unavoidable need to remain as they are.  don't even
    // try to touch them or figure it out.  Maybe some day, we can do
    // something a bit more clever here, but for now, just skip over it,
    // and all its children.
    ;(function U (obj) {
      if (unavoidable[obj.name]) {
        obj.unavoidable = true
      }
      if (obj.parent && obj.parent.unavoidable) {
        obj.unavoidable = true
      }
      Object.keys(obj.children).forEach(function (k) {
        U(obj.children[k])
      })
    })

    // then collect them up and figure out who needs them
    ;(function C (obj) {
      if (dupes[obj.name] && !obj.unavoidable) {
        dupes[obj.name].push(obj)
        obj.duplicate = true
      }
      obj.dependents = whoDepends(obj)
      Object.keys(obj.children).forEach(function (k) {
        C(obj.children[k])
      })
    })(data)

    if (dryrun) {
      var k = Object.keys(dupes)
      if (!k.length) return cb()
      return npm.commands.ls(k, silent, cb)
    }

    var summary = Object.keys(dupes).map(function (n) {
      return [n, dupes[n].filter(function (d) {
        return d && d.parent && !d.parent.duplicate && !d.unavoidable
      }).map(function M (d) {
        return [d.path, d.version, d.dependents.map(function (k) {
          return [k.path, k.version, k.dependencies[d.name] || ""]
        })]
      })]
    }).map(function (item) {
      var name = item[0]
      var set = item[1]

      var ranges = set.map(function (i) {
        return i[2].map(function (d) {
          return d[2]
        })
      }).reduce(function (l, r) {
        return l.concat(r)
      }, []).map(function (v, i, set) {
        if (set.indexOf(v) !== i) return false
        return v
      }).filter(function (v) {
        return v !== false
      })

      var locs = set.map(function (i) {
        return i[0]
      })

      var versions = set.map(function (i) {
        return i[1]
      }).filter(function (v, i, set) {
        return set.indexOf(v) === i
      })

      var has = set.map(function (i) {
        return [i[0], i[1]]
      }).reduce(function (set, kv) {
        set[kv[0]] = kv[1]
        return set
      }, {})

      var loc = locs.length ? locs.reduce(function (a, b) {
        // a=/path/to/node_modules/foo/node_modules/bar
        // b=/path/to/node_modules/elk/node_modules/bar
        // ==/path/to/node_modules/bar
        a = a.split(/\/node_modules\//)
        b = b.split(/\/node_modules\//)
        var name = a.pop()
        b.pop()
        // find the longest chain that both A and B share.
        // then push the name back on it, and join by /node_modules/
        var res = []
        for (var i = 0, al = a.length, bl = b.length; i < al && i < bl && a[i] === b[i]; i++);
        return a.slice(0, i).concat(name).join("/node_modules/")
      }) : undefined

      return [item[0], { item: item
                       , ranges: ranges
                       , locs: locs
                       , loc: loc
                       , has: has
                       , versions: versions
                       }]
    }).filter(function (i) {
      return i[1].loc
    })

    findVersions(npm, summary, function (er, set) {
      if (er) return cb(er)
      if (!set.length) return cb()
      installAndRetest(set, filter, dir, unavoidable, silent, cb)
    })
  })
}

function installAndRetest (set, filter, dir, unavoidable, silent, cb) {
  //return cb(null, set)
  var remove = []

  asyncMap(set, function (item, cb) {
    // [name, has, loc, locMatch, regMatch, others]
    var name = item[0]
    var has = item[1]
    var where = item[2]
    var locMatch = item[3]
    var regMatch = item[4]
    var others = item[5]

    // nothing to be done here.  oh well.  just a conflict.
    if (!locMatch && !regMatch) {
      log.warn("unavoidable conflict", item[0], item[1])
      log.warn("unavoidable conflict", "Not de-duplicating")
      unavoidable[item[0]] = true
      return cb()
    }

    // nothing to do except to clean up the extraneous deps
    if (locMatch && has[where] === locMatch) {
      remove.push.apply(remove, others)
      return cb()
    }

    if (regMatch) {
      var what = name + "@" + regMatch
      // where is /path/to/node_modules/foo/node_modules/bar
      // for package "bar", but we need it to be just
      // /path/to/node_modules/foo
      where = where.split(/\/node_modules\//)
      where.pop()
      where = where.join("/node_modules/")
      remove.push.apply(remove, others)

      return npm.commands.install(where, what, cb)
    }

    // hrm?
    return cb(new Error("danger zone\n" + name + " " +
                        + regMatch + " " + locMatch))

  }, function (er, installed) {
    if (er) return cb(er)
    asyncMap(remove, rimraf, function (er) {
      if (er) return cb(er)
      remove.forEach(function (r) {
        log.info("rm", r)
      })
      dedupe_(dir, filter, unavoidable, false, silent, cb)
    })
  })
}

function findVersions (npm, summary, cb) {
  // now, for each item in the summary, try to find the maximum version
  // that will satisfy all the ranges.  next step is to install it at
  // the specified location.
  asyncMap(summary, function (item, cb) {
    var name = item[0]
    var data = item[1]
    var loc = data.loc
    var locs = data.locs.filter(function (l) {
      return l !== loc
    })

    // not actually a dupe, or perhaps all the other copies were
    // children of a dupe, so this'll maybe be picked up later.
    if (locs.length === 0) {
      return cb()
    }

    // { <folder>: <version> }
    var has = data.has

    // the versions that we already have.
    // if one of these is ok, then prefer to use that.
    // otherwise, try fetching from the registry.
    var versions = data.versions

    var ranges = data.ranges
    npm.registry.get(name, function (er, data) {
      var regVersions = er ? [] : Object.keys(data.versions)
      var locMatch = bestMatch(versions, ranges)
      var regMatch = bestMatch(regVersions, ranges)

      cb(null, [[name, has, loc, locMatch, regMatch, locs]])
    })
  }, cb)
}

function bestMatch (versions, ranges) {
  return versions.filter(function (v) {
    return !ranges.some(function (r) {
      return !semver.satisfies(v, r)
    })
  }).sort(semver.compare).pop()
}

function readInstalled (dir, counter, parent, cb) {
  var pkg, children, realpath

  fs.realpath(dir, function (er, rp) {
    realpath = rp
    next()
  })

  readJson(path.resolve(dir, "package.json"), function (er, data) {
    if (er) return cb() // not a package, probably.
    counter[data.name] = counter[data.name] || 0
    counter[data.name]++
    pkg =
      { _id: data._id
      , name: data.name
      , version: data.version
      , dependencies: data.dependencies || {}
      , optionalDependencies: data.optionalDependencies || {}
      , devDependencies: data.devDependencies || {}
      , bundledDependencies: data.bundledDependencies || []
      , path: dir
      , realPath: dir
      , children: {}
      , parent: parent
      , family: Object.create(parent ? parent.family : null)
      , unavoidable: false
      , duplicate: false
      }
    if (parent) {
      parent.children[data.name] = pkg
      parent.family[data.name] = pkg
    }
    next()
  })

  fs.readdir(path.resolve(dir, "node_modules"), function (er, c) {
    children = c || [] // error is ok, just means no children.
    next()
  })

  function next () {
    if (!children || !pkg || !realpath) return

    // ignore devDependencies.  Just leave them where they are.
    children = children.filter(function (c) {
      return !pkg.devDependencies.hasOwnProperty(c)
    })

    pkg.realPath = realpath
    if (pkg.realPath !== pkg.path) children = []
    var d = path.resolve(dir, "node_modules")
    asyncMap(children, function (child, cb) {
      readInstalled(path.resolve(d, child), counter, pkg, cb)
    }, function (er) {
      cb(er, pkg, counter)
    })
  }
}

function whoDepends (pkg) {
  var start = pkg.parent || pkg
  return whoDepends_(pkg, [], start)
}

function whoDepends_ (pkg, who, test) {
  if (test !== pkg &&
      test.dependencies[pkg.name] &&
      test.family[pkg.name] === pkg) {
    who.push(test)
  }
  Object.keys(test.children).forEach(function (n) {
    whoDepends_(pkg, who, test.children[n])
  })
  return who
}

<|endoftext|>


<commit_before>'use strict';

const Broadcast = require('../../src/broadcast').Broadcast;
const Random    = require('../../src/random').Random;
const util = require('util');

exports.listeners = {

  //TODO: Consider modifying this to use dep injection that is more like the commands.
  // So that "globals" are injected instead of l10n at startup, then specific vars are sent via emitters.
  spawn: l10n => {
    return function (room, rooms, players) {
      const toRoom = Broadcast.toRoom(room, this, null, players);
      const msg = this.getShortDesc('en') + ' skitters out from a dark corner.';
      toRoom({ thirdPartyMessage: msg });
    }
  },

  playerEnter: l10n => {
    return (room, rooms, player, players, npc) => {
      const rand = Random.inRange(1, 10);
      if (rand === 3) {
        const msg = '<bold>The roach waggles its antennae.</bold>';
        const toRoom = Broadcast.toRoom(room, this, player, players);
        toRoom({
          secondPartyMessage: msg,
          thirdPartyMessage: msg
        });
      }
    }
  },

  playerDropItem: l10n => {
    return function(room, rooms, player, players, npc, npcs, item) {
      const rand = Random.inRange(1, 5);
      if (rand === 3) {
        const itemDesc = item.getShortDesc('en');
        const msg = '<bold>The roach scurries over to the ' + itemDesc +'.</bold>';
        const toRoom = Broadcast.toRoom(room, this, player, players);
        toRoom({
          secondPartyMessage: msg,
          thirdPartyMessage: msg
        });
      }
    }
  },

  hit: function(l10n) {
    return function(room, player, players, hitLocation, damage) {
      const toRoom = Broadcast.toRoom(room, this, player, players);

      const secondPartyMessage = [
        'The roach\'s pincers nip your ' + hitLocation + '.',
        'The roach bites your ' + hitLocation + ', drawing a pinprick of blood.',
      ];
      const thirdPartyMessage = [
        'The roach\'s pincers nip ' + player.getShortDesc('en') + '\'s ' + hitLocation + '.',
        'The roach bites ' + player.getShortDesc('en') + ' in the ' + hitLocation + ' and a tiny pinprick of blood wells forth.',
      ];
      Broadcast.consistentMessage(toRoom, { secondPartyMessage, thirdPartyMessage });
    }

  },

  damaged: function(l10n) {
    return function(room, player, players, hitLocation, damage) {
      const toRoom = Broadcast.toRoom(room, this, player, players);
      const hitInHead = hitLocation === 'head';
      const secondPartyMessage = hitInHead ?
        [
          'The roach chitters as its antennae are bent at an odd angle.',
        ] :
        [
          'The roach\'s chitin splinters and cracks around its ' + hitLocation + '.',
          'The roach hisses as ichor oozes from its wounds.'
        ];
      const thirdPartyMessage = hitInHead ?
        [
          'The roach chitters as ' + player.getShortDesc() + ' bends its antennae at an odd angle.'
        ] :
        [
          'The roach chitters in pain as its ' + hitLocation + ' shatters.',
          'Ichor oozes from the injured roach.'
        ];

      Broadcast.consistentMessage(toRoom, { secondPartyMessage, thirdPartyMessage });
    }
  },

  missedAttack: function(l10n) {
    return function(room, player, players, hitLocation) {
      const toRoom = Broadcast.toRoom(room, this, player, players);
      const secondPartyMessage = [
        'The roach scuttles over your feet harmlessly.',
        'The roach darts in your direction and you step out of the way.'
      ];
      const thirdPartyMessage = [
        'The roach scuttles over ' + player.getShortDesc('en') + "'s feet harmlessly.",
        'The roach darts at ' + player.getShortDesc('en') + ' but they step out of the way effortlessly.'
      ];
      Broadcast.consistentMessage(toRoom, { secondPartyMessage, thirdPartyMessage });
    }
  },

  parry: function(l10n) {
    return function (room, plaer, players, hitLocation) {
      const toRoom = Broadcast.toRoom(room, this, player, players);
      const secondPartyMessage = [
        '<white>The roach\'s abnormally tough chitin deflects your blow!</white>'
      ];
      const thirdPartyMessage = [
        '<white>' + player.getShortDesc('en') + '\'s blow is deflected by the roach\'s thick shell.</white>'
      ];
      Broadcast.consistentMessage(toRoom, { secondPartyMessage, thirdPartyMessage });
    }
  },

  npcLeave: l10n => {
    return function(room, rooms, players, npcs, dest) {
      const toRoom = Broadcast.toRoom(room, this, null, players);
      const thirdPartyMessage = Random.fromArray([
        'A cockroach leaves for ' + dest + ', leaving a trail of ooze.',
        'A roach heads to ' + dest + ', antennae jittering.',
        'An oozing coackroach scuttles over to ' + dest + '.'
      ]);
      toRoom({thirdPartyMessage});
    }
  },

  npcEnter: l10n => {
    return function(room, rooms, players, npcs, src) {
      const toRoom = Broadcast.toRoom(room, this, null, players);
      const thirdPartyMessage = Random.fromArray([
        'A cockroach leaves for ' + src + ', leaving a trail of ooze.',
        'A roach heads to ' + src + ', antennae jittering.',
        'An oozing coackroach scuttles over to ' + src + '.'
      ]);
      toRoom({thirdPartyMessage});
    }
  },

};
<commit_msg>Fix roach enter messages.<commit_after>'use strict';

const Broadcast = require('../../src/broadcast').Broadcast;
const Random    = require('../../src/random').Random;
const util = require('util');

exports.listeners = {

  //TODO: Consider modifying this to use dep injection that is more like the commands.
  // So that "globals" are injected instead of l10n at startup, then specific vars are sent via emitters.
  spawn: l10n => {
    return function (room, rooms, players) {
      const toRoom = Broadcast.toRoom(room, this, null, players);
      const msg = this.getShortDesc('en') + ' skitters out from a dark corner.';
      toRoom({ thirdPartyMessage: msg });
    }
  },

  playerEnter: l10n => {
    return (room, rooms, player, players, npc) => {
      const rand = Random.inRange(1, 10);
      if (rand === 3) {
        const msg = '<bold>The roach waggles its antennae.</bold>';
        const toRoom = Broadcast.toRoom(room, this, player, players);
        toRoom({
          secondPartyMessage: msg,
          thirdPartyMessage: msg
        });
      }
    }
  },

  playerDropItem: l10n => {
    return function(room, rooms, player, players, npc, npcs, item) {
      const rand = Random.inRange(1, 5);
      if (rand === 3) {
        const itemDesc = item.getShortDesc('en');
        const msg = '<bold>The roach scurries over to the ' + itemDesc +'.</bold>';
        const toRoom = Broadcast.toRoom(room, this, player, players);
        toRoom({
          secondPartyMessage: msg,
          thirdPartyMessage: msg
        });
      }
    }
  },

  hit: function(l10n) {
    return function(room, player, players, hitLocation, damage) {
      const toRoom = Broadcast.toRoom(room, this, player, players);

      const secondPartyMessage = [
        'The roach\'s pincers nip your ' + hitLocation + '.',
        'The roach bites your ' + hitLocation + ', drawing a pinprick of blood.',
      ];
      const thirdPartyMessage = [
        'The roach\'s pincers nip ' + player.getShortDesc('en') + '\'s ' + hitLocation + '.',
        'The roach bites ' + player.getShortDesc('en') + ' in the ' + hitLocation + ' and a tiny pinprick of blood wells forth.',
      ];
      Broadcast.consistentMessage(toRoom, { secondPartyMessage, thirdPartyMessage });
    }

  },

  damaged: function(l10n) {
    return function(room, player, players, hitLocation, damage) {
      const toRoom = Broadcast.toRoom(room, this, player, players);
      const hitInHead = hitLocation === 'head';
      const secondPartyMessage = hitInHead ?
        [
          'The roach chitters as its antennae are bent at an odd angle.',
        ] :
        [
          'The roach\'s chitin splinters and cracks around its ' + hitLocation + '.',
          'The roach hisses as ichor oozes from its wounds.'
        ];
      const thirdPartyMessage = hitInHead ?
        [
          'The roach chitters as ' + player.getShortDesc() + ' bends its antennae at an odd angle.'
        ] :
        [
          'The roach chitters in pain as its ' + hitLocation + ' shatters.',
          'Ichor oozes from the injured roach.'
        ];

      Broadcast.consistentMessage(toRoom, { secondPartyMessage, thirdPartyMessage });
    }
  },

  missedAttack: function(l10n) {
    return function(room, player, players, hitLocation) {
      const toRoom = Broadcast.toRoom(room, this, player, players);
      const secondPartyMessage = [
        'The roach scuttles over your feet harmlessly.',
        'The roach darts in your direction and you step out of the way.'
      ];
      const thirdPartyMessage = [
        'The roach scuttles over ' + player.getShortDesc('en') + "'s feet harmlessly.",
        'The roach darts at ' + player.getShortDesc('en') + ' but they step out of the way effortlessly.'
      ];
      Broadcast.consistentMessage(toRoom, { secondPartyMessage, thirdPartyMessage });
    }
  },

  parry: function(l10n) {
    return function (room, plaer, players, hitLocation) {
      const toRoom = Broadcast.toRoom(room, this, player, players);
      const secondPartyMessage = [
        '<white>The roach\'s abnormally tough chitin deflects your blow!</white>'
      ];
      const thirdPartyMessage = [
        '<white>' + player.getShortDesc('en') + '\'s blow is deflected by the roach\'s thick shell.</white>'
      ];
      Broadcast.consistentMessage(toRoom, { secondPartyMessage, thirdPartyMessage });
    }
  },

  npcLeave: l10n => {
    return function(room, rooms, players, npcs, dest) {
      const toRoom = Broadcast.toRoom(room, this, null, players);
      const thirdPartyMessage = Random.fromArray([
        'A cockroach leaves for ' + dest + ', leaving a trail of ooze.',
        'A roach heads to ' + dest + ', antennae jittering.',
        'An oozing coackroach scuttles over to ' + dest + '.'
      ]);
      toRoom({thirdPartyMessage});
    }
  },

  npcEnter: l10n => {
    return function(room, rooms, players, npcs, src) {
      const toRoom = Broadcast.toRoom(room, this, null, players);
      const thirdPartyMessage = Random.fromArray([
        'A cockroach crawls in from ' + src + ', dripping ooze.',
        'A roach scuttles in from ' + src + ', antennae jittering.',
        'An oozing coackroach skitters over to ' + src + '.'
      ]);
      toRoom({thirdPartyMessage});
    }
  },

};
<|endoftext|>


<commit_before>'use strict';

var inquirer  = require('inquirer'),
    aws       = require('aws-sdk')

class Question {
  constructor(region) {

    this.region = {
      type   : 'list',
      name   : 'region',
      message: 'Please select Region for API Gatway',
      choices: [ 'us-east-1', 'ap-northeast-1', 'us-west-2', 'eu-west-1', 'eu-central-1' ]
    }

    this.apiName = {
      type   : 'list',
      name   : 'id',
      message: 'Please input API Name',
      choices: []
    }

    this.stageSelect = {
      type   : 'list',
      name   : 'stageSelect',
      message: 'Do you want to use an existing Stage or create a new one?',
      choices: [ 'Existing Stage', 'Create A New Stage' ]
    }

    this.listStageName = {
      type   : 'list',
      name   : 'stageName',
      message: 'Please select target Stage',
      choices: []
    }

    this.inputStageName = {
      type   : 'input',
      name   : 'stageName',
      message: 'Please input Stage Name'
    }
  }
}
module.exports.question = Question

class ApiGateway {
  constructor(region) {
    this.region = region

    aws.config.update({region:region})
    this.apigateway = new aws.APIGateway({apiVersion: '2015-07-09'})
  }

  getApiList() {
    let params = {}

    return this.apigateway.getRestApis(params).promise().then(function(res) {
      let selected = []
      res.items.forEach(function(f){
        selected.push({name:f.name,value:f.id})
      })
      return selected
    })
  }

  getStageList(apiId) {
    let params = {
      restApiId: apiId
    }
    return this.apigateway.getStages(params).promise().then(function(res) {
      let selected = []
      res.item.forEach(function(f){
        selected.push(f.stageName)
      })
      return selected
    })
  }

  isStages(apiId) {
    let params = {
      restApiId: apiId
    }
    return this.apigateway.getStages(params).promise().then(function(res) {
      if (res.item.length > 0) {
        return true
      } else {
        return false
      }
    })
  }

  createDeployment(apiId, stageName) {
    let params = {
      restApiId: apiId,
      stageName: stageName
    }
    return this.apigateway.createDeployment(params).promise()
  }
}
module.exports.apigateway = ApiGateway

module.exports.action = function() {
  let q = new Question(),
      apigw,
      apiId,
      stageName

  inquirer.prompt([q.region]).then(function(answers) {
    apigw = new ApiGateway(answers.region)
  }).then(function() {
    return apigw.getApiList()
  }).then(function(res) {
    q.apiName.choices = res
    return inquirer.prompt([q.apiName])
  }).then(function(answers) {
    apiId = answers.id
    return apigw.isStages(apiId)
  }).then(function(isStages) {
    if (isStages) {
      return inquirer.prompt([q.stageSelect]).then(function(answers){
        if (answers.stageSelect === 'Existing Stage') {
          return apigw.getStageList(apiId).then(function(res){
            q.listStageName.choices = res
            return inquirer.prompt([q.listStageName])
          }).then(function(answers){
            stageName = answers.stageName
          })
        } else {
          return inquirer.prompt(q.inputStageName).then(function(answers){
            stageName = answers.stageName
          })
        }
      })
    } else {
      return inquirer.prompt(aq.inputStageName).then(function(answers){
        stageName = answers.stageName
      })
    }
  }).then(function() {
    return apigw.createDeployment(apiId, stageName)
  }).then(function(res) {
    console.log('Deploy success! Endpoint:https://'+apiId+'.execute-api.'+apigw.region+'.amazonaws.com/'+stageName)
  }).catch(function rejected(err) {
    console.log('error:', err.stack)
  })
}
<commit_msg>some fix<commit_after>'use strict';

var inquirer  = require('inquirer'),
    aws       = require('aws-sdk')

class Question {
  constructor(region) {

    this.region = {
      type   : 'list',
      name   : 'region',
      message: 'Please select Region for API Gatway',
      choices: [ 'us-east-1', 'ap-northeast-1', 'us-west-2', 'eu-west-1', 'eu-central-1' ]
    }

    this.apiName = {
      type   : 'list',
      name   : 'id',
      message: 'Please input API Name',
      choices: []
    }

    this.stageSelect = {
      type   : 'list',
      name   : 'stageSelect',
      message: 'Do you want to use an existing Stage or create a new one?',
      choices: [ 'Existing Stage', 'Create A New Stage' ]
    }

    this.listStageName = {
      type   : 'list',
      name   : 'stageName',
      message: 'Please select target Stage',
      choices: []
    }

    this.inputStageName = {
      type   : 'input',
      name   : 'stageName',
      message: 'Please input Stage Name'
    }
  }
}
module.exports.question = Question

class ApiGateway {
  constructor(region) {
    this.region = region

    aws.config.update({region:region})
    this.apigateway = new aws.APIGateway({apiVersion: '2015-07-09'})
  }

  getApiList() {
    let params = {}

    return this.apigateway.getRestApis(params).promise().then(function(res) {
      let selected = []
      res.items.forEach(function(f){
        selected.push({name:f.name,value:f.id})
      })
      return selected
    })
  }

  getStageList(apiId) {
    let params = {
      restApiId: apiId
    }
    return this.apigateway.getStages(params).promise().then(function(res) {
      let selected = []
      res.item.forEach(function(f){
        selected.push(f.stageName)
      })
      return selected
    })
  }

  isStages(apiId) {
    let params = {
      restApiId: apiId
    }
    return this.apigateway.getStages(params).promise().then(function(res) {
      if (res.item.length > 0) {
        return true
      } else {
        return false
      }
    })
  }

  createDeployment(apiId, stageName) {
    let params = {
      restApiId: apiId,
      stageName: stageName
    }
    return this.apigateway.createDeployment(params).promise()
  }
}
module.exports.apigateway = ApiGateway

module.exports.action = function() {
  let q = new Question(),
      apigw,
      apiId,
      stageName

  inquirer.prompt([q.region]).then(function(answers) {
    apigw = new ApiGateway(answers.region)
  }).then(function() {
    return apigw.getApiList()
  }).then(function(res) {
    q.apiName.choices = res
    return inquirer.prompt([q.apiName])
  }).then(function(answers) {
    apiId = answers.id
    return apigw.isStages(apiId)
  }).then(function(isStages) {
    if (isStages) {
      return inquirer.prompt([q.stageSelect]).then(function(answers){
        if (answers.stageSelect === 'Existing Stage') {
          return apigw.getStageList(apiId).then(function(res){
            q.listStageName.choices = res
            return inquirer.prompt([q.listStageName])
          }).then(function(answers){
            stageName = answers.stageName
          })
        } else {
          return inquirer.prompt(q.inputStageName).then(function(answers){
            stageName = answers.stageName
          })
        }
      })
    } else {
      return inquirer.prompt(q.inputStageName).then(function(answers){
        stageName = answers.stageName
      })
    }
  }).then(function() {
    return apigw.createDeployment(apiId, stageName)
  }).then(function(res) {
    console.log('Deploy success! Endpoint:https://'+apiId+'.execute-api.'+apigw.region+'.amazonaws.com/'+stageName)
  }).catch(function rejected(err) {
    console.log('error:', err.stack)
  })
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

var log = require('npmlog')
  , path = require('path')
  , fs = require('vigour-fs-promised')
  , configPath = path.join(__dirname, '..', 'config.json');

fs.editJSONAsync( configPath, editJSON, { space: 4 } )
  .then(function(){
    log.info('gaston', 'config[\'base-path\'] set to your home directory');
  })

function editJSON(obj){
  obj['base-path'] = process.env.HOME || process.env.USERPROFILE;
  return obj;
}<commit_msg>post-install now CREATES config/gaston.json if it does not exist<commit_after>#!/usr/bin/env node

var log = require('npmlog')
  , path = require('path')
  , fs = require('vigour-fs-promised')
  , configPath = path.join(__dirname, '..', 'config/gaston.json')
  , initialConfig = {
    "http-port": 8080,
    "api-port": 64571,
    "base-path": process.env.HOME || process.env.USERPROFILE
  };

fs.existsAsync( configPath )
  .then(function(exists){
    if(!exists){
      fs.writeJSONAsync( configPath, initialConfig, { space: 2 } );
    }
  });<|endoftext|>