Skip to content

Instantly share code, notes, and snippets.

@martin056
Last active August 28, 2017 14:25
Show Gist options
  • Save martin056/ecbde18139bbc46a15c89f6a6115e5a4 to your computer and use it in GitHub Desktop.
Save martin056/ecbde18139bbc46a15c89f6a6115e5a4 to your computer and use it in GitHub Desktop.
Bash script that generates containers for Redux apps. The directories it uses are not configurable at the moment - if you have user `create-react-app` it will work for you.
#!/bin/bash
# USAGE (cd utility/ first!): ./create_container.sh -n <CONTAINER_NAME> -a <ACTION_1> (-a <ACTION_2>...)
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'
SRC_PATH=../src
CONTAINERS_PATH=${SRC_PATH}/containers
GLOBAL_REDUCER_FILE=${SRC_PATH}/global-reducer.jsx
function join_by {
# function that joins the given array by the splitter given.
local IFS="$1"; shift; echo "$*";
}
# Get the arguments
while getopts ":n:a:" opt; do
case $opt in
n) CONTAINER_NAME="$OPTARG";;
a) ACTIONS+=($OPTARG);;
\?) echo "${RED}Invalid option -$OPTARG ${NC}" >&2;;
esac
done
shift $((OPTIND -1))
# Uppercase all actions
ACTIONS_UPPERCASED=()
if [[ ${#ACTIONS[@]} = 0 ]]; then
echo "No actions provided..."
else
for ACTION in "${ACTIONS[@]}"; do
ACTION_NAME=$(echo "${ACTION}" | tr '[:lower:]' '[:upper:]')
ACTIONS_UPPERCASED=("${ACTIONS_UPPERCASED[@]}" "${ACTION_NAME}")
done
fi
# Check if the container starts with Uppercase
re='[A-Z]'
if [[ ${CONTAINER_NAME::1} =~ $re ]]; then
echo -e "${GREEN}Container ${CONTAINER_NAME} will be generated...${NC}"
else
echo -e "${RED}Containers must start with Uppercase!${NC}"
exit 99
fi
# Generate files
CONTAINER_DIR_PATH=${CONTAINERS_PATH}/${CONTAINER_NAME}
mkdir ${CONTAINER_DIR_PATH}
touch ${CONTAINER_DIR_PATH}/component.jsx \
${CONTAINER_DIR_PATH}/reducer.jsx \
${CONTAINER_DIR_PATH}/actions.jsx \
${CONTAINER_DIR_PATH}/constants.js \
${CONTAINER_DIR_PATH}/sagas.jsx \
${CONTAINER_DIR_PATH}/services.jsx
# Generate initial code for component
COMPONENT=${CONTAINER_DIR_PATH}/component.jsx
COMPONENT_CONFIG=$( cat <<SETVAR
import React from 'react';
import { connect } from 'react-redux';
export class ${CONTAINER_NAME} extends React.Component {
constructor(props) {
super(props);
}
render() {
return ()
}
};
export default connect()(${CONTAINER_NAME});
SETVAR
)
echo -e "${COMPONENT_CONFIG}" > ${COMPONENT}
# Generate initial code for reducer
REDUCER=${CONTAINER_DIR_PATH}/reducer.jsx
# Lower the first letter of the component
CONTAINER_LOWER_FIRST_LETTER="$(echo ${CONTAINER_NAME::1} | tr [:upper:] [:lower:])"${CONTAINER_NAME:1}
REDUCER_NAME=${CONTAINER_LOWER_FIRST_LETTER}"Reducer" # <GivenName> -> <givenName>Reducer
ACTIONS_STRING=$(join_by , "${ACTIONS_UPPERCASED[@]}") # ACTION_1,ACTION_2,ACTION_3...
ACTION_CASES=()
for ACTION in "${ACTIONS_UPPERCASED[@]}"; do
ACTION_CASE=$( cat <<SETVAR
case ${ACTION}:
return {
// Object.assign({}, state, ...)
};\n
SETVAR
)
ACTION_CASES=("${ACTION_CASES[@]}""${ACTION_CASE}")
done
REDUCER_CONFIG=$( cat <<SETVAR
import { ${ACTIONS_STRING} } from './constants';
const ${REDUCER_NAME} = (state = {}, action) => {
switch(action.type) {
${ACTION_CASES[@]}
default:
return state;
}
};
export default ${REDUCER_NAME};
SETVAR
)
echo -e "${REDUCER_CONFIG}" > ${REDUCER}
REDUCER_PATH="'"./containers/${CONTAINER_NAME}/reducer"'" # think of better way to do this!
# Import the new reducer in the global reducer
echo -e "$(awk -v reducer="${REDUCER_NAME}" \
-v reducer_path="${REDUCER_PATH}" \
'/import '"{"' combineReducers '"}"' from/ { print; print "import "'"reducer"'" from "'"reducer_path"'";"; next }1' \
${GLOBAL_REDUCER_FILE})" > ${GLOBAL_REDUCER_FILE}
# Add the new reducer to the global reducer
echo -e "$(awk -v container="${CONTAINER_LOWER_FIRST_LETTER}" \
-v reducer="${REDUCER_NAME}" \
'/const appReducer = combineReducers/ { print; print " "'"container"'": "'"reducer"'","; next }1' \
${GLOBAL_REDUCER_FILE})" > ${GLOBAL_REDUCER_FILE}
# Add the actions to the constants file
CONSTANTS_FILE=${CONTAINER_DIR_PATH}/constants.js
for ACTION in "${ACTIONS_UPPERCASED[@]}"; do
echo -e "export const ${ACTION} = '${ACTION}';" >> ${CONSTANTS_FILE}
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment