Add @typescript-eslint/member-ordering to eslint

This commit is contained in:
Eric Schultz 2020-10-22 14:24:14 -05:00 committed by Eric Schultz
parent 907f44a001
commit 659c2eecc2
7 changed files with 205 additions and 125 deletions

View file

@ -38,6 +38,85 @@ const tsBase = {
'plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/recommended',
"plugin:react-hooks/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); const tsSettings = _.cloneDeep(tsBase);
@ -79,9 +158,9 @@ module.exports = {
"always", "always",
], ],
"no-trailing-spaces": ["error"], "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"], "comma-dangle": ["error", "always-multiline"],
"@typescript-eslint/no-unused-vars": ['error', {"args": "all", "argsIgnorePattern": "^_"}], "@typescript-eslint/no-unused-vars": ['error', { "args": "all", "argsIgnorePattern": "^_" }],
}, },
"settings": { "settings": {
"react": { "react": {

View file

@ -28,6 +28,13 @@ type MoneyAsJson = { amount: number, currency: string }
*/ */
export class Money { 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 readonly currency: string
protected constructor(readonly amount: number, currency: string) { protected constructor(readonly amount: number, currency: string) {
@ -63,28 +70,6 @@ export class Money {
return new Money(amount.amount, amount.currency); 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. * 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); 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. * 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; 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. * 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); 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. * 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 { multiply(multiplier: number, roundingFunction: (x: number) => number): Money {
return this.amount === 0; 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 { subtract(other: Money): Money {
return this.amount > 0;
}
isNegative(): boolean { assertType(other);
return this.amount < 0; assertSameCurrency(this, other);
return new Money(this.amount - other.amount, this.currency);
} }
/** /**

View file

@ -26,7 +26,7 @@ function FormikInner(props: { onChange:(args:{value:Money})=> void}) {
<Field component={MoneyTextField} name="value" aria-label="field"/></>; <Field component={MoneyTextField} name="value" aria-label="field"/></>;
} }
function FormikHandler(props: { value: Money, onChange:(args:{value:Money})=> void}) { function FormikHandler(props: { onChange:(args:{value:Money})=> void, value: Money,}) {
const {value, ...innerFormikProps} = props; const {value, ...innerFormikProps} = props;
return <HoudiniIntlProvider locale="en"> return <HoudiniIntlProvider locale="en">

View file

@ -19,7 +19,7 @@ function FormikInner(props: { onChange:(args:{value:Money})=> void}) {
<Field component={MoneyTextField} name="value" aria-label="field" /></>; <Field component={MoneyTextField} name="value" aria-label="field" /></>;
} }
function FormikHandler(props: { value: Money, onChange:(args:{value:Money})=> void}) { function FormikHandler(props: { onChange:(args:{value:Money})=> void, value: Money}) {
const {value, ...innerFormikProps} = props; const {value, ...innerFormikProps} = props;
return (<Formik initialValues={{ value }} onSubmit={() => { console.log("submitted");}} enableReinitialize={true}> return (<Formik initialValues={{ value }} onSubmit={() => { console.log("submitted");}} enableReinitialize={true}>

View file

@ -28,12 +28,6 @@ class WithIntl extends React.Component<any,any> {
channel.emit(EVENT_GET_LOCALE_ID); channel.emit(EVENT_GET_LOCALE_ID);
} }
setLocale (locale:string) {
this.setState({
locale: locale,
});
}
componentWillUnmount () { componentWillUnmount () {
this.props.channel.removeListener(EVENT_SET_LOCALE_ID, this.setLocale); this.props.channel.removeListener(EVENT_SET_LOCALE_ID, this.setLocale);
} }
@ -70,6 +64,12 @@ class WithIntl extends React.Component<any,any> {
</HoudiniIntlProvider> </HoudiniIntlProvider>
); );
} }
setLocale (locale:string) {
this.setState({
locale: locale,
});
}
} }

View file

@ -344,19 +344,19 @@ describe('.enable', () => {
describe('modify steps', () => { describe('modify steps', () => {
function createTableEntry(props: { function createTableEntry(props: {
initial: {
steps: KeyedStep[],
activeStep?: number,
disabled?: KeyedStepMap<boolean>,
completed?:
KeyedStepMap<boolean>
},
stepChange: KeyedStep[],
expectation: { expectation: {
activeStep?: number, activeStep?: number,
completed?: KeyedStepMap<boolean>,
disabled?: KeyedStepMap<boolean>, disabled?: KeyedStepMap<boolean>,
completed?: KeyedStepMap<boolean> },
} initial: {
activeStep?: number,
completed?:
KeyedStepMap<boolean>
disabled?: KeyedStepMap<boolean>,
steps: KeyedStep[],
},
stepChange: KeyedStep[],
} }
): [ ): [
KeyedStep[], number | undefined, KeyedStepMap<boolean> | undefined, KeyedStepMap<boolean> | undefined, // initial KeyedStep[], number | undefined, KeyedStepMap<boolean> | undefined, KeyedStepMap<boolean> | undefined, // initial

View file

@ -18,43 +18,48 @@ export interface KeyedStepMap<T = unknown> {
interface ReadonlyStepsState { interface ReadonlyStepsState {
readonly activeStep?: number; readonly activeStep?: number;
readonly activeStepKey: string;
readonly completed?: KeyedStepMap<boolean>; readonly completed?: KeyedStepMap<boolean>;
readonly disabled?: KeyedStepMap<boolean>; readonly disabled?: KeyedStepMap<boolean>;
/** /**
* An internal copy of steps which only includes the key * An internal copy of steps which only includes the key
*/ */
readonly stepKeys: readonly string[] readonly stepKeys: readonly string[]
readonly activeStepKey: string;
} }
function areKeyedStepsDifferent(first: readonly string[], second: readonly string[]) { function areKeyedStepsDifferent(first: readonly string[], second: readonly string[]) {
return first.length != second.length || first.find((value, index) => second[index] != value); 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') { if (typeof step === 'string') {
const index = steps.findIndex((i) => i === step); const index = steps.findIndex((i) => i === step);
if (index){ if (index) {
return {key: step, index}; return { key: step, index };
} }
} }
else if (typeof step === 'number' && step >= 0 && step < steps.length) { else if (typeof step === 'number' && step >= 0 && step < steps.length) {
return {key: steps[step], index: step}; return { key: steps[step], index: step };
} }
return false; return false;
} }
function getLastEnabledBeforeGivenStep(steps: readonly string[], currentActiveStep:number, disabled:KeyedStepMap<boolean>): {key:string, index:number}{ function getLastEnabledBeforeGivenStep(
steps: readonly string[],
currentActiveStep: number,
disabled: KeyedStepMap<boolean>
): { index: number, key: string } {
const possibleNewActiveStep = findLastIndex(take(steps, currentActiveStep + 1), (i) => !disabled[i]); const possibleNewActiveStep = findLastIndex(take(steps, currentActiveStep + 1), (i) => !disabled[i]);
const index = possibleNewActiveStep >= 0 ? possibleNewActiveStep : 0; const index = possibleNewActiveStep >= 0 ? possibleNewActiveStep : 0;
return {key: steps[index], index}; return { key: steps[index], index };
} }
function reindexState(state: ReadonlyStepsState, incomingSteps: readonly KeyedStep[]): ReadonlyStepsState { function reindexState(state: ReadonlyStepsState, incomingSteps: readonly KeyedStep[]): ReadonlyStepsState {
const incomingStepKeys = incomingSteps.map(i => i.key); const incomingStepKeys = incomingSteps.map(i => i.key);
//if true, we've had new steps added or removed //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); const newIndexOfActiveStep = incomingStepKeys.findIndex(v => v === state.activeStepKey);
let activeStep = state.activeStep; let activeStep = state.activeStep;
let activeStepKey = state.activeStepKey; let activeStepKey = state.activeStepKey;
@ -101,10 +106,6 @@ function reindexState(state: ReadonlyStepsState, incomingSteps: readonly KeyedSt
return state; return state;
} }
interface StepsInitOptions { interface StepsInitOptions {
readonly activeStep?: number; readonly activeStep?: number;
readonly completed?: KeyedStepMap<boolean>; readonly completed?: KeyedStepMap<boolean>;
@ -123,31 +124,31 @@ interface InputStepsMethods {
interface MutableStepsObject extends InputStepsMethods { interface MutableStepsObject extends InputStepsMethods {
goto: (step: number) => void
back: () => void back: () => void
next: () => void
first: () => void
last: () => void
complete: (step: number) => void complete: (step: number) => void
uncomplete: (step: number) => void
disable: (step: number) => void disable: (step: number) => void
enable: (step: number) => void enable: (step: number) => void
first: () => void
goto: (step: number) => void
last: () => void
next: () => void
uncomplete: (step: number) => void
} }
type StepsObject = Readonly<MutableStepsObject> & Readonly<InputStepsState> & StepsInitOptions & { readonly steps: readonly KeyedStep[] } type StepsObject = Readonly<MutableStepsObject> & Readonly<InputStepsState> & StepsInitOptions & { readonly steps: readonly KeyedStep[] }
type StepTypes = 'goto' | 'first' | 'last' | 'back' | 'next' | 'complete' | 'uncomplete' | 'disable' | 'enable' | 'stepsChanged' type StepTypes = 'goto' | 'first' | 'last' | 'back' | 'next' | 'complete' | 'uncomplete' | 'disable' | 'enable' | 'stepsChanged'
interface StepAction { interface StepAction {
type: StepTypes, payload?: number | string | readonly KeyedStep[] payload?: number | string | readonly KeyedStep[];
type: StepTypes;
} }
function stepsReducer(state: ReadonlyStepsState, args: StepAction): ReadonlyStepsState { function stepsReducer(state: ReadonlyStepsState, args: StepAction): ReadonlyStepsState {
let indexKeyPair:ReturnType<typeof getIndexAndKeyPair> = false; let indexKeyPair: ReturnType<typeof getIndexAndKeyPair> = false;
switch (args.type) { switch (args.type) {
case ('goto'): case ('goto'):
indexKeyPair = getIndexAndKeyPair(state.stepKeys, args.payload); indexKeyPair = getIndexAndKeyPair(state.stepKeys, args.payload);
if (indexKeyPair && !state.disabled[indexKeyPair.key]) { if (indexKeyPair && !state.disabled[indexKeyPair.key]) {
return {...state, activeStep:indexKeyPair.index, activeStepKey: indexKeyPair.key}; return { ...state, activeStep: indexKeyPair.index, activeStepKey: indexKeyPair.key };
} }
return state; return state;
case ('first'): case ('first'):
@ -157,7 +158,7 @@ function stepsReducer(state: ReadonlyStepsState, args: StepAction): ReadonlyStep
} }
return state; return state;
case ('last'): 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]]) { if (state.activeStep != lastStep && !state.disabled[state.stepKeys[lastStep]]) {
return { ...state, activeStep: lastStep, activeStepKey: state.stepKeys[lastStep] }; return { ...state, activeStep: lastStep, activeStepKey: state.stepKeys[lastStep] };
} }
@ -195,7 +196,7 @@ function stepsReducer(state: ReadonlyStepsState, args: StepAction): ReadonlyStep
if (indexKeyPair) { if (indexKeyPair) {
const disabled = { ...state.disabled }; const disabled = { ...state.disabled };
disabled[indexKeyPair.key] = true; disabled[indexKeyPair.key] = true;
let {activeStep, activeStepKey} = state; let { activeStep, activeStepKey } = state;
if (state.activeStep == indexKeyPair.index) { if (state.activeStep == indexKeyPair.index) {
const result = getLastEnabledBeforeGivenStep(state.stepKeys, activeStep, disabled); const result = getLastEnabledBeforeGivenStep(state.stepKeys, activeStep, disabled);
activeStep = result.index; activeStep = result.index;