Skip to content

Commit

Permalink
Convert to ES6, add linting, prepare for testing.
Browse files Browse the repository at this point in the history
Out with the old and in with the new!
  • Loading branch information
izaakschroeder committed Aug 14, 2016
1 parent 953da31 commit d54f647
Show file tree
Hide file tree
Showing 11 changed files with 159 additions and 86 deletions.
5 changes: 5 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"presets": [
"metalab"
]
}
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dist/**/*
node_modules
example
5 changes: 5 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"extends": [
"metalab"
]
}
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
*.log
build
dist
coverage
4 changes: 4 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
examples
*.log
coverage
34 changes: 34 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
sudo: false
language: node_js
matrix:
include:
# Run tests in Node.js 0.12
- node_js: '0.12'

# Run tests in Node.js 4.x
- node_js: '4'
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-4.8
- g++-4.8

# Run tests in Node.js 5.x
- node_js: '5'
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-4.8
- g++-4.8

before_install:
# Use GCC 4.8 if it's available
- 'if [ ! `which gcc-4.8` == "" ]; then export CXX=g++-4.8 && export CC=gcc-4.8; fi'

after_script:
- npm install coveralls
- cat ./coverage/coverage.json | ./node_modules/.bin/adana --format lcov | ./node_modules/coveralls/bin/coveralls.js
2 changes: 1 addition & 1 deletion example/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module.exports = {
target: 'web',
output: {
filename: '[name].js',
path: path.join(__dirname, 'build'),
path: path.join(__dirname, 'dist'),
chunkFilename: '[id].[chunkhash].js'
},
module: {
Expand Down
27 changes: 26 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,39 @@
{
"name": "sharp-loader",
"version": "0.3.0",
"main": "lib/sharp.js",
"license": "CC0-1.0",
"repository": "izaakschroeder/sharp-loader",
"main": "dist/sharp.js",
"dependencies": {
"bluebird": "^2.10.0",
"loader-utils": "^0.2.11",
"lodash": "^4.15.0",
"mime": "^1.3.4",
"option-multiplexer": "^0.1.0"
},
"scripts": {
"prepublish": "./node_modules/.bin/babel -s inline -d ./dist ./src --source-maps true",
"test": "npm run lint && npm run spec",
"lint": "eslint .",
"spec": "NODE_ENV=test ./node_modules/.bin/_mocha -r adana-dump --compilers js:babel-core/register -R spec --recursive test/spec/**/*.spec.js"
},
"devDependencies": {
"adana-cli": "^0.1.1",
"adana-dump": "^0.1.0",
"adana-format-lcov": "^0.1.1",
"babel-cli": "^6.7.7",
"babel-core": "^6.7.7",
"babel-preset-metalab": "^0.2.1",
"chai": "^3.5.0",
"eslint": "^2.8.0",
"eslint-config-metalab": "^3.1.0",
"eslint-plugin-filenames": "^0.2.0",
"eslint-plugin-import": "^1.6.0",
"eslint-plugin-react": "^4.2.3",
"memory-fs": "^0.3.0",
"mocha": "^2.4.5",
"webpack": "^1.13.0"
},
"peerDependencies": {
"sharp": ">=0.12.0"
}
Expand Down
155 changes: 72 additions & 83 deletions lib/sharp.js → src/sharp.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@

var _ = require('lodash');
var sharp = require('sharp');
var loaderUtils = require('loader-utils');
var multiplex = require('option-multiplexer');
var mime = require('mime');
var Promise = require('bluebird');
import _ from 'lodash';
import sharp from 'sharp';
import loaderUtils from 'loader-utils';
import multiplex from 'option-multiplexer';
import mime from 'mime';
import Promise from 'bluebird';

/**
* Perform a sequence of transformations on an image.
* @param {Object} image Initial sharp object.
* @param {Object} options Transformations to apply.
* @returns {Object} Resulting sharp object.
*/
function transform(image, options) {
options = options || { };
const transform = (image, options = {}) => {
return [
'blur',
'quality',
Expand All @@ -22,39 +20,38 @@ function transform(image, options) {
'max',
'min',
'crop',
'toFormat'
'toFormat',
].reduce(function(image, key) {
if (key in options) {
var value = options[key];
let value = options[key];
value = Array.isArray(value) ? value : [value];
return image[key].apply(image, value);
} else {
return image;
}
return image;
}, image.clone().flatten());
}
};

/**
* Generate the appropriate extension for a `sharp` format.
* @param {String} type `sharp` type.
* @returns {String} Extension.
*/
function extension(type) {
const extension = (type) => {
return {
'webp': '.webp',
'jpeg': '.jpg',
'png': '.png'
webp: '.webp',
jpeg: '.jpg',
png: '.png',
}[type];
}
};

/**
* Take some configuration options and transform them into a format that
* `transform` is capable of using.
* @param {Object} options Generic configuration options.
* @returns {Object} `transform` compatible options.
*/
function normalize(options) {
var result = { };
const normalize = (options) => {
const result = { };
if (options.format) {
result.toFormat = options.format;
}
Expand All @@ -64,7 +61,7 @@ function normalize(options) {

// Sizing
if (options.width || options.height) {
result.resize = [ options.width, options.height ];
result.resize = [options.width, options.height];
}

if (result.resize) {
Expand All @@ -75,13 +72,13 @@ function normalize(options) {

// Multiplicative density
if (options.density) {
var density = Number(options.density);
const density = Number(options.density);
result.resize[0] *= density;
result.resize[1] *= density;
}

// Mimic background-size
switch(options.mode) {
switch (options.mode) {
case 'cover':
result.min = true;
break;
Expand All @@ -99,39 +96,27 @@ function normalize(options) {

result.inline = !!options.inline;
return result;
}

function getPresets(localQuery, globalQuery) {
if (!globalQuery.presets) {
throw new Error('No presets defined.');
} else if (!localQuery.presets) {
throw new Error('No presets selected.');
}
return _.pick(globalQuery.presets, localQuery.presets);
}



function emit(context) {
var publicPath = context.options.output.publicPath || '/';
var query = loaderUtils.parseQuery(context.query);
var template = query.name;
};

function name(image, info, options, preset) {
const emit = (context) => {
const publicPath = context.options.output.publicPath || '/';
const query = loaderUtils.parseQuery(context.query);
const template = query.name;

const name = (image, info) => {
return loaderUtils.interpolateName({
resourcePath: context.resourcePath
.replace(/\.[^.]+$/, extension(info.format))
.replace(/\.[^.]+$/, extension(info.format)),
}, template, {
context: query.context || context.options.context,
content: image
content: image,
});
}
};

function data(image, info, options, preset) {
var n = name(image, info, options, preset);
var format = mime.lookup(n);
var extra = {format: format};
const data = (image, info, options, preset) => {
const n = name(image, info, options, preset);
const format = mime.lookup(n);
const extra = {format: format};
if (preset) {
extra.preset = preset;
}
Expand All @@ -142,19 +127,20 @@ function emit(context) {
'data:',
format,
';base64,',
image.toString('base64')
].join('')
}, options, info, extra);
} else {
context.emitFile(n, image);
return _.assign({
url: publicPath + n
image.toString('base64'),
].join(''),
}, options, info, extra);
}
}
context.emitFile(n, image);
return _.assign({
url: publicPath + n,
}, options, info, extra);
};

return function(result) {
var image = result.image, options = result.options, preset = result.preset;
return (result) => {
const image = result.image;
const options = result.options;
const preset = result.preset;

// We have to use the callback form in order to get access to the info
// object unfortunately.
Expand All @@ -165,54 +151,55 @@ function emit(context) {
} else {
resolve(data(buffer, info, options, preset));
}
})
});
});
}
}
};
};

