Implementing url Methods (#49955)

Summary:
Implemented Methods in URL which were not implemented yet
The methods output are identical to outputs of window.url .

Fixes https://github.com/facebook/react-native/issues/45030

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->
[General][Added] URL accessors for unimplemented Methods

Pull Request resolved: https://github.com/facebook/react-native/pull/49955

Test Plan:
Code:-
<img width="558" alt="image" src="https://github.com/user-attachments/assets/a75e5429-0e03-4392-9fde-138c63b96ce5" />

Tested with Hermes
![image](https://github.com/user-attachments/assets/0075826a-df3a-4eae-a8f2-bec26be42fbf)

Tested with JSC
![image](https://github.com/user-attachments/assets/bcdbd430-5ee3-48a2-873f-7d823c9072f6)

Reviewed By: rshest

Differential Revision: D71113046

Pulled By: cortinico

fbshipit-source-id: 58093c61d2e7bb732d2f1af6b19508a100c86333
This commit is contained in:
Ritesh Kumar Shukla
2025-03-14 05:22:48 -07:00
committed by Facebook GitHub Bot
parent ef0de0e848
commit 3dac90006f
5 changed files with 137 additions and 10 deletions
+23 -10
View File
@@ -107,15 +107,21 @@ export class URL {
}
get hash(): string {
throw new Error('URL.hash is not implemented');
const hashMatch = this._url.match(/#([^/]*)/);
return hashMatch ? `#${hashMatch[1]}` : '';
}
get host(): string {
throw new Error('URL.host is not implemented');
const hostMatch = this._url.match(/^https?:\/\/(?:[^@]+@)?([^:/?#]+)/);
const portMatch = this._url.match(/:(\d+)(?=[/?#]|$)/);
return hostMatch
? hostMatch[1] + (portMatch ? `:${portMatch[1]}` : '')
: '';
}
get hostname(): string {
throw new Error('URL.hostname is not implemented');
const hostnameMatch = this._url.match(/^https?:\/\/(?:[^@]+@)?([^:/?#]+)/);
return hostnameMatch ? hostnameMatch[1] : '';
}
get href(): string {
@@ -123,27 +129,33 @@ export class URL {
}
get origin(): string {
throw new Error('URL.origin is not implemented');
const matches = this._url.match(/^(https?:\/\/[^/]+)/);
return matches ? matches[1] : '';
}
get password(): string {
throw new Error('URL.password is not implemented');
const passwordMatch = this._url.match(/https?:\/\/.*:(.*)@/);
return passwordMatch ? passwordMatch[1] : '';
}
get pathname(): string {
throw new Error('URL.pathname not implemented');
const pathMatch = this._url.match(/https?:\/\/[^/]+(\/[^?#]*)?/);
return pathMatch ? pathMatch[1] || '/' : '/';
}
get port(): string {
throw new Error('URL.port is not implemented');
const portMatch = this._url.match(/:(\d+)(?=[/?#]|$)/);
return portMatch ? portMatch[1] : '';
}
get protocol(): string {
throw new Error('URL.protocol is not implemented');
const protocolMatch = this._url.match(/^([a-zA-Z][a-zA-Z\d+\-.]*):/);
return protocolMatch ? protocolMatch[1] + ':' : '';
}
get search(): string {
throw new Error('URL.search is not implemented');
const searchMatch = this._url.match(/\?([^#]*)/);
return searchMatch ? `?${searchMatch[1]}` : '';
}
get searchParams(): URLSearchParams {
@@ -168,6 +180,7 @@ export class URL {
}
get username(): string {
throw new Error('URL.username is not implemented');
const usernameMatch = this._url.match(/^https?:\/\/([^:@]+)(?::[^@]*)?@/);
return usernameMatch ? usernameMatch[1] : '';
}
}
@@ -40,5 +40,17 @@ describe('URL', function () {
// Insert / between Base and Path if missing
const k = new URL('en-US/docs', 'https://developer.mozilla.org');
expect(k.href).toBe('https://developer.mozilla.org/en-US/docs');
//More cases
const url = new URL(
'https://username:password@reactnative.dev:8080/docs/path?query=testQuery&key=value#fragment',
);
expect(url.hash).toBe('#fragment');
expect(url.host).toBe('reactnative.dev:8080');
expect(url.hostname).toBe('reactnative.dev');
expect(url.password).toBe('password');
expect(url.username).toBe('username');
expect(url.pathname).toBe('/docs/path');
expect(url.port).toBe('8080');
expect(url.search).toBe('?query=testQuery&key=value');
});
});
@@ -0,0 +1,92 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
'use strict';
import type {RNTesterModuleExample} from '../../types/RNTesterTypes';
import RNTesterText from '../../components/RNTesterText';
import React from 'react';
import {StyleSheet, View} from 'react-native';
type Props = {
url: string,
};
function URLComponent(props: Props) {
const parsedUrl = new URL(props.url);
return (
<View style={styles.container}>
<RNTesterText testID="URL-href">{`href: ${parsedUrl.href}`}</RNTesterText>
<RNTesterText testID="URL-hash">{`hash: ${parsedUrl.hash}`}</RNTesterText>
<RNTesterText testID="URL-host">{`host: ${parsedUrl.host}`}</RNTesterText>
<RNTesterText testID="URL-hostname">{`hostname: ${parsedUrl.hostname}`}</RNTesterText>
<RNTesterText testID="URL-password">{`password: ${parsedUrl.password}`}</RNTesterText>
<RNTesterText testID="URL-username">{`username: ${parsedUrl.username}`}</RNTesterText>
<RNTesterText testID="URL-pathname">{`pathname: ${parsedUrl.pathname}`}</RNTesterText>
<RNTesterText testID="URL-port">{`port: ${parsedUrl.port}`}</RNTesterText>
<RNTesterText testID="URL-search">{`search: ${parsedUrl.search}`}</RNTesterText>
</View>
);
}
const styles = StyleSheet.create({
container: {
padding: 10,
},
});
exports.title = 'URL';
exports.category = 'Basic';
exports.description = 'URL Parameters test';
exports.examples = [
{
title: 'completeURL',
description: 'URL with username,password,port,and queryparams',
render(): React.Node {
return (
<URLComponent
url={
'https://username:password@reactnative.dev:8080/docs/path?query=testQuery&key=value#fragment'
}
/>
);
},
},
{
title: 'basicURL',
description: 'Basic URL without username, password, or port',
render(): React.Node {
return <URLComponent url={'https://reactnative.dev/docs/path'} />;
},
},
{
title: 'queryParamsURL',
description: 'URL with query parameters',
render(): React.Node {
return (
<URLComponent
url={'https://reactnative.dev/docs/path?query=testQuery&key=value'}
/>
);
},
},
{
title: 'authAndPortURL',
description: 'URL with username, password, and port',
render(): React.Node {
return (
<URLComponent
url={'https://username:password@reactnative.dev:8080/docs/path'}
/>
);
},
},
] as Array<RNTesterModuleExample>;
@@ -187,6 +187,11 @@ const APIs: Array<RNTesterModuleInfo> = ([
category: 'Basic',
module: require('../examples/AppState/AppStateExample'),
},
{
key: 'URLExample',
category: 'Basic',
module: require('../examples/Urls/UrlExample'),
},
{
key: 'BorderExample',
category: 'UI',
@@ -192,6 +192,11 @@ const APIs: Array<RNTesterModuleInfo> = ([
key: 'AppStateExample',
module: require('../examples/AppState/AppStateExample'),
},
{
key: 'URLExample',
category: 'Basic',
module: require('../examples/Urls/UrlExample'),
},
{
key: 'BorderExample',
module: require('../examples/Border/BorderExample').default,