<commit_before>import React from 'react';
import { shallow } from 'enzyme';
import addUrlProps from '../addUrlProps';
import UrlQueryParamTypes from '../../UrlQueryParamTypes';
import UrlUpdateTypes from '../../UrlUpdateTypes';
import urlQueryConfig from '../../urlQueryConfig';
import configureUrlQuery from '../../configureUrlQuery';

const defaultUrlQueryConfig = { ...urlQueryConfig };

const MyComponent = () => <div />;

beforeEach(() => {
  configureUrlQuery({ ...defaultUrlQueryConfig });
});

describe('url query params as props', () => {
  it('passes URL query parameters through', () => {
    const location = { query: { foo: '94', bar: 'baz' } };

    const Wrapped = addUrlProps()(MyComponent);
    const wrapper = shallow(<Wrapped location={location} otherProp foo={1000} />);
    const props = wrapper.first().props(); // this only works when using `shallow` not `mount`

    expect(props.otherProp).toBe(true);
    expect(props.location).toBe(location);
    expect(props.foo).toBe('94');
    expect(props.bar).toBe('baz');
  });

  it('decodes URL query params as props based on config', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number, queryParam: 'fooInUrl' },
      bar: { type: UrlQueryParamTypes.string },
    };

    const Wrapped = addUrlProps({ urlPropsQueryConfig })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();

    expect(props.location).toBe(location);
    expect(props.foo).toBe(94);
    expect(props.bar).toBe('baz');
  });

  it('mapUrlToProps updates url query params as props', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };
    function mapUrlToProps(url) {
      return {
        foo: parseInt(url.fooInUrl, 10),
        bar: url.bar,
      };
    }

    const Wrapped = addUrlProps({ mapUrlToProps })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();

    expect(props.location).toBe(location);
    expect(props.foo).toBe(94);
    expect(props.bar).toBe('baz');
  });

  it('mapUrlToProps given decoded URL params if config also passed', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number, queryParam: 'fooInUrl' },
      bar: { type: UrlQueryParamTypes.string },
    };

    function mapUrlToProps(url) {
      return {
        foo: url.foo * 100,
        bar: url.bar,
      };
    }

    const Wrapped = addUrlProps({ mapUrlToProps, urlPropsQueryConfig })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();

    expect(props.location).toBe(location);
    expect(props.foo).toBe(9400);
    expect(props.bar).toBe('baz');
  });

  it('reads query params from urlQueryConfig.history.location', () => {
    const location = { query: { foo: '94', bar: 'baz' } };

    const Wrapped = addUrlProps()(MyComponent);

    // set the history to have our location in it. Configure the history after
    // the Wrapped component is defined as that is likely how it will happen
    // in applications due to the way imports are resolved.
    configureUrlQuery({ history: { location } });

    const wrapper = shallow(<Wrapped />);
    const props = wrapper.first().props();

    expect(props.foo).toBe('94');
    expect(props.bar).toBe('baz');
  });

  // TODO: would be nice to test for reading from window.location
  // but https://github.com/facebook/jest/issues/890
});

describe('adds router params', () => {
  it('url props includes props.params if addRouterParams is true', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };

    const Wrapped = addUrlProps({ addRouterParams: true })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} params={{ word: 'test' }} />);
    const props = wrapper.first().props();

    expect(props.word).toBe('test');
  });

  it('url props does not include props.params if addRouterParams is false', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };

    const Wrapped = addUrlProps({ addRouterParams: false })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} params={{ word: 'test' }} />);
    const props = wrapper.first().props();

    expect(props.word).not.toBeDefined();
  });

  it('reads addRouterParams from urlQueryConfig dynamically', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };

    // set to true before creating component
    configureUrlQuery({ addRouterParams: true });

    const Wrapped = addUrlProps()(MyComponent);

    // update global config to be false after creating component, before rendering
    configureUrlQuery({ addRouterParams: false });

    const wrapper = shallow(<Wrapped location={location} params={{ word: 'test' }} />);
    const props = wrapper.first().props();

    expect(props.word).not.toBeDefined();
  });
});

describe('url change callbacks', () => {
  it('generates change handlers based on config', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number, queryParam: 'fooInUrl' },
      bar: { type: UrlQueryParamTypes.string },
    };

    const Wrapped = addUrlProps({ urlPropsQueryConfig, addUrlChangeHandlers: true })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();

    expect(props.onChangeFoo).toBeDefined();
    expect(props.onChangeBar).toBeDefined();
  });

  it('does not generate change handlers when addUrlChangeHandlers is false', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number, queryParam: 'fooInUrl' },
      bar: { type: UrlQueryParamTypes.string },
    };

    const Wrapped = addUrlProps({ urlPropsQueryConfig, addUrlChangeHandlers: false })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();

    expect(props.onChangeFoo).not.toBeDefined();
    expect(props.onChangeBar).not.toBeDefined();
  });

  it('reads addUrlChangeHandlers from urlQueryConfig', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number, queryParam: 'fooInUrl' },
      bar: { type: UrlQueryParamTypes.string },
    };

    configureUrlQuery({ addUrlChangeHandlers: false });

    const Wrapped = addUrlProps({ urlPropsQueryConfig })(MyComponent);

    configureUrlQuery({ addUrlChangeHandlers: true });

    let wrapper = shallow(<Wrapped location={location} />);
    let props = wrapper.first().props();

    expect(props.onChangeFoo).toBeDefined();
    expect(props.onChangeBar).toBeDefined();

    configureUrlQuery({ addUrlChangeHandlers: false });

    wrapper = shallow(<Wrapped location={location} />);
    props = wrapper.first().props();

    expect(props.onChangeFoo).not.toBeDefined();
    expect(props.onChangeBar).not.toBeDefined();
  });

  it('generated change handlers have name configured by changeHandlerName', () => {
    configureUrlQuery({ addUrlChangeHandlers: true });

    const location = { query: { fooInUrl: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number, queryParam: 'fooInUrl' },
      bar: { type: UrlQueryParamTypes.string },
    };
    const changeHandlerName = propName => `handle_${propName}`;

    const Wrapped = addUrlProps({ urlPropsQueryConfig, changeHandlerName })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();

    expect(props.handle_foo).toBeDefined();
    expect(props.handle_bar).toBeDefined();
  });

  it('generated change handlers have name configured by changeHandlerName in urlQueryConfig', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number, queryParam: 'fooInUrl' },
      bar: { type: UrlQueryParamTypes.string },
    };
    const changeHandlerName = propName => `handle_${propName}`;

    const Wrapped = addUrlProps({ urlPropsQueryConfig })(MyComponent);

    configureUrlQuery({ addUrlChangeHandlers: true, changeHandlerName });

    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();

    expect(props.handle_foo).toBeDefined();
    expect(props.handle_bar).toBeDefined();
  });

  it('mapUrlChangeHandlersToProps adds props', () => {
    const location = { query: { foo: '94', bar: 'baz' } };

    function onChangeFoo(foo) {
      return foo;
    }

    function mapUrlChangeHandlersToProps() {
      return {
        onChangeFoo,
      };
    }

    const Wrapped = addUrlProps({ mapUrlChangeHandlersToProps })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();

    expect(props.onChangeFoo).toBe(onChangeFoo);
    expect(props.onChangeBar).not.toBeDefined();

    props.onChangeFoo(123);
  });

  it('mapUrlChangeHandlersToProps can access generated handlers', () => {
    const location = { query: { foo: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number },
      bar: { type: UrlQueryParamTypes.string },
    };
    const onChangeFoo = foo => foo;

    function mapUrlChangeHandlersToProps(props, handlers) {
      return {
        onChangeFoo,
        onChangeBar: handlers.onChangeBar,
      };
    }

    const Wrapped = addUrlProps({
      urlPropsQueryConfig,
      mapUrlChangeHandlersToProps,
      addUrlChangeHandlers: true,
    })(MyComponent);

    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();

    expect(props.onChangeFoo).toBe(onChangeFoo);
    expect(props.onChangeBar).toBeDefined();
  });

  it('generated change handlers are only generated once, not every render', () => {
    const location = { query: { foo: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number },
      bar: { type: UrlQueryParamTypes.string },
    };

    const Wrapped = addUrlProps({ urlPropsQueryConfig, addUrlChangeHandlers: true })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();
    const { onChangeFoo, onChangeBar } = props;

    // cause a re-render
    wrapper.setProps({ baz: 123 });

    const newProps = wrapper.first().props();
    expect(newProps.onChangeFoo).toBe(onChangeFoo);
    expect(newProps.onChangeBar).toBe(onChangeBar);
  });

  it('generated change handlers encode values properly and interpret updateType', () => {
    const location = { query: { foo: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number },
      bar: { type: UrlQueryParamTypes.string, updateType: UrlUpdateTypes.pushIn },
    };

    // make the history just return the new location so we can test for logging
    const history = {
      replace: jest.fn().mockImplementation(d => d),
      push: jest.fn().mockImplementation(d => d),
    };

    configureUrlQuery({ history });

    const Wrapped = addUrlProps({
      urlPropsQueryConfig,
      addUrlChangeHandlers: true,
    })(MyComponent);

    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();
    const { onChangeFoo, onChangeBar } = props;

    const fooChangeResult = onChangeFoo(123);
    expect(history.replace).toBeCalled();
    expect(history.push).not.toBeCalled();
    expect(fooChangeResult).toEqual({ query: { foo: '123', bar: 'baz' } });

    const barChangeResult = onChangeBar('new-bar');
    expect(history.push).toBeCalled();
    expect(barChangeResult).toEqual({ query: { foo: '94', bar: 'new-bar' } });
  });

  it('generated change handlers to read location dynamically from props', () => {
    const location = { query: { foo: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number },
      bar: { type: UrlQueryParamTypes.string, updateType: UrlUpdateTypes.pushIn },
    };

    // make the history just return the new location so we can test for logging
    const history = {
      replace: jest.fn().mockImplementation(d => d),
      push: jest.fn().mockImplementation(d => d),
    };

    configureUrlQuery({ history });

    const Wrapped = addUrlProps({
      urlPropsQueryConfig,
      addUrlChangeHandlers: true,
    })(MyComponent);

    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();
    const { onChangeFoo, onChangeBar } = props;

    // update the prop location
    const location2 = { query: { foo: '1000', bar: 'BAR' } };
    wrapper.setProps({ location: location2 });

    const fooChangeResult = onChangeFoo(123);
    expect(fooChangeResult).toEqual({ query: { foo: '123', bar: 'BAR' } });

    const barChangeResult = onChangeBar('new-bar');
    expect(barChangeResult).toEqual({ query: { foo: '1000', bar: 'new-bar' } });
  });
});
<commit_msg>Add test for checking if URL needs to update<commit_after>import React from 'react';
import { shallow } from 'enzyme';
import addUrlProps from '../addUrlProps';
import UrlQueryParamTypes from '../../UrlQueryParamTypes';
import UrlUpdateTypes from '../../UrlUpdateTypes';
import urlQueryConfig from '../../urlQueryConfig';
import configureUrlQuery from '../../configureUrlQuery';

const defaultUrlQueryConfig = { ...urlQueryConfig };

const MyComponent = () => <div />;

beforeEach(() => {
  configureUrlQuery({ ...defaultUrlQueryConfig });
});

describe('url query params as props', () => {
  it('passes URL query parameters through', () => {
    const location = { query: { foo: '94', bar: 'baz' } };

    const Wrapped = addUrlProps()(MyComponent);
    const wrapper = shallow(<Wrapped location={location} otherProp foo={1000} />);
    const props = wrapper.first().props(); // this only works when using `shallow` not `mount`

    expect(props.otherProp).toBe(true);
    expect(props.location).toBe(location);
    expect(props.foo).toBe('94');
    expect(props.bar).toBe('baz');
  });

  it('decodes URL query params as props based on config', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number, queryParam: 'fooInUrl' },
      bar: { type: UrlQueryParamTypes.string },
    };

    const Wrapped = addUrlProps({ urlPropsQueryConfig })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();

    expect(props.location).toBe(location);
    expect(props.foo).toBe(94);
    expect(props.bar).toBe('baz');
  });

  it('mapUrlToProps updates url query params as props', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };
    function mapUrlToProps(url) {
      return {
        foo: parseInt(url.fooInUrl, 10),
        bar: url.bar,
      };
    }

    const Wrapped = addUrlProps({ mapUrlToProps })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();

    expect(props.location).toBe(location);
    expect(props.foo).toBe(94);
    expect(props.bar).toBe('baz');
  });

  it('mapUrlToProps given decoded URL params if config also passed', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number, queryParam: 'fooInUrl' },
      bar: { type: UrlQueryParamTypes.string },
    };

    function mapUrlToProps(url) {
      return {
        foo: url.foo * 100,
        bar: url.bar,
      };
    }

    const Wrapped = addUrlProps({ mapUrlToProps, urlPropsQueryConfig })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();

    expect(props.location).toBe(location);
    expect(props.foo).toBe(9400);
    expect(props.bar).toBe('baz');
  });

  it('reads query params from urlQueryConfig.history.location', () => {
    const location = { query: { foo: '94', bar: 'baz' } };

    const Wrapped = addUrlProps()(MyComponent);

    // set the history to have our location in it. Configure the history after
    // the Wrapped component is defined as that is likely how it will happen
    // in applications due to the way imports are resolved.
    configureUrlQuery({ history: { location } });

    const wrapper = shallow(<Wrapped />);
    const props = wrapper.first().props();

    expect(props.foo).toBe('94');
    expect(props.bar).toBe('baz');
  });

  // TODO: would be nice to test for reading from window.location
  // but https://github.com/facebook/jest/issues/890
});

describe('adds router params', () => {
  it('url props includes props.params if addRouterParams is true', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };

    const Wrapped = addUrlProps({ addRouterParams: true })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} params={{ word: 'test' }} />);
    const props = wrapper.first().props();

    expect(props.word).toBe('test');
  });

  it('url props does not include props.params if addRouterParams is false', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };

    const Wrapped = addUrlProps({ addRouterParams: false })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} params={{ word: 'test' }} />);
    const props = wrapper.first().props();

    expect(props.word).not.toBeDefined();
  });

  it('reads addRouterParams from urlQueryConfig dynamically', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };

    // set to true before creating component
    configureUrlQuery({ addRouterParams: true });

    const Wrapped = addUrlProps()(MyComponent);

    // update global config to be false after creating component, before rendering
    configureUrlQuery({ addRouterParams: false });

    const wrapper = shallow(<Wrapped location={location} params={{ word: 'test' }} />);
    const props = wrapper.first().props();

    expect(props.word).not.toBeDefined();
  });
});

describe('url change callbacks', () => {
  it('generates change handlers based on config', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number, queryParam: 'fooInUrl' },
      bar: { type: UrlQueryParamTypes.string },
    };

    const Wrapped = addUrlProps({ urlPropsQueryConfig, addUrlChangeHandlers: true })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();

    expect(props.onChangeFoo).toBeDefined();
    expect(props.onChangeBar).toBeDefined();
  });

  it('does not generate change handlers when addUrlChangeHandlers is false', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number, queryParam: 'fooInUrl' },
      bar: { type: UrlQueryParamTypes.string },
    };

    const Wrapped = addUrlProps({ urlPropsQueryConfig, addUrlChangeHandlers: false })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();

    expect(props.onChangeFoo).not.toBeDefined();
    expect(props.onChangeBar).not.toBeDefined();
  });

  it('reads addUrlChangeHandlers from urlQueryConfig', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number, queryParam: 'fooInUrl' },
      bar: { type: UrlQueryParamTypes.string },
    };

    configureUrlQuery({ addUrlChangeHandlers: false });

    const Wrapped = addUrlProps({ urlPropsQueryConfig })(MyComponent);

    configureUrlQuery({ addUrlChangeHandlers: true });

    let wrapper = shallow(<Wrapped location={location} />);
    let props = wrapper.first().props();

    expect(props.onChangeFoo).toBeDefined();
    expect(props.onChangeBar).toBeDefined();

    configureUrlQuery({ addUrlChangeHandlers: false });

    wrapper = shallow(<Wrapped location={location} />);
    props = wrapper.first().props();

    expect(props.onChangeFoo).not.toBeDefined();
    expect(props.onChangeBar).not.toBeDefined();
  });

  it('generated change handlers have name configured by changeHandlerName', () => {
    configureUrlQuery({ addUrlChangeHandlers: true });

    const location = { query: { fooInUrl: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number, queryParam: 'fooInUrl' },
      bar: { type: UrlQueryParamTypes.string },
    };
    const changeHandlerName = propName => `handle_${propName}`;

    const Wrapped = addUrlProps({ urlPropsQueryConfig, changeHandlerName })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();

    expect(props.handle_foo).toBeDefined();
    expect(props.handle_bar).toBeDefined();
  });

  it('generated change handlers have name configured by changeHandlerName in urlQueryConfig', () => {
    const location = { query: { fooInUrl: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number, queryParam: 'fooInUrl' },
      bar: { type: UrlQueryParamTypes.string },
    };
    const changeHandlerName = propName => `handle_${propName}`;

    const Wrapped = addUrlProps({ urlPropsQueryConfig })(MyComponent);

    configureUrlQuery({ addUrlChangeHandlers: true, changeHandlerName });

    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();

    expect(props.handle_foo).toBeDefined();
    expect(props.handle_bar).toBeDefined();
  });

  it('mapUrlChangeHandlersToProps adds props', () => {
    const location = { query: { foo: '94', bar: 'baz' } };

    function onChangeFoo(foo) {
      return foo;
    }

    function mapUrlChangeHandlersToProps() {
      return {
        onChangeFoo,
      };
    }

    const Wrapped = addUrlProps({ mapUrlChangeHandlersToProps })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();

    expect(props.onChangeFoo).toBe(onChangeFoo);
    expect(props.onChangeBar).not.toBeDefined();

    props.onChangeFoo(123);
  });

  it('mapUrlChangeHandlersToProps can access generated handlers', () => {
    const location = { query: { foo: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number },
      bar: { type: UrlQueryParamTypes.string },
    };
    const onChangeFoo = foo => foo;

    function mapUrlChangeHandlersToProps(props, handlers) {
      return {
        onChangeFoo,
        onChangeBar: handlers.onChangeBar,
      };
    }

    const Wrapped = addUrlProps({
      urlPropsQueryConfig,
      mapUrlChangeHandlersToProps,
      addUrlChangeHandlers: true,
    })(MyComponent);

    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();

    expect(props.onChangeFoo).toBe(onChangeFoo);
    expect(props.onChangeBar).toBeDefined();
  });

  it('generated change handlers are only generated once, not every render', () => {
    const location = { query: { foo: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number },
      bar: { type: UrlQueryParamTypes.string },
    };

    const Wrapped = addUrlProps({ urlPropsQueryConfig, addUrlChangeHandlers: true })(MyComponent);
    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();
    const { onChangeFoo, onChangeBar } = props;

    // cause a re-render
    wrapper.setProps({ baz: 123 });

    const newProps = wrapper.first().props();
    expect(newProps.onChangeFoo).toBe(onChangeFoo);
    expect(newProps.onChangeBar).toBe(onChangeBar);
  });

  it('generated change handlers encode values properly and interpret updateType', () => {
    const location = { query: { foo: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number },
      bar: { type: UrlQueryParamTypes.string, updateType: UrlUpdateTypes.pushIn },
    };

    // make the history just return the new location so we can test for logging
    const history = {
      replace: jest.fn().mockImplementation(d => d),
      push: jest.fn().mockImplementation(d => d),
    };

    configureUrlQuery({ history });

    const Wrapped = addUrlProps({
      urlPropsQueryConfig,
      addUrlChangeHandlers: true,
    })(MyComponent);

    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();
    const { onChangeFoo, onChangeBar } = props;

    const fooChangeResult = onChangeFoo(123);
    expect(history.replace).toBeCalled();
    expect(history.push).not.toBeCalled();
    expect(fooChangeResult).toEqual({ query: { foo: '123', bar: 'baz' } });

    const barChangeResult = onChangeBar('new-bar');
    expect(history.push).toBeCalled();
    expect(barChangeResult).toEqual({ query: { foo: '94', bar: 'new-bar' } });
  });

  it('generated change handlers to read location dynamically from props', () => {
    const location = { query: { foo: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number },
      bar: { type: UrlQueryParamTypes.string, updateType: UrlUpdateTypes.pushIn },
    };

    // make the history just return the new location so we can test for logging
    const history = {
      replace: jest.fn().mockImplementation(d => d),
      push: jest.fn().mockImplementation(d => d),
    };

    configureUrlQuery({ history });

    const Wrapped = addUrlProps({
      urlPropsQueryConfig,
      addUrlChangeHandlers: true,
    })(MyComponent);

    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();
    const { onChangeFoo, onChangeBar } = props;

    // update the prop location
    const location2 = { query: { foo: '1000', bar: 'BAR' } };
    wrapper.setProps({ location: location2 });

    const fooChangeResult = onChangeFoo(123);
    expect(fooChangeResult).toEqual({ query: { foo: '123', bar: 'BAR' } });

    const barChangeResult = onChangeBar('new-bar');
    expect(barChangeResult).toEqual({ query: { foo: '1000', bar: 'new-bar' } });
  });

  it('generated change handlers do not update if the URL is the same', () => {
    const location = { query: { foo: '94', bar: 'baz' } };
    const urlPropsQueryConfig = {
      foo: { type: UrlQueryParamTypes.number },
      bar: { type: UrlQueryParamTypes.string, updateType: UrlUpdateTypes.pushIn },
    };

    // make the history just return the new location so we can test for logging
    const history = {
      replace: jest.fn().mockImplementation(d => d),
      push: jest.fn().mockImplementation(d => d),
    };

    configureUrlQuery({ history });

    const Wrapped = addUrlProps({
      urlPropsQueryConfig,
      addUrlChangeHandlers: true,
    })(MyComponent);

    const wrapper = shallow(<Wrapped location={location} />);
    const props = wrapper.first().props();
    const { onChangeFoo, onChangeBar } = props;

    onChangeFoo(94);
    expect(history.replace).not.toBeCalled();

    onChangeBar('baz');
    expect(history.push).not.toBeCalled();
  });
});
<|endoftext|>


