Skip to content

Commit

Permalink
feat(core): add new parameters preprocessors & postprocessors and…
Browse files Browse the repository at this point in the history
… deprecate `preprocessor` & `postprocessor` (#333)
  • Loading branch information
nsbarsukov authored Jun 14, 2023
1 parent d1ebcec commit 0137775
Show file tree
Hide file tree
Showing 29 changed files with 232 additions and 181 deletions.
22 changes: 12 additions & 10 deletions projects/angular/src/lib/maskito.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,19 @@ describe(`Maskito Angular package`, () => {
readonly control = new FormControl();
readonly options: MaskitoOptions = {
mask: /^\d+(,\d{0,2})?$/,
preprocessor: ({elementState, data}) => {
const {value, selection} = elementState;
preprocessors: [
({elementState, data}) => {
const {value, selection} = elementState;

return {
elementState: {
selection,
value: value.replace('.', ','),
},
data: data.replace('.', ','),
};
},
return {
elementState: {
selection,
value: value.replace('.', ','),
},
data: data.replace('.', ','),
};
},
],
};
}

Expand Down
2 changes: 2 additions & 0 deletions projects/core/src/lib/constants/default-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export const MASKITO_DEFAULT_OPTIONS: Required<MaskitoOptions> = {
mask: /^.*$/,
preprocessor: identity,
postprocessor: identity,
preprocessors: [],
postprocessors: [],
plugins: [],
overwriteMode: 'shift',
};
22 changes: 15 additions & 7 deletions projects/core/src/lib/mask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
isEventProducingCharacter,
isRedo,
isUndo,
maskitoPipe,
maskitoTransform,
} from './utils';

Expand All @@ -22,6 +23,16 @@ export class Maskito extends MaskHistory {
...this.maskitoOptions,
};

private readonly preprocessor = maskitoPipe(
this.options.preprocessor,
...this.options.preprocessors,
);

private readonly postprocessor = maskitoPipe(
this.options.postprocessor,
...this.options.postprocessors,
);

private readonly teardowns = this.options.plugins.map(plugin =>
plugin(this.element, this.options),
);
Expand Down Expand Up @@ -225,7 +236,7 @@ export class Maskito extends MaskHistory {
selection,
};
const [initialFrom, initialTo] = initialState.selection;
const {elementState} = this.options.preprocessor(
const {elementState} = this.preprocessor(
{
elementState: initialState,
data: '',
Expand All @@ -237,7 +248,7 @@ export class Maskito extends MaskHistory {

maskModel.deleteCharacters([from, to]);

const newElementState = this.options.postprocessor(maskModel, initialState);
const newElementState = this.postprocessor(maskModel, initialState);
const newPossibleValue =
initialState.value.slice(0, initialFrom) +
initialState.value.slice(initialTo);
Expand Down Expand Up @@ -269,7 +280,7 @@ export class Maskito extends MaskHistory {

private handleInsert(event: Event | TypedInputEvent, data: string): void {
const initialElementState = this.elementState;
const {elementState, data: insertedText = data} = this.options.preprocessor(
const {elementState, data: insertedText = data} = this.preprocessor(
{
data,
elementState: initialElementState,
Expand All @@ -287,10 +298,7 @@ export class Maskito extends MaskHistory {
const [from, to] = elementState.selection;
const newPossibleValue =
elementState.value.slice(0, from) + data + elementState.value.slice(to);
const newElementState = this.options.postprocessor(
maskModel,
initialElementState,
);
const newElementState = this.postprocessor(maskModel, initialElementState);

if (newPossibleValue !== newElementState.value) {
event.preventDefault();
Expand Down
10 changes: 10 additions & 0 deletions projects/core/src/lib/types/mask-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,18 @@ import {MaskitoPlugin} from './plugin';

export interface MaskitoOptions {
readonly mask: MaskitoMask;
/**
* @deprecated Use property {@link preprocessors}
* TODO: delete it in 1.x.x
*/
readonly preprocessor?: MaskitoPreprocessor;
readonly preprocessors?: readonly MaskitoPreprocessor[];
/**
* @deprecated Use property {@link postprocessors}
* TODO: delete it in 1.x.x
*/
readonly postprocessor?: MaskitoPostprocessor;
readonly postprocessors?: readonly MaskitoPostprocessor[];
readonly plugins?: readonly MaskitoPlugin[];
readonly overwriteMode?:
| 'replace'
Expand Down
12 changes: 12 additions & 0 deletions projects/core/src/lib/utils/pipe.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
import {MaskitoPostprocessor, MaskitoPreprocessor} from '../types';

/**
* @deprecated Use property `preprocessors` from `MaskitoOptions`
* @internal
*/
export function maskitoPipe(
...processors: ReadonlyArray<MaskitoPreprocessor | null | undefined>
): MaskitoPreprocessor;

/**
* @deprecated Use property `postprocessors` from `MaskitoOptions`
* @internal
*/
export function maskitoPipe(
...processors: ReadonlyArray<MaskitoPostprocessor | null | undefined>
): MaskitoPostprocessor;

/* eslint-disable @typescript-eslint/ban-types */
/**
* @deprecated Use property `preprocessors` / `postprocessors` from `MaskitoOptions`
* @internal
*/
export function maskitoPipe(
...processors: ReadonlyArray<Function | null | undefined>
): Function {
Expand Down
7 changes: 5 additions & 2 deletions projects/core/src/lib/utils/transform.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {MaskModel} from '../classes';
import {MASKITO_DEFAULT_OPTIONS} from '../constants';
import {ElementState, MaskitoOptions} from '../types';
import {maskitoPipe} from './pipe';

export function maskitoTransform(value: string, maskitoOptions: MaskitoOptions): string;
export function maskitoTransform(
Expand All @@ -16,17 +17,19 @@ export function maskitoTransform(
...MASKITO_DEFAULT_OPTIONS,
...maskitoOptions,
};
const preprocessor = maskitoPipe(options.preprocessor, ...options.preprocessors);
const postprocessor = maskitoPipe(options.postprocessor, ...options.postprocessors);
const initialElementState: ElementState =
typeof valueOrState === 'string'
? {value: valueOrState, selection: [0, 0]}
: valueOrState;

const {elementState} = options.preprocessor(
const {elementState} = preprocessor(
{elementState: initialElementState, data: ''},
'validation',
);
const maskModel = new MaskModel(elementState, options);
const {value, selection} = options.postprocessor(maskModel, initialElementState);
const {value, selection} = postprocessor(maskModel, initialElementState);

return typeof valueOrState === 'string' ? value : {value, selection};
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ export class TestDocExample1 {

readonly nameMask: MaskitoOptions = {
mask: /^[a-zA-Z\s]+$/,
postprocessor: ({value, selection}) => ({value: value.toUpperCase(), selection}),
postprocessors: [
({value, selection}) => ({value: value.toUpperCase(), selection}),
],
};

readonly cardPredicate: MaskitoElementPredicate = element =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,7 @@ <h3 class="tui-island__title">Mask expression</h3>
>
<h3 class="tui-island__title">Processors</h3>
<p class="tui-island__paragraph">
Learn about preprocessors and postprocessors, and how to
stack them via
<code>maskitoPipe</code>
.
Learn about preprocessors and postprocessors.
</p>
</a>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
```ts
import {Maskito, maskitoPipe} from '@maskito/core';
import {Maskito} from '@maskito/core';

const maskedInput = new Maskito(element, {
mask: /^\d+$/,
preprocessor: maskitoPipe(preprocessor1, preprocessor2),
postprocessor: ({value, selection}) => {
// ...
},
preprocessors: [preprocessor1, preprocessor2],
postprocessors: [
({value, selection}) => {
// ...
},
],
overwriteMode: 'shift',
});

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ import {Maskito} from '@maskito/core';

const numberInput = new Maskito(element, {
mask: /^\d+(,\d*)?$/,
postprocessor: ({value, selection}, initialElementState) => {
const [from, to] = selection;
const noRepeatedLeadingZeroesValue = value.replace(/^0+/, '0');
const removedCharacters = value.length - noRepeatedLeadingZeroesValue.length;
postprocessors: [
({value, selection}, initialElementState) => {
const [from, to] = selection;
const noRepeatedLeadingZeroesValue = value.replace(/^0+/, '0');
const removedCharacters = value.length - noRepeatedLeadingZeroesValue.length;

return {
value: noRepeatedLeadingZeroesValue, // User types "000000" => 0|
selection: [Math.max(from - removedCharacters, 0), Math.max(to - removedCharacters, 0)],
};
},
return {
value: noRepeatedLeadingZeroesValue, // User types "000000" => 0|
selection: [Math.max(from - removedCharacters, 0), Math.max(to - removedCharacters, 0)],
};
},
],
});
```
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@ import {Maskito} from '@maskito/core';

const numberInput = new Maskito(element, {
mask: /^\d+(,\d*)?$/, // digits and comma (as decimal separator)
preprocessor: ({elementState, data}, actionType) => {
const {value, selection} = elementState;
preprocessors: [
({elementState, data}, actionType) => {
const {value, selection} = elementState;

return {
elementState: {
selection,
value: value.replace('.', ','),
},
data: data.replace('.', ','),
};
},
return {
elementState: {
selection,
value: value.replace('.', ','),
},
data: data.replace('.', ','),
};
},
],
});
```
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,5 @@ export class ProcessorsDocPageComponent {
'./examples/postprocessor-in-action.md?raw'
);

readonly maskitoPipeDemo = import('./examples/maskito-pipe-demo.md?raw');
readonly elementStateDocPage = `/${DemoPath.ElementState}`;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
<code>preprocessors</code>
and
<code>postprocessors</code>
. These are functions triggered on every user's input (
. Both accept array of pure functions. These functions are triggered
on every user's input (
<a
href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/beforeinput_event"
target="_blank"
Expand Down Expand Up @@ -66,19 +67,19 @@
</tui-notification>

<section class="tui-space_bottom-12">
<h2>Preprocessor</h2>
<h2>Preprocessors</h2>

<p>
It is a function that is called
Each preprocessor is a function that is called
<strong>before</strong>
mask is applied.
</p>

<p>
For example, if user types a new character, preprocessor will be
called first, and only then value that it returned will be passed
into the mask, and finally the mask will accept or reject new typed
character and update actual value of the text field.
For example, if user types a new character, all preprocessors will
be called first, and only then final value that they returned will
be passed into the mask, and finally the mask will accept or reject
new typed character and update actual value of the text field.
</p>

<section class="tui-space_bottom-6">
Expand Down Expand Up @@ -119,12 +120,12 @@ <h2>Preprocessor</h2>
</section>

<section class="tui-space_bottom-12">
<h2>Postprocessor</h2>
<h2>Postprocessors</h2>

<p class="tui-space_bottom-0">
It is a function that is called
Each postprocessor is a function that is called
<strong>after</strong>
the mask is applied. When the preprocessor is already called, all
the mask is applied. When all preprocessors are already called, all
mask operations happened and the input's value is about to be
updated. You can change everything manually inside a postprocessor.
</p>
Expand Down Expand Up @@ -170,26 +171,24 @@ <h2>Postprocessor</h2>
<tui-doc-code [code]="postprocessorInActionDemo"></tui-doc-code>
</section>

<section class="tui-space_bottom-12">
<h2>maskitoPipe</h2>
<tui-notification>
<strong>Stacking of multiple processors</strong>

<p>
The
<strong>Maskito</strong>
team likes code decomposition and promotes it! Don't put all complex
logic inside a single processor. Break it into the several
logic inside a single processor. Both parameters
<code>preprocessors</code>
and
<code>postprocessors</code>
accepts
<strong>array</strong>
of same type processors. Break your code into the several
independent processors so that each processor implements only a
single task.
</p>

<p>
Use the built-in
<code>maskitoPipe</code>
to stack multiple processors of the same type:
</p>

<tui-doc-code [code]="maskitoPipeDemo"></tui-doc-code>
</section>
</tui-notification>

<next-steps></next-steps>
</tui-doc-page>
Loading

0 comments on commit 0137775

Please sign in to comment.