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

Migrate url tooling to twenty-shared #10440

Merged
merged 8 commits into from
Feb 24, 2025
Merged

Migrate url tooling to twenty-shared #10440

merged 8 commits into from
Feb 24, 2025

Conversation

charlesBochet
Copy link
Member

@charlesBochet charlesBochet commented Feb 24, 2025

Migrate and unify URL tooling in twenty-shared.

We now have:

  • isValidHostname which follows our own business rules
  • a zod schema that can be re-used in different context and leverages is isValidHostname
  • isValidUrl on top of the zod schema
  • a getAbsoluteURl and getHostname on top of the zod schema

I have added a LOT of tests to cover all the cases I've found

Also fixes: #10147

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

PR Summary

This PR migrates URL-related utilities from the frontend and server packages to the twenty-shared package, centralizing URL validation and manipulation functions for better code organization and reuse.

  • Modified regex pattern in packages/twenty-shared/src/utils/url/isDomain.ts changes domain validation behavior, potentially affecting handling of internationalized domains and multi-level TLDs
  • Duplicate test case for 'http://localhost:3000' in packages/twenty-shared/src/utils/url/__tests__/isValidUrl.test.ts needs to be removed
  • Test suite in isValidUrl.test.ts lacks coverage for edge cases like IDN domains and URLs with authentication credentials
  • Import paths across multiple components have been updated to use the shared package, ensuring consistent URL validation across the application

22 file(s) reviewed, 8 comment(s)
Edit PR Review Bot Settings | Greptile

@@ -1,5 +1,5 @@
export const isDomain = (url: string | undefined | null) =>
!!url &&
/^((?!-))(xn--)?[a-z0-9][a-z0-9-_]{0,61}[a-z0-9]{0,1}\.(xn--)?([a-z0-9-]{1,61}|[a-z0-9-]{1,30}\.[a-z]{2,})$/.test(
/^((?!-))(xn--)?[a-z0-9][a-z0-9-_]{0,61}[a-z0-9]{0,1}\.[a-z0-9-]{1,61}(\.[a-z]{2,})?$/.test(
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: The new regex pattern may incorrectly validate some invalid domains by making the TLD optional. Consider keeping TLD validation mandatory by removing the ? after (\.[a-z]{2,})

Suggested change
/^((?!-))(xn--)?[a-z0-9][a-z0-9-_]{0,61}[a-z0-9]{0,1}\.[a-z0-9-]{1,61}(\.[a-z]{2,})?$/.test(
/^((?!-))(xn--)?[a-z0-9][a-z0-9-_]{0,61}[a-z0-9]{0,1}\.[a-z0-9-]{1,61}(\.[a-z]{2,})$/.test(

@@ -18,5 +18,5 @@
"src/**/*.d.ts",
"src/**/*.ts",
"src/**/*.tsx"
]
, "../twenty-shared/src/utils/url/absoluteUrlSchema.ts", "../twenty-shared/src/utils/url/is-domain.ts" ]
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: The file path 'is-domain.ts' doesn't match the actual file name 'isDomain.ts' in twenty-shared package. This will cause build errors.

Suggested change
, "../twenty-shared/src/utils/url/absoluteUrlSchema.ts", "../twenty-shared/src/utils/url/is-domain.ts" ]
, "../twenty-shared/src/utils/url/absoluteUrlSchema.ts", "../twenty-shared/src/utils/url/isDomain.ts" ]

@@ -18,5 +18,5 @@
"src/**/*.d.ts",
"src/**/*.ts",
"src/**/*.tsx"
]
, "../twenty-shared/src/utils/url/absoluteUrlSchema.ts", "../twenty-shared/src/utils/url/is-domain.ts" ]
Copy link
Contributor

Choose a reason for hiding this comment

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

style: The formatting of this line is inconsistent with the rest of the file. The new entries should be on separate lines with proper indentation.

