fix: prevent asset conflicts between React and Grid.js versions

Add coexistence checks to all enqueue methods to prevent loading
both React and Grid.js assets simultaneously.

Changes:
- ReactAdmin.php: Only enqueue React assets when ?react=1
- Init.php: Skip Grid.js when React active on admin pages
- Form.php, Coupon.php, Access.php: Restore classic assets when ?react=0
- Customer.php, Product.php, License.php: Add coexistence checks

Now the toggle between Classic and React versions works correctly.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
dwindown
2026-04-18 17:02:14 +07:00
parent bd9cdac02e
commit e8fbfb14c1
74973 changed files with 6658406 additions and 71 deletions

42
node_modules/@wordpress/url/src/add-query-args.js generated vendored Normal file
View File

@@ -0,0 +1,42 @@
/**
* Internal dependencies
*/
import { getQueryArgs } from './get-query-args';
import { buildQueryString } from './build-query-string';
/**
* Appends arguments as querystring to the provided URL. If the URL already
* includes query arguments, the arguments are merged with (and take precedent
* over) the existing set.
*
* @param {string} [url=''] URL to which arguments should be appended. If omitted,
* only the resulting querystring is returned.
* @param {Object} [args] Query arguments to apply to URL.
*
* @example
* ```js
* const newURL = addQueryArgs( 'https://google.com', { q: 'test' } ); // https://google.com/?q=test
* ```
*
* @return {string} URL with arguments applied.
*/
export function addQueryArgs( url = '', args ) {
// If no arguments are to be appended, return original URL.
if ( ! args || ! Object.keys( args ).length ) {
return url;
}
let baseUrl = url;
// Determine whether URL already had query arguments.
const queryStringIndex = url.indexOf( '?' );
if ( queryStringIndex !== -1 ) {
// Merge into existing query arguments.
args = Object.assign( getQueryArgs( url ), args );
// Change working base URL to omit previous query arguments.
baseUrl = baseUrl.substr( 0, queryStringIndex );
}
return baseUrl + '?' + buildQueryString( args );
}

61
node_modules/@wordpress/url/src/build-query-string.js generated vendored Normal file
View File

@@ -0,0 +1,61 @@
/**
* Generates URL-encoded query string using input query data.
*
* It is intended to behave equivalent as PHP's `http_build_query`, configured
* with encoding type PHP_QUERY_RFC3986 (spaces as `%20`).
*
* @example
* ```js
* const queryString = buildQueryString( {
* simple: 'is ok',
* arrays: [ 'are', 'fine', 'too' ],
* objects: {
* evenNested: {
* ok: 'yes',
* },
* },
* } );
* // "simple=is%20ok&arrays%5B0%5D=are&arrays%5B1%5D=fine&arrays%5B2%5D=too&objects%5BevenNested%5D%5Bok%5D=yes"
* ```
*
* @param {Record<string,*>} data Data to encode.
*
* @return {string} Query string.
*/
export function buildQueryString( data ) {
let string = '';
const stack = Object.entries( data );
let pair;
while ( ( pair = stack.shift() ) ) {
let [ key, value ] = pair;
// Support building deeply nested data, from array or object values.
const hasNestedData =
Array.isArray( value ) || ( value && value.constructor === Object );
if ( hasNestedData ) {
// Push array or object values onto the stack as composed of their
// original key and nested index or key, retaining order by a
// combination of Array#reverse and Array#unshift onto the stack.
const valuePairs = Object.entries( value ).reverse();
for ( const [ member, memberValue ] of valuePairs ) {
stack.unshift( [ `${ key }[${ member }]`, memberValue ] );
}
} else if ( value !== undefined ) {
// Null is treated as special case, equivalent to empty string.
if ( value === null ) {
value = '';
}
string +=
'&' + [ key, value ].map( encodeURIComponent ).join( '=' );
}
}
// Loop will concatenate with leading `&`, but it's only expected for all
// but the first query parameter. This strips the leading `&`, while still
// accounting for the case that the string may in-fact be empty.
return string.substr( 1 );
}

39
node_modules/@wordpress/url/src/clean-for-slug.js generated vendored Normal file
View File

@@ -0,0 +1,39 @@
/**
* External dependencies
*/
import removeAccents from 'remove-accents';
/**
* Performs some basic cleanup of a string for use as a post slug.
*
* This replicates some of what `sanitize_title()` does in WordPress core, but
* is only designed to approximate what the slug will be.
*
* Converts Latin-1 Supplement and Latin Extended-A letters to basic Latin
* letters. Removes combining diacritical marks. Converts whitespace, periods,
* and forward slashes to hyphens. Removes any remaining non-word characters
* except hyphens. Converts remaining string to lowercase. It does not account
* for octets, HTML entities, or other encoded characters.
*
* @param {string} string Title or slug to be processed.
*
* @return {string} Processed string.
*/
export function cleanForSlug( string ) {
if ( ! string ) {
return '';
}
return (
removeAccents( string )
// Convert each group of whitespace, periods, and forward slashes to a hyphen.
.replace( /[\s\./]+/g, '-' )
// Remove anything that's not a letter, number, underscore or hyphen.
.replace( /[^\p{L}\p{N}_-]+/gu, '' )
// Convert to lowercase
.toLowerCase()
// Replace multiple hyphens with a single one.
.replace( /-+/g, '-' )
// Remove any remaining leading or trailing hyphens.
.replace( /(^-+)|(-+$)/g, '' )
);
}

View File

@@ -0,0 +1,55 @@
/**
* Returns a URL for display.
*
* @param {string} url Original URL.
* @param {number|null} maxLength URL length.
*
* @example
* ```js
* const displayUrl = filterURLForDisplay( 'https://www.wordpress.org/gutenberg/' ); // wordpress.org/gutenberg
* const imageUrl = filterURLForDisplay( 'https://www.wordpress.org/wp-content/uploads/img.png', 20 ); // …ent/uploads/img.png
* ```
*
* @return {string} Displayed URL.
*/
export function filterURLForDisplay( url, maxLength = null ) {
// Remove protocol and www prefixes.
let filteredURL = url.replace( /^(?:https?:)\/\/(?:www\.)?/, '' );
// Ends with / and only has that single slash, strip it.
if ( filteredURL.match( /^[^\/]+\/$/ ) ) {
filteredURL = filteredURL.replace( '/', '' );
}
// capture file name from URL
const fileRegexp = /\/([^\/?]+)\.(?:[\w]+)(?=\?|$)/;
if (
! maxLength ||
filteredURL.length <= maxLength ||
! filteredURL.match( fileRegexp )
) {
return filteredURL;
}
// If the file is not greater than max length, return last portion of URL.
filteredURL = filteredURL.split( '?' )[ 0 ];
const urlPieces = filteredURL.split( '/' );
const file = urlPieces[ urlPieces.length - 1 ];
if ( file.length <= maxLength ) {
return '…' + filteredURL.slice( -maxLength );
}
// If the file is greater than max length, truncate the file.
const index = file.lastIndexOf( '.' );
const [ fileName, extension ] = [
file.slice( 0, index ),
file.slice( index + 1 ),
];
const truncatedFile = fileName.slice( -3 ) + '.' + extension;
return (
file.slice( 0, maxLength - truncatedFile.length - 1 ) +
'…' +
truncatedFile
);
}

21
node_modules/@wordpress/url/src/get-authority.js generated vendored Normal file
View File

@@ -0,0 +1,21 @@
/**
* Returns the authority part of the URL.
*
* @param {string} url The full URL.
*
* @example
* ```js
* const authority1 = getAuthority( 'https://wordpress.org/help/' ); // 'wordpress.org'
* const authority2 = getAuthority( 'https://localhost:8080/test/' ); // 'localhost:8080'
* ```
*
* @return {string|void} The authority part of the URL.
*/
export function getAuthority( url ) {
const matches = /^[^\/\s:]+:(?:\/\/)?\/?([^\/\s#?]+)[\/#?]{0,1}\S*$/.exec(
url
);
if ( matches ) {
return matches[ 1 ];
}
}

30
node_modules/@wordpress/url/src/get-filename.js generated vendored Normal file
View File

@@ -0,0 +1,30 @@
/**
* Returns the filename part of the URL.
*
* @param {string} url The full URL.
*
* @example
* ```js
* const filename1 = getFilename( 'http://localhost:8080/this/is/a/test.jpg' ); // 'test.jpg'
* const filename2 = getFilename( '/this/is/a/test.png' ); // 'test.png'
* ```
*
* @return {string|void} The filename part of the URL.
*/
export function getFilename( url ) {
let filename;
if ( ! url ) {
return;
}
try {
filename = new URL( url, 'http://example.com' ).pathname
.split( '/' )
.pop();
} catch ( error ) {}
if ( filename ) {
return filename;
}
}

19
node_modules/@wordpress/url/src/get-fragment.js generated vendored Normal file
View File

@@ -0,0 +1,19 @@
/**
* Returns the fragment part of the URL.
*
* @param {string} url The full URL
*
* @example
* ```js
* const fragment1 = getFragment( 'http://localhost:8080/this/is/a/test?query=true#fragment' ); // '#fragment'
* const fragment2 = getFragment( 'https://wordpress.org#another-fragment?query=true' ); // '#another-fragment'
* ```
*
* @return {string|void} The fragment part of the URL.
*/
export function getFragment( url ) {
const matches = /^\S+?(#[^\s\?]*)/.exec( url );
if ( matches ) {
return matches[ 1 ];
}
}

View File

@@ -0,0 +1,30 @@
/**
* Internal dependencies
*/
import { getPath, getQueryString } from '.';
/**
* Returns the path part and query string part of the URL.
*
* @param {string} url The full URL.
*
* @example
* ```js
* const pathAndQueryString1 = getPathAndQueryString( 'http://localhost:8080/this/is/a/test?query=true' ); // '/this/is/a/test?query=true'
* const pathAndQueryString2 = getPathAndQueryString( 'https://wordpress.org/help/faq/' ); // '/help/faq'
* ```
*
* @return {string} The path part and query string part of the URL.
*/
export function getPathAndQueryString( url ) {
const path = getPath( url );
const queryString = getQueryString( url );
let value = '/';
if ( path ) {
value += path;
}
if ( queryString ) {
value += `?${ queryString }`;
}
return value;
}

20
node_modules/@wordpress/url/src/get-path.js generated vendored Normal file
View File

@@ -0,0 +1,20 @@
/**
* Returns the path part of the URL.
*
* @param {string} url The full URL.
*
* @example
* ```js
* const path1 = getPath( 'http://localhost:8080/this/is/a/test?query=true' ); // 'this/is/a/test'
* const path2 = getPath( 'https://wordpress.org/help/faq/' ); // 'help/faq'
* ```
*
* @return {string|void} The path part of the URL.
*/
export function getPath( url ) {
const matches =
/^[^\/\s:]+:(?:\/\/)?[^\/\s#?]+[\/]([^\s#?]+)[#?]{0,1}\S*$/.exec( url );
if ( matches ) {
return matches[ 1 ];
}
}

19
node_modules/@wordpress/url/src/get-protocol.js generated vendored Normal file
View File

@@ -0,0 +1,19 @@
/**
* Returns the protocol part of the URL.
*
* @param {string} url The full URL.
*
* @example
* ```js
* const protocol1 = getProtocol( 'tel:012345678' ); // 'tel:'
* const protocol2 = getProtocol( 'https://wordpress.org' ); // 'https:'
* ```
*
* @return {string|void} The protocol part of the URL.
*/
export function getProtocol( url ) {
const matches = /^([^\s:]+:)/.exec( url );
if ( matches ) {
return matches[ 1 ];
}
}

29
node_modules/@wordpress/url/src/get-query-arg.js generated vendored Normal file
View File

@@ -0,0 +1,29 @@
/**
* Internal dependencies
*/
import { getQueryArgs } from './get-query-args';
/**
* @typedef {{[key: string]: QueryArgParsed}} QueryArgObject
*/
/**
* @typedef {string|string[]|QueryArgObject} QueryArgParsed
*/
/**
* Returns a single query argument of the url
*
* @param {string} url URL.
* @param {string} arg Query arg name.
*
* @example
* ```js
* const foo = getQueryArg( 'https://wordpress.org?foo=bar&bar=baz', 'foo' ); // bar
* ```
*
* @return {QueryArgParsed|void} Query arg value.
*/
export function getQueryArg( url, arg ) {
return getQueryArgs( url )[ arg ];
}

99
node_modules/@wordpress/url/src/get-query-args.js generated vendored Normal file
View File

@@ -0,0 +1,99 @@
/**
* Internal dependencies
*/
import { safeDecodeURIComponent } from './safe-decode-uri-component';
import { getQueryString } from './get-query-string';
/** @typedef {import('./get-query-arg').QueryArgParsed} QueryArgParsed */
/**
* @typedef {Record<string,QueryArgParsed>} QueryArgs
*/
/**
* Sets a value in object deeply by a given array of path segments. Mutates the
* object reference.
*
* @param {Record<string,*>} object Object in which to assign.
* @param {string[]} path Path segment at which to set value.
* @param {*} value Value to set.
*/
function setPath( object, path, value ) {
const length = path.length;
const lastIndex = length - 1;
for ( let i = 0; i < length; i++ ) {
let key = path[ i ];
if ( ! key && Array.isArray( object ) ) {
// If key is empty string and next value is array, derive key from
// the current length of the array.
key = object.length.toString();
}
key = [ '__proto__', 'constructor', 'prototype' ].includes( key )
? key.toUpperCase()
: key;
// If the next key in the path is numeric (or empty string), it will be
// created as an array. Otherwise, it will be created as an object.
const isNextKeyArrayIndex = ! isNaN( Number( path[ i + 1 ] ) );
object[ key ] =
i === lastIndex
? // If at end of path, assign the intended value.
value
: // Otherwise, advance to the next object in the path, creating
// it if it does not yet exist.
object[ key ] || ( isNextKeyArrayIndex ? [] : {} );
if ( Array.isArray( object[ key ] ) && ! isNextKeyArrayIndex ) {
// If we current key is non-numeric, but the next value is an
// array, coerce the value to an object.
object[ key ] = { ...object[ key ] };
}
// Update working reference object to the next in the path.
object = object[ key ];
}
}
/**
* Returns an object of query arguments of the given URL. If the given URL is
* invalid or has no querystring, an empty object is returned.
*
* @param {string} url URL.
*
* @example
* ```js
* const foo = getQueryArgs( 'https://wordpress.org?foo=bar&bar=baz' );
* // { "foo": "bar", "bar": "baz" }
* ```
*
* @return {QueryArgs} Query args object.
*/
export function getQueryArgs( url ) {
return (
( getQueryString( url ) || '' )
// Normalize space encoding, accounting for PHP URL encoding
// corresponding to `application/x-www-form-urlencoded`.
//
// See: https://tools.ietf.org/html/rfc1866#section-8.2.1
.replace( /\+/g, '%20' )
.split( '&' )
.reduce( ( accumulator, keyValue ) => {
const [ key, value = '' ] = keyValue
.split( '=' )
// Filtering avoids decoding as `undefined` for value, where
// default is restored in destructuring assignment.
.filter( Boolean )
.map( safeDecodeURIComponent );
if ( key ) {
const segments = key.replace( /\]/g, '' ).split( '[' );
setPath( accumulator, segments, value );
}
return accumulator;
}, Object.create( null ) )
);
}

22
node_modules/@wordpress/url/src/get-query-string.js generated vendored Normal file
View File

@@ -0,0 +1,22 @@
/**
* Returns the query string part of the URL.
*
* @param {string} url The full URL.
*
* @example
* ```js
* const queryString = getQueryString( 'http://localhost:8080/this/is/a/test?query=true#fragment' ); // 'query=true'
* ```
*
* @return {string|void} The query string part of the URL.
*/
export function getQueryString( url ) {
let query;
try {
query = new URL( url, 'http://example.com' ).search.substring( 1 );
} catch ( error ) {}
if ( query ) {
return query;
}
}

21
node_modules/@wordpress/url/src/has-query-arg.js generated vendored Normal file
View File

@@ -0,0 +1,21 @@
/**
* Internal dependencies
*/
import { getQueryArg } from './get-query-arg';
/**
* Determines whether the URL contains a given query arg.
*
* @param {string} url URL.
* @param {string} arg Query arg name.
*
* @example
* ```js
* const hasBar = hasQueryArg( 'https://wordpress.org?foo=bar&bar=baz', 'bar' ); // true
* ```
*
* @return {boolean} Whether or not the URL contains the query arg.
*/
export function hasQueryArg( url, arg ) {
return getQueryArg( url, arg ) !== undefined;
}

27
node_modules/@wordpress/url/src/index.js generated vendored Normal file
View File

@@ -0,0 +1,27 @@
export { isURL } from './is-url';
export { isEmail } from './is-email';
export { getProtocol } from './get-protocol';
export { isValidProtocol } from './is-valid-protocol';
export { getAuthority } from './get-authority';
export { isValidAuthority } from './is-valid-authority';
export { getPath } from './get-path';
export { isValidPath } from './is-valid-path';
export { getQueryString } from './get-query-string';
export { buildQueryString } from './build-query-string';
export { isValidQueryString } from './is-valid-query-string';
export { getPathAndQueryString } from './get-path-and-query-string';
export { getFragment } from './get-fragment';
export { isValidFragment } from './is-valid-fragment';
export { addQueryArgs } from './add-query-args';
export { getQueryArg } from './get-query-arg';
export { getQueryArgs } from './get-query-args';
export { hasQueryArg } from './has-query-arg';
export { removeQueryArgs } from './remove-query-args';
export { prependHTTP } from './prepend-http';
export { safeDecodeURI } from './safe-decode-uri';
export { safeDecodeURIComponent } from './safe-decode-uri-component';
export { filterURLForDisplay } from './filter-url-for-display';
export { cleanForSlug } from './clean-for-slug';
export { getFilename } from './get-filename';
export { normalizePath } from './normalize-path';
export { prependHTTPS } from './prepend-https';

18
node_modules/@wordpress/url/src/is-email.js generated vendored Normal file
View File

@@ -0,0 +1,18 @@
const EMAIL_REGEXP =
/^(mailto:)?[a-z0-9._%+-]+@[a-z0-9][a-z0-9.-]*\.[a-z]{2,63}$/i;
/**
* Determines whether the given string looks like an email.
*
* @param {string} email The string to scrutinise.
*
* @example
* ```js
* const isEmail = isEmail( 'hello@wordpress.org' ); // true
* ```
*
* @return {boolean} Whether or not it looks like an email.
*/
export function isEmail( email ) {
return EMAIL_REGEXP.test( email );
}

25
node_modules/@wordpress/url/src/is-url.js generated vendored Normal file
View File

@@ -0,0 +1,25 @@
/**
* Determines whether the given string looks like a URL.
*
* @param {string} url The string to scrutinise.
*
* @example
* ```js
* const isURL = isURL( 'https://wordpress.org' ); // true
* ```
*
* @see https://url.spec.whatwg.org/
* @see https://url.spec.whatwg.org/#valid-url-string
*
* @return {boolean} Whether or not it looks like a URL.
*/
export function isURL( url ) {
// A URL can be considered value if the `URL` constructor is able to parse
// it. The constructor throws an error for an invalid URL.
try {
new URL( url );
return true;
} catch {
return false;
}
}

19
node_modules/@wordpress/url/src/is-valid-authority.js generated vendored Normal file
View File

@@ -0,0 +1,19 @@
/**
* Checks for invalid characters within the provided authority.
*
* @param {string} authority A string containing the URL authority.
*
* @example
* ```js
* const isValid = isValidAuthority( 'wordpress.org' ); // true
* const isNotValid = isValidAuthority( 'wordpress#org' ); // false
* ```
*
* @return {boolean} True if the argument contains a valid authority.
*/
export function isValidAuthority( authority ) {
if ( ! authority ) {
return false;
}
return /^[^\s#?]+$/.test( authority );
}

19
node_modules/@wordpress/url/src/is-valid-fragment.js generated vendored Normal file
View File

@@ -0,0 +1,19 @@
/**
* Checks for invalid characters within the provided fragment.
*
* @param {string} fragment The url fragment.
*
* @example
* ```js
* const isValid = isValidFragment( '#valid-fragment' ); // true
* const isNotValid = isValidFragment( '#invalid-#fragment' ); // false
* ```
*
* @return {boolean} True if the argument contains a valid fragment.
*/
export function isValidFragment( fragment ) {
if ( ! fragment ) {
return false;
}
return /^#[^\s#?\/]*$/.test( fragment );
}

19
node_modules/@wordpress/url/src/is-valid-path.js generated vendored Normal file
View File

@@ -0,0 +1,19 @@
/**
* Checks for invalid characters within the provided path.
*
* @param {string} path The URL path.
*
* @example
* ```js
* const isValid = isValidPath( 'test/path/' ); // true
* const isNotValid = isValidPath( '/invalid?test/path/' ); // false
* ```
*
* @return {boolean} True if the argument contains a valid path
*/
export function isValidPath( path ) {
if ( ! path ) {
return false;
}
return /^[^\s#?]+$/.test( path );
}

19
node_modules/@wordpress/url/src/is-valid-protocol.js generated vendored Normal file
View File

@@ -0,0 +1,19 @@
/**
* Tests if a url protocol is valid.
*
* @param {string} protocol The url protocol.
*
* @example
* ```js
* const isValid = isValidProtocol( 'https:' ); // true
* const isNotValid = isValidProtocol( 'https :' ); // false
* ```
*
* @return {boolean} True if the argument is a valid protocol (e.g. http:, tel:).
*/
export function isValidProtocol( protocol ) {
if ( ! protocol ) {
return false;
}
return /^[a-z\-.\+]+[0-9]*:$/i.test( protocol );
}

View File

@@ -0,0 +1,19 @@
/**
* Checks for invalid characters within the provided query string.
*
* @param {string} queryString The query string.
*
* @example
* ```js
* const isValid = isValidQueryString( 'query=true&another=false' ); // true
* const isNotValid = isValidQueryString( 'query=true?another=false' ); // false
* ```
*
* @return {boolean} True if the argument contains a valid query string.
*/
export function isValidQueryString( queryString ) {
if ( ! queryString ) {
return false;
}
return /^[^\s#?\/]+$/.test( queryString );
}

38
node_modules/@wordpress/url/src/normalize-path.js generated vendored Normal file
View File

@@ -0,0 +1,38 @@
/**
* Given a path, returns a normalized path where equal query parameter values
* will be treated as identical, regardless of order they appear in the original
* text.
*
* @param {string} path Original path.
*
* @return {string} Normalized path.
*/
export function normalizePath( path ) {
const splitted = path.split( '?' );
const query = splitted[ 1 ];
const base = splitted[ 0 ];
if ( ! query ) {
return base;
}
// 'b=1%2C2&c=2&a=5'
return (
base +
'?' +
query
// [ 'b=1%2C2', 'c=2', 'a=5' ]
.split( '&' )
// [ [ 'b, '1%2C2' ], [ 'c', '2' ], [ 'a', '5' ] ]
.map( ( entry ) => entry.split( '=' ) )
// [ [ 'b', '1,2' ], [ 'c', '2' ], [ 'a', '5' ] ]
.map( ( pair ) => pair.map( decodeURIComponent ) )
// [ [ 'a', '5' ], [ 'b, '1,2' ], [ 'c', '2' ] ]
.sort( ( a, b ) => a[ 0 ].localeCompare( b[ 0 ] ) )
// [ [ 'a', '5' ], [ 'b, '1%2C2' ], [ 'c', '2' ] ]
.map( ( pair ) => pair.map( encodeURIComponent ) )
// [ 'a=5', 'b=1%2C2', 'c=2' ]
.map( ( pair ) => pair.join( '=' ) )
// 'a=5&b=1%2C2&c=2'
.join( '&' )
);
}

31
node_modules/@wordpress/url/src/prepend-http.js generated vendored Normal file
View File

@@ -0,0 +1,31 @@
/**
* Internal dependencies
*/
import { isEmail } from './is-email';
const USABLE_HREF_REGEXP = /^(?:[a-z]+:|#|\?|\.|\/)/i;
/**
* Prepends "http://" to a url, if it looks like something that is meant to be a TLD.
*
* @param {string} url The URL to test.
*
* @example
* ```js
* const actualURL = prependHTTP( 'wordpress.org' ); // http://wordpress.org
* ```
*
* @return {string} The updated URL.
*/
export function prependHTTP( url ) {
if ( ! url ) {
return url;
}
url = url.trim();
if ( ! USABLE_HREF_REGEXP.test( url ) && ! isEmail( url ) ) {
return 'http://' + url;
}
return url;
}

33
node_modules/@wordpress/url/src/prepend-https.js generated vendored Normal file
View File

@@ -0,0 +1,33 @@
/**
* Internal dependencies
*/
import { prependHTTP } from './prepend-http';
/**
* Prepends "https://" to a url, if it looks like something that is meant to be a TLD.
*
* Note: this will not replace "http://" with "https://".
*
* @param {string} url The URL to test.
*
* @example
* ```js
* const actualURL = prependHTTPS( 'wordpress.org' ); // https://wordpress.org
* ```
*
* @return {string} The updated URL.
*/
export function prependHTTPS( url ) {
if ( ! url ) {
return url;
}
// If url starts with http://, return it as is.
if ( url.startsWith( 'http://' ) ) {
return url;
}
url = prependHTTP( url );
return url.replace( /^http:/, 'https:' );
}

31
node_modules/@wordpress/url/src/remove-query-args.js generated vendored Normal file
View File

@@ -0,0 +1,31 @@
/**
* Internal dependencies
*/
import { getQueryArgs } from './get-query-args';
import { buildQueryString } from './build-query-string';
/**
* Removes arguments from the query string of the url
*
* @param {string} url URL.
* @param {...string} args Query Args.
*
* @example
* ```js
* const newUrl = removeQueryArgs( 'https://wordpress.org?foo=bar&bar=baz&baz=foobar', 'foo', 'bar' ); // https://wordpress.org?baz=foobar
* ```
*
* @return {string} Updated URL.
*/
export function removeQueryArgs( url, ...args ) {
const queryStringIndex = url.indexOf( '?' );
if ( queryStringIndex === -1 ) {
return url;
}
const query = getQueryArgs( url );
const baseURL = url.substr( 0, queryStringIndex );
args.forEach( ( arg ) => delete query[ arg ] );
const queryString = buildQueryString( query );
return queryString ? baseURL + '?' + queryString : baseURL;
}

View File

@@ -0,0 +1,15 @@
/**
* Safely decodes a URI component with `decodeURIComponent`. Returns the URI component unmodified if
* `decodeURIComponent` throws an error.
*
* @param {string} uriComponent URI component to decode.
*
* @return {string} Decoded URI component if possible.
*/
export function safeDecodeURIComponent( uriComponent ) {
try {
return decodeURIComponent( uriComponent );
} catch ( uriComponentError ) {
return uriComponent;
}
}

20
node_modules/@wordpress/url/src/safe-decode-uri.js generated vendored Normal file
View File

@@ -0,0 +1,20 @@
/**
* Safely decodes a URI with `decodeURI`. Returns the URI unmodified if
* `decodeURI` throws an error.
*
* @param {string} uri URI to decode.
*
* @example
* ```js
* const badUri = safeDecodeURI( '%z' ); // does not throw an Error, simply returns '%z'
* ```
*
* @return {string} Decoded URI if possible.
*/
export function safeDecodeURI( uri ) {
try {
return decodeURI( uri );
} catch ( uriError ) {
return uri;
}
}

View File

@@ -0,0 +1,25 @@
# URL Fixtures
The `@wordpress/url` module uses data from the [Web Platform Tests project](https://github.com/web-platform-tests/wpt) to verify expected behavior of its functionality as conforming to the [URL Living Standard](https://url.spec.whatwg.org/).
This data is updated manually. To bring in the latest data, run the download script:
```
node packages/url/scripts/download-wpt-data.js
```
The Web Platform Tests URL data is made available under the 3-Clause BSD License:
```
# The 3-Clause BSD License
Copyright 2019 web-platform-tests contributors
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```

File diff suppressed because one or more lines are too long

1136
node_modules/@wordpress/url/src/test/index.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

53
node_modules/@wordpress/url/src/test/index.native.js generated vendored Normal file
View File

@@ -0,0 +1,53 @@
/**
* Internal dependencies
*/
import './index.js';
/**
* External dependencies
*/
import 'react-native-url-polyfill/auto';
jest.mock( './fixtures/wpt-data.json', () => {
const data = jest.requireActual( './fixtures/wpt-data.json' );
/**
* Test items to exclude by input. Ideally this should be empty, but are
* necessary by non-spec-conformance of the Native implementations.
* Specifically, the React Native implementation uses an implementation of
* WHATWG URL without full Unicode support.
*
* @type {string[]}
*/
const URL_EXCEPTIONS = [
'https://<2F>',
'https://%EF%BF%BD',
'http://a<b',
'http://a>b',
'http://a^b',
'non-special://a<b',
'non-special://a>b',
'non-special://a^b',
'ftp://example.com%80/',
'ftp://example.com%A0/',
'https://example.com%80/',
'https://example.com%A0/',
'file://­/p',
'file://%C2%AD/p',
'file://xn--/p',
'http://a.b.c.xn--pokxncvks',
'http://10.0.0.xn--pokxncvks',
'foo://ho|st/',
'http://ho%3Cst/',
'http://ho%3Est/',
'http://ho%7Cst/',
'file://%43%7C',
'file://%43|',
'file://C%7C',
'file://%43%7C/',
'https://%43%7C/',
'asdf://%43|/',
];
return data.filter( ( { input } ) => ! URL_EXCEPTIONS.includes( input ) );
} );

22
node_modules/@wordpress/url/src/test/is-url.native.js generated vendored Normal file
View File

@@ -0,0 +1,22 @@
/**
* Internal dependencies
*/
import { isURL } from '../is-url';
describe( 'isURL valid', () => {
it.each( [
[ 'http://wordpress.org' ],
[ 'https://wordpress.org/path?query#fragment' ],
] )( '%s', ( input ) => {
expect( isURL( input ) ).toBe( true );
} );
} );
describe( 'isURL invalid', () => {
it.each( [
[ 'http://wordpress.org:port' ],
[ 'HTTP: HyperText Transfer Protocol' ],
] )( '%s', ( input ) => {
expect( isURL( input ) ).toBe( false );
} );
} );