diff --git a/react-packager/src/AssetServer/__tests__/AssetServer-test.js b/react-packager/src/AssetServer/__tests__/AssetServer-test.js index 95916c9e..54ef7012 100644 --- a/react-packager/src/AssetServer/__tests__/AssetServer-test.js +++ b/react-packager/src/AssetServer/__tests__/AssetServer-test.js @@ -8,22 +8,22 @@ jest .mock('crypto') .mock('fs'); -var Promise = require('promise'); +const Promise = require('promise'); -describe('AssetServer', function() { - var AssetServer; - var crypto; - var fs; +describe('AssetServer', () => { + let AssetServer; + let crypto; + let fs; - beforeEach(function() { + beforeEach(() => { AssetServer = require('../'); crypto = require('crypto'); fs = require('fs'); }); - describe('assetServer.get', function() { - pit('should work for the simple case', function() { - var server = new AssetServer({ + describe('assetServer.get', () => { + pit('should work for the simple case', () => { + const server = new AssetServer({ projectRoots: ['/root'], assetExts: ['png'], }); @@ -40,15 +40,15 @@ describe('AssetServer', function() { return Promise.all([ server.get('imgs/b.png'), server.get('imgs/b@1x.png'), - ]).then(function(resp) { - resp.forEach(function(data) { - expect(data).toBe('b image'); - }); - }); + ]).then(resp => + resp.forEach(data => + expect(data).toBe('b image') + ) + ); }); - pit('should work for the simple case with jpg', function() { - var server = new AssetServer({ + pit('should work for the simple case with jpg', () => { + const server = new AssetServer({ projectRoots: ['/root'], assetExts: ['png', 'jpg'], }); @@ -65,16 +65,16 @@ describe('AssetServer', function() { return Promise.all([ server.get('imgs/b.jpg'), server.get('imgs/b.png'), - ]).then(function(data) { + ]).then(data => expect(data).toEqual([ 'jpeg image', 'png image', - ]); - }); + ]) + ); }); - pit('should pick the bigger one', function() { - var server = new AssetServer({ + pit('should pick the bigger one', () => { + const server = new AssetServer({ projectRoots: ['/root'], assetExts: ['png'], }); @@ -90,13 +90,13 @@ describe('AssetServer', function() { } }); - return server.get('imgs/b@3x.png').then(function(data) { - expect(data).toBe('b4 image'); - }); + return server.get('imgs/b@3x.png').then(data => + expect(data).toBe('b4 image') + ); }); - pit('should support multiple project roots', function() { - var server = new AssetServer({ + pit('should support multiple project roots', () => { + const server = new AssetServer({ projectRoots: ['/root', '/root2'], assetExts: ['png'], }); @@ -116,27 +116,23 @@ describe('AssetServer', function() { }, }); - return server.get('newImages/imgs/b.png').then(function(data) { - expect(data).toBe('b1 image'); - }); + return server.get('newImages/imgs/b.png').then(data => + expect(data).toBe('b1 image') + ); }); }); - describe('assetSerer.getAssetData', function() { - pit('should get assetData', function() { - var hash = { + describe('assetSerer.getAssetData', () => { + pit('should get assetData', () => { + const hash = { update: jest.genMockFn(), digest: jest.genMockFn(), }; - hash.digest.mockImpl(function() { - return 'wow such hash'; - }); - crypto.createHash.mockImpl(function() { - return hash; - }); + hash.digest.mockImpl(() => 'wow such hash'); + crypto.createHash.mockImpl(() => hash); - var server = new AssetServer({ + const server = new AssetServer({ projectRoots: ['/root'], assetExts: ['png'], }); @@ -152,7 +148,7 @@ describe('AssetServer', function() { } }); - return server.getAssetData('imgs/b.png').then(function(data) { + return server.getAssetData('imgs/b.png').then(data => { expect(hash.update.mock.calls.length).toBe(4); expect(data).toEqual({ type: 'png', @@ -163,20 +159,16 @@ describe('AssetServer', function() { }); }); - pit('should get assetData for non-png images', function() { - var hash = { + pit('should get assetData for non-png images', () => { + const hash = { update: jest.genMockFn(), digest: jest.genMockFn(), }; - hash.digest.mockImpl(function() { - return 'wow such hash'; - }); - crypto.createHash.mockImpl(function() { - return hash; - }); + hash.digest.mockImpl(() => 'wow such hash'); + crypto.createHash.mockImpl(() => hash); - var server = new AssetServer({ + const server = new AssetServer({ projectRoots: ['/root'], assetExts: ['png', 'jpeg'], }); @@ -192,7 +184,7 @@ describe('AssetServer', function() { } }); - return server.getAssetData('imgs/b.jpg').then(function(data) { + return server.getAssetData('imgs/b.jpg').then(data => { expect(hash.update.mock.calls.length).toBe(4); expect(data).toEqual({ type: 'jpg', diff --git a/react-packager/src/AssetServer/index.js b/react-packager/src/AssetServer/index.js index 2cd365fd..f442f6b8 100644 --- a/react-packager/src/AssetServer/index.js +++ b/react-packager/src/AssetServer/index.js @@ -8,20 +8,20 @@ */ 'use strict'; -var declareOpts = require('../lib/declareOpts'); -var getAssetDataFromName = require('../lib/getAssetDataFromName'); -var path = require('path'); -var Promise = require('promise'); -var fs = require('fs'); -var crypto = require('crypto'); +const Promise = require('promise'); -var stat = Promise.denodeify(fs.stat); -var readDir = Promise.denodeify(fs.readdir); -var readFile = Promise.denodeify(fs.readFile); +const crypto = require('crypto'); +const declareOpts = require('../lib/declareOpts'); +const fs = require('fs'); +const getAssetDataFromName = require('../lib/getAssetDataFromName'); +const path = require('path'); -module.exports = AssetServer; +const stat = Promise.denodeify(fs.stat); +const readDir = Promise.denodeify(fs.readdir); +const readFile = Promise.denodeify(fs.readFile); -var validateOpts = declareOpts({ + +const validateOpts = declareOpts({ projectRoots: { type: 'array', required: true, @@ -32,135 +32,136 @@ var validateOpts = declareOpts({ }, }); -function AssetServer(options) { - var opts = validateOpts(options); - this._roots = opts.projectRoots; - this._assetExts = opts.assetExts; -} +class AssetServer { + constructor(options) { + const opts = validateOpts(options); + this._roots = opts.projectRoots; + this._assetExts = opts.assetExts; + } -/** - * Given a request for an image by path. That could contain a resolution - * postfix, we need to find that image (or the closest one to it's resolution) - * in one of the project roots: - * - * 1. We first parse the directory of the asset - * 2. We check to find a matching directory in one of the project roots - * 3. We then build a map of all assets and their scales in this directory - * 4. Then pick the closest resolution (rounding up) to the requested one - */ - -AssetServer.prototype._getAssetRecord = function(assetPath) { - var filename = path.basename(assetPath); - - return findRoot( - this._roots, - path.dirname(assetPath) - ).then(function(dir) { - return Promise.all([ - dir, - readDir(dir), - ]); - }).then(function(res) { - var dir = res[0]; - var files = res[1]; - var assetData = getAssetDataFromName(filename); - - var map = buildAssetMap(dir, files); - var record = map[assetData.assetName]; - - if (!record) { - throw new Error('Asset not found'); - } - - return record; - }); -}; - -AssetServer.prototype.get = function(assetPath) { - var assetData = getAssetDataFromName(assetPath); - return this._getAssetRecord(assetPath).then(function(record) { - for (var i = 0; i < record.scales.length; i++) { - if (record.scales[i] >= assetData.resolution) { - return readFile(record.files[i]); + get(assetPath) { + const assetData = getAssetDataFromName(assetPath); + return this._getAssetRecord(assetPath).then(record => { + for (let i = 0; i < record.scales.length; i++) { + if (record.scales[i] >= assetData.resolution) { + return readFile(record.files[i]); + } } - } - return readFile(record.files[record.files.length - 1]); - }); -}; + return readFile(record.files[record.files.length - 1]); + }); + } -AssetServer.prototype.getAssetData = function(assetPath) { - var nameData = getAssetDataFromName(assetPath); - var data = { - name: nameData.name, - type: nameData.type, - }; + getAssetData(assetPath) { + const nameData = getAssetDataFromName(assetPath); + const data = { + name: nameData.name, + type: nameData.type, + }; - return this._getAssetRecord(assetPath).then(function(record) { - data.scales = record.scales; + return this._getAssetRecord(assetPath).then(record => { + data.scales = record.scales; - return Promise.all( - record.files.map(function(file) { - return stat(file); + return Promise.all( + record.files.map(file => stat(file)) + ); + }).then(stats => { + const hash = crypto.createHash('md5'); + + stats.forEach(fstat => + hash.update(fstat.mtime.getTime().toString()) + ); + + data.hash = hash.digest('hex'); + return data; + }); + } + + /** + * Given a request for an image by path. That could contain a resolution + * postfix, we need to find that image (or the closest one to it's resolution) + * in one of the project roots: + * + * 1. We first parse the directory of the asset + * 2. We check to find a matching directory in one of the project roots + * 3. We then build a map of all assets and their scales in this directory + * 4. Then pick the closest resolution (rounding up) to the requested one + */ + _getAssetRecord(assetPath) { + const filename = path.basename(assetPath); + + return ( + this._findRoot( + this._roots, + path.dirname(assetPath) + ) + .then(dir => Promise.all([ + dir, + readDir(dir), + ])) + .then(res => { + const dir = res[0]; + const files = res[1]; + const assetData = getAssetDataFromName(filename); + + const map = this._buildAssetMap(dir, files); + const record = map[assetData.assetName]; + + if (!record) { + throw new Error('Asset not found'); + } + + return record; }) ); - }).then(function(stats) { - var hash = crypto.createHash('md5'); + } - stats.forEach(function(fstat) { - hash.update(fstat.mtime.getTime().toString()); - }); - - data.hash = hash.digest('hex'); - return data; - }); -}; - -function findRoot(roots, dir) { - return Promise.all( - roots.map(function(root) { - var absPath = path.join(root, dir); - return stat(absPath).then(function(fstat) { - return {path: absPath, isDirectory: fstat.isDirectory()}; - }, function (err) { - return {path: absPath, isDirectory: false}; - }); - }) - ).then( - function(stats) { - for (var i = 0; i < stats.length; i++) { + _findRoot(roots, dir) { + return Promise.all( + roots.map(root => { + const absPath = path.join(root, dir); + return stat(absPath).then(fstat => { + return {path: absPath, isDirectory: fstat.isDirectory()}; + }, err => { + return {path: absPath, isDirectory: false}; + }); + }) + ).then(stats => { + for (let i = 0; i < stats.length; i++) { if (stats[i].isDirectory) { return stats[i].path; } } throw new Error('Could not find any directories'); - } - ); -} + }); + } -function buildAssetMap(dir, files) { - var assets = files.map(getAssetDataFromName); - var map = Object.create(null); - assets.forEach(function(asset, i) { - var file = files[i]; - var record = map[asset.assetName]; - if (!record) { - record = map[asset.assetName] = { - scales: [], - files: [], - }; - } - - var insertIndex; - var length = record.scales.length; - for (insertIndex = 0; insertIndex < length; insertIndex++) { - if (asset.resolution < record.scales[insertIndex]) { - break; + _buildAssetMap(dir, files) { + const assets = files.map(getAssetDataFromName); + const map = Object.create(null); + assets.forEach(function(asset, i) { + const file = files[i]; + let record = map[asset.assetName]; + if (!record) { + record = map[asset.assetName] = { + scales: [], + files: [], + }; } - } - record.scales.splice(insertIndex, 0, asset.resolution); - record.files.splice(insertIndex, 0, path.join(dir, file)); - }); - return map; + let insertIndex; + const length = record.scales.length; + for (insertIndex = 0; insertIndex < length; insertIndex++) { + if (asset.resolution < record.scales[insertIndex]) { + break; + } + } + record.scales.splice(insertIndex, 0, asset.resolution); + record.files.splice(insertIndex, 0, path.join(dir, file)); + }); + + return map; + } } + +module.exports = AssetServer;