Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): new maskitoPipe utility #39

Merged
merged 6 commits into from
Dec 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
uses: ./.github/actions/nodejs

- name: Build demo
run: npm run build
run: nx build-gh-pages

- name: Deploy
uses: JamesIves/github-pages-deploy-action@v4.2.5
Expand Down
1 change: 1 addition & 0 deletions projects/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export {Maskito} from './lib/mask';
export {MaskitoOptions} from './lib/types';
export {MASKITO_DEFAULT_OPTIONS} from './lib/constants';
export {maskitoPipe} from './lib/utils';
1 change: 1 addition & 0 deletions projects/core/src/lib/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './dom/is-event-producing-character';
export * from './element-states-equality';
export * from './extend-to-not-empty-range';
export * from './identity';
export * from './pipe';
12 changes: 12 additions & 0 deletions projects/core/src/lib/utils/pipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {MaskPostprocessor, MaskPreprocessor} from '../types';

export function maskitoPipe(...processors: readonly MaskPreprocessor[]): MaskPreprocessor;

export function maskitoPipe(
...processors: readonly MaskPostprocessor[]
): MaskPostprocessor;

export function maskitoPipe(...processors: readonly Function[]): Function {
return (initialData: object) =>
processors.reduce((data, fn) => ({...data, ...fn(data)}), initialData);
}
156 changes: 156 additions & 0 deletions projects/core/src/lib/utils/test/pipe.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import {MaskPostprocessor, MaskPreprocessor} from '../../types';
import {maskitoPipe} from '../pipe';

describe('maskitoPipe', () => {
describe('Preprocessor', () => {
const preprocessorData: Parameters<MaskPreprocessor>[0] = {
elementState: {value: '2', selection: [2, 2]},
data: '0',
actionType: 'insert',
};

const add0ToValue: MaskPreprocessor = ({elementState}) => ({
elementState: {
...elementState,
value: elementState.value + '0',
},
});
const add1ToValue: MaskPreprocessor = ({elementState}) => ({
elementState: {
...elementState,
value: elementState.value + '1',
},
});
const add5ToData: MaskPreprocessor = ({elementState, data}) => ({
elementState,
data: data + '5',
});
const add3ToData: MaskPreprocessor = ({elementState, data}) => ({
elementState,
data: data + '3',
});

it('take the last valid `data` if the previous processor did not modify it', () => {
expect(
maskitoPipe(add3ToData, add0ToValue, add5ToData)(preprocessorData),
).toEqual({
elementState: {value: '20', selection: [2, 2]},
data: '035',
actionType: 'insert',
});
});

describe('Order matters', () => {
it('for `elementState`', () => {
expect(maskitoPipe(add0ToValue, add1ToValue)(preprocessorData)).toEqual({
elementState: {value: '201', selection: [2, 2]},
data: '0',
actionType: 'insert',
});

expect(maskitoPipe(add1ToValue, add0ToValue)(preprocessorData)).toEqual({
elementState: {value: '210', selection: [2, 2]},
data: '0',
actionType: 'insert',
});
});

it('for `data`', () => {
expect(maskitoPipe(add3ToData, add5ToData)(preprocessorData)).toEqual({
elementState: {value: '2', selection: [2, 2]},
data: '035',
actionType: 'insert',
});

expect(maskitoPipe(add5ToData, add3ToData)(preprocessorData)).toEqual({
elementState: {value: '2', selection: [2, 2]},
data: '053',
actionType: 'insert',
});
});

it('for `elementState` & `data` in one pipe', () => {
expect(
maskitoPipe(
add5ToData,
add0ToValue,
add3ToData,
add1ToValue,
)(preprocessorData),
).toEqual({
elementState: {value: '201', selection: [2, 2]},
data: '053',
actionType: 'insert',
});
});
});
});

describe('Postprocessor', () => {
const postprocessorData: Parameters<MaskPostprocessor>[0] = {
value: '0',
selection: [5, 5],
};

const add3: MaskPostprocessor = ({value, selection}) => ({
selection,
value: value + '3',
});
const add5: MaskPostprocessor = ({value, selection}) => ({
selection,
value: value + '5',
});
const doubleCaretIndex: MaskPostprocessor = ({value, selection}) => ({
value,
selection: [selection[0] * 2, selection[1] * 2],
});
const shiftCaretIndexBy5: MaskPostprocessor = ({value, selection}) => ({
value,
selection: [selection[0] + 5, selection[1] + 5],
});

describe('Order matters', () => {
it('for `value`', () => {
expect(maskitoPipe(add3, add5)(postprocessorData)).toEqual({
value: '035',
selection: [5, 5],
});

expect(maskitoPipe(add5, add3)(postprocessorData)).toEqual({
value: '053',
selection: [5, 5],
});
});

it('for `selection`', () => {
expect(
maskitoPipe(doubleCaretIndex, shiftCaretIndexBy5)(postprocessorData),
).toEqual({
value: '0',
selection: [15, 15],
});

expect(
maskitoPipe(shiftCaretIndexBy5, doubleCaretIndex)(postprocessorData),
).toEqual({
value: '0',
selection: [20, 20],
});
});

it('for `value` & `selection` in one pipe', () => {
expect(
maskitoPipe(
add5,
doubleCaretIndex,
add3,
shiftCaretIndexBy5,
)(postprocessorData),
).toEqual({
value: '053',
selection: [15, 15],
});
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,19 @@ describe('Time', () => {
.should('have.prop', 'selectionEnd', 1);
});
});

// TODO: BUG!
it.skip('Pad typed value with zero if digit exceeds the first digit of time segment', () => {
cy.get('@input')
.type('9')
.should('have.value', '09')
.should('have.prop', 'selectionStart', '09'.length)
.should('have.prop', 'selectionEnd', '09'.length)
.type('9')
.should('have.value', '09:09')
.should('have.prop', 'selectionStart', '09:09'.length)
.should('have.prop', 'selectionEnd', '09:09'.length);
});
});

describe('HH:MM:SS', () => {
Expand Down Expand Up @@ -151,6 +164,23 @@ describe('Time', () => {
.should('have.prop', 'selectionEnd', '23:0'.length);
});
});

// TODO: BUG!
it.skip('Pad typed value with zero if digit exceeds the first digit of time segment', () => {
cy.get('@input')
.type('9')
.should('have.value', '09')
.should('have.prop', 'selectionStart', '09'.length)
.should('have.prop', 'selectionEnd', '09'.length)
.type('9')
.should('have.value', '09:09')
.should('have.prop', 'selectionStart', '09:09'.length)
.should('have.prop', 'selectionEnd', '09:09'.length)
.type('9')
.should('have.value', '09:09:09')
.should('have.prop', 'selectionStart', '09:09:09'.length)
.should('have.prop', 'selectionEnd', '09:09:09'.length);
});
});

describe('HH:MM:SS.MSS', () => {
Expand Down Expand Up @@ -233,6 +263,23 @@ describe('Time', () => {
.should('have.prop', 'selectionEnd', '23:0'.length);
});
});

// TODO: BUG!
it.skip('Pad typed value with zero if digit exceeds the first digit of time segment', () => {
cy.get('@input')
.type('9')
.should('have.value', '09')
.should('have.prop', 'selectionStart', '09'.length)
.should('have.prop', 'selectionEnd', '09'.length)
.type('9')
.should('have.value', '09:09')
.should('have.prop', 'selectionStart', '09:09'.length)
.should('have.prop', 'selectionEnd', '09:09'.length)
.type('9')
.should('have.value', '09:09:09')
.should('have.prop', 'selectionStart', '09:09:09'.length)
.should('have.prop', 'selectionEnd', '09:09:09'.length);
});
});
});
});
6 changes: 4 additions & 2 deletions projects/demo-integrations/cypress/tests/ssr/ssr.cy.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import {DemoPath} from 'projects/demo/src/app/app.routes';

