From 659c2eecc20391c9d2227b43aa4ac7bc567b85b8 Mon Sep 17 00:00:00 2001 From: Eric Schultz Date: Thu, 22 Oct 2020 14:24:14 -0500 Subject: [PATCH] Add @typescript-eslint/member-ordering to eslint --- .eslintrc.js | 83 ++++++++- app/javascript/common/money.ts | 162 +++++++++--------- .../components/formik/MoneyTextField.spec.tsx | 2 +- .../formik/MoneyTextField.stories.tsx | 2 +- .../components/tests/intl/index.tsx | 12 +- app/javascript/hooks/useSteps.spec.ts | 20 +-- app/javascript/hooks/useSteps.ts | 49 +++--- 7 files changed, 205 insertions(+), 125 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 63f3dd64..f9f4cd97 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -38,6 +38,85 @@ const tsBase = { 'plugin:@typescript-eslint/recommended', "plugin:react-hooks/recommended", ], + rules: { + '@typescript-eslint/member-ordering': ['error', + { + // this is the default from @typescript-eslint itself + "default": { + "memberTypes": [ + // Index signature + "signature", + + // Fields + "public-static-field", + "protected-static-field", + "private-static-field", + + "public-decorated-field", + "protected-decorated-field", + "private-decorated-field", + + "public-instance-field", + "protected-instance-field", + "private-instance-field", + + "public-abstract-field", + "protected-abstract-field", + "private-abstract-field", + + "public-field", + "protected-field", + "private-field", + + "static-field", + "instance-field", + "abstract-field", + + "decorated-field", + + "field", + + // Constructors + "public-constructor", + "protected-constructor", + "private-constructor", + + "constructor", + + // Methods + "public-static-method", + "protected-static-method", + "private-static-method", + + "public-decorated-method", + "protected-decorated-method", + "private-decorated-method", + + "public-instance-method", + "protected-instance-method", + "private-instance-method", + + "public-abstract-method", + "protected-abstract-method", + "private-abstract-method", + + "public-method", + "protected-method", + "private-method", + + "static-method", + "instance-method", + "abstract-method", + + "decorated-method", + + "method", + ], + "order": "alphabetically", + }, + }, + ], + }, }; const tsSettings = _.cloneDeep(tsBase); @@ -79,9 +158,9 @@ module.exports = { "always", ], "no-trailing-spaces": ["error"], - "indent": ["error", "tab", {"SwitchCase": 1}], // we use tabs for accessibility + "indent": ["error", "tab", { "SwitchCase": 1 }], // we use tabs for accessibility "comma-dangle": ["error", "always-multiline"], - "@typescript-eslint/no-unused-vars": ['error', {"args": "all", "argsIgnorePattern": "^_"}], + "@typescript-eslint/no-unused-vars": ['error', { "args": "all", "argsIgnorePattern": "^_" }], }, "settings": { "react": { diff --git a/app/javascript/common/money.ts b/app/javascript/common/money.ts index 4cef4849..240285b3 100644 --- a/app/javascript/common/money.ts +++ b/app/javascript/common/money.ts @@ -28,6 +28,13 @@ type MoneyAsJson = { amount: number, currency: string } */ export class Money { + /** + * Create a `Money` object with the given number if smallest monetary units and the ISO currency. Another name for the `fromCents` function. + * @static + * @memberof Money + */ + static fromSMU = Money.fromCents + readonly currency: string protected constructor(readonly amount: number, currency: string) { @@ -63,28 +70,6 @@ export class Money { return new Money(amount.amount, amount.currency); } - - /** - * Create a `Money` object with the given number if smallest monetary units and the ISO currency. Another name for the `fromCents` function. - * @static - * @memberof Money - */ - static fromSMU = Money.fromCents - - /** - * Returns true if the two instances of Money are equal, false otherwise. - * - * @param {Money} other - * @returns {Boolean} - */ - equals(other: Money): boolean { - - assertType(other); - - return this.amount === other.amount && - this.currency === other.currency; - } - /** * Adds the two objects together creating a new Money instance that holds the result of the operation. * @@ -99,54 +84,6 @@ export class Money { return new Money(this.amount + other.amount, this.currency); } - /** - * Subtracts the two objects creating a new Money instance that holds the result of the operation. - * - * @param {Money} other - * @returns {Money} - */ - subtract(other: Money): Money { - - assertType(other); - assertSameCurrency(this, other); - - return new Money(this.amount - other.amount, this.currency); - } - - /** - * Multiplies the object by the multiplier returning a new Money instance that holds the result of the operation. - * - * @param {number} multiplier - * @param {(x:number) => number} [fn=Math.round] - * @returns {Money} - */ - multiply(multiplier: number, roundingFunction: (x: number) => number): Money { - if (!isFunction(roundingFunction)) - roundingFunction = Math.round; - - assertOperand(multiplier); - const amount = roundingFunction(this.amount * multiplier); - - return new Money(amount, this.currency); - } - - /** - * Divides the object by the multiplier returning a new Money instance that holds the result of the operation. - * - * @param {Number} divisor - * @param {(x:number) => number} [fn=Math.round] - * @returns {Money} - */ - divide(divisor: number, fn?: (x: number) => number): Money { - if (!isFunction(fn)) - fn = Math.round; - - assertOperand(divisor); - const amount = fn(this.amount / divisor); - - return new Money(amount, this.currency); - } - /** * Allocates fund bases on the ratios provided returing an array of objects as a product of the allocation. * @@ -195,6 +132,38 @@ export class Money { return this.amount > other.amount ? 1 : -1; } + /** + * Divides the object by the multiplier returning a new Money instance that holds the result of the operation. + * + * @param {Number} divisor + * @param {(x:number) => number} [fn=Math.round] + * @returns {Money} + */ + divide(divisor: number, fn?: (x: number) => number): Money { + if (!isFunction(fn)) + fn = Math.round; + + assertOperand(divisor); + const amount = fn(this.amount / divisor); + + return new Money(amount, this.currency); + } + + + /** + * Returns true if the two instances of Money are equal, false otherwise. + * + * @param {Money} other + * @returns {Boolean} + */ + equals(other: Money): boolean { + + assertType(other); + + return this.amount === other.amount && + this.currency === other.currency; + } + /** * Checks whether the value represented by this object is greater than the other. * @@ -215,6 +184,28 @@ export class Money { return 0 <= this.compare(other); } + isNegative(): boolean { + return this.amount < 0; + } + + /** + * Returns true if the amount is positive. + * + * @returns {boolean} + */ + isPositive(): boolean { + return this.amount > 0; + } + + /** + * Returns true if the amount is zero. + * + * @returns {boolean} + */ + isZero(): boolean { + return this.amount === 0; + } + /** * Checks whether the value represented by this object is less than the other. * @@ -236,25 +227,34 @@ export class Money { } /** - * Returns true if the amount is zero. + * Multiplies the object by the multiplier returning a new Money instance that holds the result of the operation. * - * @returns {boolean} + * @param {number} multiplier + * @param {(x:number) => number} [fn=Math.round] + * @returns {Money} */ - isZero(): boolean { - return this.amount === 0; + multiply(multiplier: number, roundingFunction: (x: number) => number): Money { + if (!isFunction(roundingFunction)) + roundingFunction = Math.round; + + assertOperand(multiplier); + const amount = roundingFunction(this.amount * multiplier); + + return new Money(amount, this.currency); } /** - * Returns true if the amount is positive. + * Subtracts the two objects creating a new Money instance that holds the result of the operation. * - * @returns {boolean} + * @param {Money} other + * @returns {Money} */ - isPositive(): boolean { - return this.amount > 0; - } + subtract(other: Money): Money { - isNegative(): boolean { - return this.amount < 0; + assertType(other); + assertSameCurrency(this, other); + + return new Money(this.amount - other.amount, this.currency); } /** diff --git a/app/javascript/components/formik/MoneyTextField.spec.tsx b/app/javascript/components/formik/MoneyTextField.spec.tsx index 8ad384f6..93df90c3 100644 --- a/app/javascript/components/formik/MoneyTextField.spec.tsx +++ b/app/javascript/components/formik/MoneyTextField.spec.tsx @@ -26,7 +26,7 @@ function FormikInner(props: { onChange:(args:{value:Money})=> void}) { ; } -function FormikHandler(props: { value: Money, onChange:(args:{value:Money})=> void}) { +function FormikHandler(props: { onChange:(args:{value:Money})=> void, value: Money,}) { const {value, ...innerFormikProps} = props; return diff --git a/app/javascript/components/formik/MoneyTextField.stories.tsx b/app/javascript/components/formik/MoneyTextField.stories.tsx index c43f2823..44dc1584 100644 --- a/app/javascript/components/formik/MoneyTextField.stories.tsx +++ b/app/javascript/components/formik/MoneyTextField.stories.tsx @@ -19,7 +19,7 @@ function FormikInner(props: { onChange:(args:{value:Money})=> void}) { ; } -function FormikHandler(props: { value: Money, onChange:(args:{value:Money})=> void}) { +function FormikHandler(props: { onChange:(args:{value:Money})=> void, value: Money}) { const {value, ...innerFormikProps} = props; return ( { console.log("submitted");}} enableReinitialize={true}> diff --git a/app/javascript/components/tests/intl/index.tsx b/app/javascript/components/tests/intl/index.tsx index 66aca9dd..f7098f85 100644 --- a/app/javascript/components/tests/intl/index.tsx +++ b/app/javascript/components/tests/intl/index.tsx @@ -28,12 +28,6 @@ class WithIntl extends React.Component { channel.emit(EVENT_GET_LOCALE_ID); } - setLocale (locale:string) { - this.setState({ - locale: locale, - }); - } - componentWillUnmount () { this.props.channel.removeListener(EVENT_SET_LOCALE_ID, this.setLocale); } @@ -70,6 +64,12 @@ class WithIntl extends React.Component { ); } + + setLocale (locale:string) { + this.setState({ + locale: locale, + }); + } } diff --git a/app/javascript/hooks/useSteps.spec.ts b/app/javascript/hooks/useSteps.spec.ts index 8081d278..67a9504e 100644 --- a/app/javascript/hooks/useSteps.spec.ts +++ b/app/javascript/hooks/useSteps.spec.ts @@ -344,19 +344,19 @@ describe('.enable', () => { describe('modify steps', () => { function createTableEntry(props: { - initial: { - steps: KeyedStep[], - activeStep?: number, - disabled?: KeyedStepMap, - completed?: - KeyedStepMap - }, - stepChange: KeyedStep[], expectation: { activeStep?: number, + completed?: KeyedStepMap, disabled?: KeyedStepMap, - completed?: KeyedStepMap - } + }, + initial: { + activeStep?: number, + completed?: + KeyedStepMap + disabled?: KeyedStepMap, + steps: KeyedStep[], + }, + stepChange: KeyedStep[], } ): [ KeyedStep[], number | undefined, KeyedStepMap | undefined, KeyedStepMap | undefined, // initial diff --git a/app/javascript/hooks/useSteps.ts b/app/javascript/hooks/useSteps.ts index 38f4a006..b56cd10f 100644 --- a/app/javascript/hooks/useSteps.ts +++ b/app/javascript/hooks/useSteps.ts @@ -18,43 +18,48 @@ export interface KeyedStepMap { interface ReadonlyStepsState { readonly activeStep?: number; + readonly activeStepKey: string; readonly completed?: KeyedStepMap; readonly disabled?: KeyedStepMap; /** * An internal copy of steps which only includes the key */ readonly stepKeys: readonly string[] - readonly activeStepKey: string; + } function areKeyedStepsDifferent(first: readonly string[], second: readonly string[]) { return first.length != second.length || first.find((value, index) => second[index] != value); } -function getIndexAndKeyPair(steps: readonly string[], step: string | number | unknown): {key:string, index:number} | false { +function getIndexAndKeyPair(steps: readonly string[], step: string | number | unknown): { index: number, key: string } | false { if (typeof step === 'string') { const index = steps.findIndex((i) => i === step); - if (index){ - return {key: step, index}; + if (index) { + return { key: step, index }; } } else if (typeof step === 'number' && step >= 0 && step < steps.length) { - return {key: steps[step], index: step}; + return { key: steps[step], index: step }; } return false; } -function getLastEnabledBeforeGivenStep(steps: readonly string[], currentActiveStep:number, disabled:KeyedStepMap): {key:string, index:number}{ +function getLastEnabledBeforeGivenStep( + steps: readonly string[], + currentActiveStep: number, + disabled: KeyedStepMap +): { index: number, key: string } { const possibleNewActiveStep = findLastIndex(take(steps, currentActiveStep + 1), (i) => !disabled[i]); - const index = possibleNewActiveStep >= 0 ? possibleNewActiveStep : 0; - return {key: steps[index], index}; + const index = possibleNewActiveStep >= 0 ? possibleNewActiveStep : 0; + return { key: steps[index], index }; } function reindexState(state: ReadonlyStepsState, incomingSteps: readonly KeyedStep[]): ReadonlyStepsState { const incomingStepKeys = incomingSteps.map(i => i.key); //if true, we've had new steps added or removed - if (areKeyedStepsDifferent(state.stepKeys, incomingStepKeys) ) { + if (areKeyedStepsDifferent(state.stepKeys, incomingStepKeys)) { const newIndexOfActiveStep = incomingStepKeys.findIndex(v => v === state.activeStepKey); let activeStep = state.activeStep; let activeStepKey = state.activeStepKey; @@ -101,10 +106,6 @@ function reindexState(state: ReadonlyStepsState, incomingSteps: readonly KeyedSt return state; } - - - - interface StepsInitOptions { readonly activeStep?: number; readonly completed?: KeyedStepMap; @@ -123,31 +124,31 @@ interface InputStepsMethods { interface MutableStepsObject extends InputStepsMethods { - goto: (step: number) => void back: () => void - next: () => void - first: () => void - last: () => void complete: (step: number) => void - uncomplete: (step: number) => void disable: (step: number) => void enable: (step: number) => void - + first: () => void + goto: (step: number) => void + last: () => void + next: () => void + uncomplete: (step: number) => void } type StepsObject = Readonly & Readonly & StepsInitOptions & { readonly steps: readonly KeyedStep[] } type StepTypes = 'goto' | 'first' | 'last' | 'back' | 'next' | 'complete' | 'uncomplete' | 'disable' | 'enable' | 'stepsChanged' interface StepAction { - type: StepTypes, payload?: number | string | readonly KeyedStep[] + payload?: number | string | readonly KeyedStep[]; + type: StepTypes; } function stepsReducer(state: ReadonlyStepsState, args: StepAction): ReadonlyStepsState { - let indexKeyPair:ReturnType = false; + let indexKeyPair: ReturnType = false; switch (args.type) { case ('goto'): indexKeyPair = getIndexAndKeyPair(state.stepKeys, args.payload); if (indexKeyPair && !state.disabled[indexKeyPair.key]) { - return {...state, activeStep:indexKeyPair.index, activeStepKey: indexKeyPair.key}; + return { ...state, activeStep: indexKeyPair.index, activeStepKey: indexKeyPair.key }; } return state; case ('first'): @@ -157,7 +158,7 @@ function stepsReducer(state: ReadonlyStepsState, args: StepAction): ReadonlyStep } return state; case ('last'): - const lastStep = state.stepKeys.length - 1 >=0 ? state.stepKeys.length - 1 : 0 ; + const lastStep = state.stepKeys.length - 1 >= 0 ? state.stepKeys.length - 1 : 0; if (state.activeStep != lastStep && !state.disabled[state.stepKeys[lastStep]]) { return { ...state, activeStep: lastStep, activeStepKey: state.stepKeys[lastStep] }; } @@ -195,7 +196,7 @@ function stepsReducer(state: ReadonlyStepsState, args: StepAction): ReadonlyStep if (indexKeyPair) { const disabled = { ...state.disabled }; disabled[indexKeyPair.key] = true; - let {activeStep, activeStepKey} = state; + let { activeStep, activeStepKey } = state; if (state.activeStep == indexKeyPair.index) { const result = getLastEnabledBeforeGivenStep(state.stepKeys, activeStep, disabled); activeStep = result.index;