@@ -29,5 +29,6 @@ describe('absoluteUrlSchema', () => {
it('fails for invalid urls', () => {
expect(absoluteUrlSchema.safeParse('?o').success).toBe(false);
expect(absoluteUrlSchema.safeParse('\\').success).toBe(false);
expect(absoluteUrlSchema.safeParse('https://2')).toBe(false);
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: The safeParse() method returns an object with a success property, but here we're comparing the entire result directly to false. This will always fail since an object can't equal false. Should be absoluteUrlSchema.safeParse('https://2').success

Suggested change
expect(absoluteUrlSchema.safeParse('https://2')).toBe(false);
expect(absoluteUrlSchema.safeParse('https://2').success).toBe(false);

@@ -1,4 +1,4 @@
import { getAbsoluteUrl } from '~/utils/url/getAbsoluteUrl';
import { getAbsoluteUrl } from 'src/utils/url/getAbsoluteUrl';
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Import path 'src/utils/url/getAbsoluteUrl' may need to be relative ('../getAbsoluteUrl') since both files are in the same directory


export const isDomain = (url: string | undefined | null) =>
isDefined(url) &&
/^((?!-))(xn--)?[a-z0-9][a-z0-9-_]{0,61}[a-z0-9]{0,1}\.[a-z0-9-]{1,61}(\.[a-z]{2,})$/.test(
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: The regex pattern has a limitation - it doesn't properly handle domains with multiple levels (e.g. 'sub.example.co.uk'). Consider updating to handle these cases.


export const isDomain = (url: string | undefined | null) =>
isDefined(url) &&
/^((?!-))(xn--)?[a-z0-9][a-z0-9-_]{0,61}[a-z0-9]{0,1}\.[a-z0-9-]{1,61}(\.[a-z]{2,})$/.test(
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: The regex allows underscores in domain names which is technically invalid according to RFC 1035. The '' should be removed from the character class [a-z0-9-].

Suggested change
/^((?!-))(xn--)?[a-z0-9][a-z0-9-_]{0,61}[a-z0-9]{0,1}\.[a-z0-9-]{1,61}(\.[a-z]{2,})$/.test(
/^((?!-))(xn--)?[a-z0-9][a-z0-9-]{0,61}[a-z0-9]{0,1}\.[a-z0-9-]{1,61}(\.[a-z]{2,})$/.test(


export const isDomain = (url: string | undefined | null) =>
isDefined(url) &&
/^((?!-))(xn--)?[a-z0-9][a-z0-9-_]{0,61}[a-z0-9]{0,1}\.[a-z0-9-]{1,61}(\.[a-z]{2,})$/.test(
Copy link
Contributor

Choose a reason for hiding this comment

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

style: The pattern enforces lowercase only ([a-z0-9]). Convert url.toLowerCase() before testing to handle uppercase domains.

Suggested change
/^((?!-))(xn--)?[a-z0-9][a-z0-9-_]{0,61}[a-z0-9]{0,1}\.[a-z0-9-]{1,61}(\.[a-z]{2,})$/.test(
/^((?!-))(xn--)?[a-z0-9][a-z0-9-_]{0,61}[a-z0-9]{0,1}\.[a-z0-9-]{1,61}(\.[a-z]{2,})$/.test(url.toLowerCase(),

Copy link
Member

@Weiko Weiko left a comment

Choose a reason for hiding this comment

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

LGTM

.replace('https://', '')
.replace('http://', '');

console.log('valueWithoutProtocol', valueWithoutProtocol);
Copy link
Member

Choose a reason for hiding this comment

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

console log

return z.NEVER;
}

console.log('absoluteUrl', absoluteUrl);
Copy link
Member

Choose a reason for hiding this comment

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

log

return absoluteUrl;
}

console.log('url', url);
Copy link
Member

Choose a reason for hiding this comment

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

log

@charlesBochet charlesBochet merged commit 9046a9a into main Feb 24, 2025
49 checks passed
@charlesBochet charlesBochet deleted the prevent-invalid-link branch February 24, 2025 17:01
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.

Filter "not 0" doesn't work
2 participants