diff --git a/.eslintrc.js b/.eslintrc.js index 72258ad..5304585 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -22,11 +22,22 @@ module.exports = { 'max-lines-per-function': ['error', 250], 'no-else-return': 'error', 'max-params': ['error', 4], + 'require-jsdoc': [ + 'error', + { + require: { + FunctionDeclaration: true, + MethodDefinition: false, + ClassDeclaration: false, + ArrowFunctionExpression: false, + FunctionExpression: false + } + } + ], 'no-shadow': 'error', complexity: ['error', 5], 'no-empty': 'error', 'import/order': ['error', { groups: [['builtin', 'external', 'internal', 'parent', 'sibling', 'index']] }], - // 'immutable/no-this': 2, 'eslint-comments/no-use': 0 }, globals: { diff --git a/app/components/Clickable/index.js b/app/components/Clickable/index.js index 2fb3a26..7e56ec4 100644 --- a/app/components/Clickable/index.js +++ b/app/components/Clickable/index.js @@ -15,6 +15,12 @@ const StyledClickable = styled.div` cursor: pointer; } `; + +/** + * A component that can be clicked + * @param {function} onClick - The function to call when the component is clicked + * @param {string} textId - The id of the text to display + */ function Clickable({ onClick, textId }) { return ( diff --git a/app/components/Meta/index.js b/app/components/Meta/index.js index 33b0029..522983b 100644 --- a/app/components/Meta/index.js +++ b/app/components/Meta/index.js @@ -10,6 +10,12 @@ import PropTypes from 'prop-types'; import { useIntl } from 'react-intl'; import favicon from '@images/favicon.ico'; +/** + * The Meta component + * @param {string} title - The title of the page + * @param {string} description - The description of the page + * @param {boolean} useTranslation - Whether to use translation for the title and description + */ function Meta({ title, description, useTranslation }) { const intl = useIntl(); diff --git a/app/components/Text/index.js b/app/components/Text/index.js index d25bd60..3926204 100644 --- a/app/components/Text/index.js +++ b/app/components/Text/index.js @@ -17,6 +17,17 @@ const StyledText = styled.span` ${(props) => props.fontweight}; ${(props) => props.styles}; `; + +/** + * A component for displaying text + * @param {string} id - The id of the text to display + * @param {string} text - The text to display + * @param {object} values - The values to pass to the text + * @param {string} color - The color of the text + * @param {string} fontWeight - The font weight of the text + * @param {string} fontSize - The font size of the text + * @param {string} display - The display type of the text + */ function Text({ id = 'default', text, values = {}, children, color, fontWeight, fontSize, ...props }) { return ( diff --git a/app/components/Title/index.js b/app/components/Title/index.js index a3f3704..65addd2 100644 --- a/app/components/Title/index.js +++ b/app/components/Title/index.js @@ -11,6 +11,14 @@ import { StarOutlined } from '@ant-design/icons'; import Text from '@app/components/Text/index'; import fonts from '@app/themes/fonts'; +/** + * The title of the info container + * @param {object} props The component props + * @param {string} props.name The name of the repo + * @param {boolean} props.loading Whether the data is loading + * @param {number} props.stargazersCount The number of stargazers + * @returns {JSX.Element} The title of the info container + */ function Title(props) { const { name, loading, stargazersCount } = props; const headingStyle = fonts.style.heading(); diff --git a/app/configureStore.js b/app/configureStore.js index 7c693ca..c24b819 100644 --- a/app/configureStore.js +++ b/app/configureStore.js @@ -8,6 +8,12 @@ import { createWrapper } from 'next-redux-wrapper'; import createReducer from './reducers'; +/** + * + * @param {object} initialState The initial state + * @returns {object} The store + * + */ export default function configureStore(initialState = {}) { let composeEnhancers = compose; const reduxSagaMonitorOptions = {}; diff --git a/app/containers/Info/index.js b/app/containers/Info/index.js index 6ee9d4b..17f6dca 100644 --- a/app/containers/Info/index.js +++ b/app/containers/Info/index.js @@ -22,6 +22,16 @@ import { infoCreators } from './reducer'; import saga from './saga'; import { selectInfoData, selectInfoLoading } from './selectors'; +/** + * The Info container + * @param {object} props The component props + * @param {object} props.details The details of the repo + * @param {object} props.params The params from the route + * @param {boolean} props.loading Whether the data is loading + * @param {function} props.dispatchRequestInfo The function to request the info + * @param {object} props.fallBackDetails The details to fall back on + * @returns {JSX.Element} The Info container + */ export function Info({ details, params, loading, dispatchRequestInfo, fallBackDetails }) { const router = useRouter(); const { query } = router; @@ -74,6 +84,11 @@ const mapStateToProps = createStructuredSelector({ fallBackDetails: selectInfoData() }); +/** + * The mapDispatchToProps + * @param {function} dispatch The dispatch function + * @returns {object} The props + */ function mapDispatchToProps(dispatch) { return { dispatchRequestInfo: (repo, owner) => dispatch(infoCreators.requestInfo(repo, owner)) diff --git a/app/containers/Info/saga.js b/app/containers/Info/saga.js index 5865a0b..fd22122 100644 --- a/app/containers/Info/saga.js +++ b/app/containers/Info/saga.js @@ -3,6 +3,13 @@ import { getRepo } from '@services/info'; import { ERRORS } from '@app/utils/constants'; import { infoTypes, infoCreators, INFO_PAYLOAD } from './reducer'; +/** + * Request info from the API + * @param {object} action + * @param {string} action[INFO_PAYLOAD.REPO] - The name of the repository + * @param {string} action[INFO_PAYLOAD.OWNER] - The owner of the repository + * @returns {object} - The response from the API + */ export function* requestInfo(action) { try { if (!action[INFO_PAYLOAD.REPO] || !action[INFO_PAYLOAD.OWNER]) { @@ -16,6 +23,10 @@ export function* requestInfo(action) { } } +/** + * The root of the info saga + * @returns {void} + */ export default function* appSaga() { yield takeLatest(infoTypes.REQUEST_INFO, requestInfo); } diff --git a/app/containers/Repos/index.js b/app/containers/Repos/index.js index e6ba357..fc83dbb 100644 --- a/app/containers/Repos/index.js +++ b/app/containers/Repos/index.js @@ -25,6 +25,19 @@ import { reposActionCreators } from './reducer'; import saga from './saga'; import { selectReposData, selectReposError, selectReposSearchKey } from './selectors'; +/** + * The Repos container + * @param {object} props The component props + * @param {object} props.intl The intl object + * @param {string} props.searchKey The search key + * @param {object} props.repos The repos data + * @param {string} props.error The error message + * @param {boolean} props.loading Whether the data is loading + * @param {object} props.recommendations The list of recommendations + * @param {function} props.dispatchGetGithubRepos The function to get the github repos + * @param {function} props.dispatchClearGithubRepos The function to clear the github repos + * @returns {JSX.Element} The Repos container + */ export function Repos({ intl, repos, @@ -111,6 +124,11 @@ const mapStateToProps = createStructuredSelector({ searchKey: selectReposSearchKey() }); +/** + * The mapDispatchToProps + * @param {function} dispatch The dispatch function + * @returns {object} The props + */ function mapDispatchToProps(dispatch) { const { requestGetGithubRepos, clearGithubRepos } = reposActionCreators; return { diff --git a/app/containers/Repos/saga.js b/app/containers/Repos/saga.js index c0c51fe..c74f29e 100644 --- a/app/containers/Repos/saga.js +++ b/app/containers/Repos/saga.js @@ -5,6 +5,12 @@ import { reposActionTypes, reposActionCreators, REPOS_PAYLOAD } from './reducer' const { REQUEST_GET_GITHUB_REPOS } = reposActionTypes; const { successGetGithubRepos, failureGetGithubRepos } = reposActionCreators; +/** + * Get the github repos + * @param {object} action + * @param {string} action[REPOS_PAYLOAD.SEARCH_KEY] - The search key + * @returns {object} - The response from the API + */ export function* getGithubRepos(action) { const response = yield call(getRepos, action[REPOS_PAYLOAD.SEARCH_KEY]); const { data, ok } = response; @@ -15,6 +21,11 @@ export function* getGithubRepos(action) { } } +/** + * The root of the repos saga + * @returns {void} + * @yields {object} - The response from the API + */ export default function* appSaga() { yield takeLatest(REQUEST_GET_GITHUB_REPOS, getGithubRepos); } diff --git a/app/reducers.js b/app/reducers.js index 7592723..eb74141 100644 --- a/app/reducers.js +++ b/app/reducers.js @@ -10,6 +10,9 @@ import info from './containers/Info/reducer'; enableAllPlugins(); +/** + * Merges the main reducer with the router state and dynamically injected reducers + */ export default function createReducer(injectedReducer = {}) { const rootReducer = combineReducers({ ...injectedReducer, diff --git a/app/utils/index.js b/app/utils/index.js index 852c625..1ee08a5 100644 --- a/app/utils/index.js +++ b/app/utils/index.js @@ -1,6 +1,11 @@ import pickBy from 'lodash/pickBy'; import { screenSizes } from '@themes/media'; +/** + * Get query string value + * @param {array} keys - The keys to get the value of + * @returns {object} - The query string value + */ export function getQueryStringValue(keys) { const queryString = {}; try { diff --git a/app/utils/sagaInjectors.js b/app/utils/sagaInjectors.js index 3c2cbac..01df7ba 100644 --- a/app/utils/sagaInjectors.js +++ b/app/utils/sagaInjectors.js @@ -17,6 +17,12 @@ const checkDescriptor = (descriptor) => { invariant(conformsTo(descriptor, shape), '(app/utils...) injectSaga: Expected a valid saga descriptor'); }; +/** + * Validate the saga, mode and key + * @param {object} descriptor The saga descriptor + * @param {string} key The saga key + * @param {object} saga The saga + */ export function injectSagaFactory(store, isValid) { const updateHasSagaInDevelopment = (hasSaga, key, saga) => { const oldDescriptor = store.injectedSagas[key]; @@ -66,7 +72,18 @@ export function injectSagaFactory(store, isValid) { }; } +/** + * Eject the saga + * @param {string} key The saga key + * @param {object} store The redux store + * @param {boolean} isValid If the store is valid + */ export function ejectSagaFactory(store, isValid) { + /** + * Clean up the store + * @param {string} key The saga key + * @returns {void} + */ function updateStoreSaga(key) { // Clean up in production; in development we need `descriptor.saga` for hot reloading if (process.env.NODE_ENV === 'production') { @@ -94,6 +111,10 @@ export function ejectSagaFactory(store, isValid) { }; } +/** + * Get the injectors + * @param {object} store The redux store + */ export default function getInjectors(store) { checkStore(store); return { diff --git a/pages/index.js b/pages/index.js index e79c661..28645f5 100644 --- a/pages/index.js +++ b/pages/index.js @@ -2,6 +2,10 @@ import PropTypes from 'prop-types'; import Repos from '@app/containers/Repos/index'; import { getReccomendations } from '@services/root'; +/** + * Get the list of recommendations + * @returns {object} The list of recommendations + */ export async function getStaticProps() { const recommendations = await getReccomendations(); return { @@ -11,6 +15,11 @@ export async function getStaticProps() { }; } +/** + * The ReposPage component + * @param {object} props The component props + * @param {object} props.recommendations The list of recommendations + */ export function ReposPage({ recommendations = [] }) { return ; } diff --git a/pages/info/[name].js b/pages/info/[name].js index 68c8178..e148644 100644 --- a/pages/info/[name].js +++ b/pages/info/[name].js @@ -6,6 +6,15 @@ const RepoInfo = ({ details }) => ; export default RepoInfo; +/** + * Get the details of the repo + * @param {object} props The component props + * @param {object} props.params The route parameters + * @returns {object} The details of the repo + * @returns {string} The details.name The name of the repo + * @returns {string} The details.description The description of the repo + * @returns {number} The details.stargazersCount The number of stargazers + */ export async function getStaticProps(props) { const { params: { name } @@ -18,6 +27,10 @@ export async function getStaticProps(props) { }; } +/** + * Get the list of recommendations + * @returns {object} The list of recommendations + */ export async function getStaticPaths() { const recommendations = await getReccomendations(); // * param value should be a string