Add PropTypes verifications to all components

1) to help me when I screw up and 2) to have a clearly laid out but
still useful way of knowing what props a component can accept!
This commit is contained in:
Robbie Antenesse 2017-11-15 13:59:58 -07:00
parent 316fe07dbe
commit 43d2d48b27
20 changed files with 258 additions and 49 deletions

View File

@ -52,6 +52,7 @@
"inferno-devtools": "^3.10.1",
"marked": "^0.3.6",
"papaparse": "^4.3.3",
"prop-types": "^15.6.0",
"sanitize-html": "^1.14.1",
"store": "^2.0.12",
"sweetalert2": "^6.11.5"

View File

@ -1,4 +1,5 @@
import Inferno from 'inferno';
import PropTypes from 'prop-types';
import { LeftColumn } from './structure/LeftColumn';
import { RightColumn } from './structure/RightColumn';
@ -7,7 +8,16 @@ import { WordForm } from './management/WordForm';
import { DictionaryDetails } from './display/DictionaryDetails';
import { WordsList } from './display/WordsList';
export const MainDisplay = ({ dictionaryInfo, wordsToDisplay, updateDisplay, updater, lastRender }) => {
export const MainDisplay = (props) => {
PropTypes.checkPropTypes({
dictionaryInfo: PropTypes.object.isRequired,
wordsToDisplay: PropTypes.array.isRequired,
updateDisplay: PropTypes.func.isRequired,
updater: PropTypes.object.isRequired,
}, props, 'prop', 'MainDisplay');
const { dictionaryInfo, wordsToDisplay, updateDisplay, updater } = props;
return (
<section className='section'>
<div className='container'>
@ -15,7 +25,7 @@ export const MainDisplay = ({ dictionaryInfo, wordsToDisplay, updateDisplay, upd
<LeftColumn>
<WordForm
updateDisplay={ () => updateDisplay() }
updateDisplay={ updateDisplay }
/>
</LeftColumn>
@ -31,7 +41,6 @@ export const MainDisplay = ({ dictionaryInfo, wordsToDisplay, updateDisplay, upd
/>
<WordsList
lastRender={ lastRender }
words={ wordsToDisplay }
adsEveryXWords={ 10 }
updateDisplay={ updateDisplay } />

View File

@ -1,9 +1,13 @@
import Inferno from 'inferno';
import PropTypes from 'prop-types';
export const GeneralDisplay = ({
partsOfSpeech,
alphabeticalOrder,
}) => {
export const GeneralDisplay = (props) => {
PropTypes.checkPropTypes({
partsOfSpeech: PropTypes.array.isRequired,
alphabeticalOrder: PropTypes.array.isRequired,
}, props, 'prop', 'GeneralDisplay');
const { partsOfSpeech, alphabeticalOrder } = props;
return (
<div>
<div className='columns'>

View File

@ -1,10 +1,14 @@
import Inferno from 'inferno';
import PropTypes from 'prop-types';
import marked from 'marked';
import sanitizeHtml from 'sanitize-html';
export const OrthographyDisplay = ({
orthographyContent,
}) => {
export const OrthographyDisplay = (props) => {
PropTypes.checkPropTypes({
orthographyContent: PropTypes.object.isRequired,
}, props, 'prop', 'OrthographyDisplay');
const { orthographyContent } = props
return (
<div>
<div className='columns'>

View File

@ -1,8 +1,14 @@
import Inferno from 'inferno';
import PropTypes from 'prop-types';
import marked from 'marked';
import sanitizeHtml from 'sanitize-html';
export const PhonologyDisplay = ({ phonologyContent }) => {
export const PhonologyDisplay = (props) => {
PropTypes.checkPropTypes({
phonologyContent: PropTypes.object.isRequired,
}, props, 'prop', 'PhonologyDisplay');
const { phonologyContent } = props;
return (
<div>
<h4 className='title is-4'>

View File

@ -1,5 +1,6 @@
import Inferno from 'inferno';
import Component from 'inferno-component';
import PropTypes from 'prop-types';
import marked from 'marked';
import sanitizeHtml from 'sanitize-html';
@ -9,17 +10,16 @@ import { GeneralDisplay } from './GeneralDisplay';
import { PhonologyDisplay } from './PhonologyDisplay';
import { OrthographyDisplay } from './OrthographyDisplay';
const DISPLAY = {
NONE: false,
DESCRIPTION: 1,
DETAILS: 2,
STATS: 3,
}
export class DetailsSection extends Component {
constructor (props) {
super(props);
PropTypes.checkPropTypes({
details: PropTypes.object.isRequired,
partsOfSpeech: PropTypes.array.isRequired,
alphabeticalOrder: PropTypes.array.isRequired,
}, props, 'prop', 'DetailsSection');
this.defaultMenuItems = [
'General',
'Phonology',

View File

@ -1,5 +1,6 @@
import Inferno from 'inferno';
import Component from 'inferno-component';
import PropTypes from 'prop-types';
import marked from 'marked';
import sanitizeHtml from 'sanitize-html';
@ -19,6 +20,16 @@ export class DictionaryDetails extends Component {
constructor (props) {
super(props);
PropTypes.checkPropTypes({
name: PropTypes.string,
specification: PropTypes.string,
description: PropTypes.string,
partsOfSpeech: PropTypes.array,
alphabeticalOrder: PropTypes.array,
details: PropTypes.object,
updater: PropTypes.object,
}, props, 'prop', 'DictionaryDetails');
this.state = {
currentDisplay: DISPLAY.NONE,
}

View File

@ -1,5 +1,6 @@
import Inferno from 'inferno';
import Component from 'inferno-component';
import PropTypes from 'prop-types';
import marked from 'marked';
import swal from 'sweetalert2';
@ -14,6 +15,11 @@ export class WordDisplay extends Component {
constructor (props) {
super(props);
PropTypes.checkPropTypes({
word: PropTypes.object.isRequired,
updateDisplay: PropTypes.func.isRequired,
}, props, 'prop', 'WordDisplay');
this.state = {
menuIsOpen: false,
isEditing: false,

View File

@ -1,5 +1,6 @@
import Inferno from 'inferno';
import Component from 'inferno-component';
import PropTypes from 'prop-types';
import marked from 'marked';
// npm lazyload-inferno-component uses outdated inferno dependencies, so just using the script.
@ -19,6 +20,12 @@ const loadAd = (callback, { props, router }) => {
export class WordsList extends Component {
constructor (props) {
super(props);
PropTypes.checkPropTypes({
adsEveryXWords: PropTypes.number,
words: PropTypes.array,
updateDisplay: PropTypes.func.isRequired,
}, props, 'prop', 'WordList');
}
render () {

View File

@ -1,12 +1,20 @@
import Inferno from 'inferno';
import PropTypes from 'prop-types';
export const EditDictionaryForm = ({
editDictionaryModal,
name,
specification,
description,
alphabeticalOrder,
}) => {
export const EditDictionaryForm = (props) => {
PropTypes.checkPropTypes({
editDictionaryModal: PropTypes.object.isRequired,
name: PropTypes.string.isRequired,
specification: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
}, props, 'prop', 'EditDictionaryForm');
const {
editDictionaryModal,
name,
specification,
description,
} = props;
return (
<div className='form'>
<div className='field'>

View File

@ -1,19 +1,34 @@
import Inferno from 'inferno';
import PropTypes from 'prop-types';
import { IPAField } from '../IPAField';
export const EditLinguisticsForm = ({
editDictionaryModal,
partsOfSpeech,
consonants,
vowels,
blends,
onset,
nucleus,
coda,
exceptions,
orthographyNotes,
}) => {
export const EditLinguisticsForm = (props) => {
PropTypes.checkPropTypes({
editDictionaryModal: PropTypes.object.isRequired,
partsOfSpeech: PropTypes.string.isRequired,
consonants: PropTypes.string.isRequired,
vowels: PropTypes.string.isRequired,
blends: PropTypes.string.isRequired,
onset: PropTypes.string.isRequired,
nucleus: PropTypes.string.isRequired,
coda: PropTypes.string.isRequired,
exceptions: PropTypes.string.isRequired,
orthographyNotes: PropTypes.string.isRequired,
}, props, 'prop', 'EditLinguisticsForm');
const {
editDictionaryModal,
partsOfSpeech,
consonants,
vowels,
blends,
onset,
nucleus,
coda,
exceptions,
orthographyNotes,
} = props;
return (
<div className='form'>
<div className='field'>

View File

@ -1,5 +1,6 @@
import Inferno from 'inferno';
import Component from 'inferno-component';
import PropTypes from 'prop-types';
import marked from 'marked';
import { Modal } from '../../structure/Modal';
@ -17,6 +18,15 @@ export class EditDictionaryModal extends Component {
constructor (props) {
super(props);
PropTypes.checkPropTypes({
name: PropTypes.string,
specification: PropTypes.string,
description: PropTypes.string,
alphabeticalOrder: PropTypes.array,
partsOfSpeech: PropTypes.array,
details: PropTypes.object,
}, props, 'prop', 'EditDictionaryModal');
this.state = {
currentDisplay: DISPLAY.DETAILS,

View File

@ -1,5 +1,6 @@
import Inferno from 'inferno';
import Component from 'inferno-component';
import PropTypes from 'prop-types';
const phondueUsage = require('../../../vendor/KeyboardFire/phondue/usage.html');
const digraphs = require('../../../vendor/KeyboardFire/phondue/digraphs.json');
@ -14,6 +15,17 @@ export class IPAField extends Component {
constructor (props) {
super(props);
PropTypes.checkPropTypes({
value: PropTypes.string.isRequired,
id: PropTypes.string,
label: PropTypes.string,
helpText: PropTypes.string,
placeholder: PropTypes.string,
isDisplayOnly: PropTypes.bool,
onInput: PropTypes.func,
onChange: PropTypes.func,
}, props, 'prop', 'IPAField');
this.state = {
value: props.value || '',
doShowHelp: false,

View File

@ -1,16 +1,25 @@
import Inferno from 'inferno';
import PropTypes from 'prop-types';
import {IPAField} from './IPAField';
export const IPATable = ({
value,
close,
update
}) => {
export const IPATable = (values) => {
PropTypes.checkPropTypes({
value: PropTypes.string.isRequired,
close: PropTypes.func.isRequired,
update: PropTypes.func.isRequired,
}, values, 'value', 'IPATable');
/*
Modified from KeyboardFire's Phondue project (https://github.com/KeyboardFire/phondue)
to fit React/Inferno and Lexiconga
*/
const {
value,
close,
update
} = values;
const updateInput = (newValue) => {
update(value + newValue);
}

View File

@ -1,5 +1,6 @@
import Inferno from 'inferno';
import Component from 'inferno-component';
import PropTypes from 'prop-types';
import './styles.scss';
@ -11,6 +12,11 @@ export class SearchBox extends Component {
constructor (props) {
super(props);
PropTypes.checkPropTypes({
partsOfSpeech: PropTypes.array,
search: PropTypes.func.isRequired,
}, props, 'prop', 'SearchBox');
this.state = {
searchingIn: 'name',
searchMethod: METHOD.contains,

View File

@ -1,5 +1,6 @@
import Inferno from 'inferno';
import Component from 'inferno-component';
import PropTypes from 'prop-types';
import dictionaryData from '../../managers/DictionaryData';
import { IPAField } from './IPAField';
@ -9,6 +10,12 @@ export class WordForm extends Component {
constructor (props) {
super(props);
PropTypes.checkPropTypes({
word: PropTypes.object,
callback: PropTypes.func,
updateDisplay: PropTypes.func,
}, props, 'prop', 'WordForm');
this.state = {
wordName: props.word ? props.word.name : '',
wordPronunciation: props.word ? props.word.pronunciation : '',

View File

@ -1,5 +1,6 @@
import Inferno from 'inferno';
import Component from 'inferno-component';
import PropTypes from 'prop-types';
import marked from 'marked';
import { Modal } from './Modal';
@ -11,6 +12,11 @@ export class Header extends Component {
constructor (props) {
super(props);
PropTypes.checkPropTypes({
partsOfSpeech: PropTypes.array.isRequired,
search: PropTypes.func.isRequired,
}, props, 'prop', 'Header');
this.state = {
displayNavMenu: false,
}
@ -27,7 +33,7 @@ export class Header extends Component {
<div className='navbar-item'>
<SearchBox
partsOfSpeech={ this.props.partsOfSpeech }
search={ (searchConfig) => this.props.search(searchConfig) } />
search={ this.props.search } />
</div>
<a className={`button navbar-burger${this.state.displayNavMenu ? ' is-active' : ''}`}

View File

@ -1,10 +1,20 @@
import Inferno from 'inferno';
import Component from 'inferno-component';
import PropTypes from 'prop-types';
export class Modal extends Component {
constructor (props) {
super(props);
PropTypes.checkPropTypes({
noButton: PropTypes.bool,
buttonText: PropTypes.string,
title: PropTypes.string,
children: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
footerAlign: PropTypes.string,
footerContent: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
}, props, 'prop', 'Modal');
this.state = {
isVisible: false,
}
@ -24,6 +34,7 @@ export class Modal extends Component {
render () {
const {
noButton,
buttonText,
title,
children,
@ -33,7 +44,7 @@ export class Modal extends Component {
return (
<div className='is-inline'>
<a className={!this.props.noButton ? 'button' : null}
<a className={!noButton ? 'button' : null}
onClick={ this.show.bind(this) }>
{ buttonText || 'Show' }
</a>

View File

@ -1,9 +1,20 @@
import assert from 'assert';
import PropTypes from 'prop-types';
import store from 'store';
import wordDb from './WordDatabase';
export class Word {
constructor (values = {}) {
PropTypes.checkPropTypes({
id: PropTypes.number,
name: PropTypes.string,
pronunciation: PropTypes.string,
partOfSpeech: PropTypes.string,
definition: PropTypes.string,
details: PropTypes.string,
createdTime: PropTypes.number,
modifiedTime: PropTypes.number,
}, values, 'value', 'Word');
const {
id = false,
name = '',

View File

@ -145,6 +145,10 @@ arrify@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
asap@~2.0.3:
version "2.0.6"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
asn1.js@^4.0.0:
version "4.9.1"
resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40"
@ -902,6 +906,10 @@ cookie@0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
core-js@^1.0.0:
version "1.2.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
core-js@^2.4.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
@ -1275,6 +1283,12 @@ encodeurl@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20"
encoding@^0.1.11:
version "0.1.12"
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
dependencies:
iconv-lite "~0.4.13"
enhanced-resolve@^3.4.0:
version "3.4.1"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e"
@ -1558,6 +1572,18 @@ faye-websocket@~0.11.0:
dependencies:
websocket-driver ">=0.5.1"
fbjs@^0.8.16:
version "0.8.16"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
dependencies:
core-js "^1.0.0"
isomorphic-fetch "^2.1.1"
loose-envify "^1.0.0"
object-assign "^4.1.0"
promise "^7.1.1"
setimmediate "^1.0.5"
ua-parser-js "^0.7.9"
file-loader@^0.11.2:
version "0.11.2"
resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.11.2.tgz#4ff1df28af38719a6098093b88c82c71d1794a34"
@ -1980,6 +2006,10 @@ https-browserify@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82"
iconv-lite@~0.4.13:
version "0.4.19"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
icss-replace-symbols@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.0.2.tgz#cb0b6054eb3af6edc9ab1d62d01933e2d4c8bfa5"
@ -2222,7 +2252,7 @@ is-primitive@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
is-stream@^1.1.0:
is-stream@^1.0.1, is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
@ -2258,6 +2288,13 @@ isobject@^2.0.0:
dependencies:
isarray "1.0.0"
isomorphic-fetch@^2.1.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
dependencies:
node-fetch "^1.0.1"
whatwg-fetch ">=0.10.0"
isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
@ -2457,7 +2494,7 @@ longest@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
loose-envify@^1.0.0:
loose-envify@^1.0.0, loose-envify@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
dependencies:
@ -2674,6 +2711,13 @@ no-case@^2.2.0:
dependencies:
lower-case "^1.1.1"
node-fetch@^1.0.1:
version "1.7.3"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
dependencies:
encoding "^0.1.11"
is-stream "^1.0.1"
node-forge@0.6.33:
version "0.6.33"
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.6.33.tgz#463811879f573d45155ad6a9f43dc296e8e85ebc"
@ -2829,7 +2873,7 @@ oauth-sign@~0.8.1:
version "0.8.2"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
object-assign@^4.0.1, object-assign@^4.1.0:
object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@ -3359,6 +3403,20 @@ process@^0.11.0:
version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
promise@^7.1.1:
version "7.3.1"
resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
dependencies:
asap "~2.0.3"
prop-types@^15.6.0:
version "15.6.0"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856"
dependencies:
fbjs "^0.8.16"
loose-envify "^1.3.1"
object-assign "^4.1.1"
proxy-addr@~1.1.4, proxy-addr@~1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.5.tgz#71c0ee3b102de3f202f3b64f608d173fcba1a918"
@ -3806,7 +3864,7 @@ set-immediate-shim@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
setimmediate@^1.0.4:
setimmediate@^1.0.4, setimmediate@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
@ -4194,6 +4252,10 @@ type-is@~1.6.15:
media-typer "0.3.0"
mime-types "~2.1.15"
ua-parser-js@^0.7.9:
version "0.7.17"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac"
uglify-js@^2.8.29:
version "2.8.29"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
@ -4422,6 +4484,10 @@ websocket-extensions@>=0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7"
whatwg-fetch@>=0.10.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
whet.extend@~0.9.9:
version "0.9.9"
resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1"