Break out URLSearchParams, require typedef for unparsable files (#45783)

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

Improves type strictness in the `react-native` package.

- Break out `URLSearchParams` from `URL.js` into its own module, to isolate a `$FlowFixMe[unsupported-syntax]` suppression within that definition.
- Update `public-api-test` to require an adjacent `<module>.js.flow` type definition file whenever a `$FlowFixMe[unsupported-syntax]`is present.
- Add `URLSearchParams.js.flow` with a Flow parser compatible typedef (`@iterator` instead of `[Symbol.iterator]`).

The result of these changes is to add missing typedef test coverage for `Libraries/Blob/URL.js` (see updated test snapshots).

Changelog: [Internal]

Reviewed By: hoxyq

Differential Revision: D60376327

fbshipit-source-id: 93c0949289a4b53f621f563769ffb68d5dc38d91
This commit is contained in:
Alex Hunt
2024-08-08 10:38:12 -07:00
committed by Facebook GitHub Bot
parent 0e9c9c7c6e
commit 51ffc5cc12
5 changed files with 154 additions and 67 deletions
+2 -62
View File
@@ -27,7 +27,7 @@ if (
}
}
/**
/*
* To allow Blobs be accessed via `content://` URIs,
* you need to register `BlobProvider` as a ContentProvider in your app's `AndroidManifest.xml`:
*
@@ -52,67 +52,7 @@ if (
* ```
*/
// Small subset from whatwg-url: https://github.com/jsdom/whatwg-url/tree/master/src
// The reference code bloat comes from Unicode issues with URLs, so those won't work here.
export class URLSearchParams {
_searchParams: Array<Array<string>> = [];
constructor(params: any) {
if (typeof params === 'object') {
Object.keys(params).forEach(key => this.append(key, params[key]));
}
}
append(key: string, value: string): void {
this._searchParams.push([key, value]);
}
delete(name: string): void {
throw new Error('URLSearchParams.delete is not implemented');
}
get(name: string): void {
throw new Error('URLSearchParams.get is not implemented');
}
getAll(name: string): void {
throw new Error('URLSearchParams.getAll is not implemented');
}
has(name: string): void {
throw new Error('URLSearchParams.has is not implemented');
}
set(name: string, value: string): void {
throw new Error('URLSearchParams.set is not implemented');
}
sort(): void {
throw new Error('URLSearchParams.sort is not implemented');
}
// $FlowFixMe[unsupported-syntax]
// $FlowFixMe[missing-local-annot]
[Symbol.iterator]() {
return this._searchParams[Symbol.iterator]();
}
toString(): string {
if (this._searchParams.length === 0) {
return '';
}
const last = this._searchParams.length - 1;
return this._searchParams.reduce((acc, curr, index) => {
return (
acc +
encodeURIComponent(curr[0]) +
'=' +
encodeURIComponent(curr[1]) +
(index === last ? '' : '&')
);
}, '');
}
}
export {URLSearchParams} from './URLSearchParams';
function validateBaseUrl(url: string) {
// from this MIT-licensed gist: https://gist.github.com/dperini/729294
+71
View File
@@ -0,0 +1,71 @@
/**
* 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
*/
// Small subset from whatwg-url: https://github.com/jsdom/whatwg-url/tree/master/src
// The reference code bloat comes from Unicode issues with URLs, so those won't work here.
export class URLSearchParams {
_searchParams: Array<Array<string>> = [];
constructor(params: any) {
if (typeof params === 'object') {
Object.keys(params).forEach(key => this.append(key, params[key]));
}
}
append(key: string, value: string): void {
this._searchParams.push([key, value]);
}
delete(name: string): void {
throw new Error('URLSearchParams.delete is not implemented');
}
get(name: string): void {
throw new Error('URLSearchParams.get is not implemented');
}
getAll(name: string): void {
throw new Error('URLSearchParams.getAll is not implemented');
}
has(name: string): void {
throw new Error('URLSearchParams.has is not implemented');
}
set(name: string, value: string): void {
throw new Error('URLSearchParams.set is not implemented');
}
sort(): void {
throw new Error('URLSearchParams.sort is not implemented');
}
// $FlowFixMe[unsupported-syntax]
// $FlowFixMe[missing-local-annot]
[Symbol.iterator]() {
return this._searchParams[Symbol.iterator]();
}
toString(): string {
if (this._searchParams.length === 0) {
return '';
}
const last = this._searchParams.length - 1;
return this._searchParams.reduce((acc, curr, index) => {
return (
acc +
encodeURIComponent(curr[0]) +
'=' +
encodeURIComponent(curr[1]) +
(index === last ? '' : '&')
);
}, '');
}
}
@@ -0,0 +1,23 @@
/**
* 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
*/
declare export class URLSearchParams {
_searchParams: Array<Array<string>>;
constructor(params: any): void;
append(key: string, value: string): void;
delete(name: string): void;
get(name: string): void;
getAll(name: string): void;
has(name: string): void;
set(name: string, value: string): void;
sort(): void;
@@iterator: Iterator<Array<string>>;
toString(): string;
}
@@ -1507,7 +1507,48 @@ declare export default typeof NativeFileReaderModule;
"
`;
exports[`public API should not change unintentionally Libraries/Blob/URL.js 1`] = `"UNTYPED MODULE (unsupported-syntax suppression)"`;
exports[`public API should not change unintentionally Libraries/Blob/URL.js 1`] = `
"export { URLSearchParams } from \\"./URLSearchParams\\";
declare export class URL {
_url: string;
_searchParamsInstance: ?URLSearchParams;
static createObjectURL(blob: Blob): string;
static revokeObjectURL(url: string): void;
constructor(url: string, base: string | URL): void;
get hash(): string;
get host(): string;
get hostname(): string;
get href(): string;
get origin(): string;
get password(): string;
get pathname(): string;
get port(): string;
get protocol(): string;
get search(): string;
get searchParams(): URLSearchParams;
toJSON(): string;
toString(): string;
get username(): string;
}
"
`;
exports[`public API should not change unintentionally Libraries/Blob/URLSearchParams.js.flow 1`] = `
"declare export class URLSearchParams {
_searchParams: Array<Array<string>>;
constructor(params: any): void;
append(key: string, value: string): void;
delete(name: string): void;
get(name: string): void;
getAll(name: string): void;
has(name: string): void;
set(name: string, value: string): void;
sort(): void;
@@iterator: Iterator<Array<string>>;
toString(): string;
}
"
`;
exports[`public API should not change unintentionally Libraries/BugReporting/BugReporting.js 1`] = `
"type ExtraData = { [key: string]: string, ... };
@@ -12,7 +12,7 @@
import type {TransformVisitor} from 'hermes-transform';
const translate = require('flow-api-translator');
const {promises: fs} = require('fs');
const {existsSync, promises: fs} = require('fs');
const glob = require('glob');
const {transform} = require('hermes-transform');
const path = require('path');
@@ -47,10 +47,22 @@ describe('public API', () => {
const source = await fs.readFile(path.join(PACKAGE_ROOT, file), 'utf-8');
if (/@flow/.test(source)) {
// Require and use adjacent .js.flow file when source file includes an
// unsupported-syntax suppression
if (source.includes('// $FlowFixMe[unsupported-syntax]')) {
expect(
'UNTYPED MODULE (unsupported-syntax suppression)',
).toMatchSnapshot();
const flowDefPath = path.join(
PACKAGE_ROOT,
file.replace('.js', '.js.flow'),
);
if (!existsSync(flowDefPath)) {
throw new Error(
'Found an unsupported-syntax suppression in ' +
file +
', meaning types cannot be parsed. Add an adjacent <module>.js.flow file to fix this!',
);
}
return;
}