From 8c4a1932dc796e7b9aa6e0964d43735a1cf89200 Mon Sep 17 00:00:00 2001 From: Luis Ball Date: Fri, 25 Jun 2021 10:15:21 -0700 Subject: [PATCH] feat: create static buildURL method This commit creates a static `_buildURL` method on the imgix client. The method allows full URLs to be formatted for use with imgix. > note: If the source URL has included parameters, they are merged with the `params` passed in as an argument. - `url`: full source URL path string, required - `params`: imgix params object, optional - `options`: imgix client options, optional The method returns a URL string formatted to imgix specifications. --- src/index.js | 66 ++++++++++++++++++----- test/test-_buildURL.js | 119 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+), 12 deletions(-) create mode 100644 test/test-_buildURL.js diff --git a/src/index.js b/src/index.js index 33f51527..cff5db93 100644 --- a/src/index.js +++ b/src/index.js @@ -1,25 +1,22 @@ -import md5 from 'md5'; import { Base64 } from 'js-base64'; -import { extractUrl } from './helpers'; +import md5 from 'md5'; import { getQuery } from 'ufo'; - - import { - VERSION, - DOMAIN_REGEX, + DEFAULT_DPR, DEFAULT_OPTIONS, + DOMAIN_REGEX, DPR_QUALITIES, - DEFAULT_DPR, + VERSION, } from './constants.js'; - +import { extractUrl } from './helpers'; import { - validateRange, - validateWidths, validateAndDestructureOptions, - validateVariableQuality, - validateWidthTolerance, validateDevicePixelRatios, + validateRange, validateVariableQualities, + validateVariableQuality, + validateWidths, + validateWidthTolerance, } from './validators.js'; export default class ImgixClient { @@ -62,6 +59,51 @@ export default class ImgixClient { return this.settings.urlPrefix + this.settings.domain + path + finalParams; } + /** + *`_buildURL` static method allows full URLs to be formatted for use with + * imgix. + * + * - If the source URL has included parameters, they are merged with + * the `params` passed in as an argument. + * - URL must match `{host}/{pathname}?{query}` otherwise an error is thrown. + * + * @param {String} url - full source URL path string, required + * @param {Object} params - imgix params object, optional + * @param {Object} options - imgix client options, optional + * + * @returns URL string formatted to imgix specifications. + * + * @example + * const client = ImgixClient + * const params = { w: 100 } + * const opts = { useHttps: true } + * const src = "sdk-test.imgix.net/amsterdam.jpg?h=100" + * const url = client._buildURL(src, params, opts) + * console.log(url) + * // => "https://sdk-test.imgix.net/amsterdam.jpg?h=100&w=100" + */ + static _buildURL(url, params = {}, options = {}) { + if (url == null) { + return ''; + } + + const { host, pathname, search } = extractUrl({ + url, + useHTTPS: options.useHTTPS, + }); + // merge source URL parameters with options parameters + const combinedParams = { ...getQuery(search), ...params }; + + // throw error if no host or no pathname present + if (!host.length || !pathname.length) { + throw new Error('_buildURL: URL must match {host}/{pathname}?{query}'); + } + + const client = new ImgixClient({ domain: host, ...options }); + + return client.buildURL(pathname, combinedParams); + } + _buildParams(params = {}) { const queryParams = [ // Set the libraryParam if applicable. diff --git a/test/test-_buildURL.js b/test/test-_buildURL.js new file mode 100644 index 00000000..ed07f8cb --- /dev/null +++ b/test/test-_buildURL.js @@ -0,0 +1,119 @@ +import assert from 'assert'; +import ImgixClient from '../src/index.js'; + +describe('URL Builder:', function describeSuite() { + describe('Calling _buildURL()', function describeSuite() { + let client, params, url, options; + + beforeEach(function setupClient() { + client = ImgixClient; + }); + + describe('on a full URL', function describeSuite() { + url = 'https://assets.imgix.net/images/1.png'; + params = { h: 100 }; + options = { includeLibraryParam: false, useHTTPS: true }; + + it('should return a URL with formatted imgix params', function testSpec() { + const expectation = url + '?h=100'; + const result = client._buildURL(url, params, options); + + assert.strictEqual(result, expectation); + }); + + describe('that has no scheme', function describeSuite() { + const url = 'assets.imgix.net/images/1.png'; + const params = {}; + const options = { includeLibraryParam: false, useHTTPS: true }; + + it('should prepend the scheme to the returned URL', function testSpec() { + const expectation = 'https://' + url; + const result = client._buildURL(url, params, options); + + assert.strictEqual(result, expectation); + }); + }); + + describe('that has a proxy path', function describeSuite() { + const url = 'https://assets.imgix.net/https://sdk-test/images/1.png'; + const params = {}; + const options = { includeLibraryParam: false, useHTTPS: true }; + + it('should correctly encode the proxy path', function testSpec() { + const expectation = new client({ + domain: 'assets.imgix.net', + ...options, + }).buildURL('https://sdk-test/images/1.png', params); + const result = client._buildURL(url, params, options); + + assert.strictEqual(result, expectation); + }); + }); + + describe('that has a insecure source and secure proxy', function describeSuite() { + const url = + 'http://assets.imgix.net/https://sdk-test.imgix.net/images/1.png'; + const params = {}; + const options = { includeLibraryParam: false, useHTTPS: false }; + + it('should not modify the source or proxy schemes', function testSpec() { + const expectation = + 'http://assets.imgix.net/https%3A%2F%2Fsdk-test.imgix.net%2Fimages%2F1.png'; + const result = client._buildURL(url, params, options); + + assert.strictEqual(result, expectation); + }); + }); + + describe('that has a secure source and insecure proxy', function describeSuite() { + const url = + 'https://assets.imgix.net/http://sdk-test.imgix.net/images/1.png'; + const params = {}; + const options = { includeLibraryParam: false, useHTTPS: true }; + + it('should not modify the source or proxy schemes', function testSpec() { + const expectation = + 'https://assets.imgix.net/http%3A%2F%2Fsdk-test.imgix.net%2Fimages%2F1.png'; + const result = client._buildURL(url, params, options); + + assert.strictEqual(result, expectation); + }); + }); + }); + + describe('on a malformed URLs', function describeSuite() { + const error = new Error( + '_buildURL: URL must match {host}/{pathname}?{query}', + ); + const params = {}; + const options = { includeLibraryParam: false, useHTTPS: true }; + + it('should throw an error if no hostname', function testSpec() { + const url = '/image.png'; + assert.throws(function () { + client._buildURL(url, params, options); + }, error); + }); + + it('should throw an error if no pathname', function testSpec() { + const url = 'assets.imgix.net'; + assert.throws(function () { + client._buildURL(url, params, options); + }, error); + }); + }); + + describe('that has parameters in the URL', function describeSuite() { + const url = 'https://assets.imgix.net/images/1.png?w=100&h=100'; + const params = { h: 200 }; + const options = { includeLibraryParam: false, useHTTPS: true }; + + it('should overwrite url params with opts params', function testSpec() { + const expectation = 'https://assets.imgix.net/images/1.png?w=100&h=200'; + const result = client._buildURL(url, params, options); + + assert.strictEqual(result, expectation); + }); + }); + }); +});