<commit_before>import { Observable } from 'rxjs';
import { combineEpics } from 'redux-observable';
import { LOCATION_CHANGE } from 'react-router-redux';
import {
	apiRequest,
	apiSuccess,
	apiError,
	apiComplete,
	locationSync,
} from '../actions/syncActionCreators';
import { activeRouteQueries$ } from '../util/routeUtils';
import { fetchQueries } from '../util/fetchUtils';

/**
 * Navigation actions will provide the `location` as the payload, which this
 * epic will use to collect the current Reactive Queries associated with the
 * active routes.
 *
 * These queries will then be dispatched in the payload of `apiRequest`
 * @param {Object} routes The application's React Router routes
 * @returns {Function} an Epic function
 */
export const getNavEpic = routes => {
	const activeQueries$ = activeRouteQueries$(routes);
	return (action$, store) =>
		action$.ofType(LOCATION_CHANGE, '@@server/RENDER', 'LOCATION_SYNC')
			.map(({ payload }) => payload)  // extract the `location` from the action payload
			.flatMap(activeQueries$)        // find the queries for the location
			.map(apiRequest);               // dispatch apiRequest with all queries
};

/**
 * Listen for actions that should cause the application state to reload based
 * on the current routing location
 *
 * The action can have a Boolean `meta` prop to indicate if the action was
 * dispatched on the server. If so, the application will _not_ be reloaded
 */
export const resetLocationEpic = (action$, store) =>
	action$.ofType('CONFIGURE_AUTH')  // auth changes imply privacy changes - reload
		.filter(({ meta }) => !meta)  // throw out any server-side actions
		.map(() => locationSync(store.getState().routing.locationBeforeTransitions));

/**
 * Listen for actions that provide queries to send to the api - mainly
 * API_REQUEST
 */
export const fetchQueriesEpic = (action$, store) =>
	action$.ofType('API_REQUEST')
		.map(({ payload }) => payload)  // payload contains the queries array
		.flatMap(queries => {           // set up the fetch call to the app server
			const { config, auth } = store.getState();
			const fetch = fetchQueries(config.apiUrl, { method: 'GET', auth });
			return Observable.fromPromise(fetch(queries))  // call fetch
				.takeUntil(action$.ofType(LOCATION_CHANGE, 'LOCATION_SYNC'))  // cancel this fetch when nav happens
				.map(apiSuccess)                             // dispatch apiSuccess with server response
				.catch(err => Observable.of(apiError(err)))  // ... or apiError
				.flatMap(action => Observable.of(action, apiComplete()));  // dispatch apiComplete after resolution
		});

export default function getSyncEpic(routes) {
	return combineEpics(
		getNavEpic(routes),
		resetLocationEpic,
		fetchQueriesEpic
	);
}<commit_msg>more comments'<commit_after>import { Observable } from 'rxjs';
import { combineEpics } from 'redux-observable';
import { LOCATION_CHANGE } from 'react-router-redux';
import {
	apiRequest,
	apiSuccess,
	apiError,
	apiComplete,
	locationSync,
} from '../actions/syncActionCreators';
import { activeRouteQueries$ } from '../util/routeUtils';
import { fetchQueries } from '../util/fetchUtils';

/**
 * Navigation actions will provide the `location` as the payload, which this
 * epic will use to collect the current Reactive Queries associated with the
 * active routes.
 *
 * These queries will then be dispatched in the payload of `apiRequest`
 * @param {Object} routes The application's React Router routes
 * @returns {Function} an Epic function that emits an API_REQUEST action
 */
export const getNavEpic = routes => {
	const activeQueries$ = activeRouteQueries$(routes);
	return (action$, store) =>
		action$.ofType(LOCATION_CHANGE, '@@server/RENDER', 'LOCATION_SYNC')
			.map(({ payload }) => payload)  // extract the `location` from the action payload
			.flatMap(activeQueries$)        // find the queries for the location
			.map(apiRequest);               // dispatch apiRequest with all queries
};

/**
 * Listen for actions that should cause the application state to reload based
 * on the current routing location
 *
 * The action can have a Boolean `meta` prop to indicate if the action was
 * dispatched on the server. If so, the application will _not_ be reloaded
 *
 * emits a LOCATION_SYNC action
 */
export const resetLocationEpic = (action$, store) =>
	action$.ofType('CONFIGURE_AUTH')  // auth changes imply privacy changes - reload
		.filter(({ meta }) => !meta)  // throw out any server-side actions
		.map(() => locationSync(store.getState().routing.locationBeforeTransitions));

/**
 * Listen for actions that provide queries to send to the api - mainly
 * API_REQUEST
 *
 * emits (API_SUCCESS || API_ERROR) then API_COMPLETE
 */
export const fetchQueriesEpic = (action$, store) =>
	action$.ofType('API_REQUEST')
		.map(({ payload }) => payload)  // payload contains the queries array
		.flatMap(queries => {           // set up the fetch call to the app server
			const { config, auth } = store.getState();
			const fetch = fetchQueries(config.apiUrl, { method: 'GET', auth });
			return Observable.fromPromise(fetch(queries))  // call fetch
				.takeUntil(action$.ofType(LOCATION_CHANGE, 'LOCATION_SYNC'))  // cancel this fetch when nav happens
				.map(apiSuccess)                             // dispatch apiSuccess with server response
				.catch(err => Observable.of(apiError(err)))  // ... or apiError
				.flatMap(action => Observable.of(action, apiComplete()));  // dispatch apiComplete after resolution
		});

export default function getSyncEpic(routes) {
	return combineEpics(
		getNavEpic(routes),
		resetLocationEpic,
		fetchQueriesEpic
	);
}
{'fraction_non_alphanumeric': 0.11496090973702915, 'fraction_numerical': 0.0, 'mean_word_length': 3.8484065460809647, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1400563', 'n_tokens_mistral': 1638, 'n_tokens_neox': 1563, 'n_words': 541}