<commit_before>var httpreq = require ('httpreq');
var config = {
  timeout: 5000
};

function talk (method, path, props, callback) {
  var options = {
    url: 'http://requestb.in/api/v1/' + path,
    method: method,
    parameters: props,
    timeout: config.timeout || 5000,
    headers: {
      'User-Agent': 'requestbin.js (https://www.npmpjs.com/package/requestbin)',
      Accept: 'application/json'
    }
  };

  if (typeof props === 'function') {
    callback = props;
    props = {};
  }

  httpreq.doRequest (options, function (err, res) {
    var data = res && res.body || null;
    var error = null;

    if (err) {
      error = new Error ('request failed');
      error.error = err;
      callback (error);
      return;
    }

    if (res && res.statusCode >= 300) {
      error = new Error ('HTTP error');
      return;
    }

    try {
      data = JSON.parse (data);
    } catch (e) {
      error = new Error ('invalid response');
    }

    if (error) {
      error.httpCode = res.statusCode;
      error.request = options;
      error.response = {
        headers: res.headers,
        body: data
      };
      callback (error);
      return;
    }

    callback (null, data);
  });
}

module.exports = {
  config: function (name, val) {
    config [name] = val;
  },

  create: function (isPrivate, callback) {
    var props = {};

    if (typeof isPrivate === 'function') {
      callback = isPrivate;
    } else if (isPrivate === true) {
      props.private = 'true';
    }

    talk ('POST', 'bins', props, callback);
  },

  get: function (bin, callback) {
    talk ('GET', 'bins/' + bin, callback);
  },

  requests: function (bin, callback) {
    talk ('GET', 'bins/' + bin + '/requests', callback);
  },

  request: function (bin, request, callback) {
    talk ('GET', 'bins/' + bin + '/requests/' + request, callback);
  }
};
<commit_msg>Make sure timeout is an integer<commit_after>var httpreq = require ('httpreq');
var config = {
  timeout: 5000
};

function talk (method, path, props, callback) {
  var options = {
    url: 'http://requestb.in/api/v1/' + path,
    method: method,
    parameters: props,
    timeout: parseInt (config.timeout, 10) || 5000,
    headers: {
      'User-Agent': 'requestbin.js (https://www.npmpjs.com/package/requestbin)',
      Accept: 'application/json'
    }
  };

  if (typeof props === 'function') {
    callback = props;
    props = {};
  }

  httpreq.doRequest (options, function (err, res) {
    var data = res && res.body || null;
    var error = null;

    if (err) {
      error = new Error ('request failed');
      error.error = err;
      callback (error);
      return;
    }

    if (res && res.statusCode >= 300) {
      error = new Error ('HTTP error');
      return;
    }

    try {
      data = JSON.parse (data);
    } catch (e) {
      error = new Error ('invalid response');
    }

    if (error) {
      error.httpCode = res.statusCode;
      error.request = options;
      error.response = {
        headers: res.headers,
        body: data
      };
      callback (error);
      return;
    }

    callback (null, data);
  });
}

module.exports = {
  config: function (name, val) {
    config [name] = val;
  },

  create: function (isPrivate, callback) {
    var props = {};

    if (typeof isPrivate === 'function') {
      callback = isPrivate;
    } else if (isPrivate === true) {
      props.private = 'true';
    }

    talk ('POST', 'bins', props, callback);
  },

  get: function (bin, callback) {
    talk ('GET', 'bins/' + bin, callback);
  },

  requests: function (bin, callback) {
    talk ('GET', 'bins/' + bin + '/requests', callback);
  },

  request: function (bin, request, callback) {
    talk ('GET', 'bins/' + bin + '/requests/' + request, callback);
  }
};
<|endoftext|>


<commit_before>import {
  report,
  ruleMessages,
  styleSearch
} from "../../utils"

export const ruleName = "color-no-invalid-hex"

export const messages = ruleMessages(ruleName, {
  rejected: c => `Unexpected invalid hex color "${c}"`,
})

export default function () {
  return function (root, result) {
    root.eachDecl(function (decl) {
      const value = decl.value

      styleSearch({ source: value, target: "#" }, match => {

        const hexValue = /^#[0-9A-Za-z]+/.exec(value.substr(match.startIndex))[0]

        if (!/^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(hexValue)) {
          report({
            message: messages.rejected(hexValue),
            node: decl,
            result,
            ruleName,
          })
        }
      })
    })
  }
}
<commit_msg>Use standardised rule syntax<commit_after>import {
  report,
  ruleMessages,
  styleSearch
} from "../../utils"

export const ruleName = "color-no-invalid-hex"

export const messages = ruleMessages(ruleName, {
  rejected: c => `Unexpected invalid hex color "${c}"`,
})

export default function () {
  return (root, result) => {
    root.eachDecl(decl => {
      const value = decl.value

      styleSearch({ source: value, target: "#" }, match => {

        const hexValue = /^#[0-9A-Za-z]+/.exec(value.substr(match.startIndex))[0]

        if (!/^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(hexValue)) {
          report({
            message: messages.rejected(hexValue),
            node: decl,
            result,
            ruleName,
          })
        }
      })
    })
  }
}
<|endoftext|>


<commit_before>import React,{PropType,Component} from 'react';
import { connect } from 'dva';
import Form from "jw-form/dist/mobile";
import { createForm } from 'rc-form';
import async from "../../utils/formFetch";

class Schema extends React.Component {
  constructor(props) {
    super(props);
    let self = this;
    let schema = this.props.schema;
    let _schema = [];

    if(schema[0].element == "Section"){

      for(let i in schema){
        if(schema[i].label != "" || schema[i].logo != ""){
          _schema.push({
            name: schema[i].name,
            alias: schema[i].alias,
            element: schema[i].element,
            hidden: schema[i].hidden,
            isAdd: schema[i].isAdd,
            isPage: schema[i].isPage,
            label: schema[i].label,
            logo: schema[i].logo,
          })
        }
        for(let m in schema[i].schema){
          _schema.push(schema[i].schema[m])
        }
      }
    }else{
      _schema = schema;
    }
    this.state = {
      formData:{
        schema: _schema,
        changeData: function(i, item, value){
          self.props.events.trigger('formChange:'+item.name, i, item, value);
        }
      }
    };
  }

  componentWillMount(){
    // alert(1);
    let self = this;
    let schema = [];
    for(let i in self.state.formData.schema){
      switch(self.state.formData.schema[i].element){
        case "Input":
          schema[i] = self._input(self.state.formData.schema[i])
          if(self.state.formData.schema[i].parents && self.state.formData.schema[i].parents.length > 0 && self.state.formData.schema[i].url){
            for(let m in self.state.formData.schema[i].parents){
              self.props.events.on('formChange:'+self.state.formData.schema[i].parents[m], function(formData){
                let flag = true;
                let parms = {};
                for(let n in self.state.formData.schema[i].parents){
                  for(let x in formData){
                    if(formData[x].name == self.state.formData.schema[i].parents[n]){
                      if(formData[x].defaultValue == "" || formData[x].defaultValue == []){
                        flag = false;
                      }else{
                        parms[formData[x].name] = formData[x].defaultValue
                      }
                    }
                  }
                }
                self.fetchDataInput(parms, self.state.formData.schema[i]);
              });
            }
          }else if(self.state.formData.schema[i].parents && self.state.formData.schema[i].parents.length > 0 && !self.state.formData.schema[i].url){

            for(let m in self.state.formData.schema[i].parents){
              self.props.events.on('formChange:'+self.state.formData.schema[i].parents[m], function(formData, schema, value){
                self.setValue(value, self.state.formData.schema[i]);
              })
            }

          }

          break;
        case "Select":
          schema[i] = self._select(self.state.formData.schema[i])
          if(self.state.formData.schema[i].parents && self.state.formData.schema[i].parents.length > 0){
            for(let m in self.state.formData.schema[i].parents){
              self.props.events.on('formChange:'+self.state.formData.schema[i].parents[m], function(formData){
                let flag = true;
                let parms = {};
                for(let n in self.state.formData.schema[i].parents){
                  for(let x in formData){
                    if(formData[x].name == self.state.formData.schema[i].parents[n]){
                      if(formData[x].defaultValue == "" || formData[x].defaultValue == []){
                        flag = false;
                      }else{
                        parms[formData[x].name] = formData[x].defaultValue
                      }
                    }
                  }
                }
                self.fetchDataSelect(parms, self.state.formData.schema[i]);
              });
            }
          }
          break;
        case "DatePicker":
          schema[i] = self._datePicker(self.state.formData.schema[i]);
          break;
        case "Checkbox":
          schema[i] = self._checkbox(self.state.formData.schema[i]);
          break;
        case "Radio":
          schema[i] = self._radio(self.state.formData.schema[i]);
          break;
        case "Switch":
          schema[i] = self._switch(self.state.formData.schema[i]);
          break;
        case "Textarea":
          schema[i] = self._textarea(self.state.formData.schema[i]);
          break;
        case "Refill":
          schema[i] = self._refill(self.state.formData.schema[i]);
          self.props.events.on('formChange:'+self.state.formData.schema[i].name+"_refill", function(formData, schema){
            self.fetchDataRefill(self.state.formData.schema[i], schema.defaultValue);
          })
          break;
        default:
          schema[i] = self.state.formData.schema[i];
          break;
      }
    }
    self.state.formData.schema = schema;
    self.setState(self.state);

  }