describe('Server side rendering', () => {
const baseUrl: string = Cypress.config('baseUrl') ?? '/';

Expand All @@ -6,8 +8,8 @@ describe('Server side rendering', () => {
});

it('should successfully render lazy url', () => {
cy.request(`${baseUrl}/lazy`)
cy.request(`${baseUrl}/${DemoPath.Time}`)
.its('body')
.should('include', 'This is a lazy route');
.should('include.match', /<h1.*>\s+Time/);
});
});
16 changes: 15 additions & 1 deletion projects/demo/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,19 @@
},
"defaultConfiguration": "production"
},
"build-gh-pages": {
"executor": "@nrwl/workspace:run-commands",
"options": {
"parallel": false,
"commands": [
"echo 'Github pages require special baseHref + 404.html'",
"echo 'Read more: https://angular.io/guide/deployment#deploy-to-github-pages'",
"echo ------",
"nx build --base-href='./'",
"cp dist/demo/browser/index.html dist/demo/browser/404.html"
]
}
},
"serve": {
"executor": "@angular-devkit/build-angular:dev-server",
"options": {
Expand Down Expand Up @@ -140,7 +153,8 @@
"executor": "@nguniversal/builders:ssr-dev-server",
"options": {
"browserTarget": "demo:build",
"serverTarget": "demo:server"
"serverTarget": "demo:server",
"port": 3333
},
"configurations": {
"production": {
Expand Down
4 changes: 0 additions & 4 deletions projects/demo/src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ export const appRoutes: Routes = [
title: `Sandbox`,
},
},
{
path: 'lazy',
loadChildren: () => import(`./modules/lazy/lazy.module`).then(m => m.LazyModule),
},
{
path: DemoPath.Time,
loadChildren: () =>
Expand Down
8 changes: 0 additions & 8 deletions projects/demo/src/app/modules/lazy/lazy.component.ts

This file was deleted.

18 changes: 0 additions & 18 deletions projects/demo/src/app/modules/lazy/lazy.module.ts

This file was deleted.

1 change: 0 additions & 1 deletion projects/demo/src/app/modules/lazy/lazy.template.html

This file was deleted.

23 changes: 5 additions & 18 deletions projects/kit/src/lib/time/time-mask.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {MaskitoOptions} from '@maskito/core';
import {MaskitoOptions, maskitoPipe} from '@maskito/core';
import {DEFAULT_TIME_SEGMENT_MAX_VALUES, TIME_FIXED_CHARACTERS} from './constants';
import {
createMaxValidationPreprocessor,
Expand All @@ -23,23 +23,10 @@ export function maskitoTimeOptionsGenerator({
mask: Array.from(mode).map(char =>
TIME_FIXED_CHARACTERS.includes(char) ? char : /\d/,
),
/**
* TODO: create new utility
* ```ts
* preprocessor: MaskitoPipe(
* createZeroPlaceholdersPreprocessor(mode),
* createMaxValidationPreprocessor(enrichedTimeSegmentMaxValues),
* )
* ```
*/
preprocessor: data => {
const newData = createZeroPlaceholdersPreprocessor(mode)(data);

return createMaxValidationPreprocessor(enrichedTimeSegmentMaxValues)({
...data,
...newData,
});
},
preprocessor: maskitoPipe(
createZeroPlaceholdersPreprocessor(mode),
createMaxValidationPreprocessor(enrichedTimeSegmentMaxValues),
),
postprocessor: createZeroPaddingPostprocessor(enrichedTimeSegmentMaxValues),
overwriteMode: 'replace',
};
Expand Down