function handle(image, preset, name, presets, emit) {
function wahoo(options) {
const handle = (image, preset, name, presets, emit) => {
const wahoo = (options) => {
return Promise.props({
preset: name,
options: options,
image: transform(image, normalize(options))
image: transform(image, normalize(options)),
}).then(emit);
}
};
if (name && !presets[name]) {
return [Promise.reject('No such preset: ' + preset)];
return [Promise.reject(`No such preset: ${preset}`)];
}
var values = multiplex(_.assign({ }, presets[name] || {}, preset));
const values = multiplex(_.assign({ }, presets[name] || {}, preset));
return _.map(values, wahoo);
}
};

function lolol(image, extra, presets, globals, emit) {
const lolol = (image, extra, presets, globals, emit) => {
if (_.isArray(presets)) {
return Promise.all(_.flatMap(presets, function (name) {
return Promise.all(_.flatMap(presets, (name) => {
return handle(image, extra, name, globals, emit);
}));
} else if (_.isObject(presets)) {
return Promise.all(_.flatMap(_.toPairs(presets), function([name, preset]) {
return Promise.all(_.flatMap(_.toPairs(presets), ([name, preset]) => {
return handle(image, _.assign({}, preset, extra), name, globals, emit);
}));
} else if (_.isString(presets)) {
return Promise.all(handle(image, extra, presets, globals, emit));
}
throw new TypeError();
}
};

/* eslint import/no-commonjs: 0 */
/* global module */
module.exports = function(input) {
// This means that, for a given query string, the loader will only be
// run once. No point in barfing out the same image over and over.
this.cacheable();

var localQuery = loaderUtils.parseQuery(this.resourceQuery);
var globalQuery = loaderUtils.parseQuery(this.query);
var extra = _.omit(localQuery, ['preset', 'presets']);
var assets;
var image = sharp(input);
var meta = image.metadata();
var callback = this.async();
var e = emit(this);
const localQuery = loaderUtils.parseQuery(this.resourceQuery);
const globalQuery = loaderUtils.parseQuery(this.query);
const extra = _.omit(localQuery, ['preset', 'presets']);
let assets;
const image = sharp(input);
const callback = this.async();
const e = emit(this);

// We have three possible choices:
// - set of presets in `presets`
Expand All @@ -223,11 +210,13 @@ module.exports = function(input) {
} else if (localQuery.preset) {
assets = lolol(image, extra, localQuery.preset, globalQuery.presets, e);
} else {
assets = Promise.all(handle(image, localQuery, null, globalQuery.presets, e));
assets = Promise.all(
handle(image, localQuery, null, globalQuery.presets, e)
);
}

assets.then(function(assets) {
return 'module.exports = ' + JSON.stringify(assets) + ';';
return `module.exports = ${JSON.stringify(assets)};`;
}).nodeify(callback);
};

Expand Down
6 changes: 6 additions & 0 deletions test/spec/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"env": {
"node": true,
"mocha": true
}
}
Loading

0 comments on commit d54f647

Please sign in to comment.