  setValue(value, schema){
    let self = this;
    for(let i in self.state.formData.schema){
      if(self.state.formData.schema[i].name == schema.name){
          self.state.formData.schema[i].defaultValue = value[schema.subKey.split('.')[1]]
      }
    }
    self.setState(self.state);

  }

  fetchDataRefill(schema, value){

    let self = this;
    async(self._parse(schema.url)).then(function(data){
      for(let i in self.state.formData.schema){
        if(self.state.formData.schema[i].name == schema.name){
            self.state.formData.schema[i].dataList = data.data.list;
        }
      }
      self.setState(self.state);
    })

  }

  fetchDataSelect(parms, schema){

    let self = this;
    async(self._parse(schema.url)).then(function(data){
      for(let i in self.state.formData.schema){
        if(self.state.formData.schema[i].name == schema.name){
          let options = [];
          for(let m in data.data.list){
            options.push({
              label:data.data.list[m].key,
              value:data.data.list[m].value
            });
          }
          self.state.formData.schema[i].options = options;
        }
      }
      self.setState(self.state);
    })

  }

  fetchDataInput(parms, schema){
    let self = this;
    setTimeout(function(){
      async(self._parse(schema.url)).then(function(data){
        for(let i in self.state.formData.schema){
          if(self.state.formData.schema[i].name == schema.name){
            let setData = [];
            setData[schema.name] = data.data[self.state.formData.schema[i].subKey]
            self.state.formData.schema[i].defaultValue = data.data[self.state.formData.schema[i].subKey];
            self.state.formData.schema[i].attr = _.extend({value: data.data[self.state.formData.schema[i].subKey]}, self.state.formData.schema[i].attr);
            self.refs.formData.setFieldsValue(setData)
          }
        }
        self.setState(self.state);
      })
    })

  }

  _refill(item){

    let attrEle = [];
    let schema = {};
    let attr = {};
    for(var i in item){
      if(_.indexOf(attrEle, i) != -1){
        attr[i] = item[i];
      }else{
        schema[i] = item[i]
      }
    }
    schema.attr = attr;
    if(item.defaultValue == ""){
      schema.defaultValue = [];
    }

    let className = ["hidden"];
    if(item.hidden && item.hidden == 1){
      schema.className = schema.className+" hide";
    }

    return schema;

  }

  _checkbox(item){

    let attrEle = ["value", "disabled"];
    let schema = {};
    let attr = {};
    for(var i in item){
      if(_.indexOf(attrEle, i) != -1){
        attr[i] = item[i];
      }else{
        schema[i] = item[i]
      }
    }
    schema.attr = attr;
    if(item.defaultValue == ""){
      schema.defaultValue = [];
    }

    let className = ["hidden"];
    if(item.hidden && item.hidden == 1){
      schema.className = schema.className+" hide";
    }

    return schema;

  }

  _radio(item){

    let attrEle = ["value", "disabled"];
    let schema = {};
    let attr = {};
    for(var i in item){
      if(_.indexOf(attrEle, i) != -1){
        attr[i] = item[i];
      }else{
        schema[i] = item[i]
      }
    }
    schema.attr = attr;

    let className = ["hidden"];
    if(item.hidden && item.hidden == 1){
      schema.className = schema.className+" hide";
    }

    return schema;
  }

  _switch(item){
    let attrEle = ["value", "disabled"];
    let schema = {};
    let attr = {};
    for(var i in item){
      if(_.indexOf(attrEle, i) != -1){
        attr[i] = item[i];
      }else{
        schema[i] = item[i]
      }
    }
    schema.attr = attr;
    return schema;

  }

  _datePicker(item){
    let attrEle = ["disabled"];
    let className = ["hidden"];
    let schema = {};
    let attr = {};
    for(var i in item){
      if(_.indexOf(attrEle, i) != -1){
        attr[i] = item[i];
      }else{
        schema[i] = item[i]
      }
    }

    if(item.hidden && item.hidden == 1){
      schema.className = schema.className+" hide";
    }

    if(item.defaultValue === "0"){
      let now = Date.parse(new Date())/1000;
      let str = now+item.changeValue;
      schema.defaultValue = eval(str);
    }

    schema.attr = attr;
    schema.attr.format = (val) => val.format(item.format.replace("dd", "DD"));

    return schema;
  }

  _select(item){

    let attrEle = ["value", "placeholder", "disabled", "dropdownClassName", "cols"];
    let schema = {};
    let attr = {};
    for(var i in item){
      if(_.indexOf(attrEle, i) != -1){
        attr[i] = item[i];
      }else{
        schema[i] = item[i]
      }
    }
    schema.attr = attr;

    let className = ["hidden"];
    if(item.hidden && item.hidden == 1){
      schema.className = schema.className+" hide";
    }

    return schema;

  }

  //Input元素解析方法
  _textarea(item){

    let attrEle = ["value", "autoHeight", "placeholder", "disabled", "autosize", "rows"];
    let schema = {};
    let attr = {};
    for(var i in item){
      if(_.indexOf(attrEle, i) != -1){
        attr[i] = item[i];
      }else{
        schema[i] = item[i]
      }
    }
    schema.attr = attr;

    if(item.defaultValue && item.defaultValue != ""){
      schema.defaultValue = this._parse(item.defaultValue)
    }

    let className = ["hidden"];
    if(item.hidden && item.hidden == 1){
      schema.className = schema.className+" hide";
    }

    return schema;
  }

  //Input元素解析方法
  _input(item){

    let attrEle = ["value", "placeholder", "disabled"];
    let schema = {};
    let attr = {};
    for(var i in item){
      if(_.indexOf(attrEle, i) != -1){
        attr[i] = item[i];
      }else{
        schema[i] = item[i]
      }
    }
    schema.attr = attr;

    if(item.defaultValue && item.defaultValue != ""){
      schema.defaultValue = this._parse(item.defaultValue)
    }

    let className = ["hidden"];
    if(item.hidden && item.hidden == 1){
      schema.className = schema.className+" hide";
    }

    return schema;
  }

  //正则解析
  _parse(str){
    //
    let self = this;
    let flag = true;
    let myReg = /\{(.*?)\}/g;
    let res = str.match(myReg);

    for(let i in res){
      if(res[i].indexOf("jw.") != -1){
        str = str.replace(res[i], eval(res[i].replace("{", "").replace("}", "")));
      }else{
        let values = self.refs.formData.getFieldsValue();
        if(values[res[i].replace("{", "").replace("}", "")] == "" || !values[res[i].replace("{", "").replace("}", "")]){
          flag = false;
        }else{
          str = str.replace(res[i], values[res[i].replace("{", "").replace("}", "")])
        }
      }
    }
    if(flag){
      return str;
    }else{
      return false;
    }

  }

  render(){

    return(
        <div className="form-show-title">
          <Form formData={this.state.formData} ref="formData"/>
        </div>
      )
  }
  changeData(data){
    let dispatch = this.props.dispatch;
    dispatch({
      type:'form/changeData',
      data:{
        schema:data
      }
    })
  }
}
export default connect()(Schema);<commit_msg>日期修正YYYY到yyyy<commit_after>import React,{PropType,Component} from 'react';
import { connect } from 'dva';
import Form from "jw-form/dist/mobile";
import { createForm } from 'rc-form';
import async from "../../utils/formFetch";

class Schema extends React.Component {
  constructor(props) {
    super(props);
    let self = this;
    let schema = this.props.schema;
    let _schema = [];

    if(schema[0].element == "Section"){

      for(let i in schema){
        // if(schema[i].label != "" || schema[i].logo != ""){
          _schema.push({
            name: schema[i].name,
            alias: schema[i].alias,
            element: schema[i].element,
            hidden: schema[i].hidden,
            isAdd: schema[i].isAdd,
            isPage: schema[i].isPage,
            label: schema[i].label,
            logo: schema[i].logo,
          })
        // }
        for(let m in schema[i].schema){
          _schema.push(schema[i].schema[m])
        }
      }
    }else{
      _schema = schema;
    }
    this.state = {
      formData:{
        schema: _schema,
        changeData: function(i, item, value){
          self.props.events.trigger('formChange:'+item.name, i, item, value);
        }
      }
    };
  }

