From 13972c2f29815e7a77c6ebca05753dd9677f09e3 Mon Sep 17 00:00:00 2001 From: markostanimirovic Date: Wed, 5 Apr 2023 16:10:02 +0200 Subject: [PATCH] feat(store): preserve the event name case with createActionGroup Closes #3693 BREAKING CHANGES: The event name case is preserved when converting to the action name by using the `createActionGroup` function. BEFORE: All letters of the event name will be lowercase, except for the initial letters of words starting from the second word, which will be uppercase. ```ts const authApiActions = createActionGroup({ source: 'Auth API', events: { 'LogIn Success': emptyProps(), 'login failure': emptyProps(), 'Logout Success': emptyProps(), logoutFailure: emptyProps(), }, }); // generated actions: const { loginSuccess, loginFailure, logoutSuccess, logoutfailure, } = authApiActions; ``` AFTER: The initial letter of the first word of the event name will be lowercase, and the initial letters of the other words will be uppercase. The case of other letters in the event name will remain the same. ```ts const { logInSuccess, loginFailure, logoutSuccess, logoutFailure, } = authApiActions; ``` --- .../store/spec/action_group_creator.spec.ts | 9 +++++++-- modules/store/spec/helpers.spec.ts | 12 +++++++++++- .../spec/types/action_group_creator.spec.ts | 19 +++++++++++++++---- modules/store/src/action_group_creator.ts | 5 ++--- .../store/src/action_group_creator_models.ts | 2 +- modules/store/src/helpers.ts | 4 ++++ 6 files changed, 40 insertions(+), 11 deletions(-) diff --git a/modules/store/spec/action_group_creator.spec.ts b/modules/store/spec/action_group_creator.spec.ts index 94f741dc08..205187bc5f 100644 --- a/modules/store/spec/action_group_creator.spec.ts +++ b/modules/store/spec/action_group_creator.spec.ts @@ -14,17 +14,22 @@ describe('createActionGroup', () => { source: 'Books API', events: { ' Load BOOKS suCCess ': emptyProps(), + loadBooksFailure: emptyProps(), }, }); it('should create action name by camel casing the event name', () => { - expect(booksApiActions.loadBooksSuccess).toBeDefined(); + expect(booksApiActions.loadBOOKSSuCCess).toBeDefined(); + expect(booksApiActions.loadBooksFailure).toBeDefined(); }); it('should create action type using the "[Source] Event" pattern', () => { - expect(booksApiActions.loadBooksSuccess().type).toBe( + expect(booksApiActions.loadBOOKSSuCCess().type).toBe( '[Books API] Load BOOKS suCCess ' ); + expect(booksApiActions.loadBooksFailure().type).toBe( + '[Books API] loadBooksFailure' + ); }); it('should create action with props', () => { diff --git a/modules/store/spec/helpers.spec.ts b/modules/store/spec/helpers.spec.ts index 363493fdd2..0cc2ef985d 100644 --- a/modules/store/spec/helpers.spec.ts +++ b/modules/store/spec/helpers.spec.ts @@ -1,4 +1,4 @@ -import { capitalize } from '../src/helpers'; +import { capitalize, uncapitalize } from '../src/helpers'; describe('helpers', () => { describe('capitalize', () => { @@ -10,4 +10,14 @@ describe('helpers', () => { expect(capitalize('')).toEqual(''); }); }); + + describe('uncapitalize', () => { + it('should uncapitalize the text', () => { + expect(uncapitalize('NGRX')).toEqual('nGRX'); + }); + + it('should return an empty string when the text is an empty string', () => { + expect(uncapitalize('')).toEqual(''); + }); + }); }); diff --git a/modules/store/spec/types/action_group_creator.spec.ts b/modules/store/spec/types/action_group_creator.spec.ts index 39a8ebe984..0d517ad14b 100644 --- a/modules/store/spec/types/action_group_creator.spec.ts +++ b/modules/store/spec/types/action_group_creator.spec.ts @@ -98,22 +98,33 @@ describe('createActionGroup', () => { describe('event name', () => { it('should create action name by camel casing the event name', () => { - expectSnippet(` + const snippet = expectSnippet(` const booksApiActions = createActionGroup({ source: 'Books API', events: { ' Load BOOKS suCCess ': emptyProps(), + loadBooksFailure: emptyProps(), }, }); - let loadBooksSuccess: typeof booksApiActions.loadBooksSuccess; - `).toInfer( + let loadBooksSuccess: typeof booksApiActions.loadBOOKSSuCCess; + let loadBooksFailure: typeof booksApiActions.loadBooksFailure; + `); + + snippet.toInfer( 'loadBooksSuccess', `ActionCreator< "[Books API] Load BOOKS suCCess ", () => TypedAction<"[Books API] Load BOOKS suCCess "> >` ); + snippet.toInfer( + 'loadBooksFailure', + `ActionCreator< + "[Books API] loadBooksFailure", + () => TypedAction<"[Books API] loadBooksFailure"> + >` + ); }); it('should fail when event name is an empty string', () => { @@ -222,7 +233,7 @@ describe('createActionGroup', () => { const booksApiActions = createActionGroup({ source: 'Books API', events: { - ' Load BOOks success ': emptyProps(), + ' Load Books success ': emptyProps(), 'load Books Success': props<{ books: string[] }>(), } }); diff --git a/modules/store/src/action_group_creator.ts b/modules/store/src/action_group_creator.ts index f857d92cab..ddaba89fcf 100644 --- a/modules/store/src/action_group_creator.ts +++ b/modules/store/src/action_group_creator.ts @@ -1,6 +1,6 @@ import { createAction, props } from './action_creator'; import { ActionCreatorProps, Creator } from './models'; -import { capitalize } from './helpers'; +import { capitalize, uncapitalize } from './helpers'; import { ActionGroup, ActionGroupConfig, @@ -75,9 +75,8 @@ function toActionName( ): ActionName { return eventName .trim() - .toLowerCase() .split(' ') - .map((word, i) => (i === 0 ? word : capitalize(word))) + .map((word, i) => (i === 0 ? uncapitalize(word) : capitalize(word))) .join('') as ActionName; } diff --git a/modules/store/src/action_group_creator_models.ts b/modules/store/src/action_group_creator_models.ts index 2e96aa837f..134ff5f331 100644 --- a/modules/store/src/action_group_creator_models.ts +++ b/modules/store/src/action_group_creator_models.ts @@ -95,7 +95,7 @@ type EventCreator< : never; export type ActionName = Uncapitalize< - Join>>> + Join> >; export interface ActionGroupConfig< diff --git a/modules/store/src/helpers.ts b/modules/store/src/helpers.ts index 1606afd6bc..a2efac6f6f 100644 --- a/modules/store/src/helpers.ts +++ b/modules/store/src/helpers.ts @@ -1,3 +1,7 @@ export function capitalize(text: T): Capitalize { return (text.charAt(0).toUpperCase() + text.substring(1)) as Capitalize; } + +export function uncapitalize(text: T): Uncapitalize { + return (text.charAt(0).toLowerCase() + text.substring(1)) as Uncapitalize; +}