diff --git a/package-lock.json b/package-lock.json
index 8a3aa3554f754..1f040edd235e5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -25713,6 +25713,12 @@
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true
},
+ "typescript": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz",
+ "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==",
+ "dev": true
+ },
"ua-parser-js": {
"version": "0.7.18",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.18.tgz",
diff --git a/package.json b/package.json
index 46ebf924d604a..80da4126e0d7e 100644
--- a/package.json
+++ b/package.json
@@ -139,6 +139,7 @@
"source-map-loader": "0.2.4",
"sprintf-js": "1.1.1",
"stylelint-config-wordpress": "13.1.0",
+ "typescript": "3.5.3",
"uuid": "3.3.2",
"webpack": "4.8.3",
"worker-farm": "1.7.0"
@@ -189,13 +190,14 @@
"fixtures:server-registered": "docker-compose run -w /var/www/html/wp-content/plugins/gutenberg --rm wordpress ./bin/get-server-blocks.php > test/integration/full-content/server-registered.json",
"fixtures:generate": "npm run fixtures:server-registered && cross-env GENERATE_MISSING_FIXTURES=y npm run test-unit",
"fixtures:regenerate": "npm run fixtures:clean && npm run fixtures:generate",
- "lint": "concurrently \"npm run lint-js\" \"npm run lint-pkg-json\" \"npm run lint-css\"",
+ "lint": "concurrently \"npm run lint-js\" \"npm run lint-pkg-json\" \"npm run lint-css\" \"npm run lint-types\"",
"lint-js": "wp-scripts lint-js",
"lint-js:fix": "npm run lint-js -- --fix",
"lint-php": "docker-compose run --rm composer run-script lint",
"lint-pkg-json": "wp-scripts lint-pkg-json ./packages",
"lint-css": "wp-scripts lint-style '**/*.scss'",
"lint-css:fix": "npm run lint-css -- --fix",
+ "lint-types": "tsc",
"package-plugin": "./bin/build-plugin-zip.sh",
"pot-to-php": "./bin/pot-to-php.js",
"precommit": "lint-staged",
diff --git a/packages/url/README.md b/packages/url/README.md
index cfc6286d715b5..5b381e074f48c 100644
--- a/packages/url/README.md
+++ b/packages/url/README.md
@@ -30,7 +30,7 @@ const newURL = addQueryArgs( 'https://google.com', { q: 'test' } ); // https://g
_Parameters_
-- _url_ `?string`: URL to which arguments should be appended. If omitted, only the resulting querystring is returned.
+- _url_ `[string]`: URL to which arguments should be appended. If omitted, only the resulting querystring is returned.
- _args_ `Object`: Query arguments to apply to URL.
_Returns_
@@ -72,7 +72,7 @@ _Parameters_
_Returns_
-- `?string`: The authority part of the URL.
+- `(string|void)`: The authority part of the URL.
# **getFragment**
@@ -91,7 +91,7 @@ _Parameters_
_Returns_
-- `?string`: The fragment part of the URL.
+- `(string|void)`: The fragment part of the URL.
# **getPath**
@@ -110,7 +110,7 @@ _Parameters_
_Returns_
-- `?string`: The path part of the URL.
+- `(string|void)`: The path part of the URL.
# **getProtocol**
@@ -129,7 +129,7 @@ _Parameters_
_Returns_
-- `?string`: The protocol part of the URL.
+- `(string|void)`: The protocol part of the URL.
# **getQueryArg**
@@ -143,12 +143,12 @@ const foo = getQueryArg( 'https://wordpress.org?foo=bar&bar=baz', 'foo' ); // ba
_Parameters_
-- _url_ `string`: URL
-- _arg_ `string`: Query arg name
+- _url_ `string`: URL.
+- _arg_ `string`: Query arg name.
_Returns_
-- `(Array|string)`: Query arg value.
+- `(QueryArgParsed|undefined)`: Query arg value.
# **getQueryString**
@@ -167,7 +167,7 @@ _Parameters_
_Returns_
-- `?string`: The query string part of the URL.
+- `(string|void)`: The query string part of the URL.
# **hasQueryArg**
@@ -181,8 +181,8 @@ const hasBar = hasQueryArg( 'https://wordpress.org?foo=bar&bar=baz', 'bar' ); //
_Parameters_
-- _url_ `string`: URL
-- _arg_ `string`: Query arg name
+- _url_ `string`: URL.
+- _arg_ `string`: Query arg name.
_Returns_
@@ -331,11 +331,11 @@ const actualURL = prependHTTP( 'wordpress.org' ); // http://wordpress.org
_Parameters_
-- _url_ `string`: The URL to test
+- _url_ `string`: The URL to test.
_Returns_
-- `string`: The updated URL
+- `string`: The updated URL.
# **removeQueryArgs**
@@ -349,12 +349,12 @@ const newUrl = removeQueryArgs( 'https://wordpress.org?foo=bar&bar=baz&baz=fooba
_Parameters_
-- _url_ `string`: URL
-- _args_ `...string`: Query Args
+- _url_ `string`: URL.
+- _args_ `...string`: Query Args.
_Returns_
-- `string`: Updated URL
+- `string`: Updated URL.
# **safeDecodeURI**
diff --git a/packages/url/src/index.js b/packages/url/src/index.js
index 6cc606c9d546b..afbf1de9e7c16 100644
--- a/packages/url/src/index.js
+++ b/packages/url/src/index.js
@@ -7,6 +7,14 @@ const URL_REGEXP = /^(?:https?:)?\/\/\S+$/i;
const EMAIL_REGEXP = /^(mailto:)?[a-z0-9._%+-]+@[a-z0-9][a-z0-9.-]*\.[a-z]{2,63}$/i;
const USABLE_HREF_REGEXP = /^(?:[a-z]+:|#|\?|\.|\/)/i;
+/**
+ * @typedef {{[key: string]: QueryArgParsed}} QueryArgObject
+ */
+
+/**
+ * @typedef {string|string[]|QueryArgObject} QueryArgParsed
+ */
+
/**
* Determines whether the given string looks like a URL.
*
@@ -50,7 +58,7 @@ export function isEmail( email ) {
* const protocol2 = getProtocol( 'https://wordpress.org' ); // 'https:'
* ```
*
- * @return {?string} The protocol part of the URL.
+ * @return {string|void} The protocol part of the URL.
*/
export function getProtocol( url ) {
const matches = /^([^\s:]+:)/.exec( url );
@@ -90,7 +98,7 @@ export function isValidProtocol( protocol ) {
* const authority2 = getAuthority( 'https://localhost:8080/test/' ); // 'localhost:8080'
* ```
*
- * @return {?string} The authority part of the URL.
+ * @return {string|void} The authority part of the URL.
*/
export function getAuthority( url ) {
const matches = /^[^\/\s:]+:(?:\/\/)?\/?([^\/\s#?]+)[\/#?]{0,1}\S*$/.exec( url );
@@ -130,7 +138,7 @@ export function isValidAuthority( authority ) {
* const path2 = getPath( 'https://wordpress.org/help/faq/' ); // 'help/faq'
* ```
*
- * @return {?string} The path part of the URL.
+ * @return {string|void} The path part of the URL.
*/
export function getPath( url ) {
const matches = /^[^\/\s:]+:(?:\/\/)?[^\/\s#?]+[\/]([^\s#?]+)[#?]{0,1}\S*$/.exec( url );
@@ -170,7 +178,7 @@ export function isValidPath( path ) {
* const queryString2 = getQueryString( 'https://wordpress.org#fragment?query=false&search=hello' ); // 'query=false&search=hello'
* ```
*
- * @return {?string} The query string part of the URL.
+ * @return {string|void} The query string part of the URL.
*/
export function getQueryString( url ) {
const matches = /^\S+?\?([^\s#]+)/.exec( url );
@@ -210,7 +218,7 @@ export function isValidQueryString( queryString ) {
* const fragment2 = getFragment( 'https://wordpress.org#another-fragment?query=true' ); // '#another-fragment'
* ```
*
- * @return {?string} The fragment part of the URL.
+ * @return {string|void} The fragment part of the URL.
*/
export function getFragment( url ) {
const matches = /^\S+?(#[^\s\?]*)/.exec( url );
@@ -244,9 +252,9 @@ export function isValidFragment( fragment ) {
* 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.
+ * @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
@@ -282,15 +290,15 @@ export function addQueryArgs( url = '', args ) {
/**
* Returns a single query argument of the url
*
- * @param {string} url URL
- * @param {string} arg Query arg name
+ * @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 {Array|string} Query arg value.
+ * @return {QueryArgParsed|undefined} Query arg value.
*/
export function getQueryArg( url, arg ) {
const queryStringIndex = url.indexOf( '?' );
@@ -302,8 +310,8 @@ export function getQueryArg( url, arg ) {
/**
* Determines whether the URL contains a given query arg.
*
- * @param {string} url URL
- * @param {string} arg Query arg name
+ * @param {string} url URL.
+ * @param {string} arg Query arg name.
*
* @example
* ```js
@@ -319,15 +327,15 @@ export function hasQueryArg( url, arg ) {
/**
* Removes arguments from the query string of the url
*
- * @param {string} url URL
- * @param {...string} args Query Args
+ * @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
+ * @return {string} Updated URL.
*/
export function removeQueryArgs( url, ...args ) {
const queryStringIndex = url.indexOf( '?' );
@@ -342,14 +350,14 @@ export function removeQueryArgs( url, ...args ) {
/**
* Prepends "http://" to a url, if it looks like something that is meant to be a TLD.
*
- * @param {string} url The URL to test
+ * @param {string} url The URL to test.
*
* @example
* ```js
* const actualURL = prependHTTP( 'wordpress.org' ); // http://wordpress.org
* ```
*
- * @return {string} The updated URL
+ * @return {string} The updated URL.
*/
export function prependHTTP( url ) {
if ( ! USABLE_HREF_REGEXP.test( url ) && ! EMAIL_REGEXP.test( url ) ) {
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000000000..cee321c53693e
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,32 @@
+{
+ "compilerOptions": {
+ "allowJs": true,
+ "allowSyntheticDefaultImports": true,
+ "checkJs": true,
+ "jsx": "preserve",
+ "lib": ["dom", "esnext"],
+ "module": "commonjs",
+ "noEmit": true,
+ "resolveJsonModule": true,
+ "target": "esnext",
+
+ /* Strict Type-Checking Options */
+ "strict": true, /* Enable all strict type-checking options. */
+ "noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
+
+ /* Additional Checks */
+ "noUnusedLocals": true, /* Report errors on unused locals. */
+ "noUnusedParameters": true, /* Report errors on unused parameters. */
+ "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
+ "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
+
+ },
+ "include": [
+ "./packages/url/**/*.js"
+ ],
+ "exclude": [
+ "./packages/**/test/**",
+ "./packages/**/build/**",
+ "./packages/**/build-module/**"
+ ]
+}