  componentWillMount(){
    // alert(1);
    let self = this;
    let schema = [];
    for(let i in self.state.formData.schema){
      switch(self.state.formData.schema[i].element){
        case "Input":
          schema[i] = self._input(self.state.formData.schema[i])
          if(self.state.formData.schema[i].parents && self.state.formData.schema[i].parents.length > 0 && self.state.formData.schema[i].url){
            for(let m in self.state.formData.schema[i].parents){
              self.props.events.on('formChange:'+self.state.formData.schema[i].parents[m], function(formData){
                let flag = true;
                let parms = {};
                for(let n in self.state.formData.schema[i].parents){
                  for(let x in formData){
                    if(formData[x].name == self.state.formData.schema[i].parents[n]){
                      if(formData[x].defaultValue == "" || formData[x].defaultValue == []){
                        flag = false;
                      }else{
                        parms[formData[x].name] = formData[x].defaultValue
                      }
                    }
                  }
                }
                self.fetchDataInput(parms, self.state.formData.schema[i]);
              });
            }
          }else if(self.state.formData.schema[i].parents && self.state.formData.schema[i].parents.length > 0 && !self.state.formData.schema[i].url){

            for(let m in self.state.formData.schema[i].parents){
              self.props.events.on('formChange:'+self.state.formData.schema[i].parents[m], function(formData, schema, value){
                self.setValue(value, self.state.formData.schema[i]);
              })
            }

          }

          break;
        case "Select":
          schema[i] = self._select(self.state.formData.schema[i])
          if(self.state.formData.schema[i].parents && self.state.formData.schema[i].parents.length > 0){
            for(let m in self.state.formData.schema[i].parents){
              self.props.events.on('formChange:'+self.state.formData.schema[i].parents[m], function(formData){
                let flag = true;
                let parms = {};
                for(let n in self.state.formData.schema[i].parents){
                  for(let x in formData){
                    if(formData[x].name == self.state.formData.schema[i].parents[n]){
                      if(formData[x].defaultValue == "" || formData[x].defaultValue == []){
                        flag = false;
                      }else{
                        parms[formData[x].name] = formData[x].defaultValue
                      }
                    }
                  }
                }
                self.fetchDataSelect(parms, self.state.formData.schema[i]);
              });
            }
          }
          break;
        case "DatePicker":
          schema[i] = self._datePicker(self.state.formData.schema[i]);
          break;
        case "Checkbox":
          schema[i] = self._checkbox(self.state.formData.schema[i]);
          break;
        case "Radio":
          schema[i] = self._radio(self.state.formData.schema[i]);
          break;
        case "Switch":
          schema[i] = self._switch(self.state.formData.schema[i]);
          break;
        case "Textarea":
          schema[i] = self._textarea(self.state.formData.schema[i]);
          break;
        case "Refill":
          schema[i] = self._refill(self.state.formData.schema[i]);
          self.props.events.on('formChange:'+self.state.formData.schema[i].name+"_refill", function(formData, schema){
            self.fetchDataRefill(self.state.formData.schema[i], schema.defaultValue);
          })
          break;
        default:
          schema[i] = self.state.formData.schema[i];
          break;
      }
    }
    self.state.formData.schema = schema;
    self.setState(self.state);

  }

  setValue(value, schema){
    let self = this;
    for(let i in self.state.formData.schema){
      if(self.state.formData.schema[i].name == schema.name){
          self.state.formData.schema[i].defaultValue = value[schema.subKey.split('.')[1]]
      }
    }
    self.setState(self.state);

  }

  fetchDataRefill(schema, value){

    let self = this;
    async(self._parse(schema.url)).then(function(data){
      for(let i in self.state.formData.schema){
        if(self.state.formData.schema[i].name == schema.name){
            self.state.formData.schema[i].dataList = data.data.list;
        }
      }
      self.setState(self.state);
    })

  }

  fetchDataSelect(parms, schema){

    let self = this;
    async(self._parse(schema.url)).then(function(data){
      for(let i in self.state.formData.schema){
        if(self.state.formData.schema[i].name == schema.name){
          let options = [];
          for(let m in data.data.list){
            options.push({
              label:data.data.list[m].key,
              value:data.data.list[m].value
            });
          }
          self.state.formData.schema[i].options = options;
        }
      }
      self.setState(self.state);
    })

  }

  fetchDataInput(parms, schema){
    let self = this;
    setTimeout(function(){
      async(self._parse(schema.url)).then(function(data){
        for(let i in self.state.formData.schema){
          if(self.state.formData.schema[i].name == schema.name){
            let setData = [];
            setData[schema.name] = data.data[self.state.formData.schema[i].subKey]
            self.state.formData.schema[i].defaultValue = data.data[self.state.formData.schema[i].subKey];
            self.state.formData.schema[i].attr = _.extend({value: data.data[self.state.formData.schema[i].subKey]}, self.state.formData.schema[i].attr);
            self.refs.formData.setFieldsValue(setData)
          }
        }
        self.setState(self.state);
      })
    })

  }

  _refill(item){

    let attrEle = [];
    let schema = {};
    let attr = {};
    for(var i in item){
      if(_.indexOf(attrEle, i) != -1){
        attr[i] = item[i];
      }else{
        schema[i] = item[i]
      }
    }
    schema.attr = attr;
    if(item.defaultValue == ""){
      schema.defaultValue = [];
    }

    let className = ["hidden"];
    if(item.hidden && item.hidden == 1){
      schema.className = schema.className+" hide";
    }

    return schema;

  }

  _checkbox(item){

    let attrEle = ["value", "disabled"];
    let schema = {};
    let attr = {};
    for(var i in item){
      if(_.indexOf(attrEle, i) != -1){
        attr[i] = item[i];
      }else{
        schema[i] = item[i]
      }
    }
    schema.attr = attr;
    if(item.defaultValue == ""){
      schema.defaultValue = [];
    }

    let className = ["hidden"];
    if(item.hidden && item.hidden == 1){
      schema.className = schema.className+" hide";
    }

    return schema;

  }

  _radio(item){

    let attrEle = ["value", "disabled"];
    let schema = {};
    let attr = {};
    for(var i in item){
      if(_.indexOf(attrEle, i) != -1){
        attr[i] = item[i];
      }else{
        schema[i] = item[i]
      }
    }
    schema.attr = attr;

    let className = ["hidden"];
    if(item.hidden && item.hidden == 1){
      schema.className = schema.className+" hide";
    }

    return schema;
  }

  _switch(item){
    let attrEle = ["value", "disabled"];
    let schema = {};
    let attr = {};
    for(var i in item){
      if(_.indexOf(attrEle, i) != -1){
        attr[i] = item[i];
      }else{
        schema[i] = item[i]
      }
    }
    schema.attr = attr;
    return schema;

  }

  _datePicker(item){
    let attrEle = ["disabled"];
    let className = ["hidden"];
    let schema = {};
    let attr = {};
    for(var i in item){
      if(_.indexOf(attrEle, i) != -1){
        attr[i] = item[i];
      }else{
        schema[i] = item[i]
      }
    }

    if(item.hidden && item.hidden == 1){
      schema.className = schema.className+" hide";
    }

    if(item.defaultValue === "0"){
      let now = Date.parse(new Date())/1000;
      let str = now+item.changeValue;
      schema.defaultValue = eval(str);
    }

    schema.attr = attr;
    schema.attr.format = (val) => val.format(item.format.replace("dd", "DD").replace("yyyy", "YYYY"));

    return schema;
  }

  _select(item){

    let attrEle = ["value", "placeholder", "disabled", "dropdownClassName", "cols"];
    let schema = {};
    let attr = {};
    for(var i in item){
      if(_.indexOf(attrEle, i) != -1){
        attr[i] = item[i];
      }else{
        schema[i] = item[i]
      }
    }
    schema.attr = attr;

    let className = ["hidden"];
    if(item.hidden && item.hidden == 1){
      schema.className = schema.className+" hide";
    }

    return schema;

  }

  //Input元素解析方法
  _textarea(item){

    let attrEle = ["value", "autoHeight", "placeholder", "disabled", "autosize", "rows"];
    let schema = {};
    let attr = {};
    for(var i in item){
      if(_.indexOf(attrEle, i) != -1){
        attr[i] = item[i];
      }else{
        schema[i] = item[i]
      }
    }
    schema.attr = attr;

    if(item.defaultValue && item.defaultValue != ""){
      schema.defaultValue = this._parse(item.defaultValue)
    }

    let className = ["hidden"];
    if(item.hidden && item.hidden == 1){
      schema.className = schema.className+" hide";
    }

    return schema;
  }

  //Input元素解析方法
  _input(item){

    let attrEle = ["value", "placeholder", "disabled"];
    let schema = {};
    let attr = {};
    for(var i in item){
      if(_.indexOf(attrEle, i) != -1){
        attr[i] = item[i];
      }else{
        schema[i] = item[i]
      }
    }
    schema.attr = attr;

    if(item.defaultValue && item.defaultValue != ""){
      schema.defaultValue = this._parse(item.defaultValue)
    }

    let className = ["hidden"];
    if(item.hidden && item.hidden == 1){
      schema.className = schema.className+" hide";
    }

    return schema;
  }

  //正则解析
  _parse(str){
    //
    let self = this;
    let flag = true;
    let myReg = /\{(.*?)\}/g;
    let res = str.match(myReg);

    for(let i in res){
      if(res[i].indexOf("jw.") != -1){
        str = str.replace(res[i], eval(res[i].replace("{", "").replace("}", "")));
      }else{
        let values = self.refs.formData.getFieldsValue();
        if(values[res[i].replace("{", "").replace("}", "")] == "" || !values[res[i].replace("{", "").replace("}", "")]){
          flag = false;
        }else{
          str = str.replace(res[i], values[res[i].replace("{", "").replace("}", "")])
        }
      }
    }
    if(flag){
      return str;
    }else{
      return false;
    }

  }

  render(){

    return(
        <div className="form-show-title">
          <Form formData={this.state.formData} ref="formData"/>
        </div>
      )
  }
  changeData(data){
    let dispatch = this.props.dispatch;
    dispatch({
      type:'form/changeData',
      data:{
        schema:data
      }
    })
  }
}
export default connect()(Schema);<|endoftext|>


<commit_before>/*$AMPERSAND_VERSION*/
var Store = require('key-tree-store');
var dom = require('ampersand-dom');
var matchesSelector = require('matches-selector');
var partial = require('lodash.partial');
var slice = Array.prototype.slice;

function getMatches(el, selector) {
    if (selector === '') return [el];
    var matches = [];
    if(!selector) return matches;
    if(selector.firstMatchOnly) {
        //interactar modification to retrieve only firstMatchOnly element
        if (matchesSelector(el, selector.firstMatchOnly)) return [el];
        return matches.concat(slice.call([el.querySelector(selector.firstMatchOnly) || el]));
    }else{
        if (matchesSelector(el, selector)) matches.push(el);
        return matches.concat(slice.call(el.querySelectorAll(selector)));
    }
}
function setAttributes(el, attrs) {
    for (var name in attrs) {
        dom.setAttribute(el, name, attrs[name]);
    }
}

function removeAttributes(el, attrs) {
    for (var name in attrs) {
        dom.removeAttribute(el, name);
    }
}

