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(utils): add string helper #916

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

feat(utils): add string helper #916

wants to merge 2 commits into from

Conversation

BioPhoton
Copy link
Collaborator

This PR includes helper for the TypeScript plugin #902

@BioPhoton BioPhoton marked this pull request as ready for review January 10, 2025 18:53
@BioPhoton BioPhoton requested a review from matejchalk January 10, 2025 18:53
Copy link

github-actions bot commented Jan 10, 2025

Code PushUp

🤨 Code PushUp report has both improvements and regressions – compared target commit bef6ec1 with source commit 6a74c2d.

🕵️ See full comparison in Code PushUp portal 🔍

🏷️ Categories

🏷️ Category ⭐ Previous score ⭐ Current score 🔄 Score change
Performance 🟡 50 🟡 51 ↑ +1.5
Code coverage 🟢 91 🟢 91 ↓ −0.1
Security 🟡 81 🟡 81
Updates 🟡 80 🟡 80
Accessibility 🟢 91 🟢 91
Best Practices 🟢 100 🟢 100
SEO 🟡 61 🟡 61
Bug prevention 🟢 100 🟢 100
Code style 🟢 100 🟢 100
👍 1 group improved, 👎 1 group regressed, 👍 3 audits improved, 👎 4 audits regressed, 12 audits changed without impacting score

🗃️ Groups

🔌 Plugin 🗃️ Group ⭐ Previous score ⭐ Current score 🔄 Score change
Lighthouse Performance 🟡 50 🟡 51 ↑ +1.5
Code coverage Code coverage metrics 🟢 91 🟢 91 ↓ −0.1

15 other groups are unchanged.

🛡️ Audits

🔌 Plugin 🛡️ Audit 📏 Previous value 📏 Current value 🔄 Value change
Lighthouse Speed Index 🟥 6.2 s 🟨 5.6 s ↓ −10.5 %
Lighthouse Largest Contentful Paint 🟨 3.6 s 🟨 3.5 s ↓ −3.3 %
Lighthouse Total Blocking Time 🟥 3,850 ms 🟥 5,040 ms ↑ +31 %
Lighthouse Time to Interactive 🟥 14.4 s 🟥 14.8 s ↑ +3.2 %
Code coverage Function coverage 🟩 93.2 % 🟩 93.1 % ↓ −0.1 %
Code coverage Branch coverage 🟨 85.8 % 🟨 85.8 % ↑ +0.1 %
Code coverage Line coverage 🟩 90.5 % 🟩 90.5 % ↓ −0.1 %
Lighthouse Avoids enormous network payloads 🟩 Total size was 1,822 KiB 🟩 Total size was 1,826 KiB ↑ +0.2 %
Lighthouse Minimizes main-thread work 🟥 14.4 s 🟥 16.2 s ↑ +12.4 %
Lighthouse JavaScript execution time 🟥 6.2 s 🟥 7.2 s ↑ +15.6 %
Lighthouse Metrics 🟩 100% 🟩 100% ↑ +3.2 %
Lighthouse Max Potential First Input Delay 🟥 2,670 ms 🟥 2,470 ms ↓ −7.7 %
Lighthouse Server Backend Latencies 🟩 320 ms 🟩 210 ms ↓ −34.2 %
Lighthouse Initial server response time was short 🟩 Root document took 430 ms 🟩 Root document took 340 ms ↓ −20.7 %
Lighthouse Reduce unused CSS 🟥 Potential savings of 66 KiB 🟥 Potential savings of 66 KiB ↑ +20 %
Lighthouse Network Round Trip Times 🟩 60 ms 🟩 20 ms ↓ −59.8 %
Lighthouse Eliminate render-blocking resources 🟥 Potential savings of 990 ms 🟥 Potential savings of 1,020 ms ↑ +2.5 %
Lighthouse Uses efficient cache policy on static assets 🟨 28 resources found 🟨 28 resources found ↑ +0.1 %
Lighthouse First Contentful Paint 🟨 2.9 s 🟨 2.9 s ↑ +0.1 %

569 other audits are unchanged.

* @param string - The slug to format.
* @returns The formatted title.
*/
export function kebabCaseToSentence(string = '') {
Copy link
Contributor

Choose a reason for hiding this comment

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

Since export function kebabCaseToCamelCase(string: string) { the param it's not optional, I would not do this optional either

Suggested change
export function kebabCaseToSentence(string = '') {
export function kebabCaseToSentence(string: string) {

Copy link
Collaborator

Choose a reason for hiding this comment

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

Agreed. There would be no sense in calling kebabCaseToSentence() without arguments. Same goes for camelCaseToSentence().

* @param string - The slug to format.
* @returns The formatted title.
*/
export function camelCaseToSentence(string = '') {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This function is missing unit tests.

Comment on lines +59 to +66
describe('kebabCaseToSentence', () => {
it('should convert simple slug to title case', () => {
expect(kebabCaseToSentence('hello-world')).toBe('Hello World');
});

it('should handle multiple hyphens', () => {
expect(kebabCaseToSentence('this-is-a-title')).toBe('This Is A Title');
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

What you've implemented is called title case, not sentence case. See Title Case vs. Sentence Case: What’s the Difference?:

Title case and sentence case are two different styles of capitalization used in writing titles, headings, and headlines. With title case, the first letter of every major word is capitalized, while articles, conjunctions, or prepositions are lowercase—unless they are the first word in the title. In sentence case, only the first word is capitalized, along with any proper nouns in the title or heading.

  • Title case example: The Mystery of the Missing Red Ruby
  • Sentence case example: The mystery of the missing red ruby

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe string.ts a bit too broad? 🤔 How about casings.ts or case-conversions.ts?

Copy link
Collaborator

Choose a reason for hiding this comment

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

We have a capitalize function in transform.ts. Since it's also about converting string case, it could be moved in here.

Comment on lines +19 to +24
export type CamelCaseToKebabCase<T extends string> =
T extends `${infer First}${infer Rest}`
? Rest extends Uncapitalize<Rest>
? `${Lowercase<First>}${CamelCaseToKebabCase<Rest>}`
: `${Lowercase<First>}-${CamelCaseToKebabCase<Rest>}`
: T;
Copy link
Collaborator

Choose a reason for hiding this comment

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

The inferred type doesn't match the returned string from camelCaseToKebabCase:

image

It's important (for developer sanity) that the type is consistent with reality, even if that means making the function less "robust". For example, the 'hello_world test' input string isn't in camelCase, so converting it need not be the function's responsibility. After all, the function is called camelCaseToKebabCase, it doesn't claim to convert anything to kebab-case. Simplifying the runtime conversion will also simplify the type conversion - reimplementing the current conversion in types would very challenging otherwise.

Copy link
Collaborator

Choose a reason for hiding this comment

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

BTW, Vitest supports Testing Types. We should consider that for these complex types. I actually used it recently here and it works really well, all I had to do was add --typecheck to vitest command. We could leave that for another PR, though.

* @param string - The kebab-case string to convert.
* @returns The camelCase string.
*/
export function kebabCaseToCamelCase(string: string) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since the inverse function uses a CamelCaseToKebabCase<T>, why not create a KebabCaseToCamelCase<T> type also? It's actually a lot easier to do the conversion in this direction:

export type KebabCaseToCamelCase<T extends string> =
  T extends `${infer First}-${infer Rest}`
    ? `${First}${Capitalize<KebabCaseToCamelCase<Rest>>}`
    : T;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants