Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
describe('#treeSelect', () => {
const shipsInUniverses = treeSelect(
(state: State) => [state.ships, state.selectedUniverses],
([ships, universes], sortBy?: Sorting) =>
ships
.filter(ship => universes.indexOf(ship.name) > -1)
.sort(sortBy)
);
it('infers correct arugment type', () => {
// $ExpectError requires State as parameter
shipsInUniverses('hi');
});
it('infers correct return type', () => {
const state = {
ships: [],
selectedUniverses: [],
export function getSiteStatsForQuery( state, siteId, statType, query ) {
const serializedQuery = getSerializedStatsQuery( query );
return get( state.stats.lists.items, [ siteId, statType, serializedQuery ], null );
}
/**
* Returns a parsed object of statsStreak data for a given query, or default "empty" object
* if no statsStreak data has been received for that site.
*
* @param {object} state Global state tree
* @param {number} siteId Site ID
* @param {object} query Stats query object
* @param {?number} query.gmtOffset GMT offset of the queried site
* @returns {object} Parsed Data for the query
*/
export const getSiteStatsPostStreakData = treeSelect(
( state, siteId, query ) => [ getSiteStatsForQuery( state, siteId, 'statsStreak', query ) ],
( [ streakData ], siteId, query ) => {
const gmtOffset = query.gmtOffset || 0;
const response = {};
// ensure streakData.data exists and it is not an array
if ( streakData && streakData.data && ! isArray( streakData.data ) ) {
Object.keys( streakData.data ).forEach( timestamp => {
const postDay = moment.unix( timestamp );
const datestamp = postDay.utcOffset( gmtOffset ).format( 'YYYY-MM-DD' );
if ( 'undefined' === typeof response[ datestamp ] ) {
response[ datestamp ] = 0;
}
response[ datestamp ] += streakData.data[ timestamp ];
} );
const getPostMapByPostKey = treeSelect(
state => [ state.reader.posts.items ],
( [ posts ] ) => keyBy( posts, post => keyToString( keyForPost( post ) ) )
);
export const getPostByKey = ( state, postKey ) => {
if ( ! postKey || ! keyToString( postKey ) ) {
return null;
}
const postMap = getPostMapByPostKey( state );
return postMap[ keyToString( postKey ) ];
};
export const getPostsByKeys = treeSelect(
state => [ getPostMapByPostKey( state ) ],
( [ postMap ], postKeys ) => {
if ( ! postKeys || some( postKeys, postKey => ! keyToString( postKey ) ) ) {
return null;
}
return postKeys.map( keyToString ).map( key => postMap[ key ] );
},
{ getCacheKey: postKeys => postKeys.map( keyToString ).join() }
);
export const hasPostBeenSeen = ( state, globalId ) =>
!! get( state, [ 'reader', 'posts', 'seen', globalId ] );
* @return {?Number} The number of invites found for the given site
*/
export function getNumberOfInvitesFoundForSite( state, siteId ) {
return state.invites.counts[ siteId ] || null;
}
/**
* Returns an invite object for the given site and invite ID, or `null` if no
* invite with the given ID exists for the site.
*
* @param {Object} state Global state tree
* @param {Number} siteId Site ID
* @param {String} inviteId Invite ID
* @return {?Object} Invite object (if found)
*/
export const getInviteForSite = treeSelect(
( state, siteId ) => [ state.invites.items[ siteId ] ],
( [ siteInvites ], siteId, inviteId ) => {
if ( ! siteInvites ) {
return null;
}
return (
find( siteInvites.pending, { key: inviteId } ) ||
find( siteInvites.accepted, { key: inviteId } ) ||
null
);
}
);
/**
* Returns true if currently requesting an invite resend for the given site and
* invite ID, or false otherwise.
haveEarlierCommentsToFetch: fetchStatus.before && hasMoreComments,
haveLaterCommentsToFetch: fetchStatus.after && hasMoreComments,
hasReceivedBefore: fetchStatus.hasReceivedBefore,
hasReceivedAfter: fetchStatus.hasReceivedAfter,
};
};
/***
* Gets likes stats for the comment
* @param {Object} state redux state
* @param {Number} siteId site identification
* @param {Number} postId site identification
* @param {Number} commentId comment identification
* @return {Object} that has i_like and like_count props
*/
export const getCommentLike = treeSelect(
( state, siteId, postId ) => [ getPostCommentItems( state, siteId, postId ) ],
( [ comments ], siteId, postId, commentId ) => {
const comment = find( comments, { ID: commentId } );
if ( ! comment ) {
return undefined;
}
const { i_like, like_count } = comment;
return { i_like, like_count };
}
);
const dateTimestamp = date.getTime() / 1000;
const postCommentsAtDate = filter( postComments, postComment => {
return Date.parse( postComment.date ) / 1000 === dateTimestamp;
} );
return size( postCommentsAtDate );
};
/***
* Get most recent comment date for a given post
* @param {Object} state redux state
* @param {Number} siteId site identification
* @param {Number} postId site identification
* @return {Date} most recent comment date
*/
export const getPostNewestCommentDate = treeSelect(
( state, siteId, postId ) => [ getPostCommentItems( state, siteId, postId ) ],
( [ comments ] ) => {
const firstContiguousComment = find( comments, 'contiguous' );
return firstContiguousComment ? new Date( get( firstContiguousComment, 'date' ) ) : undefined;
}
);
/***
* Get oldest comment date for a given post
* @param {Object} state redux state
* @param {Number} siteId site identification
* @param {Number} postId site identification
* @return {Date} earliest comment date
*/
export const getPostOldestCommentDate = treeSelect(
( state, siteId, postId ) => [ getPostCommentItems( state, siteId, postId ) ],
*/
import treeSelect from '@automattic/tree-select';
import { fetchStatusInitialState } from './reducer';
import { getStateKey, deconstructStateKey, getErrorKey } from './utils';
/***
* Gets comment items for post
* @param {Object} state redux state
* @param {Number} siteId site identification
* @param {Number} postId site identification
* @return {Array} comment items
*/
export const getPostCommentItems = ( state, siteId, postId ) =>
get( state.comments.items, `${ siteId }-${ postId }` );
export const getDateSortedPostComments = treeSelect(
( state, siteId, postId ) => [ getPostCommentItems( state, siteId, postId ) ],
( [ comments ] ) => {
return sortBy( comments, comment => new Date( comment.date ) );
}
);
export const getCommentById = ( { state, commentId, siteId } ) => {
const errorKey = getErrorKey( siteId, commentId );
if ( get( state, 'comments.errors', {} )[ errorKey ] ) {
return state.comments.errors[ errorKey ];
}
const commentsForSite = flatMap(
filter( get( state, 'comments.items', [] ), ( comment, key ) => {
return deconstructStateKey( key ).siteId === siteId;
} )
*/
import treeSelect from '@automattic/tree-select';
import { keyToString, keyForPost } from 'reader/post-key';
/**
* Returns a single post.
*
* @param {Object} state Global state tree
* @param {String} postGlobalId Post global ID
* @return {Object} Post
*/
export function getPostById( state, postGlobalId ) {
return state.reader.posts.items[ postGlobalId ];
}
const getPostMapByPostKey = treeSelect(
state => [ state.reader.posts.items ],
( [ posts ] ) => keyBy( posts, post => keyToString( keyForPost( post ) ) )
);
export const getPostByKey = ( state, postKey ) => {
if ( ! postKey || ! keyToString( postKey ) ) {
return null;
}
const postMap = getPostMapByPostKey( state );
return postMap[ keyToString( postKey ) ];
};
export const getPostsByKeys = treeSelect(
state => [ getPostMapByPostKey( state ) ],
( [ postMap ], postKeys ) => {
{
getCacheKey: ( siteId, query ) => [ siteId, getSerializedStatsQuery( query ) ].join(),
}
);
/**
* Returns normalized stats data for a given query and stat type, or the un-normalized response
* from the API if no normalizer method for that stats type exists in ./utils
*
* @param {object} state Global state tree
* @param {number} siteId Site ID
* @param {string} statType Type of stat
* @param {object} query Stats query object
* @returns {*} Normalized Data for the query, typically an array or object
*/
export const getSiteStatsNormalizedData = treeSelect(
( state, siteId, statType, query ) => [
getSiteStatsForQuery( state, siteId, statType, query ),
getSite( state, siteId ),
],
( [ siteStats, site ], siteId, statType, query ) => {
const normalizer = normalizers[ statType ];
if ( typeof normalizer !== 'function' ) {
return siteStats;
}
return normalizer( siteStats, query, siteId, site );
},
{
getCacheKey: ( siteId, statType, query ) =>
[ siteId, statType, getSerializedStatsQuery( query ) ].join(),
}
);
children: parentToChildIdMap[ item.ID ] || [],
} );
const commentsByIdMap = keyBy( map( items, transformItemToNode ), 'data.ID' );
return {
...commentsByIdMap,
children: map( roots, root => root.ID ).reverse(),
};
}
);
export const getExpansionsForPost = ( state, siteId, postId ) =>
state.comments.expansions[ getStateKey( siteId, postId ) ];
export const getHiddenCommentsForPost = treeSelect(
( state, siteId, postId ) => [
getPostCommentItems( state, siteId, postId ),
getExpansionsForPost( state, siteId, postId ),
],
( [ comments, expanded ] ) => {
const commentsById = keyBy( comments, 'ID' );
return pickBy( commentsById, comment => ! get( expanded, comment.ID ) );
}
);
export const commentsFetchingStatus = ( state, siteId, postId, commentTotal = 0 ) => {
const fetchStatus = get(
state.comments.fetchStatus,
getStateKey( siteId, postId ),
fetchStatusInitialState