function makeArray(val) {
    return Array.isArray(val) ? val : [val];
}

function switchHandler(binding, el, value) {
    // the element selector to show
    var showValue = binding.cases[value];
    // hide all the other elements with a different value
    for (var item in binding.cases) {
        var curValue = binding.cases[item];
        if (value !== item && curValue !== showValue) {
            getMatches(el, curValue).forEach(function (match) {
                dom.hide(match);
            });
        }
    }
    getMatches(el, showValue).forEach(function (match) {
        dom.show(match);
    });
}

function getSelector(binding) {
    if(binding.firstMatchOnly !== undefined && binding.firstMatchOnly === true) {
        if (typeof binding.selector === 'string') {
            return {firstMatchOnly:binding.selector};
        } else if (binding.hook) {
            return {firstMatchOnly:'[data-hook~="' + binding.hook + '"]'};
        } else {
            return {firstMatchOnly:''};
        }
    }else{
        if (typeof binding.selector === 'string') {
          return binding.selector;
        } else if (binding.hook) {
          return '[data-hook~="' + binding.hook + '"]';
        } else {
          return '';
        }
    }
}

function getBindingFunc(binding, context) {
    var type = binding.type || 'text';
    var isCustomBinding = typeof type === 'function';
    var selector = getSelector(binding);
    var yes = binding.yes;
    var no = binding.no;
    var hasYesNo = !!(yes || no);

    // storage variable for previous if relevant
    var previousValue;

    if (isCustomBinding) {
        return function (el, value) {
            getMatches(el, selector).forEach(function (match) {
                type.call(context, match, value, previousValue);
            });
            previousValue = value;
        };
    } else if (type === 'text') {
        return function (el, value) {
            getMatches(el, selector).forEach(function (match) {
                dom.text(match, value);
            });
        };
    } else if (type === 'class') {
        return function (el, value) {
            getMatches(el, selector).forEach(function (match) {
                dom.switchClass(match, previousValue, value);
            });
            previousValue = value;
        };
    } else if (type === 'attribute') {
        if (!binding.name) throw Error('attribute bindings must have a "name"');
        return function (el, value) {
            var names = makeArray(binding.name);
            getMatches(el, selector).forEach(function (match) {
                names.forEach(function (name) {
                    dom.setAttribute(match, name, value);
                });
            });
            previousValue = value;
        };
    } else if (type === 'value') {
        return function (el, value) {
            getMatches(el, selector).forEach(function (match) {
                if (!value && value !== 0) value = '';
                // only apply bindings if element is not currently focused
                if (document.activeElement !== match) match.value = value;
            });
            previousValue = value;
        };
    } else if (type === 'booleanClass') {
        // if there's a `no` case this is actually a switch
        if (hasYesNo) {
            yes = makeArray(yes || '');
            no = makeArray(no || '');
            return function (el, value) {
                var prevClass = value ? no : yes;
                var newClass = value ? yes : no;
                getMatches(el, selector).forEach(function (match) {
                    prevClass.forEach(function (pc) {
                        dom.removeClass(match, pc);
                    });
                    newClass.forEach(function (nc) {
                        dom.addClass(match, nc);
                    });
                });
            };
        } else {
            return function (el, value, keyName) {
                var name = makeArray(binding.name || keyName);
                var invert = (binding.invert || false);
                value = (invert ? (value ? false : true) : value);
                getMatches(el, selector).forEach(function (match) {
                    name.forEach(function (className) {
                        dom[value ? 'addClass' : 'removeClass'](match, className);
                    });
                });
            };
        }
    } else if (type === 'booleanAttribute') {
        // if there are `yes` and `no` selectors, this swaps between them
        if (hasYesNo) {
            yes = makeArray(yes || '');
            no = makeArray(no || '');
            return function (el, value) {
                var prevAttribute = value ? no : yes;
                var newAttribute = value ? yes : no;
                getMatches(el, selector).forEach(function (match) {
                    prevAttribute.forEach(function (pa) {
                        if (pa) {
                            dom.removeAttribute(match, pa);
                        }
                    });
                    newAttribute.forEach(function (na) {
                        if (na) {
                            dom.addAttribute(match, na);
                        }
                    });
                });
            };
        } else {
            return function (el, value, keyName) {
                var name = makeArray(binding.name || keyName);
                var invert = (binding.invert || false);
                value = (invert ? (value ? false : true) : value);
                getMatches(el, selector).forEach(function (match) {
                    name.forEach(function (attr) {
                        dom[value ? 'addAttribute' : 'removeAttribute'](match, attr);
                    });
                });
            };
        }
    } else if (type === 'toggle') {
        var mode = (binding.mode || 'display');
        var invert = (binding.invert || false);
        // this doesn't require a selector since we can pass yes/no selectors
        if (hasYesNo) {
            return function (el, value) {
                getMatches(el, yes).forEach(function (match) {
                    dom[value ? 'show' : 'hide'](match, mode);
                });
                getMatches(el, no).forEach(function (match) {
                    dom[value ? 'hide' : 'show'](match, mode);
                });
            };
        } else {
            return function (el, value) {
                value = (invert ? (value ? false : true) : value);
                getMatches(el, selector).forEach(function (match) {
                    dom[value ? 'show' : 'hide'](match, mode);
                });
            };
        }
    } else if (type === 'switch') {
        if (!binding.cases) throw Error('switch bindings must have "cases"');
        return partial(switchHandler, binding);
    } else if (type === 'innerHTML') {
        return function (el, value) {
            getMatches(el, selector).forEach(function (match) {
                dom.html(match, value);
            });
        };
    } else if (type === 'switchClass') {
        if (!binding.cases) throw Error('switchClass bindings must have "cases"');
        return function (el, value, keyName) {
            var name = makeArray(binding.name || keyName);
            for (var item in binding.cases) {
                getMatches(el, binding.cases[item]).forEach(function (match) {
                    name.forEach(function (className) {
                        dom[value === item ? 'addClass' : 'removeClass'](match, className);
                    });
                });
            }
        };
    } else if (type === 'switchAttribute') {
        if (!binding.cases) throw Error('switchAttribute bindings must have "cases"');
        return function (el, value, keyName) {
            getMatches(el, selector).forEach(function (match) {
                if (previousValue) {
                    removeAttributes(match, previousValue);
                }

                if (value in binding.cases) {
                    var attrs = binding.cases[value];
                    if (typeof attrs === 'string') {
                        attrs = {};
                        attrs[binding.name || keyName] = binding.cases[value];
                    }
                    setAttributes(match, attrs);

                    previousValue = attrs;
                }
            });
        };
    } else {
        throw new Error('no such binding type: ' + type);
    }
}

// returns a key-tree-store of functions
// that can be applied to any element/model.

// all resulting functions should be called
// like func(el, value, lastKeyName)
module.exports = function (bindings, context) {
    var store = new Store();
    var key, current;

    for (key in bindings) {
        current = bindings[key];
        if (typeof current === 'string') {
            store.add(key, getBindingFunc({
                type: 'text',
                selector: current
            }));
        } else if (current.forEach) {
            current.forEach(function (binding) {
                store.add(key, getBindingFunc(binding, context));
            });
        } else {
            store.add(key, getBindingFunc(current, context));
        }
    }

    return store;
};
<commit_msg>removed unnecessary comments<commit_after>/*$AMPERSAND_VERSION*/
var Store = require('key-tree-store');
var dom = require('ampersand-dom');
var matchesSelector = require('matches-selector');
var partial = require('lodash.partial');
var slice = Array.prototype.slice;

function getMatches(el, selector) {
    if (selector === '') return [el];
    var matches = [];
    if(!selector) return matches;
    if(selector.firstMatchOnly) {
        if (matchesSelector(el, selector.firstMatchOnly)) return [el];
        return matches.concat(slice.call([el.querySelector(selector.firstMatchOnly) || el]));
    }else{
        if (matchesSelector(el, selector)) matches.push(el);
        return matches.concat(slice.call(el.querySelectorAll(selector)));
    }
}
function setAttributes(el, attrs) {
    for (var name in attrs) {
        dom.setAttribute(el, name, attrs[name]);
    }
}

function removeAttributes(el, attrs) {
    for (var name in attrs) {
        dom.removeAttribute(el, name);
    }
}

function makeArray(val) {
    return Array.isArray(val) ? val : [val];
}

function switchHandler(binding, el, value) {
    // the element selector to show
    var showValue = binding.cases[value];
    // hide all the other elements with a different value
    for (var item in binding.cases) {
        var curValue = binding.cases[item];
        if (value !== item && curValue !== showValue) {
            getMatches(el, curValue).forEach(function (match) {
                dom.hide(match);
            });
        }
    }
    getMatches(el, showValue).forEach(function (match) {
        dom.show(match);
    });
}

function getSelector(binding) {
    if(binding.firstMatchOnly !== undefined && binding.firstMatchOnly === true) {
        if (typeof binding.selector === 'string') {
            return {firstMatchOnly:binding.selector};
        } else if (binding.hook) {
            return {firstMatchOnly:'[data-hook~="' + binding.hook + '"]'};
        } else {
            return {firstMatchOnly:''};
        }
    }else{
        if (typeof binding.selector === 'string') {
          return binding.selector;
        } else if (binding.hook) {
          return '[data-hook~="' + binding.hook + '"]';
        } else {
          return '';
        }
    }
}

function getBindingFunc(binding, context) {
    var type = binding.type || 'text';
    var isCustomBinding = typeof type === 'function';
    var selector = getSelector(binding);
    var yes = binding.yes;
    var no = binding.no;
    var hasYesNo = !!(yes || no);

    // storage variable for previous if relevant
    var previousValue;

    if (isCustomBinding) {
        return function (el, value) {
            getMatches(el, selector).forEach(function (match) {
                type.call(context, match, value, previousValue);
            });
            previousValue = value;
        };
    } else if (type === 'text') {
        return function (el, value) {
            getMatches(el, selector).forEach(function (match) {
                dom.text(match, value);
            });
        };
    } else if (type === 'class') {
        return function (el, value) {
            getMatches(el, selector).forEach(function (match) {
                dom.switchClass(match, previousValue, value);
            });
            previousValue = value;
        };
    } else if (type === 'attribute') {
        if (!binding.name) throw Error('attribute bindings must have a "name"');
        return function (el, value) {
            var names = makeArray(binding.name);
            getMatches(el, selector).forEach(function (match) {
                names.forEach(function (name) {
                    dom.setAttribute(match, name, value);
                });
            });
            previousValue = value;
        };
    } else if (type === 'value') {
        return function (el, value) {
            getMatches(el, selector).forEach(function (match) {
                if (!value && value !== 0) value = '';
                // only apply bindings if element is not currently focused
                if (document.activeElement !== match) match.value = value;
            });
            previousValue = value;
        };
    } else if (type === 'booleanClass') {
        // if there's a `no` case this is actually a switch
        if (hasYesNo) {
            yes = makeArray(yes || '');
            no = makeArray(no || '');
            return function (el, value) {
                var prevClass = value ? no : yes;
                var newClass = value ? yes : no;
                getMatches(el, selector).forEach(function (match) {
                    prevClass.forEach(function (pc) {
                        dom.removeClass(match, pc);
                    });
                    newClass.forEach(function (nc) {
                        dom.addClass(match, nc);
                    });
                });
            };
        } else {
            return function (el, value, keyName) {
                var name = makeArray(binding.name || keyName);
                var invert = (binding.invert || false);
                value = (invert ? (value ? false : true) : value);
                getMatches(el, selector).forEach(function (match) {
                    name.forEach(function (className) {
                        dom[value ? 'addClass' : 'removeClass'](match, className);
                    });
                });
            };
        }
    } else if (type === 'booleanAttribute') {
        // if there are `yes` and `no` selectors, this swaps between them
        if (hasYesNo) {
            yes = makeArray(yes || '');
            no = makeArray(no || '');
            return function (el, value) {
                var prevAttribute = value ? no : yes;
                var newAttribute = value ? yes : no;
                getMatches(el, selector).forEach(function (match) {
                    prevAttribute.forEach(function (pa) {
                        if (pa) {
                            dom.removeAttribute(match, pa);
                        }
                    });
                    newAttribute.forEach(function (na) {
                        if (na) {
                            dom.addAttribute(match, na);
                        }
                    });
                });
            };
        } else {
            return function (el, value, keyName) {
                var name = makeArray(binding.name || keyName);
                var invert = (binding.invert || false);
                value = (invert ? (value ? false : true) : value);
                getMatches(el, selector).forEach(function (match) {
                    name.forEach(function (attr) {
                        dom[value ? 'addAttribute' : 'removeAttribute'](match, attr);
                    });
                });
            };
        }
    } else if (type === 'toggle') {
        var mode = (binding.mode || 'display');
        var invert = (binding.invert || false);
        // this doesn't require a selector since we can pass yes/no selectors
        if (hasYesNo) {
            return function (el, value) {
                getMatches(el, yes).forEach(function (match) {
                    dom[value ? 'show' : 'hide'](match, mode);
                });
                getMatches(el, no).forEach(function (match) {
                    dom[value ? 'hide' : 'show'](match, mode);
                });
            };
        } else {
            return function (el, value) {
                value = (invert ? (value ? false : true) : value);
                getMatches(el, selector).forEach(function (match) {
                    dom[value ? 'show' : 'hide'](match, mode);
                });
            };
        }
    } else if (type === 'switch') {
        if (!binding.cases) throw Error('switch bindings must have "cases"');
        return partial(switchHandler, binding);
    } else if (type === 'innerHTML') {
        return function (el, value) {
            getMatches(el, selector).forEach(function (match) {
                dom.html(match, value);
            });
        };
    } else if (type === 'switchClass') {
        if (!binding.cases) throw Error('switchClass bindings must have "cases"');
        return function (el, value, keyName) {
            var name = makeArray(binding.name || keyName);
            for (var item in binding.cases) {
                getMatches(el, binding.cases[item]).forEach(function (match) {
                    name.forEach(function (className) {
                        dom[value === item ? 'addClass' : 'removeClass'](match, className);
                    });
                });
            }
        };
    } else if (type === 'switchAttribute') {
        if (!binding.cases) throw Error('switchAttribute bindings must have "cases"');
        return function (el, value, keyName) {
            getMatches(el, selector).forEach(function (match) {
                if (previousValue) {
                    removeAttributes(match, previousValue);
                }

                if (value in binding.cases) {
                    var attrs = binding.cases[value];
                    if (typeof attrs === 'string') {
                        attrs = {};
                        attrs[binding.name || keyName] = binding.cases[value];
                    }
                    setAttributes(match, attrs);

                    previousValue = attrs;
                }
            });
        };
    } else {
        throw new Error('no such binding type: ' + type);
    }
}

// returns a key-tree-store of functions
// that can be applied to any element/model.

// all resulting functions should be called
// like func(el, value, lastKeyName)
module.exports = function (bindings, context) {
    var store = new Store();
    var key, current;

    for (key in bindings) {
        current = bindings[key];
        if (typeof current === 'string') {
            store.add(key, getBindingFunc({
                type: 'text',
                selector: current
            }));
        } else if (current.forEach) {
            current.forEach(function (binding) {
                store.add(key, getBindingFunc(binding, context));
            });
        } else {
            store.add(key, getBindingFunc(current, context));
        }
    }

    return store;
};
<|endoftext|>


<commit_before>/*
 *  gridfs/put.js
 *
 *  David Janes
 *  IOTDB.org
 *  2018-11-06
 *
 *  Copyright [2013-2019] [David P. Janes]
 *
 *  Licensed under the Apache License, Version 2.0 (the "License")
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

"use strict"

const _ = require("iotdb-helpers")

const assert = require("assert")

const logger = require("../logger")(__filename)

/**
 */
const put = _.promise((self, done) => {
    const gridfs = require("gridfs")

    logger.trace({
        method: put.method,
        bucket: self.bucket,
        filename: self.filename,
    }, "called")

    _.promise(self)
        .validate(put)
        .make((sd, sdone) => {
            let document = self.document
            if (_.is.String(document)) {
                document = Buffer.from(document, self.document_encoding || "utf8")
            }

            const initd = {
                filename: self.filename,
                metadata: {},
            }

            if (self.bucket) {
                initd.bucket = self.bucket
            }

            if (self.document_media_type) {
                initd.metadata.document_media_type = self.document_media_type
            }

            gridfs.writeFile(initd, document, (error, result) => {
                if (error) {
                    return sdone(error)
                }

                sdone(null, self)
            })
        })
        .end(done, self)
})

put.method = "gridfs.put"
put.required = {
    bucket: [ _.is.String, null ],
    filename: _.is.String,
    mongodb: _.is.Object,
    document: [ _.is.String, _.is.Buffer ],
}
put.accepts = {
    document_media_type: _.is.String,
    document_encoding: _.is.String,
}

/**
 */
const put_json = _.promise((self, done) => {
    _.promise(self)
        .validate(put)
        .add({
            document: JSON.stringify(self.json),
            document_media_type: "application/json",
            document_encoding: "utf8",
        })
        .end(done, self)
})

put_json.method = "gridfs.put.json"
put_json.required = {
    bucket: [ _.is.String, null ],
    filename: _.is.String,
    json: _.is.JSON,
    mongodb: _.is.Object,
}

/**
 *  API
 */
exports.put = put
exports.put.json = put_json
<commit_msg>make bucket optional<commit_after>/*
 *  gridfs/put.js
 *
 *  David Janes
 *  IOTDB.org
 *  2018-11-06
 *
 *  Copyright [2013-2019] [David P. Janes]
 *
 *  Licensed under the Apache License, Version 2.0 (the "License")
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

"use strict"

const _ = require("iotdb-helpers")

const assert = require("assert")

const logger = require("../logger")(__filename)

/**
 */
const put = _.promise((self, done) => {
    const gridfs = require("gridfs")

    logger.trace({
        method: put.method,
        bucket: self.bucket,
        filename: self.filename,
    }, "called")

    _.promise(self)
        .validate(put)
        .make((sd, sdone) => {
            let document = self.document
            if (_.is.String(document)) {
                document = Buffer.from(document, self.document_encoding || "utf8")
            }

            const initd = {
                filename: self.filename,
                metadata: {},
            }

            if (self.bucket) {
                initd.bucket = self.bucket
            }

            if (self.document_media_type) {
                initd.metadata.document_media_type = self.document_media_type
            }

            gridfs.writeFile(initd, document, (error, result) => {
                if (error) {
                    return sdone(error)
                }

                sdone(null, self)
            })
        })
        .end(done, self)
})

put.method = "gridfs.put"
put.required = {
    filename: _.is.String,
    mongodb: _.is.Object,
    document: [ _.is.String, _.is.Buffer ],
}
put.accepts = {
    bucket: _.is.String,
    document_media_type: _.is.String,
    document_encoding: _.is.String,
}

/**
 */
const put_json = _.promise((self, done) => {
    _.promise(self)
        .validate(put)
        .add({
            document: JSON.stringify(self.json),
            document_media_type: "application/json",
            document_encoding: "utf8",
        })
        .end(done, self)
})

put_json.method = "gridfs.put.json"
put_json.required = {
    filename: _.is.String,
    json: _.is.JSON,
    mongodb: _.is.Object,
}
put_json.accepts = {
    bucket: _.is.String,
}

/**
 *  API
 */
exports.put = put
exports.put.json = put_json
<|endoftext|>


<commit_before>var artist = require("./modules/artist"),
	song = require("./modules/songs"),
	utilsRegex = require("./utils/regex"),
	cheerio = require("cheerio"),
	request = require("request"),
	util = require("util"),
	async = require("async"),
	Artist = require("./MongoDB/schema").Artist,
	_ = require("underscore"),
	mongoose = require("mongoose");

// https://github.com/MatthewMueller/cheerio
// https://github.com/mikeal/request
// http://nodejs.org/api/util.html
// http://underscorejs.org/
// https://github.com/caolan/async
// http://mongoosejs.com/docs/guide.html

