Skip to content

Improve DelimiterCase#930

Merged
sindresorhus merged 18 commits intosindresorhus:mainfrom
filipw01:improve-delimiter-case
Feb 26, 2025
Merged

Improve DelimiterCase#930
sindresorhus merged 18 commits intosindresorhus:mainfrom
filipw01:improve-delimiter-case

Conversation

@filipw01
Copy link
Copy Markdown
Contributor

@filipw01 filipw01 commented Aug 7, 2024

I made some changes that pass more test cases than the current solution. I was heavily inspired by CamelCase implementation

Opinions seem to be mixed from one library to another how hello123 case should be handled
Screenshot 2024-08-08 at 00 20 07
Even more interestingly, those libraries that default to hello_123 don't have an option to customize it, but those that default to hello123 have optional parameters to change that

I made the type customizable via a parameter to fit both cases

Related issues:
#223
#336

What I'd still like to add:

  • add more test cases for other cases (kebab-case etc.)

@filipw01
Copy link
Copy Markdown
Contributor Author

@voxpelli Could you take a look? At the moment I just want to know if this is something I should dig deeper into

@voxpelli
Copy link
Copy Markdown
Collaborator

@filipw01 Its not immediately obvious to me what the improvements are, and my experience with these helpers has been that they easily turn into a game of whackamole – any improvement reveals a couple of regressions.

I do see that you ultimate refer to my wish to unify the two: #224 (comment)

To support this use case I think we essentially would have to merge the functionality of the two. I can't remember why I didn't do that initially.

But that was ultimately solved through a new option instead: #501

I guess my main feedback would be to split this PR into more commits and try to make it as clear what and why the changes made are made, so that one can as easily as possible follow the reasoning in a review

@filipw01 filipw01 marked this pull request as draft August 27, 2024 13:06
@filipw01
Copy link
Copy Markdown
Contributor Author

filipw01 commented Nov 8, 2024

For the no split on number I decided to align with change-case library which seems to be the best at handling different edge cases

? [...SkipEmptyWord<CurrentWord>, ...SplitWords<RemainingCharacters, FirstCharacter, FirstCharacter>]
// Case change: numeric to non-numeric, push word
// Split on number: push word
? Options['splitOnNumber'] extends true
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When there's a numeric/non-numeric case change I added and used a new option splitOnNumber which depending on how it is set will either

  1. When set to true - Like before split words on number
  2. When set to false - concat to current word

@category Template literal
*/
export type ScreamingSnakeCase<Value> = Value extends string
? IsScreamingSnakeCase<Value> extends true
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can bring this back, but I believe it shouldn't be necessary, especially that we don't use it for other things like snake case or kebab case

Comment on lines +52 to +77
const kebabFromMixed2: KebabCase<'parseHTML'> = 'parse-html';
expectType<'parse-html'>(kebabFromMixed2);

const kebabFromMixed3: KebabCase<'parseHTMLItem'> = 'parse-html-item';
expectType<'parse-html-item'>(kebabFromMixed3);

const kebabFromNumberInTheMiddleSplitOnNumber: KebabCase<'foo2bar'> = 'foo-2-bar';
expectType<'foo-2-bar'>(kebabFromNumberInTheMiddleSplitOnNumber);

const kebabFromNumberInTheMiddleSplitOnNumberEdgeCase: KebabCase<'foO2Bar'> = 'fo-o-2-bar';
expectType<'fo-o-2-bar'>(kebabFromNumberInTheMiddleSplitOnNumberEdgeCase);

const kebabFromNumberInTheMiddleSplitOnNumberEdgeCase2: KebabCase<'foO2bar'> = 'fo-o-2-bar';
expectType<'fo-o-2-bar'>(kebabFromNumberInTheMiddleSplitOnNumberEdgeCase2);

const kebabFromNumberInTheMiddleNoSplitOnNumber: KebabCase<'foo2bar', {splitOnNumber: false}> = 'foo2bar';
expectType<'foo2bar'>(kebabFromNumberInTheMiddleNoSplitOnNumber);