var geniusQuery = {
    albumURLs: function(artistName, callback) {
        var artistURL = "http://rapgenius.com/artists/";
        request(artistURL + artistName, function (error, response, body) {
            if (error || response.statusCode !== 200) {
                callback("Artist not found");
            } else {
	              var $ = cheerio.load(body);
                callback(null, $(".album_list li a").map(function() {
                    return this.attr("href");
                }));
            }
        });
    },

    albumData: function(baseAlbumURL, callback) {
		    request(baseAlbumURL, function (error, response, body) {
            if (error || response.statusCode !== 200) {
                callback(error);
            } else {
			          var $ = cheerio.load(body);
                var title = utilsRegex
                    .obtainAlbumTitle($("h1.name a.artist")["0"]["next"]["data"]);

			          // Extract album year from albumTitle if present
				        var year = title.match(/\(\d{4}\)/);
                callback(null, {
                    title: title,
                    year: year === null ? -1 : year[0].replace(/(\(|\))/g,""),
                    songURLs: $(".song_list .song_link").map(function() {
                        return this.attr("href");
                    })
                });
            }
        });
    },

    songData: function(songURL, callback) {
		    request(songURL, function (error, response, body) {
			      if (error !== null || response.statusCode !== 200)
                throw "Couldn't get song: " + songURL;

			      var $ = cheerio.load(body);
            var title = utilsRegex.obtainSongTitle($("h1.song_title a")["0"]["next"]["data"])
            console.log("Got song: ", title);
            var lyricsText = $(".lyrics_container .lyrics p").text();
            callback(null, {
			          title: title,
				        trackNumber: $(".album_title_and_track_number").text().trim().split(" ")[1],
				        lyrics: lyricsText.split("\n"),
                URL: songURL
            });
        });
    }
};

// Process artist page

var getAlbums = function (artistName, callback) {
    geniusQuery.albumURLs(artistName, function(error, albumURLs) {
        async.parallel(_.map(albumURLs, function(albumURL) {
	          return function (parallelCallback) {
                console.log("processing album", albumURL)
                geniusQuery.albumData(homeURL + albumURL, parallelCallback);
            };
        }), callback);
    });
};

// process song(s)
var addSongs = function (year, albumTitle, $, callback) {
	  var processSongsTasks = [];
    $(".song_list .song_link").each(function() {
		    var songURL = (homeURL + this.attr("href"));
		    var track = new song(albumTitle, songURL, year);
		    var task = buildfn2(songURL, track);
		    processSongsTasks.push(task);
    });
    async.parallel(processSongsTasks, function (errors, results) {
		    console.log("All songs in " + albumTitle + " processed", errors, results);
		    callback(errors, results);
    });
};

var buildfn2 = function (songURL, track) {
	  // Closure invoked w/ async.parallel
	  var processSong = function (callback) {
		    console.log('processing song', songURL);
		    request(songURL, function (error, response, body) {
			      if (!error && response.statusCode == 200) {
			          var $ = cheerio.load(body);
			          var songTitle = utilsRegex.obtainSongTitle($("h1.song_title a")["0"]["next"]["data"]);
				        var trackNumber = $(".album_title_and_track_number").text().trim().split(" ")[1];
				        var lyricsText = $(".lyrics_container .lyrics p").text();
				        var songlyrics = lyricsText.split("\n");
				        track.addSongName(songTitle);
				        track.addTrackNumber(trackNumber);
				        track.addArtist(rapper.name);
				        track.addLyrics(songlyrics);
				        rapper.addSong(track);
				        callback(null);
			      } else {
				        console.log("Error retrieveing song details");
				        callback(error);
			      }
		    });
	  };
	  return processSong;
};

				// rapper.printFourLyricsFromARandomSong();

var getSongsForAllAlbums = function(albums, callback) {
    async.parallel(_.map(albums, function(album) {
        return function(parallelCallback) {
            getAlbumSongs(album.title, album.songURLs, parallelCallback);
        };
    }), function (errors, songs) {
		    callback(errors, songs);
    });
};

var getAlbumSongs = function(title, songURLs, callback) {
    async.parallel(_.map(songURLs, function(x) {
        return function(parallelCallback) {
            geniusQuery.songData(homeURL + x, function(error, song) {
                song.albumTitle = title;
                parallelCallback(error, song);
            });
        };
    }), function (errors, songs) {
		    callback(errors, songs);
    });
};

var songDataToTrack = function(songData) {
    var track = new song(songData.album.title, songData.songURL, songData.album.year);
		track.addSongName(songData.title);
		track.addTrackNumber(songData.trackNumber);
		track.addLyrics(songData.lyrics);
    return track;
};
// Connect to DB
mongoose.connect("mongodb://localhost/rapgenius");
var homeURL = "http://rapgenius.com";
var rapper = new artist(process.argv[2] || "Skinnyman");
getAlbums(rapper.name, function(error, albums) {
    getSongsForAllAlbums(albums, function(error, songs) {
        console.log(songs)
    });
});
<commit_msg>Add code to save an artist<commit_after>var artist = require("./modules/artist"),
	song = require("./modules/songs"),
	utilsRegex = require("./utils/regex"),
	cheerio = require("cheerio"),
	request = require("request"),
	util = require("util"),
	async = require("async"),
	Artist = require("./MongoDB/schema").Artist,
	_ = require("underscore"),
	mongoose = require("mongoose");

// https://github.com/MatthewMueller/cheerio
// https://github.com/mikeal/request
// http://nodejs.org/api/util.html
// http://underscorejs.org/
// https://github.com/caolan/async
// http://mongoosejs.com/docs/guide.html

var geniusQuery = {
    albumURLs: function(artistName, callback) {
        var artistURL = "http://rapgenius.com/artists/";
        request(artistURL + artistName, function (error, response, body) {
            if (error || response.statusCode !== 200) {
                callback("Artist not found");
            } else {
	              var $ = cheerio.load(body);
                callback(null, $(".album_list li a").map(function() {
                    return this.attr("href");
                }));
            }
        });
    },

    albumData: function(baseAlbumURL, callback) {
		    request(baseAlbumURL, function (error, response, body) {
            if (error || response.statusCode !== 200) {
                callback(error);
            } else {
			          var $ = cheerio.load(body);
                var title = utilsRegex
                    .obtainAlbumTitle($("h1.name a.artist")["0"]["next"]["data"]);

			          // Extract album year from albumTitle if present
				        var year = title.match(/\(\d{4}\)/);
                callback(null, {
                    title: title,
                    year: year === null ? -1 : year[0].replace(/(\(|\))/g,""),
                    songURLs: $(".song_list .song_link").map(function() {
                        return this.attr("href");
                    })
                });
            }
        });
    },

    songData: function(songURL, callback) {
		    request(songURL, function (error, response, body) {
			      if (error !== null || response.statusCode !== 200)
                throw "Couldn't get song: " + songURL;

			      var $ = cheerio.load(body);
            var title = utilsRegex.obtainSongTitle($("h1.song_title a")["0"]["next"]["data"])
            console.log("Got song: ", title);
            var lyricsText = $(".lyrics_container .lyrics p").text();
            callback(null, {
			          title: title,
				        trackNumber: $(".album_title_and_track_number").text().trim().split(" ")[1],
				        lyrics: lyricsText.split("\n"),
                URL: songURL
            });
        });
    }
};

// Process artist page

var getAlbums = function (artistName, callback) {
    geniusQuery.albumURLs(artistName, function(error, albumURLs) {
        async.parallel(_.map(albumURLs, function(albumURL) {
	          return function (parallelCallback) {
                console.log("processing album", albumURL)
                geniusQuery.albumData(homeURL + albumURL, parallelCallback);
            };
        }), callback);
    });
};

// process song(s)
var addSongs = function (year, albumTitle, $, callback) {
	  var processSongsTasks = [];
    $(".song_list .song_link").each(function() {
		    var songURL = (homeURL + this.attr("href"));
		    var track = new song(albumTitle, songURL, year);
		    var task = buildfn2(songURL, track);
		    processSongsTasks.push(task);
    });
    async.parallel(processSongsTasks, function (errors, results) {
		    console.log("All songs in " + albumTitle + " processed", errors, results);
		    callback(errors, results);
    });
};

var buildfn2 = function (songURL, track) {
	  // Closure invoked w/ async.parallel
	  var processSong = function (callback) {
		    console.log('processing song', songURL);
		    request(songURL, function (error, response, body) {
			      if (!error && response.statusCode == 200) {
			          var $ = cheerio.load(body);
			          var songTitle = utilsRegex.obtainSongTitle($("h1.song_title a")["0"]["next"]["data"]);
				        var trackNumber = $(".album_title_and_track_number").text().trim().split(" ")[1];
				        var lyricsText = $(".lyrics_container .lyrics p").text();
				        var songlyrics = lyricsText.split("\n");
				        track.addSongName(songTitle);
				        track.addTrackNumber(trackNumber);
				        track.addArtist(rapper.name);
				        track.addLyrics(songlyrics);
				        rapper.addSong(track);
				        callback(null);
			      } else {
				        console.log("Error retrieveing song details");
				        callback(error);
			      }
		    });
	  };
	  return processSong;
};

				// rapper.printFourLyricsFromARandomSong();

var getSongsForAllAlbums = function(albums, callback) {
    async.parallel(_.map(albums, function(album) {
        return function(parallelCallback) {
            getAlbumSongs(album.title, album.songURLs, parallelCallback);
        };
    }), function (errors, songs) {
		    callback(errors, songs);
    });
};

var getAlbumSongs = function(title, songURLs, callback) {
    async.parallel(_.map(songURLs, function(x) {
        return function(parallelCallback) {
            geniusQuery.songData(homeURL + x, function(error, song) {
                song.albumTitle = title;
                parallelCallback(error, song);
            });
        };
    }), function (errors, songs) {
		    callback(errors, songs);
    });
};

var songDataToTrack = function(songData) {
    var track = new song(songData.album.title, songData.songURL, songData.album.year);
		track.addSongName(songData.title);
		track.addTrackNumber(songData.trackNumber);
		track.addLyrics(songData.lyrics);
    return track;
};

var saveArtist = function(rapper, callback) {
		new Artist(rapper).save(function (err) {
        if (err !== null) throw "Error saving " + rapper.name + " into DB: " + err;
        callback();
		});
};

// Connect to DB
mongoose.connect("mongodb://localhost/rapgenius");
var homeURL = "http://rapgenius.com";
var rapper = new artist(process.argv[2] || "Skinnyman");
getAlbums(rapper.name, function(error, albums) {
    getSongsForAllAlbums(albums, function(error, songs) {
        console.log(songs)
    });
});
<|endoftext|>