const kebabFromNumberInTheMiddleNoSplitOnNumberEdgeCase: KebabCase<'foo2Bar', {splitOnNumber: false}> = 'foo2-bar';
expectType<'foo2-bar'>(kebabFromNumberInTheMiddleNoSplitOnNumberEdgeCase);

const kebabFromNumberInTheMiddleNoSplitOnNumberEdgeCase2: KebabCase<'foO2bar', {splitOnNumber: false}> = 'fo-o2bar';
expectType<'fo-o2bar'>(kebabFromNumberInTheMiddleNoSplitOnNumberEdgeCase2);

const kebabFromNumberInTheMiddleNoSplitOnNumberEdgeCase3: KebabCase<'FOO22Bar', {splitOnNumber: false}> = 'foo22-bar';
expectType<'foo22-bar'>(kebabFromNumberInTheMiddleNoSplitOnNumberEdgeCase3);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the same tests to all case types as well as some edge cases visible here. If you have any doubts about the implementation I can add more tests

// Simple

const someVariable: KebabCase<'fooBar'> = 'foo-bar';
const someVariableNoSplitOnNumber: KebabCase<'p2pNetwork', {splitOnNumber: false}> = 'p2p-network';
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this new option on case changing types

: Parts extends [string]
? string
: '';
type DelimiterCaseFromArray<
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This gets the words split and inserts the delimited at the beginning and after every word

Like ['here', 'We', 'Go'] -> '#here#We#Go'

Delimiter
>
*/
export type DelimiterCase<Value, Delimiter extends string, Options extends SplitWordsOptions = {splitOnNumber: true}> = Value extends string
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we

  1. 'hereWeGo' -> SplitWords -> ['here', 'We', 'Go']
  2. ['here', 'We', 'Go'] -> DelimiterCaseFromArray -> '#here#We#Go'
  3. '#here#We#Go' -> RemoveFirstLetter -> 'here#We#Go'
  4. 'here#We#Go' -> Lowercase -> 'here#we#go'

@filipw01
Copy link
Copy Markdown
Contributor Author

filipw01 commented Nov 8, 2024

@voxpelli At this point where all the commits are made I'd prefer not to do any git wizardry splitting into smaller commits. I left some comments for easier review. I hope this will be enough. If something is unclear let me know.

I tried to add more edge cases to avoid the whack a mole game

@filipw01 filipw01 marked this pull request as ready for review November 8, 2024 22:49
@voxpelli voxpelli mentioned this pull request Nov 10, 2024
@voxpelli
Copy link
Copy Markdown
Collaborator

#975 is also touching some of these files. I will not have time to review either, just noting it

@filipw01
Copy link
Copy Markdown
Contributor Author

filipw01 commented Feb 16, 2025

@sindresorhus any chance to move this forward?

Delimiter
>
*/
export type DelimiterCase<Value, Delimiter extends string, Options extends SplitWordsOptions = {splitOnNumber: true}> = Value extends string
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SplitWordsOptions = {splitOnNumber: true} will not allow us to add more options in the future, as if you specify one, you override the existing defaults.

Example: https://github.com/sindresorhus/type-fest/blob/7dfb307e3ecc0e7717de6880395f1de8715c82c1/source/paths.d.ts

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

@sindresorhus
Copy link
Copy Markdown
Owner

You need to resolve the merge conflict.

@sindresorhus sindresorhus requested a review from som-sm February 20, 2025 16:56
@sindresorhus
Copy link
Copy Markdown
Owner

And maybe splitOnNumber => splitOnNumbers?

@filipw01 filipw01 force-pushed the improve-delimiter-case branch from e983b73 to 5bd9be0 Compare February 25, 2025 23:51
Copy link
Copy Markdown
Collaborator

@som-sm som-sm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR LGTM!

@filipw01 I've removed all formatting-related changes in word.d.ts in b3c49aa. Please give it a quick look to make sure I haven't accidentally messed anything up.

@filipw01
Copy link
Copy Markdown
Contributor Author

Looks good 😉

@sindresorhus sindresorhus merged commit a463c30 into sindresorhus:main Feb 26, 2025
12 checks passed
};

type DefaultOptions = {
splitOnNumbers: true;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this default to false? 4.36.0 seems to be a breaking change since I have to set this to false to avoid errors using KebabCase.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants